xref: /openbmc/linux/tools/perf/builtin-annotate.c (revision 57594454)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
286470930SIngo Molnar /*
386470930SIngo Molnar  * builtin-annotate.c
486470930SIngo Molnar  *
586470930SIngo Molnar  * Builtin annotate command: Analyze the perf.data input file,
686470930SIngo Molnar  * look up and read DSOs and symbol information and display
786470930SIngo Molnar  * a histogram of results, along various sorting keys.
886470930SIngo Molnar  */
986470930SIngo Molnar #include "builtin.h"
1086470930SIngo Molnar 
1186470930SIngo Molnar #include "util/color.h"
125da50258SArnaldo Carvalho de Melo #include <linux/list.h>
1386470930SIngo Molnar #include "util/cache.h"
1443cbcd8aSArnaldo Carvalho de Melo #include <linux/rbtree.h>
157f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
1686470930SIngo Molnar #include "util/symbol.h"
1786470930SIngo Molnar 
1886470930SIngo Molnar #include "perf.h"
198f28827aSFrederic Weisbecker #include "util/debug.h"
2086470930SIngo Molnar 
21e248de33SArnaldo Carvalho de Melo #include "util/evlist.h"
22e248de33SArnaldo Carvalho de Melo #include "util/evsel.h"
2378f7defeSArnaldo Carvalho de Melo #include "util/annotate.h"
2462daacb5SArnaldo Carvalho de Melo #include "util/event.h"
254b6ab94eSJosh Poimboeuf #include <subcmd/parse-options.h>
2686470930SIngo Molnar #include "util/parse-events.h"
27dd68ada2SJohn Kacur #include "util/sort.h"
283d1d07ecSJohn Kacur #include "util/hist.h"
294a3cec84SArnaldo Carvalho de Melo #include "util/dso.h"
303f79132aSArnaldo Carvalho de Melo #include "util/machine.h"
311101f69aSArnaldo Carvalho de Melo #include "util/map.h"
3294c744b6SArnaldo Carvalho de Melo #include "util/session.h"
3345694aa7SArnaldo Carvalho de Melo #include "util/tool.h"
34f5fc1412SJiri Olsa #include "util/data.h"
3568e94f4eSIrina Tirdea #include "arch/common.h"
3670fbe057SPeter Zijlstra #include "util/block-range.h"
37d3300a3cSArnaldo Carvalho de Melo #include "util/map_symbol.h"
38d3300a3cSArnaldo Carvalho de Melo #include "util/branch.h"
3986470930SIngo Molnar 
40fc67297bSNamhyung Kim #include <dlfcn.h>
41a43783aeSArnaldo Carvalho de Melo #include <errno.h>
425d67be97SAnton Blanchard #include <linux/bitmap.h>
436ef81c55SMamatha Inamdar #include <linux/err.h>
445d67be97SAnton Blanchard 
45d20deb64SArnaldo Carvalho de Melo struct perf_annotate {
4645694aa7SArnaldo Carvalho de Melo 	struct perf_tool tool;
47fa10f316SNamhyung Kim 	struct perf_session *session;
48982d410bSArnaldo Carvalho de Melo 	struct annotation_options opts;
493402ae0aSIan Rogers #ifdef HAVE_SLANG_SUPPORT
503402ae0aSIan Rogers 	bool	   use_tui;
513402ae0aSIan Rogers #endif
523402ae0aSIan Rogers 	bool	   use_stdio, use_stdio2;
53557cc18eSIan Rogers #ifdef HAVE_GTK2_SUPPORT
543402ae0aSIan Rogers 	bool	   use_gtk;
55557cc18eSIan Rogers #endif
5618c9e5c5SNamhyung Kim 	bool	   skip_missing;
57bb848c14SJin Yao 	bool	   has_br_stack;
587ebaf489SJin Yao 	bool	   group_set;
59cad10ce3SNamhyung Kim 	float	   min_percent;
607009cc34SArnaldo Carvalho de Melo 	const char *sym_hist_filter;
617009cc34SArnaldo Carvalho de Melo 	const char *cpu_list;
627009cc34SArnaldo Carvalho de Melo 	DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
63d20deb64SArnaldo Carvalho de Melo };
645d67be97SAnton Blanchard 
6570fbe057SPeter Zijlstra /*
6670fbe057SPeter Zijlstra  * Given one basic block:
6770fbe057SPeter Zijlstra  *
6870fbe057SPeter Zijlstra  *	from	to		branch_i
6970fbe057SPeter Zijlstra  *	* ----> *
7070fbe057SPeter Zijlstra  *		|
7170fbe057SPeter Zijlstra  *		| block
7270fbe057SPeter Zijlstra  *		v
7370fbe057SPeter Zijlstra  *		* ----> *
7470fbe057SPeter Zijlstra  *		from	to	branch_i+1
7570fbe057SPeter Zijlstra  *
7670fbe057SPeter Zijlstra  * where the horizontal are the branches and the vertical is the executed
7770fbe057SPeter Zijlstra  * block of instructions.
7870fbe057SPeter Zijlstra  *
7970fbe057SPeter Zijlstra  * We count, for each 'instruction', the number of blocks that covered it as
8070fbe057SPeter Zijlstra  * well as count the ratio each branch is taken.
8170fbe057SPeter Zijlstra  *
8270fbe057SPeter Zijlstra  * We can do this without knowing the actual instruction stream by keeping
8370fbe057SPeter Zijlstra  * track of the address ranges. We break down ranges such that there is no
8470fbe057SPeter Zijlstra  * overlap and iterate from the start until the end.
8570fbe057SPeter Zijlstra  *
8670fbe057SPeter Zijlstra  * @acme: once we parse the objdump output _before_ processing the samples,
8770fbe057SPeter Zijlstra  * we can easily fold the branch.cycles IPC bits in.
8870fbe057SPeter Zijlstra  */
8970fbe057SPeter Zijlstra static void process_basic_block(struct addr_map_symbol *start,
9070fbe057SPeter Zijlstra 				struct addr_map_symbol *end,
9170fbe057SPeter Zijlstra 				struct branch_flags *flags)
9270fbe057SPeter Zijlstra {
93d46a4cdfSArnaldo Carvalho de Melo 	struct symbol *sym = start->ms.sym;
9470fbe057SPeter Zijlstra 	struct annotation *notes = sym ? symbol__annotation(sym) : NULL;
9570fbe057SPeter Zijlstra 	struct block_range_iter iter;
9670fbe057SPeter Zijlstra 	struct block_range *entry;
9770fbe057SPeter Zijlstra 
9870fbe057SPeter Zijlstra 	/*
9970fbe057SPeter Zijlstra 	 * Sanity; NULL isn't executable and the CPU cannot execute backwards
10070fbe057SPeter Zijlstra 	 */
10170fbe057SPeter Zijlstra 	if (!start->addr || start->addr > end->addr)
10270fbe057SPeter Zijlstra 		return;
10370fbe057SPeter Zijlstra 
10470fbe057SPeter Zijlstra 	iter = block_range__create(start->addr, end->addr);
10570fbe057SPeter Zijlstra 	if (!block_range_iter__valid(&iter))
10670fbe057SPeter Zijlstra 		return;
10770fbe057SPeter Zijlstra 
10870fbe057SPeter Zijlstra 	/*
10970fbe057SPeter Zijlstra 	 * First block in range is a branch target.
11070fbe057SPeter Zijlstra 	 */
11170fbe057SPeter Zijlstra 	entry = block_range_iter(&iter);
11270fbe057SPeter Zijlstra 	assert(entry->is_target);
11370fbe057SPeter Zijlstra 	entry->entry++;
11470fbe057SPeter Zijlstra 
11570fbe057SPeter Zijlstra 	do {
11670fbe057SPeter Zijlstra 		entry = block_range_iter(&iter);
11770fbe057SPeter Zijlstra 
11870fbe057SPeter Zijlstra 		entry->coverage++;
11970fbe057SPeter Zijlstra 		entry->sym = sym;
12070fbe057SPeter Zijlstra 
12170fbe057SPeter Zijlstra 		if (notes)
12270fbe057SPeter Zijlstra 			notes->max_coverage = max(notes->max_coverage, entry->coverage);
12370fbe057SPeter Zijlstra 
12470fbe057SPeter Zijlstra 	} while (block_range_iter__next(&iter));
12570fbe057SPeter Zijlstra 
12670fbe057SPeter Zijlstra 	/*
12770fbe057SPeter Zijlstra 	 * Last block in rage is a branch.
12870fbe057SPeter Zijlstra 	 */
12970fbe057SPeter Zijlstra 	entry = block_range_iter(&iter);
13070fbe057SPeter Zijlstra 	assert(entry->is_branch);
13170fbe057SPeter Zijlstra 	entry->taken++;
13270fbe057SPeter Zijlstra 	if (flags->predicted)
13370fbe057SPeter Zijlstra 		entry->pred++;
13470fbe057SPeter Zijlstra }
13570fbe057SPeter Zijlstra 
13670fbe057SPeter Zijlstra static void process_branch_stack(struct branch_stack *bs, struct addr_location *al,
13770fbe057SPeter Zijlstra 				 struct perf_sample *sample)
13870fbe057SPeter Zijlstra {
13970fbe057SPeter Zijlstra 	struct addr_map_symbol *prev = NULL;
14070fbe057SPeter Zijlstra 	struct branch_info *bi;
14170fbe057SPeter Zijlstra 	int i;
14270fbe057SPeter Zijlstra 
14370fbe057SPeter Zijlstra 	if (!bs || !bs->nr)
14470fbe057SPeter Zijlstra 		return;
14570fbe057SPeter Zijlstra 
14670fbe057SPeter Zijlstra 	bi = sample__resolve_bstack(sample, al);
14770fbe057SPeter Zijlstra 	if (!bi)
14870fbe057SPeter Zijlstra 		return;
14970fbe057SPeter Zijlstra 
15070fbe057SPeter Zijlstra 	for (i = bs->nr - 1; i >= 0; i--) {
15170fbe057SPeter Zijlstra 		/*
15270fbe057SPeter Zijlstra 		 * XXX filter against symbol
15370fbe057SPeter Zijlstra 		 */
15470fbe057SPeter Zijlstra 		if (prev)
15570fbe057SPeter Zijlstra 			process_basic_block(prev, &bi[i].from, &bi[i].flags);
15670fbe057SPeter Zijlstra 		prev = &bi[i].to;
15770fbe057SPeter Zijlstra 	}
15870fbe057SPeter Zijlstra 
15970fbe057SPeter Zijlstra 	free(bi);
16070fbe057SPeter Zijlstra }
16170fbe057SPeter Zijlstra 
162bb848c14SJin Yao static int hist_iter__branch_callback(struct hist_entry_iter *iter,
163bb848c14SJin Yao 				      struct addr_location *al __maybe_unused,
164bb848c14SJin Yao 				      bool single __maybe_unused,
165bb848c14SJin Yao 				      void *arg __maybe_unused)
166bb848c14SJin Yao {
167bb848c14SJin Yao 	struct hist_entry *he = iter->he;
168bb848c14SJin Yao 	struct branch_info *bi;
169bb848c14SJin Yao 	struct perf_sample *sample = iter->sample;
17032dcd021SJiri Olsa 	struct evsel *evsel = iter->evsel;
171bb848c14SJin Yao 	int err;
172bb848c14SJin Yao 
173bb848c14SJin Yao 	bi = he->branch_info;
174e345f3bdSArnaldo Carvalho de Melo 	err = addr_map_symbol__inc_samples(&bi->from, sample, evsel);
175bb848c14SJin Yao 
176bb848c14SJin Yao 	if (err)
177bb848c14SJin Yao 		goto out;
178bb848c14SJin Yao 
179e345f3bdSArnaldo Carvalho de Melo 	err = addr_map_symbol__inc_samples(&bi->to, sample, evsel);
180bb848c14SJin Yao 
181bb848c14SJin Yao out:
182bb848c14SJin Yao 	return err;
183bb848c14SJin Yao }
184bb848c14SJin Yao 
18532dcd021SJiri Olsa static int process_branch_callback(struct evsel *evsel,
186bb848c14SJin Yao 				   struct perf_sample *sample,
187bb848c14SJin Yao 				   struct addr_location *al __maybe_unused,
188bb848c14SJin Yao 				   struct perf_annotate *ann,
189bb848c14SJin Yao 				   struct machine *machine)
190bb848c14SJin Yao {
191bb848c14SJin Yao 	struct hist_entry_iter iter = {
192bb848c14SJin Yao 		.evsel		= evsel,
193bb848c14SJin Yao 		.sample		= sample,
194bb848c14SJin Yao 		.add_entry_cb	= hist_iter__branch_callback,
195bb848c14SJin Yao 		.hide_unresolved	= symbol_conf.hide_unresolved,
196bb848c14SJin Yao 		.ops		= &hist_iter_branch,
197bb848c14SJin Yao 	};
198bb848c14SJin Yao 
199bb848c14SJin Yao 	struct addr_location a;
200bb848c14SJin Yao 
201bb848c14SJin Yao 	if (machine__resolve(machine, &a, sample) < 0)
202bb848c14SJin Yao 		return -1;
203bb848c14SJin Yao 
204bb848c14SJin Yao 	if (a.sym == NULL)
205bb848c14SJin Yao 		return 0;
206bb848c14SJin Yao 
207bb848c14SJin Yao 	if (a.map != NULL)
208bb848c14SJin Yao 		a.map->dso->hit = 1;
209bb848c14SJin Yao 
2107841f40aSJin Yao 	hist__account_cycles(sample->branch_stack, al, sample, false, NULL);
211bdd1666bSJin Yao 
21269c31f96Stangmeng 	return hist_entry_iter__add(&iter, &a, PERF_MAX_STACK_DEPTH, ann);
213bb848c14SJin Yao }
214bb848c14SJin Yao 
215befd2a38SArnaldo Carvalho de Melo static bool has_annotation(struct perf_annotate *ann)
216befd2a38SArnaldo Carvalho de Melo {
217befd2a38SArnaldo Carvalho de Melo 	return ui__has_annotation() || ann->use_stdio2;
218befd2a38SArnaldo Carvalho de Melo }
219befd2a38SArnaldo Carvalho de Melo 
22074aa90e8SArnaldo Carvalho de Melo static int evsel__add_sample(struct evsel *evsel, struct perf_sample *sample,
22174aa90e8SArnaldo Carvalho de Melo 			     struct addr_location *al, struct perf_annotate *ann,
222bb848c14SJin Yao 			     struct machine *machine)
22386470930SIngo Molnar {
2244ea062edSArnaldo Carvalho de Melo 	struct hists *hists = evsel__hists(evsel);
225628ada0cSArnaldo Carvalho de Melo 	struct hist_entry *he;
226e248de33SArnaldo Carvalho de Melo 	int ret;
227628ada0cSArnaldo Carvalho de Melo 
228befd2a38SArnaldo Carvalho de Melo 	if ((!ann->has_br_stack || !has_annotation(ann)) &&
229bb848c14SJin Yao 	    ann->sym_hist_filter != NULL &&
2307009cc34SArnaldo Carvalho de Melo 	    (al->sym == NULL ||
2317009cc34SArnaldo Carvalho de Melo 	     strcmp(ann->sym_hist_filter, al->sym->name) != 0)) {
232628ada0cSArnaldo Carvalho de Melo 		/* We're only interested in a symbol named sym_hist_filter */
233facf3f06SArnaldo Carvalho de Melo 		/*
234facf3f06SArnaldo Carvalho de Melo 		 * FIXME: why isn't this done in the symbol_filter when loading
235facf3f06SArnaldo Carvalho de Melo 		 * the DSO?
236facf3f06SArnaldo Carvalho de Melo 		 */
237628ada0cSArnaldo Carvalho de Melo 		if (al->sym != NULL) {
2387137ff50SDavidlohr Bueso 			rb_erase_cached(&al->sym->rb_node,
2393183f8caSArnaldo Carvalho de Melo 				 &al->map->dso->symbols);
240628ada0cSArnaldo Carvalho de Melo 			symbol__delete(al->sym);
241c0b4dffbSArnaldo Carvalho de Melo 			dso__reset_find_symbol_cache(al->map->dso);
242628ada0cSArnaldo Carvalho de Melo 		}
243628ada0cSArnaldo Carvalho de Melo 		return 0;
244628ada0cSArnaldo Carvalho de Melo 	}
245628ada0cSArnaldo Carvalho de Melo 
24670fbe057SPeter Zijlstra 	/*
2474d39c89fSIngo Molnar 	 * XXX filtered samples can still have branch entries pointing into our
24870fbe057SPeter Zijlstra 	 * symbol and are missed.
24970fbe057SPeter Zijlstra 	 */
25070fbe057SPeter Zijlstra 	process_branch_stack(sample->branch_stack, al, sample);
25170fbe057SPeter Zijlstra 
252befd2a38SArnaldo Carvalho de Melo 	if (ann->has_br_stack && has_annotation(ann))
253bb848c14SJin Yao 		return process_branch_callback(evsel, sample, al, ann, machine);
254bb848c14SJin Yao 
255ebf39d29SLeo Yan 	he = hists__add_entry(hists, al, NULL, NULL, NULL, NULL, sample, true);
2569735abf1SArnaldo Carvalho de Melo 	if (he == NULL)
25786470930SIngo Molnar 		return -ENOMEM;
258628ada0cSArnaldo Carvalho de Melo 
259e345f3bdSArnaldo Carvalho de Melo 	ret = hist_entry__inc_addr_samples(he, sample, evsel, al->addr);
2604ea062edSArnaldo Carvalho de Melo 	hists__inc_nr_samples(hists, true);
261e248de33SArnaldo Carvalho de Melo 	return ret;
26286470930SIngo Molnar }
26386470930SIngo Molnar 
26445694aa7SArnaldo Carvalho de Melo static int process_sample_event(struct perf_tool *tool,
265d20deb64SArnaldo Carvalho de Melo 				union perf_event *event,
2668115d60cSArnaldo Carvalho de Melo 				struct perf_sample *sample,
26732dcd021SJiri Olsa 				struct evsel *evsel,
268743eb868SArnaldo Carvalho de Melo 				struct machine *machine)
26986470930SIngo Molnar {
27045694aa7SArnaldo Carvalho de Melo 	struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool);
2711ed091c4SArnaldo Carvalho de Melo 	struct addr_location al;
272b91fc39fSArnaldo Carvalho de Melo 	int ret = 0;
2736baa0a5aSFrederic Weisbecker 
274bb3eb566SArnaldo Carvalho de Melo 	if (machine__resolve(machine, &al, sample) < 0) {
27529a9f66dSArnaldo Carvalho de Melo 		pr_warning("problem processing %d event, skipping it.\n",
27686470930SIngo Molnar 			   event->header.type);
27786470930SIngo Molnar 		return -1;
27886470930SIngo Molnar 	}
27986470930SIngo Molnar 
2807009cc34SArnaldo Carvalho de Melo 	if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap))
281b91fc39fSArnaldo Carvalho de Melo 		goto out_put;
2825d67be97SAnton Blanchard 
283bb848c14SJin Yao 	if (!al.filtered &&
28474aa90e8SArnaldo Carvalho de Melo 	    evsel__add_sample(evsel, sample, &al, ann, machine)) {
28529a9f66dSArnaldo Carvalho de Melo 		pr_warning("problem incrementing symbol count, "
286ec218fc4SArnaldo Carvalho de Melo 			   "skipping event\n");
287b91fc39fSArnaldo Carvalho de Melo 		ret = -1;
28886470930SIngo Molnar 	}
289b91fc39fSArnaldo Carvalho de Melo out_put:
290b91fc39fSArnaldo Carvalho de Melo 	addr_location__put(&al);
291b91fc39fSArnaldo Carvalho de Melo 	return ret;
29286470930SIngo Molnar }
29386470930SIngo Molnar 
29489f1688aSJiri Olsa static int process_feature_event(struct perf_session *session,
29589f1688aSJiri Olsa 				 union perf_event *event)
29692ead7eeSRavi Bangoria {
29792ead7eeSRavi Bangoria 	if (event->feat.feat_id < HEADER_LAST_FEATURE)
29889f1688aSJiri Olsa 		return perf_event__process_feature(session, event);
29992ead7eeSRavi Bangoria 	return 0;
30092ead7eeSRavi Bangoria }
30192ead7eeSRavi Bangoria 
302db8fd07aSNamhyung Kim static int hist_entry__tty_annotate(struct hist_entry *he,
30332dcd021SJiri Olsa 				    struct evsel *evsel,
304d20deb64SArnaldo Carvalho de Melo 				    struct perf_annotate *ann)
30586470930SIngo Molnar {
306befd2a38SArnaldo Carvalho de Melo 	if (!ann->use_stdio2)
30729754894SArnaldo Carvalho de Melo 		return symbol__tty_annotate(&he->ms, evsel, &ann->opts);
308982d410bSArnaldo Carvalho de Melo 
30929754894SArnaldo Carvalho de Melo 	return symbol__tty_annotate2(&he->ms, evsel, &ann->opts);
31086470930SIngo Molnar }
31186470930SIngo Molnar 
312c824c433SArnaldo Carvalho de Melo static void hists__find_annotations(struct hists *hists,
31332dcd021SJiri Olsa 				    struct evsel *evsel,
314d20deb64SArnaldo Carvalho de Melo 				    struct perf_annotate *ann)
31586470930SIngo Molnar {
3162eb3d689SDavidlohr Bueso 	struct rb_node *nd = rb_first_cached(&hists->entries), *next;
317cf958003SArnaldo Carvalho de Melo 	int key = K_RIGHT;
31886470930SIngo Molnar 
31946e3e055SArnaldo Carvalho de Melo 	while (nd) {
320ed52ce2eSArnaldo Carvalho de Melo 		struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
32178f7defeSArnaldo Carvalho de Melo 		struct annotation *notes;
32286470930SIngo Molnar 
32346e3e055SArnaldo Carvalho de Melo 		if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned)
32446e3e055SArnaldo Carvalho de Melo 			goto find_next;
325e4204992SArnaldo Carvalho de Melo 
326bb848c14SJin Yao 		if (ann->sym_hist_filter &&
327bb848c14SJin Yao 		    (strcmp(he->ms.sym->name, ann->sym_hist_filter) != 0))
328bb848c14SJin Yao 			goto find_next;
329bb848c14SJin Yao 
330cad10ce3SNamhyung Kim 		if (ann->min_percent) {
331cad10ce3SNamhyung Kim 			float percent = 0;
332cad10ce3SNamhyung Kim 			u64 total = hists__total_period(hists);
333cad10ce3SNamhyung Kim 
334cad10ce3SNamhyung Kim 			if (total)
335cad10ce3SNamhyung Kim 				percent = 100.0 * he->stat.period / total;
336cad10ce3SNamhyung Kim 
337cad10ce3SNamhyung Kim 			if (percent < ann->min_percent)
338cad10ce3SNamhyung Kim 				goto find_next;
339cad10ce3SNamhyung Kim 		}
340cad10ce3SNamhyung Kim 
34178f7defeSArnaldo Carvalho de Melo 		notes = symbol__annotation(he->ms.sym);
342ce6f4fabSArnaldo Carvalho de Melo 		if (notes->src == NULL) {
34346e3e055SArnaldo Carvalho de Melo find_next:
344cf958003SArnaldo Carvalho de Melo 			if (key == K_LEFT)
34546e3e055SArnaldo Carvalho de Melo 				nd = rb_prev(nd);
34646e3e055SArnaldo Carvalho de Melo 			else
34746e3e055SArnaldo Carvalho de Melo 				nd = rb_next(nd);
348e4204992SArnaldo Carvalho de Melo 			continue;
34946e3e055SArnaldo Carvalho de Melo 		}
350e4204992SArnaldo Carvalho de Melo 
3512b676bf0SNamhyung Kim 		if (use_browser == 2) {
35218c9e5c5SNamhyung Kim 			int ret;
353fc67297bSNamhyung Kim 			int (*annotate)(struct hist_entry *he,
35432dcd021SJiri Olsa 					struct evsel *evsel,
355217b7d41SIan Rogers 					struct annotation_options *options,
356fc67297bSNamhyung Kim 					struct hist_browser_timer *hbt);
35718c9e5c5SNamhyung Kim 
358fc67297bSNamhyung Kim 			annotate = dlsym(perf_gtk_handle,
359fc67297bSNamhyung Kim 					 "hist_entry__gtk_annotate");
360fc67297bSNamhyung Kim 			if (annotate == NULL) {
361fc67297bSNamhyung Kim 				ui__error("GTK browser not found!\n");
362fc67297bSNamhyung Kim 				return;
363fc67297bSNamhyung Kim 			}
364fc67297bSNamhyung Kim 
365217b7d41SIan Rogers 			ret = annotate(he, evsel, &ann->opts, NULL);
36618c9e5c5SNamhyung Kim 			if (!ret || !ann->skip_missing)
3672b676bf0SNamhyung Kim 				return;
36818c9e5c5SNamhyung Kim 
36918c9e5c5SNamhyung Kim 			/* skip missing symbols */
37018c9e5c5SNamhyung Kim 			nd = rb_next(nd);
3712b676bf0SNamhyung Kim 		} else if (use_browser == 1) {
372cd0cccbaSArnaldo Carvalho de Melo 			key = hist_entry__tui_annotate(he, evsel, NULL, &ann->opts);
373bb848c14SJin Yao 
37446e3e055SArnaldo Carvalho de Melo 			switch (key) {
37518c9e5c5SNamhyung Kim 			case -1:
37618c9e5c5SNamhyung Kim 				if (!ann->skip_missing)
37718c9e5c5SNamhyung Kim 					return;
37818c9e5c5SNamhyung Kim 				/* fall through */
379cf958003SArnaldo Carvalho de Melo 			case K_RIGHT:
380b50e003dSArnaldo Carvalho de Melo 				next = rb_next(nd);
38146e3e055SArnaldo Carvalho de Melo 				break;
382cf958003SArnaldo Carvalho de Melo 			case K_LEFT:
383b50e003dSArnaldo Carvalho de Melo 				next = rb_prev(nd);
38446e3e055SArnaldo Carvalho de Melo 				break;
385b50e003dSArnaldo Carvalho de Melo 			default:
386b50e003dSArnaldo Carvalho de Melo 				return;
38746e3e055SArnaldo Carvalho de Melo 			}
388b50e003dSArnaldo Carvalho de Melo 
389b50e003dSArnaldo Carvalho de Melo 			if (next != NULL)
390b50e003dSArnaldo Carvalho de Melo 				nd = next;
39146e3e055SArnaldo Carvalho de Melo 		} else {
392db8fd07aSNamhyung Kim 			hist_entry__tty_annotate(he, evsel, ann);
39346e3e055SArnaldo Carvalho de Melo 			nd = rb_next(nd);
39486470930SIngo Molnar 		}
39586470930SIngo Molnar 	}
39646e3e055SArnaldo Carvalho de Melo }
39786470930SIngo Molnar 
398d20deb64SArnaldo Carvalho de Melo static int __cmd_annotate(struct perf_annotate *ann)
39986470930SIngo Molnar {
400bab81b62SLi Zefan 	int ret;
401fa10f316SNamhyung Kim 	struct perf_session *session = ann->session;
40232dcd021SJiri Olsa 	struct evsel *pos;
403e248de33SArnaldo Carvalho de Melo 	u64 total_nr_samples;
40494c744b6SArnaldo Carvalho de Melo 
4057009cc34SArnaldo Carvalho de Melo 	if (ann->cpu_list) {
4067009cc34SArnaldo Carvalho de Melo 		ret = perf_session__cpu_bitmap(session, ann->cpu_list,
4077009cc34SArnaldo Carvalho de Melo 					       ann->cpu_bitmap);
4085d67be97SAnton Blanchard 		if (ret)
409fa10f316SNamhyung Kim 			goto out;
4105d67be97SAnton Blanchard 	}
4115d67be97SAnton Blanchard 
412f178fd2dSArnaldo Carvalho de Melo 	if (!ann->opts.objdump_path) {
413f178fd2dSArnaldo Carvalho de Melo 		ret = perf_env__lookup_objdump(&session->header.env,
414f178fd2dSArnaldo Carvalho de Melo 					       &ann->opts.objdump_path);
41568e94f4eSIrina Tirdea 		if (ret)
416fa10f316SNamhyung Kim 			goto out;
41768e94f4eSIrina Tirdea 	}
41868e94f4eSIrina Tirdea 
419b7b61cbeSArnaldo Carvalho de Melo 	ret = perf_session__process_events(session);
420bab81b62SLi Zefan 	if (ret)
421fa10f316SNamhyung Kim 		goto out;
42286470930SIngo Molnar 
42362daacb5SArnaldo Carvalho de Melo 	if (dump_trace) {
4242775de0bSNamhyung Kim 		perf_session__fprintf_nr_events(session, stdout, false);
4252775de0bSNamhyung Kim 		evlist__fprintf_nr_events(session->evlist, stdout, false);
426fa10f316SNamhyung Kim 		goto out;
42762daacb5SArnaldo Carvalho de Melo 	}
42886470930SIngo Molnar 
429da21d1b5SArnaldo Carvalho de Melo 	if (verbose > 3)
430b3165f41SArnaldo Carvalho de Melo 		perf_session__fprintf(session, stdout);
43186470930SIngo Molnar 
432da21d1b5SArnaldo Carvalho de Melo 	if (verbose > 2)
433cbf69680SArnaldo Carvalho de Melo 		perf_session__fprintf_dsos(session, stdout);
43486470930SIngo Molnar 
435e248de33SArnaldo Carvalho de Melo 	total_nr_samples = 0;
436e5cadb93SArnaldo Carvalho de Melo 	evlist__for_each_entry(session->evlist, pos) {
4374ea062edSArnaldo Carvalho de Melo 		struct hists *hists = evsel__hists(pos);
4380f0abbacSNamhyung Kim 		u32 nr_samples = hists->stats.nr_samples;
43986470930SIngo Molnar 
440e248de33SArnaldo Carvalho de Melo 		if (nr_samples > 0) {
441e248de33SArnaldo Carvalho de Melo 			total_nr_samples += nr_samples;
442c1fb5651SNamhyung Kim 			hists__collapse_resort(hists, NULL);
443f9db0d0fSKan Liang 			/* Don't sort callchain */
444862b2f8fSArnaldo Carvalho de Melo 			evsel__reset_sample_bit(pos, CALLCHAIN);
44510c513f7SArnaldo Carvalho de Melo 			evsel__output_resort(pos, NULL);
446b1dd4432SNamhyung Kim 
447c754c382SArnaldo Carvalho de Melo 			if (symbol_conf.event_group && !evsel__is_group_leader(pos))
448b1dd4432SNamhyung Kim 				continue;
449b1dd4432SNamhyung Kim 
450db8fd07aSNamhyung Kim 			hists__find_annotations(hists, pos, ann);
451e248de33SArnaldo Carvalho de Melo 		}
452e248de33SArnaldo Carvalho de Melo 	}
453e248de33SArnaldo Carvalho de Melo 
454e248de33SArnaldo Carvalho de Melo 	if (total_nr_samples == 0) {
4552d4f2799SJiri Olsa 		ui__error("The %s data has no samples!\n", session->data->path);
456fa10f316SNamhyung Kim 		goto out;
457e248de33SArnaldo Carvalho de Melo 	}
4587a60ba94SNamhyung Kim 
459fc67297bSNamhyung Kim 	if (use_browser == 2) {
460fc67297bSNamhyung Kim 		void (*show_annotations)(void);
461fc67297bSNamhyung Kim 
462fc67297bSNamhyung Kim 		show_annotations = dlsym(perf_gtk_handle,
463fc67297bSNamhyung Kim 					 "perf_gtk__show_annotations");
464fc67297bSNamhyung Kim 		if (show_annotations == NULL) {
465fc67297bSNamhyung Kim 			ui__error("GTK browser not found!\n");
466fa10f316SNamhyung Kim 			goto out;
467fc67297bSNamhyung Kim 		}
468fc67297bSNamhyung Kim 		show_annotations();
469fc67297bSNamhyung Kim 	}
4707a60ba94SNamhyung Kim 
471fa10f316SNamhyung Kim out:
472bab81b62SLi Zefan 	return ret;
47386470930SIngo Molnar }
47486470930SIngo Molnar 
475cad10ce3SNamhyung Kim static int parse_percent_limit(const struct option *opt, const char *str,
476cad10ce3SNamhyung Kim 			       int unset __maybe_unused)
477cad10ce3SNamhyung Kim {
478cad10ce3SNamhyung Kim 	struct perf_annotate *ann = opt->value;
479cad10ce3SNamhyung Kim 	double pcnt = strtof(str, NULL);
480cad10ce3SNamhyung Kim 
481cad10ce3SNamhyung Kim 	ann->min_percent = pcnt;
482cad10ce3SNamhyung Kim 	return 0;
483cad10ce3SNamhyung Kim }
484cad10ce3SNamhyung Kim 
48586470930SIngo Molnar static const char * const annotate_usage[] = {
48699345254SNamhyung Kim 	"perf annotate [<options>]",
48786470930SIngo Molnar 	NULL
48886470930SIngo Molnar };
48986470930SIngo Molnar 
490b0ad8ea6SArnaldo Carvalho de Melo int cmd_annotate(int argc, const char **argv)
491d20deb64SArnaldo Carvalho de Melo {
492d20deb64SArnaldo Carvalho de Melo 	struct perf_annotate annotate = {
49345694aa7SArnaldo Carvalho de Melo 		.tool = {
494d20deb64SArnaldo Carvalho de Melo 			.sample	= process_sample_event,
495d20deb64SArnaldo Carvalho de Melo 			.mmap	= perf_event__process_mmap,
4965c5e854bSStephane Eranian 			.mmap2	= perf_event__process_mmap2,
497d20deb64SArnaldo Carvalho de Melo 			.comm	= perf_event__process_comm,
498ec4622f5SArnaldo Carvalho de Melo 			.exit	= perf_event__process_exit,
499f62d3f0fSArnaldo Carvalho de Melo 			.fork	= perf_event__process_fork,
500f3b3614aSHari Bathini 			.namespaces = perf_event__process_namespaces,
5016ab11f3aSDavid Carrillo-Cisneros 			.attr	= perf_event__process_attr,
5026ab11f3aSDavid Carrillo-Cisneros 			.build_id = perf_event__process_build_id,
503378ef0f5SIan Rogers #ifdef HAVE_LIBTRACEEVENT
504f4849599SDavid Carrillo-Cisneros 			.tracing_data   = perf_event__process_tracing_data,
505378ef0f5SIan Rogers #endif
5064bcbe438SYang Jihong 			.id_index	= perf_event__process_id_index,
5074bcbe438SYang Jihong 			.auxtrace_info	= perf_event__process_auxtrace_info,
5084bcbe438SYang Jihong 			.auxtrace	= perf_event__process_auxtrace,
50992ead7eeSRavi Bangoria 			.feature	= process_feature_event,
5100a8cb85cSJiri Olsa 			.ordered_events = true,
511d20deb64SArnaldo Carvalho de Melo 			.ordering_requires_timestamps = true,
512d20deb64SArnaldo Carvalho de Melo 		},
513d20deb64SArnaldo Carvalho de Melo 	};
5148ceb41d7SJiri Olsa 	struct perf_data data = {
515fa10f316SNamhyung Kim 		.mode  = PERF_DATA_MODE_READ,
516fa10f316SNamhyung Kim 	};
5174bcbe438SYang Jihong 	struct itrace_synth_opts itrace_synth_opts = {
5184bcbe438SYang Jihong 		.set = 0,
5194bcbe438SYang Jihong 	};
520*57594454SIan Rogers 	const char *disassembler_style = NULL, *objdump_path = NULL, *addr2line_path = NULL;
5211ac39372STaeung Song 	struct option options[] = {
52270cb4e96SFeng Tang 	OPT_STRING('i', "input", &input_name, "file",
52386470930SIngo Molnar 		    "input file name"),
524ac73c5a9SArnaldo Carvalho de Melo 	OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
525ac73c5a9SArnaldo Carvalho de Melo 		   "only consider symbols in these dsos"),
5267009cc34SArnaldo Carvalho de Melo 	OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol",
52786470930SIngo Molnar 		    "symbol to annotate"),
5288ceb41d7SJiri Olsa 	OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"),
529c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
53086470930SIngo Molnar 		    "be more verbose (show symbol address, etc)"),
531a527c2c1SJames Clark 	OPT_BOOLEAN('q', "quiet", &quiet, "do now show any warnings or messages"),
53286470930SIngo Molnar 	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
53386470930SIngo Molnar 		    "dump raw trace in ASCII"),
534557cc18eSIan Rogers #ifdef HAVE_GTK2_SUPPORT
5352b676bf0SNamhyung Kim 	OPT_BOOLEAN(0, "gtk", &annotate.use_gtk, "Use the GTK interface"),
536557cc18eSIan Rogers #endif
5373402ae0aSIan Rogers #ifdef HAVE_SLANG_SUPPORT
5387009cc34SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"),
5393402ae0aSIan Rogers #endif
5407009cc34SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"),
541befd2a38SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "stdio2", &annotate.use_stdio2, "Use the stdio interface"),
542be316409SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "ignore-vmlinux", &symbol_conf.ignore_vmlinux,
543be316409SArnaldo Carvalho de Melo                     "don't load vmlinux even if found"),
544b32d133aSArnaldo Carvalho de Melo 	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
545b32d133aSArnaldo Carvalho de Melo 		   "file", "vmlinux pathname"),
546b32d133aSArnaldo Carvalho de Melo 	OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
54742976487SMike Galbraith 		    "load module symbols - WARNING: use only with -k and LIVE kernel"),
548982d410bSArnaldo Carvalho de Melo 	OPT_BOOLEAN('l', "print-line", &annotate.opts.print_lines,
549301406b9SFrederic Weisbecker 		    "print matching source lines (may be slow)"),
550982d410bSArnaldo Carvalho de Melo 	OPT_BOOLEAN('P', "full-paths", &annotate.opts.full_path,
55142976487SMike Galbraith 		    "Don't shorten the displayed pathnames"),
55218c9e5c5SNamhyung Kim 	OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing,
55318c9e5c5SNamhyung Kim 		    "Skip symbols that cannot be annotated"),
5547ebaf489SJin Yao 	OPT_BOOLEAN_SET(0, "group", &symbol_conf.event_group,
5557ebaf489SJin Yao 			&annotate.group_set,
5567ebaf489SJin Yao 			"Show event group information together"),
557c8e66720SDavid Ahern 	OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"),
558a7066709SHe Kuang 	OPT_CALLBACK(0, "symfs", NULL, "directory",
559a7066709SHe Kuang 		     "Look for files with symbols relative to this directory",
560a7066709SHe Kuang 		     symbol__config_symfs),
5611eddd9e4SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "source", &annotate.opts.annotate_src,
5623e6a2a7fSStephane Eranian 		    "Interleave source code with assembly code (default)"),
5631eddd9e4SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "asm-raw", &annotate.opts.show_asm_raw,
5643e6a2a7fSStephane Eranian 		    "Display raw encoding of assembly instructions (default)"),
56556d9117cSIan Rogers 	OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
566f69b64f7SAndi Kleen 		   "Specify disassembler style (e.g. -M intel for intel syntax)"),
5673b0b16bfSAndi Kleen 	OPT_STRING(0, "prefix", &annotate.opts.prefix, "prefix",
5683b0b16bfSAndi Kleen 		    "Add prefix to source file path names in programs (with --prefix-strip)"),
5693b0b16bfSAndi Kleen 	OPT_STRING(0, "prefix-strip", &annotate.opts.prefix_strip, "N",
5703b0b16bfSAndi Kleen 		    "Strip first N entries of source file path name in programs (with --prefix)"),
57156d9117cSIan Rogers 	OPT_STRING(0, "objdump", &objdump_path, "path",
5727a4ec938SMaciek Borzecki 		   "objdump binary to use for disassembly and annotations"),
573*57594454SIan Rogers 	OPT_STRING(0, "addr2line", &addr2line_path, "path",
574*57594454SIan Rogers 		   "addr2line binary to use for line numbers"),
5753406ac53SMartin Liška 	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
5763406ac53SMartin Liška 		    "Enable symbol demangling"),
5773406ac53SMartin Liška 	OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
5783406ac53SMartin Liška 		    "Enable kernel symbol demangling"),
579b1dd4432SNamhyung Kim 	OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
580b1dd4432SNamhyung Kim 		    "Show event group information together"),
5810c4a5bceSMartin Liška 	OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
5820c4a5bceSMartin Liška 		    "Show a column with the sum of periods"),
5831ac39372STaeung Song 	OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
5841ac39372STaeung Song 		    "Show a column with the number of samples"),
58553fe4ba1SArnaldo Carvalho de Melo 	OPT_CALLBACK_DEFAULT(0, "stdio-color", NULL, "mode",
58653fe4ba1SArnaldo Carvalho de Melo 			     "'always' (default), 'never' or 'auto' only applicable to --stdio mode",
58753fe4ba1SArnaldo Carvalho de Melo 			     stdio__config_color, "always"),
58888c21190SJiri Olsa 	OPT_CALLBACK(0, "percent-type", &annotate.opts, "local-period",
58988c21190SJiri Olsa 		     "Set percent type local/global-period/hits",
59088c21190SJiri Olsa 		     annotate_parse_percent_type),
591cad10ce3SNamhyung Kim 	OPT_CALLBACK(0, "percent-limit", &annotate, "percent",
592cad10ce3SNamhyung Kim 		     "Don't show entries under that percent", parse_percent_limit),
5934bcbe438SYang Jihong 	OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",
5944bcbe438SYang Jihong 			    "Instruction Tracing options\n" ITRACE_HELP,
5954bcbe438SYang Jihong 			    itrace_parse_synth_opts),
59688c21190SJiri Olsa 
59786470930SIngo Molnar 	OPT_END()
59886470930SIngo Molnar 	};
5991ac39372STaeung Song 	int ret;
600a635fc51SArnaldo Carvalho de Melo 
6011ac39372STaeung Song 	set_option_flag(options, 0, "show-total-period", PARSE_OPT_EXCLUSIVE);
6021ac39372STaeung Song 	set_option_flag(options, 0, "show-nr-samples", PARSE_OPT_EXCLUSIVE);
6031ac39372STaeung Song 
604217b7d41SIan Rogers 	annotation_options__init(&annotate.opts);
6051ac39372STaeung Song 
6061ac39372STaeung Song 	ret = hists__init();
607a635fc51SArnaldo Carvalho de Melo 	if (ret < 0)
608a635fc51SArnaldo Carvalho de Melo 		return ret;
60986470930SIngo Molnar 
610812b0f52SRavi Bangoria 	annotation_config__init(&annotate.opts);
611812b0f52SRavi Bangoria 
612655000e7SArnaldo Carvalho de Melo 	argc = parse_options(argc, argv, options, annotate_usage, 0);
61350e19ef9SNamhyung Kim 	if (argc) {
61450e19ef9SNamhyung Kim 		/*
61550e19ef9SNamhyung Kim 		 * Special case: if there's an argument left then assume that
61650e19ef9SNamhyung Kim 		 * it's a symbol filter:
61750e19ef9SNamhyung Kim 		 */
61850e19ef9SNamhyung Kim 		if (argc > 1)
61950e19ef9SNamhyung Kim 			usage_with_options(annotate_usage, options);
62050e19ef9SNamhyung Kim 
62150e19ef9SNamhyung Kim 		annotate.sym_hist_filter = argv[0];
62250e19ef9SNamhyung Kim 	}
623655000e7SArnaldo Carvalho de Melo 
62456d9117cSIan Rogers 	if (disassembler_style) {
62556d9117cSIan Rogers 		annotate.opts.disassembler_style = strdup(disassembler_style);
62656d9117cSIan Rogers 		if (!annotate.opts.disassembler_style)
62756d9117cSIan Rogers 			return -ENOMEM;
62856d9117cSIan Rogers 	}
62956d9117cSIan Rogers 	if (objdump_path) {
63056d9117cSIan Rogers 		annotate.opts.objdump_path = strdup(objdump_path);
63156d9117cSIan Rogers 		if (!annotate.opts.objdump_path)
63256d9117cSIan Rogers 			return -ENOMEM;
63356d9117cSIan Rogers 	}
634*57594454SIan Rogers 	if (addr2line_path) {
635*57594454SIan Rogers 		symbol_conf.addr2line_path = strdup(addr2line_path);
636*57594454SIan Rogers 		if (!symbol_conf.addr2line_path)
637*57594454SIan Rogers 			return -ENOMEM;
638*57594454SIan Rogers 	}
63956d9117cSIan Rogers 
6403b0b16bfSAndi Kleen 	if (annotate_check_args(&annotate.opts) < 0)
6413b0b16bfSAndi Kleen 		return -EINVAL;
6423b0b16bfSAndi Kleen 
643557cc18eSIan Rogers #ifdef HAVE_GTK2_SUPPORT
6449cef4b0bSTaeung Song 	if (symbol_conf.show_nr_samples && annotate.use_gtk) {
6459cef4b0bSTaeung Song 		pr_err("--show-nr-samples is not available in --gtk mode at this time\n");
6461ac39372STaeung Song 		return ret;
6471ac39372STaeung Song 	}
648557cc18eSIan Rogers #endif
6491ac39372STaeung Song 
6507cc72553SJames Clark 	ret = symbol__validate_sym_arguments();
6517cc72553SJames Clark 	if (ret)
6527cc72553SJames Clark 		return ret;
6537cc72553SJames Clark 
654eddaef88SNamhyung Kim 	if (quiet)
655eddaef88SNamhyung Kim 		perf_quiet_option();
656eddaef88SNamhyung Kim 
6572d4f2799SJiri Olsa 	data.path = input_name;
65844848cdbSMartin Liška 
6592681bd85SNamhyung Kim 	annotate.session = perf_session__new(&data, &annotate.tool);
6606ef81c55SMamatha Inamdar 	if (IS_ERR(annotate.session))
6616ef81c55SMamatha Inamdar 		return PTR_ERR(annotate.session);
662fa10f316SNamhyung Kim 
6634bcbe438SYang Jihong 	annotate.session->itrace_synth_opts = &itrace_synth_opts;
6644bcbe438SYang Jihong 
665bb848c14SJin Yao 	annotate.has_br_stack = perf_header__has_feat(&annotate.session->header,
666bb848c14SJin Yao 						      HEADER_BRANCH_STACK);
667bb848c14SJin Yao 
6687ebaf489SJin Yao 	if (annotate.group_set)
66964b4778bSArnaldo Carvalho de Melo 		evlist__force_leader(annotate.session->evlist);
6707ebaf489SJin Yao 
671b01141f4SArnaldo Carvalho de Melo 	ret = symbol__annotation_init();
672b01141f4SArnaldo Carvalho de Melo 	if (ret < 0)
673b01141f4SArnaldo Carvalho de Melo 		goto out_delete;
674b01141f4SArnaldo Carvalho de Melo 
67575be6cf4SArnaldo Carvalho de Melo 	symbol_conf.try_vmlinux_path = true;
67675be6cf4SArnaldo Carvalho de Melo 
6770a7e6d1bSNamhyung Kim 	ret = symbol__init(&annotate.session->header.env);
678fa10f316SNamhyung Kim 	if (ret < 0)
679fa10f316SNamhyung Kim 		goto out_delete;
68086470930SIngo Molnar 
681befd2a38SArnaldo Carvalho de Melo 	if (annotate.use_stdio || annotate.use_stdio2)
6823df668e7SNamhyung Kim 		use_browser = 0;
6833402ae0aSIan Rogers #ifdef HAVE_SLANG_SUPPORT
6843df668e7SNamhyung Kim 	else if (annotate.use_tui)
6853df668e7SNamhyung Kim 		use_browser = 1;
6863402ae0aSIan Rogers #endif
687557cc18eSIan Rogers #ifdef HAVE_GTK2_SUPPORT
6883df668e7SNamhyung Kim 	else if (annotate.use_gtk)
6893df668e7SNamhyung Kim 		use_browser = 2;
690557cc18eSIan Rogers #endif
6913df668e7SNamhyung Kim 
6923df668e7SNamhyung Kim 	setup_browser(true);
6933df668e7SNamhyung Kim 
6945676dba7SYang Jihong 	/*
6955676dba7SYang Jihong 	 * Events of different processes may correspond to the same
6965676dba7SYang Jihong 	 * symbol, we do not care about the processes in annotate,
6975676dba7SYang Jihong 	 * set sort order to avoid repeated output.
6985676dba7SYang Jihong 	 */
6995676dba7SYang Jihong 	sort_order = "dso,symbol";
7005676dba7SYang Jihong 
7015676dba7SYang Jihong 	/*
7025676dba7SYang Jihong 	 * Set SORT_MODE__BRANCH so that annotate display IPC/Cycle
7035676dba7SYang Jihong 	 * if branch info is in perf data in TUI mode.
7045676dba7SYang Jihong 	 */
7055676dba7SYang Jihong 	if ((use_browser == 1 || annotate.use_stdio2) && annotate.has_br_stack)
706bb848c14SJin Yao 		sort__mode = SORT_MODE__BRANCH;
7075676dba7SYang Jihong 
708bb848c14SJin Yao 	if (setup_sorting(NULL) < 0)
709bb848c14SJin Yao 		usage_with_options(annotate_usage, options);
710bb848c14SJin Yao 
711fa10f316SNamhyung Kim 	ret = __cmd_annotate(&annotate);
712fa10f316SNamhyung Kim 
713fa10f316SNamhyung Kim out_delete:
714fa10f316SNamhyung Kim 	/*
715333b1b11SIan Rogers 	 * Speed up the exit process by only deleting for debug builds. For
716333b1b11SIan Rogers 	 * large files this can save time.
717fa10f316SNamhyung Kim 	 */
718333b1b11SIan Rogers #ifndef NDEBUG
719333b1b11SIan Rogers 	perf_session__delete(annotate.session);
720333b1b11SIan Rogers #endif
721217b7d41SIan Rogers 	annotation_options__exit(&annotate.opts);
722333b1b11SIan Rogers 
723fa10f316SNamhyung Kim 	return ret;
72486470930SIngo Molnar }
725