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