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