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