diff options
Diffstat (limited to 'tools/perf/builtin-report.c')
| -rw-r--r-- | tools/perf/builtin-report.c | 150 | 
1 files changed, 140 insertions, 10 deletions
| diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 96b5a7fee4b..bd0ca81eeac 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -13,7 +13,6 @@  #include "util/annotate.h"  #include "util/color.h"  #include <linux/list.h> -#include "util/cache.h"  #include <linux/rbtree.h>  #include "util/symbol.h"  #include "util/callchain.h" @@ -47,6 +46,7 @@ struct perf_report {  	bool			show_full_info;  	bool			show_threads;  	bool			inverted_callchain; +	bool			mem_mode;  	struct perf_read_values	show_threads_values;  	const char		*pretty_printing_style;  	symbol_filter_t		annotate_init; @@ -65,6 +65,99 @@ static int perf_report_config(const char *var, const char *value, void *cb)  	return perf_default_config(var, value, cb);  } +static int perf_report__add_mem_hist_entry(struct perf_tool *tool, +					   struct addr_location *al, +					   struct perf_sample *sample, +					   struct perf_evsel *evsel, +					   struct machine *machine, +					   union perf_event *event) +{ +	struct perf_report *rep = container_of(tool, struct perf_report, tool); +	struct symbol *parent = NULL; +	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; +	int err = 0; +	struct hist_entry *he; +	struct mem_info *mi, *mx; +	uint64_t cost; + +	if ((sort__has_parent || symbol_conf.use_callchain) && +	    sample->callchain) { +		err = machine__resolve_callchain(machine, evsel, al->thread, +						 sample, &parent); +		if (err) +			return err; +	} + +	mi = machine__resolve_mem(machine, al->thread, sample, cpumode); +	if (!mi) +		return -ENOMEM; + +	if (rep->hide_unresolved && !al->sym) +		return 0; + +	cost = sample->weight; +	if (!cost) +		cost = 1; + +	/* +	 * must pass period=weight in order to get the correct +	 * sorting from hists__collapse_resort() which is solely +	 * based on periods. We want sorting be done on nr_events * weight +	 * and this is indirectly achieved by passing period=weight here +	 * and the he_stat__add_period() function. +	 */ +	he = __hists__add_mem_entry(&evsel->hists, al, parent, mi, cost, cost); +	if (!he) +		return -ENOMEM; + +	/* +	 * In the TUI browser, we are doing integrated annotation, +	 * so we don't allocate the extra space needed because the stdio +	 * code will not use it. +	 */ +	if (sort__has_sym && he->ms.sym && use_browser > 0) { +		struct annotation *notes = symbol__annotation(he->ms.sym); + +		assert(evsel != NULL); + +		if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0) +			goto out; + +		err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); +		if (err) +			goto out; +	} + +	if (sort__has_sym && he->mem_info->daddr.sym && use_browser > 0) { +		struct annotation *notes; + +		mx = he->mem_info; + +		notes = symbol__annotation(mx->daddr.sym); +		if (notes->src == NULL && symbol__alloc_hist(mx->daddr.sym) < 0) +			goto out; + +		err = symbol__inc_addr_samples(mx->daddr.sym, +					       mx->daddr.map, +					       evsel->idx, +					       mx->daddr.al_addr); +		if (err) +			goto out; +	} + +	evsel->hists.stats.total_period += cost; +	hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); +	err = 0; + +	if (symbol_conf.use_callchain) { +		err = callchain_append(he->callchain, +				       &callchain_cursor, +				       sample->period); +	} +out: +	return err; +} +  static int perf_report__add_branch_hist_entry(struct perf_tool *tool,  					struct addr_location *al,  					struct perf_sample *sample, @@ -99,7 +192,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,  		 * and not events sampled. Thus we use a pseudo period of 1.  		 */  		he = __hists__add_branch_entry(&evsel->hists, al, parent, -				&bi[i], 1); +				&bi[i], 1, 1);  		if (he) {  			struct annotation *notes;  			err = -ENOMEM; @@ -157,7 +250,8 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,  			return err;  	} -	he = __hists__add_entry(&evsel->hists, al, parent, sample->period); +	he = __hists__add_entry(&evsel->hists, al, parent, sample->period, +					sample->weight);  	if (he == NULL)  		return -ENOMEM; @@ -169,7 +263,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,  			return err;  	}  	/* -	 * Only in the newt browser we are doing integrated annotation, +	 * Only in the TUI browser we are doing integrated annotation,  	 * so we don't allocated the extra space needed because the stdio  	 * code will not use it.  	 */ @@ -220,6 +314,12 @@ static int process_sample_event(struct perf_tool *tool,  			pr_debug("problem adding lbr entry, skipping event\n");  			return -1;  		} +	} else if (rep->mem_mode == 1) { +		if (perf_report__add_mem_hist_entry(tool, &al, sample, +						    evsel, machine, event)) { +			pr_debug("problem adding mem entry, skipping event\n"); +			return -1; +		}  	} else {  		if (al.map != NULL)  			al.map->dso->hit = 1; @@ -303,7 +403,8 @@ static void sig_handler(int sig __maybe_unused)  	session_done = 1;  } -static size_t hists__fprintf_nr_sample_events(struct hists *self, +static size_t hists__fprintf_nr_sample_events(struct perf_report *rep, +					      struct hists *self,  					      const char *evname, FILE *fp)  {  	size_t ret; @@ -314,7 +415,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,  	char buf[512];  	size_t size = sizeof(buf); -	if (symbol_conf.event_group && evsel->nr_members > 1) { +	if (perf_evsel__is_group_event(evsel)) {  		struct perf_evsel *pos;  		perf_evsel__group_desc(evsel, buf, size); @@ -331,7 +432,11 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,  	if (evname != NULL)  		ret += fprintf(fp, " of event '%s'", evname); -	ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events); +	if (rep->mem_mode) { +		ret += fprintf(fp, "\n# Total weight : %" PRIu64, nr_events); +		ret += fprintf(fp, "\n# Sort order   : %s", sort_order); +	} else +		ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);  	return ret + fprintf(fp, "\n#\n");  } @@ -349,7 +454,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,  		    !perf_evsel__is_group_leader(pos))  			continue; -		hists__fprintf_nr_sample_events(hists, evname, stdout); +		hists__fprintf_nr_sample_events(rep, hists, evname, stdout);  		hists__fprintf(hists, true, 0, 0, stdout);  		fprintf(stdout, "\n\n");  	} @@ -645,7 +750,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)  		    "Use the stdio interface"),  	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",  		   "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," -		   " dso_to, dso_from, symbol_to, symbol_from, mispredict"), +		   " dso_to, dso_from, symbol_to, symbol_from, mispredict," +		   " weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, " +		   "snoop, locked"),  	OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,  		    "Show sample percentage for different cpu modes"),  	OPT_STRING('p', "parent", &parent_pattern, "regex", @@ -693,6 +800,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)  		    "use branch records for histogram filling", parse_branch_mode),  	OPT_STRING(0, "objdump", &objdump_path, "path",  		   "objdump binary to use for disassembly and annotations"), +	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, +		    "Disable symbol demangling"), +	OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),  	OPT_END()  	}; @@ -750,12 +860,24 @@ repeat:  				     "dso_to,symbol_to";  	} +	if (report.mem_mode) { +		if (sort__branch_mode == 1) { +			fprintf(stderr, "branch and mem mode incompatible\n"); +			goto error; +		} +		/* +		 * if no sort_order is provided, then specify +		 * branch-mode specific order +		 */ +		if (sort_order == default_sort_order) +			sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked"; +	}  	if (setup_sorting() < 0)  		usage_with_options(report_usage, options);  	/* -	 * Only in the newt browser we are doing integrated annotation, +	 * Only in the TUI browser we are doing integrated annotation,  	 * so don't allocate extra space that won't be used in the stdio  	 * implementation.  	 */ @@ -815,6 +937,14 @@ repeat:  		sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout);  		sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout);  	} else { +		if (report.mem_mode) { +			sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "symbol_daddr", stdout); +			sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso_daddr", stdout); +			sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "mem", stdout); +			sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "local_weight", stdout); +			sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "tlb", stdout); +			sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "snoop", stdout); +		}  		sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);  		sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);  	} |