b99205f917ab4f3fc474f33432771860a76df223
[akaros.git] / tools / dev-util / 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,
334                              opts.got_cores ? &opts.cores : NULL);
335         perf_stop_sampling(pctx);
336         if (opts.verbose)
337                 perf_context_show_events(pctx, stdout);
338         /* The events are still counting and firing IRQs.  Let's be nice and turn
339          * them off to minimize our impact. */
340         perf_stop_events(pctx);
341         /* Generate the Linux perf file format with the traces which have been
342          * created during this operation. */
343         perf_convert_trace_data(cctx, perf_cfg.kpdata_file, opts.outfile);
344         fclose(opts.outfile);
345         return 0;
346 }
347
348 /**************************** perf stat  ************************/
349
350 static struct argp_option stat_opts[] = {
351         {"big-num", 'B', 0, 0, "Formatting option"},
352         {"output", 'o', "FILE", 0, "Print output to file (default stdout)"},
353         { 0 }
354 };
355
356 static error_t parse_stat_opt(int key, char *arg, struct argp_state *state)
357 {
358         struct perf_opts *p_opts = state->input;
359
360         switch (key) {
361         case 'B':
362                 p_opts->stat_bignum = TRUE;
363                 break;
364         case 'o':
365                 p_opts->outfile = xfopen(arg, "w");
366                 break;
367         case ARGP_KEY_END:
368                 if (!p_opts->events)
369                         p_opts->events = "cache-misses,cache-references,"
370                                          "branch-misses,branches,instructions,cycles";
371                 if (!p_opts->outfile)
372                         p_opts->outfile = stdout;
373                 break;
374         default:
375                 return ARGP_ERR_UNKNOWN;
376         }
377         return 0;
378 }
379
380 struct stat_val {
381         char                                            *name;
382         uint64_t                                        count;
383 };
384
385 /* Helper, given a name, fetches its value as a float. */
386 static float get_count_for(char *name, struct stat_val *all_vals,
387                            size_t nr_vals)
388 {
389         for (int i = 0; i < nr_vals; i++) {
390                 if (!strcmp(name, all_vals[i].name))
391                         return (float)all_vals[i].count;
392         }
393         return 0.0;
394 }
395
396 /* Helper, gets the seconds count as a float */
397 static float get_seconds(struct stat_val *all_vals, size_t nr_vals)
398 {
399         float sec = get_count_for("nsec", all_vals, nr_vals) / 1000000000;
400
401         /* We should never have a time of 0, but in case something went wrong, don't
402          * hand back 0 (divide by 0 errors). */
403         return sec != 0.0 ? sec : 1.0;
404 }
405
406 /* Prints "X per second", scaling for K, M, or G. */
407 static void print_default_rate(FILE *out, struct stat_val *val,
408                                struct stat_val *all_vals, size_t nr_vals)
409 {
410         float rate = val->count / get_seconds(all_vals, nr_vals);
411         char scale = ' ';
412
413         if (rate > 1000000000) {
414                 rate /= 1000000000;
415                 scale = 'G';
416         } else if (rate > 1000000) {
417                 rate /= 1000000;
418                 scale = 'M';
419         } else if (rate > 1000) {
420                 rate /= 1000;
421                 scale = 'K';
422         }
423         fprintf(out, "%9.3f %c/sec\n", rate, scale);
424 }
425
426 /* Prints a line for the given stat val.  We pass all the vals since some stats
427  * will adjust their output based on *other* known values.  e.g. IPC. */
428 static void stat_print_val(FILE *out, struct stat_val *val,
429                            struct stat_val *all_vals, size_t nr_vals)
430 {
431         /* Everyone gets the same front part of the printout */
432         fprintf(out, "%18llu      %-25s #", val->count, val->name);
433
434         /* Based on the particular event and what other events we know, we may print
435          * something different to the summary bit after the #. */
436         if (!strcmp(val->name, "instructions")) {
437                 float cycles = get_count_for("cycles", all_vals, nr_vals);
438
439                 if (cycles != 0.0)
440                         fprintf(out, "%9.3f insns per cycle\n", val->count / cycles);
441                 else
442                         print_default_rate(out, val, all_vals, nr_vals);
443         } else if (!strcmp(val->name, "cache-misses")) {
444                 float cache_ref = get_count_for("cache-references", all_vals, nr_vals);
445
446                 if (cache_ref != 0.0)
447                         fprintf(out, "%8.2f%% of all refs\n", val->count * 100 / cache_ref);
448                 else
449                         print_default_rate(out, val, all_vals, nr_vals);
450         } else if (!strcmp(val->name, "branch-misses")) {
451                 float branches = get_count_for("branches", all_vals, nr_vals);
452
453                 if (branches != 0.0)
454                         fprintf(out, "%8.2f%% of all branches\n",
455                                 val->count * 100 / branches);
456                 else
457                         print_default_rate(out, val, all_vals, nr_vals);
458         } else {
459                 print_default_rate(out, val, all_vals, nr_vals);
460         }
461 }
462
463 static char *cmd_as_str(int argc, char *const argv[])
464 {
465         size_t len = 0;
466         char *str;
467
468         for (int i = 0; i < argc; i++)
469                 len += strlen(argv[i]) + 1;
470         str = xzmalloc(len);
471         for (int i = 0; i < argc; i++) {
472                 strlcat(str, argv[i], len);
473                 if (i != argc - 1)
474                         strlcat(str, " ", len);
475         }
476         return str;
477 }
478
479 static struct stat_val *collect_stats(struct perf_context *pctx,
480                                       struct timespec *diff)
481 {
482         struct stat_val *stat_vals;
483
484         /* the last stat is time (nsec). */
485         stat_vals = xzmalloc(sizeof(struct stat_val) * (pctx->event_count + 1));
486         for (int i = 0; i < pctx->event_count; i++) {
487                 stat_vals[i].count = perf_get_event_count(pctx, i);
488                 stat_vals[i].name = pctx->events[i].sel.fq_str;
489         }
490         stat_vals[pctx->event_count].name = "nsec";
491         stat_vals[pctx->event_count].count = diff->tv_sec * 1000000000 +
492                                              diff->tv_nsec;
493         return stat_vals;
494 }
495
496 static int perf_stat(struct perf_cmd *cmd, int argc, char *argv[])
497 {
498         struct argp argp_stat = {stat_opts, parse_stat_opt};
499         struct argp_child children[] = { {&argp_stat, 0, 0, 0}, {0} };
500         FILE *out;
501         struct timespec start, end, diff;
502         struct stat_val *stat_vals;
503         char *cmd_string;
504
505         collect_argp(cmd, argc, argv, children, &opts);
506         opts.sampling = FALSE;
507         out = opts.outfile;
508
509         /* As soon as we submit one event, that event is being tracked, meaning that
510          * the setup/teardown of perf events is also tracked.  Each event (including
511          * the clock measurement) will roughly account for either the start or stop
512          * of every other event. */
513         clock_gettime(CLOCK_REALTIME, &start);
514         submit_events(&opts);
515         run_process_and_wait(opts.cmd_argc, opts.cmd_argv,
516                              opts.got_cores ? &opts.cores : NULL);
517         clock_gettime(CLOCK_REALTIME, &end);
518         subtract_timespecs(&diff, &end, &start);
519         stat_vals = collect_stats(pctx, &diff);
520         perf_stop_events(pctx);
521         cmd_string = cmd_as_str(opts.cmd_argc, opts.cmd_argv);
522         fprintf(out, "\nPerformance counter stats for '%s':\n\n", cmd_string);
523         free(cmd_string);
524         for (int i = 0; i < pctx->event_count; i++)
525                 stat_print_val(out, &stat_vals[i], stat_vals, pctx->event_count + 1);
526         fprintf(out, "\n%8llu.%09llu seconds time elapsed\n\n", diff.tv_sec,
527                 diff.tv_nsec);
528         fclose(out);
529         free(stat_vals);
530         return 0;
531 }
532
533 static void run_process_and_wait(int argc, char *argv[],
534                                                                  const struct core_set *cores)
535 {
536         int pid, status;
537         size_t max_cores = ros_total_cores();
538         struct core_set pvcores;
539
540         pid = create_child_with_stdfds(argv[0], argc, argv, environ);
541         if (pid < 0) {
542                 perror("Unable to spawn child");
543                 fflush(stderr);
544                 exit(1);
545         }
546         if (cores) {
547                 ros_get_low_latency_core_set(&pvcores);
548                 ros_not_core_set(&pvcores);
549                 ros_and_core_sets(&pvcores, cores);
550                 for (size_t i = 0; i < max_cores; i++) {
551                         if (ros_get_bit(&pvcores, i)) {
552                                 if (sys_provision(pid, RES_CORES, i)) {
553                                         fprintf(stderr,
554                                                         "Unable to provision CPU %lu to PID %d: cmd='%s'\n",
555                                                         i, pid, argv[0]);
556                                         sys_proc_destroy(pid, -1);
557                                         exit(1);
558                                 }
559                         }
560                 }
561         }
562         sys_proc_run(pid);
563         waitpid(pid, &status, 0);
564 }
565
566 static void save_cmdline(int argc, char *argv[])
567 {
568         size_t len = 0;
569         char *p;
570
571         for (int i = 0; i < argc; i++)
572                 len += strlen(argv[i]) + 1;
573         cmd_line_save = xmalloc(len);
574         p = cmd_line_save;
575         for (int i = 0; i < argc; i++) {
576                 strcpy(p, argv[i]);
577                 p += strlen(argv[i]);
578                 if (!(i == argc - 1)) {
579                         *p = ' ';       /* overwrite \0 with ' ' */
580                         p++;
581                 }
582         }
583 }
584
585 static void global_usage(void)
586 {
587         fprintf(stderr, "  Usage: perf COMMAND [ARGS]\n");
588         fprintf(stderr, "\n  Available commands:\n\n");
589         for (int i = 0; i < COUNT_OF(perf_cmds); i++)
590                 fprintf(stderr, "  \t%s: %s\n", perf_cmds[i].name, perf_cmds[i].desc);
591         exit(-1);
592 }
593
594 int main(int argc, char *argv[])
595 {
596         int i, ret = -1;
597
598         save_cmdline(argc, argv);
599
600         /* Common inits.  Some functions don't need these, but it doesn't hurt. */
601         perf_initialize();
602         pctx = perf_create_context(&perf_cfg);
603         cctx = perfconv_create_context(pctx);
604
605         if (argc < 2)
606                 global_usage();
607         for (i = 0; i < COUNT_OF(perf_cmds); i++) {
608                 if (!strcmp(perf_cmds[i].name, argv[1])) {
609                         ret = perf_cmds[i].func(&perf_cmds[i], argc - 1, argv + 1);
610                         break;
611                 }
612         }
613         if (i == COUNT_OF(perf_cmds))
614                 global_usage();
615         /* This cleanup is optional - they'll all be dealt with when the program
616          * exits.  This means its safe for us to exit(-1) at any point in the
617          * program. */
618         perf_free_context(pctx);
619         perfconv_free_context(cctx);
620         perf_finalize();
621         return ret;
622 }