[RFC PATCH 0/1] Notifications for perf sideband events

From: Naveen N. Rao
Date: Tue Jun 06 2017 - 10:50:26 EST


Currently, there is no way to ask for signals to be delivered when a
certain number of sideband events have been logged into the ring
buffer. This is problematic if we are only interested in, say, context
switch events. This patch provides for a way to achieve this.

As noted, this is a RFC and I am not too specific about the interface or
the ioctl name. Kindly suggest if you think there is a better way to
achieve this.

- Naveen

---
Here is a sample program demonstrating the same:

#define _GNU_SOURCE

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/perf_event.h>
#include <asm/unistd.h>

static long
perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
int cpu, int group_fd, unsigned long flags)
{
return syscall(__NR_perf_event_open, hw_event, pid, cpu,
group_fd, flags);
}

static void sigio_handler(int n, siginfo_t *info, void *uc)
{
fprintf (stderr, "Caught %s\n", info->si_code == POLL_HUP ? "POLL_HUP" :
(info->si_code == POLL_IN ? "POLL_IN" : "other signal"));

if (ioctl(info->si_fd, PERF_EVENT_IOC_REFRESH, 2) == -1)
perror("SIGIO: IOC_REFRESH");
}

int main(int argc, char **argv)
{
struct perf_event_attr pe;
struct sigaction act;
int fd;
void *buf;

memset(&act, 0, sizeof(act));
act.sa_sigaction = sigio_handler;
act.sa_flags = SA_SIGINFO;
sigaction(SIGIO, &act, 0);

memset(&pe, 0, sizeof(struct perf_event_attr));
pe.size = sizeof(struct perf_event_attr);
pe.type = PERF_TYPE_SOFTWARE;
pe.config = PERF_COUNT_SW_DUMMY;
pe.disabled = 1;
pe.sample_period = 1;
pe.context_switch = 1;

fd = perf_event_open(&pe, 0, -1, -1, 0);
if (fd == -1) {
fprintf(stderr, "Error opening leader %lx\n", pe.config);
exit(EXIT_FAILURE);
}

buf = mmap(NULL, sysconf(_SC_PAGESIZE) * 2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (buf == MAP_FAILED) {
fprintf(stderr, "Can't mmap buffer\n");
return -1;
}

if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_ASYNC) == -1)
return -2;

if (fcntl(fd, F_SETSIG, SIGIO) == -1)
return -3;

if (fcntl(fd, F_SETOWN, getpid()) == -1)
return -4;

if (ioctl(fd, PERF_EVENT_IOC_COUNT_RECORDS, 0) == -1)
return -5;

if (ioctl(fd, PERF_EVENT_IOC_REFRESH, 2) == -1)
return -6;

fprintf (stderr, "Sleep 1\n");
sleep(1);
fprintf (stderr, "Sleep 2\n");
sleep(1);
fprintf (stderr, "Sleep 3\n");
sleep(1);

/* Disable the event counter */
ioctl(fd, PERF_EVENT_IOC_DISABLE, 1);

close(fd);

return 0;
}

A sample output:
$ time ./cs
Sleep 1
Caught POLL_HUP
Sleep 2
Caught POLL_HUP
Sleep 3
Caught POLL_HUP

real 0m3.060s
user 0m0.001s
sys 0m0.005s


Naveen N. Rao (1):
kernel/events: Introduce IOC_COUNT_RECORDS

include/linux/perf_event.h | 1 +
include/uapi/linux/perf_event.h | 1 +
kernel/events/core.c | 16 +++++++++++++++-
kernel/events/ring_buffer.c | 9 +++++++++
4 files changed, 26 insertions(+), 1 deletion(-)

--
2.12.2