aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-report.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r--tools/perf/builtin-report.c88
1 files changed, 48 insertions, 40 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 3662047cc6b1..9725aa375414 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -49,7 +49,6 @@ struct perf_report {
49 bool mem_mode; 49 bool mem_mode;
50 struct perf_read_values show_threads_values; 50 struct perf_read_values show_threads_values;
51 const char *pretty_printing_style; 51 const char *pretty_printing_style;
52 symbol_filter_t annotate_init;
53 const char *cpu_list; 52 const char *cpu_list;
54 const char *symbol_filter_str; 53 const char *symbol_filter_str;
55 float min_percent; 54 float min_percent;
@@ -89,7 +88,7 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
89 if ((sort__has_parent || symbol_conf.use_callchain) && 88 if ((sort__has_parent || symbol_conf.use_callchain) &&
90 sample->callchain) { 89 sample->callchain) {
91 err = machine__resolve_callchain(machine, evsel, al->thread, 90 err = machine__resolve_callchain(machine, evsel, al->thread,
92 sample, &parent); 91 sample, &parent, al);
93 if (err) 92 if (err)
94 return err; 93 return err;
95 } 94 }
@@ -180,7 +179,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
180 if ((sort__has_parent || symbol_conf.use_callchain) 179 if ((sort__has_parent || symbol_conf.use_callchain)
181 && sample->callchain) { 180 && sample->callchain) {
182 err = machine__resolve_callchain(machine, evsel, al->thread, 181 err = machine__resolve_callchain(machine, evsel, al->thread,
183 sample, &parent); 182 sample, &parent, al);
184 if (err) 183 if (err)
185 return err; 184 return err;
186 } 185 }
@@ -254,7 +253,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
254 253
255 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { 254 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
256 err = machine__resolve_callchain(machine, evsel, al->thread, 255 err = machine__resolve_callchain(machine, evsel, al->thread,
257 sample, &parent); 256 sample, &parent, al);
258 if (err) 257 if (err)
259 return err; 258 return err;
260 } 259 }
@@ -305,8 +304,7 @@ static int process_sample_event(struct perf_tool *tool,
305 struct addr_location al; 304 struct addr_location al;
306 int ret; 305 int ret;
307 306
308 if (perf_event__preprocess_sample(event, machine, &al, sample, 307 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
309 rep->annotate_init) < 0) {
310 fprintf(stderr, "problem processing %d event, skipping it.\n", 308 fprintf(stderr, "problem processing %d event, skipping it.\n",
311 event->header.type); 309 event->header.type);
312 return -1; 310 return -1;
@@ -367,7 +365,7 @@ static int process_read_event(struct perf_tool *tool,
367static int perf_report__setup_sample_type(struct perf_report *rep) 365static int perf_report__setup_sample_type(struct perf_report *rep)
368{ 366{
369 struct perf_session *self = rep->session; 367 struct perf_session *self = rep->session;
370 u64 sample_type = perf_evlist__sample_type(self->evlist); 368 u64 sample_type = perf_evlist__combined_sample_type(self->evlist);
371 369
372 if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { 370 if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
373 if (sort__has_parent) { 371 if (sort__has_parent) {
@@ -497,7 +495,7 @@ static int __cmd_report(struct perf_report *rep)
497 ret = perf_session__cpu_bitmap(session, rep->cpu_list, 495 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
498 rep->cpu_bitmap); 496 rep->cpu_bitmap);
499 if (ret) 497 if (ret)
500 goto out_delete; 498 return ret;
501 } 499 }
502 500
503 if (use_browser <= 0) 501 if (use_browser <= 0)
@@ -508,11 +506,11 @@ static int __cmd_report(struct perf_report *rep)
508 506
509 ret = perf_report__setup_sample_type(rep); 507 ret = perf_report__setup_sample_type(rep);
510 if (ret) 508 if (ret)
511 goto out_delete; 509 return ret;
512 510
513 ret = perf_session__process_events(session, &rep->tool); 511 ret = perf_session__process_events(session, &rep->tool);
514 if (ret) 512 if (ret)
515 goto out_delete; 513 return ret;
516 514
517 kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION]; 515 kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
518 kernel_kmap = map__kmap(kernel_map); 516 kernel_kmap = map__kmap(kernel_map);
@@ -547,7 +545,7 @@ static int __cmd_report(struct perf_report *rep)
547 545
548 if (dump_trace) { 546 if (dump_trace) {
549 perf_session__fprintf_nr_events(session, stdout); 547 perf_session__fprintf_nr_events(session, stdout);
550 goto out_delete; 548 return 0;
551 } 549 }
552 550
553 nr_samples = 0; 551 nr_samples = 0;
@@ -572,7 +570,7 @@ static int __cmd_report(struct perf_report *rep)
572 570
573 if (nr_samples == 0) { 571 if (nr_samples == 0) {
574 ui__error("The %s file has no samples!\n", session->filename); 572 ui__error("The %s file has no samples!\n", session->filename);
575 goto out_delete; 573 return 0;
576 } 574 }
577 575
578 list_for_each_entry(pos, &session->evlist->entries, node) 576 list_for_each_entry(pos, &session->evlist->entries, node)
@@ -598,19 +596,6 @@ static int __cmd_report(struct perf_report *rep)
598 } else 596 } else
599 perf_evlist__tty_browse_hists(session->evlist, rep, help); 597 perf_evlist__tty_browse_hists(session->evlist, rep, help);
600 598
601out_delete:
602 /*
603 * Speed up the exit process, for large files this can
604 * take quite a while.
605 *
606 * XXX Enable this when using valgrind or if we ever
607 * librarize this command.
608 *
609 * Also experiment with obstacks to see how much speed
610 * up we'll get here.
611 *
612 * perf_session__delete(session);
613 */
614 return ret; 599 return ret;
615} 600}
616 601
@@ -680,12 +665,23 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
680 } 665 }
681 666
682 /* get the call chain order */ 667 /* get the call chain order */
683 if (!strcmp(tok2, "caller")) 668 if (!strncmp(tok2, "caller", strlen("caller")))
684 callchain_param.order = ORDER_CALLER; 669 callchain_param.order = ORDER_CALLER;
685 else if (!strcmp(tok2, "callee")) 670 else if (!strncmp(tok2, "callee", strlen("callee")))
686 callchain_param.order = ORDER_CALLEE; 671 callchain_param.order = ORDER_CALLEE;
687 else 672 else
688 return -1; 673 return -1;
674
675 /* Get the sort key */
676 tok2 = strtok(NULL, ",");
677 if (!tok2)
678 goto setup;
679 if (!strncmp(tok2, "function", strlen("function")))
680 callchain_param.key = CCKEY_FUNCTION;
681 else if (!strncmp(tok2, "address", strlen("address")))
682 callchain_param.key = CCKEY_ADDRESS;
683 else
684 return -1;
689setup: 685setup:
690 if (callchain_register_param(&callchain_param) < 0) { 686 if (callchain_register_param(&callchain_param) < 0) {
691 fprintf(stderr, "Can't register callchain params\n"); 687 fprintf(stderr, "Can't register callchain params\n");
@@ -694,6 +690,24 @@ setup:
694 return 0; 690 return 0;
695} 691}
696 692
693int
694report_parse_ignore_callees_opt(const struct option *opt __maybe_unused,
695 const char *arg, int unset __maybe_unused)
696{
697 if (arg) {
698 int err = regcomp(&ignore_callees_regex, arg, REG_EXTENDED);
699 if (err) {
700 char buf[BUFSIZ];
701 regerror(err, &ignore_callees_regex, buf, sizeof(buf));
702 pr_err("Invalid --ignore-callees regex: %s\n%s", arg, buf);
703 return -1;
704 }
705 have_ignore_callees = 1;
706 }
707
708 return 0;
709}
710
697static int 711static int
698parse_branch_mode(const struct option *opt __maybe_unused, 712parse_branch_mode(const struct option *opt __maybe_unused,
699 const char *str __maybe_unused, int unset) 713 const char *str __maybe_unused, int unset)
@@ -736,7 +750,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
736 .lost = perf_event__process_lost, 750 .lost = perf_event__process_lost,
737 .read = process_read_event, 751 .read = process_read_event,
738 .attr = perf_event__process_attr, 752 .attr = perf_event__process_attr,
739 .event_type = perf_event__process_event_type,
740 .tracing_data = perf_event__process_tracing_data, 753 .tracing_data = perf_event__process_tracing_data,
741 .build_id = perf_event__process_build_id, 754 .build_id = perf_event__process_build_id,
742 .ordered_samples = true, 755 .ordered_samples = true,
@@ -780,10 +793,13 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
780 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, 793 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
781 "Only display entries with parent-match"), 794 "Only display entries with parent-match"),
782 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order", 795 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
783 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit and callchain order. " 796 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
784 "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), 797 "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt),
785 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, 798 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
786 "alias for inverted call graph"), 799 "alias for inverted call graph"),
800 OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
801 "ignore callees of these functions in call graphs",
802 report_parse_ignore_callees_opt),
787 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 803 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
788 "only consider symbols in these dsos"), 804 "only consider symbols in these dsos"),
789 OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", 805 OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
@@ -853,7 +869,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
853 setup_browser(true); 869 setup_browser(true);
854 else { 870 else {
855 use_browser = 0; 871 use_browser = 0;
856 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
857 perf_hpp__init(); 872 perf_hpp__init();
858 } 873 }
859 874
@@ -907,7 +922,8 @@ repeat:
907 */ 922 */
908 if (use_browser == 1 && sort__has_sym) { 923 if (use_browser == 1 && sort__has_sym) {
909 symbol_conf.priv_size = sizeof(struct annotation); 924 symbol_conf.priv_size = sizeof(struct annotation);
910 report.annotate_init = symbol__annotate_init; 925 machines__set_symbol_filter(&session->machines,
926 symbol__annotate_init);
911 /* 927 /*
912 * For searching by name on the "Browse map details". 928 * For searching by name on the "Browse map details".
913 * providing it only in verbose mode not to bloat too 929 * providing it only in verbose mode not to bloat too
@@ -931,14 +947,6 @@ repeat:
931 if (parent_pattern != default_parent_pattern) { 947 if (parent_pattern != default_parent_pattern) {
932 if (sort_dimension__add("parent") < 0) 948 if (sort_dimension__add("parent") < 0)
933 goto error; 949 goto error;
934
935 /*
936 * Only show the parent fields if we explicitly
937 * sort that way. If we only use parent machinery
938 * for filtering, we don't want it.
939 */
940 if (!strstr(sort_order, "parent"))
941 sort_parent.elide = 1;
942 } 950 }
943 951
944 if (argc) { 952 if (argc) {