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