1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright 2013, Michael Ellerman, IBM Corp. 4 */ 5 6 #define _GNU_SOURCE 7 #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 17 int 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 24 static 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 44 void event_init_opts(struct event *e, u64 config, int type, char *name) 45 { 46 __event_init_opts(e, config, type, name, false); 47 } 48 49 void event_init_named(struct event *e, u64 config, char *name) 50 { 51 event_init_opts(e, config, PERF_TYPE_RAW, name); 52 } 53 54 void event_init(struct event *e, u64 config) 55 { 56 event_init_opts(e, config, PERF_TYPE_RAW, "event"); 57 } 58 59 void 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 0 65 #define PERF_NO_PID -1 66 #define PERF_NO_CPU -1 67 #define PERF_NO_GROUP -1 68 69 int 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 80 int 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 85 int 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 90 int 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 95 int event_open(struct event *e) 96 { 97 return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, PERF_NO_GROUP); 98 } 99 100 void event_close(struct event *e) 101 { 102 close(e->fd); 103 } 104 105 int event_enable(struct event *e) 106 { 107 return ioctl(e->fd, PERF_EVENT_IOC_ENABLE); 108 } 109 110 int event_disable(struct event *e) 111 { 112 return ioctl(e->fd, PERF_EVENT_IOC_DISABLE); 113 } 114 115 int event_reset(struct event *e) 116 { 117 return ioctl(e->fd, PERF_EVENT_IOC_RESET); 118 } 119 120 int 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 133 void 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 else 141 printf("running %llu enabled %llu\n", e->result.running, 142 e->result.enabled); 143 } 144 145 void event_report(struct event *e) 146 { 147 event_report_justified(e, 0, 0); 148 } 149