diff options
Diffstat (limited to 'tools/perf/util/annotate.c')
| -rw-r--r-- | tools/perf/util/annotate.c | 262 | 
1 files changed, 199 insertions, 63 deletions
| diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index d33fe937e6f..d102716c43a 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -14,6 +14,7 @@  #include "symbol.h"  #include "debug.h"  #include "annotate.h" +#include "evsel.h"  #include <pthread.h>  #include <linux/bitops.h> @@ -602,8 +603,42 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa  	return NULL;  } +double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, +			    s64 end, const char **path) +{ +	struct source_line *src_line = notes->src->lines; +	double percent = 0.0; + +	if (src_line) { +		size_t sizeof_src_line = sizeof(*src_line) + +				sizeof(src_line->p) * (src_line->nr_pcnt - 1); + +		while (offset < end) { +			src_line = (void *)notes->src->lines + +					(sizeof_src_line * offset); + +			if (*path == NULL) +				*path = src_line->path; + +			percent += src_line->p[evidx].percent; +			offset++; +		} +	} else { +		struct sym_hist *h = annotation__histogram(notes, evidx); +		unsigned int hits = 0; + +		while (offset < end) +			hits += h->addr[offset++]; + +		if (h->sum) +			percent = 100.0 * hits / h->sum; +	} + +	return percent; +} +  static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, -		      int evidx, u64 len, int min_pcnt, int printed, +		      struct perf_evsel *evsel, u64 len, int min_pcnt, int printed,  		      int max_lines, struct disasm_line *queue)  {  	static const char *prev_line; @@ -611,34 +646,37 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st  	if (dl->offset != -1) {  		const char *path = NULL; -		unsigned int hits = 0; -		double percent = 0.0; +		double percent, max_percent = 0.0; +		double *ppercents = &percent; +		int i, nr_percent = 1;  		const char *color;  		struct annotation *notes = symbol__annotation(sym); -		struct source_line *src_line = notes->src->lines; -		struct sym_hist *h = annotation__histogram(notes, evidx);  		s64 offset = dl->offset;  		const u64 addr = start + offset;  		struct disasm_line *next;  		next = disasm__get_next_ip_line(¬es->src->source, dl); -		while (offset < (s64)len && -		       (next == NULL || offset < next->offset)) { -			if (src_line) { -				if (path == NULL) -					path = src_line[offset].path; -				percent += src_line[offset].percent; -			} else -				hits += h->addr[offset]; - -			++offset; +		if (perf_evsel__is_group_event(evsel)) { +			nr_percent = evsel->nr_members; +			ppercents = calloc(nr_percent, sizeof(double)); +			if (ppercents == NULL) +				return -1;  		} -		if (src_line == NULL && h->sum) -			percent = 100.0 * hits / h->sum; +		for (i = 0; i < nr_percent; i++) { +			percent = disasm__calc_percent(notes, +					notes->src->lines ? i : evsel->idx + i, +					offset, +					next ? next->offset : (s64) len, +					&path); + +			ppercents[i] = percent; +			if (percent > max_percent) +				max_percent = percent; +		} -		if (percent < min_pcnt) +		if (max_percent < min_pcnt)  			return -1;  		if (max_lines && printed >= max_lines) @@ -648,12 +686,12 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st  			list_for_each_entry_from(queue, ¬es->src->source, node) {  				if (queue == dl)  					break; -				disasm_line__print(queue, sym, start, evidx, len, +				disasm_line__print(queue, sym, start, evsel, len,  						    0, 0, 1, NULL);  			}  		} -		color = get_percent_color(percent); +		color = get_percent_color(max_percent);  		/*  		 * Also color the filename and line if needed, with @@ -669,25 +707,59 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st  			}  		} -		color_fprintf(stdout, color, " %7.2f", percent); +		for (i = 0; i < nr_percent; i++) { +			percent = ppercents[i]; +			color = get_percent_color(percent); +			color_fprintf(stdout, color, " %7.2f", percent); +		} +  		printf(" :	");  		color_fprintf(stdout, PERF_COLOR_MAGENTA, "  %" PRIx64 ":", addr);  		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); + +		if (ppercents != &percent) +			free(ppercents); +  	} else if (max_lines && printed >= max_lines)  		return 1;  	else { +		int width = 8; +  		if (queue)  			return -1; +		if (perf_evsel__is_group_event(evsel)) +			width *= evsel->nr_members; +  		if (!*dl->line) -			printf("         :\n"); +			printf(" %*s:\n", width, " ");  		else -			printf("         :	%s\n", dl->line); +			printf(" %*s:	%s\n", width, " ", dl->line);  	}  	return 0;  } +/* + * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw) + * which looks like following + * + *  0000000000415500 <_init>: + *    415500:       sub    $0x8,%rsp + *    415504:       mov    0x2f5ad5(%rip),%rax        # 70afe0 <_DYNAMIC+0x2f8> + *    41550b:       test   %rax,%rax + *    41550e:       je     415515 <_init+0x15> + *    415510:       callq  416e70 <__gmon_start__@plt> + *    415515:       add    $0x8,%rsp + *    415519:       retq + * + * it will be parsed and saved into struct disasm_line as + *  <offset>       <name>  <ops.raw> + * + * The offset will be a relative offset from the start of the symbol and -1 + * means that it's not a disassembly line so should be treated differently. + * The ops.raw part will be parsed further according to type of the instruction. + */  static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,  				      FILE *file, size_t privsize)  { @@ -858,7 +930,7 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin  	struct source_line *iter;  	struct rb_node **p = &root->rb_node;  	struct rb_node *parent = NULL; -	int ret; +	int i, ret;  	while (*p != NULL) {  		parent = *p; @@ -866,7 +938,8 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin  		ret = strcmp(iter->path, src_line->path);  		if (ret == 0) { -			iter->percent_sum += src_line->percent; +			for (i = 0; i < src_line->nr_pcnt; i++) +				iter->p[i].percent_sum += src_line->p[i].percent;  			return;  		} @@ -876,12 +949,26 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin  			p = &(*p)->rb_right;  	} -	src_line->percent_sum = src_line->percent; +	for (i = 0; i < src_line->nr_pcnt; i++) +		src_line->p[i].percent_sum = src_line->p[i].percent;  	rb_link_node(&src_line->node, parent, p);  	rb_insert_color(&src_line->node, root);  } +static int cmp_source_line(struct source_line *a, struct source_line *b) +{ +	int i; + +	for (i = 0; i < a->nr_pcnt; i++) { +		if (a->p[i].percent_sum == b->p[i].percent_sum) +			continue; +		return a->p[i].percent_sum > b->p[i].percent_sum; +	} + +	return 0; +} +  static void __resort_source_line(struct rb_root *root, struct source_line *src_line)  {  	struct source_line *iter; @@ -892,7 +979,7 @@ static void __resort_source_line(struct rb_root *root, struct source_line *src_l  		parent = *p;  		iter = rb_entry(parent, struct source_line, node); -		if (src_line->percent_sum > iter->percent_sum) +		if (cmp_source_line(src_line, iter))  			p = &(*p)->rb_left;  		else  			p = &(*p)->rb_right; @@ -924,32 +1011,52 @@ static void symbol__free_source_line(struct symbol *sym, int len)  {  	struct annotation *notes = symbol__annotation(sym);  	struct source_line *src_line = notes->src->lines; +	size_t sizeof_src_line;  	int i; -	for (i = 0; i < len; i++) -		free(src_line[i].path); +	sizeof_src_line = sizeof(*src_line) + +			  (sizeof(src_line->p) * (src_line->nr_pcnt - 1)); + +	for (i = 0; i < len; i++) { +		free(src_line->path); +		src_line = (void *)src_line + sizeof_src_line; +	} -	free(src_line); +	free(notes->src->lines);  	notes->src->lines = NULL;  }  /* Get the filename:line for the colored entries */  static int symbol__get_source_line(struct symbol *sym, struct map *map, -				   int evidx, struct rb_root *root, int len, +				   struct perf_evsel *evsel, +				   struct rb_root *root, int len,  				   const char *filename)  {  	u64 start; -	int i; +	int i, k; +	int evidx = evsel->idx;  	char cmd[PATH_MAX * 2];  	struct source_line *src_line;  	struct annotation *notes = symbol__annotation(sym);  	struct sym_hist *h = annotation__histogram(notes, evidx);  	struct rb_root tmp_root = RB_ROOT; +	int nr_pcnt = 1; +	u64 h_sum = h->sum; +	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_pcnt = evsel->nr_members; +		sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->p); +	} -	if (!h->sum) +	if (!h_sum)  		return 0; -	src_line = notes->src->lines = calloc(len, sizeof(struct source_line)); +	src_line = notes->src->lines = calloc(len, sizeof_src_line);  	if (!notes->src->lines)  		return -1; @@ -960,29 +1067,41 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,  		size_t line_len;  		u64 offset;  		FILE *fp; +		double percent_max = 0.0; -		src_line[i].percent = 100.0 * h->addr[i] / h->sum; -		if (src_line[i].percent <= 0.5) -			continue; +		src_line->nr_pcnt = nr_pcnt; + +		for (k = 0; k < nr_pcnt; k++) { +			h = annotation__histogram(notes, evidx + k); +			src_line->p[k].percent = 100.0 * h->addr[i] / h->sum; + +			if (src_line->p[k].percent > percent_max) +				percent_max = src_line->p[k].percent; +		} + +		if (percent_max <= 0.5) +			goto next;  		offset = start + i;  		sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);  		fp = popen(cmd, "r");  		if (!fp) -			continue; +			goto next;  		if (getline(&path, &line_len, fp) < 0 || !line_len) -			goto next; +			goto next_close; -		src_line[i].path = malloc(sizeof(char) * line_len + 1); -		if (!src_line[i].path) -			goto next; +		src_line->path = malloc(sizeof(char) * line_len + 1); +		if (!src_line->path) +			goto next_close; -		strcpy(src_line[i].path, path); -		insert_source_line(&tmp_root, &src_line[i]); +		strcpy(src_line->path, path); +		insert_source_line(&tmp_root, src_line); -	next: +	next_close:  		pclose(fp); +	next: +		src_line = (void *)src_line + sizeof_src_line;  	}  	resort_source_line(root, &tmp_root); @@ -1004,24 +1123,33 @@ static void print_summary(struct rb_root *root, const char *filename)  	node = rb_first(root);  	while (node) { -		double percent; +		double percent, percent_max = 0.0;  		const char *color;  		char *path; +		int i;  		src_line = rb_entry(node, struct source_line, node); -		percent = src_line->percent_sum; -		color = get_percent_color(percent); +		for (i = 0; i < src_line->nr_pcnt; i++) { +			percent = src_line->p[i].percent_sum; +			color = get_percent_color(percent); +			color_fprintf(stdout, color, " %7.2f", percent); + +			if (percent > percent_max) +				percent_max = percent; +		} +  		path = src_line->path; +		color = get_percent_color(percent_max); +		color_fprintf(stdout, color, " %s", path); -		color_fprintf(stdout, color, " %7.2f %s", percent, path);  		node = rb_next(node);  	}  } -static void symbol__annotate_hits(struct symbol *sym, int evidx) +static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel)  {  	struct annotation *notes = symbol__annotation(sym); -	struct sym_hist *h = annotation__histogram(notes, evidx); +	struct sym_hist *h = annotation__histogram(notes, evsel->idx);  	u64 len = symbol__size(sym), offset;  	for (offset = 0; offset < len; ++offset) @@ -1031,9 +1159,9 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx)  	printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);  } -int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, -			    bool full_paths, int min_pcnt, int max_lines, -			    int context) +int symbol__annotate_printf(struct symbol *sym, struct map *map, +			    struct perf_evsel *evsel, bool full_paths, +			    int min_pcnt, int max_lines, int context)  {  	struct dso *dso = map->dso;  	char *filename; @@ -1044,6 +1172,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,  	int printed = 2, queue_len = 0;  	int more = 0;  	u64 len; +	int width = 8; +	int namelen;  	filename = strdup(dso->long_name);  	if (!filename) @@ -1055,12 +1185,18 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,  		d_filename = basename(filename);  	len = symbol__size(sym); +	namelen = strlen(d_filename); + +	if (perf_evsel__is_group_event(evsel)) +		width *= evsel->nr_members; -	printf(" Percent |	Source code & Disassembly of %s\n", d_filename); -	printf("------------------------------------------------\n"); +	printf(" %-*.*s|	Source code & Disassembly of %s\n", +	       width, width, "Percent", d_filename); +	printf("-%-*.*s-------------------------------------\n", +	       width+namelen, width+namelen, graph_dotted_line);  	if (verbose) -		symbol__annotate_hits(sym, evidx); +		symbol__annotate_hits(sym, evsel);  	list_for_each_entry(pos, ¬es->src->source, node) {  		if (context && queue == NULL) { @@ -1068,7 +1204,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,  			queue_len = 0;  		} -		switch (disasm_line__print(pos, sym, start, evidx, len, +		switch (disasm_line__print(pos, sym, start, evsel, len,  					    min_pcnt, printed, max_lines,  					    queue)) {  		case 0: @@ -1163,9 +1299,9 @@ size_t disasm__fprintf(struct list_head *head, FILE *fp)  	return printed;  } -int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, -			 bool print_lines, bool full_paths, int min_pcnt, -			 int max_lines) +int symbol__tty_annotate(struct symbol *sym, struct map *map, +			 struct perf_evsel *evsel, bool print_lines, +			 bool full_paths, int min_pcnt, int max_lines)  {  	struct dso *dso = map->dso;  	const char *filename = dso->long_name; @@ -1178,12 +1314,12 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,  	len = symbol__size(sym);  	if (print_lines) { -		symbol__get_source_line(sym, map, evidx, &source_line, +		symbol__get_source_line(sym, map, evsel, &source_line,  					len, filename);  		print_summary(&source_line, filename);  	} -	symbol__annotate_printf(sym, map, evidx, full_paths, +	symbol__annotate_printf(sym, map, evsel, full_paths,  				min_pcnt, max_lines, 0);  	if (print_lines)  		symbol__free_source_line(sym, len); | 
