diff options
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r-- | tools/perf/builtin-report.c | 72 |
1 files changed, 57 insertions, 15 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 287a173523a..d7ff277bdb7 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -33,6 +33,8 @@ | |||
33 | #include "util/sort.h" | 33 | #include "util/sort.h" |
34 | #include "util/hist.h" | 34 | #include "util/hist.h" |
35 | 35 | ||
36 | #include <linux/bitmap.h> | ||
37 | |||
36 | static char const *input_name = "perf.data"; | 38 | static char const *input_name = "perf.data"; |
37 | 39 | ||
38 | static bool force, use_tui, use_stdio; | 40 | static bool force, use_tui, use_stdio; |
@@ -45,9 +47,13 @@ static struct perf_read_values show_threads_values; | |||
45 | static const char default_pretty_printing_style[] = "normal"; | 47 | static const char default_pretty_printing_style[] = "normal"; |
46 | static const char *pretty_printing_style = default_pretty_printing_style; | 48 | static const char *pretty_printing_style = default_pretty_printing_style; |
47 | 49 | ||
48 | static char callchain_default_opt[] = "fractal,0.5"; | 50 | static char callchain_default_opt[] = "fractal,0.5,callee"; |
51 | static bool inverted_callchain; | ||
49 | static symbol_filter_t annotate_init; | 52 | static symbol_filter_t annotate_init; |
50 | 53 | ||
54 | static const char *cpu_list; | ||
55 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | ||
56 | |||
51 | static int perf_session__add_hist_entry(struct perf_session *session, | 57 | static int perf_session__add_hist_entry(struct perf_session *session, |
52 | struct addr_location *al, | 58 | struct addr_location *al, |
53 | struct perf_sample *sample, | 59 | struct perf_sample *sample, |
@@ -116,6 +122,9 @@ static int process_sample_event(union perf_event *event, | |||
116 | if (al.filtered || (hide_unresolved && al.sym == NULL)) | 122 | if (al.filtered || (hide_unresolved && al.sym == NULL)) |
117 | return 0; | 123 | return 0; |
118 | 124 | ||
125 | if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) | ||
126 | return 0; | ||
127 | |||
119 | if (al.map != NULL) | 128 | if (al.map != NULL) |
120 | al.map->dso->hit = 1; | 129 | al.map->dso->hit = 1; |
121 | 130 | ||
@@ -153,23 +162,22 @@ static int perf_session__setup_sample_type(struct perf_session *self) | |||
153 | { | 162 | { |
154 | if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { | 163 | if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { |
155 | if (sort__has_parent) { | 164 | if (sort__has_parent) { |
156 | fprintf(stderr, "selected --sort parent, but no" | 165 | ui__warning("Selected --sort parent, but no " |
157 | " callchain data. Did you call" | 166 | "callchain data. Did you call " |
158 | " perf record without -g?\n"); | 167 | "'perf record' without -g?\n"); |
159 | return -EINVAL; | 168 | return -EINVAL; |
160 | } | 169 | } |
161 | if (symbol_conf.use_callchain) { | 170 | if (symbol_conf.use_callchain) { |
162 | fprintf(stderr, "selected -g but no callchain data." | 171 | ui__warning("Selected -g but no callchain data. Did " |
163 | " Did you call perf record without" | 172 | "you call 'perf record' without -g?\n"); |
164 | " -g?\n"); | ||
165 | return -1; | 173 | return -1; |
166 | } | 174 | } |
167 | } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && | 175 | } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && |
168 | !symbol_conf.use_callchain) { | 176 | !symbol_conf.use_callchain) { |
169 | symbol_conf.use_callchain = true; | 177 | symbol_conf.use_callchain = true; |
170 | if (callchain_register_param(&callchain_param) < 0) { | 178 | if (callchain_register_param(&callchain_param) < 0) { |
171 | fprintf(stderr, "Can't register callchain" | 179 | ui__warning("Can't register callchain " |
172 | " params\n"); | 180 | "params.\n"); |
173 | return -EINVAL; | 181 | return -EINVAL; |
174 | } | 182 | } |
175 | } | 183 | } |
@@ -262,6 +270,12 @@ static int __cmd_report(void) | |||
262 | if (session == NULL) | 270 | if (session == NULL) |
263 | return -ENOMEM; | 271 | return -ENOMEM; |
264 | 272 | ||
273 | if (cpu_list) { | ||
274 | ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); | ||
275 | if (ret) | ||
276 | goto out_delete; | ||
277 | } | ||
278 | |||
265 | if (show_threads) | 279 | if (show_threads) |
266 | perf_read_values_init(&show_threads_values); | 280 | perf_read_values_init(&show_threads_values); |
267 | 281 | ||
@@ -386,13 +400,29 @@ parse_callchain_opt(const struct option *opt __used, const char *arg, | |||
386 | if (!tok) | 400 | if (!tok) |
387 | goto setup; | 401 | goto setup; |
388 | 402 | ||
389 | tok2 = strtok(NULL, ","); | ||
390 | callchain_param.min_percent = strtod(tok, &endptr); | 403 | callchain_param.min_percent = strtod(tok, &endptr); |
391 | if (tok == endptr) | 404 | if (tok == endptr) |
392 | return -1; | 405 | return -1; |
393 | 406 | ||
394 | if (tok2) | 407 | /* get the print limit */ |
408 | tok2 = strtok(NULL, ","); | ||
409 | if (!tok2) | ||
410 | goto setup; | ||
411 | |||
412 | if (tok2[0] != 'c') { | ||
395 | callchain_param.print_limit = strtod(tok2, &endptr); | 413 | callchain_param.print_limit = strtod(tok2, &endptr); |
414 | tok2 = strtok(NULL, ","); | ||
415 | if (!tok2) | ||
416 | goto setup; | ||
417 | } | ||
418 | |||
419 | /* get the call chain order */ | ||
420 | if (!strcmp(tok2, "caller")) | ||
421 | callchain_param.order = ORDER_CALLER; | ||
422 | else if (!strcmp(tok2, "callee")) | ||
423 | callchain_param.order = ORDER_CALLEE; | ||
424 | else | ||
425 | return -1; | ||
396 | setup: | 426 | setup: |
397 | if (callchain_register_param(&callchain_param) < 0) { | 427 | if (callchain_register_param(&callchain_param) < 0) { |
398 | fprintf(stderr, "Can't register callchain params\n"); | 428 | fprintf(stderr, "Can't register callchain params\n"); |
@@ -436,9 +466,10 @@ static const struct option options[] = { | |||
436 | "regex filter to identify parent, see: '--sort parent'"), | 466 | "regex filter to identify parent, see: '--sort parent'"), |
437 | OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, | 467 | OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, |
438 | "Only display entries with parent-match"), | 468 | "Only display entries with parent-match"), |
439 | OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent", | 469 | OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent, call_order", |
440 | "Display callchains using output_type (graph, flat, fractal, or none) and min percent threshold. " | 470 | "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. " |
441 | "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt), | 471 | "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), |
472 | OPT_BOOLEAN('G', "inverted", &inverted_callchain, "alias for inverted call graph"), | ||
442 | OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", | 473 | OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", |
443 | "only consider symbols in these dsos"), | 474 | "only consider symbols in these dsos"), |
444 | OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", | 475 | OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", |
@@ -455,6 +486,7 @@ static const struct option options[] = { | |||
455 | "Only display entries resolved to a symbol"), | 486 | "Only display entries resolved to a symbol"), |
456 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | 487 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", |
457 | "Look for files with symbols relative to this directory"), | 488 | "Look for files with symbols relative to this directory"), |
489 | OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), | ||
458 | OPT_END() | 490 | OPT_END() |
459 | }; | 491 | }; |
460 | 492 | ||
@@ -467,6 +499,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) | |||
467 | else if (use_tui) | 499 | else if (use_tui) |
468 | use_browser = 1; | 500 | use_browser = 1; |
469 | 501 | ||
502 | if (inverted_callchain) | ||
503 | callchain_param.order = ORDER_CALLER; | ||
504 | |||
470 | if (strcmp(input_name, "-") != 0) | 505 | if (strcmp(input_name, "-") != 0) |
471 | setup_browser(true); | 506 | setup_browser(true); |
472 | else | 507 | else |
@@ -504,7 +539,14 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) | |||
504 | if (parent_pattern != default_parent_pattern) { | 539 | if (parent_pattern != default_parent_pattern) { |
505 | if (sort_dimension__add("parent") < 0) | 540 | if (sort_dimension__add("parent") < 0) |
506 | return -1; | 541 | return -1; |
507 | sort_parent.elide = 1; | 542 | |
543 | /* | ||
544 | * Only show the parent fields if we explicitly | ||
545 | * sort that way. If we only use parent machinery | ||
546 | * for filtering, we don't want it. | ||
547 | */ | ||
548 | if (!strstr(sort_order, "parent")) | ||
549 | sort_parent.elide = 1; | ||
508 | } else | 550 | } else |
509 | symbol_conf.exclude_other = false; | 551 | symbol_conf.exclude_other = false; |
510 | 552 | ||