xref: /openbmc/linux/tools/perf/builtin-annotate.c (revision 628ada0c)
186470930SIngo Molnar /*
286470930SIngo Molnar  * builtin-annotate.c
386470930SIngo Molnar  *
486470930SIngo Molnar  * Builtin annotate command: Analyze the perf.data input file,
586470930SIngo Molnar  * look up and read DSOs and symbol information and display
686470930SIngo Molnar  * a histogram of results, along various sorting keys.
786470930SIngo Molnar  */
886470930SIngo Molnar #include "builtin.h"
986470930SIngo Molnar 
1086470930SIngo Molnar #include "util/util.h"
1186470930SIngo Molnar 
1286470930SIngo Molnar #include "util/color.h"
135da50258SArnaldo Carvalho de Melo #include <linux/list.h>
1486470930SIngo Molnar #include "util/cache.h"
1543cbcd8aSArnaldo Carvalho de Melo #include <linux/rbtree.h>
1686470930SIngo Molnar #include "util/symbol.h"
1786470930SIngo Molnar #include "util/string.h"
1886470930SIngo Molnar 
1986470930SIngo Molnar #include "perf.h"
208f28827aSFrederic Weisbecker #include "util/debug.h"
2186470930SIngo Molnar 
2262daacb5SArnaldo Carvalho de Melo #include "util/event.h"
2386470930SIngo Molnar #include "util/parse-options.h"
2486470930SIngo Molnar #include "util/parse-events.h"
256baa0a5aSFrederic Weisbecker #include "util/thread.h"
26dd68ada2SJohn Kacur #include "util/sort.h"
273d1d07ecSJohn Kacur #include "util/hist.h"
2894c744b6SArnaldo Carvalho de Melo #include "util/session.h"
2986470930SIngo Molnar 
3086470930SIngo Molnar static char		const *input_name = "perf.data";
3186470930SIngo Molnar 
32fa6963b2SPeter Zijlstra static int		force;
3386470930SIngo Molnar 
3442976487SMike Galbraith static int		full_paths;
3542976487SMike Galbraith 
36301406b9SFrederic Weisbecker static int		print_line;
37301406b9SFrederic Weisbecker 
38e4204992SArnaldo Carvalho de Melo struct sym_hist {
39e4204992SArnaldo Carvalho de Melo 	u64		sum;
40e4204992SArnaldo Carvalho de Melo 	u64		ip[0];
41e4204992SArnaldo Carvalho de Melo };
42e4204992SArnaldo Carvalho de Melo 
43301406b9SFrederic Weisbecker struct sym_ext {
44971738f3SFrederic Weisbecker 	struct rb_node	node;
45301406b9SFrederic Weisbecker 	double		percent;
46301406b9SFrederic Weisbecker 	char		*path;
47301406b9SFrederic Weisbecker };
48301406b9SFrederic Weisbecker 
49e4204992SArnaldo Carvalho de Melo struct sym_priv {
50e4204992SArnaldo Carvalho de Melo 	struct sym_hist	*hist;
51e4204992SArnaldo Carvalho de Melo 	struct sym_ext	*ext;
52e4204992SArnaldo Carvalho de Melo };
53e4204992SArnaldo Carvalho de Melo 
54e4204992SArnaldo Carvalho de Melo static const char *sym_hist_filter;
55e4204992SArnaldo Carvalho de Melo 
56628ada0cSArnaldo Carvalho de Melo static int sym__alloc_hist(struct symbol *self)
57e4204992SArnaldo Carvalho de Melo {
58628ada0cSArnaldo Carvalho de Melo 	struct sym_priv *priv = symbol__priv(self);
59e4204992SArnaldo Carvalho de Melo 	const int size = (sizeof(*priv->hist) +
60628ada0cSArnaldo Carvalho de Melo 			  (self->end - self->start) * sizeof(u64));
61e4204992SArnaldo Carvalho de Melo 
62628ada0cSArnaldo Carvalho de Melo 	priv->hist = zalloc(size);
63628ada0cSArnaldo Carvalho de Melo 	return priv->hist == NULL ? -1 : 0;
64e4204992SArnaldo Carvalho de Melo }
6586470930SIngo Molnar 
6686470930SIngo Molnar /*
6786470930SIngo Molnar  * collect histogram counts
6886470930SIngo Molnar  */
69628ada0cSArnaldo Carvalho de Melo static int annotate__hist_hit(struct hist_entry *he, u64 ip)
7086470930SIngo Molnar {
7186470930SIngo Molnar 	unsigned int sym_size, offset;
7286470930SIngo Molnar 	struct symbol *sym = he->sym;
73e4204992SArnaldo Carvalho de Melo 	struct sym_priv *priv;
74e4204992SArnaldo Carvalho de Melo 	struct sym_hist *h;
7586470930SIngo Molnar 
7686470930SIngo Molnar 	he->count++;
7786470930SIngo Molnar 
78e4204992SArnaldo Carvalho de Melo 	if (!sym || !he->map)
79628ada0cSArnaldo Carvalho de Melo 		return 0;
80e4204992SArnaldo Carvalho de Melo 
8100a192b3SArnaldo Carvalho de Melo 	priv = symbol__priv(sym);
82628ada0cSArnaldo Carvalho de Melo 	if (priv->hist == NULL && sym__alloc_hist(sym) < 0)
83628ada0cSArnaldo Carvalho de Melo 		return -ENOMEM;
8486470930SIngo Molnar 
8586470930SIngo Molnar 	sym_size = sym->end - sym->start;
8686470930SIngo Molnar 	offset = ip - sym->start;
8786470930SIngo Molnar 
8829a9f66dSArnaldo Carvalho de Melo 	pr_debug3("%s: ip=%#Lx\n", __func__, he->map->unmap_ip(he->map, ip));
89ed52ce2eSArnaldo Carvalho de Melo 
9086470930SIngo Molnar 	if (offset >= sym_size)
91628ada0cSArnaldo Carvalho de Melo 		return 0;
9286470930SIngo Molnar 
93e4204992SArnaldo Carvalho de Melo 	h = priv->hist;
94e4204992SArnaldo Carvalho de Melo 	h->sum++;
95e4204992SArnaldo Carvalho de Melo 	h->ip[offset]++;
9686470930SIngo Molnar 
9729a9f66dSArnaldo Carvalho de Melo 	pr_debug3("%#Lx %s: count++ [ip: %#Lx, %#Lx] => %Ld\n", he->sym->start,
9829a9f66dSArnaldo Carvalho de Melo 		  he->sym->name, ip, ip - he->sym->start, h->ip[offset]);
99628ada0cSArnaldo Carvalho de Melo 	return 0;
10086470930SIngo Molnar }
10186470930SIngo Molnar 
1024e4f06e4SArnaldo Carvalho de Melo static int perf_session__add_hist_entry(struct perf_session *self,
1034e4f06e4SArnaldo Carvalho de Melo 					struct addr_location *al, u64 count)
10486470930SIngo Molnar {
1059735abf1SArnaldo Carvalho de Melo 	bool hit;
106628ada0cSArnaldo Carvalho de Melo 	struct hist_entry *he;
107628ada0cSArnaldo Carvalho de Melo 
108628ada0cSArnaldo Carvalho de Melo 	if (sym_hist_filter != NULL &&
109628ada0cSArnaldo Carvalho de Melo 	    (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) {
110628ada0cSArnaldo Carvalho de Melo 		/* We're only interested in a symbol named sym_hist_filter */
111628ada0cSArnaldo Carvalho de Melo 		if (al->sym != NULL) {
112628ada0cSArnaldo Carvalho de Melo 			rb_erase(&al->sym->rb_node,
113628ada0cSArnaldo Carvalho de Melo 				 &al->map->dso->symbols[al->map->type]);
114628ada0cSArnaldo Carvalho de Melo 			symbol__delete(al->sym);
115628ada0cSArnaldo Carvalho de Melo 		}
116628ada0cSArnaldo Carvalho de Melo 		return 0;
117628ada0cSArnaldo Carvalho de Melo 	}
118628ada0cSArnaldo Carvalho de Melo 
119628ada0cSArnaldo Carvalho de Melo 	he = __perf_session__add_hist_entry(self, al, NULL, count, &hit);
1209735abf1SArnaldo Carvalho de Melo 	if (he == NULL)
12186470930SIngo Molnar 		return -ENOMEM;
122628ada0cSArnaldo Carvalho de Melo 
123628ada0cSArnaldo Carvalho de Melo 	return annotate__hist_hit(he, al->addr);
12486470930SIngo Molnar }
12586470930SIngo Molnar 
126b3165f41SArnaldo Carvalho de Melo static int process_sample_event(event_t *event, struct perf_session *session)
12786470930SIngo Molnar {
1281ed091c4SArnaldo Carvalho de Melo 	struct addr_location al;
1296baa0a5aSFrederic Weisbecker 
1300d755034SArnaldo Carvalho de Melo 	dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc,
1310d755034SArnaldo Carvalho de Melo 		    event->ip.pid, event->ip.ip);
13286470930SIngo Molnar 
133628ada0cSArnaldo Carvalho de Melo 	if (event__preprocess_sample(event, session, &al, NULL) < 0) {
13429a9f66dSArnaldo Carvalho de Melo 		pr_warning("problem processing %d event, skipping it.\n",
13586470930SIngo Molnar 			   event->header.type);
13686470930SIngo Molnar 		return -1;
13786470930SIngo Molnar 	}
13886470930SIngo Molnar 
139c410a338SArnaldo Carvalho de Melo 	if (!al.filtered && perf_session__add_hist_entry(session, &al, 1)) {
14029a9f66dSArnaldo Carvalho de Melo 		pr_warning("problem incrementing symbol count, "
141ec218fc4SArnaldo Carvalho de Melo 			   "skipping event\n");
14286470930SIngo Molnar 		return -1;
14386470930SIngo Molnar 	}
14486470930SIngo Molnar 
14586470930SIngo Molnar 	return 0;
14686470930SIngo Molnar }
14786470930SIngo Molnar 
148ed52ce2eSArnaldo Carvalho de Melo static int parse_line(FILE *file, struct hist_entry *he, u64 len)
14986470930SIngo Molnar {
150ed52ce2eSArnaldo Carvalho de Melo 	struct symbol *sym = he->sym;
15186470930SIngo Molnar 	char *line = NULL, *tmp, *tmp2;
152301406b9SFrederic Weisbecker 	static const char *prev_line;
153301406b9SFrederic Weisbecker 	static const char *prev_color;
15486470930SIngo Molnar 	unsigned int offset;
15586470930SIngo Molnar 	size_t line_len;
156ed52ce2eSArnaldo Carvalho de Melo 	u64 start;
157f37a291cSIngo Molnar 	s64 line_ip;
15886470930SIngo Molnar 	int ret;
15986470930SIngo Molnar 	char *c;
16086470930SIngo Molnar 
16186470930SIngo Molnar 	if (getline(&line, &line_len, file) < 0)
16286470930SIngo Molnar 		return -1;
16386470930SIngo Molnar 	if (!line)
16486470930SIngo Molnar 		return -1;
16586470930SIngo Molnar 
16686470930SIngo Molnar 	c = strchr(line, '\n');
16786470930SIngo Molnar 	if (c)
16886470930SIngo Molnar 		*c = 0;
16986470930SIngo Molnar 
17086470930SIngo Molnar 	line_ip = -1;
17186470930SIngo Molnar 	offset = 0;
17286470930SIngo Molnar 	ret = -2;
17386470930SIngo Molnar 
17486470930SIngo Molnar 	/*
17586470930SIngo Molnar 	 * Strip leading spaces:
17686470930SIngo Molnar 	 */
17786470930SIngo Molnar 	tmp = line;
17886470930SIngo Molnar 	while (*tmp) {
17986470930SIngo Molnar 		if (*tmp != ' ')
18086470930SIngo Molnar 			break;
18186470930SIngo Molnar 		tmp++;
18286470930SIngo Molnar 	}
18386470930SIngo Molnar 
18486470930SIngo Molnar 	if (*tmp) {
18586470930SIngo Molnar 		/*
18686470930SIngo Molnar 		 * Parse hexa addresses followed by ':'
18786470930SIngo Molnar 		 */
18886470930SIngo Molnar 		line_ip = strtoull(tmp, &tmp2, 16);
18986470930SIngo Molnar 		if (*tmp2 != ':')
19086470930SIngo Molnar 			line_ip = -1;
19186470930SIngo Molnar 	}
19286470930SIngo Molnar 
1937a2b6209SKirill Smelkov 	start = map__rip_2objdump(he->map, sym->start);
194ed52ce2eSArnaldo Carvalho de Melo 
19586470930SIngo Molnar 	if (line_ip != -1) {
196301406b9SFrederic Weisbecker 		const char *path = NULL;
19786470930SIngo Molnar 		unsigned int hits = 0;
19886470930SIngo Molnar 		double percent = 0.0;
19983a0944fSIngo Molnar 		const char *color;
20000a192b3SArnaldo Carvalho de Melo 		struct sym_priv *priv = symbol__priv(sym);
201e4204992SArnaldo Carvalho de Melo 		struct sym_ext *sym_ext = priv->ext;
202e4204992SArnaldo Carvalho de Melo 		struct sym_hist *h = priv->hist;
20386470930SIngo Molnar 
204ed52ce2eSArnaldo Carvalho de Melo 		offset = line_ip - start;
20586470930SIngo Molnar 		if (offset < len)
206e4204992SArnaldo Carvalho de Melo 			hits = h->ip[offset];
20786470930SIngo Molnar 
208c17c2db1SFrederic Weisbecker 		if (offset < len && sym_ext) {
209301406b9SFrederic Weisbecker 			path = sym_ext[offset].path;
210301406b9SFrederic Weisbecker 			percent = sym_ext[offset].percent;
211e4204992SArnaldo Carvalho de Melo 		} else if (h->sum)
212e4204992SArnaldo Carvalho de Melo 			percent = 100.0 * hits / h->sum;
21386470930SIngo Molnar 
2141e11fd82SFrederic Weisbecker 		color = get_percent_color(percent);
21586470930SIngo Molnar 
216301406b9SFrederic Weisbecker 		/*
217301406b9SFrederic Weisbecker 		 * Also color the filename and line if needed, with
218301406b9SFrederic Weisbecker 		 * the same color than the percentage. Don't print it
219301406b9SFrederic Weisbecker 		 * twice for close colored ip with the same filename:line
220301406b9SFrederic Weisbecker 		 */
221301406b9SFrederic Weisbecker 		if (path) {
222301406b9SFrederic Weisbecker 			if (!prev_line || strcmp(prev_line, path)
223301406b9SFrederic Weisbecker 				       || color != prev_color) {
224301406b9SFrederic Weisbecker 				color_fprintf(stdout, color, " %s", path);
225301406b9SFrederic Weisbecker 				prev_line = path;
226301406b9SFrederic Weisbecker 				prev_color = color;
227301406b9SFrederic Weisbecker 			}
228301406b9SFrederic Weisbecker 		}
229301406b9SFrederic Weisbecker 
23086470930SIngo Molnar 		color_fprintf(stdout, color, " %7.2f", percent);
23186470930SIngo Molnar 		printf(" :	");
23286470930SIngo Molnar 		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line);
23386470930SIngo Molnar 	} else {
23486470930SIngo Molnar 		if (!*line)
23586470930SIngo Molnar 			printf("         :\n");
23686470930SIngo Molnar 		else
23786470930SIngo Molnar 			printf("         :	%s\n", line);
23886470930SIngo Molnar 	}
23986470930SIngo Molnar 
24086470930SIngo Molnar 	return 0;
24186470930SIngo Molnar }
24286470930SIngo Molnar 
243971738f3SFrederic Weisbecker static struct rb_root root_sym_ext;
244971738f3SFrederic Weisbecker 
245971738f3SFrederic Weisbecker static void insert_source_line(struct sym_ext *sym_ext)
246971738f3SFrederic Weisbecker {
247971738f3SFrederic Weisbecker 	struct sym_ext *iter;
248971738f3SFrederic Weisbecker 	struct rb_node **p = &root_sym_ext.rb_node;
249971738f3SFrederic Weisbecker 	struct rb_node *parent = NULL;
250971738f3SFrederic Weisbecker 
251971738f3SFrederic Weisbecker 	while (*p != NULL) {
252971738f3SFrederic Weisbecker 		parent = *p;
253971738f3SFrederic Weisbecker 		iter = rb_entry(parent, struct sym_ext, node);
254971738f3SFrederic Weisbecker 
255971738f3SFrederic Weisbecker 		if (sym_ext->percent > iter->percent)
256971738f3SFrederic Weisbecker 			p = &(*p)->rb_left;
257971738f3SFrederic Weisbecker 		else
258971738f3SFrederic Weisbecker 			p = &(*p)->rb_right;
259971738f3SFrederic Weisbecker 	}
260971738f3SFrederic Weisbecker 
261971738f3SFrederic Weisbecker 	rb_link_node(&sym_ext->node, parent, p);
262971738f3SFrederic Weisbecker 	rb_insert_color(&sym_ext->node, &root_sym_ext);
263971738f3SFrederic Weisbecker }
264971738f3SFrederic Weisbecker 
265e4204992SArnaldo Carvalho de Melo static void free_source_line(struct hist_entry *he, int len)
266301406b9SFrederic Weisbecker {
26700a192b3SArnaldo Carvalho de Melo 	struct sym_priv *priv = symbol__priv(he->sym);
268e4204992SArnaldo Carvalho de Melo 	struct sym_ext *sym_ext = priv->ext;
269301406b9SFrederic Weisbecker 	int i;
270301406b9SFrederic Weisbecker 
271301406b9SFrederic Weisbecker 	if (!sym_ext)
272301406b9SFrederic Weisbecker 		return;
273301406b9SFrederic Weisbecker 
274301406b9SFrederic Weisbecker 	for (i = 0; i < len; i++)
275301406b9SFrederic Weisbecker 		free(sym_ext[i].path);
276301406b9SFrederic Weisbecker 	free(sym_ext);
277301406b9SFrederic Weisbecker 
278e4204992SArnaldo Carvalho de Melo 	priv->ext = NULL;
279971738f3SFrederic Weisbecker 	root_sym_ext = RB_ROOT;
280301406b9SFrederic Weisbecker }
281301406b9SFrederic Weisbecker 
282301406b9SFrederic Weisbecker /* Get the filename:line for the colored entries */
283c17c2db1SFrederic Weisbecker static void
284ed52ce2eSArnaldo Carvalho de Melo get_source_line(struct hist_entry *he, int len, const char *filename)
285301406b9SFrederic Weisbecker {
286ed52ce2eSArnaldo Carvalho de Melo 	struct symbol *sym = he->sym;
287ed52ce2eSArnaldo Carvalho de Melo 	u64 start;
288301406b9SFrederic Weisbecker 	int i;
289301406b9SFrederic Weisbecker 	char cmd[PATH_MAX * 2];
290301406b9SFrederic Weisbecker 	struct sym_ext *sym_ext;
29100a192b3SArnaldo Carvalho de Melo 	struct sym_priv *priv = symbol__priv(sym);
292e4204992SArnaldo Carvalho de Melo 	struct sym_hist *h = priv->hist;
293301406b9SFrederic Weisbecker 
294e4204992SArnaldo Carvalho de Melo 	if (!h->sum)
295301406b9SFrederic Weisbecker 		return;
296301406b9SFrederic Weisbecker 
297e4204992SArnaldo Carvalho de Melo 	sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
298e4204992SArnaldo Carvalho de Melo 	if (!priv->ext)
299301406b9SFrederic Weisbecker 		return;
300301406b9SFrederic Weisbecker 
301ed52ce2eSArnaldo Carvalho de Melo 	start = he->map->unmap_ip(he->map, sym->start);
302301406b9SFrederic Weisbecker 
303301406b9SFrederic Weisbecker 	for (i = 0; i < len; i++) {
304301406b9SFrederic Weisbecker 		char *path = NULL;
305301406b9SFrederic Weisbecker 		size_t line_len;
3069cffa8d5SPaul Mackerras 		u64 offset;
307301406b9SFrederic Weisbecker 		FILE *fp;
308301406b9SFrederic Weisbecker 
309e4204992SArnaldo Carvalho de Melo 		sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
310301406b9SFrederic Weisbecker 		if (sym_ext[i].percent <= 0.5)
311301406b9SFrederic Weisbecker 			continue;
312301406b9SFrederic Weisbecker 
313ed52ce2eSArnaldo Carvalho de Melo 		offset = start + i;
314c17c2db1SFrederic Weisbecker 		sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
315301406b9SFrederic Weisbecker 		fp = popen(cmd, "r");
316301406b9SFrederic Weisbecker 		if (!fp)
317301406b9SFrederic Weisbecker 			continue;
318301406b9SFrederic Weisbecker 
319301406b9SFrederic Weisbecker 		if (getline(&path, &line_len, fp) < 0 || !line_len)
320301406b9SFrederic Weisbecker 			goto next;
321301406b9SFrederic Weisbecker 
322c17c2db1SFrederic Weisbecker 		sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
323301406b9SFrederic Weisbecker 		if (!sym_ext[i].path)
324301406b9SFrederic Weisbecker 			goto next;
325301406b9SFrederic Weisbecker 
326301406b9SFrederic Weisbecker 		strcpy(sym_ext[i].path, path);
327971738f3SFrederic Weisbecker 		insert_source_line(&sym_ext[i]);
328301406b9SFrederic Weisbecker 
329301406b9SFrederic Weisbecker 	next:
330301406b9SFrederic Weisbecker 		pclose(fp);
331301406b9SFrederic Weisbecker 	}
332301406b9SFrederic Weisbecker }
333301406b9SFrederic Weisbecker 
33483a0944fSIngo Molnar static void print_summary(const char *filename)
335971738f3SFrederic Weisbecker {
336971738f3SFrederic Weisbecker 	struct sym_ext *sym_ext;
337971738f3SFrederic Weisbecker 	struct rb_node *node;
338971738f3SFrederic Weisbecker 
339971738f3SFrederic Weisbecker 	printf("\nSorted summary for file %s\n", filename);
340971738f3SFrederic Weisbecker 	printf("----------------------------------------------\n\n");
341971738f3SFrederic Weisbecker 
342971738f3SFrederic Weisbecker 	if (RB_EMPTY_ROOT(&root_sym_ext)) {
343971738f3SFrederic Weisbecker 		printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
344971738f3SFrederic Weisbecker 		return;
345971738f3SFrederic Weisbecker 	}
346971738f3SFrederic Weisbecker 
347971738f3SFrederic Weisbecker 	node = rb_first(&root_sym_ext);
348971738f3SFrederic Weisbecker 	while (node) {
349971738f3SFrederic Weisbecker 		double percent;
35083a0944fSIngo Molnar 		const char *color;
351971738f3SFrederic Weisbecker 		char *path;
352971738f3SFrederic Weisbecker 
353971738f3SFrederic Weisbecker 		sym_ext = rb_entry(node, struct sym_ext, node);
354971738f3SFrederic Weisbecker 		percent = sym_ext->percent;
3551e11fd82SFrederic Weisbecker 		color = get_percent_color(percent);
356971738f3SFrederic Weisbecker 		path = sym_ext->path;
357971738f3SFrederic Weisbecker 
358971738f3SFrederic Weisbecker 		color_fprintf(stdout, color, " %7.2f %s", percent, path);
359971738f3SFrederic Weisbecker 		node = rb_next(node);
360971738f3SFrederic Weisbecker 	}
361971738f3SFrederic Weisbecker }
362971738f3SFrederic Weisbecker 
363ed52ce2eSArnaldo Carvalho de Melo static void annotate_sym(struct hist_entry *he)
36486470930SIngo Molnar {
365ed52ce2eSArnaldo Carvalho de Melo 	struct map *map = he->map;
366ed52ce2eSArnaldo Carvalho de Melo 	struct dso *dso = map->dso;
367ed52ce2eSArnaldo Carvalho de Melo 	struct symbol *sym = he->sym;
368439d473bSArnaldo Carvalho de Melo 	const char *filename = dso->long_name, *d_filename;
369439d473bSArnaldo Carvalho de Melo 	u64 len;
37086470930SIngo Molnar 	char command[PATH_MAX*2];
37186470930SIngo Molnar 	FILE *file;
37286470930SIngo Molnar 
37386470930SIngo Molnar 	if (!filename)
37486470930SIngo Molnar 		return;
37586470930SIngo Molnar 
37629a9f66dSArnaldo Carvalho de Melo 	pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
37729a9f66dSArnaldo Carvalho de Melo 		 filename, sym->name, map->unmap_ip(map, sym->start),
378ed52ce2eSArnaldo Carvalho de Melo 		 map->unmap_ip(map, sym->end));
379ed52ce2eSArnaldo Carvalho de Melo 
38042976487SMike Galbraith 	if (full_paths)
38142976487SMike Galbraith 		d_filename = filename;
38242976487SMike Galbraith 	else
38342976487SMike Galbraith 		d_filename = basename(filename);
38486470930SIngo Molnar 
38586470930SIngo Molnar 	len = sym->end - sym->start;
38686470930SIngo Molnar 
387971738f3SFrederic Weisbecker 	if (print_line) {
388ed52ce2eSArnaldo Carvalho de Melo 		get_source_line(he, len, filename);
389971738f3SFrederic Weisbecker 		print_summary(filename);
390971738f3SFrederic Weisbecker 	}
391971738f3SFrederic Weisbecker 
392971738f3SFrederic Weisbecker 	printf("\n\n------------------------------------------------\n");
39342976487SMike Galbraith 	printf(" Percent |	Source code & Disassembly of %s\n", d_filename);
394971738f3SFrederic Weisbecker 	printf("------------------------------------------------\n");
395971738f3SFrederic Weisbecker 
396971738f3SFrederic Weisbecker 	if (verbose >= 2)
397439d473bSArnaldo Carvalho de Melo 		printf("annotating [%p] %30s : [%p] %30s\n",
398439d473bSArnaldo Carvalho de Melo 		       dso, dso->long_name, sym, sym->name);
399301406b9SFrederic Weisbecker 
40042976487SMike Galbraith 	sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
4017a2b6209SKirill Smelkov 		map__rip_2objdump(map, sym->start),
4027a2b6209SKirill Smelkov 		map__rip_2objdump(map, sym->end),
403ed52ce2eSArnaldo Carvalho de Melo 		filename, filename);
40486470930SIngo Molnar 
40586470930SIngo Molnar 	if (verbose >= 3)
40686470930SIngo Molnar 		printf("doing: %s\n", command);
40786470930SIngo Molnar 
40886470930SIngo Molnar 	file = popen(command, "r");
40986470930SIngo Molnar 	if (!file)
41086470930SIngo Molnar 		return;
41186470930SIngo Molnar 
41286470930SIngo Molnar 	while (!feof(file)) {
413ed52ce2eSArnaldo Carvalho de Melo 		if (parse_line(file, he, len) < 0)
41486470930SIngo Molnar 			break;
41586470930SIngo Molnar 	}
41686470930SIngo Molnar 
41786470930SIngo Molnar 	pclose(file);
418971738f3SFrederic Weisbecker 	if (print_line)
419e4204992SArnaldo Carvalho de Melo 		free_source_line(he, len);
42086470930SIngo Molnar }
42186470930SIngo Molnar 
4224e4f06e4SArnaldo Carvalho de Melo static void perf_session__find_annotations(struct perf_session *self)
42386470930SIngo Molnar {
42486470930SIngo Molnar 	struct rb_node *nd;
42586470930SIngo Molnar 
4264e4f06e4SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
427ed52ce2eSArnaldo Carvalho de Melo 		struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
428e4204992SArnaldo Carvalho de Melo 		struct sym_priv *priv;
42986470930SIngo Molnar 
430e4204992SArnaldo Carvalho de Melo 		if (he->sym == NULL)
431e4204992SArnaldo Carvalho de Melo 			continue;
432e4204992SArnaldo Carvalho de Melo 
43300a192b3SArnaldo Carvalho de Melo 		priv = symbol__priv(he->sym);
434e4204992SArnaldo Carvalho de Melo 		if (priv->hist == NULL)
435e4204992SArnaldo Carvalho de Melo 			continue;
436e4204992SArnaldo Carvalho de Melo 
437ed52ce2eSArnaldo Carvalho de Melo 		annotate_sym(he);
438ed52ce2eSArnaldo Carvalho de Melo 		/*
439e4204992SArnaldo Carvalho de Melo 		 * Since we have a hist_entry per IP for the same symbol, free
440e4204992SArnaldo Carvalho de Melo 		 * he->sym->hist to signal we already processed this symbol.
441ed52ce2eSArnaldo Carvalho de Melo 		 */
442e4204992SArnaldo Carvalho de Melo 		free(priv->hist);
443e4204992SArnaldo Carvalho de Melo 		priv->hist = NULL;
44486470930SIngo Molnar 	}
44586470930SIngo Molnar }
44686470930SIngo Molnar 
447301a0b02SArnaldo Carvalho de Melo static struct perf_event_ops event_ops = {
44855aa640fSArnaldo Carvalho de Melo 	.sample	= process_sample_event,
44955aa640fSArnaldo Carvalho de Melo 	.mmap	= event__process_mmap,
45055aa640fSArnaldo Carvalho de Melo 	.comm	= event__process_comm,
45155aa640fSArnaldo Carvalho de Melo 	.fork	= event__process_task,
452bab81b62SLi Zefan };
453bab81b62SLi Zefan 
45486470930SIngo Molnar static int __cmd_annotate(void)
45586470930SIngo Molnar {
456bab81b62SLi Zefan 	int ret;
45775be6cf4SArnaldo Carvalho de Melo 	struct perf_session *session;
45886470930SIngo Molnar 
45975be6cf4SArnaldo Carvalho de Melo 	session = perf_session__new(input_name, O_RDONLY, force);
46094c744b6SArnaldo Carvalho de Melo 	if (session == NULL)
46194c744b6SArnaldo Carvalho de Melo 		return -ENOMEM;
46294c744b6SArnaldo Carvalho de Melo 
463ec913369SArnaldo Carvalho de Melo 	ret = perf_session__process_events(session, &event_ops);
464bab81b62SLi Zefan 	if (ret)
46594c744b6SArnaldo Carvalho de Melo 		goto out_delete;
46686470930SIngo Molnar 
46762daacb5SArnaldo Carvalho de Melo 	if (dump_trace) {
46862daacb5SArnaldo Carvalho de Melo 		event__print_totals();
46994c744b6SArnaldo Carvalho de Melo 		goto out_delete;
47062daacb5SArnaldo Carvalho de Melo 	}
47186470930SIngo Molnar 
472da21d1b5SArnaldo Carvalho de Melo 	if (verbose > 3)
473b3165f41SArnaldo Carvalho de Melo 		perf_session__fprintf(session, stdout);
47486470930SIngo Molnar 
475da21d1b5SArnaldo Carvalho de Melo 	if (verbose > 2)
47686470930SIngo Molnar 		dsos__fprintf(stdout);
47786470930SIngo Molnar 
4784e4f06e4SArnaldo Carvalho de Melo 	perf_session__collapse_resort(session);
479f823e441SArnaldo Carvalho de Melo 	perf_session__output_resort(session, session->event_total[0]);
4804e4f06e4SArnaldo Carvalho de Melo 	perf_session__find_annotations(session);
48194c744b6SArnaldo Carvalho de Melo out_delete:
48294c744b6SArnaldo Carvalho de Melo 	perf_session__delete(session);
48386470930SIngo Molnar 
484bab81b62SLi Zefan 	return ret;
48586470930SIngo Molnar }
48686470930SIngo Molnar 
48786470930SIngo Molnar static const char * const annotate_usage[] = {
48886470930SIngo Molnar 	"perf annotate [<options>] <command>",
48986470930SIngo Molnar 	NULL
49086470930SIngo Molnar };
49186470930SIngo Molnar 
49286470930SIngo Molnar static const struct option options[] = {
49386470930SIngo Molnar 	OPT_STRING('i', "input", &input_name, "file",
49486470930SIngo Molnar 		    "input file name"),
49523b87116SIngo Molnar 	OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
49686470930SIngo Molnar 		    "symbol to annotate"),
497fa6963b2SPeter Zijlstra 	OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
49886470930SIngo Molnar 	OPT_BOOLEAN('v', "verbose", &verbose,
49986470930SIngo Molnar 		    "be more verbose (show symbol address, etc)"),
50086470930SIngo Molnar 	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
50186470930SIngo Molnar 		    "dump raw trace in ASCII"),
502b32d133aSArnaldo Carvalho de Melo 	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
503b32d133aSArnaldo Carvalho de Melo 		   "file", "vmlinux pathname"),
504b32d133aSArnaldo Carvalho de Melo 	OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
50542976487SMike Galbraith 		    "load module symbols - WARNING: use only with -k and LIVE kernel"),
506301406b9SFrederic Weisbecker 	OPT_BOOLEAN('l', "print-line", &print_line,
507301406b9SFrederic Weisbecker 		    "print matching source lines (may be slow)"),
50842976487SMike Galbraith 	OPT_BOOLEAN('P', "full-paths", &full_paths,
50942976487SMike Galbraith 		    "Don't shorten the displayed pathnames"),
51086470930SIngo Molnar 	OPT_END()
51186470930SIngo Molnar };
51286470930SIngo Molnar 
513f37a291cSIngo Molnar int cmd_annotate(int argc, const char **argv, const char *prefix __used)
51486470930SIngo Molnar {
515655000e7SArnaldo Carvalho de Melo 	argc = parse_options(argc, argv, options, annotate_usage, 0);
516655000e7SArnaldo Carvalho de Melo 
51775be6cf4SArnaldo Carvalho de Melo 	symbol_conf.priv_size = sizeof(struct sym_priv);
51875be6cf4SArnaldo Carvalho de Melo 	symbol_conf.try_vmlinux_path = true;
51975be6cf4SArnaldo Carvalho de Melo 
52075be6cf4SArnaldo Carvalho de Melo 	if (symbol__init() < 0)
521b32d133aSArnaldo Carvalho de Melo 		return -1;
52286470930SIngo Molnar 
523c8829c7aSArnaldo Carvalho de Melo 	setup_sorting(annotate_usage, options);
52486470930SIngo Molnar 
52586470930SIngo Molnar 	if (argc) {
52686470930SIngo Molnar 		/*
52786470930SIngo Molnar 		 * Special case: if there's an argument left then assume tha
52886470930SIngo Molnar 		 * it's a symbol filter:
52986470930SIngo Molnar 		 */
53086470930SIngo Molnar 		if (argc > 1)
53186470930SIngo Molnar 			usage_with_options(annotate_usage, options);
53286470930SIngo Molnar 
53386470930SIngo Molnar 		sym_hist_filter = argv[0];
53486470930SIngo Molnar 	}
53586470930SIngo Molnar 
53686470930SIngo Molnar 	setup_pager();
53786470930SIngo Molnar 
538dd68ada2SJohn Kacur 	if (field_sep && *field_sep == '.') {
53929a9f66dSArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
54029a9f66dSArnaldo Carvalho de Melo 		return -1;
541dd68ada2SJohn Kacur 	}
542dd68ada2SJohn Kacur 
54386470930SIngo Molnar 	return __cmd_annotate();
54486470930SIngo Molnar }
545