diff options
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r-- | tools/perf/builtin-report.c | 105 |
1 files changed, 55 insertions, 50 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index bd0ca81eeaca..3662047cc6b1 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -52,6 +52,7 @@ struct perf_report { | |||
52 | symbol_filter_t annotate_init; | 52 | symbol_filter_t annotate_init; |
53 | const char *cpu_list; | 53 | const char *cpu_list; |
54 | const char *symbol_filter_str; | 54 | const char *symbol_filter_str; |
55 | float min_percent; | ||
55 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 56 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
56 | }; | 57 | }; |
57 | 58 | ||
@@ -61,6 +62,11 @@ static int perf_report_config(const char *var, const char *value, void *cb) | |||
61 | symbol_conf.event_group = perf_config_bool(var, value); | 62 | symbol_conf.event_group = perf_config_bool(var, value); |
62 | return 0; | 63 | return 0; |
63 | } | 64 | } |
65 | if (!strcmp(var, "report.percent-limit")) { | ||
66 | struct perf_report *rep = cb; | ||
67 | rep->min_percent = strtof(value, NULL); | ||
68 | return 0; | ||
69 | } | ||
64 | 70 | ||
65 | return perf_default_config(var, value, cb); | 71 | return perf_default_config(var, value, cb); |
66 | } | 72 | } |
@@ -187,6 +193,9 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, | |||
187 | for (i = 0; i < sample->branch_stack->nr; i++) { | 193 | for (i = 0; i < sample->branch_stack->nr; i++) { |
188 | if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym)) | 194 | if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym)) |
189 | continue; | 195 | continue; |
196 | |||
197 | err = -ENOMEM; | ||
198 | |||
190 | /* | 199 | /* |
191 | * The report shows the percentage of total branches captured | 200 | * The report shows the percentage of total branches captured |
192 | * and not events sampled. Thus we use a pseudo period of 1. | 201 | * and not events sampled. Thus we use a pseudo period of 1. |
@@ -195,7 +204,6 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, | |||
195 | &bi[i], 1, 1); | 204 | &bi[i], 1, 1); |
196 | if (he) { | 205 | if (he) { |
197 | struct annotation *notes; | 206 | struct annotation *notes; |
198 | err = -ENOMEM; | ||
199 | bx = he->branch_info; | 207 | bx = he->branch_info; |
200 | if (bx->from.sym && use_browser == 1 && sort__has_sym) { | 208 | if (bx->from.sym && use_browser == 1 && sort__has_sym) { |
201 | notes = symbol__annotation(bx->from.sym); | 209 | notes = symbol__annotation(bx->from.sym); |
@@ -226,11 +234,12 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, | |||
226 | } | 234 | } |
227 | evsel->hists.stats.total_period += 1; | 235 | evsel->hists.stats.total_period += 1; |
228 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | 236 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); |
229 | err = 0; | ||
230 | } else | 237 | } else |
231 | return -ENOMEM; | 238 | goto out; |
232 | } | 239 | } |
240 | err = 0; | ||
233 | out: | 241 | out: |
242 | free(bi); | ||
234 | return err; | 243 | return err; |
235 | } | 244 | } |
236 | 245 | ||
@@ -294,6 +303,7 @@ static int process_sample_event(struct perf_tool *tool, | |||
294 | { | 303 | { |
295 | struct perf_report *rep = container_of(tool, struct perf_report, tool); | 304 | struct perf_report *rep = container_of(tool, struct perf_report, tool); |
296 | struct addr_location al; | 305 | struct addr_location al; |
306 | int ret; | ||
297 | 307 | ||
298 | if (perf_event__preprocess_sample(event, machine, &al, sample, | 308 | if (perf_event__preprocess_sample(event, machine, &al, sample, |
299 | rep->annotate_init) < 0) { | 309 | rep->annotate_init) < 0) { |
@@ -308,28 +318,25 @@ static int process_sample_event(struct perf_tool *tool, | |||
308 | if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) | 318 | if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) |
309 | return 0; | 319 | return 0; |
310 | 320 | ||
311 | if (sort__branch_mode == 1) { | 321 | if (sort__mode == SORT_MODE__BRANCH) { |
312 | if (perf_report__add_branch_hist_entry(tool, &al, sample, | 322 | ret = perf_report__add_branch_hist_entry(tool, &al, sample, |
313 | evsel, machine)) { | 323 | evsel, machine); |
324 | if (ret < 0) | ||
314 | pr_debug("problem adding lbr entry, skipping event\n"); | 325 | pr_debug("problem adding lbr entry, skipping event\n"); |
315 | return -1; | ||
316 | } | ||
317 | } else if (rep->mem_mode == 1) { | 326 | } else if (rep->mem_mode == 1) { |
318 | if (perf_report__add_mem_hist_entry(tool, &al, sample, | 327 | ret = perf_report__add_mem_hist_entry(tool, &al, sample, |
319 | evsel, machine, event)) { | 328 | evsel, machine, event); |
329 | if (ret < 0) | ||
320 | pr_debug("problem adding mem entry, skipping event\n"); | 330 | pr_debug("problem adding mem entry, skipping event\n"); |
321 | return -1; | ||
322 | } | ||
323 | } else { | 331 | } else { |
324 | if (al.map != NULL) | 332 | if (al.map != NULL) |
325 | al.map->dso->hit = 1; | 333 | al.map->dso->hit = 1; |
326 | 334 | ||
327 | if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) { | 335 | ret = perf_evsel__add_hist_entry(evsel, &al, sample, machine); |
336 | if (ret < 0) | ||
328 | pr_debug("problem incrementing symbol period, skipping event\n"); | 337 | pr_debug("problem incrementing symbol period, skipping event\n"); |
329 | return -1; | ||
330 | } | ||
331 | } | 338 | } |
332 | return 0; | 339 | return ret; |
333 | } | 340 | } |
334 | 341 | ||
335 | static int process_read_event(struct perf_tool *tool, | 342 | static int process_read_event(struct perf_tool *tool, |
@@ -384,7 +391,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep) | |||
384 | } | 391 | } |
385 | } | 392 | } |
386 | 393 | ||
387 | if (sort__branch_mode == 1) { | 394 | if (sort__mode == SORT_MODE__BRANCH) { |
388 | if (!self->fd_pipe && | 395 | if (!self->fd_pipe && |
389 | !(sample_type & PERF_SAMPLE_BRANCH_STACK)) { | 396 | !(sample_type & PERF_SAMPLE_BRANCH_STACK)) { |
390 | ui__error("Selected -b but no branch data. " | 397 | ui__error("Selected -b but no branch data. " |
@@ -455,7 +462,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | |||
455 | continue; | 462 | continue; |
456 | 463 | ||
457 | hists__fprintf_nr_sample_events(rep, hists, evname, stdout); | 464 | hists__fprintf_nr_sample_events(rep, hists, evname, stdout); |
458 | hists__fprintf(hists, true, 0, 0, stdout); | 465 | hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout); |
459 | fprintf(stdout, "\n\n"); | 466 | fprintf(stdout, "\n\n"); |
460 | } | 467 | } |
461 | 468 | ||
@@ -574,8 +581,8 @@ static int __cmd_report(struct perf_report *rep) | |||
574 | if (use_browser > 0) { | 581 | if (use_browser > 0) { |
575 | if (use_browser == 1) { | 582 | if (use_browser == 1) { |
576 | ret = perf_evlist__tui_browse_hists(session->evlist, | 583 | ret = perf_evlist__tui_browse_hists(session->evlist, |
577 | help, | 584 | help, NULL, |
578 | NULL, | 585 | rep->min_percent, |
579 | &session->header.env); | 586 | &session->header.env); |
580 | /* | 587 | /* |
581 | * Usually "ret" is the last pressed key, and we only | 588 | * Usually "ret" is the last pressed key, and we only |
@@ -586,7 +593,7 @@ static int __cmd_report(struct perf_report *rep) | |||
586 | 593 | ||
587 | } else if (use_browser == 2) { | 594 | } else if (use_browser == 2) { |
588 | perf_evlist__gtk_browse_hists(session->evlist, help, | 595 | perf_evlist__gtk_browse_hists(session->evlist, help, |
589 | NULL); | 596 | NULL, rep->min_percent); |
590 | } | 597 | } |
591 | } else | 598 | } else |
592 | perf_evlist__tty_browse_hists(session->evlist, rep, help); | 599 | perf_evlist__tty_browse_hists(session->evlist, rep, help); |
@@ -691,7 +698,19 @@ static int | |||
691 | parse_branch_mode(const struct option *opt __maybe_unused, | 698 | parse_branch_mode(const struct option *opt __maybe_unused, |
692 | const char *str __maybe_unused, int unset) | 699 | const char *str __maybe_unused, int unset) |
693 | { | 700 | { |
694 | sort__branch_mode = !unset; | 701 | int *branch_mode = opt->value; |
702 | |||
703 | *branch_mode = !unset; | ||
704 | return 0; | ||
705 | } | ||
706 | |||
707 | static int | ||
708 | parse_percent_limit(const struct option *opt, const char *str, | ||
709 | int unset __maybe_unused) | ||
710 | { | ||
711 | struct perf_report *rep = opt->value; | ||
712 | |||
713 | rep->min_percent = strtof(str, NULL); | ||
695 | return 0; | 714 | return 0; |
696 | } | 715 | } |
697 | 716 | ||
@@ -700,6 +719,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
700 | struct perf_session *session; | 719 | struct perf_session *session; |
701 | struct stat st; | 720 | struct stat st; |
702 | bool has_br_stack = false; | 721 | bool has_br_stack = false; |
722 | int branch_mode = -1; | ||
703 | int ret = -1; | 723 | int ret = -1; |
704 | char callchain_default_opt[] = "fractal,0.5,callee"; | 724 | char callchain_default_opt[] = "fractal,0.5,callee"; |
705 | const char * const report_usage[] = { | 725 | const char * const report_usage[] = { |
@@ -796,17 +816,19 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
796 | "Show a column with the sum of periods"), | 816 | "Show a column with the sum of periods"), |
797 | OPT_BOOLEAN(0, "group", &symbol_conf.event_group, | 817 | OPT_BOOLEAN(0, "group", &symbol_conf.event_group, |
798 | "Show event group information together"), | 818 | "Show event group information together"), |
799 | OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "", | 819 | OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "", |
800 | "use branch records for histogram filling", parse_branch_mode), | 820 | "use branch records for histogram filling", parse_branch_mode), |
801 | OPT_STRING(0, "objdump", &objdump_path, "path", | 821 | OPT_STRING(0, "objdump", &objdump_path, "path", |
802 | "objdump binary to use for disassembly and annotations"), | 822 | "objdump binary to use for disassembly and annotations"), |
803 | OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, | 823 | OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, |
804 | "Disable symbol demangling"), | 824 | "Disable symbol demangling"), |
805 | OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"), | 825 | OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"), |
826 | OPT_CALLBACK(0, "percent-limit", &report, "percent", | ||
827 | "Don't show entries under that percent", parse_percent_limit), | ||
806 | OPT_END() | 828 | OPT_END() |
807 | }; | 829 | }; |
808 | 830 | ||
809 | perf_config(perf_report_config, NULL); | 831 | perf_config(perf_report_config, &report); |
810 | 832 | ||
811 | argc = parse_options(argc, argv, options, report_usage, 0); | 833 | argc = parse_options(argc, argv, options, report_usage, 0); |
812 | 834 | ||
@@ -846,11 +868,11 @@ repeat: | |||
846 | has_br_stack = perf_header__has_feat(&session->header, | 868 | has_br_stack = perf_header__has_feat(&session->header, |
847 | HEADER_BRANCH_STACK); | 869 | HEADER_BRANCH_STACK); |
848 | 870 | ||
849 | if (sort__branch_mode == -1 && has_br_stack) | 871 | if (branch_mode == -1 && has_br_stack) |
850 | sort__branch_mode = 1; | 872 | sort__mode = SORT_MODE__BRANCH; |
851 | 873 | ||
852 | /* sort__branch_mode could be 0 if --no-branch-stack */ | 874 | /* sort__mode could be NORMAL if --no-branch-stack */ |
853 | if (sort__branch_mode == 1) { | 875 | if (sort__mode == SORT_MODE__BRANCH) { |
854 | /* | 876 | /* |
855 | * if no sort_order is provided, then specify | 877 | * if no sort_order is provided, then specify |
856 | * branch-mode specific order | 878 | * branch-mode specific order |
@@ -861,10 +883,12 @@ repeat: | |||
861 | 883 | ||
862 | } | 884 | } |
863 | if (report.mem_mode) { | 885 | if (report.mem_mode) { |
864 | if (sort__branch_mode == 1) { | 886 | if (sort__mode == SORT_MODE__BRANCH) { |
865 | fprintf(stderr, "branch and mem mode incompatible\n"); | 887 | fprintf(stderr, "branch and mem mode incompatible\n"); |
866 | goto error; | 888 | goto error; |
867 | } | 889 | } |
890 | sort__mode = SORT_MODE__MEMORY; | ||
891 | |||
868 | /* | 892 | /* |
869 | * if no sort_order is provided, then specify | 893 | * if no sort_order is provided, then specify |
870 | * branch-mode specific order | 894 | * branch-mode specific order |
@@ -915,8 +939,7 @@ repeat: | |||
915 | */ | 939 | */ |
916 | if (!strstr(sort_order, "parent")) | 940 | if (!strstr(sort_order, "parent")) |
917 | sort_parent.elide = 1; | 941 | sort_parent.elide = 1; |
918 | } else | 942 | } |
919 | symbol_conf.exclude_other = false; | ||
920 | 943 | ||
921 | if (argc) { | 944 | if (argc) { |
922 | /* | 945 | /* |
@@ -929,25 +952,7 @@ repeat: | |||
929 | report.symbol_filter_str = argv[0]; | 952 | report.symbol_filter_str = argv[0]; |
930 | } | 953 | } |
931 | 954 | ||
932 | sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); | 955 | sort__setup_elide(stdout); |
933 | |||
934 | if (sort__branch_mode == 1) { | ||
935 | sort_entry__setup_elide(&sort_dso_from, symbol_conf.dso_from_list, "dso_from", stdout); | ||
936 | sort_entry__setup_elide(&sort_dso_to, symbol_conf.dso_to_list, "dso_to", stdout); | ||
937 | sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout); | ||
938 | sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout); | ||
939 | } else { | ||
940 | if (report.mem_mode) { | ||
941 | sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "symbol_daddr", stdout); | ||
942 | sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso_daddr", stdout); | ||
943 | sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "mem", stdout); | ||
944 | sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "local_weight", stdout); | ||
945 | sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "tlb", stdout); | ||
946 | sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "snoop", stdout); | ||
947 | } | ||
948 | sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout); | ||
949 | sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); | ||
950 | } | ||
951 | 956 | ||
952 | ret = __cmd_report(&report); | 957 | ret = __cmd_report(&report); |
953 | if (ret == K_SWITCH_INPUT_DATA) { | 958 | if (ret == K_SWITCH_INPUT_DATA) { |