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