xref: /openbmc/linux/tools/perf/builtin-annotate.c (revision eac23d1c)
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 
318b9e74ebSArnaldo Carvalho de Melo static bool		force, use_tui, use_stdio;
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 
61640c03ceSArnaldo Carvalho de Melo static int process_sample_event(event_t *event, struct sample_data *sample,
62640c03ceSArnaldo Carvalho de Melo 				struct perf_session *session)
6386470930SIngo Molnar {
641ed091c4SArnaldo Carvalho de Melo 	struct addr_location al;
656baa0a5aSFrederic Weisbecker 
66640c03ceSArnaldo Carvalho de Melo 	if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
6729a9f66dSArnaldo Carvalho de Melo 		pr_warning("problem processing %d event, skipping it.\n",
6886470930SIngo Molnar 			   event->header.type);
6986470930SIngo Molnar 		return -1;
7086470930SIngo Molnar 	}
7186470930SIngo Molnar 
721c02c4d2SArnaldo Carvalho de Melo 	if (!al.filtered && hists__add_entry(&session->hists, &al)) {
7329a9f66dSArnaldo Carvalho de Melo 		pr_warning("problem incrementing symbol count, "
74ec218fc4SArnaldo Carvalho de Melo 			   "skipping event\n");
7586470930SIngo Molnar 		return -1;
7686470930SIngo Molnar 	}
7786470930SIngo Molnar 
7886470930SIngo Molnar 	return 0;
7986470930SIngo Molnar }
8086470930SIngo Molnar 
8148fb4fddSArnaldo Carvalho de Melo static int objdump_line__print(struct objdump_line *self,
8248fb4fddSArnaldo Carvalho de Melo 			       struct list_head *head,
8348fb4fddSArnaldo Carvalho de Melo 			       struct hist_entry *he, u64 len)
8448fb4fddSArnaldo Carvalho de Melo {
8559fd5306SArnaldo Carvalho de Melo 	struct symbol *sym = he->ms.sym;
8648fb4fddSArnaldo Carvalho de Melo 	static const char *prev_line;
8748fb4fddSArnaldo Carvalho de Melo 	static const char *prev_color;
8848fb4fddSArnaldo Carvalho de Melo 
8948fb4fddSArnaldo Carvalho de Melo 	if (self->offset != -1) {
90301406b9SFrederic Weisbecker 		const char *path = NULL;
9186470930SIngo Molnar 		unsigned int hits = 0;
9286470930SIngo Molnar 		double percent = 0.0;
9383a0944fSIngo Molnar 		const char *color;
9400a192b3SArnaldo Carvalho de Melo 		struct sym_priv *priv = symbol__priv(sym);
95e4204992SArnaldo Carvalho de Melo 		struct sym_ext *sym_ext = priv->ext;
96e4204992SArnaldo Carvalho de Melo 		struct sym_hist *h = priv->hist;
9748fb4fddSArnaldo Carvalho de Melo 		s64 offset = self->offset;
9848fb4fddSArnaldo Carvalho de Melo 		struct objdump_line *next = objdump__get_next_ip_line(head, self);
9986470930SIngo Molnar 
10048fb4fddSArnaldo Carvalho de Melo 		while (offset < (s64)len &&
10148fb4fddSArnaldo Carvalho de Melo 		       (next == NULL || offset < next->offset)) {
10248fb4fddSArnaldo Carvalho de Melo 			if (sym_ext) {
10348fb4fddSArnaldo Carvalho de Melo 				if (path == NULL)
104301406b9SFrederic Weisbecker 					path = sym_ext[offset].path;
10548fb4fddSArnaldo Carvalho de Melo 				percent += sym_ext[offset].percent;
10648fb4fddSArnaldo Carvalho de Melo 			} else
10748fb4fddSArnaldo Carvalho de Melo 				hits += h->ip[offset];
10848fb4fddSArnaldo Carvalho de Melo 
10948fb4fddSArnaldo Carvalho de Melo 			++offset;
11048fb4fddSArnaldo Carvalho de Melo 		}
11148fb4fddSArnaldo Carvalho de Melo 
11248fb4fddSArnaldo Carvalho de Melo 		if (sym_ext == NULL && h->sum)
113e4204992SArnaldo Carvalho de Melo 			percent = 100.0 * hits / h->sum;
11486470930SIngo Molnar 
1151e11fd82SFrederic Weisbecker 		color = get_percent_color(percent);
11686470930SIngo Molnar 
117301406b9SFrederic Weisbecker 		/*
118301406b9SFrederic Weisbecker 		 * Also color the filename and line if needed, with
119301406b9SFrederic Weisbecker 		 * the same color than the percentage. Don't print it
120301406b9SFrederic Weisbecker 		 * twice for close colored ip with the same filename:line
121301406b9SFrederic Weisbecker 		 */
122301406b9SFrederic Weisbecker 		if (path) {
123301406b9SFrederic Weisbecker 			if (!prev_line || strcmp(prev_line, path)
124301406b9SFrederic Weisbecker 				       || color != prev_color) {
125301406b9SFrederic Weisbecker 				color_fprintf(stdout, color, " %s", path);
126301406b9SFrederic Weisbecker 				prev_line = path;
127301406b9SFrederic Weisbecker 				prev_color = color;
128301406b9SFrederic Weisbecker 			}
129301406b9SFrederic Weisbecker 		}
130301406b9SFrederic Weisbecker 
13186470930SIngo Molnar 		color_fprintf(stdout, color, " %7.2f", percent);
13286470930SIngo Molnar 		printf(" :	");
13348fb4fddSArnaldo Carvalho de Melo 		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line);
13486470930SIngo Molnar 	} else {
13548fb4fddSArnaldo Carvalho de Melo 		if (!*self->line)
13686470930SIngo Molnar 			printf("         :\n");
13786470930SIngo Molnar 		else
13848fb4fddSArnaldo Carvalho de Melo 			printf("         :	%s\n", self->line);
13986470930SIngo Molnar 	}
14086470930SIngo Molnar 
14186470930SIngo Molnar 	return 0;
14286470930SIngo Molnar }
14386470930SIngo Molnar 
144971738f3SFrederic Weisbecker static struct rb_root root_sym_ext;
145971738f3SFrederic Weisbecker 
146971738f3SFrederic Weisbecker static void insert_source_line(struct sym_ext *sym_ext)
147971738f3SFrederic Weisbecker {
148971738f3SFrederic Weisbecker 	struct sym_ext *iter;
149971738f3SFrederic Weisbecker 	struct rb_node **p = &root_sym_ext.rb_node;
150971738f3SFrederic Weisbecker 	struct rb_node *parent = NULL;
151971738f3SFrederic Weisbecker 
152971738f3SFrederic Weisbecker 	while (*p != NULL) {
153971738f3SFrederic Weisbecker 		parent = *p;
154971738f3SFrederic Weisbecker 		iter = rb_entry(parent, struct sym_ext, node);
155971738f3SFrederic Weisbecker 
156971738f3SFrederic Weisbecker 		if (sym_ext->percent > iter->percent)
157971738f3SFrederic Weisbecker 			p = &(*p)->rb_left;
158971738f3SFrederic Weisbecker 		else
159971738f3SFrederic Weisbecker 			p = &(*p)->rb_right;
160971738f3SFrederic Weisbecker 	}
161971738f3SFrederic Weisbecker 
162971738f3SFrederic Weisbecker 	rb_link_node(&sym_ext->node, parent, p);
163971738f3SFrederic Weisbecker 	rb_insert_color(&sym_ext->node, &root_sym_ext);
164971738f3SFrederic Weisbecker }
165971738f3SFrederic Weisbecker 
166e4204992SArnaldo Carvalho de Melo static void free_source_line(struct hist_entry *he, int len)
167301406b9SFrederic Weisbecker {
16859fd5306SArnaldo Carvalho de Melo 	struct sym_priv *priv = symbol__priv(he->ms.sym);
169e4204992SArnaldo Carvalho de Melo 	struct sym_ext *sym_ext = priv->ext;
170301406b9SFrederic Weisbecker 	int i;
171301406b9SFrederic Weisbecker 
172301406b9SFrederic Weisbecker 	if (!sym_ext)
173301406b9SFrederic Weisbecker 		return;
174301406b9SFrederic Weisbecker 
175301406b9SFrederic Weisbecker 	for (i = 0; i < len; i++)
176301406b9SFrederic Weisbecker 		free(sym_ext[i].path);
177301406b9SFrederic Weisbecker 	free(sym_ext);
178301406b9SFrederic Weisbecker 
179e4204992SArnaldo Carvalho de Melo 	priv->ext = NULL;
180971738f3SFrederic Weisbecker 	root_sym_ext = RB_ROOT;
181301406b9SFrederic Weisbecker }
182301406b9SFrederic Weisbecker 
183301406b9SFrederic Weisbecker /* Get the filename:line for the colored entries */
184c17c2db1SFrederic Weisbecker static void
185ed52ce2eSArnaldo Carvalho de Melo get_source_line(struct hist_entry *he, int len, const char *filename)
186301406b9SFrederic Weisbecker {
18759fd5306SArnaldo Carvalho de Melo 	struct symbol *sym = he->ms.sym;
188ed52ce2eSArnaldo Carvalho de Melo 	u64 start;
189301406b9SFrederic Weisbecker 	int i;
190301406b9SFrederic Weisbecker 	char cmd[PATH_MAX * 2];
191301406b9SFrederic Weisbecker 	struct sym_ext *sym_ext;
19200a192b3SArnaldo Carvalho de Melo 	struct sym_priv *priv = symbol__priv(sym);
193e4204992SArnaldo Carvalho de Melo 	struct sym_hist *h = priv->hist;
194301406b9SFrederic Weisbecker 
195e4204992SArnaldo Carvalho de Melo 	if (!h->sum)
196301406b9SFrederic Weisbecker 		return;
197301406b9SFrederic Weisbecker 
198e4204992SArnaldo Carvalho de Melo 	sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
199e4204992SArnaldo Carvalho de Melo 	if (!priv->ext)
200301406b9SFrederic Weisbecker 		return;
201301406b9SFrederic Weisbecker 
20259fd5306SArnaldo Carvalho de Melo 	start = he->ms.map->unmap_ip(he->ms.map, sym->start);
203301406b9SFrederic Weisbecker 
204301406b9SFrederic Weisbecker 	for (i = 0; i < len; i++) {
205301406b9SFrederic Weisbecker 		char *path = NULL;
206301406b9SFrederic Weisbecker 		size_t line_len;
2079cffa8d5SPaul Mackerras 		u64 offset;
208301406b9SFrederic Weisbecker 		FILE *fp;
209301406b9SFrederic Weisbecker 
210e4204992SArnaldo Carvalho de Melo 		sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
211301406b9SFrederic Weisbecker 		if (sym_ext[i].percent <= 0.5)
212301406b9SFrederic Weisbecker 			continue;
213301406b9SFrederic Weisbecker 
214ed52ce2eSArnaldo Carvalho de Melo 		offset = start + i;
215c17c2db1SFrederic Weisbecker 		sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
216301406b9SFrederic Weisbecker 		fp = popen(cmd, "r");
217301406b9SFrederic Weisbecker 		if (!fp)
218301406b9SFrederic Weisbecker 			continue;
219301406b9SFrederic Weisbecker 
220301406b9SFrederic Weisbecker 		if (getline(&path, &line_len, fp) < 0 || !line_len)
221301406b9SFrederic Weisbecker 			goto next;
222301406b9SFrederic Weisbecker 
223c17c2db1SFrederic Weisbecker 		sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
224301406b9SFrederic Weisbecker 		if (!sym_ext[i].path)
225301406b9SFrederic Weisbecker 			goto next;
226301406b9SFrederic Weisbecker 
227301406b9SFrederic Weisbecker 		strcpy(sym_ext[i].path, path);
228971738f3SFrederic Weisbecker 		insert_source_line(&sym_ext[i]);
229301406b9SFrederic Weisbecker 
230301406b9SFrederic Weisbecker 	next:
231301406b9SFrederic Weisbecker 		pclose(fp);
232301406b9SFrederic Weisbecker 	}
233301406b9SFrederic Weisbecker }
234301406b9SFrederic Weisbecker 
23583a0944fSIngo Molnar static void print_summary(const char *filename)
236971738f3SFrederic Weisbecker {
237971738f3SFrederic Weisbecker 	struct sym_ext *sym_ext;
238971738f3SFrederic Weisbecker 	struct rb_node *node;
239971738f3SFrederic Weisbecker 
240971738f3SFrederic Weisbecker 	printf("\nSorted summary for file %s\n", filename);
241971738f3SFrederic Weisbecker 	printf("----------------------------------------------\n\n");
242971738f3SFrederic Weisbecker 
243971738f3SFrederic Weisbecker 	if (RB_EMPTY_ROOT(&root_sym_ext)) {
244971738f3SFrederic Weisbecker 		printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
245971738f3SFrederic Weisbecker 		return;
246971738f3SFrederic Weisbecker 	}
247971738f3SFrederic Weisbecker 
248971738f3SFrederic Weisbecker 	node = rb_first(&root_sym_ext);
249971738f3SFrederic Weisbecker 	while (node) {
250971738f3SFrederic Weisbecker 		double percent;
25183a0944fSIngo Molnar 		const char *color;
252971738f3SFrederic Weisbecker 		char *path;
253971738f3SFrederic Weisbecker 
254971738f3SFrederic Weisbecker 		sym_ext = rb_entry(node, struct sym_ext, node);
255971738f3SFrederic Weisbecker 		percent = sym_ext->percent;
2561e11fd82SFrederic Weisbecker 		color = get_percent_color(percent);
257971738f3SFrederic Weisbecker 		path = sym_ext->path;
258971738f3SFrederic Weisbecker 
259971738f3SFrederic Weisbecker 		color_fprintf(stdout, color, " %7.2f %s", percent, path);
260971738f3SFrederic Weisbecker 		node = rb_next(node);
261971738f3SFrederic Weisbecker 	}
262971738f3SFrederic Weisbecker }
263971738f3SFrederic Weisbecker 
26448fb4fddSArnaldo Carvalho de Melo static void hist_entry__print_hits(struct hist_entry *self)
26548fb4fddSArnaldo Carvalho de Melo {
26659fd5306SArnaldo Carvalho de Melo 	struct symbol *sym = self->ms.sym;
26748fb4fddSArnaldo Carvalho de Melo 	struct sym_priv *priv = symbol__priv(sym);
26848fb4fddSArnaldo Carvalho de Melo 	struct sym_hist *h = priv->hist;
26948fb4fddSArnaldo Carvalho de Melo 	u64 len = sym->end - sym->start, offset;
27048fb4fddSArnaldo Carvalho de Melo 
27148fb4fddSArnaldo Carvalho de Melo 	for (offset = 0; offset < len; ++offset)
27248fb4fddSArnaldo Carvalho de Melo 		if (h->ip[offset] != 0)
27348fb4fddSArnaldo Carvalho de Melo 			printf("%*Lx: %Lu\n", BITS_PER_LONG / 2,
27448fb4fddSArnaldo Carvalho de Melo 			       sym->start + offset, h->ip[offset]);
27548fb4fddSArnaldo Carvalho de Melo 	printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum);
27648fb4fddSArnaldo Carvalho de Melo }
27748fb4fddSArnaldo Carvalho de Melo 
27846e3e055SArnaldo Carvalho de Melo static int hist_entry__tty_annotate(struct hist_entry *he)
27986470930SIngo Molnar {
28059fd5306SArnaldo Carvalho de Melo 	struct map *map = he->ms.map;
281ed52ce2eSArnaldo Carvalho de Melo 	struct dso *dso = map->dso;
28259fd5306SArnaldo Carvalho de Melo 	struct symbol *sym = he->ms.sym;
283439d473bSArnaldo Carvalho de Melo 	const char *filename = dso->long_name, *d_filename;
284439d473bSArnaldo Carvalho de Melo 	u64 len;
28548fb4fddSArnaldo Carvalho de Melo 	LIST_HEAD(head);
28648fb4fddSArnaldo Carvalho de Melo 	struct objdump_line *pos, *n;
28786470930SIngo Molnar 
28892221162SArnaldo Carvalho de Melo 	if (hist_entry__annotate(he, &head, 0) < 0)
28946e3e055SArnaldo Carvalho de Melo 		return -1;
29086470930SIngo Molnar 
29142976487SMike Galbraith 	if (full_paths)
29242976487SMike Galbraith 		d_filename = filename;
29342976487SMike Galbraith 	else
29442976487SMike Galbraith 		d_filename = basename(filename);
29586470930SIngo Molnar 
29686470930SIngo Molnar 	len = sym->end - sym->start;
29786470930SIngo Molnar 
298971738f3SFrederic Weisbecker 	if (print_line) {
299ed52ce2eSArnaldo Carvalho de Melo 		get_source_line(he, len, filename);
300971738f3SFrederic Weisbecker 		print_summary(filename);
301971738f3SFrederic Weisbecker 	}
302971738f3SFrederic Weisbecker 
303971738f3SFrederic Weisbecker 	printf("\n\n------------------------------------------------\n");
30442976487SMike Galbraith 	printf(" Percent |	Source code & Disassembly of %s\n", d_filename);
305971738f3SFrederic Weisbecker 	printf("------------------------------------------------\n");
306971738f3SFrederic Weisbecker 
30748fb4fddSArnaldo Carvalho de Melo 	if (verbose)
30848fb4fddSArnaldo Carvalho de Melo 		hist_entry__print_hits(he);
30948fb4fddSArnaldo Carvalho de Melo 
31048fb4fddSArnaldo Carvalho de Melo 	list_for_each_entry_safe(pos, n, &head, node) {
31148fb4fddSArnaldo Carvalho de Melo 		objdump_line__print(pos, &head, he, len);
31248fb4fddSArnaldo Carvalho de Melo 		list_del(&pos->node);
31348fb4fddSArnaldo Carvalho de Melo 		objdump_line__free(pos);
31448fb4fddSArnaldo Carvalho de Melo 	}
31548fb4fddSArnaldo Carvalho de Melo 
316971738f3SFrederic Weisbecker 	if (print_line)
317e4204992SArnaldo Carvalho de Melo 		free_source_line(he, len);
31846e3e055SArnaldo Carvalho de Melo 
31946e3e055SArnaldo Carvalho de Melo 	return 0;
32086470930SIngo Molnar }
32186470930SIngo Molnar 
3221c02c4d2SArnaldo Carvalho de Melo static void hists__find_annotations(struct hists *self)
32386470930SIngo Molnar {
324b50e003dSArnaldo Carvalho de Melo 	struct rb_node *nd = rb_first(&self->entries), *next;
32546e3e055SArnaldo Carvalho de Melo 	int key = KEY_RIGHT;
32686470930SIngo Molnar 
32746e3e055SArnaldo Carvalho de Melo 	while (nd) {
328ed52ce2eSArnaldo Carvalho de Melo 		struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
329e4204992SArnaldo Carvalho de Melo 		struct sym_priv *priv;
33086470930SIngo Molnar 
33146e3e055SArnaldo Carvalho de Melo 		if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned)
33246e3e055SArnaldo Carvalho de Melo 			goto find_next;
333e4204992SArnaldo Carvalho de Melo 
33459fd5306SArnaldo Carvalho de Melo 		priv = symbol__priv(he->ms.sym);
33546e3e055SArnaldo Carvalho de Melo 		if (priv->hist == NULL) {
33646e3e055SArnaldo Carvalho de Melo find_next:
33746e3e055SArnaldo Carvalho de Melo 			if (key == KEY_LEFT)
33846e3e055SArnaldo Carvalho de Melo 				nd = rb_prev(nd);
33946e3e055SArnaldo Carvalho de Melo 			else
34046e3e055SArnaldo Carvalho de Melo 				nd = rb_next(nd);
341e4204992SArnaldo Carvalho de Melo 			continue;
34246e3e055SArnaldo Carvalho de Melo 		}
343e4204992SArnaldo Carvalho de Melo 
34462e3436bSArnaldo Carvalho de Melo 		if (use_browser > 0) {
34546e3e055SArnaldo Carvalho de Melo 			key = hist_entry__tui_annotate(he);
34646e3e055SArnaldo Carvalho de Melo 			switch (key) {
34746e3e055SArnaldo Carvalho de Melo 			case KEY_RIGHT:
348b50e003dSArnaldo Carvalho de Melo 				next = rb_next(nd);
34946e3e055SArnaldo Carvalho de Melo 				break;
35046e3e055SArnaldo Carvalho de Melo 			case KEY_LEFT:
351b50e003dSArnaldo Carvalho de Melo 				next = rb_prev(nd);
35246e3e055SArnaldo Carvalho de Melo 				break;
353b50e003dSArnaldo Carvalho de Melo 			default:
354b50e003dSArnaldo Carvalho de Melo 				return;
35546e3e055SArnaldo Carvalho de Melo 			}
356b50e003dSArnaldo Carvalho de Melo 
357b50e003dSArnaldo Carvalho de Melo 			if (next != NULL)
358b50e003dSArnaldo Carvalho de Melo 				nd = next;
35946e3e055SArnaldo Carvalho de Melo 		} else {
36046e3e055SArnaldo Carvalho de Melo 			hist_entry__tty_annotate(he);
36146e3e055SArnaldo Carvalho de Melo 			nd = rb_next(nd);
362ed52ce2eSArnaldo Carvalho de Melo 			/*
36346e3e055SArnaldo Carvalho de Melo 			 * Since we have a hist_entry per IP for the same
36446e3e055SArnaldo Carvalho de Melo 			 * symbol, free he->ms.sym->hist to signal we already
36546e3e055SArnaldo Carvalho de Melo 			 * processed this symbol.
366ed52ce2eSArnaldo Carvalho de Melo 			 */
367e4204992SArnaldo Carvalho de Melo 			free(priv->hist);
368e4204992SArnaldo Carvalho de Melo 			priv->hist = NULL;
36986470930SIngo Molnar 		}
37086470930SIngo Molnar 	}
37146e3e055SArnaldo Carvalho de Melo }
37286470930SIngo Molnar 
373301a0b02SArnaldo Carvalho de Melo static struct perf_event_ops event_ops = {
37455aa640fSArnaldo Carvalho de Melo 	.sample	= process_sample_event,
37555aa640fSArnaldo Carvalho de Melo 	.mmap	= event__process_mmap,
37655aa640fSArnaldo Carvalho de Melo 	.comm	= event__process_comm,
37755aa640fSArnaldo Carvalho de Melo 	.fork	= event__process_task,
378eac23d1cSIan Munsie 	.ordered_samples = true,
379eac23d1cSIan Munsie 	.ordering_requires_timestamps = true,
380bab81b62SLi Zefan };
381bab81b62SLi Zefan 
38286470930SIngo Molnar static int __cmd_annotate(void)
38386470930SIngo Molnar {
384bab81b62SLi Zefan 	int ret;
38575be6cf4SArnaldo Carvalho de Melo 	struct perf_session *session;
38686470930SIngo Molnar 
38721ef97f0SIan Munsie 	session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
38894c744b6SArnaldo Carvalho de Melo 	if (session == NULL)
38994c744b6SArnaldo Carvalho de Melo 		return -ENOMEM;
39094c744b6SArnaldo Carvalho de Melo 
391ec913369SArnaldo Carvalho de Melo 	ret = perf_session__process_events(session, &event_ops);
392bab81b62SLi Zefan 	if (ret)
39394c744b6SArnaldo Carvalho de Melo 		goto out_delete;
39486470930SIngo Molnar 
39562daacb5SArnaldo Carvalho de Melo 	if (dump_trace) {
396c8446b9bSArnaldo Carvalho de Melo 		perf_session__fprintf_nr_events(session, stdout);
39794c744b6SArnaldo Carvalho de Melo 		goto out_delete;
39862daacb5SArnaldo Carvalho de Melo 	}
39986470930SIngo Molnar 
400da21d1b5SArnaldo Carvalho de Melo 	if (verbose > 3)
401b3165f41SArnaldo Carvalho de Melo 		perf_session__fprintf(session, stdout);
40286470930SIngo Molnar 
403da21d1b5SArnaldo Carvalho de Melo 	if (verbose > 2)
404cbf69680SArnaldo Carvalho de Melo 		perf_session__fprintf_dsos(session, stdout);
40586470930SIngo Molnar 
4061c02c4d2SArnaldo Carvalho de Melo 	hists__collapse_resort(&session->hists);
4071c02c4d2SArnaldo Carvalho de Melo 	hists__output_resort(&session->hists);
4081c02c4d2SArnaldo Carvalho de Melo 	hists__find_annotations(&session->hists);
40994c744b6SArnaldo Carvalho de Melo out_delete:
41094c744b6SArnaldo Carvalho de Melo 	perf_session__delete(session);
41186470930SIngo Molnar 
412bab81b62SLi Zefan 	return ret;
41386470930SIngo Molnar }
41486470930SIngo Molnar 
41586470930SIngo Molnar static const char * const annotate_usage[] = {
41686470930SIngo Molnar 	"perf annotate [<options>] <command>",
41786470930SIngo Molnar 	NULL
41886470930SIngo Molnar };
41986470930SIngo Molnar 
42086470930SIngo Molnar static const struct option options[] = {
42186470930SIngo Molnar 	OPT_STRING('i', "input", &input_name, "file",
42286470930SIngo Molnar 		    "input file name"),
423ac73c5a9SArnaldo Carvalho de Melo 	OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
424ac73c5a9SArnaldo Carvalho de Melo 		   "only consider symbols in these dsos"),
42523b87116SIngo Molnar 	OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
42686470930SIngo Molnar 		    "symbol to annotate"),
427fa6963b2SPeter Zijlstra 	OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
428c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
42986470930SIngo Molnar 		    "be more verbose (show symbol address, etc)"),
43086470930SIngo Molnar 	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
43186470930SIngo Molnar 		    "dump raw trace in ASCII"),
4328b9e74ebSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
4338b9e74ebSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
434b32d133aSArnaldo Carvalho de Melo 	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
435b32d133aSArnaldo Carvalho de Melo 		   "file", "vmlinux pathname"),
436b32d133aSArnaldo Carvalho de Melo 	OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
43742976487SMike Galbraith 		    "load module symbols - WARNING: use only with -k and LIVE kernel"),
438301406b9SFrederic Weisbecker 	OPT_BOOLEAN('l', "print-line", &print_line,
439301406b9SFrederic Weisbecker 		    "print matching source lines (may be slow)"),
44042976487SMike Galbraith 	OPT_BOOLEAN('P', "full-paths", &full_paths,
44142976487SMike Galbraith 		    "Don't shorten the displayed pathnames"),
44286470930SIngo Molnar 	OPT_END()
44386470930SIngo Molnar };
44486470930SIngo Molnar 
445f37a291cSIngo Molnar int cmd_annotate(int argc, const char **argv, const char *prefix __used)
44686470930SIngo Molnar {
447655000e7SArnaldo Carvalho de Melo 	argc = parse_options(argc, argv, options, annotate_usage, 0);
448655000e7SArnaldo Carvalho de Melo 
4498b9e74ebSArnaldo Carvalho de Melo 	if (use_stdio)
4508b9e74ebSArnaldo Carvalho de Melo 		use_browser = 0;
4518b9e74ebSArnaldo Carvalho de Melo 	else if (use_tui)
4528b9e74ebSArnaldo Carvalho de Melo 		use_browser = 1;
4538b9e74ebSArnaldo Carvalho de Melo 
45446e3e055SArnaldo Carvalho de Melo 	setup_browser();
45546e3e055SArnaldo Carvalho de Melo 
45675be6cf4SArnaldo Carvalho de Melo 	symbol_conf.priv_size = sizeof(struct sym_priv);
45775be6cf4SArnaldo Carvalho de Melo 	symbol_conf.try_vmlinux_path = true;
45875be6cf4SArnaldo Carvalho de Melo 
45975be6cf4SArnaldo Carvalho de Melo 	if (symbol__init() < 0)
460b32d133aSArnaldo Carvalho de Melo 		return -1;
46186470930SIngo Molnar 
462c8829c7aSArnaldo Carvalho de Melo 	setup_sorting(annotate_usage, options);
46386470930SIngo Molnar 
46486470930SIngo Molnar 	if (argc) {
46586470930SIngo Molnar 		/*
46686470930SIngo Molnar 		 * Special case: if there's an argument left then assume tha
46786470930SIngo Molnar 		 * it's a symbol filter:
46886470930SIngo Molnar 		 */
46986470930SIngo Molnar 		if (argc > 1)
47086470930SIngo Molnar 			usage_with_options(annotate_usage, options);
47186470930SIngo Molnar 
47286470930SIngo Molnar 		sym_hist_filter = argv[0];
47386470930SIngo Molnar 	}
47486470930SIngo Molnar 
475dd68ada2SJohn Kacur 	if (field_sep && *field_sep == '.') {
47629a9f66dSArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
47729a9f66dSArnaldo Carvalho de Melo 		return -1;
478dd68ada2SJohn Kacur 	}
479dd68ada2SJohn Kacur 
48086470930SIngo Molnar 	return __cmd_annotate();
48186470930SIngo Molnar }
482