1 #include <unistd.h>
2 #include <sys/syscall.h>
3 #include <sys/mman.h>
4 #include <signal.h>
5 #include <linux/perf_event.h>
6
7 #include <tracefs.h>
8
perf_init_pe(struct perf_event_attr * pe)9 static void perf_init_pe(struct perf_event_attr *pe)
10 {
11 memset(pe, 0, sizeof(struct perf_event_attr));
12 pe->type = PERF_TYPE_SOFTWARE;
13 pe->sample_type = PERF_SAMPLE_CPU;
14 pe->size = sizeof(struct perf_event_attr);
15 pe->config = PERF_COUNT_HW_CPU_CYCLES;
16 pe->disabled = 1;
17 pe->exclude_kernel = 1;
18 pe->freq = 1;
19 pe->sample_freq = 1000;
20 pe->inherit = 1;
21 pe->mmap = 1;
22 pe->comm = 1;
23 pe->task = 1;
24 pe->precise_ip = 1;
25 pe->sample_id_all = 1;
26 pe->read_format = PERF_FORMAT_ID |
27 PERF_FORMAT_TOTAL_TIME_ENABLED|
28 PERF_FORMAT_TOTAL_TIME_RUNNING;
29
30 }
31
perf_event_open(struct perf_event_attr * event,pid_t pid,int cpu,int group_fd,unsigned long flags)32 static long perf_event_open(struct perf_event_attr *event, pid_t pid,
33 int cpu, int group_fd, unsigned long flags)
34 {
35 return syscall(__NR_perf_event_open, event, pid, cpu, group_fd, flags);
36 }
37
38 #define MAP_SIZE (9 * getpagesize())
39
perf_mmap(int fd)40 static struct perf_event_mmap_page *perf_mmap(int fd)
41 {
42 struct perf_event_mmap_page *perf_mmap;
43
44 /* associate a buffer with the file */
45 perf_mmap = mmap(NULL, MAP_SIZE,
46 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
47 if (perf_mmap == MAP_FAILED)
48 return NULL;
49
50 return perf_mmap;
51 }
52
perf_read_maps(int cpu,int * shift,int * mult,long long * offset)53 static int perf_read_maps(int cpu, int *shift, int *mult, long long *offset)
54 {
55 struct perf_event_attr perf_attr;
56 struct perf_event_mmap_page *mpage;
57 int fd;
58
59 /* We succeed if theres' nothing to do! */
60 if (!shift && !mult && !offset)
61 return 0;
62
63 perf_init_pe(&perf_attr);
64 fd = perf_event_open(&perf_attr, getpid(), cpu, -1, 0);
65 if (fd < 0)
66 return -1;
67
68 mpage = perf_mmap(fd);
69 if (!mpage) {
70 close(fd);
71 return -1;
72 }
73
74 if (shift)
75 *shift = mpage->time_shift;
76 if (mult)
77 *mult = mpage->time_mult;
78 if (offset)
79 *offset = mpage->time_offset;
80 munmap(mpage, MAP_SIZE);
81 return 0;
82 }
83
84 /**
85 * tracefs_time_conversion - Find how the kernel converts the raw counters
86 * @cpu: The CPU to check for
87 * @shift: If non-NULL it will be set to the shift value
88 * @mult: If non-NULL it will be set to the multiplier value
89 * @offset: If non-NULL it will be set to the offset
90 */
tracefs_time_conversion(int cpu,int * shift,int * mult,long long * offset)91 int tracefs_time_conversion(int cpu, int *shift, int *mult, long long *offset)
92 {
93 return perf_read_maps(cpu, shift, mult, offset);
94 }
95