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