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