149 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright 2013, Michael Ellerman, IBM Corp.4 */5 6#define _GNU_SOURCE7#include <unistd.h>8#include <sys/syscall.h>9#include <string.h>10#include <stdio.h>11#include <stdbool.h>12#include <sys/ioctl.h>13 14#include "event.h"15 16 17int perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu,18 int group_fd, unsigned long flags)19{20 return syscall(__NR_perf_event_open, attr, pid, cpu,21 group_fd, flags);22}23 24static void __event_init_opts(struct event *e, u64 config,25 int type, char *name, bool sampling)26{27 memset(e, 0, sizeof(*e));28 29 e->name = name;30 31 e->attr.type = type;32 e->attr.config = config;33 e->attr.size = sizeof(e->attr);34 /* This has to match the structure layout in the header */35 e->attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | \36 PERF_FORMAT_TOTAL_TIME_RUNNING;37 if (sampling) {38 e->attr.sample_period = 1000;39 e->attr.sample_type = PERF_SAMPLE_REGS_INTR;40 e->attr.disabled = 1;41 }42}43 44void event_init_opts(struct event *e, u64 config, int type, char *name)45{46 __event_init_opts(e, config, type, name, false);47}48 49void event_init_named(struct event *e, u64 config, char *name)50{51 event_init_opts(e, config, PERF_TYPE_RAW, name);52}53 54void event_init(struct event *e, u64 config)55{56 event_init_opts(e, config, PERF_TYPE_RAW, "event");57}58 59void event_init_sampling(struct event *e, u64 config)60{61 __event_init_opts(e, config, PERF_TYPE_RAW, "event", true);62}63 64#define PERF_CURRENT_PID 065#define PERF_NO_PID -166#define PERF_NO_CPU -167#define PERF_NO_GROUP -168 69int event_open_with_options(struct event *e, pid_t pid, int cpu, int group_fd)70{71 e->fd = perf_event_open(&e->attr, pid, cpu, group_fd, 0);72 if (e->fd == -1) {73 perror("perf_event_open");74 return -1;75 }76 77 return 0;78}79 80int event_open_with_group(struct event *e, int group_fd)81{82 return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, group_fd);83}84 85int event_open_with_pid(struct event *e, pid_t pid)86{87 return event_open_with_options(e, pid, PERF_NO_CPU, PERF_NO_GROUP);88}89 90int event_open_with_cpu(struct event *e, int cpu)91{92 return event_open_with_options(e, PERF_NO_PID, cpu, PERF_NO_GROUP);93}94 95int event_open(struct event *e)96{97 return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, PERF_NO_GROUP);98}99 100void event_close(struct event *e)101{102 close(e->fd);103}104 105int event_enable(struct event *e)106{107 return ioctl(e->fd, PERF_EVENT_IOC_ENABLE);108}109 110int event_disable(struct event *e)111{112 return ioctl(e->fd, PERF_EVENT_IOC_DISABLE);113}114 115int event_reset(struct event *e)116{117 return ioctl(e->fd, PERF_EVENT_IOC_RESET);118}119 120int event_read(struct event *e)121{122 int rc;123 124 rc = read(e->fd, &e->result, sizeof(e->result));125 if (rc != sizeof(e->result)) {126 fprintf(stderr, "read error on event %p!\n", e);127 return -1;128 }129 130 return 0;131}132 133void event_report_justified(struct event *e, int name_width, int result_width)134{135 printf("%*s: result %*llu ", name_width, e->name, result_width,136 e->result.value);137 138 if (e->result.running == e->result.enabled)139 printf("running/enabled %llu\n", e->result.running);140 else141 printf("running %llu enabled %llu\n", e->result.running,142 e->result.enabled);143}144 145void event_report(struct event *e)146{147 event_report_justified(e, 0, 0);148}149