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