1// SPDX-License-Identifier: GPL-2.0
2#include <dirent.h>
3#include <errno.h>
4#include <inttypes.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <linux/rbtree.h>
9#include <linux/string.h>
10#include <sys/ttydefaults.h>
11#include <linux/time64.h>
12#include <linux/zalloc.h>
13
14#include "../../util/debug.h"
15#include "../../util/dso.h"
16#include "../../util/callchain.h"
17#include "../../util/evsel.h"
18#include "../../util/evlist.h"
19#include "../../util/header.h"
20#include "../../util/hist.h"
21#include "../../util/machine.h"
22#include "../../util/map.h"
23#include "../../util/maps.h"
24#include "../../util/symbol.h"
25#include "../../util/map_symbol.h"
26#include "../../util/branch.h"
27#include "../../util/pstack.h"
28#include "../../util/sort.h"
29#include "../../util/top.h"
30#include "../../util/thread.h"
31#include "../../util/block-info.h"
32#include "../../util/util.h"
33#include "../../arch/common.h"
34
35#include "../browsers/hists.h"
36#include "../helpline.h"
37#include "../util.h"
38#include "../ui.h"
39#include "map.h"
40#include "annotate.h"
41#include "srcline.h"
42#include "string2.h"
43#include "units.h"
44#include "time-utils.h"
45
46#include <linux/ctype.h>
47
48extern void hist_browser__init_hpp(void);
49
50static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size);
51static void hist_browser__update_nr_entries(struct hist_browser *hb);
52
53static struct rb_node *hists__filter_entries(struct rb_node *nd,
54					     float min_pcnt);
55
56static bool hist_browser__has_filter(struct hist_browser *hb)
57{
58	return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter;
59}
60
61static int hist_browser__get_folding(struct hist_browser *browser)
62{
63	struct rb_node *nd;
64	struct hists *hists = browser->hists;
65	int unfolded_rows = 0;
66
67	for (nd = rb_first_cached(&hists->entries);
68	     (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
69	     nd = rb_hierarchy_next(nd)) {
70		struct hist_entry *he =
71			rb_entry(nd, struct hist_entry, rb_node);
72
73		if (he->leaf && he->unfolded)
74			unfolded_rows += he->nr_rows;
75	}
76	return unfolded_rows;
77}
78
79static void hist_browser__set_title_space(struct hist_browser *hb)
80{
81	struct ui_browser *browser = &hb->b;
82	struct hists *hists = hb->hists;
83	struct perf_hpp_list *hpp_list = hists->hpp_list;
84
85	browser->extra_title_lines = hb->show_headers ? hpp_list->nr_header_lines : 0;
86}
87
88static u32 hist_browser__nr_entries(struct hist_browser *hb)
89{
90	u32 nr_entries;
91
92	if (symbol_conf.report_hierarchy)
93		nr_entries = hb->nr_hierarchy_entries;
94	else if (hist_browser__has_filter(hb))
95		nr_entries = hb->nr_non_filtered_entries;
96	else
97		nr_entries = hb->hists->nr_entries;
98
99	hb->nr_callchain_rows = hist_browser__get_folding(hb);
100	return nr_entries + hb->nr_callchain_rows;
101}
102
103static void hist_browser__update_rows(struct hist_browser *hb)
104{
105	struct ui_browser *browser = &hb->b;
106	struct hists *hists = hb->hists;
107	struct perf_hpp_list *hpp_list = hists->hpp_list;
108	u16 index_row;
109
110	if (!hb->show_headers) {
111		browser->rows += browser->extra_title_lines;
112		browser->extra_title_lines = 0;
113		return;
114	}
115
116	browser->extra_title_lines = hpp_list->nr_header_lines;
117	browser->rows -= browser->extra_title_lines;
118	/*
119	 * Verify if we were at the last line and that line isn't
120	 * visible because we now show the header line(s).
121	 */
122	index_row = browser->index - browser->top_idx;
123	if (index_row >= browser->rows)
124		browser->index -= index_row - browser->rows + 1;
125}
126
127static void hist_browser__refresh_dimensions(struct ui_browser *browser)
128{
129	struct hist_browser *hb = container_of(browser, struct hist_browser, b);
130
131	/* 3 == +/- toggle symbol before actual hist_entry rendering */
132	browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
133	/*
134 	 * FIXME: Just keeping existing behaviour, but this really should be
135 	 *	  before updating browser->width, as it will invalidate the
136 	 *	  calculation above. Fix this and the fallout in another
137 	 *	  changeset.
138 	 */
139	ui_browser__refresh_dimensions(browser);
140}
141
142static void hist_browser__reset(struct hist_browser *browser)
143{
144	/*
145	 * The hists__remove_entry_filter() already folds non-filtered
146	 * entries so we can assume it has 0 callchain rows.
147	 */
148	browser->nr_callchain_rows = 0;
149
150	hist_browser__update_nr_entries(browser);
151	browser->b.nr_entries = hist_browser__nr_entries(browser);
152	hist_browser__refresh_dimensions(&browser->b);
153	ui_browser__reset_index(&browser->b);
154}
155
156static char tree__folded_sign(bool unfolded)
157{
158	return unfolded ? '-' : '+';
159}
160
161static char hist_entry__folded(const struct hist_entry *he)
162{
163	return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
164}
165
166static char callchain_list__folded(const struct callchain_list *cl)
167{
168	return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
169}
170
171static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
172{
173	cl->unfolded = unfold ? cl->has_children : false;
174}
175
176static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
177{
178	int n = 0;
179	struct rb_node *nd;
180
181	for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
182		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
183		struct callchain_list *chain;
184		char folded_sign = ' '; /* No children */
185
186		list_for_each_entry(chain, &child->val, list) {
187			++n;
188
189			/* We need this because we may not have children */
190			folded_sign = callchain_list__folded(chain);
191			if (folded_sign == '+')
192				break;
193		}
194
195		if (folded_sign == '-') /* Have children and they're unfolded */
196			n += callchain_node__count_rows_rb_tree(child);
197	}
198
199	return n;
200}
201
202static int callchain_node__count_flat_rows(struct callchain_node *node)
203{
204	struct callchain_list *chain;
205	char folded_sign = 0;
206	int n = 0;
207
208	list_for_each_entry(chain, &node->parent_val, list) {
209		if (!folded_sign) {
210			/* only check first chain list entry */
211			folded_sign = callchain_list__folded(chain);
212			if (folded_sign == '+')
213				return 1;
214		}
215		n++;
216	}
217
218	list_for_each_entry(chain, &node->val, list) {
219		if (!folded_sign) {
220			/* node->parent_val list might be empty */
221			folded_sign = callchain_list__folded(chain);
222			if (folded_sign == '+')
223				return 1;
224		}
225		n++;
226	}
227
228	return n;
229}
230
231static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
232{
233	return 1;
234}
235
236static int callchain_node__count_rows(struct callchain_node *node)
237{
238	struct callchain_list *chain;
239	bool unfolded = false;
240	int n = 0;
241
242	if (callchain_param.mode == CHAIN_FLAT)
243		return callchain_node__count_flat_rows(node);
244	else if (callchain_param.mode == CHAIN_FOLDED)
245		return callchain_node__count_folded_rows(node);
246
247	list_for_each_entry(chain, &node->val, list) {
248		++n;
249
250		unfolded = chain->unfolded;
251	}
252
253	if (unfolded)
254		n += callchain_node__count_rows_rb_tree(node);
255
256	return n;
257}
258
259static int callchain__count_rows(struct rb_root *chain)
260{
261	struct rb_node *nd;
262	int n = 0;
263
264	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
265		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
266		n += callchain_node__count_rows(node);
267	}
268
269	return n;
270}
271
272static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
273				bool include_children)
274{
275	int count = 0;
276	struct rb_node *node;
277	struct hist_entry *child;
278
279	if (he->leaf)
280		return callchain__count_rows(&he->sorted_chain);
281
282	if (he->has_no_entry)
283		return 1;
284
285	node = rb_first_cached(&he->hroot_out);
286	while (node) {
287		float percent;
288
289		child = rb_entry(node, struct hist_entry, rb_node);
290		percent = hist_entry__get_percent_limit(child);
291
292		if (!child->filtered && percent >= hb->min_pcnt) {
293			count++;
294
295			if (include_children && child->unfolded)
296				count += hierarchy_count_rows(hb, child, true);
297		}
298
299		node = rb_next(node);
300	}
301	return count;
302}
303
304static bool hist_entry__toggle_fold(struct hist_entry *he)
305{
306	if (!he)
307		return false;
308
309	if (!he->has_children)
310		return false;
311
312	he->unfolded = !he->unfolded;
313	return true;
314}
315
316static bool callchain_list__toggle_fold(struct callchain_list *cl)
317{
318	if (!cl)
319		return false;
320
321	if (!cl->has_children)
322		return false;
323
324	cl->unfolded = !cl->unfolded;
325	return true;
326}
327
328static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
329{
330	struct rb_node *nd = rb_first(&node->rb_root);
331
332	for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
333		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
334		struct callchain_list *chain;
335		bool first = true;
336
337		list_for_each_entry(chain, &child->val, list) {
338			if (first) {
339				first = false;
340				chain->has_children = chain->list.next != &child->val ||
341							 !RB_EMPTY_ROOT(&child->rb_root);
342			} else
343				chain->has_children = chain->list.next == &child->val &&
344							 !RB_EMPTY_ROOT(&child->rb_root);
345		}
346
347		callchain_node__init_have_children_rb_tree(child);
348	}
349}
350
351static void callchain_node__init_have_children(struct callchain_node *node,
352					       bool has_sibling)
353{
354	struct callchain_list *chain;
355
356	chain = list_entry(node->val.next, struct callchain_list, list);
357	chain->has_children = has_sibling;
358
359	if (!list_empty(&node->val)) {
360		chain = list_entry(node->val.prev, struct callchain_list, list);
361		chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
362	}
363
364	callchain_node__init_have_children_rb_tree(node);
365}
366
367static void callchain__init_have_children(struct rb_root *root)
368{
369	struct rb_node *nd = rb_first(root);
370	bool has_sibling = nd && rb_next(nd);
371
372	for (nd = rb_first(root); nd; nd = rb_next(nd)) {
373		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
374		callchain_node__init_have_children(node, has_sibling);
375		if (callchain_param.mode == CHAIN_FLAT ||
376		    callchain_param.mode == CHAIN_FOLDED)
377			callchain_node__make_parent_list(node);
378	}
379}
380
381static void hist_entry__init_have_children(struct hist_entry *he)
382{
383	if (he->init_have_children)
384		return;
385
386	if (he->leaf) {
387		he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
388		callchain__init_have_children(&he->sorted_chain);
389	} else {
390		he->has_children = !RB_EMPTY_ROOT(&he->hroot_out.rb_root);
391	}
392
393	he->init_have_children = true;
394}
395
396static bool hist_browser__selection_has_children(struct hist_browser *browser)
397{
398	struct hist_entry *he = browser->he_selection;
399	struct map_symbol *ms = browser->selection;
400
401	if (!he || !ms)
402		return false;
403
404	if (ms == &he->ms)
405	       return he->has_children;
406
407	return container_of(ms, struct callchain_list, ms)->has_children;
408}
409
410static bool hist_browser__selection_unfolded(struct hist_browser *browser)
411{
412	struct hist_entry *he = browser->he_selection;
413	struct map_symbol *ms = browser->selection;
414
415	if (!he || !ms)
416		return false;
417
418	if (ms == &he->ms)
419	       return he->unfolded;
420
421	return container_of(ms, struct callchain_list, ms)->unfolded;
422}
423
424static char *hist_browser__selection_sym_name(struct hist_browser *browser, char *bf, size_t size)
425{
426	struct hist_entry *he = browser->he_selection;
427	struct map_symbol *ms = browser->selection;
428	struct callchain_list *callchain_entry;
429
430	if (!he || !ms)
431		return NULL;
432
433	if (ms == &he->ms) {
434	       hist_entry__sym_snprintf(he, bf, size, 0);
435	       return bf + 4; // skip the level, e.g. '[k] '
436	}
437
438	callchain_entry = container_of(ms, struct callchain_list, ms);
439	return callchain_list__sym_name(callchain_entry, bf, size, browser->show_dso);
440}
441
442static bool hist_browser__toggle_fold(struct hist_browser *browser)
443{
444	struct hist_entry *he = browser->he_selection;
445	struct map_symbol *ms = browser->selection;
446	struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
447	bool has_children;
448
449	if (!he || !ms)
450		return false;
451
452	if (ms == &he->ms)
453		has_children = hist_entry__toggle_fold(he);
454	else
455		has_children = callchain_list__toggle_fold(cl);
456
457	if (has_children) {
458		int child_rows = 0;
459
460		hist_entry__init_have_children(he);
461		browser->b.nr_entries -= he->nr_rows;
462
463		if (he->leaf)
464			browser->nr_callchain_rows -= he->nr_rows;
465		else
466			browser->nr_hierarchy_entries -= he->nr_rows;
467
468		if (symbol_conf.report_hierarchy)
469			child_rows = hierarchy_count_rows(browser, he, true);
470
471		if (he->unfolded) {
472			if (he->leaf)
473				he->nr_rows = callchain__count_rows(
474						&he->sorted_chain);
475			else
476				he->nr_rows = hierarchy_count_rows(browser, he, false);
477
478			/* account grand children */
479			if (symbol_conf.report_hierarchy)
480				browser->b.nr_entries += child_rows - he->nr_rows;
481
482			if (!he->leaf && he->nr_rows == 0) {
483				he->has_no_entry = true;
484				he->nr_rows = 1;
485			}
486		} else {
487			if (symbol_conf.report_hierarchy)
488				browser->b.nr_entries -= child_rows - he->nr_rows;
489
490			if (he->has_no_entry)
491				he->has_no_entry = false;
492
493			he->nr_rows = 0;
494		}
495
496		browser->b.nr_entries += he->nr_rows;
497
498		if (he->leaf)
499			browser->nr_callchain_rows += he->nr_rows;
500		else
501			browser->nr_hierarchy_entries += he->nr_rows;
502
503		return true;
504	}
505
506	/* If it doesn't have children, no toggling performed */
507	return false;
508}
509
510static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
511{
512	int n = 0;
513	struct rb_node *nd;
514
515	for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
516		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
517		struct callchain_list *chain;
518		bool has_children = false;
519
520		list_for_each_entry(chain, &child->val, list) {
521			++n;
522			callchain_list__set_folding(chain, unfold);
523			has_children = chain->has_children;
524		}
525
526		if (has_children)
527			n += callchain_node__set_folding_rb_tree(child, unfold);
528	}
529
530	return n;
531}
532
533static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
534{
535	struct callchain_list *chain;
536	bool has_children = false;
537	int n = 0;
538
539	list_for_each_entry(chain, &node->val, list) {
540		++n;
541		callchain_list__set_folding(chain, unfold);
542		has_children = chain->has_children;
543	}
544
545	if (has_children)
546		n += callchain_node__set_folding_rb_tree(node, unfold);
547
548	return n;
549}
550
551static int callchain__set_folding(struct rb_root *chain, bool unfold)
552{
553	struct rb_node *nd;
554	int n = 0;
555
556	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
557		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
558		n += callchain_node__set_folding(node, unfold);
559	}
560
561	return n;
562}
563
564static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
565				 bool unfold __maybe_unused)
566{
567	float percent;
568	struct rb_node *nd;
569	struct hist_entry *child;
570	int n = 0;
571
572	for (nd = rb_first_cached(&he->hroot_out); nd; nd = rb_next(nd)) {
573		child = rb_entry(nd, struct hist_entry, rb_node);
574		percent = hist_entry__get_percent_limit(child);
575		if (!child->filtered && percent >= hb->min_pcnt)
576			n++;
577	}
578
579	return n;
580}
581
582static void hist_entry__set_folding(struct hist_entry *he,
583				    struct hist_browser *hb, bool unfold)
584{
585	hist_entry__init_have_children(he);
586	he->unfolded = unfold ? he->has_children : false;
587
588	if (he->has_children) {
589		int n;
590
591		if (he->leaf)
592			n = callchain__set_folding(&he->sorted_chain, unfold);
593		else
594			n = hierarchy_set_folding(hb, he, unfold);
595
596		he->nr_rows = unfold ? n : 0;
597	} else
598		he->nr_rows = 0;
599}
600
601static void
602__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
603{
604	struct rb_node *nd;
605	struct hist_entry *he;
606	double percent;
607
608	nd = rb_first_cached(&browser->hists->entries);
609	while (nd) {
610		he = rb_entry(nd, struct hist_entry, rb_node);
611
612		/* set folding state even if it's currently folded */
613		nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
614
615		hist_entry__set_folding(he, browser, unfold);
616
617		percent = hist_entry__get_percent_limit(he);
618		if (he->filtered || percent < browser->min_pcnt)
619			continue;
620
621		if (!he->depth || unfold)
622			browser->nr_hierarchy_entries++;
623		if (he->leaf)
624			browser->nr_callchain_rows += he->nr_rows;
625		else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
626			browser->nr_hierarchy_entries++;
627			he->has_no_entry = true;
628			he->nr_rows = 1;
629		} else
630			he->has_no_entry = false;
631	}
632}
633
634static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
635{
636	browser->nr_hierarchy_entries = 0;
637	browser->nr_callchain_rows = 0;
638	__hist_browser__set_folding(browser, unfold);
639
640	browser->b.nr_entries = hist_browser__nr_entries(browser);
641	/* Go to the start, we may be way after valid entries after a collapse */
642	ui_browser__reset_index(&browser->b);
643}
644
645static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold)
646{
647	if (!browser->he_selection)
648		return;
649
650	if (unfold == browser->he_selection->unfolded)
651		return;
652
653	hist_browser__toggle_fold(browser);
654}
655
656static void ui_browser__warn_lost_events(struct ui_browser *browser)
657{
658	ui_browser__warning(browser, 4,
659		"Events are being lost, check IO/CPU overload!\n\n"
660		"You may want to run 'perf' using a RT scheduler policy:\n\n"
661		" perf top -r 80\n\n"
662		"Or reduce the sampling frequency.");
663}
664
665static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
666{
667	return browser->title ? browser->title(browser, bf, size) : 0;
668}
669
670static int hist_browser__handle_hotkey(struct hist_browser *browser, bool warn_lost_event, char *title, size_t size, int key)
671{
672	switch (key) {
673	case K_TIMER: {
674		struct hist_browser_timer *hbt = browser->hbt;
675		struct evsel *evsel = hists_to_evsel(browser->hists);
676		u64 nr_entries;
677
678		WARN_ON_ONCE(!hbt);
679
680		if (hbt)
681			hbt->timer(hbt->arg);
682
683		if (hist_browser__has_filter(browser) || symbol_conf.report_hierarchy)
684			hist_browser__update_nr_entries(browser);
685
686		nr_entries = hist_browser__nr_entries(browser);
687		ui_browser__update_nr_entries(&browser->b, nr_entries);
688
689		if (warn_lost_event &&
690		    (evsel->evlist->stats.nr_lost_warned !=
691		     evsel->evlist->stats.nr_events[PERF_RECORD_LOST])) {
692			evsel->evlist->stats.nr_lost_warned =
693				evsel->evlist->stats.nr_events[PERF_RECORD_LOST];
694			ui_browser__warn_lost_events(&browser->b);
695		}
696
697		hist_browser__title(browser, title, size);
698		ui_browser__show_title(&browser->b, title);
699		break;
700	}
701	case 'D': { /* Debug */
702		struct hist_entry *h = rb_entry(browser->b.top, struct hist_entry, rb_node);
703		static int seq;
704
705		ui_helpline__pop();
706		ui_helpline__fpush("%d: nr_ent=(%d,%d), etl: %d, rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
707				   seq++, browser->b.nr_entries, browser->hists->nr_entries,
708				   browser->b.extra_title_lines, browser->b.rows,
709				   browser->b.index, browser->b.top_idx, h->row_offset, h->nr_rows);
710	}
711		break;
712	case 'C':
713		/* Collapse the whole world. */
714		hist_browser__set_folding(browser, false);
715		break;
716	case 'c':
717		/* Collapse the selected entry. */
718		hist_browser__set_folding_selected(browser, false);
719		break;
720	case 'E':
721		/* Expand the whole world. */
722		hist_browser__set_folding(browser, true);
723		break;
724	case 'e':
725		/* Toggle expand/collapse the selected entry. */
726		hist_browser__toggle_fold(browser);
727		break;
728	case 'H':
729		browser->show_headers = !browser->show_headers;
730		hist_browser__update_rows(browser);
731		break;
732	case '+':
733		if (hist_browser__toggle_fold(browser))
734			break;
735		/* fall thru */
736	default:
737		return -1;
738	}
739
740	return 0;
741}
742
743int hist_browser__run(struct hist_browser *browser, const char *help,
744		      bool warn_lost_event, int key)
745{
746	char title[160];
747	struct hist_browser_timer *hbt = browser->hbt;
748	int delay_secs = hbt ? hbt->refresh : 0;
749
750	browser->b.entries = &browser->hists->entries;
751	browser->b.nr_entries = hist_browser__nr_entries(browser);
752
753	hist_browser__title(browser, title, sizeof(title));
754
755	if (ui_browser__show(&browser->b, title, "%s", help) < 0)
756		return -1;
757
758	if (key && hist_browser__handle_hotkey(browser, warn_lost_event, title, sizeof(title), key))
759		goto out;
760
761	while (1) {
762		key = ui_browser__run(&browser->b, delay_secs);
763
764		if (hist_browser__handle_hotkey(browser, warn_lost_event, title, sizeof(title), key))
765			break;
766	}
767out:
768	ui_browser__hide(&browser->b);
769	return key;
770}
771
772struct callchain_print_arg {
773	/* for hists browser */
774	off_t	row_offset;
775	bool	is_current_entry;
776
777	/* for file dump */
778	FILE	*fp;
779	int	printed;
780};
781
782typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
783					 struct callchain_list *chain,
784					 const char *str, int offset,
785					 unsigned short row,
786					 struct callchain_print_arg *arg);
787
788static void hist_browser__show_callchain_entry(struct hist_browser *browser,
789					       struct callchain_list *chain,
790					       const char *str, int offset,
791					       unsigned short row,
792					       struct callchain_print_arg *arg)
793{
794	int color, width;
795	char folded_sign = callchain_list__folded(chain);
796	bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
797
798	color = HE_COLORSET_NORMAL;
799	width = browser->b.width - (offset + 2);
800	if (ui_browser__is_current_entry(&browser->b, row)) {
801		browser->selection = &chain->ms;
802		color = HE_COLORSET_SELECTED;
803		arg->is_current_entry = true;
804	}
805
806	ui_browser__set_color(&browser->b, color);
807	ui_browser__gotorc(&browser->b, row, 0);
808	ui_browser__write_nstring(&browser->b, " ", offset);
809	ui_browser__printf(&browser->b, "%c", folded_sign);
810	ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
811	ui_browser__write_nstring(&browser->b, str, width);
812}
813
814static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
815						  struct callchain_list *chain,
816						  const char *str, int offset,
817						  unsigned short row __maybe_unused,
818						  struct callchain_print_arg *arg)
819{
820	char folded_sign = callchain_list__folded(chain);
821
822	arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
823				folded_sign, str);
824}
825
826typedef bool (*check_output_full_fn)(struct hist_browser *browser,
827				     unsigned short row);
828
829static bool hist_browser__check_output_full(struct hist_browser *browser,
830					    unsigned short row)
831{
832	return browser->b.rows == row;
833}
834
835static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
836					  unsigned short row __maybe_unused)
837{
838	return false;
839}
840
841#define LEVEL_OFFSET_STEP 3
842
843static int hist_browser__show_callchain_list(struct hist_browser *browser,
844					     struct callchain_node *node,
845					     struct callchain_list *chain,
846					     unsigned short row, u64 total,
847					     bool need_percent, int offset,
848					     print_callchain_entry_fn print,
849					     struct callchain_print_arg *arg)
850{
851	char bf[1024], *alloc_str;
852	char buf[64], *alloc_str2;
853	const char *str;
854	int ret = 1;
855
856	if (arg->row_offset != 0) {
857		arg->row_offset--;
858		return 0;
859	}
860
861	alloc_str = NULL;
862	alloc_str2 = NULL;
863
864	str = callchain_list__sym_name(chain, bf, sizeof(bf),
865				       browser->show_dso);
866
867	if (symbol_conf.show_branchflag_count) {
868		callchain_list_counts__printf_value(chain, NULL,
869						    buf, sizeof(buf));
870
871		if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
872			str = "Not enough memory!";
873		else
874			str = alloc_str2;
875	}
876
877	if (need_percent) {
878		callchain_node__scnprintf_value(node, buf, sizeof(buf),
879						total);
880
881		if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
882			str = "Not enough memory!";
883		else
884			str = alloc_str;
885	}
886
887	print(browser, chain, str, offset, row, arg);
888	free(alloc_str);
889	free(alloc_str2);
890
891	return ret;
892}
893
894static bool check_percent_display(struct rb_node *node, u64 parent_total)
895{
896	struct callchain_node *child;
897
898	if (node == NULL)
899		return false;
900
901	if (rb_next(node))
902		return true;
903
904	child = rb_entry(node, struct callchain_node, rb_node);
905	return callchain_cumul_hits(child) != parent_total;
906}
907
908static int hist_browser__show_callchain_flat(struct hist_browser *browser,
909					     struct rb_root *root,
910					     unsigned short row, u64 total,
911					     u64 parent_total,
912					     print_callchain_entry_fn print,
913					     struct callchain_print_arg *arg,
914					     check_output_full_fn is_output_full)
915{
916	struct rb_node *node;
917	int first_row = row, offset = LEVEL_OFFSET_STEP;
918	bool need_percent;
919
920	node = rb_first(root);
921	need_percent = check_percent_display(node, parent_total);
922
923	while (node) {
924		struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
925		struct rb_node *next = rb_next(node);
926		struct callchain_list *chain;
927		char folded_sign = ' ';
928		int first = true;
929		int extra_offset = 0;
930
931		list_for_each_entry(chain, &child->parent_val, list) {
932			bool was_first = first;
933
934			if (first)
935				first = false;
936			else if (need_percent)
937				extra_offset = LEVEL_OFFSET_STEP;
938
939			folded_sign = callchain_list__folded(chain);
940
941			row += hist_browser__show_callchain_list(browser, child,
942							chain, row, total,
943							was_first && need_percent,
944							offset + extra_offset,
945							print, arg);
946
947			if (is_output_full(browser, row))
948				goto out;
949
950			if (folded_sign == '+')
951				goto next;
952		}
953
954		list_for_each_entry(chain, &child->val, list) {
955			bool was_first = first;
956
957			if (first)
958				first = false;
959			else if (need_percent)
960				extra_offset = LEVEL_OFFSET_STEP;
961
962			folded_sign = callchain_list__folded(chain);
963
964			row += hist_browser__show_callchain_list(browser, child,
965							chain, row, total,
966							was_first && need_percent,
967							offset + extra_offset,
968							print, arg);
969
970			if (is_output_full(browser, row))
971				goto out;
972
973			if (folded_sign == '+')
974				break;
975		}
976
977next:
978		if (is_output_full(browser, row))
979			break;
980		node = next;
981	}
982out:
983	return row - first_row;
984}
985
986static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
987						struct callchain_list *chain,
988						char *value_str, char *old_str)
989{
990	char bf[1024];
991	const char *str;
992	char *new;
993
994	str = callchain_list__sym_name(chain, bf, sizeof(bf),
995				       browser->show_dso);
996	if (old_str) {
997		if (asprintf(&new, "%s%s%s", old_str,
998			     symbol_conf.field_sep ?: ";", str) < 0)
999			new = NULL;
1000	} else {
1001		if (value_str) {
1002			if (asprintf(&new, "%s %s", value_str, str) < 0)
1003				new = NULL;
1004		} else {
1005			if (asprintf(&new, "%s", str) < 0)
1006				new = NULL;
1007		}
1008	}
1009	return new;
1010}
1011
1012static int hist_browser__show_callchain_folded(struct hist_browser *browser,
1013					       struct rb_root *root,
1014					       unsigned short row, u64 total,
1015					       u64 parent_total,
1016					       print_callchain_entry_fn print,
1017					       struct callchain_print_arg *arg,
1018					       check_output_full_fn is_output_full)
1019{
1020	struct rb_node *node;
1021	int first_row = row, offset = LEVEL_OFFSET_STEP;
1022	bool need_percent;
1023
1024	node = rb_first(root);
1025	need_percent = check_percent_display(node, parent_total);
1026
1027	while (node) {
1028		struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1029		struct rb_node *next = rb_next(node);
1030		struct callchain_list *chain, *first_chain = NULL;
1031		int first = true;
1032		char *value_str = NULL, *value_str_alloc = NULL;
1033		char *chain_str = NULL, *chain_str_alloc = NULL;
1034
1035		if (arg->row_offset != 0) {
1036			arg->row_offset--;
1037			goto next;
1038		}
1039
1040		if (need_percent) {
1041			char buf[64];
1042
1043			callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
1044			if (asprintf(&value_str, "%s", buf) < 0) {
1045				value_str = (char *)"<...>";
1046				goto do_print;
1047			}
1048			value_str_alloc = value_str;
1049		}
1050
1051		list_for_each_entry(chain, &child->parent_val, list) {
1052			chain_str = hist_browser__folded_callchain_str(browser,
1053						chain, value_str, chain_str);
1054			if (first) {
1055				first = false;
1056				first_chain = chain;
1057			}
1058
1059			if (chain_str == NULL) {
1060				chain_str = (char *)"Not enough memory!";
1061				goto do_print;
1062			}
1063
1064			chain_str_alloc = chain_str;
1065		}
1066
1067		list_for_each_entry(chain, &child->val, list) {
1068			chain_str = hist_browser__folded_callchain_str(browser,
1069						chain, value_str, chain_str);
1070			if (first) {
1071				first = false;
1072				first_chain = chain;
1073			}
1074
1075			if (chain_str == NULL) {
1076				chain_str = (char *)"Not enough memory!";
1077				goto do_print;
1078			}
1079
1080			chain_str_alloc = chain_str;
1081		}
1082
1083do_print:
1084		print(browser, first_chain, chain_str, offset, row++, arg);
1085		free(value_str_alloc);
1086		free(chain_str_alloc);
1087
1088next:
1089		if (is_output_full(browser, row))
1090			break;
1091		node = next;
1092	}
1093
1094	return row - first_row;
1095}
1096
1097static int hist_browser__show_callchain_graph(struct hist_browser *browser,
1098					struct rb_root *root, int level,
1099					unsigned short row, u64 total,
1100					u64 parent_total,
1101					print_callchain_entry_fn print,
1102					struct callchain_print_arg *arg,
1103					check_output_full_fn is_output_full)
1104{
1105	struct rb_node *node;
1106	int first_row = row, offset = level * LEVEL_OFFSET_STEP;
1107	bool need_percent;
1108	u64 percent_total = total;
1109
1110	if (callchain_param.mode == CHAIN_GRAPH_REL)
1111		percent_total = parent_total;
1112
1113	node = rb_first(root);
1114	need_percent = check_percent_display(node, parent_total);
1115
1116	while (node) {
1117		struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1118		struct rb_node *next = rb_next(node);
1119		struct callchain_list *chain;
1120		char folded_sign = ' ';
1121		int first = true;
1122		int extra_offset = 0;
1123
1124		list_for_each_entry(chain, &child->val, list) {
1125			bool was_first = first;
1126
1127			if (first)
1128				first = false;
1129			else if (need_percent)
1130				extra_offset = LEVEL_OFFSET_STEP;
1131
1132			folded_sign = callchain_list__folded(chain);
1133
1134			row += hist_browser__show_callchain_list(browser, child,
1135							chain, row, percent_total,
1136							was_first && need_percent,
1137							offset + extra_offset,
1138							print, arg);
1139
1140			if (is_output_full(browser, row))
1141				goto out;
1142
1143			if (folded_sign == '+')
1144				break;
1145		}
1146
1147		if (folded_sign == '-') {
1148			const int new_level = level + (extra_offset ? 2 : 1);
1149
1150			row += hist_browser__show_callchain_graph(browser, &child->rb_root,
1151							    new_level, row, total,
1152							    child->children_hit,
1153							    print, arg, is_output_full);
1154		}
1155		if (is_output_full(browser, row))
1156			break;
1157		node = next;
1158	}
1159out:
1160	return row - first_row;
1161}
1162
1163static int hist_browser__show_callchain(struct hist_browser *browser,
1164					struct hist_entry *entry, int level,
1165					unsigned short row,
1166					print_callchain_entry_fn print,
1167					struct callchain_print_arg *arg,
1168					check_output_full_fn is_output_full)
1169{
1170	u64 total = hists__total_period(entry->hists);
1171	u64 parent_total;
1172	int printed;
1173
1174	if (symbol_conf.cumulate_callchain)
1175		parent_total = entry->stat_acc->period;
1176	else
1177		parent_total = entry->stat.period;
1178
1179	if (callchain_param.mode == CHAIN_FLAT) {
1180		printed = hist_browser__show_callchain_flat(browser,
1181						&entry->sorted_chain, row,
1182						total, parent_total, print, arg,
1183						is_output_full);
1184	} else if (callchain_param.mode == CHAIN_FOLDED) {
1185		printed = hist_browser__show_callchain_folded(browser,
1186						&entry->sorted_chain, row,
1187						total, parent_total, print, arg,
1188						is_output_full);
1189	} else {
1190		printed = hist_browser__show_callchain_graph(browser,
1191						&entry->sorted_chain, level, row,
1192						total, parent_total, print, arg,
1193						is_output_full);
1194	}
1195
1196	if (arg->is_current_entry)
1197		browser->he_selection = entry;
1198
1199	return printed;
1200}
1201
1202struct hpp_arg {
1203	struct ui_browser *b;
1204	char folded_sign;
1205	bool current_entry;
1206};
1207
1208int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
1209{
1210	struct hpp_arg *arg = hpp->ptr;
1211	int ret, len;
1212	va_list args;
1213	double percent;
1214
1215	va_start(args, fmt);
1216	len = va_arg(args, int);
1217	percent = va_arg(args, double);
1218	va_end(args);
1219
1220	ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
1221
1222	ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
1223	ui_browser__printf(arg->b, "%s", hpp->buf);
1224
1225	return ret;
1226}
1227
1228#define __HPP_COLOR_PERCENT_FN(_type, _field)				\
1229static u64 __hpp_get_##_field(struct hist_entry *he)			\
1230{									\
1231	return he->stat._field;						\
1232}									\
1233									\
1234static int								\
1235hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt,		\
1236				struct perf_hpp *hpp,			\
1237				struct hist_entry *he)			\
1238{									\
1239	return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%",	\
1240			__hpp__slsmg_color_printf, true);		\
1241}
1242
1243#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)			\
1244static u64 __hpp_get_acc_##_field(struct hist_entry *he)		\
1245{									\
1246	return he->stat_acc->_field;					\
1247}									\
1248									\
1249static int								\
1250hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt,		\
1251				struct perf_hpp *hpp,			\
1252				struct hist_entry *he)			\
1253{									\
1254	if (!symbol_conf.cumulate_callchain) {				\
1255		struct hpp_arg *arg = hpp->ptr;				\
1256		int len = fmt->user_len ?: fmt->len;			\
1257		int ret = scnprintf(hpp->buf, hpp->size,		\
1258				    "%*s", len, "N/A");			\
1259		ui_browser__printf(arg->b, "%s", hpp->buf);		\
1260									\
1261		return ret;						\
1262	}								\
1263	return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field,		\
1264			" %*.2f%%", __hpp__slsmg_color_printf, true);	\
1265}
1266
1267__HPP_COLOR_PERCENT_FN(overhead, period)
1268__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1269__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1270__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1271__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
1272__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
1273
1274#undef __HPP_COLOR_PERCENT_FN
1275#undef __HPP_COLOR_ACC_PERCENT_FN
1276
1277void hist_browser__init_hpp(void)
1278{
1279	perf_hpp__format[PERF_HPP__OVERHEAD].color =
1280				hist_browser__hpp_color_overhead;
1281	perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1282				hist_browser__hpp_color_overhead_sys;
1283	perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1284				hist_browser__hpp_color_overhead_us;
1285	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1286				hist_browser__hpp_color_overhead_guest_sys;
1287	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1288				hist_browser__hpp_color_overhead_guest_us;
1289	perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1290				hist_browser__hpp_color_overhead_acc;
1291
1292	res_sample_init();
1293}
1294
1295static int hist_browser__show_entry(struct hist_browser *browser,
1296				    struct hist_entry *entry,
1297				    unsigned short row)
1298{
1299	int printed = 0;
1300	int width = browser->b.width;
1301	char folded_sign = ' ';
1302	bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1303	bool use_callchain = hist_entry__has_callchains(entry) && symbol_conf.use_callchain;
1304	off_t row_offset = entry->row_offset;
1305	bool first = true;
1306	struct perf_hpp_fmt *fmt;
1307
1308	if (current_entry) {
1309		browser->he_selection = entry;
1310		browser->selection = &entry->ms;
1311	}
1312
1313	if (use_callchain) {
1314		hist_entry__init_have_children(entry);
1315		folded_sign = hist_entry__folded(entry);
1316	}
1317
1318	if (row_offset == 0) {
1319		struct hpp_arg arg = {
1320			.b		= &browser->b,
1321			.folded_sign	= folded_sign,
1322			.current_entry	= current_entry,
1323		};
1324		int column = 0;
1325
1326		ui_browser__gotorc(&browser->b, row, 0);
1327
1328		hists__for_each_format(browser->hists, fmt) {
1329			char s[2048];
1330			struct perf_hpp hpp = {
1331				.buf	= s,
1332				.size	= sizeof(s),
1333				.ptr	= &arg,
1334			};
1335
1336			if (perf_hpp__should_skip(fmt, entry->hists) ||
1337			    column++ < browser->b.horiz_scroll)
1338				continue;
1339
1340			if (current_entry && browser->b.navkeypressed) {
1341				ui_browser__set_color(&browser->b,
1342						      HE_COLORSET_SELECTED);
1343			} else {
1344				ui_browser__set_color(&browser->b,
1345						      HE_COLORSET_NORMAL);
1346			}
1347
1348			if (first) {
1349				if (use_callchain) {
1350					ui_browser__printf(&browser->b, "%c ", folded_sign);
1351					width -= 2;
1352				}
1353				first = false;
1354			} else {
1355				ui_browser__printf(&browser->b, "  ");
1356				width -= 2;
1357			}
1358
1359			if (fmt->color) {
1360				int ret = fmt->color(fmt, &hpp, entry);
1361				hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1362				/*
1363				 * fmt->color() already used ui_browser to
1364				 * print the non alignment bits, skip it (+ret):
1365				 */
1366				ui_browser__printf(&browser->b, "%s", s + ret);
1367			} else {
1368				hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
1369				ui_browser__printf(&browser->b, "%s", s);
1370			}
1371			width -= hpp.buf - s;
1372		}
1373
1374		/* The scroll bar isn't being used */
1375		if (!browser->b.navkeypressed)
1376			width += 1;
1377
1378		ui_browser__write_nstring(&browser->b, "", width);
1379
1380		++row;
1381		++printed;
1382	} else
1383		--row_offset;
1384
1385	if (folded_sign == '-' && row != browser->b.rows) {
1386		struct callchain_print_arg arg = {
1387			.row_offset = row_offset,
1388			.is_current_entry = current_entry,
1389		};
1390
1391		printed += hist_browser__show_callchain(browser,
1392				entry, 1, row,
1393				hist_browser__show_callchain_entry,
1394				&arg,
1395				hist_browser__check_output_full);
1396	}
1397
1398	return printed;
1399}
1400
1401static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1402					      struct hist_entry *entry,
1403					      unsigned short row,
1404					      int level)
1405{
1406	int printed = 0;
1407	int width = browser->b.width;
1408	char folded_sign = ' ';
1409	bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1410	off_t row_offset = entry->row_offset;
1411	bool first = true;
1412	struct perf_hpp_fmt *fmt;
1413	struct perf_hpp_list_node *fmt_node;
1414	struct hpp_arg arg = {
1415		.b		= &browser->b,
1416		.current_entry	= current_entry,
1417	};
1418	int column = 0;
1419	int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
1420
1421	if (current_entry) {
1422		browser->he_selection = entry;
1423		browser->selection = &entry->ms;
1424	}
1425
1426	hist_entry__init_have_children(entry);
1427	folded_sign = hist_entry__folded(entry);
1428	arg.folded_sign = folded_sign;
1429
1430	if (entry->leaf && row_offset) {
1431		row_offset--;
1432		goto show_callchain;
1433	}
1434
1435	ui_browser__gotorc(&browser->b, row, 0);
1436
1437	if (current_entry && browser->b.navkeypressed)
1438		ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1439	else
1440		ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1441
1442	ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1443	width -= level * HIERARCHY_INDENT;
1444
1445	/* the first hpp_list_node is for overhead columns */
1446	fmt_node = list_first_entry(&entry->hists->hpp_formats,
1447				    struct perf_hpp_list_node, list);
1448	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1449		char s[2048];
1450		struct perf_hpp hpp = {
1451			.buf		= s,
1452			.size		= sizeof(s),
1453			.ptr		= &arg,
1454		};
1455
1456		if (perf_hpp__should_skip(fmt, entry->hists) ||
1457		    column++ < browser->b.horiz_scroll)
1458			continue;
1459
1460		if (current_entry && browser->b.navkeypressed) {
1461			ui_browser__set_color(&browser->b,
1462					      HE_COLORSET_SELECTED);
1463		} else {
1464			ui_browser__set_color(&browser->b,
1465					      HE_COLORSET_NORMAL);
1466		}
1467
1468		if (first) {
1469			ui_browser__printf(&browser->b, "%c ", folded_sign);
1470			width -= 2;
1471			first = false;
1472		} else {
1473			ui_browser__printf(&browser->b, "  ");
1474			width -= 2;
1475		}
1476
1477		if (fmt->color) {
1478			int ret = fmt->color(fmt, &hpp, entry);
1479			hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1480			/*
1481			 * fmt->color() already used ui_browser to
1482			 * print the non alignment bits, skip it (+ret):
1483			 */
1484			ui_browser__printf(&browser->b, "%s", s + ret);
1485		} else {
1486			int ret = fmt->entry(fmt, &hpp, entry);
1487			hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1488			ui_browser__printf(&browser->b, "%s", s);
1489		}
1490		width -= hpp.buf - s;
1491	}
1492
1493	if (!first) {
1494		ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1495		width -= hierarchy_indent;
1496	}
1497
1498	if (column >= browser->b.horiz_scroll) {
1499		char s[2048];
1500		struct perf_hpp hpp = {
1501			.buf		= s,
1502			.size		= sizeof(s),
1503			.ptr		= &arg,
1504		};
1505
1506		if (current_entry && browser->b.navkeypressed) {
1507			ui_browser__set_color(&browser->b,
1508					      HE_COLORSET_SELECTED);
1509		} else {
1510			ui_browser__set_color(&browser->b,
1511					      HE_COLORSET_NORMAL);
1512		}
1513
1514		perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
1515			if (first) {
1516				ui_browser__printf(&browser->b, "%c ", folded_sign);
1517				first = false;
1518			} else {
1519				ui_browser__write_nstring(&browser->b, "", 2);
1520			}
1521
1522			width -= 2;
1523
1524			/*
1525			 * No need to call hist_entry__snprintf_alignment()
1526			 * since this fmt is always the last column in the
1527			 * hierarchy mode.
1528			 */
1529			if (fmt->color) {
1530				width -= fmt->color(fmt, &hpp, entry);
1531			} else {
1532				int i = 0;
1533
1534				width -= fmt->entry(fmt, &hpp, entry);
1535				ui_browser__printf(&browser->b, "%s", skip_spaces(s));
1536
1537				while (isspace(s[i++]))
1538					width++;
1539			}
1540		}
1541	}
1542
1543	/* The scroll bar isn't being used */
1544	if (!browser->b.navkeypressed)
1545		width += 1;
1546
1547	ui_browser__write_nstring(&browser->b, "", width);
1548
1549	++row;
1550	++printed;
1551
1552show_callchain:
1553	if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1554		struct callchain_print_arg carg = {
1555			.row_offset = row_offset,
1556		};
1557
1558		printed += hist_browser__show_callchain(browser, entry,
1559					level + 1, row,
1560					hist_browser__show_callchain_entry, &carg,
1561					hist_browser__check_output_full);
1562	}
1563
1564	return printed;
1565}
1566
1567static int hist_browser__show_no_entry(struct hist_browser *browser,
1568				       unsigned short row, int level)
1569{
1570	int width = browser->b.width;
1571	bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1572	bool first = true;
1573	int column = 0;
1574	int ret;
1575	struct perf_hpp_fmt *fmt;
1576	struct perf_hpp_list_node *fmt_node;
1577	int indent = browser->hists->nr_hpp_node - 2;
1578
1579	if (current_entry) {
1580		browser->he_selection = NULL;
1581		browser->selection = NULL;
1582	}
1583
1584	ui_browser__gotorc(&browser->b, row, 0);
1585
1586	if (current_entry && browser->b.navkeypressed)
1587		ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1588	else
1589		ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1590
1591	ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1592	width -= level * HIERARCHY_INDENT;
1593
1594	/* the first hpp_list_node is for overhead columns */
1595	fmt_node = list_first_entry(&browser->hists->hpp_formats,
1596				    struct perf_hpp_list_node, list);
1597	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1598		if (perf_hpp__should_skip(fmt, browser->hists) ||
1599		    column++ < browser->b.horiz_scroll)
1600			continue;
1601
1602		ret = fmt->width(fmt, NULL, browser->hists);
1603
1604		if (first) {
1605			/* for folded sign */
1606			first = false;
1607			ret++;
1608		} else {
1609			/* space between columns */
1610			ret += 2;
1611		}
1612
1613		ui_browser__write_nstring(&browser->b, "", ret);
1614		width -= ret;
1615	}
1616
1617	ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1618	width -= indent * HIERARCHY_INDENT;
1619
1620	if (column >= browser->b.horiz_scroll) {
1621		char buf[32];
1622
1623		ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1624		ui_browser__printf(&browser->b, "  %s", buf);
1625		width -= ret + 2;
1626	}
1627
1628	/* The scroll bar isn't being used */
1629	if (!browser->b.navkeypressed)
1630		width += 1;
1631
1632	ui_browser__write_nstring(&browser->b, "", width);
1633	return 1;
1634}
1635
1636static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1637{
1638	advance_hpp(hpp, inc);
1639	return hpp->size <= 0;
1640}
1641
1642static int
1643hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1644				 size_t size, int line)
1645{
1646	struct hists *hists = browser->hists;
1647	struct perf_hpp dummy_hpp = {
1648		.buf    = buf,
1649		.size   = size,
1650	};
1651	struct perf_hpp_fmt *fmt;
1652	size_t ret = 0;
1653	int column = 0;
1654	int span = 0;
1655
1656	if (hists__has_callchains(hists) && symbol_conf.use_callchain) {
1657		ret = scnprintf(buf, size, "  ");
1658		if (advance_hpp_check(&dummy_hpp, ret))
1659			return ret;
1660	}
1661
1662	hists__for_each_format(browser->hists, fmt) {
1663		if (perf_hpp__should_skip(fmt, hists)  || column++ < browser->b.horiz_scroll)
1664			continue;
1665
1666		ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
1667		if (advance_hpp_check(&dummy_hpp, ret))
1668			break;
1669
1670		if (span)
1671			continue;
1672
1673		ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "  ");
1674		if (advance_hpp_check(&dummy_hpp, ret))
1675			break;
1676	}
1677
1678	return ret;
1679}
1680
1681static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1682{
1683	struct hists *hists = browser->hists;
1684	struct perf_hpp dummy_hpp = {
1685		.buf    = buf,
1686		.size   = size,
1687	};
1688	struct perf_hpp_fmt *fmt;
1689	struct perf_hpp_list_node *fmt_node;
1690	size_t ret = 0;
1691	int column = 0;
1692	int indent = hists->nr_hpp_node - 2;
1693	bool first_node, first_col;
1694
1695	ret = scnprintf(buf, size, "  ");
1696	if (advance_hpp_check(&dummy_hpp, ret))
1697		return ret;
1698
1699	first_node = true;
1700	/* the first hpp_list_node is for overhead columns */
1701	fmt_node = list_first_entry(&hists->hpp_formats,
1702				    struct perf_hpp_list_node, list);
1703	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1704		if (column++ < browser->b.horiz_scroll)
1705			continue;
1706
1707		ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
1708		if (advance_hpp_check(&dummy_hpp, ret))
1709			break;
1710
1711		ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "  ");
1712		if (advance_hpp_check(&dummy_hpp, ret))
1713			break;
1714
1715		first_node = false;
1716	}
1717
1718	if (!first_node) {
1719		ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1720				indent * HIERARCHY_INDENT, "");
1721		if (advance_hpp_check(&dummy_hpp, ret))
1722			return ret;
1723	}
1724
1725	first_node = true;
1726	list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1727		if (!first_node) {
1728			ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1729			if (advance_hpp_check(&dummy_hpp, ret))
1730				break;
1731		}
1732		first_node = false;
1733
1734		first_col = true;
1735		perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1736			char *start;
1737
1738			if (perf_hpp__should_skip(fmt, hists))
1739				continue;
1740
1741			if (!first_col) {
1742				ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1743				if (advance_hpp_check(&dummy_hpp, ret))
1744					break;
1745			}
1746			first_col = false;
1747
1748			ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
1749			dummy_hpp.buf[ret] = '\0';
1750
1751			start = strim(dummy_hpp.buf);
1752			ret = strlen(start);
1753
1754			if (start != dummy_hpp.buf)
1755				memmove(dummy_hpp.buf, start, ret + 1);
1756
1757			if (advance_hpp_check(&dummy_hpp, ret))
1758				break;
1759		}
1760	}
1761
1762	return ret;
1763}
1764
1765static void hists_browser__hierarchy_headers(struct hist_browser *browser)
1766{
1767	char headers[1024];
1768
1769	hists_browser__scnprintf_hierarchy_headers(browser, headers,
1770						   sizeof(headers));
1771
1772	ui_browser__gotorc_title(&browser->b, 0, 0);
1773	ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1774	ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1775}
1776
1777static void hists_browser__headers(struct hist_browser *browser)
1778{
1779	struct hists *hists = browser->hists;
1780	struct perf_hpp_list *hpp_list = hists->hpp_list;
1781
1782	int line;
1783
1784	for (line = 0; line < hpp_list->nr_header_lines; line++) {
1785		char headers[1024];
1786
1787		hists_browser__scnprintf_headers(browser, headers,
1788						 sizeof(headers), line);
1789
1790		ui_browser__gotorc_title(&browser->b, line, 0);
1791		ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1792		ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1793	}
1794}
1795
1796static void hist_browser__show_headers(struct hist_browser *browser)
1797{
1798	if (symbol_conf.report_hierarchy)
1799		hists_browser__hierarchy_headers(browser);
1800	else
1801		hists_browser__headers(browser);
1802}
1803
1804static void ui_browser__hists_init_top(struct ui_browser *browser)
1805{
1806	if (browser->top == NULL) {
1807		struct hist_browser *hb;
1808
1809		hb = container_of(browser, struct hist_browser, b);
1810		browser->top = rb_first_cached(&hb->hists->entries);
1811	}
1812}
1813
1814static unsigned int hist_browser__refresh(struct ui_browser *browser)
1815{
1816	unsigned row = 0;
1817	struct rb_node *nd;
1818	struct hist_browser *hb = container_of(browser, struct hist_browser, b);
1819
1820	if (hb->show_headers)
1821		hist_browser__show_headers(hb);
1822
1823	ui_browser__hists_init_top(browser);
1824	hb->he_selection = NULL;
1825	hb->selection = NULL;
1826
1827	for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
1828		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1829		float percent;
1830
1831		if (h->filtered) {
1832			/* let it move to sibling */
1833			h->unfolded = false;
1834			continue;
1835		}
1836
1837		if (symbol_conf.report_individual_block)
1838			percent = block_info__total_cycles_percent(h);
1839		else
1840			percent = hist_entry__get_percent_limit(h);
1841
1842		if (percent < hb->min_pcnt)
1843			continue;
1844
1845		if (symbol_conf.report_hierarchy) {
1846			row += hist_browser__show_hierarchy_entry(hb, h, row,
1847								  h->depth);
1848			if (row == browser->rows)
1849				break;
1850
1851			if (h->has_no_entry) {
1852				hist_browser__show_no_entry(hb, row, h->depth + 1);
1853				row++;
1854			}
1855		} else {
1856			row += hist_browser__show_entry(hb, h, row);
1857		}
1858
1859		if (row == browser->rows)
1860			break;
1861	}
1862
1863	return row;
1864}
1865
1866static struct rb_node *hists__filter_entries(struct rb_node *nd,
1867					     float min_pcnt)
1868{
1869	while (nd != NULL) {
1870		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1871		float percent = hist_entry__get_percent_limit(h);
1872
1873		if (!h->filtered && percent >= min_pcnt)
1874			return nd;
1875
1876		/*
1877		 * If it's filtered, its all children also were filtered.
1878		 * So move to sibling node.
1879		 */
1880		if (rb_next(nd))
1881			nd = rb_next(nd);
1882		else
1883			nd = rb_hierarchy_next(nd);
1884	}
1885
1886	return NULL;
1887}
1888
1889static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
1890						  float min_pcnt)
1891{
1892	while (nd != NULL) {
1893		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1894		float percent = hist_entry__get_percent_limit(h);
1895
1896		if (!h->filtered && percent >= min_pcnt)
1897			return nd;
1898
1899		nd = rb_hierarchy_prev(nd);
1900	}
1901
1902	return NULL;
1903}
1904
1905static void ui_browser__hists_seek(struct ui_browser *browser,
1906				   off_t offset, int whence)
1907{
1908	struct hist_entry *h;
1909	struct rb_node *nd;
1910	bool first = true;
1911	struct hist_browser *hb;
1912
1913	hb = container_of(browser, struct hist_browser, b);
1914
1915	if (browser->nr_entries == 0)
1916		return;
1917
1918	ui_browser__hists_init_top(browser);
1919
1920	switch (whence) {
1921	case SEEK_SET:
1922		nd = hists__filter_entries(rb_first(browser->entries),
1923					   hb->min_pcnt);
1924		break;
1925	case SEEK_CUR:
1926		nd = browser->top;
1927		goto do_offset;
1928	case SEEK_END:
1929		nd = rb_hierarchy_last(rb_last(browser->entries));
1930		nd = hists__filter_prev_entries(nd, hb->min_pcnt);
1931		first = false;
1932		break;
1933	default:
1934		return;
1935	}
1936
1937	/*
1938	 * Moves not relative to the first visible entry invalidates its
1939	 * row_offset:
1940	 */
1941	h = rb_entry(browser->top, struct hist_entry, rb_node);
1942	h->row_offset = 0;
1943
1944	/*
1945	 * Here we have to check if nd is expanded (+), if it is we can't go
1946	 * the next top level hist_entry, instead we must compute an offset of
1947	 * what _not_ to show and not change the first visible entry.
1948	 *
1949	 * This offset increments when we are going from top to bottom and
1950	 * decreases when we're going from bottom to top.
1951	 *
1952	 * As we don't have backpointers to the top level in the callchains
1953	 * structure, we need to always print the whole hist_entry callchain,
1954	 * skipping the first ones that are before the first visible entry
1955	 * and stop when we printed enough lines to fill the screen.
1956	 */
1957do_offset:
1958	if (!nd)
1959		return;
1960
1961	if (offset > 0) {
1962		do {
1963			h = rb_entry(nd, struct hist_entry, rb_node);
1964			if (h->unfolded && h->leaf) {
1965				u16 remaining = h->nr_rows - h->row_offset;
1966				if (offset > remaining) {
1967					offset -= remaining;
1968					h->row_offset = 0;
1969				} else {
1970					h->row_offset += offset;
1971					offset = 0;
1972					browser->top = nd;
1973					break;
1974				}
1975			}
1976			nd = hists__filter_entries(rb_hierarchy_next(nd),
1977						   hb->min_pcnt);
1978			if (nd == NULL)
1979				break;
1980			--offset;
1981			browser->top = nd;
1982		} while (offset != 0);
1983	} else if (offset < 0) {
1984		while (1) {
1985			h = rb_entry(nd, struct hist_entry, rb_node);
1986			if (h->unfolded && h->leaf) {
1987				if (first) {
1988					if (-offset > h->row_offset) {
1989						offset += h->row_offset;
1990						h->row_offset = 0;
1991					} else {
1992						h->row_offset += offset;
1993						offset = 0;
1994						browser->top = nd;
1995						break;
1996					}
1997				} else {
1998					if (-offset > h->nr_rows) {
1999						offset += h->nr_rows;
2000						h->row_offset = 0;
2001					} else {
2002						h->row_offset = h->nr_rows + offset;
2003						offset = 0;
2004						browser->top = nd;
2005						break;
2006					}
2007				}
2008			}
2009
2010			nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
2011							hb->min_pcnt);
2012			if (nd == NULL)
2013				break;
2014			++offset;
2015			browser->top = nd;
2016			if (offset == 0) {
2017				/*
2018				 * Last unfiltered hist_entry, check if it is
2019				 * unfolded, if it is then we should have
2020				 * row_offset at its last entry.
2021				 */
2022				h = rb_entry(nd, struct hist_entry, rb_node);
2023				if (h->unfolded && h->leaf)
2024					h->row_offset = h->nr_rows;
2025				break;
2026			}
2027			first = false;
2028		}
2029	} else {
2030		browser->top = nd;
2031		h = rb_entry(nd, struct hist_entry, rb_node);
2032		h->row_offset = 0;
2033	}
2034}
2035
2036static int hist_browser__fprintf_callchain(struct hist_browser *browser,
2037					   struct hist_entry *he, FILE *fp,
2038					   int level)
2039{
2040	struct callchain_print_arg arg  = {
2041		.fp = fp,
2042	};
2043
2044	hist_browser__show_callchain(browser, he, level, 0,
2045				     hist_browser__fprintf_callchain_entry, &arg,
2046				     hist_browser__check_dump_full);
2047	return arg.printed;
2048}
2049
2050static int hist_browser__fprintf_entry(struct hist_browser *browser,
2051				       struct hist_entry *he, FILE *fp)
2052{
2053	char s[8192];
2054	int printed = 0;
2055	char folded_sign = ' ';
2056	struct perf_hpp hpp = {
2057		.buf = s,
2058		.size = sizeof(s),
2059	};
2060	struct perf_hpp_fmt *fmt;
2061	bool first = true;
2062	int ret;
2063
2064	if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
2065		folded_sign = hist_entry__folded(he);
2066		printed += fprintf(fp, "%c ", folded_sign);
2067	}
2068
2069	hists__for_each_format(browser->hists, fmt) {
2070		if (perf_hpp__should_skip(fmt, he->hists))
2071			continue;
2072
2073		if (!first) {
2074			ret = scnprintf(hpp.buf, hpp.size, "  ");
2075			advance_hpp(&hpp, ret);
2076		} else
2077			first = false;
2078
2079		ret = fmt->entry(fmt, &hpp, he);
2080		ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
2081		advance_hpp(&hpp, ret);
2082	}
2083	printed += fprintf(fp, "%s\n", s);
2084
2085	if (folded_sign == '-')
2086		printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
2087
2088	return printed;
2089}
2090
2091
2092static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
2093						 struct hist_entry *he,
2094						 FILE *fp, int level)
2095{
2096	char s[8192];
2097	int printed = 0;
2098	char folded_sign = ' ';
2099	struct perf_hpp hpp = {
2100		.buf = s,
2101		.size = sizeof(s),
2102	};
2103	struct perf_hpp_fmt *fmt;
2104	struct perf_hpp_list_node *fmt_node;
2105	bool first = true;
2106	int ret;
2107	int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
2108
2109	printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
2110
2111	folded_sign = hist_entry__folded(he);
2112	printed += fprintf(fp, "%c", folded_sign);
2113
2114	/* the first hpp_list_node is for overhead columns */
2115	fmt_node = list_first_entry(&he->hists->hpp_formats,
2116				    struct perf_hpp_list_node, list);
2117	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
2118		if (!first) {
2119			ret = scnprintf(hpp.buf, hpp.size, "  ");
2120			advance_hpp(&hpp, ret);
2121		} else
2122			first = false;
2123
2124		ret = fmt->entry(fmt, &hpp, he);
2125		advance_hpp(&hpp, ret);
2126	}
2127
2128	ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
2129	advance_hpp(&hpp, ret);
2130
2131	perf_hpp_list__for_each_format(he->hpp_list, fmt) {
2132		ret = scnprintf(hpp.buf, hpp.size, "  ");
2133		advance_hpp(&hpp, ret);
2134
2135		ret = fmt->entry(fmt, &hpp, he);
2136		advance_hpp(&hpp, ret);
2137	}
2138
2139	strim(s);
2140	printed += fprintf(fp, "%s\n", s);
2141
2142	if (he->leaf && folded_sign == '-') {
2143		printed += hist_browser__fprintf_callchain(browser, he, fp,
2144							   he->depth + 1);
2145	}
2146
2147	return printed;
2148}
2149
2150static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2151{
2152	struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
2153						   browser->min_pcnt);
2154	int printed = 0;
2155
2156	while (nd) {
2157		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2158
2159		if (symbol_conf.report_hierarchy) {
2160			printed += hist_browser__fprintf_hierarchy_entry(browser,
2161									 h, fp,
2162									 h->depth);
2163		} else {
2164			printed += hist_browser__fprintf_entry(browser, h, fp);
2165		}
2166
2167		nd = hists__filter_entries(rb_hierarchy_next(nd),
2168					   browser->min_pcnt);
2169	}
2170
2171	return printed;
2172}
2173
2174static int hist_browser__dump(struct hist_browser *browser)
2175{
2176	char filename[64];
2177	FILE *fp;
2178
2179	while (1) {
2180		scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2181		if (access(filename, F_OK))
2182			break;
2183		/*
2184 		 * XXX: Just an arbitrary lazy upper limit
2185 		 */
2186		if (++browser->print_seq == 8192) {
2187			ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2188			return -1;
2189		}
2190	}
2191
2192	fp = fopen(filename, "w");
2193	if (fp == NULL) {
2194		char bf[64];
2195		const char *err = str_error_r(errno, bf, sizeof(bf));
2196		ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
2197		return -1;
2198	}
2199
2200	++browser->print_seq;
2201	hist_browser__fprintf(browser, fp);
2202	fclose(fp);
2203	ui_helpline__fpush("%s written!", filename);
2204
2205	return 0;
2206}
2207
2208void hist_browser__init(struct hist_browser *browser,
2209			struct hists *hists)
2210{
2211	struct perf_hpp_fmt *fmt;
2212
2213	browser->hists			= hists;
2214	browser->b.refresh		= hist_browser__refresh;
2215	browser->b.refresh_dimensions	= hist_browser__refresh_dimensions;
2216	browser->b.seek			= ui_browser__hists_seek;
2217	browser->b.use_navkeypressed	= true;
2218	browser->show_headers		= symbol_conf.show_hist_headers;
2219	hist_browser__set_title_space(browser);
2220
2221	if (symbol_conf.report_hierarchy) {
2222		struct perf_hpp_list_node *fmt_node;
2223
2224		/* count overhead columns (in the first node) */
2225		fmt_node = list_first_entry(&hists->hpp_formats,
2226					    struct perf_hpp_list_node, list);
2227		perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
2228			++browser->b.columns;
2229
2230		/* add a single column for whole hierarchy sort keys*/
2231		++browser->b.columns;
2232	} else {
2233		hists__for_each_format(hists, fmt)
2234			++browser->b.columns;
2235	}
2236
2237	hists__reset_column_width(hists);
2238}
2239
2240struct hist_browser *hist_browser__new(struct hists *hists)
2241{
2242	struct hist_browser *browser = zalloc(sizeof(*browser));
2243
2244	if (browser)
2245		hist_browser__init(browser, hists);
2246
2247	return browser;
2248}
2249
2250static struct hist_browser *
2251perf_evsel_browser__new(struct evsel *evsel,
2252			struct hist_browser_timer *hbt,
2253			struct perf_env *env,
2254			struct annotation_options *annotation_opts)
2255{
2256	struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2257
2258	if (browser) {
2259		browser->hbt   = hbt;
2260		browser->env   = env;
2261		browser->title = hists_browser__scnprintf_title;
2262		browser->annotation_opts = annotation_opts;
2263	}
2264	return browser;
2265}
2266
2267void hist_browser__delete(struct hist_browser *browser)
2268{
2269	free(browser);
2270}
2271
2272static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
2273{
2274	return browser->he_selection;
2275}
2276
2277static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
2278{
2279	return browser->he_selection->thread;
2280}
2281
2282static struct res_sample *hist_browser__selected_res_sample(struct hist_browser *browser)
2283{
2284	return browser->he_selection ? browser->he_selection->res_samples : NULL;
2285}
2286
2287/* Check whether the browser is for 'top' or 'report' */
2288static inline bool is_report_browser(void *timer)
2289{
2290	return timer == NULL;
2291}
2292
2293static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size)
2294{
2295	struct hist_browser_timer *hbt = browser->hbt;
2296	int printed = __hists__scnprintf_title(browser->hists, bf, size, !is_report_browser(hbt));
2297
2298	if (!is_report_browser(hbt)) {
2299		struct perf_top *top = hbt->arg;
2300
2301		printed += scnprintf(bf + printed, size - printed,
2302				     " lost: %" PRIu64 "/%" PRIu64,
2303				     top->lost, top->lost_total);
2304
2305		printed += scnprintf(bf + printed, size - printed,
2306				     " drop: %" PRIu64 "/%" PRIu64,
2307				     top->drop, top->drop_total);
2308
2309		if (top->zero)
2310			printed += scnprintf(bf + printed, size - printed, " [z]");
2311
2312		perf_top__reset_sample_counters(top);
2313	}
2314
2315
2316	return printed;
2317}
2318
2319static inline void free_popup_options(char **options, int n)
2320{
2321	int i;
2322
2323	for (i = 0; i < n; ++i)
2324		zfree(&options[i]);
2325}
2326
2327/*
2328 * Only runtime switching of perf data file will make "input_name" point
2329 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2330 * whether we need to call free() for current "input_name" during the switch.
2331 */
2332static bool is_input_name_malloced = false;
2333
2334static int switch_data_file(void)
2335{
2336	char *pwd, *options[32], *abs_path[32], *tmp;
2337	DIR *pwd_dir;
2338	int nr_options = 0, choice = -1, ret = -1;
2339	struct dirent *dent;
2340
2341	pwd = getenv("PWD");
2342	if (!pwd)
2343		return ret;
2344
2345	pwd_dir = opendir(pwd);
2346	if (!pwd_dir)
2347		return ret;
2348
2349	memset(options, 0, sizeof(options));
2350	memset(abs_path, 0, sizeof(abs_path));
2351
2352	while ((dent = readdir(pwd_dir))) {
2353		char path[PATH_MAX];
2354		u64 magic;
2355		char *name = dent->d_name;
2356		FILE *file;
2357
2358		if (!(dent->d_type == DT_REG))
2359			continue;
2360
2361		snprintf(path, sizeof(path), "%s/%s", pwd, name);
2362
2363		file = fopen(path, "r");
2364		if (!file)
2365			continue;
2366
2367		if (fread(&magic, 1, 8, file) < 8)
2368			goto close_file_and_continue;
2369
2370		if (is_perf_magic(magic)) {
2371			options[nr_options] = strdup(name);
2372			if (!options[nr_options])
2373				goto close_file_and_continue;
2374
2375			abs_path[nr_options] = strdup(path);
2376			if (!abs_path[nr_options]) {
2377				zfree(&options[nr_options]);
2378				ui__warning("Can't search all data files due to memory shortage.\n");
2379				fclose(file);
2380				break;
2381			}
2382
2383			nr_options++;
2384		}
2385
2386close_file_and_continue:
2387		fclose(file);
2388		if (nr_options >= 32) {
2389			ui__warning("Too many perf data files in PWD!\n"
2390				    "Only the first 32 files will be listed.\n");
2391			break;
2392		}
2393	}
2394	closedir(pwd_dir);
2395
2396	if (nr_options) {
2397		choice = ui__popup_menu(nr_options, options, NULL);
2398		if (choice < nr_options && choice >= 0) {
2399			tmp = strdup(abs_path[choice]);
2400			if (tmp) {
2401				if (is_input_name_malloced)
2402					free((void *)input_name);
2403				input_name = tmp;
2404				is_input_name_malloced = true;
2405				ret = 0;
2406			} else
2407				ui__warning("Data switch failed due to memory shortage!\n");
2408		}
2409	}
2410
2411	free_popup_options(options, nr_options);
2412	free_popup_options(abs_path, nr_options);
2413	return ret;
2414}
2415
2416struct popup_action {
2417	unsigned long		time;
2418	struct thread 		*thread;
2419	struct map_symbol 	ms;
2420	int			socket;
2421	struct evsel	*evsel;
2422	enum rstype		rstype;
2423
2424	int (*fn)(struct hist_browser *browser, struct popup_action *act);
2425};
2426
2427static int
2428do_annotate(struct hist_browser *browser, struct popup_action *act)
2429{
2430	struct evsel *evsel;
2431	struct annotation *notes;
2432	struct hist_entry *he;
2433	int err;
2434
2435	if (!browser->annotation_opts->objdump_path &&
2436	    perf_env__lookup_objdump(browser->env, &browser->annotation_opts->objdump_path))
2437		return 0;
2438
2439	notes = symbol__annotation(act->ms.sym);
2440	if (!notes->src)
2441		return 0;
2442
2443	if (browser->block_evsel)
2444		evsel = browser->block_evsel;
2445	else
2446		evsel = hists_to_evsel(browser->hists);
2447
2448	err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt,
2449				       browser->annotation_opts);
2450	he = hist_browser__selected_entry(browser);
2451	/*
2452	 * offer option to annotate the other branch source or target
2453	 * (if they exists) when returning from annotate
2454	 */
2455	if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2456		return 1;
2457
2458	ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2459	if (err)
2460		ui_browser__handle_resize(&browser->b);
2461	return 0;
2462}
2463
2464static struct symbol *symbol__new_unresolved(u64 addr, struct map *map)
2465{
2466	struct annotated_source *src;
2467	struct symbol *sym;
2468	char name[64];
2469
2470	snprintf(name, sizeof(name), "%.*" PRIx64, BITS_PER_LONG / 4, addr);
2471
2472	sym = symbol__new(addr, ANNOTATION_DUMMY_LEN, 0, 0, name);
2473	if (sym) {
2474		src = symbol__hists(sym, 1);
2475		if (!src) {
2476			symbol__delete(sym);
2477			return NULL;
2478		}
2479
2480		dso__insert_symbol(map__dso(map), sym);
2481	}
2482
2483	return sym;
2484}
2485
2486static int
2487add_annotate_opt(struct hist_browser *browser __maybe_unused,
2488		 struct popup_action *act, char **optstr,
2489		 struct map_symbol *ms,
2490		 u64 addr)
2491{
2492	struct dso *dso;
2493
2494	if (!ms->map || (dso = map__dso(ms->map)) == NULL || dso->annotate_warned)
2495		return 0;
2496
2497	if (!ms->sym)
2498		ms->sym = symbol__new_unresolved(addr, ms->map);
2499
2500	if (ms->sym == NULL || symbol__annotation(ms->sym)->src == NULL)
2501		return 0;
2502
2503	if (asprintf(optstr, "Annotate %s", ms->sym->name) < 0)
2504		return 0;
2505
2506	act->ms = *ms;
2507	act->fn = do_annotate;
2508	return 1;
2509}
2510
2511static int
2512do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2513{
2514	struct thread *thread = act->thread;
2515
2516	if ((!hists__has(browser->hists, thread) &&
2517	     !hists__has(browser->hists, comm)) || thread == NULL)
2518		return 0;
2519
2520	if (browser->hists->thread_filter) {
2521		pstack__remove(browser->pstack, &browser->hists->thread_filter);
2522		perf_hpp__set_elide(HISTC_THREAD, false);
2523		thread__zput(browser->hists->thread_filter);
2524		ui_helpline__pop();
2525	} else {
2526		const char *comm_set_str =
2527			thread__comm_set(thread) ? thread__comm_str(thread) : "";
2528
2529		if (hists__has(browser->hists, thread)) {
2530			ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2531					   comm_set_str, thread__tid(thread));
2532		} else {
2533			ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2534					   comm_set_str);
2535		}
2536
2537		browser->hists->thread_filter = thread__get(thread);
2538		perf_hpp__set_elide(HISTC_THREAD, false);
2539		pstack__push(browser->pstack, &browser->hists->thread_filter);
2540	}
2541
2542	hists__filter_by_thread(browser->hists);
2543	hist_browser__reset(browser);
2544	return 0;
2545}
2546
2547static int
2548add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2549	       char **optstr, struct thread *thread)
2550{
2551	int ret;
2552	const char *comm_set_str, *in_out;
2553
2554	if ((!hists__has(browser->hists, thread) &&
2555	     !hists__has(browser->hists, comm)) || thread == NULL)
2556		return 0;
2557
2558	in_out = browser->hists->thread_filter ? "out of" : "into";
2559	comm_set_str = thread__comm_set(thread) ? thread__comm_str(thread) : "";
2560	if (hists__has(browser->hists, thread)) {
2561		ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2562			       in_out, comm_set_str, thread__tid(thread));
2563	} else {
2564		ret = asprintf(optstr, "Zoom %s %s thread", in_out, comm_set_str);
2565	}
2566	if (ret < 0)
2567		return 0;
2568
2569	act->thread = thread;
2570	act->fn = do_zoom_thread;
2571	return 1;
2572}
2573
2574static int hists_browser__zoom_map(struct hist_browser *browser, struct map *map)
2575{
2576	if (!hists__has(browser->hists, dso) || map == NULL)
2577		return 0;
2578
2579	if (browser->hists->dso_filter) {
2580		pstack__remove(browser->pstack, &browser->hists->dso_filter);
2581		perf_hpp__set_elide(HISTC_DSO, false);
2582		browser->hists->dso_filter = NULL;
2583		ui_helpline__pop();
2584	} else {
2585		struct dso *dso = map__dso(map);
2586		ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
2587				   __map__is_kernel(map) ? "the Kernel" : dso->short_name);
2588		browser->hists->dso_filter = dso;
2589		perf_hpp__set_elide(HISTC_DSO, true);
2590		pstack__push(browser->pstack, &browser->hists->dso_filter);
2591	}
2592
2593	hists__filter_by_dso(browser->hists);
2594	hist_browser__reset(browser);
2595	return 0;
2596}
2597
2598static int
2599do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2600{
2601	return hists_browser__zoom_map(browser, act->ms.map);
2602}
2603
2604static int
2605add_dso_opt(struct hist_browser *browser, struct popup_action *act,
2606	    char **optstr, struct map *map)
2607{
2608	if (!hists__has(browser->hists, dso) || map == NULL)
2609		return 0;
2610
2611	if (asprintf(optstr, "Zoom %s %s DSO (use the 'k' hotkey to zoom directly into the kernel)",
2612		     browser->hists->dso_filter ? "out of" : "into",
2613		     __map__is_kernel(map) ? "the Kernel" : map__dso(map)->short_name) < 0)
2614		return 0;
2615
2616	act->ms.map = map;
2617	act->fn = do_zoom_dso;
2618	return 1;
2619}
2620
2621static int do_toggle_callchain(struct hist_browser *browser, struct popup_action *act __maybe_unused)
2622{
2623	hist_browser__toggle_fold(browser);
2624	return 0;
2625}
2626
2627static int add_callchain_toggle_opt(struct hist_browser *browser, struct popup_action *act, char **optstr)
2628{
2629	char sym_name[512];
2630
2631        if (!hist_browser__selection_has_children(browser))
2632                return 0;
2633
2634	if (asprintf(optstr, "%s [%s] callchain (one level, same as '+' hotkey, use 'e'/'c' for the whole main level entry)",
2635		     hist_browser__selection_unfolded(browser) ? "Collapse" : "Expand",
2636		     hist_browser__selection_sym_name(browser, sym_name, sizeof(sym_name))) < 0)
2637		return 0;
2638
2639	act->fn = do_toggle_callchain;
2640	return 1;
2641}
2642
2643static int
2644do_browse_map(struct hist_browser *browser __maybe_unused,
2645	      struct popup_action *act)
2646{
2647	map__browse(act->ms.map);
2648	return 0;
2649}
2650
2651static int
2652add_map_opt(struct hist_browser *browser,
2653	    struct popup_action *act, char **optstr, struct map *map)
2654{
2655	if (!hists__has(browser->hists, dso) || map == NULL)
2656		return 0;
2657
2658	if (asprintf(optstr, "Browse map details") < 0)
2659		return 0;
2660
2661	act->ms.map = map;
2662	act->fn = do_browse_map;
2663	return 1;
2664}
2665
2666static int
2667do_run_script(struct hist_browser *browser __maybe_unused,
2668	      struct popup_action *act)
2669{
2670	char *script_opt;
2671	int len;
2672	int n = 0;
2673
2674	len = 100;
2675	if (act->thread)
2676		len += strlen(thread__comm_str(act->thread));
2677	else if (act->ms.sym)
2678		len += strlen(act->ms.sym->name);
2679	script_opt = malloc(len);
2680	if (!script_opt)
2681		return -1;
2682
2683	script_opt[0] = 0;
2684	if (act->thread) {
2685		n = scnprintf(script_opt, len, " -c %s ",
2686			  thread__comm_str(act->thread));
2687	} else if (act->ms.sym) {
2688		n = scnprintf(script_opt, len, " -S %s ",
2689			  act->ms.sym->name);
2690	}
2691
2692	if (act->time) {
2693		char start[32], end[32];
2694		unsigned long starttime = act->time;
2695		unsigned long endtime = act->time + symbol_conf.time_quantum;
2696
2697		if (starttime == endtime) { /* Display 1ms as fallback */
2698			starttime -= 1*NSEC_PER_MSEC;
2699			endtime += 1*NSEC_PER_MSEC;
2700		}
2701		timestamp__scnprintf_usec(starttime, start, sizeof start);
2702		timestamp__scnprintf_usec(endtime, end, sizeof end);
2703		n += snprintf(script_opt + n, len - n, " --time %s,%s", start, end);
2704	}
2705
2706	script_browse(script_opt, act->evsel);
2707	free(script_opt);
2708	return 0;
2709}
2710
2711static int
2712do_res_sample_script(struct hist_browser *browser __maybe_unused,
2713		     struct popup_action *act)
2714{
2715	struct hist_entry *he;
2716
2717	he = hist_browser__selected_entry(browser);
2718	res_sample_browse(he->res_samples, he->num_res, act->evsel, act->rstype);
2719	return 0;
2720}
2721
2722static int
2723add_script_opt_2(struct hist_browser *browser __maybe_unused,
2724	       struct popup_action *act, char **optstr,
2725	       struct thread *thread, struct symbol *sym,
2726	       struct evsel *evsel, const char *tstr)
2727{
2728
2729	if (thread) {
2730		if (asprintf(optstr, "Run scripts for samples of thread [%s]%s",
2731			     thread__comm_str(thread), tstr) < 0)
2732			return 0;
2733	} else if (sym) {
2734		if (asprintf(optstr, "Run scripts for samples of symbol [%s]%s",
2735			     sym->name, tstr) < 0)
2736			return 0;
2737	} else {
2738		if (asprintf(optstr, "Run scripts for all samples%s", tstr) < 0)
2739			return 0;
2740	}
2741
2742	act->thread = thread;
2743	act->ms.sym = sym;
2744	act->evsel = evsel;
2745	act->fn = do_run_script;
2746	return 1;
2747}
2748
2749static int
2750add_script_opt(struct hist_browser *browser,
2751	       struct popup_action *act, char **optstr,
2752	       struct thread *thread, struct symbol *sym,
2753	       struct evsel *evsel)
2754{
2755	int n, j;
2756	struct hist_entry *he;
2757
2758	n = add_script_opt_2(browser, act, optstr, thread, sym, evsel, "");
2759
2760	he = hist_browser__selected_entry(browser);
2761	if (sort_order && strstr(sort_order, "time")) {
2762		char tstr[128];
2763
2764		optstr++;
2765		act++;
2766		j = sprintf(tstr, " in ");
2767		j += timestamp__scnprintf_usec(he->time, tstr + j,
2768					       sizeof tstr - j);
2769		j += sprintf(tstr + j, "-");
2770		timestamp__scnprintf_usec(he->time + symbol_conf.time_quantum,
2771				          tstr + j, sizeof tstr - j);
2772		n += add_script_opt_2(browser, act, optstr, thread, sym,
2773					  evsel, tstr);
2774		act->time = he->time;
2775	}
2776	return n;
2777}
2778
2779static int
2780add_res_sample_opt(struct hist_browser *browser __maybe_unused,
2781		   struct popup_action *act, char **optstr,
2782		   struct res_sample *res_sample,
2783		   struct evsel *evsel,
2784		   enum rstype type)
2785{
2786	if (!res_sample)
2787		return 0;
2788
2789	if (asprintf(optstr, "Show context for individual samples %s",
2790		type == A_ASM ? "with assembler" :
2791		type == A_SOURCE ? "with source" : "") < 0)
2792		return 0;
2793
2794	act->fn = do_res_sample_script;
2795	act->evsel = evsel;
2796	act->rstype = type;
2797	return 1;
2798}
2799
2800static int
2801do_switch_data(struct hist_browser *browser __maybe_unused,
2802	       struct popup_action *act __maybe_unused)
2803{
2804	if (switch_data_file()) {
2805		ui__warning("Won't switch the data files due to\n"
2806			    "no valid data file get selected!\n");
2807		return 0;
2808	}
2809
2810	return K_SWITCH_INPUT_DATA;
2811}
2812
2813static int
2814add_switch_opt(struct hist_browser *browser,
2815	       struct popup_action *act, char **optstr)
2816{
2817	if (!is_report_browser(browser->hbt))
2818		return 0;
2819
2820	if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2821		return 0;
2822
2823	act->fn = do_switch_data;
2824	return 1;
2825}
2826
2827static int
2828do_exit_browser(struct hist_browser *browser __maybe_unused,
2829		struct popup_action *act __maybe_unused)
2830{
2831	return 0;
2832}
2833
2834static int
2835add_exit_opt(struct hist_browser *browser __maybe_unused,
2836	     struct popup_action *act, char **optstr)
2837{
2838	if (asprintf(optstr, "Exit") < 0)
2839		return 0;
2840
2841	act->fn = do_exit_browser;
2842	return 1;
2843}
2844
2845static int
2846do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2847{
2848	if (!hists__has(browser->hists, socket) || act->socket < 0)
2849		return 0;
2850
2851	if (browser->hists->socket_filter > -1) {
2852		pstack__remove(browser->pstack, &browser->hists->socket_filter);
2853		browser->hists->socket_filter = -1;
2854		perf_hpp__set_elide(HISTC_SOCKET, false);
2855	} else {
2856		browser->hists->socket_filter = act->socket;
2857		perf_hpp__set_elide(HISTC_SOCKET, true);
2858		pstack__push(browser->pstack, &browser->hists->socket_filter);
2859	}
2860
2861	hists__filter_by_socket(browser->hists);
2862	hist_browser__reset(browser);
2863	return 0;
2864}
2865
2866static int
2867add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2868	       char **optstr, int socket_id)
2869{
2870	if (!hists__has(browser->hists, socket) || socket_id < 0)
2871		return 0;
2872
2873	if (asprintf(optstr, "Zoom %s Processor Socket %d",
2874		     (browser->hists->socket_filter > -1) ? "out of" : "into",
2875		     socket_id) < 0)
2876		return 0;
2877
2878	act->socket = socket_id;
2879	act->fn = do_zoom_socket;
2880	return 1;
2881}
2882
2883static void hist_browser__update_nr_entries(struct hist_browser *hb)
2884{
2885	u64 nr_entries = 0;
2886	struct rb_node *nd = rb_first_cached(&hb->hists->entries);
2887
2888	if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
2889		hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2890		return;
2891	}
2892
2893	while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2894		nr_entries++;
2895		nd = rb_hierarchy_next(nd);
2896	}
2897
2898	hb->nr_non_filtered_entries = nr_entries;
2899	hb->nr_hierarchy_entries = nr_entries;
2900}
2901
2902static void hist_browser__update_percent_limit(struct hist_browser *hb,
2903					       double percent)
2904{
2905	struct hist_entry *he;
2906	struct rb_node *nd = rb_first_cached(&hb->hists->entries);
2907	u64 total = hists__total_period(hb->hists);
2908	u64 min_callchain_hits = total * (percent / 100);
2909
2910	hb->min_pcnt = callchain_param.min_percent = percent;
2911
2912	while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2913		he = rb_entry(nd, struct hist_entry, rb_node);
2914
2915		if (he->has_no_entry) {
2916			he->has_no_entry = false;
2917			he->nr_rows = 0;
2918		}
2919
2920		if (!he->leaf || !hist_entry__has_callchains(he) || !symbol_conf.use_callchain)
2921			goto next;
2922
2923		if (callchain_param.mode == CHAIN_GRAPH_REL) {
2924			total = he->stat.period;
2925
2926			if (symbol_conf.cumulate_callchain)
2927				total = he->stat_acc->period;
2928
2929			min_callchain_hits = total * (percent / 100);
2930		}
2931
2932		callchain_param.sort(&he->sorted_chain, he->callchain,
2933				     min_callchain_hits, &callchain_param);
2934
2935next:
2936		nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
2937
2938		/* force to re-evaluate folding state of callchains */
2939		he->init_have_children = false;
2940		hist_entry__set_folding(he, hb, false);
2941	}
2942}
2943
2944static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *helpline,
2945			       bool left_exits, struct hist_browser_timer *hbt, float min_pcnt,
2946			       struct perf_env *env, bool warn_lost_event,
2947			       struct annotation_options *annotation_opts)
2948{
2949	struct hists *hists = evsel__hists(evsel);
2950	struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env, annotation_opts);
2951	struct branch_info *bi = NULL;
2952#define MAX_OPTIONS  16
2953	char *options[MAX_OPTIONS];
2954	struct popup_action actions[MAX_OPTIONS];
2955	int nr_options = 0;
2956	int key = -1;
2957	char buf[128];
2958	int delay_secs = hbt ? hbt->refresh : 0;
2959
2960#define HIST_BROWSER_HELP_COMMON					\
2961	"h/?/F1        Show this window\n"				\
2962	"UP/DOWN/PGUP\n"						\
2963	"PGDN/SPACE    Navigate\n"					\
2964	"q/ESC/CTRL+C  Exit browser or go back to previous screen\n\n"	\
2965	"For multiple event sessions:\n\n"				\
2966	"TAB/UNTAB     Switch events\n\n"				\
2967	"For symbolic views (--sort has sym):\n\n"			\
2968	"ENTER         Zoom into DSO/Threads & Annotate current symbol\n" \
2969	"ESC           Zoom out\n"					\
2970	"+             Expand/Collapse one callchain level\n"		\
2971	"a             Annotate current symbol\n"			\
2972	"C             Collapse all callchains\n"			\
2973	"d             Zoom into current DSO\n"				\
2974	"e             Expand/Collapse main entry callchains\n"	\
2975	"E             Expand all callchains\n"				\
2976	"F             Toggle percentage of filtered entries\n"		\
2977	"H             Display column headers\n"			\
2978	"k             Zoom into the kernel map\n"			\
2979	"L             Change percent limit\n"				\
2980	"m             Display context menu\n"				\
2981	"S             Zoom into current Processor Socket\n"		\
2982
2983	/* help messages are sorted by lexical order of the hotkey */
2984	static const char report_help[] = HIST_BROWSER_HELP_COMMON
2985	"i             Show header information\n"
2986	"P             Print histograms to perf.hist.N\n"
2987	"r             Run available scripts\n"
2988	"s             Switch to another data file in PWD\n"
2989	"t             Zoom into current Thread\n"
2990	"V             Verbose (DSO names in callchains, etc)\n"
2991	"/             Filter symbol by name\n"
2992	"0-9           Sort by event n in group";
2993	static const char top_help[] = HIST_BROWSER_HELP_COMMON
2994	"P             Print histograms to perf.hist.N\n"
2995	"t             Zoom into current Thread\n"
2996	"V             Verbose (DSO names in callchains, etc)\n"
2997	"z             Toggle zeroing of samples\n"
2998	"f             Enable/Disable events\n"
2999	"/             Filter symbol by name";
3000
3001	if (browser == NULL)
3002		return -1;
3003
3004	/* reset abort key so that it can get Ctrl-C as a key */
3005	SLang_reset_tty();
3006	SLang_init_tty(0, 0, 0);
3007
3008	if (min_pcnt)
3009		browser->min_pcnt = min_pcnt;
3010	hist_browser__update_nr_entries(browser);
3011
3012	browser->pstack = pstack__new(3);
3013	if (browser->pstack == NULL)
3014		goto out;
3015
3016	ui_helpline__push(helpline);
3017
3018	memset(options, 0, sizeof(options));
3019	memset(actions, 0, sizeof(actions));
3020
3021	if (symbol_conf.col_width_list_str)
3022		perf_hpp__set_user_width(symbol_conf.col_width_list_str);
3023
3024	if (!is_report_browser(hbt))
3025		browser->b.no_samples_msg = "Collecting samples...";
3026
3027	while (1) {
3028		struct thread *thread = NULL;
3029		struct map *map = NULL;
3030		int choice;
3031		int socked_id = -1;
3032
3033		key = 0; // reset key
3034do_hotkey:		 // key came straight from options ui__popup_menu()
3035		choice = nr_options = 0;
3036		key = hist_browser__run(browser, helpline, warn_lost_event, key);
3037
3038		if (browser->he_selection != NULL) {
3039			thread = hist_browser__selected_thread(browser);
3040			map = browser->selection->map;
3041			socked_id = browser->he_selection->socket;
3042		}
3043		switch (key) {
3044		case K_TAB:
3045		case K_UNTAB:
3046			if (nr_events == 1)
3047				continue;
3048			/*
3049			 * Exit the browser, let hists__browser_tree
3050			 * go to the next or previous
3051			 */
3052			goto out_free_stack;
3053		case '0' ... '9':
3054			if (!symbol_conf.event_group ||
3055			    evsel->core.nr_members < 2) {
3056				snprintf(buf, sizeof(buf),
3057					 "Sort by index only available with group events!");
3058				helpline = buf;
3059				continue;
3060			}
3061
3062			if (key - '0' == symbol_conf.group_sort_idx)
3063				continue;
3064
3065			symbol_conf.group_sort_idx = key - '0';
3066
3067			if (symbol_conf.group_sort_idx >= evsel->core.nr_members) {
3068				snprintf(buf, sizeof(buf),
3069					 "Max event group index to sort is %d (index from 0 to %d)",
3070					 evsel->core.nr_members - 1,
3071					 evsel->core.nr_members - 1);
3072				helpline = buf;
3073				continue;
3074			}
3075
3076			key = K_RELOAD;
3077			goto out_free_stack;
3078		case 'a':
3079			if (!hists__has(hists, sym)) {
3080				ui_browser__warning(&browser->b, delay_secs * 2,
3081			"Annotation is only available for symbolic views, "
3082			"include \"sym*\" in --sort to use it.");
3083				continue;
3084			}
3085
3086			if (!browser->selection ||
3087			    !browser->selection->map ||
3088			    !map__dso(browser->selection->map) ||
3089			    map__dso(browser->selection->map)->annotate_warned) {
3090				continue;
3091			}
3092
3093			if (!browser->selection->sym) {
3094				if (!browser->he_selection)
3095					continue;
3096
3097				if (sort__mode == SORT_MODE__BRANCH) {
3098					bi = browser->he_selection->branch_info;
3099					if (!bi || !bi->to.ms.map)
3100						continue;
3101
3102					actions->ms.sym = symbol__new_unresolved(bi->to.al_addr, bi->to.ms.map);
3103					actions->ms.map = bi->to.ms.map;
3104				} else {
3105					actions->ms.sym = symbol__new_unresolved(browser->he_selection->ip,
3106										 browser->selection->map);
3107					actions->ms.map = browser->selection->map;
3108				}
3109
3110				if (!actions->ms.sym)
3111					continue;
3112			} else {
3113				if (symbol__annotation(browser->selection->sym)->src == NULL) {
3114					ui_browser__warning(&browser->b, delay_secs * 2,
3115						"No samples for the \"%s\" symbol.\n\n"
3116						"Probably appeared just in a callchain",
3117						browser->selection->sym->name);
3118					continue;
3119				}
3120
3121				actions->ms.map = browser->selection->map;
3122				actions->ms.sym = browser->selection->sym;
3123			}
3124
3125			do_annotate(browser, actions);
3126			continue;
3127		case 'P':
3128			hist_browser__dump(browser);
3129			continue;
3130		case 'd':
3131			actions->ms.map = map;
3132			do_zoom_dso(browser, actions);
3133			continue;
3134		case 'k':
3135			if (browser->selection != NULL)
3136				hists_browser__zoom_map(browser,
3137					      maps__machine(browser->selection->maps)->vmlinux_map);
3138			continue;
3139		case 'V':
3140			verbose = (verbose + 1) % 4;
3141			browser->show_dso = verbose > 0;
3142			ui_helpline__fpush("Verbosity level set to %d\n",
3143					   verbose);
3144			continue;
3145		case 't':
3146			actions->thread = thread;
3147			do_zoom_thread(browser, actions);
3148			continue;
3149		case 'S':
3150			actions->socket = socked_id;
3151			do_zoom_socket(browser, actions);
3152			continue;
3153		case '/':
3154			if (ui_browser__input_window("Symbol to show",
3155					"Please enter the name of symbol you want to see.\n"
3156					"To remove the filter later, press / + ENTER.",
3157					buf, "ENTER: OK, ESC: Cancel",
3158					delay_secs * 2) == K_ENTER) {
3159				hists->symbol_filter_str = *buf ? buf : NULL;
3160				hists__filter_by_symbol(hists);
3161				hist_browser__reset(browser);
3162			}
3163			continue;
3164		case 'r':
3165			if (is_report_browser(hbt)) {
3166				actions->thread = NULL;
3167				actions->ms.sym = NULL;
3168				do_run_script(browser, actions);
3169			}
3170			continue;
3171		case 's':
3172			if (is_report_browser(hbt)) {
3173				key = do_switch_data(browser, actions);
3174				if (key == K_SWITCH_INPUT_DATA)
3175					goto out_free_stack;
3176			}
3177			continue;
3178		case 'i':
3179			/* env->arch is NULL for live-mode (i.e. perf top) */
3180			if (env->arch)
3181				tui__header_window(env);
3182			continue;
3183		case 'F':
3184			symbol_conf.filter_relative ^= 1;
3185			continue;
3186		case 'z':
3187			if (!is_report_browser(hbt)) {
3188				struct perf_top *top = hbt->arg;
3189
3190				top->zero = !top->zero;
3191			}
3192			continue;
3193		case 'L':
3194			if (ui_browser__input_window("Percent Limit",
3195					"Please enter the value you want to hide entries under that percent.",
3196					buf, "ENTER: OK, ESC: Cancel",
3197					delay_secs * 2) == K_ENTER) {
3198				char *end;
3199				double new_percent = strtod(buf, &end);
3200
3201				if (new_percent < 0 || new_percent > 100) {
3202					ui_browser__warning(&browser->b, delay_secs * 2,
3203						"Invalid percent: %.2f", new_percent);
3204					continue;
3205				}
3206
3207				hist_browser__update_percent_limit(browser, new_percent);
3208				hist_browser__reset(browser);
3209			}
3210			continue;
3211		case K_F1:
3212		case 'h':
3213		case '?':
3214			ui_browser__help_window(&browser->b,
3215				is_report_browser(hbt) ? report_help : top_help);
3216			continue;
3217		case K_ENTER:
3218		case K_RIGHT:
3219		case 'm':
3220			/* menu */
3221			break;
3222		case K_ESC:
3223		case K_LEFT: {
3224			const void *top;
3225
3226			if (pstack__empty(browser->pstack)) {
3227				/*
3228				 * Go back to the perf_evsel_menu__run or other user
3229				 */
3230				if (left_exits)
3231					goto out_free_stack;
3232
3233				if (key == K_ESC &&
3234				    ui_browser__dialog_yesno(&browser->b,
3235							     "Do you really want to exit?"))
3236					goto out_free_stack;
3237
3238				continue;
3239			}
3240			actions->ms.map = map;
3241			top = pstack__peek(browser->pstack);
3242			if (top == &browser->hists->dso_filter) {
3243				/*
3244				 * No need to set actions->dso here since
3245				 * it's just to remove the current filter.
3246				 * Ditto for thread below.
3247				 */
3248				do_zoom_dso(browser, actions);
3249			} else if (top == &browser->hists->thread_filter) {
3250				do_zoom_thread(browser, actions);
3251			} else if (top == &browser->hists->socket_filter) {
3252				do_zoom_socket(browser, actions);
3253			}
3254			continue;
3255		}
3256		case 'q':
3257		case CTRL('c'):
3258			goto out_free_stack;
3259		case 'f':
3260			if (!is_report_browser(hbt)) {
3261				struct perf_top *top = hbt->arg;
3262
3263				evlist__toggle_enable(top->evlist);
3264				/*
3265				 * No need to refresh, resort/decay histogram
3266				 * entries if we are not collecting samples:
3267				 */
3268				if (top->evlist->enabled) {
3269					helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
3270					hbt->refresh = delay_secs;
3271				} else {
3272					helpline = "Press 'f' again to re-enable the events";
3273					hbt->refresh = 0;
3274				}
3275				continue;
3276			}
3277			/* Fall thru */
3278		default:
3279			helpline = "Press '?' for help on key bindings";
3280			continue;
3281		}
3282
3283		if (!hists__has(hists, sym) || browser->selection == NULL)
3284			goto skip_annotation;
3285
3286		if (sort__mode == SORT_MODE__BRANCH) {
3287
3288			if (browser->he_selection)
3289				bi = browser->he_selection->branch_info;
3290
3291			if (bi == NULL)
3292				goto skip_annotation;
3293
3294			nr_options += add_annotate_opt(browser,
3295						       &actions[nr_options],
3296						       &options[nr_options],
3297						       &bi->from.ms,
3298						       bi->from.al_addr);
3299			if (bi->to.ms.sym != bi->from.ms.sym)
3300				nr_options += add_annotate_opt(browser,
3301							&actions[nr_options],
3302							&options[nr_options],
3303							&bi->to.ms,
3304							bi->to.al_addr);
3305		} else {
3306			nr_options += add_annotate_opt(browser,
3307						       &actions[nr_options],
3308						       &options[nr_options],
3309						       browser->selection,
3310						       browser->he_selection->ip);
3311		}
3312skip_annotation:
3313		nr_options += add_thread_opt(browser, &actions[nr_options],
3314					     &options[nr_options], thread);
3315		nr_options += add_dso_opt(browser, &actions[nr_options],
3316					  &options[nr_options], map);
3317		nr_options += add_callchain_toggle_opt(browser, &actions[nr_options], &options[nr_options]);
3318		nr_options += add_map_opt(browser, &actions[nr_options],
3319					  &options[nr_options],
3320					  browser->selection ?
3321						browser->selection->map : NULL);
3322		nr_options += add_socket_opt(browser, &actions[nr_options],
3323					     &options[nr_options],
3324					     socked_id);
3325		/* perf script support */
3326		if (!is_report_browser(hbt))
3327			goto skip_scripting;
3328
3329		if (browser->he_selection) {
3330			if (hists__has(hists, thread) && thread) {
3331				nr_options += add_script_opt(browser,
3332							     &actions[nr_options],
3333							     &options[nr_options],
3334							     thread, NULL, evsel);
3335			}
3336			/*
3337			 * Note that browser->selection != NULL
3338			 * when browser->he_selection is not NULL,
3339			 * so we don't need to check browser->selection
3340			 * before fetching browser->selection->sym like what
3341			 * we do before fetching browser->selection->map.
3342			 *
3343			 * See hist_browser__show_entry.
3344			 */
3345			if (hists__has(hists, sym) && browser->selection->sym) {
3346				nr_options += add_script_opt(browser,
3347							     &actions[nr_options],
3348							     &options[nr_options],
3349							     NULL, browser->selection->sym,
3350							     evsel);
3351			}
3352		}
3353		nr_options += add_script_opt(browser, &actions[nr_options],
3354					     &options[nr_options], NULL, NULL, evsel);
3355		nr_options += add_res_sample_opt(browser, &actions[nr_options],
3356						 &options[nr_options],
3357						 hist_browser__selected_res_sample(browser),
3358						 evsel, A_NORMAL);
3359		nr_options += add_res_sample_opt(browser, &actions[nr_options],
3360						 &options[nr_options],
3361						 hist_browser__selected_res_sample(browser),
3362						 evsel, A_ASM);
3363		nr_options += add_res_sample_opt(browser, &actions[nr_options],
3364						 &options[nr_options],
3365						 hist_browser__selected_res_sample(browser),
3366						 evsel, A_SOURCE);
3367		nr_options += add_switch_opt(browser, &actions[nr_options],
3368					     &options[nr_options]);
3369skip_scripting:
3370		nr_options += add_exit_opt(browser, &actions[nr_options],
3371					   &options[nr_options]);
3372
3373		do {
3374			struct popup_action *act;
3375
3376			choice = ui__popup_menu(nr_options, options, &key);
3377			if (choice == -1)
3378				break;
3379
3380			if (choice == nr_options)
3381				goto do_hotkey;
3382
3383			act = &actions[choice];
3384			key = act->fn(browser, act);
3385		} while (key == 1);
3386
3387		if (key == K_SWITCH_INPUT_DATA)
3388			break;
3389	}
3390out_free_stack:
3391	pstack__delete(browser->pstack);
3392out:
3393	hist_browser__delete(browser);
3394	free_popup_options(options, MAX_OPTIONS);
3395	return key;
3396}
3397
3398struct evsel_menu {
3399	struct ui_browser b;
3400	struct evsel *selection;
3401	struct annotation_options *annotation_opts;
3402	bool lost_events, lost_events_warned;
3403	float min_pcnt;
3404	struct perf_env *env;
3405};
3406
3407static void perf_evsel_menu__write(struct ui_browser *browser,
3408				   void *entry, int row)
3409{
3410	struct evsel_menu *menu = container_of(browser,
3411						    struct evsel_menu, b);
3412	struct evsel *evsel = list_entry(entry, struct evsel, core.node);
3413	struct hists *hists = evsel__hists(evsel);
3414	bool current_entry = ui_browser__is_current_entry(browser, row);
3415	unsigned long nr_events = hists->stats.nr_samples;
3416	const char *ev_name = evsel__name(evsel);
3417	char bf[256], unit;
3418	const char *warn = " ";
3419	size_t printed;
3420
3421	ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3422						       HE_COLORSET_NORMAL);
3423
3424	if (evsel__is_group_event(evsel)) {
3425		struct evsel *pos;
3426
3427		ev_name = evsel__group_name(evsel);
3428
3429		for_each_group_member(pos, evsel) {
3430			struct hists *pos_hists = evsel__hists(pos);
3431			nr_events += pos_hists->stats.nr_samples;
3432		}
3433	}
3434
3435	nr_events = convert_unit(nr_events, &unit);
3436	printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
3437			   unit, unit == ' ' ? "" : " ", ev_name);
3438	ui_browser__printf(browser, "%s", bf);
3439
3440	nr_events = evsel->evlist->stats.nr_events[PERF_RECORD_LOST];
3441	if (nr_events != 0) {
3442		menu->lost_events = true;
3443		if (!current_entry)
3444			ui_browser__set_color(browser, HE_COLORSET_TOP);
3445		nr_events = convert_unit(nr_events, &unit);
3446		printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3447				     nr_events, unit, unit == ' ' ? "" : " ");
3448		warn = bf;
3449	}
3450
3451	ui_browser__write_nstring(browser, warn, browser->width - printed);
3452
3453	if (current_entry)
3454		menu->selection = evsel;
3455}
3456
3457static int perf_evsel_menu__run(struct evsel_menu *menu,
3458				int nr_events, const char *help,
3459				struct hist_browser_timer *hbt,
3460				bool warn_lost_event)
3461{
3462	struct evlist *evlist = menu->b.priv;
3463	struct evsel *pos;
3464	const char *title = "Available samples";
3465	int delay_secs = hbt ? hbt->refresh : 0;
3466	int key;
3467
3468	if (ui_browser__show(&menu->b, title,
3469			     "ESC: exit, ENTER|->: Browse histograms") < 0)
3470		return -1;
3471
3472	while (1) {
3473		key = ui_browser__run(&menu->b, delay_secs);
3474
3475		switch (key) {
3476		case K_TIMER:
3477			if (hbt)
3478				hbt->timer(hbt->arg);
3479
3480			if (!menu->lost_events_warned &&
3481			    menu->lost_events &&
3482			    warn_lost_event) {
3483				ui_browser__warn_lost_events(&menu->b);
3484				menu->lost_events_warned = true;
3485			}
3486			continue;
3487		case K_RIGHT:
3488		case K_ENTER:
3489			if (!menu->selection)
3490				continue;
3491			pos = menu->selection;
3492browse_hists:
3493			evlist__set_selected(evlist, pos);
3494			/*
3495			 * Give the calling tool a chance to populate the non
3496			 * default evsel resorted hists tree.
3497			 */
3498			if (hbt)
3499				hbt->timer(hbt->arg);
3500			key = evsel__hists_browse(pos, nr_events, help, true, hbt,
3501						  menu->min_pcnt, menu->env,
3502						  warn_lost_event,
3503						  menu->annotation_opts);
3504			ui_browser__show_title(&menu->b, title);
3505			switch (key) {
3506			case K_TAB:
3507				if (pos->core.node.next == &evlist->core.entries)
3508					pos = evlist__first(evlist);
3509				else
3510					pos = evsel__next(pos);
3511				goto browse_hists;
3512			case K_UNTAB:
3513				if (pos->core.node.prev == &evlist->core.entries)
3514					pos = evlist__last(evlist);
3515				else
3516					pos = evsel__prev(pos);
3517				goto browse_hists;
3518			case K_SWITCH_INPUT_DATA:
3519			case K_RELOAD:
3520			case 'q':
3521			case CTRL('c'):
3522				goto out;
3523			case K_ESC:
3524			default:
3525				continue;
3526			}
3527		case K_LEFT:
3528			continue;
3529		case K_ESC:
3530			if (!ui_browser__dialog_yesno(&menu->b,
3531					       "Do you really want to exit?"))
3532				continue;
3533			/* Fall thru */
3534		case 'q':
3535		case CTRL('c'):
3536			goto out;
3537		default:
3538			continue;
3539		}
3540	}
3541
3542out:
3543	ui_browser__hide(&menu->b);
3544	return key;
3545}
3546
3547static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
3548				 void *entry)
3549{
3550	struct evsel *evsel = list_entry(entry, struct evsel, core.node);
3551
3552	if (symbol_conf.event_group && !evsel__is_group_leader(evsel))
3553		return true;
3554
3555	return false;
3556}
3557
3558static int __evlist__tui_browse_hists(struct evlist *evlist, int nr_entries, const char *help,
3559				      struct hist_browser_timer *hbt, float min_pcnt, struct perf_env *env,
3560				      bool warn_lost_event, struct annotation_options *annotation_opts)
3561{
3562	struct evsel *pos;
3563	struct evsel_menu menu = {
3564		.b = {
3565			.entries    = &evlist->core.entries,
3566			.refresh    = ui_browser__list_head_refresh,
3567			.seek	    = ui_browser__list_head_seek,
3568			.write	    = perf_evsel_menu__write,
3569			.filter	    = filter_group_entries,
3570			.nr_entries = nr_entries,
3571			.priv	    = evlist,
3572		},
3573		.min_pcnt = min_pcnt,
3574		.env = env,
3575		.annotation_opts = annotation_opts,
3576	};
3577
3578	ui_helpline__push("Press ESC to exit");
3579
3580	evlist__for_each_entry(evlist, pos) {
3581		const char *ev_name = evsel__name(pos);
3582		size_t line_len = strlen(ev_name) + 7;
3583
3584		if (menu.b.width < line_len)
3585			menu.b.width = line_len;
3586	}
3587
3588	return perf_evsel_menu__run(&menu, nr_entries, help,
3589				    hbt, warn_lost_event);
3590}
3591
3592static bool evlist__single_entry(struct evlist *evlist)
3593{
3594	int nr_entries = evlist->core.nr_entries;
3595
3596	if (nr_entries == 1)
3597	       return true;
3598
3599	if (nr_entries == 2) {
3600		struct evsel *last = evlist__last(evlist);
3601
3602		if (evsel__is_dummy_event(last))
3603			return true;
3604	}
3605
3606	return false;
3607}
3608
3609int evlist__tui_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt,
3610			     float min_pcnt, struct perf_env *env, bool warn_lost_event,
3611			     struct annotation_options *annotation_opts)
3612{
3613	int nr_entries = evlist->core.nr_entries;
3614
3615	if (evlist__single_entry(evlist)) {
3616single_entry: {
3617		struct evsel *first = evlist__first(evlist);
3618
3619		return evsel__hists_browse(first, nr_entries, help, false, hbt, min_pcnt,
3620					   env, warn_lost_event, annotation_opts);
3621	}
3622	}
3623
3624	if (symbol_conf.event_group) {
3625		struct evsel *pos;
3626
3627		nr_entries = 0;
3628		evlist__for_each_entry(evlist, pos) {
3629			if (evsel__is_group_leader(pos))
3630				nr_entries++;
3631		}
3632
3633		if (nr_entries == 1)
3634			goto single_entry;
3635	}
3636
3637	return __evlist__tui_browse_hists(evlist, nr_entries, help, hbt, min_pcnt, env,
3638					  warn_lost_event, annotation_opts);
3639}
3640
3641static int block_hists_browser__title(struct hist_browser *browser, char *bf,
3642				      size_t size)
3643{
3644	struct hists *hists = evsel__hists(browser->block_evsel);
3645	const char *evname = evsel__name(browser->block_evsel);
3646	unsigned long nr_samples = hists->stats.nr_samples;
3647	int ret;
3648
3649	ret = scnprintf(bf, size, "# Samples: %lu", nr_samples);
3650	if (evname)
3651		scnprintf(bf + ret, size -  ret, " of event '%s'", evname);
3652
3653	return 0;
3654}
3655
3656int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,
3657			   float min_percent, struct perf_env *env,
3658			   struct annotation_options *annotation_opts)
3659{
3660	struct hists *hists = &bh->block_hists;
3661	struct hist_browser *browser;
3662	int key = -1;
3663	struct popup_action action;
3664	static const char help[] =
3665	" q             Quit \n";
3666
3667	browser = hist_browser__new(hists);
3668	if (!browser)
3669		return -1;
3670
3671	browser->block_evsel = evsel;
3672	browser->title = block_hists_browser__title;
3673	browser->min_pcnt = min_percent;
3674	browser->env = env;
3675	browser->annotation_opts = annotation_opts;
3676
3677	/* reset abort key so that it can get Ctrl-C as a key */
3678	SLang_reset_tty();
3679	SLang_init_tty(0, 0, 0);
3680
3681	memset(&action, 0, sizeof(action));
3682
3683	while (1) {
3684		key = hist_browser__run(browser, "? - help", true, 0);
3685
3686		switch (key) {
3687		case 'q':
3688			goto out;
3689		case '?':
3690			ui_browser__help_window(&browser->b, help);
3691			break;
3692		case 'a':
3693		case K_ENTER:
3694			if (!browser->selection ||
3695			    !browser->selection->sym) {
3696				continue;
3697			}
3698
3699			action.ms.map = browser->selection->map;
3700			action.ms.sym = browser->selection->sym;
3701			do_annotate(browser, &action);
3702			continue;
3703		default:
3704			break;
3705		}
3706	}
3707
3708out:
3709	hist_browser__delete(browser);
3710	return 0;
3711}
3712