|
@@ -226,8 +226,9 @@ static int report__setup_sample_type(struct report *rep)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
if (symbol_conf.use_callchain) {
|
|
|
- ui__error("Selected -g but no callchain data. Did "
|
|
|
- "you call 'perf record' without -g?\n");
|
|
|
+ ui__error("Selected -g or --branch-history but no "
|
|
|
+ "callchain data. Did\n"
|
|
|
+ "you call 'perf record' without -g?\n");
|
|
|
return -1;
|
|
|
}
|
|
|
} else if (!rep->dont_use_callchains &&
|
|
@@ -575,6 +576,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
|
|
struct stat st;
|
|
|
bool has_br_stack = false;
|
|
|
int branch_mode = -1;
|
|
|
+ bool branch_call_mode = false;
|
|
|
char callchain_default_opt[] = "fractal,0.5,callee";
|
|
|
const char * const report_usage[] = {
|
|
|
"perf report [<options>]",
|
|
@@ -637,8 +639,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
|
|
"regex filter to identify parent, see: '--sort parent'"),
|
|
|
OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
|
|
|
"Only display entries with parent-match"),
|
|
|
- OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
|
|
|
- "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
|
|
|
+ OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order[,branch]",
|
|
|
+ "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address), add branches. "
|
|
|
"Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt),
|
|
|
OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
|
|
|
"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)
|
|
|
OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
|
|
|
"Show event group information together"),
|
|
|
OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
|
|
|
- "use branch records for histogram filling", parse_branch_mode),
|
|
|
+ "use branch records for per branch histogram filling",
|
|
|
+ parse_branch_mode),
|
|
|
+ OPT_BOOLEAN(0, "branch-history", &branch_call_mode,
|
|
|
+ "add last branch records to call history"),
|
|
|
OPT_STRING(0, "objdump", &objdump_path, "path",
|
|
|
"objdump binary to use for disassembly and annotations"),
|
|
|
OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
|
|
@@ -745,10 +750,24 @@ repeat:
|
|
|
has_br_stack = perf_header__has_feat(&session->header,
|
|
|
HEADER_BRANCH_STACK);
|
|
|
|
|
|
- if ((branch_mode == -1 && has_br_stack) || branch_mode == 1) {
|
|
|
+ /*
|
|
|
+ * Branch mode is a tristate:
|
|
|
+ * -1 means default, so decide based on the file having branch data.
|
|
|
+ * 0/1 means the user chose a mode.
|
|
|
+ */
|
|
|
+ if (((branch_mode == -1 && has_br_stack) || branch_mode == 1) &&
|
|
|
+ branch_call_mode == -1) {
|
|
|
sort__mode = SORT_MODE__BRANCH;
|
|
|
symbol_conf.cumulate_callchain = false;
|
|
|
}
|
|
|
+ if (branch_call_mode) {
|
|
|
+ callchain_param.key = CCKEY_ADDRESS;
|
|
|
+ callchain_param.branch_callstack = 1;
|
|
|
+ symbol_conf.use_callchain = true;
|
|
|
+ callchain_register_param(&callchain_param);
|
|
|
+ if (sort_order == NULL)
|
|
|
+ sort_order = "srcline,symbol,dso";
|
|
|
+ }
|
|
|
|
|
|
if (report.mem_mode) {
|
|
|
if (sort__mode == SORT_MODE__BRANCH) {
|