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