diff options
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r-- | tools/perf/builtin-report.c | 88 |
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, | |||
367 | static int perf_report__setup_sample_type(struct perf_report *rep) | 365 | static 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 | ||
601 | out_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; | ||
689 | setup: | 685 | setup: |
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 | ||
693 | int | ||
694 | report_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 | |||
697 | static int | 711 | static int |
698 | parse_branch_mode(const struct option *opt __maybe_unused, | 712 | parse_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) { |