b6b3aa17482dbbda85be260cc40eabef10b90aa8
[akaros.git] / tools / profile / perf / perf.c
1 /* Copyright (c) 2015-2016 Google Inc
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * Davide Libenzi <dlibenzi@google.com>
4  * See LICENSE for details.
5  */
6
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <sys/wait.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <limits.h>
17 #include <errno.h>
18 #include <argp.h>
19 #include <time.h>
20 #include <parlib/parlib.h>
21 #include <parlib/timing.h>
22 #include "xlib.h"
23 #include "akaros.h"
24 #include "perfconv.h"
25 #include "perf_core.h"
26
27 /* Helpers */
28 static void run_process_and_wait(int argc, char *argv[],
29                                                                  const struct core_set *cores);
30
31 /* For communicating with perf_create_context() */
32 static struct perf_context_config perf_cfg = {
33         .perf_file = "#arch/perf",
34         .kpctl_file = "#kprof/kpctl",
35         .kpdata_file = "#kprof/kpdata",
36 };
37
38 static struct perfconv_context *cctx;
39 static struct perf_context *pctx;
40 extern char **environ;  /* POSIX envp */
41
42 struct perf_opts {
43         FILE                                            *outfile;
44         const char                                      *events;
45         char                                            **cmd_argv;
46         int                                                     cmd_argc;
47         struct core_set                         cores;
48         bool                                            got_cores;
49         bool                                            verbose;
50         bool                                            sampling;
51         bool                                            stat_bignum;
52         bool                                            record_quiet;
53         unsigned long                           record_period;
54 };
55 static struct perf_opts opts;
56
57 struct perf_cmd {
58         char                                            *name;
59         char                                            *desc;
60         char                                            *opts;
61         int (*func)(struct perf_cmd *, int, char **);
62 };
63
64 static int perf_help(struct perf_cmd *cmd, int argc, char *argv[]);
65 static int perf_list(struct perf_cmd *cmd, int argc, char *argv[]);
66 static int perf_record(struct perf_cmd *cmd, int argc, char *argv[]);
67 static int perf_stat(struct perf_cmd *cmd, int argc, char *argv[]);
68 static int perf_pmu_caps(struct perf_cmd *cmd, int argc, char *argv[]);
69
70 static struct perf_cmd perf_cmds[] = {
71         { .name = "help",
72           .desc = "Detailed help for commands",
73           .opts = "COMMAND",
74           .func = perf_help,
75         },
76         { .name = "list",
77           .desc = "Lists all available events",
78           .opts = "[REGEX]",
79           .func = perf_list,
80         },
81         { .name = "record",
82           .desc = "Samples events during command execution",
83           .opts = 0,
84           .func = perf_record,
85         },
86         { .name = "stat",
87           .desc = "Counts events during command execution",
88           .opts = 0,
89           .func = perf_stat,
90         },
91         { .name = "pmu_caps",
92           .desc = "Shows PMU capabilities",
93           .opts = "",
94           .func = perf_pmu_caps,
95         },
96 };
97
98 /**************************** perf help ****************************/
99
100 static int perf_help(struct perf_cmd *cmd, int argc, char *argv[])
101 {
102         char *sub_argv[2];
103
104         if (argc < 2) {
105                 fprintf(stderr, "perf %s %s\n", cmd->name, cmd->opts);
106                 return -1;
107         }
108         for (int i = 0; i < COUNT_OF(perf_cmds); i++) {
109                 if (!strcmp(perf_cmds[i].name, argv[1])) {
110                         if (perf_cmds[i].opts) {
111                                 fprintf(stdout, "perf %s %s\n", perf_cmds[i].name,
112                                         perf_cmds[i].opts);
113                                 fprintf(stdout, "\t%s\n", perf_cmds[i].desc);
114                         } else {
115                                 /* For argp subcommands, call their help directly. */
116                                 sub_argv[0] = xstrdup(perf_cmds[i].name);
117                                 sub_argv[1] = xstrdup("--help");
118                                 perf_cmds[i].func(&perf_cmds[i], 2, sub_argv);
119                                 free(sub_argv[0]);
120                                 free(sub_argv[1]);
121                         }
122                         return 0;
123                 }
124         }
125         fprintf(stderr, "Unknown perf command %s\n", argv[1]);
126         return -1;
127 }
128
129 /**************************** perf list ****************************/
130
131 static int perf_list(struct perf_cmd *cmd, int argc, char *argv[])
132 {
133         char *show_regex = NULL;
134
135         if (argc > 1)
136                 show_regex = argv[1];
137         perf_show_events(show_regex, stdout);
138         return 0;
139 }
140
141 /**************************** perf pmu_caps ************************/
142
143 static int perf_pmu_caps(struct perf_cmd *cmd, int argc, char *argv[])
144 {
145         const struct perf_arch_info *pai = perf_context_get_arch_info(pctx);
146
147         fprintf(stdout,
148                         "PERF.version             = %u\n"
149                         "PERF.proc_arch_events    = %u\n"
150                         "PERF.bits_x_counter      = %u\n"
151                         "PERF.counters_x_proc     = %u\n"
152                         "PERF.bits_x_fix_counter  = %u\n"
153                         "PERF.fix_counters_x_proc = %u\n",
154                         pai->perfmon_version, pai->proc_arch_events, pai->bits_x_counter,
155                         pai->counters_x_proc, pai->bits_x_fix_counter,
156                         pai->fix_counters_x_proc);
157         return 0;
158 }
159
160 /**************************** Common argp ************************/
161
162 /* Collection argument parsing.  These options are common to any function that
163  * will collect perf events, e.g. perf record and perf stat. */
164
165 static struct argp_option collect_opts[] = {
166         {"event", 'e', "EVENT", 0, "Event string, e.g. cycles:u:k"},
167         {"cores", 'C', "CORE_LIST", 0, "List of cores, e.g. 0.2.4:8-19"},
168         {"cpu", 'C', 0, OPTION_ALIAS},
169         {"all-cpus", 'a', 0, 0, "Collect events on all cores (on by default)"},
170         {"verbose", 'v', 0, 0, 0},
171         { 0 }
172 };
173
174 static const char *collect_args_doc = "COMMAND [ARGS]";
175
176 static error_t parse_collect_opt(int key, char *arg, struct argp_state *state)
177 {
178         struct perf_opts *p_opts = state->input;
179
180         /* argp doesn't pass input to the child parser(s) by default... */
181         state->child_inputs[0] = state->input;
182
183         switch (key) {
184         case 'a':
185                 /* Our default operation is to track all cores; we don't follow
186                  * processes yet. */
187                 break;
188         case 'C':
189                 ros_parse_cores(arg, &p_opts->cores);
190                 p_opts->got_cores = TRUE;
191                 break;
192         case 'e':
193                 p_opts->events = arg;
194                 break;
195         case 'v':
196                 p_opts->verbose = TRUE;
197                 break;
198         case ARGP_KEY_ARG:
199                 p_opts->cmd_argc = state->argc - state->next + 1;
200                 p_opts->cmd_argv = xmalloc(sizeof(char*) * (p_opts->cmd_argc + 1));
201                 p_opts->cmd_argv[0] = arg;
202                 memcpy(&p_opts->cmd_argv[1], &state->argv[state->next],
203                        sizeof(char*) * (p_opts->cmd_argc - 1));
204                 p_opts->cmd_argv[p_opts->cmd_argc] = NULL;
205                 state->next = state->argc;
206                 break;
207         case ARGP_KEY_END:
208                 if (!p_opts->cmd_argc)
209                         argp_usage(state);
210                 /* By default, we set all cores (different than linux) */
211                 if (!p_opts->got_cores)
212                         ros_get_all_cores_set(&p_opts->cores);
213                 break;
214         default:
215                 return ARGP_ERR_UNKNOWN;
216         }
217         return 0;
218 }
219
220 /* Helper, parses args using the collect_opts and the child parser for a given
221  * cmd. */
222 static void collect_argp(struct perf_cmd *cmd, int argc, char *argv[],
223                          struct argp_child *children, struct perf_opts *opts)
224 {
225         struct argp collect_opt = {collect_opts, parse_collect_opt,
226                                    collect_args_doc, cmd->desc, children};
227         char *cmd_name;
228         const char *fmt = "perf %s";
229         size_t cmd_sz = strlen(cmd->name) + strlen(fmt) + 1;
230
231         /* Rewrite the command name from foo to perf foo for the --help output */
232         cmd_name = xmalloc(cmd_sz);
233         snprintf(cmd_name, cmd_sz, fmt, cmd->name);
234         cmd_name[cmd_sz - 1] = '\0';
235         argv[0] = cmd_name;
236         argp_parse(&collect_opt, argc, argv, ARGP_IN_ORDER, 0, opts);
237         /* It's possible that someone could still be using cmd_name */
238 }
239
240 /* Helper, submits the events in opts to the kernel for monitoring. */
241 static void submit_events(struct perf_opts *opts)
242 {
243         struct perf_eventsel *sel;
244         char *dup_evts, *tok, *tok_save = 0;
245
246         dup_evts = xstrdup(opts->events);
247         for (tok = strtok_r(dup_evts, ",", &tok_save);
248              tok;
249                  tok = strtok_r(NULL, ",", &tok_save)) {
250
251                 sel = perf_parse_event(tok);
252                 PMEV_SET_INTEN(sel->ev.event, opts->sampling);
253                 sel->ev.trigger_count = opts->record_period;
254                 perf_context_event_submit(pctx, &opts->cores, sel);
255         }
256         free(dup_evts);
257 }
258
259 /**************************** perf record ************************/
260
261 static struct argp_option record_opts[] = {
262         {"count", 'c', "PERIOD", 0, "Sampling period"},
263         {"output", 'o', "FILE", 0, "Output file name (default perf.data)"},
264         {"freq", 'F', "FREQUENCY", 0, "Sampling frequency (assumes cycles)"},
265         {"call-graph", 'g', 0, 0, "Backtrace recording (always on!)"},
266         {"quiet", 'q', 0, 0, "No printing to stdio"},
267         { 0 }
268 };
269
270 /* In lieu of adaptively changing the period to maintain a set freq, we
271  * just assume they want cycles and that the TSC is close to that.
272  *
273  * (cycles/sec) / (samples/sec) = cycles / sample = period.
274  *
275  * TODO: this also assumes we're running the core at full speed. */
276 static unsigned long freq_to_period(unsigned long freq)
277 {
278         return get_tsc_freq() / freq;
279 }
280
281 static error_t parse_record_opt(int key, char *arg, struct argp_state *state)
282 {
283         struct perf_opts *p_opts = state->input;
284
285         switch (key) {
286         case 'c':
287                 if (p_opts->record_period)
288                         argp_error(state, "Period set.  Only use at most one of -c -F");
289                 p_opts->record_period = atol(arg);
290                 break;
291         case 'F':
292                 if (p_opts->record_period)
293                         argp_error(state, "Period set.  Only use at most one of -c -F");
294                 /* TODO: when we properly support freq, multiple events will have the
295                  * same freq but different, dynamic, periods. */
296                 p_opts->record_period = freq_to_period(atol(arg));
297                 break;
298         case 'g':
299                 /* Our default operation is to record backtraces. */
300                 break;
301         case 'o':
302                 p_opts->outfile = xfopen(arg, "wb");
303                 break;
304         case 'q':
305                 p_opts->record_quiet = TRUE;
306                 break;
307         case ARGP_KEY_END:
308                 if (!p_opts->events)
309                         p_opts->events = "cycles";
310                 if (!p_opts->outfile)
311                         p_opts->outfile = xfopen("perf.data", "wb");
312                 if (!p_opts->record_period)
313                         p_opts->record_period = freq_to_period(1000);
314                 break;
315         default:
316                 return ARGP_ERR_UNKNOWN;
317         }
318         return 0;
319 }
320
321 static int perf_record(struct perf_cmd *cmd, int argc, char *argv[])
322 {
323         struct argp argp_record = {record_opts, parse_record_opt};
324         struct argp_child children[] = { {&argp_record, 0, 0, 0}, {0} };
325
326         collect_argp(cmd, argc, argv, children, &opts);
327         opts.sampling = TRUE;
328
329         /* Once a perf event is submitted, it'll start counting and firing the IRQ.
330          * However, we can control whether or not the samples are collected. */
331         submit_events(&opts);
332         perf_start_sampling(pctx);
333         run_process_and_wait(opts.cmd_argc, opts.cmd_argv, &opts.cores);
334         perf_stop_sampling(pctx);
335         if (opts.verbose)
336                 perf_context_show_events(pctx, stdout);
337         /* The events are still counting and firing IRQs.  Let's be nice and turn
338          * them off to minimize our impact. */
339         perf_stop_events(pctx);
340         /* Generate the Linux perf file format with the traces which have been
341          * created during this operation. */
342         perf_convert_trace_data(cctx, perf_cfg.kpdata_file, opts.outfile);
343         fclose(opts.outfile);
344         return 0;
345 }
346
347 /**************************** perf stat  ************************/
348
349 static struct argp_option stat_opts[] = {
350         {"big-num", 'B', 0, 0, "Formatting option"},
351         {"output", 'o', "FILE", 0, "Print output to file (default stdout)"},
352         { 0 }
353 };
354
355 static error_t parse_stat_opt(int key, char *arg, struct argp_state *state)
356 {
357         struct perf_opts *p_opts = state->input;
358
359         switch (key) {
360         case 'B':
361                 p_opts->stat_bignum = TRUE;
362                 break;
363         case 'o':
364                 p_opts->outfile = xfopen(arg, "w+");
365                 break;
366         case ARGP_KEY_END:
367                 if (!p_opts->events)
368                         p_opts->events = "cache-misses,cache-references,"
369                                          "branch-misses,branches,instructions,cycles";
370                 if (!p_opts->outfile)
371                         p_opts->outfile = xfdopen(1, "w+");
372                 break;
373         default:
374                 return ARGP_ERR_UNKNOWN;
375         }
376         return 0;
377 }
378
379 struct stat_val {
380         char                                            *name;
381         uint64_t                                        count;
382 };
383
384 /* Helper, given a name, fetches its value as a float. */
385 static float get_count_for(char *name, struct stat_val *all_vals,
386                            size_t nr_vals)
387 {
388         for (int i = 0; i < nr_vals; i++) {
389                 if (!strcmp(name, all_vals[i].name))
390                         return (float)all_vals[i].count;
391         }
392         return 0.0;
393 }
394
395 /* Helper, gets the seconds count as a float */
396 static float get_seconds(struct stat_val *all_vals, size_t nr_vals)
397 {
398         float sec = get_count_for("nsec", all_vals, nr_vals) / 1000000000;
399
400         /* We should never have a time of 0, but in case something went wrong, don't
401          * hand back 0 (divide by 0 errors). */
402         return sec != 0.0 ? sec : 1.0;
403 }
404
405 /* Prints "X per second", scaling for K, M, or G. */
406 static void print_default_rate(FILE *out, struct stat_val *val,
407                                struct stat_val *all_vals, size_t nr_vals)
408 {
409         float rate = val->count / get_seconds(all_vals, nr_vals);
410         char scale = ' ';
411
412         if (rate > 1000000000) {
413                 rate /= 1000000000;
414                 scale = 'G';
415         } else if (rate > 1000000) {
416                 rate /= 1000000;
417                 scale = 'M';
418         } else if (rate > 1000) {
419                 rate /= 1000;
420                 scale = 'K';
421         }
422         fprintf(out, "%9.3f %c/sec\n", rate, scale);
423 }
424
425 /* Prints a line for the given stat val.  We pass all the vals since some stats
426  * will adjust their output based on *other* known values.  e.g. IPC. */
427 static void stat_print_val(FILE *out, struct stat_val *val,
428                            struct stat_val *all_vals, size_t nr_vals)
429 {
430         /* Everyone gets the same front part of the printout */
431         fprintf(out, "%18llu      %-25s #", val->count, val->name);
432
433         /* Based on the particular event and what other events we know, we may print
434          * something different to the summary bit after the #. */
435         if (!strcmp(val->name, "instructions")) {
436                 float cycles = get_count_for("cycles", all_vals, nr_vals);
437
438                 if (cycles != 0.0)
439                         fprintf(out, "%9.3f insns per cycle\n", val->count / cycles);
440                 else
441                         print_default_rate(out, val, all_vals, nr_vals);
442         } else if (!strcmp(val->name, "cache-misses")) {
443                 float cache_ref = get_count_for("cache-references", all_vals, nr_vals);
444
445                 if (cache_ref != 0.0)
446                         fprintf(out, "%8.2f%% of all refs\n", val->count * 100 / cache_ref);
447                 else
448                         print_default_rate(out, val, all_vals, nr_vals);
449         } else if (!strcmp(val->name, "branch-misses")) {
450                 float branches = get_count_for("branches", all_vals, nr_vals);
451
452                 if (branches != 0.0)
453                         fprintf(out, "%8.2f%% of all branches\n",
454                                 val->count * 100 / branches);
455                 else
456                         print_default_rate(out, val, all_vals, nr_vals);
457         } else {
458                 print_default_rate(out, val, all_vals, nr_vals);
459         }
460 }
461
462 static char *cmd_as_str(int argc, char *const argv[])
463 {
464         size_t len = 0;
465         char *str;
466
467         for (int i = 0; i < argc; i++)
468                 len += strlen(argv[i]) + 1;
469         str = xzmalloc(len);
470         for (int i = 0; i < argc; i++) {
471                 strlcat(str, argv[i], len);
472                 if (i != argc - 1)
473                         strlcat(str, " ", len);
474         }
475         return str;
476 }
477
478 static struct stat_val *collect_stats(struct perf_context *pctx,
479                                       struct timespec *diff)
480 {
481         struct stat_val *stat_vals;
482
483         /* the last stat is time (nsec). */
484         stat_vals = xzmalloc(sizeof(struct stat_val) * (pctx->event_count + 1));
485         for (int i = 0; i < pctx->event_count; i++) {
486                 stat_vals[i].count = perf_get_event_count(pctx, i);
487                 stat_vals[i].name = pctx->events[i].sel.fq_str;
488         }
489         stat_vals[pctx->event_count].name = "nsec";
490         stat_vals[pctx->event_count].count = diff->tv_sec * 1000000000 +
491                                              diff->tv_nsec;
492         return stat_vals;
493 }
494
495 static int perf_stat(struct perf_cmd *cmd, int argc, char *argv[])
496 {
497         struct argp argp_stat = {stat_opts, parse_stat_opt};
498         struct argp_child children[] = { {&argp_stat, 0, 0, 0}, {0} };
499         FILE *out;
500         struct timespec start, end, diff;
501         struct stat_val *stat_vals;
502         char *cmd_string;
503
504         collect_argp(cmd, argc, argv, children, &opts);
505         opts.sampling = FALSE;
506         out = opts.outfile;
507
508         /* As soon as we submit one event, that event is being tracked, meaning that
509          * the setup/teardown of perf events is also tracked.  Each event (including
510          * the clock measurement) will roughly account for either the start or stop
511          * of every other event. */
512         clock_gettime(CLOCK_REALTIME, &start);
513         submit_events(&opts);
514         run_process_and_wait(opts.cmd_argc, opts.cmd_argv, &opts.cores);
515         clock_gettime(CLOCK_REALTIME, &end);
516         subtract_timespecs(&diff, &end, &start);
517         stat_vals = collect_stats(pctx, &diff);
518         perf_stop_events(pctx);
519         cmd_string = cmd_as_str(opts.cmd_argc, opts.cmd_argv);
520         fprintf(out, "\nPerformance counter stats for '%s':\n\n", cmd_string);
521         free(cmd_string);
522         for (int i = 0; i < pctx->event_count; i++)
523                 stat_print_val(out, &stat_vals[i], stat_vals, pctx->event_count + 1);
524         fprintf(out, "\n%8llu.%09llu seconds time elapsed\n\n", diff.tv_sec,
525                 diff.tv_nsec);
526         fclose(out);
527         free(stat_vals);
528         return 0;
529 }
530
531 static void run_process_and_wait(int argc, char *argv[],
532                                                                  const struct core_set *cores)
533 {
534         int pid, status;
535         size_t max_cores = ros_total_cores();
536         struct core_set pvcores;
537
538         pid = create_child_with_stdfds(argv[0], argc, argv, environ);
539         if (pid < 0) {
540                 perror("Unable to spawn child");
541                 fflush(stderr);
542                 exit(1);
543         }
544
545         ros_get_low_latency_core_set(&pvcores);
546         ros_not_core_set(&pvcores);
547         ros_and_core_sets(&pvcores, cores);
548         for (size_t i = 0; i < max_cores; i++) {
549                 if (ros_get_bit(&pvcores, i)) {
550                         if (sys_provision(pid, RES_CORES, i)) {
551                                 fprintf(stderr,
552                                                 "Unable to provision CPU %lu to PID %d: cmd='%s'\n",
553                                                 i, pid, argv[0]);
554                                 sys_proc_destroy(pid, -1);
555                                 exit(1);
556                         }
557                 }
558         }
559
560         sys_proc_run(pid);
561         waitpid(pid, &status, 0);
562 }
563
564 static void save_cmdline(int argc, char *argv[])
565 {
566         size_t len = 0;
567         char *p;
568
569         for (int i = 0; i < argc; i++)
570                 len += strlen(argv[i]) + 1;
571         cmd_line_save = xmalloc(len);
572         p = cmd_line_save;
573         for (int i = 0; i < argc; i++) {
574                 strcpy(p, argv[i]);
575                 p += strlen(argv[i]);
576                 if (!(i == argc - 1)) {
577                         *p = ' ';       /* overwrite \0 with ' ' */
578                         p++;
579                 }
580         }
581 }
582
583 static void global_usage(void)
584 {
585         fprintf(stderr, "  Usage: perf COMMAND [ARGS]\n");
586         fprintf(stderr, "\n  Available commands:\n\n");
587         for (int i = 0; i < COUNT_OF(perf_cmds); i++)
588                 fprintf(stderr, "  \t%s: %s\n", perf_cmds[i].name, perf_cmds[i].desc);
589         exit(-1);
590 }
591
592 int main(int argc, char *argv[])
593 {
594         int i, ret = -1;
595
596         save_cmdline(argc, argv);
597
598         /* Common inits.  Some functions don't need these, but it doesn't hurt. */
599         perf_initialize();
600         pctx = perf_create_context(&perf_cfg);
601         cctx = perfconv_create_context(pctx);
602
603         if (argc < 2)
604                 global_usage();
605         for (i = 0; i < COUNT_OF(perf_cmds); i++) {
606                 if (!strcmp(perf_cmds[i].name, argv[1])) {
607                         ret = perf_cmds[i].func(&perf_cmds[i], argc - 1, argv + 1);
608                         break;
609                 }
610         }
611         if (i == COUNT_OF(perf_cmds))
612                 global_usage();
613         /* This cleanup is optional - they'll all be dealt with when the program
614          * exits.  This means its safe for us to exit(-1) at any point in the
615          * program. */
616         perf_free_context(pctx);
617         perfconv_free_context(cctx);
618         perf_finalize();
619         return ret;
620 }