diff options
Diffstat (limited to 'tools/perf/builtin-annotate.c')
| -rw-r--r-- | tools/perf/builtin-annotate.c | 98 | 
1 files changed, 97 insertions, 1 deletions
| diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index b1ed5f766cb..6a08da41f76 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -39,6 +39,8 @@ static int		dump_trace = 0;  static int		verbose; +static int		print_line; +  static unsigned long	page_size;  static unsigned long	mmap_window = 32; @@ -84,6 +86,12 @@ typedef union event_union {  	struct period_event		period;  } event_t; + +struct sym_ext { +	double		percent; +	char		*path; +}; +  static LIST_HEAD(dsos);  static struct dso *kernel_dso;  static struct dso *vdso; @@ -1034,6 +1042,8 @@ static int  parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)  {  	char *line = NULL, *tmp, *tmp2; +	static const char *prev_line; +	static const char *prev_color;  	unsigned int offset;  	size_t line_len;  	__u64 line_ip; @@ -1073,15 +1083,20 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)  	}  	if (line_ip != -1) { +		const char *path = NULL;  		unsigned int hits = 0;  		double percent = 0.0;  		char *color = PERF_COLOR_NORMAL; +		struct sym_ext *sym_ext = sym->priv;  		offset = line_ip - start;  		if (offset < len)  			hits = sym->hist[offset]; -		if (sym->hist_sum) +		if (sym_ext) { +			path = sym_ext[offset].path; +			percent = sym_ext[offset].percent; +		} else if (sym->hist_sum)  			percent = 100.0 * hits / sym->hist_sum;  		/* @@ -1096,6 +1111,20 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)  				color = PERF_COLOR_GREEN;  		} +		/* +		 * Also color the filename and line if needed, with +		 * the same color than the percentage. Don't print it +		 * twice for close colored ip with the same filename:line +		 */ +		if (path) { +			if (!prev_line || strcmp(prev_line, path) +				       || color != prev_color) { +				color_fprintf(stdout, color, " %s", path); +				prev_line = path; +				prev_color = color; +			} +		} +  		color_fprintf(stdout, color, " %7.2f", percent);  		printf(" :	");  		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line); @@ -1109,6 +1138,67 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)  	return 0;  } +static void free_source_line(struct symbol *sym, int len) +{ +	struct sym_ext *sym_ext = sym->priv; +	int i; + +	if (!sym_ext) +		return; + +	for (i = 0; i < len; i++) +		free(sym_ext[i].path); +	free(sym_ext); + +	sym->priv = NULL; +} + +/* Get the filename:line for the colored entries */ +static void get_source_line(struct symbol *sym, __u64 start, int len) +{ +	int i; +	char cmd[PATH_MAX * 2]; +	struct sym_ext *sym_ext; + +	if (!sym->hist_sum) +		return; + +	sym->priv = calloc(len, sizeof(struct sym_ext)); +	if (!sym->priv) +		return; + +	sym_ext = sym->priv; + +	for (i = 0; i < len; i++) { +		char *path = NULL; +		size_t line_len; +		__u64 offset; +		FILE *fp; + +		sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum; +		if (sym_ext[i].percent <= 0.5) +			continue; + +		offset = start + i; +		sprintf(cmd, "addr2line -e %s %016llx", vmlinux, offset); +		fp = popen(cmd, "r"); +		if (!fp) +			continue; + +		if (getline(&path, &line_len, fp) < 0 || !line_len) +			goto next; + +		sym_ext[i].path = malloc(sizeof(char) * line_len); +		if (!sym_ext[i].path) +			goto next; + +		strcpy(sym_ext[i].path, path); + +	next: +		pclose(fp); +	} +} +  static void annotate_sym(struct dso *dso, struct symbol *sym)  {  	char *filename = dso->name; @@ -1135,6 +1225,9 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)  	end = start + sym->end - sym->start + 1;  	len = sym->end - sym->start; +	if (print_line) +		get_source_line(sym, start, len); +  	sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (__u64)start, (__u64)end, filename);  	if (verbose >= 3) @@ -1150,6 +1243,7 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)  	}  	pclose(file); +	free_source_line(sym, len);  }  static void find_annotations(void) @@ -1308,6 +1402,8 @@ static const struct option options[] = {  	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,  		    "dump raw trace in ASCII"),  	OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), +	OPT_BOOLEAN('l', "print-line", &print_line, +		    "print matching source lines (may be slow)"),  	OPT_END()  }; | 
