diff options
Diffstat (limited to 'tools/perf/util/annotate.c')
| -rw-r--r-- | tools/perf/util/annotate.c | 149 | 
1 files changed, 100 insertions, 49 deletions
| diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index be1caabb9290..aa66791b1bfc 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -47,7 +47,12 @@ struct arch {  	bool		sorted_instructions;  	bool		initialized;  	void		*priv; +	unsigned int	model; +	unsigned int	family;  	int		(*init)(struct arch *arch); +	bool		(*ins_is_fused)(struct arch *arch, const char *ins1, +					const char *ins2); +	int		(*cpuid_parse)(struct arch *arch, char *cpuid);  	struct		{  		char comment_char;  		char skip_functions_char; @@ -129,6 +134,8 @@ static struct arch architectures[] = {  		.name = "x86",  		.instructions = x86__instructions,  		.nr_instructions = ARRAY_SIZE(x86__instructions), +		.ins_is_fused = x86__ins_is_fused, +		.cpuid_parse = x86__cpuid_parse,  		.objdump =  {  			.comment_char = '#',  		}, @@ -171,6 +178,14 @@ int ins__scnprintf(struct ins *ins, char *bf, size_t size,  	return ins__raw_scnprintf(ins, bf, size, ops);  } +bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2) +{ +	if (!arch || !arch->ins_is_fused) +		return false; + +	return arch->ins_is_fused(arch, ins1, ins2); +} +  static int call__parse(struct arch *arch, struct ins_operands *ops, struct map *map)  {  	char *endptr, *tok, *name; @@ -502,6 +517,11 @@ bool ins__is_ret(const struct ins *ins)  	return ins->ops == &ret_ops;  } +bool ins__is_lock(const struct ins *ins) +{ +	return ins->ops == &lock_ops; +} +  static int ins__key_cmp(const void *name, const void *insp)  {  	const struct ins *ins = insp; @@ -586,14 +606,24 @@ static struct arch *arch__find(const char *name)  int symbol__alloc_hist(struct symbol *sym)  {  	struct annotation *notes = symbol__annotation(sym); -	const size_t size = symbol__size(sym); +	size_t size = symbol__size(sym);  	size_t sizeof_sym_hist; +	/* +	 * Add buffer of one element for zero length symbol. +	 * When sample is taken from first instruction of +	 * zero length symbol, perf still resolves it and +	 * shows symbol name in perf report and allows to +	 * annotate it. +	 */ +	if (size == 0) +		size = 1; +  	/* Check for overflow when calculating sizeof_sym_hist */ -	if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(u64)) +	if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(struct sym_hist_entry))  		return -1; -	sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); +	sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(struct sym_hist_entry));  	/* Check for overflow in zalloc argument */  	if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src)) @@ -677,7 +707,8 @@ static int __symbol__account_cycles(struct annotation *notes,  }  static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, -				      struct annotation *notes, int evidx, u64 addr) +				      struct annotation *notes, int evidx, u64 addr, +				      struct perf_sample *sample)  {  	unsigned offset;  	struct sym_hist *h; @@ -693,12 +724,15 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map,  	offset = addr - sym->start;  	h = annotation__histogram(notes, evidx); -	h->sum++; -	h->addr[offset]++; +	h->nr_samples++; +	h->addr[offset].nr_samples++; +	h->period += sample->period; +	h->addr[offset].period += sample->period;  	pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64 -		  ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name, -		  addr, addr - sym->start, evidx, h->addr[offset]); +		  ", evidx=%d] => nr_samples: %" PRIu64 ", period: %" PRIu64 "\n", +		  sym->start, sym->name, addr, addr - sym->start, evidx, +		  h->addr[offset].nr_samples, h->addr[offset].period);  	return 0;  } @@ -718,7 +752,8 @@ static struct annotation *symbol__get_annotation(struct symbol *sym, bool cycles  }  static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, -				    int evidx, u64 addr) +				    int evidx, u64 addr, +				    struct perf_sample *sample)  {  	struct annotation *notes; @@ -727,7 +762,7 @@ static int symbol__inc_addr_samples(struct symbol *sym, struct map *map,  	notes = symbol__get_annotation(sym, false);  	if (notes == NULL)  		return -ENOMEM; -	return __symbol__inc_addr_samples(sym, map, notes, evidx, addr); +	return __symbol__inc_addr_samples(sym, map, notes, evidx, addr, sample);  }  static int symbol__account_cycles(u64 addr, u64 start, @@ -791,14 +826,16 @@ int addr_map_symbol__account_cycles(struct addr_map_symbol *ams,  	return err;  } -int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx) +int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, +				 int evidx)  { -	return symbol__inc_addr_samples(ams->sym, ams->map, evidx, ams->al_addr); +	return symbol__inc_addr_samples(ams->sym, ams->map, evidx, ams->al_addr, sample);  } -int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) +int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, +				 int evidx, u64 ip)  { -	return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); +	return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip, sample);  }  static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map *map) @@ -908,11 +945,12 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa  }  double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, -			    s64 end, const char **path, u64 *nr_samples) +			    s64 end, const char **path, struct sym_hist_entry *sample)  {  	struct source_line *src_line = notes->src->lines;  	double percent = 0.0; -	*nr_samples = 0; + +	sample->nr_samples = sample->period = 0;  	if (src_line) {  		size_t sizeof_src_line = sizeof(*src_line) + @@ -926,19 +964,24 @@ double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,  				*path = src_line->path;  			percent += src_line->samples[evidx].percent; -			*nr_samples += src_line->samples[evidx].nr; +			sample->nr_samples += src_line->samples[evidx].nr;  			offset++;  		}  	} else {  		struct sym_hist *h = annotation__histogram(notes, evidx);  		unsigned int hits = 0; +		u64 period = 0; -		while (offset < end) -			hits += h->addr[offset++]; +		while (offset < end) { +			hits   += h->addr[offset].nr_samples; +			period += h->addr[offset].period; +			++offset; +		} -		if (h->sum) { -			*nr_samples = hits; -			percent = 100.0 * hits / h->sum; +		if (h->nr_samples) { +			sample->period	   = period; +			sample->nr_samples = hits; +			percent = 100.0 * hits / h->nr_samples;  		}  	} @@ -1037,10 +1080,10 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st  	if (dl->offset != -1) {  		const char *path = NULL; -		u64 nr_samples;  		double percent, max_percent = 0.0;  		double *ppercents = &percent; -		u64 *psamples = &nr_samples; +		struct sym_hist_entry sample; +		struct sym_hist_entry *psamples = &sample;  		int i, nr_percent = 1;  		const char *color;  		struct annotation *notes = symbol__annotation(sym); @@ -1054,7 +1097,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st  		if (perf_evsel__is_group_event(evsel)) {  			nr_percent = evsel->nr_members;  			ppercents = calloc(nr_percent, sizeof(double)); -			psamples = calloc(nr_percent, sizeof(u64)); +			psamples = calloc(nr_percent, sizeof(struct sym_hist_entry));  			if (ppercents == NULL || psamples == NULL) {  				return -1;  			} @@ -1065,10 +1108,10 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st  					notes->src->lines ? i : evsel->idx + i,  					offset,  					next ? next->offset : (s64) len, -					&path, &nr_samples); +					&path, &sample);  			ppercents[i] = percent; -			psamples[i] = nr_samples; +			psamples[i] = sample;  			if (percent > max_percent)  				max_percent = percent;  		} @@ -1106,12 +1149,15 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st  		for (i = 0; i < nr_percent; i++) {  			percent = ppercents[i]; -			nr_samples = psamples[i]; +			sample = psamples[i];  			color = get_percent_color(percent);  			if (symbol_conf.show_total_period) +				color_fprintf(stdout, color, " %11" PRIu64, +					      sample.period); +			else if (symbol_conf.show_nr_samples)  				color_fprintf(stdout, color, " %7" PRIu64, -					      nr_samples); +					      sample.nr_samples);  			else  				color_fprintf(stdout, color, " %7.2f", percent);  		} @@ -1127,13 +1173,13 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st  		if (ppercents != &percent)  			free(ppercents); -		if (psamples != &nr_samples) +		if (psamples != &sample)  			free(psamples);  	} else if (max_lines && printed >= max_lines)  		return 1;  	else { -		int width = 8; +		int width = symbol_conf.show_total_period ? 12 : 8;  		if (queue)  			return -1; @@ -1327,7 +1373,7 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil  	    !dso__is_kcore(dso))  		return SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX; -	build_id_filename = dso__build_id_filename(dso, NULL, 0); +	build_id_filename = dso__build_id_filename(dso, NULL, 0, false);  	if (build_id_filename) {  		__symbol__join_symfs(filename, filename_size, build_id_filename);  		free(build_id_filename); @@ -1381,7 +1427,7 @@ static const char *annotate__norm_arch(const char *arch_name)  int symbol__disassemble(struct symbol *sym, struct map *map,  			const char *arch_name, size_t privsize, -			struct arch **parch) +			struct arch **parch, char *cpuid)  {  	struct dso *dso = map->dso;  	char command[PATH_MAX * 2]; @@ -1418,6 +1464,9 @@ int symbol__disassemble(struct symbol *sym, struct map *map,  		}  	} +	if (arch->cpuid_parse && cpuid) +		arch->cpuid_parse(arch, cpuid); +  	pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,  		 symfs_filename, sym->name, map->unmap_ip(map, sym->start),  		 map->unmap_ip(map, sym->end)); @@ -1648,19 +1697,19 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,  	struct sym_hist *h = annotation__histogram(notes, evidx);  	struct rb_root tmp_root = RB_ROOT;  	int nr_pcnt = 1; -	u64 h_sum = h->sum; +	u64 nr_samples = h->nr_samples;  	size_t sizeof_src_line = sizeof(struct source_line);  	if (perf_evsel__is_group_event(evsel)) {  		for (i = 1; i < evsel->nr_members; i++) {  			h = annotation__histogram(notes, evidx + i); -			h_sum += h->sum; +			nr_samples += h->nr_samples;  		}  		nr_pcnt = evsel->nr_members;  		sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->samples);  	} -	if (!h_sum) +	if (!nr_samples)  		return 0;  	src_line = notes->src->lines = calloc(len, sizeof_src_line); @@ -1670,7 +1719,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,  	start = map__rip_2objdump(map, sym->start);  	for (i = 0; i < len; i++) { -		u64 offset, nr_samples; +		u64 offset;  		double percent_max = 0.0;  		src_line->nr_pcnt = nr_pcnt; @@ -1679,9 +1728,9 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,  			double percent = 0.0;  			h = annotation__histogram(notes, evidx + k); -			nr_samples = h->addr[i]; -			if (h->sum) -				percent = 100.0 * nr_samples / h->sum; +			nr_samples = h->addr[i].nr_samples; +			if (h->nr_samples) +				percent = 100.0 * nr_samples / h->nr_samples;  			if (percent > percent_max)  				percent_max = percent; @@ -1750,10 +1799,10 @@ static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel)  	u64 len = symbol__size(sym), offset;  	for (offset = 0; offset < len; ++offset) -		if (h->addr[offset] != 0) +		if (h->addr[offset].nr_samples != 0)  			printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2, -			       sym->start + offset, h->addr[offset]); -	printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); +			       sym->start + offset, h->addr[offset].nr_samples); +	printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->nr_samples", h->nr_samples);  }  int symbol__annotate_printf(struct symbol *sym, struct map *map, @@ -1771,7 +1820,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,  	int printed = 2, queue_len = 0;  	int more = 0;  	u64 len; -	int width = 8; +	int width = symbol_conf.show_total_period ? 12 : 8;  	int graph_dotted_len;  	filename = strdup(dso->long_name); @@ -1789,7 +1838,9 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,  		width *= evsel->nr_members;  	graph_dotted_len = printf(" %-*.*s|	Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n", -	       width, width, "Percent", d_filename, evsel_name, h->sum); +				  width, width, symbol_conf.show_total_period ? "Period" : +				  symbol_conf.show_nr_samples ? "Samples" : "Percent", +				  d_filename, evsel_name, h->nr_samples);  	printf("%-*.*s----\n",  	       graph_dotted_len, graph_dotted_len, graph_dotted_line); @@ -1853,10 +1904,10 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)  	struct sym_hist *h = annotation__histogram(notes, evidx);  	int len = symbol__size(sym), offset; -	h->sum = 0; +	h->nr_samples = 0;  	for (offset = 0; offset < len; ++offset) { -		h->addr[offset] = h->addr[offset] * 7 / 8; -		h->sum += h->addr[offset]; +		h->addr[offset].nr_samples = h->addr[offset].nr_samples * 7 / 8; +		h->nr_samples += h->addr[offset].nr_samples;  	}  } @@ -1907,7 +1958,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,  	u64 len;  	if (symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), -				0, NULL) < 0) +				0, NULL, NULL) < 0)  		return -1;  	len = symbol__size(sym); |