diff options
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r-- | tools/perf/builtin-report.c | 31 |
1 files changed, 25 insertions, 6 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 140a6cd88351..39367609c707 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -226,8 +226,9 @@ static int report__setup_sample_type(struct report *rep) | |||
226 | return -EINVAL; | 226 | return -EINVAL; |
227 | } | 227 | } |
228 | if (symbol_conf.use_callchain) { | 228 | if (symbol_conf.use_callchain) { |
229 | ui__error("Selected -g but no callchain data. Did " | 229 | ui__error("Selected -g or --branch-history but no " |
230 | "you call 'perf record' without -g?\n"); | 230 | "callchain data. Did\n" |
231 | "you call 'perf record' without -g?\n"); | ||
231 | return -1; | 232 | return -1; |
232 | } | 233 | } |
233 | } else if (!rep->dont_use_callchains && | 234 | } else if (!rep->dont_use_callchains && |
@@ -575,6 +576,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
575 | struct stat st; | 576 | struct stat st; |
576 | bool has_br_stack = false; | 577 | bool has_br_stack = false; |
577 | int branch_mode = -1; | 578 | int branch_mode = -1; |
579 | bool branch_call_mode = false; | ||
578 | char callchain_default_opt[] = "fractal,0.5,callee"; | 580 | char callchain_default_opt[] = "fractal,0.5,callee"; |
579 | const char * const report_usage[] = { | 581 | const char * const report_usage[] = { |
580 | "perf report [<options>]", | 582 | "perf report [<options>]", |
@@ -637,8 +639,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
637 | "regex filter to identify parent, see: '--sort parent'"), | 639 | "regex filter to identify parent, see: '--sort parent'"), |
638 | OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, | 640 | OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, |
639 | "Only display entries with parent-match"), | 641 | "Only display entries with parent-match"), |
640 | OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order", | 642 | OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order[,branch]", |
641 | "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). " | 643 | "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address), add branches. " |
642 | "Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt), | 644 | "Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt), |
643 | OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, | 645 | OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, |
644 | "Accumulate callchains of children and show total overhead as well"), | 646 | "Accumulate callchains of children and show total overhead as well"), |
@@ -684,7 +686,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
684 | OPT_BOOLEAN(0, "group", &symbol_conf.event_group, | 686 | OPT_BOOLEAN(0, "group", &symbol_conf.event_group, |
685 | "Show event group information together"), | 687 | "Show event group information together"), |
686 | OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "", | 688 | OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "", |
687 | "use branch records for histogram filling", parse_branch_mode), | 689 | "use branch records for per branch histogram filling", |
690 | parse_branch_mode), | ||
691 | OPT_BOOLEAN(0, "branch-history", &branch_call_mode, | ||
692 | "add last branch records to call history"), | ||
688 | OPT_STRING(0, "objdump", &objdump_path, "path", | 693 | OPT_STRING(0, "objdump", &objdump_path, "path", |
689 | "objdump binary to use for disassembly and annotations"), | 694 | "objdump binary to use for disassembly and annotations"), |
690 | OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, | 695 | OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, |
@@ -745,10 +750,24 @@ repeat: | |||
745 | has_br_stack = perf_header__has_feat(&session->header, | 750 | has_br_stack = perf_header__has_feat(&session->header, |
746 | HEADER_BRANCH_STACK); | 751 | HEADER_BRANCH_STACK); |
747 | 752 | ||
748 | if ((branch_mode == -1 && has_br_stack) || branch_mode == 1) { | 753 | /* |
754 | * Branch mode is a tristate: | ||
755 | * -1 means default, so decide based on the file having branch data. | ||
756 | * 0/1 means the user chose a mode. | ||
757 | */ | ||
758 | if (((branch_mode == -1 && has_br_stack) || branch_mode == 1) && | ||
759 | branch_call_mode == -1) { | ||
749 | sort__mode = SORT_MODE__BRANCH; | 760 | sort__mode = SORT_MODE__BRANCH; |
750 | symbol_conf.cumulate_callchain = false; | 761 | symbol_conf.cumulate_callchain = false; |
751 | } | 762 | } |
763 | if (branch_call_mode) { | ||
764 | callchain_param.key = CCKEY_ADDRESS; | ||
765 | callchain_param.branch_callstack = 1; | ||
766 | symbol_conf.use_callchain = true; | ||
767 | callchain_register_param(&callchain_param); | ||
768 | if (sort_order == NULL) | ||
769 | sort_order = "srcline,symbol,dso"; | ||
770 | } | ||
752 | 771 | ||
753 | if (report.mem_mode) { | 772 | if (report.mem_mode) { |
754 | if (sort__mode == SORT_MODE__BRANCH) { | 773 | if (sort__mode == SORT_MODE__BRANCH) { |