xref: /openbmc/linux/tools/perf/builtin-annotate.c (revision 62e3436b)
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 
1886470930SIngo Molnar #include "perf.h"
198f28827aSFrederic Weisbecker #include "util/debug.h"
2086470930SIngo Molnar 
2162daacb5SArnaldo Carvalho de Melo #include "util/event.h"
2286470930SIngo Molnar #include "util/parse-options.h"
2386470930SIngo Molnar #include "util/parse-events.h"
246baa0a5aSFrederic Weisbecker #include "util/thread.h"
25dd68ada2SJohn Kacur #include "util/sort.h"
263d1d07ecSJohn Kacur #include "util/hist.h"
2794c744b6SArnaldo Carvalho de Melo #include "util/session.h"
2886470930SIngo Molnar 
2986470930SIngo Molnar static char		const *input_name = "perf.data";
3086470930SIngo Molnar 
31c0555642SIan Munsie static bool		force;
3286470930SIngo Molnar 
33c0555642SIan Munsie static bool		full_paths;
3442976487SMike Galbraith 
35c0555642SIan Munsie static bool		print_line;
36301406b9SFrederic Weisbecker 
37e4204992SArnaldo Carvalho de Melo static const char *sym_hist_filter;
38e4204992SArnaldo Carvalho de Melo 
391c02c4d2SArnaldo Carvalho de Melo static int hists__add_entry(struct hists *self, struct addr_location *al)
4086470930SIngo Molnar {
41628ada0cSArnaldo Carvalho de Melo 	struct hist_entry *he;
42628ada0cSArnaldo Carvalho de Melo 
43628ada0cSArnaldo Carvalho de Melo 	if (sym_hist_filter != NULL &&
44628ada0cSArnaldo Carvalho de Melo 	    (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) {
45628ada0cSArnaldo Carvalho de Melo 		/* We're only interested in a symbol named sym_hist_filter */
46628ada0cSArnaldo Carvalho de Melo 		if (al->sym != NULL) {
47628ada0cSArnaldo Carvalho de Melo 			rb_erase(&al->sym->rb_node,
48628ada0cSArnaldo Carvalho de Melo 				 &al->map->dso->symbols[al->map->type]);
49628ada0cSArnaldo Carvalho de Melo 			symbol__delete(al->sym);
50628ada0cSArnaldo Carvalho de Melo 		}
51628ada0cSArnaldo Carvalho de Melo 		return 0;
52628ada0cSArnaldo Carvalho de Melo 	}
53628ada0cSArnaldo Carvalho de Melo 
541c02c4d2SArnaldo Carvalho de Melo 	he = __hists__add_entry(self, al, NULL, 1);
559735abf1SArnaldo Carvalho de Melo 	if (he == NULL)
5686470930SIngo Molnar 		return -ENOMEM;
57628ada0cSArnaldo Carvalho de Melo 
58ef7b93a1SArnaldo Carvalho de Melo 	return hist_entry__inc_addr_samples(he, al->addr);
5986470930SIngo Molnar }
6086470930SIngo Molnar 
61b3165f41SArnaldo Carvalho de Melo static int process_sample_event(event_t *event, struct perf_session *session)
6286470930SIngo Molnar {
631ed091c4SArnaldo Carvalho de Melo 	struct addr_location al;
646baa0a5aSFrederic Weisbecker 
650d755034SArnaldo Carvalho de Melo 	dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc,
660d755034SArnaldo Carvalho de Melo 		    event->ip.pid, event->ip.ip);
6786470930SIngo Molnar 
68628ada0cSArnaldo Carvalho de Melo 	if (event__preprocess_sample(event, session, &al, NULL) < 0) {
6929a9f66dSArnaldo Carvalho de Melo 		pr_warning("problem processing %d event, skipping it.\n",
7086470930SIngo Molnar 			   event->header.type);
7186470930SIngo Molnar 		return -1;
7286470930SIngo Molnar 	}
7386470930SIngo Molnar 
741c02c4d2SArnaldo Carvalho de Melo 	if (!al.filtered && hists__add_entry(&session->hists, &al)) {
7529a9f66dSArnaldo Carvalho de Melo 		pr_warning("problem incrementing symbol count, "
76ec218fc4SArnaldo Carvalho de Melo 			   "skipping event\n");
7786470930SIngo Molnar 		return -1;
7886470930SIngo Molnar 	}
7986470930SIngo Molnar 
8086470930SIngo Molnar 	return 0;
8186470930SIngo Molnar }
8286470930SIngo Molnar 
8348fb4fddSArnaldo Carvalho de Melo static int objdump_line__print(struct objdump_line *self,
8448fb4fddSArnaldo Carvalho de Melo 			       struct list_head *head,
8548fb4fddSArnaldo Carvalho de Melo 			       struct hist_entry *he, u64 len)
8648fb4fddSArnaldo Carvalho de Melo {
8759fd5306SArnaldo Carvalho de Melo 	struct symbol *sym = he->ms.sym;
8848fb4fddSArnaldo Carvalho de Melo 	static const char *prev_line;
8948fb4fddSArnaldo Carvalho de Melo 	static const char *prev_color;
9048fb4fddSArnaldo Carvalho de Melo 
9148fb4fddSArnaldo Carvalho de Melo 	if (self->offset != -1) {
92301406b9SFrederic Weisbecker 		const char *path = NULL;
9386470930SIngo Molnar 		unsigned int hits = 0;
9486470930SIngo Molnar 		double percent = 0.0;
9583a0944fSIngo Molnar 		const char *color;
9600a192b3SArnaldo Carvalho de Melo 		struct sym_priv *priv = symbol__priv(sym);
97e4204992SArnaldo Carvalho de Melo 		struct sym_ext *sym_ext = priv->ext;
98e4204992SArnaldo Carvalho de Melo 		struct sym_hist *h = priv->hist;
9948fb4fddSArnaldo Carvalho de Melo 		s64 offset = self->offset;
10048fb4fddSArnaldo Carvalho de Melo 		struct objdump_line *next = objdump__get_next_ip_line(head, self);
10186470930SIngo Molnar 
10248fb4fddSArnaldo Carvalho de Melo 		while (offset < (s64)len &&
10348fb4fddSArnaldo Carvalho de Melo 		       (next == NULL || offset < next->offset)) {
10448fb4fddSArnaldo Carvalho de Melo 			if (sym_ext) {
10548fb4fddSArnaldo Carvalho de Melo 				if (path == NULL)
106301406b9SFrederic Weisbecker 					path = sym_ext[offset].path;
10748fb4fddSArnaldo Carvalho de Melo 				percent += sym_ext[offset].percent;
10848fb4fddSArnaldo Carvalho de Melo 			} else
10948fb4fddSArnaldo Carvalho de Melo 				hits += h->ip[offset];
11048fb4fddSArnaldo Carvalho de Melo 
11148fb4fddSArnaldo Carvalho de Melo 			++offset;
11248fb4fddSArnaldo Carvalho de Melo 		}
11348fb4fddSArnaldo Carvalho de Melo 
11448fb4fddSArnaldo Carvalho de Melo 		if (sym_ext == NULL && h->sum)
115e4204992SArnaldo Carvalho de Melo 			percent = 100.0 * hits / h->sum;
11686470930SIngo Molnar 
1171e11fd82SFrederic Weisbecker 		color = get_percent_color(percent);
11886470930SIngo Molnar 
119301406b9SFrederic Weisbecker 		/*
120301406b9SFrederic Weisbecker 		 * Also color the filename and line if needed, with
121301406b9SFrederic Weisbecker 		 * the same color than the percentage. Don't print it
122301406b9SFrederic Weisbecker 		 * twice for close colored ip with the same filename:line
123301406b9SFrederic Weisbecker 		 */
124301406b9SFrederic Weisbecker 		if (path) {
125301406b9SFrederic Weisbecker 			if (!prev_line || strcmp(prev_line, path)
126301406b9SFrederic Weisbecker 				       || color != prev_color) {
127301406b9SFrederic Weisbecker 				color_fprintf(stdout, color, " %s", path);
128301406b9SFrederic Weisbecker 				prev_line = path;
129301406b9SFrederic Weisbecker 				prev_color = color;
130301406b9SFrederic Weisbecker 			}
131301406b9SFrederic Weisbecker 		}
132301406b9SFrederic Weisbecker 
13386470930SIngo Molnar 		color_fprintf(stdout, color, " %7.2f", percent);
13486470930SIngo Molnar 		printf(" :	");
13548fb4fddSArnaldo Carvalho de Melo 		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line);
13686470930SIngo Molnar 	} else {
13748fb4fddSArnaldo Carvalho de Melo 		if (!*self->line)
13886470930SIngo Molnar 			printf("         :\n");
13986470930SIngo Molnar 		else
14048fb4fddSArnaldo Carvalho de Melo 			printf("         :	%s\n", self->line);
14186470930SIngo Molnar 	}
14286470930SIngo Molnar 
14386470930SIngo Molnar 	return 0;
14486470930SIngo Molnar }
14586470930SIngo Molnar 
146971738f3SFrederic Weisbecker static struct rb_root root_sym_ext;
147971738f3SFrederic Weisbecker 
148971738f3SFrederic Weisbecker static void insert_source_line(struct sym_ext *sym_ext)
149971738f3SFrederic Weisbecker {
150971738f3SFrederic Weisbecker 	struct sym_ext *iter;
151971738f3SFrederic Weisbecker 	struct rb_node **p = &root_sym_ext.rb_node;
152971738f3SFrederic Weisbecker 	struct rb_node *parent = NULL;
153971738f3SFrederic Weisbecker 
154971738f3SFrederic Weisbecker 	while (*p != NULL) {
155971738f3SFrederic Weisbecker 		parent = *p;
156971738f3SFrederic Weisbecker 		iter = rb_entry(parent, struct sym_ext, node);
157971738f3SFrederic Weisbecker 
158971738f3SFrederic Weisbecker 		if (sym_ext->percent > iter->percent)
159971738f3SFrederic Weisbecker 			p = &(*p)->rb_left;
160971738f3SFrederic Weisbecker 		else
161971738f3SFrederic Weisbecker 			p = &(*p)->rb_right;
162971738f3SFrederic Weisbecker 	}
163971738f3SFrederic Weisbecker 
164971738f3SFrederic Weisbecker 	rb_link_node(&sym_ext->node, parent, p);
165971738f3SFrederic Weisbecker 	rb_insert_color(&sym_ext->node, &root_sym_ext);
166971738f3SFrederic Weisbecker }
167971738f3SFrederic Weisbecker 
168e4204992SArnaldo Carvalho de Melo static void free_source_line(struct hist_entry *he, int len)
169301406b9SFrederic Weisbecker {
17059fd5306SArnaldo Carvalho de Melo 	struct sym_priv *priv = symbol__priv(he->ms.sym);
171e4204992SArnaldo Carvalho de Melo 	struct sym_ext *sym_ext = priv->ext;
172301406b9SFrederic Weisbecker 	int i;
173301406b9SFrederic Weisbecker 
174301406b9SFrederic Weisbecker 	if (!sym_ext)
175301406b9SFrederic Weisbecker 		return;
176301406b9SFrederic Weisbecker 
177301406b9SFrederic Weisbecker 	for (i = 0; i < len; i++)
178301406b9SFrederic Weisbecker 		free(sym_ext[i].path);
179301406b9SFrederic Weisbecker 	free(sym_ext);
180301406b9SFrederic Weisbecker 
181e4204992SArnaldo Carvalho de Melo 	priv->ext = NULL;
182971738f3SFrederic Weisbecker 	root_sym_ext = RB_ROOT;
183301406b9SFrederic Weisbecker }
184301406b9SFrederic Weisbecker 
185301406b9SFrederic Weisbecker /* Get the filename:line for the colored entries */
186c17c2db1SFrederic Weisbecker static void
187ed52ce2eSArnaldo Carvalho de Melo get_source_line(struct hist_entry *he, int len, const char *filename)
188301406b9SFrederic Weisbecker {
18959fd5306SArnaldo Carvalho de Melo 	struct symbol *sym = he->ms.sym;
190ed52ce2eSArnaldo Carvalho de Melo 	u64 start;
191301406b9SFrederic Weisbecker 	int i;
192301406b9SFrederic Weisbecker 	char cmd[PATH_MAX * 2];
193301406b9SFrederic Weisbecker 	struct sym_ext *sym_ext;
19400a192b3SArnaldo Carvalho de Melo 	struct sym_priv *priv = symbol__priv(sym);
195e4204992SArnaldo Carvalho de Melo 	struct sym_hist *h = priv->hist;
196301406b9SFrederic Weisbecker 
197e4204992SArnaldo Carvalho de Melo 	if (!h->sum)
198301406b9SFrederic Weisbecker 		return;
199301406b9SFrederic Weisbecker 
200e4204992SArnaldo Carvalho de Melo 	sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
201e4204992SArnaldo Carvalho de Melo 	if (!priv->ext)
202301406b9SFrederic Weisbecker 		return;
203301406b9SFrederic Weisbecker 
20459fd5306SArnaldo Carvalho de Melo 	start = he->ms.map->unmap_ip(he->ms.map, sym->start);
205301406b9SFrederic Weisbecker 
206301406b9SFrederic Weisbecker 	for (i = 0; i < len; i++) {
207301406b9SFrederic Weisbecker 		char *path = NULL;
208301406b9SFrederic Weisbecker 		size_t line_len;
2099cffa8d5SPaul Mackerras 		u64 offset;
210301406b9SFrederic Weisbecker 		FILE *fp;
211301406b9SFrederic Weisbecker 
212e4204992SArnaldo Carvalho de Melo 		sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
213301406b9SFrederic Weisbecker 		if (sym_ext[i].percent <= 0.5)
214301406b9SFrederic Weisbecker 			continue;
215301406b9SFrederic Weisbecker 
216ed52ce2eSArnaldo Carvalho de Melo 		offset = start + i;
217c17c2db1SFrederic Weisbecker 		sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
218301406b9SFrederic Weisbecker 		fp = popen(cmd, "r");
219301406b9SFrederic Weisbecker 		if (!fp)
220301406b9SFrederic Weisbecker 			continue;
221301406b9SFrederic Weisbecker 
222301406b9SFrederic Weisbecker 		if (getline(&path, &line_len, fp) < 0 || !line_len)
223301406b9SFrederic Weisbecker 			goto next;
224301406b9SFrederic Weisbecker 
225c17c2db1SFrederic Weisbecker 		sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
226301406b9SFrederic Weisbecker 		if (!sym_ext[i].path)
227301406b9SFrederic Weisbecker 			goto next;
228301406b9SFrederic Weisbecker 
229301406b9SFrederic Weisbecker 		strcpy(sym_ext[i].path, path);
230971738f3SFrederic Weisbecker 		insert_source_line(&sym_ext[i]);
231301406b9SFrederic Weisbecker 
232301406b9SFrederic Weisbecker 	next:
233301406b9SFrederic Weisbecker 		pclose(fp);
234301406b9SFrederic Weisbecker 	}
235301406b9SFrederic Weisbecker }
236301406b9SFrederic Weisbecker 
23783a0944fSIngo Molnar static void print_summary(const char *filename)
238971738f3SFrederic Weisbecker {
239971738f3SFrederic Weisbecker 	struct sym_ext *sym_ext;
240971738f3SFrederic Weisbecker 	struct rb_node *node;
241971738f3SFrederic Weisbecker 
242971738f3SFrederic Weisbecker 	printf("\nSorted summary for file %s\n", filename);
243971738f3SFrederic Weisbecker 	printf("----------------------------------------------\n\n");
244971738f3SFrederic Weisbecker 
245971738f3SFrederic Weisbecker 	if (RB_EMPTY_ROOT(&root_sym_ext)) {
246971738f3SFrederic Weisbecker 		printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
247971738f3SFrederic Weisbecker 		return;
248971738f3SFrederic Weisbecker 	}
249971738f3SFrederic Weisbecker 
250971738f3SFrederic Weisbecker 	node = rb_first(&root_sym_ext);
251971738f3SFrederic Weisbecker 	while (node) {
252971738f3SFrederic Weisbecker 		double percent;
25383a0944fSIngo Molnar 		const char *color;
254971738f3SFrederic Weisbecker 		char *path;
255971738f3SFrederic Weisbecker 
256971738f3SFrederic Weisbecker 		sym_ext = rb_entry(node, struct sym_ext, node);
257971738f3SFrederic Weisbecker 		percent = sym_ext->percent;
2581e11fd82SFrederic Weisbecker 		color = get_percent_color(percent);
259971738f3SFrederic Weisbecker 		path = sym_ext->path;
260971738f3SFrederic Weisbecker 
261971738f3SFrederic Weisbecker 		color_fprintf(stdout, color, " %7.2f %s", percent, path);
262971738f3SFrederic Weisbecker 		node = rb_next(node);
263971738f3SFrederic Weisbecker 	}
264971738f3SFrederic Weisbecker }
265971738f3SFrederic Weisbecker 
26648fb4fddSArnaldo Carvalho de Melo static void hist_entry__print_hits(struct hist_entry *self)
26748fb4fddSArnaldo Carvalho de Melo {
26859fd5306SArnaldo Carvalho de Melo 	struct symbol *sym = self->ms.sym;
26948fb4fddSArnaldo Carvalho de Melo 	struct sym_priv *priv = symbol__priv(sym);
27048fb4fddSArnaldo Carvalho de Melo 	struct sym_hist *h = priv->hist;
27148fb4fddSArnaldo Carvalho de Melo 	u64 len = sym->end - sym->start, offset;
27248fb4fddSArnaldo Carvalho de Melo 
27348fb4fddSArnaldo Carvalho de Melo 	for (offset = 0; offset < len; ++offset)
27448fb4fddSArnaldo Carvalho de Melo 		if (h->ip[offset] != 0)
27548fb4fddSArnaldo Carvalho de Melo 			printf("%*Lx: %Lu\n", BITS_PER_LONG / 2,
27648fb4fddSArnaldo Carvalho de Melo 			       sym->start + offset, h->ip[offset]);
27748fb4fddSArnaldo Carvalho de Melo 	printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum);
27848fb4fddSArnaldo Carvalho de Melo }
27948fb4fddSArnaldo Carvalho de Melo 
28046e3e055SArnaldo Carvalho de Melo static int hist_entry__tty_annotate(struct hist_entry *he)
28186470930SIngo Molnar {
28259fd5306SArnaldo Carvalho de Melo 	struct map *map = he->ms.map;
283ed52ce2eSArnaldo Carvalho de Melo 	struct dso *dso = map->dso;
28459fd5306SArnaldo Carvalho de Melo 	struct symbol *sym = he->ms.sym;
285439d473bSArnaldo Carvalho de Melo 	const char *filename = dso->long_name, *d_filename;
286439d473bSArnaldo Carvalho de Melo 	u64 len;
28748fb4fddSArnaldo Carvalho de Melo 	LIST_HEAD(head);
28848fb4fddSArnaldo Carvalho de Melo 	struct objdump_line *pos, *n;
28986470930SIngo Molnar 
290ef7b93a1SArnaldo Carvalho de Melo 	if (hist_entry__annotate(he, &head) < 0)
29146e3e055SArnaldo Carvalho de Melo 		return -1;
29286470930SIngo Molnar 
29342976487SMike Galbraith 	if (full_paths)
29442976487SMike Galbraith 		d_filename = filename;
29542976487SMike Galbraith 	else
29642976487SMike Galbraith 		d_filename = basename(filename);
29786470930SIngo Molnar 
29886470930SIngo Molnar 	len = sym->end - sym->start;
29986470930SIngo Molnar 
300971738f3SFrederic Weisbecker 	if (print_line) {
301ed52ce2eSArnaldo Carvalho de Melo 		get_source_line(he, len, filename);
302971738f3SFrederic Weisbecker 		print_summary(filename);
303971738f3SFrederic Weisbecker 	}
304971738f3SFrederic Weisbecker 
305971738f3SFrederic Weisbecker 	printf("\n\n------------------------------------------------\n");
30642976487SMike Galbraith 	printf(" Percent |	Source code & Disassembly of %s\n", d_filename);
307971738f3SFrederic Weisbecker 	printf("------------------------------------------------\n");
308971738f3SFrederic Weisbecker 
30948fb4fddSArnaldo Carvalho de Melo 	if (verbose)
31048fb4fddSArnaldo Carvalho de Melo 		hist_entry__print_hits(he);
31148fb4fddSArnaldo Carvalho de Melo 
31248fb4fddSArnaldo Carvalho de Melo 	list_for_each_entry_safe(pos, n, &head, node) {
31348fb4fddSArnaldo Carvalho de Melo 		objdump_line__print(pos, &head, he, len);
31448fb4fddSArnaldo Carvalho de Melo 		list_del(&pos->node);
31548fb4fddSArnaldo Carvalho de Melo 		objdump_line__free(pos);
31648fb4fddSArnaldo Carvalho de Melo 	}
31748fb4fddSArnaldo Carvalho de Melo 
318971738f3SFrederic Weisbecker 	if (print_line)
319e4204992SArnaldo Carvalho de Melo 		free_source_line(he, len);
32046e3e055SArnaldo Carvalho de Melo 
32146e3e055SArnaldo Carvalho de Melo 	return 0;
32286470930SIngo Molnar }
32386470930SIngo Molnar 
3241c02c4d2SArnaldo Carvalho de Melo static void hists__find_annotations(struct hists *self)
32586470930SIngo Molnar {
32646e3e055SArnaldo Carvalho de Melo 	struct rb_node *first = rb_first(&self->entries), *nd = first;
32746e3e055SArnaldo Carvalho de Melo 	int key = KEY_RIGHT;
32886470930SIngo Molnar 
32946e3e055SArnaldo Carvalho de Melo 	while (nd) {
330ed52ce2eSArnaldo Carvalho de Melo 		struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
331e4204992SArnaldo Carvalho de Melo 		struct sym_priv *priv;
33286470930SIngo Molnar 
33346e3e055SArnaldo Carvalho de Melo 		if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned)
33446e3e055SArnaldo Carvalho de Melo 			goto find_next;
335e4204992SArnaldo Carvalho de Melo 
33659fd5306SArnaldo Carvalho de Melo 		priv = symbol__priv(he->ms.sym);
33746e3e055SArnaldo Carvalho de Melo 		if (priv->hist == NULL) {
33846e3e055SArnaldo Carvalho de Melo find_next:
33946e3e055SArnaldo Carvalho de Melo 			if (key == KEY_LEFT)
34046e3e055SArnaldo Carvalho de Melo 				nd = rb_prev(nd);
34146e3e055SArnaldo Carvalho de Melo 			else
34246e3e055SArnaldo Carvalho de Melo 				nd = rb_next(nd);
343e4204992SArnaldo Carvalho de Melo 			continue;
34446e3e055SArnaldo Carvalho de Melo 		}
345e4204992SArnaldo Carvalho de Melo 
34662e3436bSArnaldo Carvalho de Melo 		if (use_browser > 0) {
34746e3e055SArnaldo Carvalho de Melo 			key = hist_entry__tui_annotate(he);
34846e3e055SArnaldo Carvalho de Melo 			if (is_exit_key(key))
34946e3e055SArnaldo Carvalho de Melo 				break;
35046e3e055SArnaldo Carvalho de Melo 			switch (key) {
35146e3e055SArnaldo Carvalho de Melo 			case KEY_RIGHT:
35246e3e055SArnaldo Carvalho de Melo 			case '\t':
35346e3e055SArnaldo Carvalho de Melo 				nd = rb_next(nd);
35446e3e055SArnaldo Carvalho de Melo 				break;
35546e3e055SArnaldo Carvalho de Melo 			case KEY_LEFT:
35646e3e055SArnaldo Carvalho de Melo 				if (nd == first)
35746e3e055SArnaldo Carvalho de Melo 					continue;
35846e3e055SArnaldo Carvalho de Melo 				nd = rb_prev(nd);
35946e3e055SArnaldo Carvalho de Melo 			default:
36046e3e055SArnaldo Carvalho de Melo 				break;
36146e3e055SArnaldo Carvalho de Melo 			}
36246e3e055SArnaldo Carvalho de Melo 		} else {
36346e3e055SArnaldo Carvalho de Melo 			hist_entry__tty_annotate(he);
36446e3e055SArnaldo Carvalho de Melo 			nd = rb_next(nd);
365ed52ce2eSArnaldo Carvalho de Melo 			/*
36646e3e055SArnaldo Carvalho de Melo 			 * Since we have a hist_entry per IP for the same
36746e3e055SArnaldo Carvalho de Melo 			 * symbol, free he->ms.sym->hist to signal we already
36846e3e055SArnaldo Carvalho de Melo 			 * processed this symbol.
369ed52ce2eSArnaldo Carvalho de Melo 			 */
370e4204992SArnaldo Carvalho de Melo 			free(priv->hist);
371e4204992SArnaldo Carvalho de Melo 			priv->hist = NULL;
37286470930SIngo Molnar 		}
37386470930SIngo Molnar 	}
37446e3e055SArnaldo Carvalho de Melo }
37586470930SIngo Molnar 
376301a0b02SArnaldo Carvalho de Melo static struct perf_event_ops event_ops = {
37755aa640fSArnaldo Carvalho de Melo 	.sample	= process_sample_event,
37855aa640fSArnaldo Carvalho de Melo 	.mmap	= event__process_mmap,
37955aa640fSArnaldo Carvalho de Melo 	.comm	= event__process_comm,
38055aa640fSArnaldo Carvalho de Melo 	.fork	= event__process_task,
381bab81b62SLi Zefan };
382bab81b62SLi Zefan 
38386470930SIngo Molnar static int __cmd_annotate(void)
38486470930SIngo Molnar {
385bab81b62SLi Zefan 	int ret;
38675be6cf4SArnaldo Carvalho de Melo 	struct perf_session *session;
38786470930SIngo Molnar 
388454c407eSTom Zanussi 	session = perf_session__new(input_name, O_RDONLY, force, false);
38994c744b6SArnaldo Carvalho de Melo 	if (session == NULL)
39094c744b6SArnaldo Carvalho de Melo 		return -ENOMEM;
39194c744b6SArnaldo Carvalho de Melo 
392ec913369SArnaldo Carvalho de Melo 	ret = perf_session__process_events(session, &event_ops);
393bab81b62SLi Zefan 	if (ret)
39494c744b6SArnaldo Carvalho de Melo 		goto out_delete;
39586470930SIngo Molnar 
39662daacb5SArnaldo Carvalho de Melo 	if (dump_trace) {
397c8446b9bSArnaldo Carvalho de Melo 		perf_session__fprintf_nr_events(session, stdout);
39894c744b6SArnaldo Carvalho de Melo 		goto out_delete;
39962daacb5SArnaldo Carvalho de Melo 	}
40086470930SIngo Molnar 
401da21d1b5SArnaldo Carvalho de Melo 	if (verbose > 3)
402b3165f41SArnaldo Carvalho de Melo 		perf_session__fprintf(session, stdout);
40386470930SIngo Molnar 
404da21d1b5SArnaldo Carvalho de Melo 	if (verbose > 2)
405cbf69680SArnaldo Carvalho de Melo 		perf_session__fprintf_dsos(session, stdout);
40686470930SIngo Molnar 
4071c02c4d2SArnaldo Carvalho de Melo 	hists__collapse_resort(&session->hists);
4081c02c4d2SArnaldo Carvalho de Melo 	hists__output_resort(&session->hists);
4091c02c4d2SArnaldo Carvalho de Melo 	hists__find_annotations(&session->hists);
41094c744b6SArnaldo Carvalho de Melo out_delete:
41194c744b6SArnaldo Carvalho de Melo 	perf_session__delete(session);
41286470930SIngo Molnar 
413bab81b62SLi Zefan 	return ret;
41486470930SIngo Molnar }
41586470930SIngo Molnar 
41686470930SIngo Molnar static const char * const annotate_usage[] = {
41786470930SIngo Molnar 	"perf annotate [<options>] <command>",
41886470930SIngo Molnar 	NULL
41986470930SIngo Molnar };
42086470930SIngo Molnar 
42186470930SIngo Molnar static const struct option options[] = {
42286470930SIngo Molnar 	OPT_STRING('i', "input", &input_name, "file",
42386470930SIngo Molnar 		    "input file name"),
424ac73c5a9SArnaldo Carvalho de Melo 	OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
425ac73c5a9SArnaldo Carvalho de Melo 		   "only consider symbols in these dsos"),
42623b87116SIngo Molnar 	OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
42786470930SIngo Molnar 		    "symbol to annotate"),
428fa6963b2SPeter Zijlstra 	OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
429c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
43086470930SIngo Molnar 		    "be more verbose (show symbol address, etc)"),
43186470930SIngo Molnar 	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
43286470930SIngo Molnar 		    "dump raw trace in ASCII"),
433b32d133aSArnaldo Carvalho de Melo 	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
434b32d133aSArnaldo Carvalho de Melo 		   "file", "vmlinux pathname"),
435b32d133aSArnaldo Carvalho de Melo 	OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
43642976487SMike Galbraith 		    "load module symbols - WARNING: use only with -k and LIVE kernel"),
437301406b9SFrederic Weisbecker 	OPT_BOOLEAN('l', "print-line", &print_line,
438301406b9SFrederic Weisbecker 		    "print matching source lines (may be slow)"),
43942976487SMike Galbraith 	OPT_BOOLEAN('P', "full-paths", &full_paths,
44042976487SMike Galbraith 		    "Don't shorten the displayed pathnames"),
44186470930SIngo Molnar 	OPT_END()
44286470930SIngo Molnar };
44386470930SIngo Molnar 
444f37a291cSIngo Molnar int cmd_annotate(int argc, const char **argv, const char *prefix __used)
44586470930SIngo Molnar {
446655000e7SArnaldo Carvalho de Melo 	argc = parse_options(argc, argv, options, annotate_usage, 0);
447655000e7SArnaldo Carvalho de Melo 
44846e3e055SArnaldo Carvalho de Melo 	setup_browser();
44946e3e055SArnaldo Carvalho de Melo 
45075be6cf4SArnaldo Carvalho de Melo 	symbol_conf.priv_size = sizeof(struct sym_priv);
45175be6cf4SArnaldo Carvalho de Melo 	symbol_conf.try_vmlinux_path = true;
45275be6cf4SArnaldo Carvalho de Melo 
45375be6cf4SArnaldo Carvalho de Melo 	if (symbol__init() < 0)
454b32d133aSArnaldo Carvalho de Melo 		return -1;
45586470930SIngo Molnar 
456c8829c7aSArnaldo Carvalho de Melo 	setup_sorting(annotate_usage, options);
45786470930SIngo Molnar 
45886470930SIngo Molnar 	if (argc) {
45986470930SIngo Molnar 		/*
46086470930SIngo Molnar 		 * Special case: if there's an argument left then assume tha
46186470930SIngo Molnar 		 * it's a symbol filter:
46286470930SIngo Molnar 		 */
46386470930SIngo Molnar 		if (argc > 1)
46486470930SIngo Molnar 			usage_with_options(annotate_usage, options);
46586470930SIngo Molnar 
46686470930SIngo Molnar 		sym_hist_filter = argv[0];
46786470930SIngo Molnar 	}
46886470930SIngo Molnar 
469dd68ada2SJohn Kacur 	if (field_sep && *field_sep == '.') {
47029a9f66dSArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
47129a9f66dSArnaldo Carvalho de Melo 		return -1;
472dd68ada2SJohn Kacur 	}
473dd68ada2SJohn Kacur 
47486470930SIngo Molnar 	return __cmd_annotate();
47586470930SIngo Molnar }
476