Move Linux perf format conversion into perf tool, drop kprof2perf
[akaros.git] / tools / profile / perf / perf.c
1 /* Copyright (c) 2015 Google Inc
2  * Davide Libenzi <dlibenzi@google.com>
3  * See LICENSE for details.
4  */
5
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <sys/wait.h>
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <limits.h>
16 #include <errno.h>
17 #include <parlib/parlib.h>
18 #include "xlib.h"
19 #include "akaros.h"
20 #include "perfconv.h"
21 #include "perf_core.h"
22
23 static struct perf_context_config perf_cfg = {
24         .perf_file = "#arch/perf",
25         .kpctl_file = "#kprof/kpctl",
26 };
27
28 static void usage(const char *prg)
29 {
30         fprintf(stderr,
31                         "Use: %s {list,cpucaps,record} [-mkecxoKh] -- CMD [ARGS ...]\n"
32                         "\tlist            Lists all the available events and their meaning.\n"
33                         "\tcpucaps         Shows the system CPU capabilities in term of "
34                         "performance counters.\n"
35                         "\trecord           Setups the configured counters, runs CMD, and "
36                         "shows the values of the counters.\n"
37                         "Options:\n"
38                         "\t-m PATH          Sets the path of the PERF file ('%s').\n"
39                         "\t-k PATH          Sets the path of the KPROF control file "
40                         "('%s').\n"
41                         "\t-e EVENT_SPEC    Adds an event to be tracked.\n"
42                         "\t-c CPUS_STR      Selects the CPU set on which the counters "
43                         "should be active.\n"
44                         "\t                 The following format is supported for the CPU "
45                         "set:\n"
46                         "\t                   !      = Negates the following set\n"
47                         "\t                   all    = Enable all CPUs\n"
48                         "\t                   llall  = Enable all low latency CPUs\n"
49                         "\t                   I.J.K  = Enable CPUs I, J, and K\n"
50                         "\t                   N-M    = Enable CPUs from N to M, included\n"
51                         "\t                 Examples: all:!3.4.7  0-15:!3.5.7\n"
52                         "\t-x EVENT_RX      Sets the event name regular expression for "
53                         "list.\n"
54                         "\t-o PATH          Sets the perf output file path ('perf.data').\n"
55                         "\t-K PATH          Sets the kprof data file path ('#kprof/kpdata').\n"
56                         "\t-h               Displays this help screen.\n", prg,
57                         perf_cfg.perf_file, perf_cfg.kpctl_file);
58         exit(1);
59 }
60
61 static void show_perf_arch_info(const struct perf_arch_info *pai, FILE *file)
62 {
63         fprintf(file,
64                         "PERF.version             = %u\n"
65                         "PERF.proc_arch_events    = %u\n"
66                         "PERF.bits_x_counter      = %u\n"
67                         "PERF.counters_x_proc     = %u\n"
68                         "PERF.bits_x_fix_counter  = %u\n"
69                         "PERF.fix_counters_x_proc = %u\n",
70                         pai->perfmon_version, pai->proc_arch_events, pai->bits_x_counter,
71                         pai->counters_x_proc, pai->bits_x_fix_counter,
72                         pai->fix_counters_x_proc);
73 }
74
75 static void run_process_and_wait(int argc, const char * const *argv,
76                                                                  const struct core_set *cores)
77 {
78         int pid, status;
79         size_t max_cores = ros_total_cores();
80         struct core_set pvcores;
81
82         pid = sys_proc_create(argv[0], strlen(argv[0]), argv, NULL, 0);
83         if (pid < 0) {
84                 perror(argv[0]);
85                 exit(1);
86         }
87
88         ros_get_low_latency_core_set(&pvcores);
89         ros_not_core_set(&pvcores);
90         ros_and_core_sets(&pvcores, cores);
91         for (size_t i = 0; i < max_cores; i++) {
92                 if (ros_get_bit(&pvcores, i)) {
93                         if (sys_provision(pid, RES_CORES, i)) {
94                                 fprintf(stderr,
95                                                 "Unable to provision CPU %lu to PID %d: cmd='%s'\n",
96                                                 i, pid, argv[0]);
97                                 exit(1);
98                         }
99                 }
100         }
101
102         sys_proc_run(pid);
103         waitpid(pid, &status, 0);
104 }
105
106 int main(int argc, const char * const *argv)
107 {
108         int i, icmd = -1, num_events = 0;
109         const char *cmd = argv[1], *show_rx = NULL;
110         const char *kpdata_file = "#kprof/kpdata", *outfile = "perf.data";
111         struct perfconv_context *cctx;
112         struct perf_context *pctx;
113         struct core_set cores;
114         const char *events[MAX_CPU_EVENTS];
115
116         ros_get_all_cores_set(&cores);
117         cctx = perfconv_create_context();
118
119         for (i = 2; i < argc; i++) {
120                 if (!strcmp(argv[i], "-m")) {
121                         if (++i < argc)
122                                 perf_cfg.perf_file = argv[i];
123                 } else if (!strcmp(argv[i], "-k")) {
124                         if (++i < argc)
125                                 perf_cfg.kpctl_file = argv[i];
126                 } else if (!strcmp(argv[i], "-e")) {
127                         if (++i < argc) {
128                                 if (num_events >= MAX_CPU_EVENTS) {
129                                         fprintf(stderr, "Too many events: %d\n", num_events);
130                                         return 1;
131                                 }
132                                 events[num_events++] = argv[i];
133                         }
134                 } else if (!strcmp(argv[i], "-x")) {
135                         if (++i < argc)
136                                 show_rx = argv[i];
137                 } else if (!strcmp(argv[i], "-c")) {
138                         if (++i < argc)
139                                 ros_parse_cores(argv[i], &cores);
140                 } else if (!strcmp(argv[i], "-o")) {
141                         if (++i < argc)
142                                 outfile = argv[i];
143                 } else if (!strcmp(argv[i], "-K")) {
144                         if (++i < argc)
145                                 kpdata_file = argv[i];
146                 } else if (!strcmp(argv[i], "--")) {
147                         icmd = i + 1;
148                         break;
149                 } else {
150                         usage(argv[0]);
151                 }
152         }
153         if (!cmd)
154                 usage(argv[0]);
155
156         perf_initialize(argc, argv);
157         pctx = perf_create_context(&perf_cfg);
158
159         if (!strcmp(cmd, "list")) {
160                 perf_show_events(show_rx, stdout);
161         } else if (!strcmp(cmd, "cpucaps")) {
162                 show_perf_arch_info(perf_context_get_arch_info(pctx), stdout);
163         } else if (!strcmp(cmd, "record")) {
164                 if (icmd < 0)
165                         usage(argv[0]);
166
167                 for (i = 0; i < num_events; i++) {
168                         struct perf_eventsel sel;
169
170                         perf_parse_event(events[i], &sel);
171                         perf_context_event_submit(pctx, &cores, &sel);
172                 }
173
174                 if (!strcmp(argv[icmd], "sleep") && (icmd + 1) < argc)
175                         sleep(atoi(argv[icmd + 1]));
176                 else
177                         run_process_and_wait(argc - icmd, argv + icmd, &cores);
178
179                 perf_context_show_values(pctx, stdout);
180
181                 /* Flush the profiler per-CPU trace data into the main queue, so that
182                  * it will be available for read.
183                  */
184                 perf_flush_context_traces(pctx);
185
186                 /* Generate the Linux perf file format with the traces which have been
187                  * created during this operation.
188                  */
189                 perf_convert_trace_data(cctx, kpdata_file, outfile);
190         } else {
191                 usage(argv[0]);
192         }
193         perf_free_context(pctx);
194         perfconv_free_context(cctx);
195         perf_finalize();
196
197         return 0;
198 }