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)  			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) {  |