Made Akaros perf to use the new #version device for kernel path
[akaros.git] / tools / profile / perf / perf_core.c
1 /* Copyright (c) 2015 Google Inc
2  * Davide Libenzi <dlibenzi@google.com>
3  * See LICENSE for details.
4  */
5
6 #include <ros/arch/msr-index.h>
7 #include <ros/arch/perfmon.h>
8 #include <ros/common.h>
9 #include <ros/memops.h>
10 #include <sys/types.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <ctype.h>
17 #include <limits.h>
18 #include <errno.h>
19 #include <regex.h>
20 #include <parlib/parlib.h>
21 #include <perfmon/err.h>
22 #include <perfmon/pfmlib.h>
23 #include "xlib.h"
24 #include "perfconv.h"
25 #include "akaros.h"
26 #include "perf_core.h"
27
28 struct event_coords {
29         char *buffer;
30         const char *event;
31         const char *umask;
32 };
33
34 static const uint32_t invalid_mask = (uint32_t) -1;
35
36 static void perf_parse_event_coords(const char *name, struct event_coords *ec)
37 {
38         const char *cptr = strchr(name, ':');
39
40         if (cptr == NULL) {
41                 ec->buffer = NULL;
42                 ec->event = name;
43                 ec->umask = NULL;
44         } else {
45                 size_t cpos = cptr - name;
46
47                 ec->buffer = xstrdup(name);
48                 ec->event = ec->buffer;
49                 ec->umask = ec->buffer + cpos + 1;
50                 ec->buffer[cpos] = 0;
51         }
52 }
53
54 static void perf_free_event_coords(struct event_coords *ec)
55 {
56         free(ec->buffer);
57 }
58
59 static const char *perf_get_event_mask_name(const pfm_event_info_t *einfo,
60                                                                                         uint32_t mask)
61 {
62         int i;
63         pfm_event_attr_info_t ainfo;
64
65         ZERO_DATA(ainfo);
66         ainfo.size = sizeof(ainfo);
67         pfm_for_each_event_attr(i, einfo) {
68                 pfm_err_t err = pfm_get_event_attr_info(einfo->idx, i, PFM_OS_NONE,
69                                                                                                 &ainfo);
70
71                 if (err != PFM_SUCCESS) {
72                         fprintf(stderr, "Failed to get attribute info: %s\n",
73                                         pfm_strerror(err));
74                         exit(1);
75                 }
76                 if (ainfo.type == PFM_ATTR_UMASK) {
77                         if (mask == (uint32_t) ainfo.code)
78                                 return ainfo.name;
79                 }
80         }
81
82         return NULL;
83 }
84
85 static int perf_resolve_event_name(const char *name, uint32_t *event,
86                                                                    uint32_t *mask, uint32_t mask_hint)
87 {
88         int idx;
89         struct event_coords ec;
90
91         perf_parse_event_coords(name, &ec);
92
93         idx = pfm_find_event(ec.event);
94         if (idx >= 0) {
95                 int i;
96                 pfm_err_t err;
97                 pfm_event_info_t einfo;
98                 pfm_event_attr_info_t ainfo;
99
100                 ZERO_DATA(einfo);
101                 einfo.size = sizeof(einfo);
102                 err = pfm_get_event_info(idx, PFM_OS_NONE, &einfo);
103                 if (err != PFM_SUCCESS) {
104                         fprintf(stderr, "Unable to retrieve event (%s) info: %s\n",
105                                         name, pfm_strerror(err));
106                         exit(1);
107                 }
108
109                 *event = (uint32_t) einfo.code;
110                 *mask = invalid_mask;
111
112                 ZERO_DATA(ainfo);
113                 ainfo.size = sizeof(ainfo);
114                 pfm_for_each_event_attr(i, &einfo) {
115                         err = pfm_get_event_attr_info(idx, i, PFM_OS_NONE, &ainfo);
116                         if (err != PFM_SUCCESS) {
117                                 fprintf(stderr, "Failed to get attribute info: %s\n",
118                                                 pfm_strerror(err));
119                                 exit(1);
120                         }
121                         if (ainfo.type == PFM_ATTR_UMASK) {
122                                 if (mask_hint != invalid_mask) {
123                                         if (mask_hint == (uint32_t) ainfo.code) {
124                                                 *mask = (uint32_t) ainfo.code;
125                                                 break;
126                                         }
127                                 } else if (!ec.umask) {
128                                         *mask = (uint32_t) ainfo.code;
129                                         if (ainfo.is_dfl)
130                                                 break;
131                                 } else if (!strcmp(ec.umask, ainfo.name)) {
132                                         *mask = (uint32_t) ainfo.code;
133                                         break;
134                                 }
135                         }
136                 }
137         }
138         perf_free_event_coords(&ec);
139
140         return idx;
141 }
142
143 static int perf_find_event_by_id(uint32_t event, uint32_t mask)
144 {
145         int pmu;
146         pfm_pmu_info_t pinfo;
147         pfm_event_info_t info;
148
149     ZERO_DATA(pinfo);
150     pinfo.size = sizeof(pinfo);
151     ZERO_DATA(info);
152     info.size = sizeof(info);
153
154         pfm_for_all_pmus(pmu) {
155                 pfm_err_t err = pfm_get_pmu_info(pmu, &pinfo);
156
157                 if (err != PFM_SUCCESS || !pinfo.is_present)
158                         continue;
159
160                 for (int i = pinfo.first_event; i != -1; i = pfm_get_event_next(i)) {
161                         uint32_t cevent, cmask;
162
163                         err = pfm_get_event_info(i, PFM_OS_NONE, &info);
164                         if (err != PFM_SUCCESS) {
165                                 fprintf(stderr, "Failed to get event info: %s\n",
166                                                 pfm_strerror(err));
167                                 exit(1);
168                         }
169                         if (perf_resolve_event_name(info.name, &cevent, &cmask, mask) != i)
170                                 continue;
171                         if ((cevent == event) && (cmask == mask))
172                                 return i;
173                 }
174         }
175
176         return -1;
177 }
178
179 void perf_initialize(int argc, const char * const *argv)
180 {
181         pfm_err_t err = pfm_initialize();
182
183         if (err != PFM_SUCCESS) {
184                 fprintf(stderr, "Unable to initialize perfmon library: %s\n",
185                                 pfm_strerror(err));
186                 exit(1);
187         }
188 }
189
190 void perf_finalize(void)
191 {
192         pfm_terminate();
193 }
194
195 void perf_parse_event(const char *str, struct perf_eventsel *sel)
196 {
197         static const char *const event_spec =
198                 "{EVENT_ID:MASK,EVENT_NAME:MASK_NAME}[,os[={0,1}]][,usr[={0,1}]]"
199                 "[,int[={0,1}]][,invcmsk[={0,1}]][,cmask=MASK][,icount=COUNT]";
200         char *dstr = xstrdup(str), *sptr, *tok, *ev;
201
202         tok = strtok_r(dstr, ",", &sptr);
203         if (tok == NULL) {
204                 fprintf(stderr, "Invalid event spec string: '%s'\n\t%s\n", str,
205                                 event_spec);
206                 exit(1);
207         }
208         ZERO_DATA(*sel);
209         sel->eidx = -1;
210         sel->ev.flags = 0;
211         sel->ev.event = 0;
212         PMEV_SET_OS(sel->ev.event, 1);
213         PMEV_SET_USR(sel->ev.event, 1);
214         PMEV_SET_EN(sel->ev.event, 1);
215         if (isdigit(*tok)) {
216                 ev = strchr(tok, ':');
217                 if (ev == NULL) {
218                         fprintf(stderr, "Invalid event spec string: '%s'\n"
219                                         "\tShould be: %s\n", str, event_spec);
220                         exit(1);
221                 }
222                 *ev++ = 0;
223                 PMEV_SET_EVENT(sel->ev.event, (uint8_t) strtoul(tok, NULL, 0));
224                 PMEV_SET_MASK(sel->ev.event, (uint8_t) strtoul(ev, NULL, 0));
225         } else {
226                 uint32_t event, mask;
227
228                 sel->eidx = perf_resolve_event_name(tok, &event, &mask, invalid_mask);
229                 if (sel->eidx < 0) {
230                         fprintf(stderr, "Unable to find event: %s\n", tok);
231                         exit(1);
232                 }
233                 PMEV_SET_EVENT(sel->ev.event, (uint8_t) event);
234                 PMEV_SET_MASK(sel->ev.event, (uint8_t) mask);
235         }
236         while ((tok = strtok_r(NULL, ",", &sptr)) != NULL) {
237                 ev = strchr(tok, '=');
238                 if (ev)
239                         *ev++ = 0;
240                 if (!strcmp(tok, "os")) {
241                         PMEV_SET_OS(sel->ev.event, (ev == NULL || atoi(ev) != 0) ? 1 : 0);
242                 } else if (!strcmp(tok, "usr")) {
243                         PMEV_SET_USR(sel->ev.event, (ev == NULL || atoi(ev) != 0) ? 1 : 0);
244                 } else if (!strcmp(tok, "int")) {
245                         PMEV_SET_INTEN(sel->ev.event,
246                                                    (ev == NULL || atoi(ev) != 0) ? 1 : 0);
247                 } else if (!strcmp(tok, "invcmsk")) {
248                         PMEV_SET_INVCMSK(sel->ev.event,
249                                                          (ev == NULL || atoi(ev) != 0) ? 1 : 0);
250                 } else if (!strcmp(tok, "cmask")) {
251                         if (ev == NULL) {
252                                 fprintf(stderr, "Invalid event spec string: '%s'\n"
253                                                 "\tShould be: %s\n", str, event_spec);
254                                 exit(1);
255                         }
256                         PMEV_SET_CMASK(sel->ev.event, (uint32_t) strtoul(ev, NULL, 0));
257                 } else if (!strcmp(tok, "icount")) {
258                         if (ev == NULL) {
259                                 fprintf(stderr, "Invalid event spec string: '%s'\n"
260                                                 "\tShould be: %s\n", str, event_spec);
261                                 exit(1);
262                         }
263                         sel->ev.trigger_count = (uint64_t) strtoul(ev, NULL, 0);
264                 }
265         }
266         if (PMEV_GET_INTEN(sel->ev.event) && !sel->ev.trigger_count) {
267                 fprintf(stderr,
268                                 "Counter trigger count for interrupt is too small: %lu\n",
269                                 sel->ev.trigger_count);
270                 exit(1);
271         }
272         free(dstr);
273 }
274
275 static void perf_get_arch_info(int perf_fd, struct perf_arch_info *pai)
276 {
277         uint8_t cmdbuf[6 * sizeof(uint32_t)];
278         const uint8_t *rptr = cmdbuf;
279
280         cmdbuf[0] = PERFMON_CMD_CPU_CAPS;
281
282         xpwrite(perf_fd, cmdbuf, 1, 0);
283         xpread(perf_fd, cmdbuf, 6 * sizeof(uint32_t), 0);
284
285         rptr = get_le_u32(rptr, &pai->perfmon_version);
286         rptr = get_le_u32(rptr, &pai->proc_arch_events);
287         rptr = get_le_u32(rptr, &pai->bits_x_counter);
288         rptr = get_le_u32(rptr, &pai->counters_x_proc);
289         rptr = get_le_u32(rptr, &pai->bits_x_fix_counter);
290         rptr = get_le_u32(rptr, &pai->fix_counters_x_proc);
291 }
292
293 static int perf_open_event(int perf_fd, const struct core_set *cores,
294                                                    const struct perf_eventsel *sel)
295 {
296         uint8_t cmdbuf[1 + 3 * sizeof(uint64_t) + sizeof(uint32_t) +
297                                    CORE_SET_SIZE];
298         uint8_t *wptr = cmdbuf;
299         const uint8_t *rptr = cmdbuf;
300         uint32_t ped;
301         int i, j;
302
303         *wptr++ = PERFMON_CMD_COUNTER_OPEN;
304         wptr = put_le_u64(wptr, sel->ev.event);
305         wptr = put_le_u64(wptr, sel->ev.flags);
306         wptr = put_le_u64(wptr, sel->ev.trigger_count);
307
308         for (i = CORE_SET_SIZE - 1; (i >= 0) && !cores->core_set[i]; i--)
309                 ;
310         if (i < 0) {
311                 fprintf(stderr, "Performance event CPU set must not be empty\n");
312                 exit(1);
313         }
314         wptr = put_le_u32(wptr, i + 1);
315         for (j = 0; j <= i; j++)
316                 *wptr++ = cores->core_set[j];
317
318         xpwrite(perf_fd, cmdbuf, wptr - cmdbuf, 0);
319         xpread(perf_fd, cmdbuf, sizeof(uint32_t), 0);
320
321         rptr = get_le_u32(rptr, &ped);
322
323         return (int) ped;
324 }
325
326 static uint64_t *perf_get_event_values(int perf_fd, int ped,
327                                                                            struct perf_eventsel *sel,
328                                                                            size_t *pnvalues)
329 {
330         ssize_t rsize;
331         uint32_t i, n;
332         uint64_t *values;
333         size_t bufsize = 3 * sizeof(uint64_t) + sizeof(uint32_t) +
334                 MAX_NUM_CORES * sizeof(uint64_t);
335         uint8_t *cmdbuf = xmalloc(bufsize);
336         uint8_t *wptr = cmdbuf;
337         const uint8_t *rptr = cmdbuf;
338
339         *wptr++ = PERFMON_CMD_COUNTER_STATUS;
340         wptr = put_le_u32(wptr, ped);
341
342         xpwrite(perf_fd, cmdbuf, wptr - cmdbuf, 0);
343         rsize = pread(perf_fd, cmdbuf, bufsize, 0);
344
345         if (rsize < (3 * sizeof(uint64_t) + sizeof(uint32_t))) {
346                 fprintf(stderr, "Invalid read size while fetching event status: %ld\n",
347                                 rsize);
348                 exit(1);
349         }
350
351         rptr = get_le_u64(rptr, &sel->ev.event);
352         rptr = get_le_u64(rptr, &sel->ev.flags);
353         rptr = get_le_u64(rptr, &sel->ev.trigger_count);
354         rptr = get_le_u32(rptr, &n);
355         if (((rptr - cmdbuf) + n * sizeof(uint64_t)) > rsize) {
356                 fprintf(stderr, "Invalid read size while fetching event status: %ld\n",
357                                 rsize);
358                 exit(1);
359         }
360         values = xmalloc(n * sizeof(uint64_t));
361         for (i = 0; i < n; i++)
362                 rptr = get_le_u64(rptr, values + i);
363         free(cmdbuf);
364
365         *pnvalues = n;
366
367         return values;
368 }
369
370 static void perf_close_event(int perf_fd, int ped)
371 {
372         uint8_t cmdbuf[1 + sizeof(uint32_t)];
373         uint8_t *wptr = cmdbuf;
374
375         *wptr++ = PERFMON_CMD_COUNTER_CLOSE;
376         wptr = put_le_u32(wptr, ped);
377
378         xpwrite(perf_fd, cmdbuf, wptr - cmdbuf, 0);
379 }
380
381 static void perf_enable_sampling(int kpctl_fd)
382 {
383         static const char * const enable_str = "start";
384
385         xwrite(kpctl_fd, enable_str, strlen(enable_str));
386 }
387
388 static void perf_disable_sampling(int kpctl_fd)
389 {
390         static const char * const disable_str = "stop";
391
392         xwrite(kpctl_fd, disable_str, strlen(disable_str));
393 }
394
395 static void perf_flush_sampling(int kpctl_fd)
396 {
397         static const char * const flush_str = "flush";
398
399         xwrite(kpctl_fd, flush_str, strlen(flush_str));
400 }
401
402 struct perf_context *perf_create_context(const struct perf_context_config *cfg)
403 {
404         struct perf_context *pctx = xzmalloc(sizeof(struct perf_context));
405
406         pctx->perf_fd = xopen(cfg->perf_file, O_RDWR, 0);
407         pctx->kpctl_fd = xopen(cfg->kpctl_file, O_RDWR, 0);
408         perf_get_arch_info(pctx->perf_fd, &pctx->pai);
409         perf_enable_sampling(pctx->kpctl_fd);
410
411         return pctx;
412 }
413
414 void perf_free_context(struct perf_context *pctx)
415 {
416         for (int i = 0; i < pctx->event_count; i++)
417                 perf_close_event(pctx->perf_fd, pctx->events[i].ped);
418         perf_disable_sampling(pctx->kpctl_fd);
419         close(pctx->kpctl_fd);
420         close(pctx->perf_fd);
421         free(pctx);
422 }
423
424 void perf_flush_context_traces(struct perf_context *pctx)
425 {
426         perf_flush_sampling(pctx->kpctl_fd);
427 }
428
429 void perf_context_event_submit(struct perf_context *pctx,
430                                                            const struct core_set *cores,
431                                                            const struct perf_eventsel *sel)
432 {
433         struct perf_event *pevt = pctx->events + pctx->event_count;
434
435         if (pctx->event_count >= COUNT_OF(pctx->events)) {
436                 fprintf(stderr, "Too many open events: %d\n", pctx->event_count);
437                 exit(1);
438         }
439         pctx->event_count++;
440         pevt->cores = *cores;
441         pevt->sel = *sel;
442         pevt->ped = perf_open_event(pctx->perf_fd, cores, sel);
443 }
444
445 void perf_context_show_values(struct perf_context *pctx, FILE *file)
446 {
447         for (int i = 0; i < pctx->event_count; i++) {
448                 size_t nvalues;
449                 struct perf_eventsel sel;
450                 uint64_t *values = perf_get_event_values(pctx->perf_fd,
451                                                                                                  pctx->events[i].ped, &sel,
452                                                                                                  &nvalues);
453                 char ename[256];
454
455                 perf_get_event_string(&pctx->events[i].sel, ename, sizeof(ename));
456                 fprintf(file, "Event: %s\n\t", ename);
457                 for (size_t j = 0; j < nvalues; j++)
458                         fprintf(file, "%lu ", values[j]);
459                 fprintf(file, "\n");
460
461                 free(values);
462         }
463 }
464
465 static void perf_print_event_flags(const pfm_event_info_t *info, FILE *file)
466 {
467         int n = 0;
468
469         if (info->is_precise) {
470                 fputs("[precise] ", file);
471                 n++;
472         }
473         if (!n)
474                 fputs("None", file);
475 }
476
477 static void perf_print_attr_flags(const pfm_event_attr_info_t *info, FILE *file)
478 {
479         int n = 0;
480
481         if (info->is_dfl) {
482                 fputs("[default] ", file);
483                 n++;
484         }
485         if (info->is_precise) {
486                 fputs("[precise] ", file);
487                 n++;
488         }
489         if (!n)
490                 fputs("None ", file);
491 }
492
493 static void perf_show_event_info(const pfm_event_info_t *info,
494                                                                  const pfm_pmu_info_t *pinfo, FILE *file)
495 {
496         static const char * const srcs[PFM_ATTR_CTRL_MAX] = {
497                 [PFM_ATTR_CTRL_UNKNOWN] = "???",
498                 [PFM_ATTR_CTRL_PMU] = "PMU",
499                 [PFM_ATTR_CTRL_PERF_EVENT] = "perf_event",
500         };
501         pfm_event_attr_info_t ainfo;
502         int i, mod = 0, um = 0;
503
504         fprintf(file, "#-----------------------------\n"
505                         "IDX      : %d\n"
506                         "PMU name : %s (%s)\n"
507                         "Name     : %s\n"
508                         "Equiv    : %s\n",
509                         info->idx, pinfo->name, pinfo->desc,
510                         info->name, info->equiv ? info->equiv : "None");
511
512         fprintf(file, "Flags    : ");
513         perf_print_event_flags(info, file);
514         fputc('\n', file);
515
516         fprintf(file, "Desc     : %s\n", info->desc ? info->desc :
517                         "no description available");
518         fprintf(file, "Code     : 0x%"PRIx64"\n", info->code);
519
520         ZERO_DATA(ainfo);
521         ainfo.size = sizeof(ainfo);
522
523         pfm_for_each_event_attr(i, info) {
524                 const char *src;
525                 pfm_err_t err = pfm_get_event_attr_info(info->idx, i, PFM_OS_NONE,
526                                                                                                 &ainfo);
527
528                 if (err != PFM_SUCCESS) {
529                         fprintf(stderr, "Failed to get attribute info: %s\n",
530                                         pfm_strerror(err));
531                         exit(1);
532                 }
533
534                 if (ainfo.ctrl >= PFM_ATTR_CTRL_MAX) {
535                         fprintf(stderr, "event: %s has unsupported attribute source %d",
536                                         info->name, ainfo.ctrl);
537                         ainfo.ctrl = PFM_ATTR_CTRL_UNKNOWN;
538                 }
539                 src = srcs[ainfo.ctrl];
540                 switch (ainfo.type) {
541                         case PFM_ATTR_UMASK:
542                                 fprintf(file, "Umask-%02u : 0x%02"PRIx64" : %s : [%s] : ",
543                                                 um, ainfo.code, src, ainfo.name);
544                                 perf_print_attr_flags(&ainfo, file);
545                                 fputc(':', file);
546                                 if (ainfo.equiv)
547                                         fprintf(file, " Alias to %s", ainfo.equiv);
548                                 else
549                                         fprintf(file, " %s", ainfo.desc);
550                                 fputc('\n', file);
551                                 um++;
552                                 break;
553                         case PFM_ATTR_MOD_BOOL:
554                                 fprintf(file, "Modif-%02u : 0x%02"PRIx64" : %s : [%s] : "
555                                                 "%s (boolean)\n", mod, ainfo.code, src, ainfo.name,
556                                                 ainfo.desc);
557                                 mod++;
558                                 break;
559                         case PFM_ATTR_MOD_INTEGER:
560                                 fprintf(file, "Modif-%02u : 0x%02"PRIx64" : %s : [%s] : "
561                                                 "%s (integer)\n", mod, ainfo.code, src, ainfo.name,
562                                                 ainfo.desc);
563                                 mod++;
564                                 break;
565                         default:
566                                 fprintf(file, "Attr-%02u  : 0x%02"PRIx64" : %s : [%s] : %s\n",
567                                                 i, ainfo.code, ainfo.name, src, ainfo.desc);
568                 }
569         }
570 }
571
572 void perf_show_events(const char *rx, FILE *file)
573 {
574         int pmu;
575         regex_t crx;
576         pfm_pmu_info_t pinfo;
577         pfm_event_info_t info;
578         char fullname[256];
579
580         if (rx && regcomp(&crx, rx, REG_ICASE)) {
581                 fprintf(stderr, "Failed to compile event regex: '%s'\n", rx);
582                 exit(1);
583         }
584
585     ZERO_DATA(pinfo);
586     pinfo.size = sizeof(pinfo);
587     ZERO_DATA(info);
588     info.size = sizeof(info);
589
590         pfm_for_all_pmus(pmu) {
591                 pfm_err_t err = pfm_get_pmu_info(pmu, &pinfo);
592
593                 if (err != PFM_SUCCESS || !pinfo.is_present)
594                         continue;
595
596                 for (int i = pinfo.first_event; i != -1; i = pfm_get_event_next(i)) {
597                         err = pfm_get_event_info(i, PFM_OS_NONE, &info);
598                         if (err != PFM_SUCCESS) {
599                                 fprintf(stderr, "Failed to get event info: %s\n",
600                                                 pfm_strerror(err));
601                                 exit(1);
602                         }
603                         snprintf(fullname, sizeof(fullname), "%s::%s", pinfo.name,
604                                          info.name);
605                         if (!rx || regexec(&crx, fullname, 0, NULL, 0) == 0)
606                                 perf_show_event_info(&info, &pinfo, file);
607                 }
608         }
609         if (rx)
610                 regfree(&crx);
611 }
612
613 void perf_get_event_string(const struct perf_eventsel *sel, char *sbuf,
614                                                    size_t size)
615 {
616         pfm_event_info_t einfo;
617
618     ZERO_DATA(einfo);
619     einfo.size = sizeof(einfo);
620         if ((sel->eidx >= 0) &&
621                 (pfm_get_event_info(sel->eidx, PFM_OS_NONE, &einfo) == PFM_SUCCESS)) {
622                 const char *mask_name =
623                         perf_get_event_mask_name(&einfo, PMEV_GET_MASK(sel->ev.event));
624
625                 if (mask_name)
626                         snprintf(sbuf, size, "%s:%s", einfo.name, mask_name);
627                 else
628                         snprintf(sbuf, size, "%s", einfo.name);
629         } else {
630                 snprintf(sbuf, size, "0x%02x:0x%02x",
631                                  (int) PMEV_GET_EVENT(sel->ev.event),
632                                  (int) PMEV_GET_MASK(sel->ev.event));
633         }
634 }
635
636 void perf_make_eventsel_from_event_mask(struct perf_eventsel *sel,
637                                                                                 uint32_t event, uint32_t mask)
638 {
639         ZERO_DATA(*sel);
640         PMEV_SET_EVENT(sel->ev.event, (uint8_t) event);
641         PMEV_SET_MASK(sel->ev.event, (uint8_t) mask);
642         sel->eidx = perf_find_event_by_id(event, mask);
643 }
644
645 static bool perf_get_kernel_elf_path(char *path, size_t psize, size_t *ksize)
646 {
647         int fd;
648         ssize_t rsize = -1;
649
650         fd = open("#version/kernel_path", O_RDONLY);
651         if (fd >= 0) {
652                 rsize = read(fd, path, psize);
653                 while ((rsize > 0) && (path[rsize - 1] == '\n'))
654                         rsize--;
655                 close(fd);
656
657                 /* We do not export the real kernel size from the #versions device,
658                  * because of cyclic dependency issues. The only reason the size is
659                  * needed, is because we generate an MMAP record, which Linux perf
660                  * uses to find which ELF should be used to resolve addresses to
661                  * symbols. Above the Akaros kernel, hardly other ELF will be loaded,
662                  * so the worst it can happen if something above the kernel ELF
663                  * proper address gets a hit, is that Linux perf will ask the kernel
664                  * ELF to resolve an address, and that will fail.
665                  * So here we use a large enough size to cover kernel size expansions
666                  * for the next 10 years.
667                  */
668                 *ksize = 128 * 1024 * 1024;
669         }
670
671         return rsize > 0;
672 }
673
674 void perf_convert_trace_data(struct perfconv_context *cctx, const char *input,
675                                                          const char *output)
676 {
677         FILE *infile, *outfile;
678         size_t ksize;
679         char kpath[1024];
680
681         infile = xfopen(input, "rb");
682         if (xfsize(infile) > 0) {
683                 outfile = xfopen(output, "wb");
684
685                 if (perf_get_kernel_elf_path(kpath, sizeof(kpath), &ksize))
686                         perfconv_add_kernel_mmap(kpath, ksize, cctx);
687                 else
688                         fprintf(stderr, "Unable to fetch kernel build information!\n"
689                                         "Kernel traces will be missing symbol information.\n");
690
691                 perfconv_process_input(cctx, infile, outfile);
692
693                 fclose(outfile);
694         }
695         fclose(infile);
696 }