diff options
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r-- | tools/perf/builtin-report.c | 97 |
1 files changed, 53 insertions, 44 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 5d2e819dfc4..8795520f6e1 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -35,7 +35,9 @@ | |||
35 | 35 | ||
36 | #include <linux/bitmap.h> | 36 | #include <linux/bitmap.h> |
37 | 37 | ||
38 | static struct perf_report { | 38 | struct perf_report { |
39 | struct perf_event_ops ops; | ||
40 | struct perf_session *session; | ||
39 | char const *input_name; | 41 | char const *input_name; |
40 | bool force, use_tui, use_stdio; | 42 | bool force, use_tui, use_stdio; |
41 | bool hide_unresolved; | 43 | bool hide_unresolved; |
@@ -48,12 +50,7 @@ static struct perf_report { | |||
48 | symbol_filter_t annotate_init; | 50 | symbol_filter_t annotate_init; |
49 | const char *cpu_list; | 51 | const char *cpu_list; |
50 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 52 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
51 | } report = { | 53 | }; |
52 | .input_name = "perf.data", | ||
53 | .pretty_printing_style = "normal", | ||
54 | }, *rep = &report; | ||
55 | |||
56 | static char callchain_default_opt[] = "fractal,0.5,callee"; | ||
57 | 54 | ||
58 | static int perf_session__add_hist_entry(struct perf_session *session, | 55 | static int perf_session__add_hist_entry(struct perf_session *session, |
59 | struct addr_location *al, | 56 | struct addr_location *al, |
@@ -106,11 +103,13 @@ out: | |||
106 | } | 103 | } |
107 | 104 | ||
108 | 105 | ||
109 | static int process_sample_event(union perf_event *event, | 106 | static int process_sample_event(struct perf_event_ops *ops, |
107 | union perf_event *event, | ||
110 | struct perf_sample *sample, | 108 | struct perf_sample *sample, |
111 | struct perf_evsel *evsel, | 109 | struct perf_evsel *evsel, |
112 | struct perf_session *session) | 110 | struct perf_session *session) |
113 | { | 111 | { |
112 | struct perf_report *rep = container_of(ops, struct perf_report, ops); | ||
114 | struct addr_location al; | 113 | struct addr_location al; |
115 | 114 | ||
116 | if (perf_event__preprocess_sample(event, session, &al, sample, | 115 | if (perf_event__preprocess_sample(event, session, &al, sample, |
@@ -137,10 +136,12 @@ static int process_sample_event(union perf_event *event, | |||
137 | return 0; | 136 | return 0; |
138 | } | 137 | } |
139 | 138 | ||
140 | static int process_read_event(union perf_event *event, | 139 | static int process_read_event(struct perf_event_ops *ops, |
140 | union perf_event *event, | ||
141 | struct perf_sample *sample __used, | 141 | struct perf_sample *sample __used, |
142 | struct perf_session *session) | 142 | struct perf_session *session) |
143 | { | 143 | { |
144 | struct perf_report *rep = container_of(ops, struct perf_report, ops); | ||
144 | struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, | 145 | struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, |
145 | event->read.id); | 146 | event->read.id); |
146 | if (rep->show_threads) { | 147 | if (rep->show_threads) { |
@@ -159,8 +160,10 @@ static int process_read_event(union perf_event *event, | |||
159 | return 0; | 160 | return 0; |
160 | } | 161 | } |
161 | 162 | ||
162 | static int perf_session__setup_sample_type(struct perf_session *self) | 163 | static int perf_report__setup_sample_type(struct perf_report *rep) |
163 | { | 164 | { |
165 | struct perf_session *self = rep->session; | ||
166 | |||
164 | if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { | 167 | if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { |
165 | if (sort__has_parent) { | 168 | if (sort__has_parent) { |
166 | ui__warning("Selected --sort parent, but no " | 169 | ui__warning("Selected --sort parent, but no " |
@@ -187,22 +190,6 @@ static int perf_session__setup_sample_type(struct perf_session *self) | |||
187 | return 0; | 190 | return 0; |
188 | } | 191 | } |
189 | 192 | ||
190 | static struct perf_event_ops event_ops = { | ||
191 | .sample = process_sample_event, | ||
192 | .mmap = perf_event__process_mmap, | ||
193 | .comm = perf_event__process_comm, | ||
194 | .exit = perf_event__process_task, | ||
195 | .fork = perf_event__process_task, | ||
196 | .lost = perf_event__process_lost, | ||
197 | .read = process_read_event, | ||
198 | .attr = perf_event__process_attr, | ||
199 | .event_type = perf_event__process_event_type, | ||
200 | .tracing_data = perf_event__process_tracing_data, | ||
201 | .build_id = perf_event__process_build_id, | ||
202 | .ordered_samples = true, | ||
203 | .ordering_requires_timestamps = true, | ||
204 | }; | ||
205 | |||
206 | extern volatile int session_done; | 193 | extern volatile int session_done; |
207 | 194 | ||
208 | static void sig_handler(int sig __used) | 195 | static void sig_handler(int sig __used) |
@@ -225,6 +212,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self, | |||
225 | } | 212 | } |
226 | 213 | ||
227 | static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | 214 | static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, |
215 | struct perf_report *rep, | ||
228 | const char *help) | 216 | const char *help) |
229 | { | 217 | { |
230 | struct perf_evsel *pos; | 218 | struct perf_evsel *pos; |
@@ -253,7 +241,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | |||
253 | return 0; | 241 | return 0; |
254 | } | 242 | } |
255 | 243 | ||
256 | static int __cmd_report(void) | 244 | static int __cmd_report(struct perf_report *rep) |
257 | { | 245 | { |
258 | int ret = -EINVAL; | 246 | int ret = -EINVAL; |
259 | u64 nr_samples; | 247 | u64 nr_samples; |
@@ -266,10 +254,12 @@ static int __cmd_report(void) | |||
266 | signal(SIGINT, sig_handler); | 254 | signal(SIGINT, sig_handler); |
267 | 255 | ||
268 | session = perf_session__new(rep->input_name, O_RDONLY, | 256 | session = perf_session__new(rep->input_name, O_RDONLY, |
269 | rep->force, false, &event_ops); | 257 | rep->force, false, &rep->ops); |
270 | if (session == NULL) | 258 | if (session == NULL) |
271 | return -ENOMEM; | 259 | return -ENOMEM; |
272 | 260 | ||
261 | rep->session = session; | ||
262 | |||
273 | if (rep->cpu_list) { | 263 | if (rep->cpu_list) { |
274 | ret = perf_session__cpu_bitmap(session, rep->cpu_list, | 264 | ret = perf_session__cpu_bitmap(session, rep->cpu_list, |
275 | rep->cpu_bitmap); | 265 | rep->cpu_bitmap); |
@@ -283,11 +273,11 @@ static int __cmd_report(void) | |||
283 | if (rep->show_threads) | 273 | if (rep->show_threads) |
284 | perf_read_values_init(&rep->show_threads_values); | 274 | perf_read_values_init(&rep->show_threads_values); |
285 | 275 | ||
286 | ret = perf_session__setup_sample_type(session); | 276 | ret = perf_report__setup_sample_type(rep); |
287 | if (ret) | 277 | if (ret) |
288 | goto out_delete; | 278 | goto out_delete; |
289 | 279 | ||
290 | ret = perf_session__process_events(session, &event_ops); | 280 | ret = perf_session__process_events(session, &rep->ops); |
291 | if (ret) | 281 | if (ret) |
292 | goto out_delete; | 282 | goto out_delete; |
293 | 283 | ||
@@ -339,7 +329,7 @@ static int __cmd_report(void) | |||
339 | perf_evlist__tui_browse_hists(session->evlist, help, | 329 | perf_evlist__tui_browse_hists(session->evlist, help, |
340 | NULL, NULL, 0); | 330 | NULL, NULL, 0); |
341 | } else | 331 | } else |
342 | perf_evlist__tty_browse_hists(session->evlist, help); | 332 | perf_evlist__tty_browse_hists(session->evlist, rep, help); |
343 | 333 | ||
344 | out_delete: | 334 | out_delete: |
345 | /* | 335 | /* |
@@ -358,9 +348,9 @@ out_delete: | |||
358 | } | 348 | } |
359 | 349 | ||
360 | static int | 350 | static int |
361 | parse_callchain_opt(const struct option *opt __used, const char *arg, | 351 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) |
362 | int unset) | ||
363 | { | 352 | { |
353 | struct perf_report *rep = (struct perf_report *)opt->value; | ||
364 | char *tok, *tok2; | 354 | char *tok, *tok2; |
365 | char *endptr; | 355 | char *endptr; |
366 | 356 | ||
@@ -437,12 +427,33 @@ setup: | |||
437 | return 0; | 427 | return 0; |
438 | } | 428 | } |
439 | 429 | ||
440 | static const char * const report_usage[] = { | 430 | int cmd_report(int argc, const char **argv, const char *prefix __used) |
441 | "perf report [<options>] <command>", | 431 | { |
442 | NULL | 432 | char callchain_default_opt[] = "fractal,0.5,callee"; |
443 | }; | 433 | const char * const report_usage[] = { |
444 | 434 | "perf report [<options>] <command>", | |
445 | static const struct option options[] = { | 435 | NULL |
436 | }; | ||
437 | struct perf_report report = { | ||
438 | .ops = { | ||
439 | .sample = process_sample_event, | ||
440 | .mmap = perf_event__process_mmap, | ||
441 | .comm = perf_event__process_comm, | ||
442 | .exit = perf_event__process_task, | ||
443 | .fork = perf_event__process_task, | ||
444 | .lost = perf_event__process_lost, | ||
445 | .read = process_read_event, | ||
446 | .attr = perf_event__process_attr, | ||
447 | .event_type = perf_event__process_event_type, | ||
448 | .tracing_data = perf_event__process_tracing_data, | ||
449 | .build_id = perf_event__process_build_id, | ||
450 | .ordered_samples = true, | ||
451 | .ordering_requires_timestamps = true, | ||
452 | }, | ||
453 | .input_name = "perf.data", | ||
454 | .pretty_printing_style = "normal", | ||
455 | }; | ||
456 | const struct option options[] = { | ||
446 | OPT_STRING('i', "input", &report.input_name, "file", | 457 | OPT_STRING('i', "input", &report.input_name, "file", |
447 | "input file name"), | 458 | "input file name"), |
448 | OPT_INCR('v', "verbose", &verbose, | 459 | OPT_INCR('v', "verbose", &verbose, |
@@ -473,7 +484,7 @@ static const struct option options[] = { | |||
473 | "regex filter to identify parent, see: '--sort parent'"), | 484 | "regex filter to identify parent, see: '--sort parent'"), |
474 | OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, | 485 | OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, |
475 | "Only display entries with parent-match"), | 486 | "Only display entries with parent-match"), |
476 | OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent, call_order", | 487 | OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent, call_order", |
477 | "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. " | 488 | "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. " |
478 | "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), | 489 | "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), |
479 | OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, | 490 | OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, |
@@ -507,10 +518,8 @@ static const struct option options[] = { | |||
507 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, | 518 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, |
508 | "Show a column with the sum of periods"), | 519 | "Show a column with the sum of periods"), |
509 | OPT_END() | 520 | OPT_END() |
510 | }; | 521 | }; |
511 | 522 | ||
512 | int cmd_report(int argc, const char **argv, const char *prefix __used) | ||
513 | { | ||
514 | argc = parse_options(argc, argv, options, report_usage, 0); | 523 | argc = parse_options(argc, argv, options, report_usage, 0); |
515 | 524 | ||
516 | if (report.use_stdio) | 525 | if (report.use_stdio) |
@@ -579,5 +588,5 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) | |||
579 | sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); | 588 | sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); |
580 | sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); | 589 | sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); |
581 | 590 | ||
582 | return __cmd_report(); | 591 | return __cmd_report(&report); |
583 | } | 592 | } |