perf: Handle generic event types
[akaros.git] / tools / profile / perf / perf_core.c
1 /* Copyright (c) 2015-2016 Google Inc
2  * Davide Libenzi <dlibenzi@google.com>
3  * Barret Rhoden <brho@cs.berkeley.edu>
4  * Stephane Eranian <eranian@gmail.com> (perf_show_event_info() from libpfm4)
5  *
6  * See LICENSE for details. */
7
8 #include <ros/arch/msr-index.h>
9 #include <ros/arch/perfmon.h>
10 #include <ros/common.h>
11 #include <ros/memops.h>
12 #include <sys/types.h>
13 #include <stdint.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <ctype.h>
19 #include <limits.h>
20 #include <errno.h>
21 #include <regex.h>
22 #include <parlib/parlib.h>
23 #include <perfmon/err.h>
24 #include <perfmon/pfmlib.h>
25 #include "xlib.h"
26 #include "perfconv.h"
27 #include "akaros.h"
28 #include "perf_core.h"
29 #include "elf.h"
30
31 struct event_coords {
32         char *buffer;
33         const char *event;
34         const char *umask;
35 };
36
37 struct perf_generic_event {
38         char                                            *name;
39         uint32_t                                        type;
40         uint32_t                                        config;
41 };
42
43 struct perf_generic_event generic_events[] = {
44         { .name = "cycles",
45           .type = PERF_TYPE_HARDWARE,
46           .config = PERF_COUNT_HW_CPU_CYCLES,
47         },
48         { .name = "cpu-cycles",
49           .type = PERF_TYPE_HARDWARE,
50           .config = PERF_COUNT_HW_CPU_CYCLES,
51         },
52         { .name = "instructions",
53           .type = PERF_TYPE_HARDWARE,
54           .config = PERF_COUNT_HW_INSTRUCTIONS,
55         },
56         { .name = "cache-references",
57           .type = PERF_TYPE_HARDWARE,
58           .config = PERF_COUNT_HW_CACHE_REFERENCES,
59         },
60         { .name = "cache-misses",
61           .type = PERF_TYPE_HARDWARE,
62           .config = PERF_COUNT_HW_CACHE_MISSES,
63         },
64         { .name = "branches",
65           .type = PERF_TYPE_HARDWARE,
66           .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS,
67         },
68         { .name = "branch-instructions",
69           .type = PERF_TYPE_HARDWARE,
70           .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS,
71         },
72         { .name = "branch-misses",
73           .type = PERF_TYPE_HARDWARE,
74           .config = PERF_COUNT_HW_BRANCH_MISSES,
75         },
76         { .name = "bus-cycles",
77           .type = PERF_TYPE_HARDWARE,
78           .config = PERF_COUNT_HW_BUS_CYCLES,
79         },
80 };
81
82 static const char *perf_get_event_mask_name(const pfm_event_info_t *einfo,
83                                                                                         uint32_t mask)
84 {
85         int i;
86         pfm_event_attr_info_t ainfo;
87
88         ZERO_DATA(ainfo);
89         ainfo.size = sizeof(ainfo);
90         pfm_for_each_event_attr(i, einfo) {
91                 pfm_err_t err = pfm_get_event_attr_info(einfo->idx, i, PFM_OS_NONE,
92                                                                                                 &ainfo);
93
94                 if (err != PFM_SUCCESS) {
95                         fprintf(stderr, "Failed to get attribute info: %s\n",
96                                         pfm_strerror(err));
97                         exit(1);
98                 }
99                 if (ainfo.type == PFM_ATTR_UMASK) {
100                         if (mask == (uint32_t) ainfo.code)
101                                 return ainfo.name;
102                 }
103         }
104
105         return NULL;
106 }
107
108 void perf_initialize(int argc, char *argv[])
109 {
110         pfm_err_t err = pfm_initialize();
111
112         if (err != PFM_SUCCESS) {
113                 fprintf(stderr, "Unable to initialize perfmon library: %s\n",
114                                 pfm_strerror(err));
115                 exit(1);
116         }
117         symbol__elf_init();
118 }
119
120 void perf_finalize(void)
121 {
122         pfm_terminate();
123 }
124
125 /* This is arch-specific and maybe model specific in the future.  For some
126  * events, pfm4 gives us a pseudo encoding.  Those codes don't map to real
127  * hardware events and are meant to be interpreted by Linux for *other* HW
128  * events, e.g. in arch/x86/events/intel/core.c.
129  *
130  * While we're here, we can also take *real* encodings and treat them like
131  * pseudo encodings.  For instance, the arch event 0x3c (unhalted_core_cycles)
132  * can also be done with fixed counter 1.  This all assumes we have version 2 or
133  * later of Intel's perfmon. */
134 static void x86_handle_pseudo_encoding(struct perf_eventsel *sel)
135 {
136         uint8_t lower_byte;
137
138         switch (sel->ev.event & 0xffff) {
139         case 0xc0:      /* arch inst_retired */
140                 sel->ev.flags |= PERFMON_FIXED_EVENT;
141                 PMEV_SET_MASK(sel->ev.event, 0);
142                 PMEV_SET_EVENT(sel->ev.event, 0);
143                 return;
144         case 0x3c:      /* arch unhalted_core_cycles */
145                 sel->ev.flags |= PERFMON_FIXED_EVENT;
146                 PMEV_SET_MASK(sel->ev.event, 0);
147                 PMEV_SET_EVENT(sel->ev.event, 1);
148                 return;
149         case 0x13c:     /* arch unhalted_reference_cycles */
150         case 0x300:     /* pseudo encode: unhalted_reference_cycles */
151                 sel->ev.flags |= PERFMON_FIXED_EVENT;
152                 PMEV_SET_MASK(sel->ev.event, 0);
153                 PMEV_SET_EVENT(sel->ev.event, 2);
154                 return;
155         };
156         lower_byte = sel->ev.event & 0xff;
157         if ((lower_byte == 0x00) || (lower_byte == 0xff))
158                 fprintf(stderr, "Unhandled pseudo encoding %d\n", lower_byte);
159 }
160
161 /* Parse the string using pfm's lookup functions.  Returns TRUE on success and
162  * fills in parts of sel. */
163 static bool parse_pfm_encoding(const char *str, struct perf_eventsel *sel)
164 {
165         pfm_pmu_encode_arg_t encode;
166         int err;
167         char *ptr;
168
169         memset(&encode, 0, sizeof(encode));
170         encode.size = sizeof(encode);
171         encode.fstr = &ptr;
172         err = pfm_get_os_event_encoding(str, PFM_PLM3 | PFM_PLM0, PFM_OS_NONE,
173                                         &encode);
174         if (err)
175                 return FALSE;
176         strlcpy(sel->fq_str, ptr, MAX_FQSTR_SZ);
177         free(ptr);
178         if (encode.count == 0) {
179                 fprintf(stderr, "Found event %s, but it had no codes!\n", sel->fq_str);
180                 return FALSE;
181         }
182         sel->ev.event = encode.codes[0];
183         sel->eidx = encode.idx;
184         x86_handle_pseudo_encoding(sel);
185         sel->type = PERF_TYPE_RAW;
186         sel->config = PMEV_GET_MASK(sel->ev.event) | PMEV_GET_EVENT(sel->ev.event);
187         return TRUE;
188 }
189
190 static bool is_end_of_raw(char c)
191 {
192         return (c == ':') || (c == '\0');
193 }
194
195 /* Helper: given a string, if the event is a raw hex code, return its numeric
196  * value.  Returns -1 if it does not match a raw code.
197  *
198  * rNN[N][N][:,\0].  Begins with r, has at least two hexdigits, up to 4, and
199  * ends with : , or \0. */
200 static int extract_raw_code(const char *event)
201 {
202         int i;
203         char copy[5] = {0};
204
205         if (event[0] != 'r')
206                 return -1;
207         event++;
208         for (i = 0; i < 4; i++) {
209                 if (isxdigit(event[i]))
210                         continue;
211                 if (is_end_of_raw(event[i]))
212                         break;
213                 return -1;
214         }
215         if (!is_end_of_raw(event[i]))
216                 return -1;
217         /* 'i' tracks how many we found (i.e. every 'continue') */
218         if (i < 2)
219                 return -1;
220         /* need a null-terminated raw code for strtol. */
221         for (int j = 0; j < i; j++)
222                 copy[j] = event[j];
223         return strtol(copy, NULL, 16);
224 }
225
226 /* Takes any modifiers, e.g. u:k:etc, and sets the respective values in sel. */
227 static void parse_modifiers(const char *str, struct perf_eventsel *sel)
228 {
229         char *dup_str, *tok, *tok_save = 0;
230
231         dup_str = xstrdup(str);
232         for (tok = strtok_r(dup_str, ":", &tok_save);
233              tok;
234              tok = strtok_r(NULL, ":", &tok_save)) {
235
236                 switch (tok[0]) {
237                 case 'u':
238                         PMEV_SET_USR(sel->ev.event, 1);
239                         break;
240                 case 'k':
241                         PMEV_SET_OS(sel->ev.event, 1);
242                         break;
243                 case 'e':
244                         PMEV_SET_EDGE(sel->ev.event, 1);
245                         break;
246                 case 'p':
247                         PMEV_SET_PC(sel->ev.event, 1);
248                         break;
249                 case 't':
250                         PMEV_SET_ANYTH(sel->ev.event, 1);
251                         break;
252                 case 'i':
253                         PMEV_SET_INVCMSK(sel->ev.event, 1);
254                         break;
255                 case 'c':
256                         if (tok[1] != '=') {
257                                 fprintf(stderr, "Bad cmask tok %s, ignoring\n", tok);
258                                 break;
259                         }
260                         errno = 0;
261                         PMEV_SET_CMASK(sel->ev.event, strtoul(&tok[2], NULL, 0));
262                         if (errno)
263                                 fprintf(stderr, "Bad cmask tok %s, trying anyway\n", tok);
264                         break;
265                 }
266         }
267         free(dup_str);
268 }
269
270 /* Parse the string for a raw encoding.  Returns TRUE on success and fills in
271  * parts of sel.  It has basic modifiers, like pfm4, for setting bits in the
272  * event code.  This is arch specific, and is all x86 (intel) for now. */
273 static bool parse_raw_encoding(const char *str, struct perf_eventsel *sel)
274 {
275         int code = extract_raw_code(str);
276         char *colon;
277
278         if (code == -1)
279                 return FALSE;
280         sel->eidx = -1;
281         sel->ev.event = code;
282         strlcpy(sel->fq_str, str, MAX_FQSTR_SZ);
283         colon = strchr(str, ':');
284         if (colon)
285                 parse_modifiers(colon + 1, sel);
286         /* Note that we do not call x86_handle_pseudo_encoding here.  We'll submit
287          * exactly what the user asked us for - which also means no fixed counters
288          * for them (unless we want a :f: token or something). */
289         sel->type = PERF_TYPE_RAW;
290         sel->config = PMEV_GET_MASK(sel->ev.event) | PMEV_GET_EVENT(sel->ev.event);
291         return TRUE;
292 }
293
294 /* Helper, returns true is str is a generic event string, and fills in sel with
295  * the type and config. */
296 static bool generic_str_get_code(const char *str, struct perf_eventsel *sel)
297 {
298         char *colon = strchr(str, ':');
299         /* if there was no :, we compare as far as we can.  generic_events.name is a
300          * string literal, so strcmp() is fine. */
301         size_t len = colon ? colon - str : SIZE_MAX;
302
303         for (int i = 0; i < COUNT_OF(generic_events); i++) {
304                 if (!strncmp(generic_events[i].name, str, len)) {
305                         sel->type = generic_events[i].type;
306                         sel->config = generic_events[i].config;
307                         return TRUE;
308                 }
309         }
310         return FALSE;
311 }
312
313 /* TODO: this is arch-specific and possibly machine-specific. (intel for now).
314  * Basically a lot of our perf is arch-dependent. (e.g. PMEV_*). */
315 static bool arch_translate_generic(struct perf_eventsel *sel)
316 {
317         switch (sel->type) {
318         case PERF_TYPE_HARDWARE:
319                 /* These are the intel/x86 architectural perf events */
320                 switch (sel->config) {
321                 case PERF_COUNT_HW_CPU_CYCLES:
322                         PMEV_SET_MASK(sel->ev.event, 0x00);
323                         PMEV_SET_EVENT(sel->ev.event, 0x3c);
324                         break;
325                 case PERF_COUNT_HW_INSTRUCTIONS:
326                         PMEV_SET_MASK(sel->ev.event, 0x00);
327                         PMEV_SET_EVENT(sel->ev.event, 0xc0);
328                         break;
329                 case PERF_COUNT_HW_CACHE_REFERENCES:
330                         PMEV_SET_MASK(sel->ev.event, 0x4f);
331                         PMEV_SET_EVENT(sel->ev.event, 0x2e);
332                         break;
333                 case PERF_COUNT_HW_CACHE_MISSES:
334                         PMEV_SET_MASK(sel->ev.event, 0x41);
335                         PMEV_SET_EVENT(sel->ev.event, 0x2e);
336                         break;
337                 case PERF_COUNT_HW_BRANCH_INSTRUCTIONS:
338                         PMEV_SET_MASK(sel->ev.event, 0x00);
339                         PMEV_SET_EVENT(sel->ev.event, 0xc4);
340                         break;
341                 case PERF_COUNT_HW_BRANCH_MISSES:
342                         PMEV_SET_MASK(sel->ev.event, 0x00);
343                         PMEV_SET_EVENT(sel->ev.event, 0xc5);
344                         break;
345                 case PERF_COUNT_HW_BUS_CYCLES:
346                         /* Unhalted reference cycles */
347                         PMEV_SET_MASK(sel->ev.event, 0x01);
348                         PMEV_SET_EVENT(sel->ev.event, 0x3c);
349                         break;
350                 default:
351                         return FALSE;
352                 };
353                 break;
354         default:
355                 return FALSE;
356         };
357         /* This will make sure we use fixed counters if available */
358         x86_handle_pseudo_encoding(sel);
359         return TRUE;
360 }
361
362 /* Parse the string for a built-in encoding.  These are the perf defaults such
363  * as 'cycles' or 'cache-references.' Returns TRUE on success and fills in parts
364  * of sel. */
365 static bool parse_generic_encoding(const char *str, struct perf_eventsel *sel)
366 {
367         bool ret = FALSE;
368         char *colon;
369
370         if (!generic_str_get_code(str, sel))
371                 return FALSE;
372         switch (sel->type) {
373         case PERF_TYPE_HARDWARE:
374         case PERF_TYPE_HW_CACHE:
375                 ret = arch_translate_generic(sel);
376                 break;
377         };
378         if (!ret) {
379                 fprintf(stderr, "Unsupported built-in event %s\n", str);
380                 return FALSE;
381         }
382         strlcpy(sel->fq_str, str, MAX_FQSTR_SZ);
383         colon = strchr(str, ':');
384         if (colon)
385                 parse_modifiers(colon + 1, sel);
386         return TRUE;
387 }
388
389 /* Given an event description string, fills out sel with the info from the
390  * string such that it can be submitted to the OS.
391  *
392  * The caller can set more bits if they like, such as whether or not to
393  * interrupt on overflow, the sample_period, etc.  None of those settings are
394  * part of the event string.
395  *
396  * Kills the program on failure. */
397 struct perf_eventsel *perf_parse_event(const char *str)
398 {
399         struct perf_eventsel *sel = xzmalloc(sizeof(struct perf_eventsel));
400
401         sel->ev.user_data = (uint64_t)sel;
402         if (parse_generic_encoding(str, sel))
403                 goto success;
404         if (parse_pfm_encoding(str, sel))
405                 goto success;
406         if (parse_raw_encoding(str, sel))
407                 goto success;
408         free(sel);
409         fprintf(stderr, "Failed to parse event string %s\n", str);
410         exit(-1);
411 success:
412         if (!PMEV_GET_OS(sel->ev.event) && !PMEV_GET_USR(sel->ev.event)) {
413                 PMEV_SET_OS(sel->ev.event, 1);
414                 PMEV_SET_USR(sel->ev.event, 1);
415         }
416         PMEV_SET_EN(sel->ev.event, 1);
417         return sel;
418 }
419
420 static void perf_get_arch_info(int perf_fd, struct perf_arch_info *pai)
421 {
422         uint8_t cmdbuf[6 * sizeof(uint32_t)];
423         const uint8_t *rptr = cmdbuf;
424
425         cmdbuf[0] = PERFMON_CMD_CPU_CAPS;
426
427         xpwrite(perf_fd, cmdbuf, 1, 0);
428         xpread(perf_fd, cmdbuf, 6 * sizeof(uint32_t), 0);
429
430         rptr = get_le_u32(rptr, &pai->perfmon_version);
431         rptr = get_le_u32(rptr, &pai->proc_arch_events);
432         rptr = get_le_u32(rptr, &pai->bits_x_counter);
433         rptr = get_le_u32(rptr, &pai->counters_x_proc);
434         rptr = get_le_u32(rptr, &pai->bits_x_fix_counter);
435         rptr = get_le_u32(rptr, &pai->fix_counters_x_proc);
436 }
437
438 static int perf_open_event(int perf_fd, const struct core_set *cores,
439                                                    const struct perf_eventsel *sel)
440 {
441         uint8_t cmdbuf[1 + 3 * sizeof(uint64_t) + sizeof(uint32_t) +
442                                    CORE_SET_SIZE];
443         uint8_t *wptr = cmdbuf;
444         const uint8_t *rptr = cmdbuf;
445         uint32_t ped;
446         int i, j;
447
448         *wptr++ = PERFMON_CMD_COUNTER_OPEN;
449         wptr = put_le_u64(wptr, sel->ev.event);
450         wptr = put_le_u64(wptr, sel->ev.flags);
451         wptr = put_le_u64(wptr, sel->ev.trigger_count);
452         wptr = put_le_u64(wptr, sel->ev.user_data);
453
454         for (i = CORE_SET_SIZE - 1; (i >= 0) && !cores->core_set[i]; i--)
455                 ;
456         if (i < 0) {
457                 fprintf(stderr, "Performance event CPU set must not be empty\n");
458                 exit(1);
459         }
460         wptr = put_le_u32(wptr, i + 1);
461         for (j = 0; j <= i; j++)
462                 *wptr++ = cores->core_set[j];
463
464         xpwrite(perf_fd, cmdbuf, wptr - cmdbuf, 0);
465         xpread(perf_fd, cmdbuf, sizeof(uint32_t), 0);
466
467         rptr = get_le_u32(rptr, &ped);
468
469         return (int) ped;
470 }
471
472 static uint64_t *perf_get_event_values(int perf_fd, int ped, size_t *pnvalues)
473 {
474         ssize_t rsize;
475         uint32_t i, n;
476         uint64_t *values;
477         uint64_t temp;
478         size_t bufsize = 3 * sizeof(uint64_t) + sizeof(uint32_t) +
479                 MAX_NUM_CORES * sizeof(uint64_t);
480         uint8_t *cmdbuf = xmalloc(bufsize);
481         uint8_t *wptr = cmdbuf;
482         const uint8_t *rptr = cmdbuf;
483
484         *wptr++ = PERFMON_CMD_COUNTER_STATUS;
485         wptr = put_le_u32(wptr, ped);
486
487         xpwrite(perf_fd, cmdbuf, wptr - cmdbuf, 0);
488         rsize = pread(perf_fd, cmdbuf, bufsize, 0);
489
490         if (rsize < (3 * sizeof(uint64_t) + sizeof(uint32_t))) {
491                 fprintf(stderr, "Invalid read size while fetching event status: %ld\n",
492                                 rsize);
493                 exit(1);
494         }
495
496         /* TODO: The kernel lies to us about this, it's all 0. */
497         rptr = get_le_u64(rptr, &temp);         /* discard ev.event */
498         rptr = get_le_u64(rptr, &temp);         /* discard ev.flags */
499         rptr = get_le_u64(rptr, &temp);         /* discard ev.trigger_count */
500
501         rptr = get_le_u32(rptr, &n);
502         if (((rptr - cmdbuf) + n * sizeof(uint64_t)) > rsize) {
503                 fprintf(stderr, "Invalid read size while fetching event status: %ld\n",
504                                 rsize);
505                 exit(1);
506         }
507         values = xmalloc(n * sizeof(uint64_t));
508         for (i = 0; i < n; i++)
509                 rptr = get_le_u64(rptr, values + i);
510         free(cmdbuf);
511
512         *pnvalues = n;
513
514         return values;
515 }
516
517 static void perf_close_event(int perf_fd, int ped)
518 {
519         uint8_t cmdbuf[1 + sizeof(uint32_t)];
520         uint8_t *wptr = cmdbuf;
521
522         *wptr++ = PERFMON_CMD_COUNTER_CLOSE;
523         wptr = put_le_u32(wptr, ped);
524
525         xpwrite(perf_fd, cmdbuf, wptr - cmdbuf, 0);
526 }
527
528 static void perf_enable_sampling(int kpctl_fd)
529 {
530         static const char * const enable_str = "start";
531
532         xwrite(kpctl_fd, enable_str, strlen(enable_str));
533 }
534
535 static void perf_disable_sampling(int kpctl_fd)
536 {
537         static const char * const disable_str = "stop";
538
539         xwrite(kpctl_fd, disable_str, strlen(disable_str));
540 }
541
542 static void perf_flush_sampling(int kpctl_fd)
543 {
544         static const char * const flush_str = "flush";
545
546         xwrite(kpctl_fd, flush_str, strlen(flush_str));
547 }
548
549 struct perf_context *perf_create_context(const struct perf_context_config *cfg)
550 {
551         struct perf_context *pctx = xzmalloc(sizeof(struct perf_context));
552
553         pctx->perf_fd = xopen(cfg->perf_file, O_RDWR, 0);
554         pctx->kpctl_fd = xopen(cfg->kpctl_file, O_RDWR, 0);
555         perf_get_arch_info(pctx->perf_fd, &pctx->pai);
556         perf_enable_sampling(pctx->kpctl_fd);
557
558         return pctx;
559 }
560
561 void perf_free_context(struct perf_context *pctx)
562 {
563         for (int i = 0; i < pctx->event_count; i++)
564                 perf_close_event(pctx->perf_fd, pctx->events[i].ped);
565         perf_disable_sampling(pctx->kpctl_fd);
566         close(pctx->kpctl_fd);
567         close(pctx->perf_fd);
568         free(pctx);
569 }
570
571 void perf_flush_context_traces(struct perf_context *pctx)
572 {
573         perf_flush_sampling(pctx->kpctl_fd);
574 }
575
576 void perf_context_event_submit(struct perf_context *pctx,
577                                                            const struct core_set *cores,
578                                                            const struct perf_eventsel *sel)
579 {
580         struct perf_event *pevt = pctx->events + pctx->event_count;
581
582         if (pctx->event_count >= COUNT_OF(pctx->events)) {
583                 fprintf(stderr, "Too many open events: %d\n", pctx->event_count);
584                 exit(1);
585         }
586         pctx->event_count++;
587         pevt->cores = *cores;
588         pevt->sel = *sel;
589         pevt->ped = perf_open_event(pctx->perf_fd, cores, sel);
590 }
591
592 void perf_context_show_values(struct perf_context *pctx, FILE *file)
593 {
594         for (int i = 0; i < pctx->event_count; i++) {
595                 size_t nvalues;
596                 struct perf_eventsel *sel = &pctx->events[i].sel;
597                 uint64_t *values = perf_get_event_values(pctx->perf_fd,
598                                                                                                  pctx->events[i].ped,
599                                                                                                  &nvalues);
600
601                 fprintf(file, "Event: %s, final code %p%s, trigger count %d\n\t",
602                         sel->fq_str, sel->ev.event,
603                         perfmon_is_fixed_event(&sel->ev) ? " (fixed)" : "",
604                         sel->ev.trigger_count);
605                 for (size_t j = 0; j < nvalues; j++)
606                         fprintf(file, "%lu ", values[j]);
607                 fprintf(file, "\n");
608
609                 free(values);
610         }
611 }
612
613 static void perf_print_event_flags(const pfm_event_info_t *info, FILE *file)
614 {
615         int n = 0;
616
617         if (info->is_precise) {
618                 fputs("[precise] ", file);
619                 n++;
620         }
621         if (!n)
622                 fputs("None", file);
623 }
624
625 static void perf_print_attr_flags(const pfm_event_attr_info_t *info, FILE *file)
626 {
627         int n = 0;
628
629         if (info->is_dfl) {
630                 fputs("[default] ", file);
631                 n++;
632         }
633         if (info->is_precise) {
634                 fputs("[precise] ", file);
635                 n++;
636         }
637         if (!n)
638                 fputs("None ", file);
639 }
640
641 /* Ported from libpfm4 */
642 static void perf_show_event_info(const pfm_event_info_t *info,
643                                                                  const pfm_pmu_info_t *pinfo, FILE *file)
644 {
645         static const char * const srcs[PFM_ATTR_CTRL_MAX] = {
646                 [PFM_ATTR_CTRL_UNKNOWN] = "???",
647                 [PFM_ATTR_CTRL_PMU] = "PMU",
648                 [PFM_ATTR_CTRL_PERF_EVENT] = "perf_event",
649         };
650         pfm_event_attr_info_t ainfo;
651         int i, mod = 0, um = 0;
652
653         fprintf(file, "#-----------------------------\n"
654                         "IDX      : %d\n"
655                         "PMU name : %s (%s)\n"
656                         "Name     : %s\n"
657                         "Equiv    : %s\n",
658                         info->idx, pinfo->name, pinfo->desc,
659                         info->name, info->equiv ? info->equiv : "None");
660
661         fprintf(file, "Flags    : ");
662         perf_print_event_flags(info, file);
663         fputc('\n', file);
664
665         fprintf(file, "Desc     : %s\n", info->desc ? info->desc :
666                         "no description available");
667         fprintf(file, "Code     : 0x%"PRIx64"\n", info->code);
668
669         ZERO_DATA(ainfo);
670         ainfo.size = sizeof(ainfo);
671
672         pfm_for_each_event_attr(i, info) {
673                 const char *src;
674                 pfm_err_t err = pfm_get_event_attr_info(info->idx, i, PFM_OS_NONE,
675                                                                                                 &ainfo);
676
677                 if (err != PFM_SUCCESS) {
678                         fprintf(stderr, "Failed to get attribute info: %s\n",
679                                         pfm_strerror(err));
680                         exit(1);
681                 }
682
683                 if (ainfo.ctrl >= PFM_ATTR_CTRL_MAX) {
684                         fprintf(stderr, "event: %s has unsupported attribute source %d",
685                                         info->name, ainfo.ctrl);
686                         ainfo.ctrl = PFM_ATTR_CTRL_UNKNOWN;
687                 }
688                 src = srcs[ainfo.ctrl];
689                 switch (ainfo.type) {
690                         case PFM_ATTR_UMASK:
691                                 fprintf(file, "Umask-%02u : 0x%02"PRIx64" : %s : [%s] : ",
692                                                 um, ainfo.code, src, ainfo.name);
693                                 perf_print_attr_flags(&ainfo, file);
694                                 fputc(':', file);
695                                 if (ainfo.equiv)
696                                         fprintf(file, " Alias to %s", ainfo.equiv);
697                                 else
698                                         fprintf(file, " %s", ainfo.desc);
699                                 fputc('\n', file);
700                                 um++;
701                                 break;
702                         case PFM_ATTR_MOD_BOOL:
703                                 fprintf(file, "Modif-%02u : 0x%02"PRIx64" : %s : [%s] : "
704                                                 "%s (boolean)\n", mod, ainfo.code, src, ainfo.name,
705                                                 ainfo.desc);
706                                 mod++;
707                                 break;
708                         case PFM_ATTR_MOD_INTEGER:
709                                 fprintf(file, "Modif-%02u : 0x%02"PRIx64" : %s : [%s] : "
710                                                 "%s (integer)\n", mod, ainfo.code, src, ainfo.name,
711                                                 ainfo.desc);
712                                 mod++;
713                                 break;
714                         default:
715                                 fprintf(file, "Attr-%02u  : 0x%02"PRIx64" : %s : [%s] : %s\n",
716                                                 i, ainfo.code, ainfo.name, src, ainfo.desc);
717                 }
718         }
719 }
720
721 void perf_show_events(const char *rx, FILE *file)
722 {
723         int pmu;
724         regex_t crx;
725         pfm_pmu_info_t pinfo;
726         pfm_event_info_t info;
727         char fullname[256];
728
729         if (rx && regcomp(&crx, rx, REG_ICASE)) {
730                 fprintf(stderr, "Failed to compile event regex: '%s'\n", rx);
731                 exit(1);
732         }
733
734     ZERO_DATA(pinfo);
735     pinfo.size = sizeof(pinfo);
736     ZERO_DATA(info);
737     info.size = sizeof(info);
738
739         pfm_for_all_pmus(pmu) {
740                 pfm_err_t err = pfm_get_pmu_info(pmu, &pinfo);
741
742                 if (err != PFM_SUCCESS || !pinfo.is_present)
743                         continue;
744
745                 for (int i = pinfo.first_event; i != -1; i = pfm_get_event_next(i)) {
746                         err = pfm_get_event_info(i, PFM_OS_NONE, &info);
747                         if (err != PFM_SUCCESS) {
748                                 fprintf(stderr, "Failed to get event info: %s\n",
749                                                 pfm_strerror(err));
750                                 exit(1);
751                         }
752                         snprintf(fullname, sizeof(fullname), "%s::%s", pinfo.name,
753                                          info.name);
754                         if (!rx || regexec(&crx, fullname, 0, NULL, 0) == 0)
755                                 perf_show_event_info(&info, &pinfo, file);
756                 }
757         }
758         if (rx)
759                 regfree(&crx);
760 }
761
762 void perf_convert_trace_data(struct perfconv_context *cctx, const char *input,
763                                                          const char *output)
764 {
765         FILE *infile, *outfile;
766         size_t ksize;
767         char kpath[1024];
768
769         infile = xfopen(input, "rb");
770         if (xfsize(infile) > 0) {
771                 outfile = xfopen(output, "wb");
772
773                 perfconv_add_kernel_mmap(cctx);
774                 perfconv_add_kernel_buildid(cctx);
775                 perfconv_process_input(cctx, infile, outfile);
776
777                 fclose(outfile);
778         }
779         fclose(infile);
780 }