Skip to content

Instantly share code, notes, and snippets.

@o-
Created December 19, 2019 07:13
Show Gist options
  • Save o-/6d4c05546431dbd3d9c0f9b23a98ee4c to your computer and use it in GitHub Desktop.
Save o-/6d4c05546431dbd3d9c0f9b23a98ee4c to your computer and use it in GitHub Desktop.
#define _GNU_SOURCE 1
#include <asm/unistd.h>
#include <fcntl.h>
#include <linux/perf_event.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
long perf_event_open(struct perf_event_attr* event_attr, pid_t pid, int cpu, int group_fd, unsigned long flags)
{
return syscall(__NR_perf_event_open, event_attr, pid, cpu, group_fd, flags);
}
volatile int fd;
volatile char gotPerfEvent = 0;
static void perf_event_handler(int signum, siginfo_t* info, void* ucontext) {
if(info->si_code != POLL_HUP) {
// Only POLL_HUP should happen.
exit(EXIT_FAILURE);
}
gotPerfEvent = 1;
ioctl(info->si_fd, PERF_EVENT_IOC_REFRESH, 1);
}
int main(int argc, char** argv)
{
int signo = SIGRTMIN + 1;
// Configure signal handler
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_sigaction = perf_event_handler;
sa.sa_flags = SA_SIGINFO;
// Setup signal handler
if (sigaction(signo, &sa, NULL) < 0) {
fprintf(stderr,"Error setting up signal handler\n");
perror("sigaction");
exit(EXIT_FAILURE);
}
struct perf_event_attr pe;
memset(&pe, 0, sizeof(struct perf_event_attr));
pe.type = PERF_TYPE_HARDWARE;
pe.size = sizeof(struct perf_event_attr);
pe.config = PERF_COUNT_SW_TASK_CLOCK;
pe.disabled = 1;
pe.sample_period = 1000;
pe.exclude_kernel = 1;
pe.exclude_hv = 1;
pe.exclude_idle = 1;
pid_t pid = 0; // measure the current process/thread
int cpu = -1; // measure on any cpu
int group_fd = -1;
unsigned long flags = 0;
fd = perf_event_open(&pe, pid, cpu, group_fd, flags);
if (fd == -1) {
fprintf(stderr, "Error opening leader %llx\n", pe.config);
perror("perf_event_open");
exit(EXIT_FAILURE);
}
// Setup event handler for overflow signals
fcntl(fd, F_SETFL, O_NONBLOCK|O_ASYNC);
fcntl(fd, F_SETSIG, signo);
fcntl(fd, F_SETOWN, getpid());
ioctl(fd, PERF_EVENT_IOC_RESET, 0); // Reset event counter to 0
ioctl(fd, PERF_EVENT_IOC_REFRESH, 1);
// Start monitoring
for(int i = 0; i < 1000; i++) {
putchar('.');
if (gotPerfEvent) {
long long counter;
read(fd, &counter, sizeof(long long)); // Read event counter value
printf("\nUsed %lld instructions\n", counter);
gotPerfEvent = 0;
}
}
// End monitoring
ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); // Disable event
close(fd);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment