perf: Use libpfm4 and Linux style event strings
[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
30 struct event_coords {
31         char *buffer;
32         const char *event;
33         const char *umask;
34 };
35
36 static const char *perf_get_event_mask_name(const pfm_event_info_t *einfo,
37                                                                                         uint32_t mask)
38 {
39         int i;
40         pfm_event_attr_info_t ainfo;
41
42         ZERO_DATA(ainfo);
43         ainfo.size = sizeof(ainfo);
44         pfm_for_each_event_attr(i, einfo) {
45                 pfm_err_t err = pfm_get_event_attr_info(einfo->idx, i, PFM_OS_NONE,
46                                                                                                 &ainfo);
47
48                 if (err != PFM_SUCCESS) {
49                         fprintf(stderr, "Failed to get attribute info: %s\n",
50                                         pfm_strerror(err));
51                         exit(1);
52                 }
53                 if (ainfo.type == PFM_ATTR_UMASK) {
54                         if (mask == (uint32_t) ainfo.code)
55                                 return ainfo.name;
56                 }
57         }
58
59         return NULL;
60 }
61
62 void perf_initialize(int argc, char *argv[])
63 {
64         pfm_err_t err = pfm_initialize();
65
66         if (err != PFM_SUCCESS) {
67                 fprintf(stderr, "Unable to initialize perfmon library: %s\n",
68                                 pfm_strerror(err));
69                 exit(1);
70         }
71 }
72
73 void perf_finalize(void)
74 {
75         pfm_terminate();
76 }
77
78 /* This is arch-specific and maybe model specific in the future.  For some
79  * events, pfm4 gives us a pseudo encoding.  Those codes don't map to real
80  * hardware events and are meant to be interpreted by Linux for *other* HW
81  * events, e.g. in arch/x86/events/intel/core.c.
82  *
83  * While we're here, we can also take *real* encodings and treat them like
84  * pseudo encodings.  For instance, the arch event 0x3c (unhalted_core_cycles)
85  * can also be done with fixed counter 1.  This all assumes we have version 2 or
86  * later of Intel's perfmon. */
87 static void x86_handle_pseudo_encoding(struct perf_eventsel *sel)
88 {
89         uint8_t lower_byte;
90
91         switch (sel->ev.event & 0xffff) {
92         case 0xc0:      /* arch inst_retired */
93                 sel->ev.flags |= PERFMON_FIXED_EVENT;
94                 PMEV_SET_MASK(sel->ev.event, 0);
95                 PMEV_SET_EVENT(sel->ev.event, 0);
96                 return;
97         case 0x3c:      /* arch unhalted_core_cycles */
98                 sel->ev.flags |= PERFMON_FIXED_EVENT;
99                 PMEV_SET_MASK(sel->ev.event, 0);
100                 PMEV_SET_EVENT(sel->ev.event, 1);
101                 return;
102         case 0x13c:     /* arch unhalted_reference_cycles */
103         case 0x300:     /* pseudo encode: unhalted_reference_cycles */
104                 sel->ev.flags |= PERFMON_FIXED_EVENT;
105                 PMEV_SET_MASK(sel->ev.event, 0);
106                 PMEV_SET_EVENT(sel->ev.event, 2);
107                 return;
108         };
109         lower_byte = sel->ev.event & 0xff;
110         if ((lower_byte == 0x00) || (lower_byte == 0xff))
111                 fprintf(stderr, "Unhandled pseudo encoding %d\n", lower_byte);
112 }
113
114 /* Parse the string using pfm's lookup functions.  Returns TRUE on success and
115  * fills in parts of sel. */
116 static bool parse_os_encoding(const char *str, struct perf_eventsel *sel)
117 {
118         pfm_pmu_encode_arg_t encode;
119         int err;
120         char *ptr;
121
122         memset(&encode, 0, sizeof(encode));
123         encode.size = sizeof(encode);
124         encode.fstr = &ptr;
125         err = pfm_get_os_event_encoding(str, PFM_PLM3 | PFM_PLM0, PFM_OS_NONE,
126                                         &encode);
127         if (err)
128                 return FALSE;
129         strlcpy(sel->fq_str, ptr, MAX_FQSTR_SZ);
130         free(ptr);
131         if (encode.count == 0) {
132                 fprintf(stderr, "Found event %s, but it had no codes!\n", sel->fq_str);
133                 return FALSE;
134         }
135         sel->ev.event = encode.codes[0];
136         sel->eidx = encode.idx;
137         x86_handle_pseudo_encoding(sel);
138         return TRUE;
139 }
140
141 static bool is_end_of_raw(char c)
142 {
143         return (c == ':') || (c == '\0');
144 }
145
146 /* Helper: given a string, if the event is a raw hex code, return its numeric
147  * value.  Returns -1 if it does not match a raw code.
148  *
149  * rNN[N][N][:,\0].  Begins with r, has at least two hexdigits, up to 4, and
150  * ends with : , or \0. */
151 static int extract_raw_code(const char *event)
152 {
153         int i;
154         char copy[5] = {0};
155
156         if (event[0] != 'r')
157                 return -1;
158         event++;
159         for (i = 0; i < 4; i++) {
160                 if (isxdigit(event[i]))
161                         continue;
162                 if (is_end_of_raw(event[i]))
163                         break;
164                 return -1;
165         }
166         if (!is_end_of_raw(event[i]))
167                 return -1;
168         /* 'i' tracks how many we found (i.e. every 'continue') */
169         if (i < 2)
170                 return -1;
171         /* need a null-terminated raw code for strtol. */
172         for (int j = 0; j < i; j++)
173                 copy[j] = event[j];
174         return strtol(copy, NULL, 16);
175 }
176
177 /* Parse the string for a raw encoding.  Returns TRUE on success and fills in
178  * parts of sel.  It has basic modifiers, like pfm4, for setting bits in the
179  * event code.  This is arch specific, and is all x86 (intel) for now. */
180 static bool parse_raw_encoding(const char *str, struct perf_eventsel *sel)
181 {
182         int code = extract_raw_code(str);
183         char *dup_str, *tok_save, *tok;
184
185         if (code == -1)
186                 return FALSE;
187         sel->eidx = -1;
188         sel->ev.event = code;
189         strncpy(sel->fq_str, str, MAX_FQSTR_SZ);
190         dup_str = xstrdup(str);
191         tok = strtok_r(dup_str, ":", &tok_save);
192         assert(tok);    /* discard first token; it must exist */
193         while ((tok = strtok_r(NULL, ":", &tok_save))) {
194                 switch (tok[0]) {
195                 case 'u':
196                         PMEV_SET_USR(sel->ev.event, 1);
197                         break;
198                 case 'k':
199                         PMEV_SET_OS(sel->ev.event, 1);
200                         break;
201                 case 'e':
202                         PMEV_SET_EDGE(sel->ev.event, 1);
203                         break;
204                 case 'p':
205                         PMEV_SET_PC(sel->ev.event, 1);
206                         break;
207                 case 't':
208                         PMEV_SET_ANYTH(sel->ev.event, 1);
209                         break;
210                 case 'i':
211                         PMEV_SET_INVCMSK(sel->ev.event, 1);
212                         break;
213                 case 'c':
214                         if (tok[1] != '=') {
215                                 fprintf(stderr, "Bad cmask tok %s, ignoring\n", tok);
216                                 break;
217                         }
218                         errno = 0;
219                         PMEV_SET_CMASK(sel->ev.event, strtoul(&tok[2], NULL, 0));
220                         if (errno)
221                                 fprintf(stderr, "Bad cmask tok %s, trying anyway\n", tok);
222                         break;
223                 }
224         }
225         free(dup_str);
226         /* Note that we do not call x86_handle_pseudo_encoding here.  We'll submit
227          * exactly what the user asked us for - which also means no fixed counters
228          * for them (unless we want a :f: token or something). */
229         return TRUE;
230 }
231
232 /* Given an event description string, fills out sel with the info from the
233  * string such that it can be submitted to the OS.
234  *
235  * The caller can set more bits if they like, such as whether or not to
236  * interrupt on overflow, the sample_period, etc.  None of those settings are
237  * part of the event string.
238  *
239  * Kills the program on failure. */
240 void perf_parse_event(const char *str, struct perf_eventsel *sel)
241 {
242         ZERO_DATA(*sel);
243         if (parse_os_encoding(str, sel))
244                 goto success;
245         if (parse_raw_encoding(str, sel))
246                 goto success;
247         fprintf(stderr, "Failed to parse event string %s\n", str);
248         exit(-1);
249 success:
250         if (!PMEV_GET_OS(sel->ev.event) && !PMEV_GET_USR(sel->ev.event)) {
251                 PMEV_SET_OS(sel->ev.event, 1);
252                 PMEV_SET_USR(sel->ev.event, 1);
253         }
254         PMEV_SET_EN(sel->ev.event, 1);
255 }
256
257 static void perf_get_arch_info(int perf_fd, struct perf_arch_info *pai)
258 {
259         uint8_t cmdbuf[6 * sizeof(uint32_t)];
260         const uint8_t *rptr = cmdbuf;
261
262         cmdbuf[0] = PERFMON_CMD_CPU_CAPS;
263
264         xpwrite(perf_fd, cmdbuf, 1, 0);
265         xpread(perf_fd, cmdbuf, 6 * sizeof(uint32_t), 0);
266
267         rptr = get_le_u32(rptr, &pai->perfmon_version);
268         rptr = get_le_u32(rptr, &pai->proc_arch_events);
269         rptr = get_le_u32(rptr, &pai->bits_x_counter);
270         rptr = get_le_u32(rptr, &pai->counters_x_proc);
271         rptr = get_le_u32(rptr, &pai->bits_x_fix_counter);
272         rptr = get_le_u32(rptr, &pai->fix_counters_x_proc);
273 }
274
275 static int perf_open_event(int perf_fd, const struct core_set *cores,
276                                                    const struct perf_eventsel *sel)
277 {
278         uint8_t cmdbuf[1 + 3 * sizeof(uint64_t) + sizeof(uint32_t) +
279                                    CORE_SET_SIZE];
280         uint8_t *wptr = cmdbuf;
281         const uint8_t *rptr = cmdbuf;
282         uint32_t ped;
283         int i, j;
284
285         *wptr++ = PERFMON_CMD_COUNTER_OPEN;
286         wptr = put_le_u64(wptr, sel->ev.event);
287         wptr = put_le_u64(wptr, sel->ev.flags);
288         wptr = put_le_u64(wptr, sel->ev.trigger_count);
289
290         for (i = CORE_SET_SIZE - 1; (i >= 0) && !cores->core_set[i]; i--)
291                 ;
292         if (i < 0) {
293                 fprintf(stderr, "Performance event CPU set must not be empty\n");
294                 exit(1);
295         }
296         wptr = put_le_u32(wptr, i + 1);
297         for (j = 0; j <= i; j++)
298                 *wptr++ = cores->core_set[j];
299
300         xpwrite(perf_fd, cmdbuf, wptr - cmdbuf, 0);
301         xpread(perf_fd, cmdbuf, sizeof(uint32_t), 0);
302
303         rptr = get_le_u32(rptr, &ped);
304
305         return (int) ped;
306 }
307
308 static uint64_t *perf_get_event_values(int perf_fd, int ped,
309                                                                            struct perf_eventsel *sel,
310                                                                            size_t *pnvalues)
311 {
312         ssize_t rsize;
313         uint32_t i, n;
314         uint64_t *values;
315         size_t bufsize = 3 * sizeof(uint64_t) + sizeof(uint32_t) +
316                 MAX_NUM_CORES * sizeof(uint64_t);
317         uint8_t *cmdbuf = xmalloc(bufsize);
318         uint8_t *wptr = cmdbuf;
319         const uint8_t *rptr = cmdbuf;
320
321         *wptr++ = PERFMON_CMD_COUNTER_STATUS;
322         wptr = put_le_u32(wptr, ped);
323
324         xpwrite(perf_fd, cmdbuf, wptr - cmdbuf, 0);
325         rsize = pread(perf_fd, cmdbuf, bufsize, 0);
326
327         if (rsize < (3 * sizeof(uint64_t) + sizeof(uint32_t))) {
328                 fprintf(stderr, "Invalid read size while fetching event status: %ld\n",
329                                 rsize);
330                 exit(1);
331         }
332
333         rptr = get_le_u64(rptr, &sel->ev.event);
334         rptr = get_le_u64(rptr, &sel->ev.flags);
335         rptr = get_le_u64(rptr, &sel->ev.trigger_count);
336         rptr = get_le_u32(rptr, &n);
337         if (((rptr - cmdbuf) + n * sizeof(uint64_t)) > rsize) {
338                 fprintf(stderr, "Invalid read size while fetching event status: %ld\n",
339                                 rsize);
340                 exit(1);
341         }
342         values = xmalloc(n * sizeof(uint64_t));
343         for (i = 0; i < n; i++)
344                 rptr = get_le_u64(rptr, values + i);
345         free(cmdbuf);
346
347         *pnvalues = n;
348
349         return values;
350 }
351
352 static void perf_close_event(int perf_fd, int ped)
353 {
354         uint8_t cmdbuf[1 + sizeof(uint32_t)];
355         uint8_t *wptr = cmdbuf;
356
357         *wptr++ = PERFMON_CMD_COUNTER_CLOSE;
358         wptr = put_le_u32(wptr, ped);
359
360         xpwrite(perf_fd, cmdbuf, wptr - cmdbuf, 0);
361 }
362
363 static void perf_enable_sampling(int kpctl_fd)
364 {
365         static const char * const enable_str = "start";
366
367         xwrite(kpctl_fd, enable_str, strlen(enable_str));
368 }
369
370 static void perf_disable_sampling(int kpctl_fd)
371 {
372         static const char * const disable_str = "stop";
373
374         xwrite(kpctl_fd, disable_str, strlen(disable_str));
375 }
376
377 static void perf_flush_sampling(int kpctl_fd)
378 {
379         static const char * const flush_str = "flush";
380
381         xwrite(kpctl_fd, flush_str, strlen(flush_str));
382 }
383
384 struct perf_context *perf_create_context(const struct perf_context_config *cfg)
385 {
386         struct perf_context *pctx = xzmalloc(sizeof(struct perf_context));
387
388         pctx->perf_fd = xopen(cfg->perf_file, O_RDWR, 0);
389         pctx->kpctl_fd = xopen(cfg->kpctl_file, O_RDWR, 0);
390         perf_get_arch_info(pctx->perf_fd, &pctx->pai);
391         perf_enable_sampling(pctx->kpctl_fd);
392
393         return pctx;
394 }
395
396 void perf_free_context(struct perf_context *pctx)
397 {
398         for (int i = 0; i < pctx->event_count; i++)
399                 perf_close_event(pctx->perf_fd, pctx->events[i].ped);
400         perf_disable_sampling(pctx->kpctl_fd);
401         close(pctx->kpctl_fd);
402         close(pctx->perf_fd);
403         free(pctx);
404 }
405
406 void perf_flush_context_traces(struct perf_context *pctx)
407 {
408         perf_flush_sampling(pctx->kpctl_fd);
409 }
410
411 void perf_context_event_submit(struct perf_context *pctx,
412                                                            const struct core_set *cores,
413                                                            const struct perf_eventsel *sel)
414 {
415         struct perf_event *pevt = pctx->events + pctx->event_count;
416
417         if (pctx->event_count >= COUNT_OF(pctx->events)) {
418                 fprintf(stderr, "Too many open events: %d\n", pctx->event_count);
419                 exit(1);
420         }
421         pctx->event_count++;
422         pevt->cores = *cores;
423         pevt->sel = *sel;
424         pevt->ped = perf_open_event(pctx->perf_fd, cores, sel);
425 }
426
427 void perf_context_show_values(struct perf_context *pctx, FILE *file)
428 {
429         for (int i = 0; i < pctx->event_count; i++) {
430                 size_t nvalues;
431                 struct perf_eventsel sel;
432                 uint64_t *values = perf_get_event_values(pctx->perf_fd,
433                                                                                                  pctx->events[i].ped, &sel,
434                                                                                                  &nvalues);
435                 char ename[256];
436
437                 perf_get_event_string(&pctx->events[i].sel, ename, sizeof(ename));
438                 fprintf(file, "Event: %s\n\t", ename);
439                 for (size_t j = 0; j < nvalues; j++)
440                         fprintf(file, "%lu ", values[j]);
441                 fprintf(file, "\n");
442
443                 free(values);
444         }
445 }
446
447 static void perf_print_event_flags(const pfm_event_info_t *info, FILE *file)
448 {
449         int n = 0;
450
451         if (info->is_precise) {
452                 fputs("[precise] ", file);
453                 n++;
454         }
455         if (!n)
456                 fputs("None", file);
457 }
458
459 static void perf_print_attr_flags(const pfm_event_attr_info_t *info, FILE *file)
460 {
461         int n = 0;
462
463         if (info->is_dfl) {
464                 fputs("[default] ", file);
465                 n++;
466         }
467         if (info->is_precise) {
468                 fputs("[precise] ", file);
469                 n++;
470         }
471         if (!n)
472                 fputs("None ", file);
473 }
474
475 /* Ported from libpfm4 */
476 static void perf_show_event_info(const pfm_event_info_t *info,
477                                                                  const pfm_pmu_info_t *pinfo, FILE *file)
478 {
479         static const char * const srcs[PFM_ATTR_CTRL_MAX] = {
480                 [PFM_ATTR_CTRL_UNKNOWN] = "???",
481                 [PFM_ATTR_CTRL_PMU] = "PMU",
482                 [PFM_ATTR_CTRL_PERF_EVENT] = "perf_event",
483         };
484         pfm_event_attr_info_t ainfo;
485         int i, mod = 0, um = 0;
486
487         fprintf(file, "#-----------------------------\n"
488                         "IDX      : %d\n"
489                         "PMU name : %s (%s)\n"
490                         "Name     : %s\n"
491                         "Equiv    : %s\n",
492                         info->idx, pinfo->name, pinfo->desc,
493                         info->name, info->equiv ? info->equiv : "None");
494
495         fprintf(file, "Flags    : ");
496         perf_print_event_flags(info, file);
497         fputc('\n', file);
498
499         fprintf(file, "Desc     : %s\n", info->desc ? info->desc :
500                         "no description available");
501         fprintf(file, "Code     : 0x%"PRIx64"\n", info->code);
502
503         ZERO_DATA(ainfo);
504         ainfo.size = sizeof(ainfo);
505
506         pfm_for_each_event_attr(i, info) {
507                 const char *src;
508                 pfm_err_t err = pfm_get_event_attr_info(info->idx, i, PFM_OS_NONE,
509                                                                                                 &ainfo);
510
511                 if (err != PFM_SUCCESS) {
512                         fprintf(stderr, "Failed to get attribute info: %s\n",
513                                         pfm_strerror(err));
514                         exit(1);
515                 }
516
517                 if (ainfo.ctrl >= PFM_ATTR_CTRL_MAX) {
518                         fprintf(stderr, "event: %s has unsupported attribute source %d",
519                                         info->name, ainfo.ctrl);
520                         ainfo.ctrl = PFM_ATTR_CTRL_UNKNOWN;
521                 }
522                 src = srcs[ainfo.ctrl];
523                 switch (ainfo.type) {
524                         case PFM_ATTR_UMASK:
525                                 fprintf(file, "Umask-%02u : 0x%02"PRIx64" : %s : [%s] : ",
526                                                 um, ainfo.code, src, ainfo.name);
527                                 perf_print_attr_flags(&ainfo, file);
528                                 fputc(':', file);
529                                 if (ainfo.equiv)
530                                         fprintf(file, " Alias to %s", ainfo.equiv);
531                                 else
532                                         fprintf(file, " %s", ainfo.desc);
533                                 fputc('\n', file);
534                                 um++;
535                                 break;
536                         case PFM_ATTR_MOD_BOOL:
537                                 fprintf(file, "Modif-%02u : 0x%02"PRIx64" : %s : [%s] : "
538                                                 "%s (boolean)\n", mod, ainfo.code, src, ainfo.name,
539                                                 ainfo.desc);
540                                 mod++;
541                                 break;
542                         case PFM_ATTR_MOD_INTEGER:
543                                 fprintf(file, "Modif-%02u : 0x%02"PRIx64" : %s : [%s] : "
544                                                 "%s (integer)\n", mod, ainfo.code, src, ainfo.name,
545                                                 ainfo.desc);
546                                 mod++;
547                                 break;
548                         default:
549                                 fprintf(file, "Attr-%02u  : 0x%02"PRIx64" : %s : [%s] : %s\n",
550                                                 i, ainfo.code, ainfo.name, src, ainfo.desc);
551                 }
552         }
553 }
554
555 void perf_show_events(const char *rx, FILE *file)
556 {
557         int pmu;
558         regex_t crx;
559         pfm_pmu_info_t pinfo;
560         pfm_event_info_t info;
561         char fullname[256];
562
563         if (rx && regcomp(&crx, rx, REG_ICASE)) {
564                 fprintf(stderr, "Failed to compile event regex: '%s'\n", rx);
565                 exit(1);
566         }
567
568     ZERO_DATA(pinfo);
569     pinfo.size = sizeof(pinfo);
570     ZERO_DATA(info);
571     info.size = sizeof(info);
572
573         pfm_for_all_pmus(pmu) {
574                 pfm_err_t err = pfm_get_pmu_info(pmu, &pinfo);
575
576                 if (err != PFM_SUCCESS || !pinfo.is_present)
577                         continue;
578
579                 for (int i = pinfo.first_event; i != -1; i = pfm_get_event_next(i)) {
580                         err = pfm_get_event_info(i, PFM_OS_NONE, &info);
581                         if (err != PFM_SUCCESS) {
582                                 fprintf(stderr, "Failed to get event info: %s\n",
583                                                 pfm_strerror(err));
584                                 exit(1);
585                         }
586                         snprintf(fullname, sizeof(fullname), "%s::%s", pinfo.name,
587                                          info.name);
588                         if (!rx || regexec(&crx, fullname, 0, NULL, 0) == 0)
589                                 perf_show_event_info(&info, &pinfo, file);
590                 }
591         }
592         if (rx)
593                 regfree(&crx);
594 }
595
596 void perf_get_event_string(const struct perf_eventsel *sel, char *sbuf,
597                                                    size_t size)
598 {
599         pfm_event_info_t einfo;
600
601     ZERO_DATA(einfo);
602     einfo.size = sizeof(einfo);
603         if ((sel->eidx >= 0) &&
604                 (pfm_get_event_info(sel->eidx, PFM_OS_NONE, &einfo) == PFM_SUCCESS)) {
605                 const char *mask_name =
606                         perf_get_event_mask_name(&einfo, PMEV_GET_MASK(sel->ev.event));
607
608                 if (mask_name)
609                         snprintf(sbuf, size, "%s:%s", einfo.name, mask_name);
610                 else
611                         snprintf(sbuf, size, "%s", einfo.name);
612         } else {
613                 snprintf(sbuf, size, "0x%02x:0x%02x",
614                                  (int) PMEV_GET_EVENT(sel->ev.event),
615                                  (int) PMEV_GET_MASK(sel->ev.event));
616         }
617 }
618
619 void perf_convert_trace_data(struct perfconv_context *cctx, const char *input,
620                                                          const char *output)
621 {
622         FILE *infile, *outfile;
623         size_t ksize;
624         char kpath[1024];
625
626         infile = xfopen(input, "rb");
627         if (xfsize(infile) > 0) {
628                 outfile = xfopen(output, "wb");
629
630                 perfconv_add_kernel_mmap(cctx);
631                 perfconv_process_input(cctx, infile, outfile);
632
633                 fclose(outfile);
634         }
635         fclose(infile);
636 }