xref: /openbmc/linux/tools/perf/ui/browsers/hists.c (revision 0f4630f3)
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <linux/rbtree.h>
5 
6 #include "../../util/evsel.h"
7 #include "../../util/evlist.h"
8 #include "../../util/hist.h"
9 #include "../../util/pstack.h"
10 #include "../../util/sort.h"
11 #include "../../util/util.h"
12 #include "../../util/top.h"
13 #include "../../arch/common.h"
14 
15 #include "../browser.h"
16 #include "../helpline.h"
17 #include "../util.h"
18 #include "../ui.h"
19 #include "map.h"
20 #include "annotate.h"
21 
22 struct hist_browser {
23 	struct ui_browser   b;
24 	struct hists	    *hists;
25 	struct hist_entry   *he_selection;
26 	struct map_symbol   *selection;
27 	struct hist_browser_timer *hbt;
28 	struct pstack	    *pstack;
29 	struct perf_env *env;
30 	int		     print_seq;
31 	bool		     show_dso;
32 	bool		     show_headers;
33 	float		     min_pcnt;
34 	u64		     nr_non_filtered_entries;
35 	u64		     nr_callchain_rows;
36 };
37 
38 extern void hist_browser__init_hpp(void);
39 
40 static int hists__browser_title(struct hists *hists,
41 				struct hist_browser_timer *hbt,
42 				char *bf, size_t size);
43 static void hist_browser__update_nr_entries(struct hist_browser *hb);
44 
45 static struct rb_node *hists__filter_entries(struct rb_node *nd,
46 					     float min_pcnt);
47 
48 static bool hist_browser__has_filter(struct hist_browser *hb)
49 {
50 	return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter;
51 }
52 
53 static int hist_browser__get_folding(struct hist_browser *browser)
54 {
55 	struct rb_node *nd;
56 	struct hists *hists = browser->hists;
57 	int unfolded_rows = 0;
58 
59 	for (nd = rb_first(&hists->entries);
60 	     (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
61 	     nd = rb_next(nd)) {
62 		struct hist_entry *he =
63 			rb_entry(nd, struct hist_entry, rb_node);
64 
65 		if (he->unfolded)
66 			unfolded_rows += he->nr_rows;
67 	}
68 	return unfolded_rows;
69 }
70 
71 static u32 hist_browser__nr_entries(struct hist_browser *hb)
72 {
73 	u32 nr_entries;
74 
75 	if (hist_browser__has_filter(hb))
76 		nr_entries = hb->nr_non_filtered_entries;
77 	else
78 		nr_entries = hb->hists->nr_entries;
79 
80 	hb->nr_callchain_rows = hist_browser__get_folding(hb);
81 	return nr_entries + hb->nr_callchain_rows;
82 }
83 
84 static void hist_browser__update_rows(struct hist_browser *hb)
85 {
86 	struct ui_browser *browser = &hb->b;
87 	u16 header_offset = hb->show_headers ? 1 : 0, index_row;
88 
89 	browser->rows = browser->height - header_offset;
90 	/*
91 	 * Verify if we were at the last line and that line isn't
92 	 * visibe because we now show the header line(s).
93 	 */
94 	index_row = browser->index - browser->top_idx;
95 	if (index_row >= browser->rows)
96 		browser->index -= index_row - browser->rows + 1;
97 }
98 
99 static void hist_browser__refresh_dimensions(struct ui_browser *browser)
100 {
101 	struct hist_browser *hb = container_of(browser, struct hist_browser, b);
102 
103 	/* 3 == +/- toggle symbol before actual hist_entry rendering */
104 	browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
105 	/*
106  	 * FIXME: Just keeping existing behaviour, but this really should be
107  	 *	  before updating browser->width, as it will invalidate the
108  	 *	  calculation above. Fix this and the fallout in another
109  	 *	  changeset.
110  	 */
111 	ui_browser__refresh_dimensions(browser);
112 	hist_browser__update_rows(hb);
113 }
114 
115 static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
116 {
117 	u16 header_offset = browser->show_headers ? 1 : 0;
118 
119 	ui_browser__gotorc(&browser->b, row + header_offset, column);
120 }
121 
122 static void hist_browser__reset(struct hist_browser *browser)
123 {
124 	/*
125 	 * The hists__remove_entry_filter() already folds non-filtered
126 	 * entries so we can assume it has 0 callchain rows.
127 	 */
128 	browser->nr_callchain_rows = 0;
129 
130 	hist_browser__update_nr_entries(browser);
131 	browser->b.nr_entries = hist_browser__nr_entries(browser);
132 	hist_browser__refresh_dimensions(&browser->b);
133 	ui_browser__reset_index(&browser->b);
134 }
135 
136 static char tree__folded_sign(bool unfolded)
137 {
138 	return unfolded ? '-' : '+';
139 }
140 
141 static char hist_entry__folded(const struct hist_entry *he)
142 {
143 	return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
144 }
145 
146 static char callchain_list__folded(const struct callchain_list *cl)
147 {
148 	return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
149 }
150 
151 static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
152 {
153 	cl->unfolded = unfold ? cl->has_children : false;
154 }
155 
156 static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
157 {
158 	int n = 0;
159 	struct rb_node *nd;
160 
161 	for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
162 		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
163 		struct callchain_list *chain;
164 		char folded_sign = ' '; /* No children */
165 
166 		list_for_each_entry(chain, &child->val, list) {
167 			++n;
168 			/* We need this because we may not have children */
169 			folded_sign = callchain_list__folded(chain);
170 			if (folded_sign == '+')
171 				break;
172 		}
173 
174 		if (folded_sign == '-') /* Have children and they're unfolded */
175 			n += callchain_node__count_rows_rb_tree(child);
176 	}
177 
178 	return n;
179 }
180 
181 static int callchain_node__count_rows(struct callchain_node *node)
182 {
183 	struct callchain_list *chain;
184 	bool unfolded = false;
185 	int n = 0;
186 
187 	list_for_each_entry(chain, &node->val, list) {
188 		++n;
189 		unfolded = chain->unfolded;
190 	}
191 
192 	if (unfolded)
193 		n += callchain_node__count_rows_rb_tree(node);
194 
195 	return n;
196 }
197 
198 static int callchain__count_rows(struct rb_root *chain)
199 {
200 	struct rb_node *nd;
201 	int n = 0;
202 
203 	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
204 		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
205 		n += callchain_node__count_rows(node);
206 	}
207 
208 	return n;
209 }
210 
211 static bool hist_entry__toggle_fold(struct hist_entry *he)
212 {
213 	if (!he)
214 		return false;
215 
216 	if (!he->has_children)
217 		return false;
218 
219 	he->unfolded = !he->unfolded;
220 	return true;
221 }
222 
223 static bool callchain_list__toggle_fold(struct callchain_list *cl)
224 {
225 	if (!cl)
226 		return false;
227 
228 	if (!cl->has_children)
229 		return false;
230 
231 	cl->unfolded = !cl->unfolded;
232 	return true;
233 }
234 
235 static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
236 {
237 	struct rb_node *nd = rb_first(&node->rb_root);
238 
239 	for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
240 		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
241 		struct callchain_list *chain;
242 		bool first = true;
243 
244 		list_for_each_entry(chain, &child->val, list) {
245 			if (first) {
246 				first = false;
247 				chain->has_children = chain->list.next != &child->val ||
248 							 !RB_EMPTY_ROOT(&child->rb_root);
249 			} else
250 				chain->has_children = chain->list.next == &child->val &&
251 							 !RB_EMPTY_ROOT(&child->rb_root);
252 		}
253 
254 		callchain_node__init_have_children_rb_tree(child);
255 	}
256 }
257 
258 static void callchain_node__init_have_children(struct callchain_node *node,
259 					       bool has_sibling)
260 {
261 	struct callchain_list *chain;
262 
263 	chain = list_entry(node->val.next, struct callchain_list, list);
264 	chain->has_children = has_sibling;
265 
266 	if (!list_empty(&node->val)) {
267 		chain = list_entry(node->val.prev, struct callchain_list, list);
268 		chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
269 	}
270 
271 	callchain_node__init_have_children_rb_tree(node);
272 }
273 
274 static void callchain__init_have_children(struct rb_root *root)
275 {
276 	struct rb_node *nd = rb_first(root);
277 	bool has_sibling = nd && rb_next(nd);
278 
279 	for (nd = rb_first(root); nd; nd = rb_next(nd)) {
280 		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
281 		callchain_node__init_have_children(node, has_sibling);
282 	}
283 }
284 
285 static void hist_entry__init_have_children(struct hist_entry *he)
286 {
287 	if (!he->init_have_children) {
288 		he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
289 		callchain__init_have_children(&he->sorted_chain);
290 		he->init_have_children = true;
291 	}
292 }
293 
294 static bool hist_browser__toggle_fold(struct hist_browser *browser)
295 {
296 	struct hist_entry *he = browser->he_selection;
297 	struct map_symbol *ms = browser->selection;
298 	struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
299 	bool has_children;
300 
301 	if (ms == &he->ms)
302 		has_children = hist_entry__toggle_fold(he);
303 	else
304 		has_children = callchain_list__toggle_fold(cl);
305 
306 	if (has_children) {
307 		hist_entry__init_have_children(he);
308 		browser->b.nr_entries -= he->nr_rows;
309 		browser->nr_callchain_rows -= he->nr_rows;
310 
311 		if (he->unfolded)
312 			he->nr_rows = callchain__count_rows(&he->sorted_chain);
313 		else
314 			he->nr_rows = 0;
315 
316 		browser->b.nr_entries += he->nr_rows;
317 		browser->nr_callchain_rows += he->nr_rows;
318 
319 		return true;
320 	}
321 
322 	/* If it doesn't have children, no toggling performed */
323 	return false;
324 }
325 
326 static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
327 {
328 	int n = 0;
329 	struct rb_node *nd;
330 
331 	for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
332 		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
333 		struct callchain_list *chain;
334 		bool has_children = false;
335 
336 		list_for_each_entry(chain, &child->val, list) {
337 			++n;
338 			callchain_list__set_folding(chain, unfold);
339 			has_children = chain->has_children;
340 		}
341 
342 		if (has_children)
343 			n += callchain_node__set_folding_rb_tree(child, unfold);
344 	}
345 
346 	return n;
347 }
348 
349 static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
350 {
351 	struct callchain_list *chain;
352 	bool has_children = false;
353 	int n = 0;
354 
355 	list_for_each_entry(chain, &node->val, list) {
356 		++n;
357 		callchain_list__set_folding(chain, unfold);
358 		has_children = chain->has_children;
359 	}
360 
361 	if (has_children)
362 		n += callchain_node__set_folding_rb_tree(node, unfold);
363 
364 	return n;
365 }
366 
367 static int callchain__set_folding(struct rb_root *chain, bool unfold)
368 {
369 	struct rb_node *nd;
370 	int n = 0;
371 
372 	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
373 		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
374 		n += callchain_node__set_folding(node, unfold);
375 	}
376 
377 	return n;
378 }
379 
380 static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
381 {
382 	hist_entry__init_have_children(he);
383 	he->unfolded = unfold ? he->has_children : false;
384 
385 	if (he->has_children) {
386 		int n = callchain__set_folding(&he->sorted_chain, unfold);
387 		he->nr_rows = unfold ? n : 0;
388 	} else
389 		he->nr_rows = 0;
390 }
391 
392 static void
393 __hist_browser__set_folding(struct hist_browser *browser, bool unfold)
394 {
395 	struct rb_node *nd;
396 	struct hists *hists = browser->hists;
397 
398 	for (nd = rb_first(&hists->entries);
399 	     (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
400 	     nd = rb_next(nd)) {
401 		struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
402 		hist_entry__set_folding(he, unfold);
403 		browser->nr_callchain_rows += he->nr_rows;
404 	}
405 }
406 
407 static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
408 {
409 	browser->nr_callchain_rows = 0;
410 	__hist_browser__set_folding(browser, unfold);
411 
412 	browser->b.nr_entries = hist_browser__nr_entries(browser);
413 	/* Go to the start, we may be way after valid entries after a collapse */
414 	ui_browser__reset_index(&browser->b);
415 }
416 
417 static void ui_browser__warn_lost_events(struct ui_browser *browser)
418 {
419 	ui_browser__warning(browser, 4,
420 		"Events are being lost, check IO/CPU overload!\n\n"
421 		"You may want to run 'perf' using a RT scheduler policy:\n\n"
422 		" perf top -r 80\n\n"
423 		"Or reduce the sampling frequency.");
424 }
425 
426 static int hist_browser__run(struct hist_browser *browser, const char *help)
427 {
428 	int key;
429 	char title[160];
430 	struct hist_browser_timer *hbt = browser->hbt;
431 	int delay_secs = hbt ? hbt->refresh : 0;
432 
433 	browser->b.entries = &browser->hists->entries;
434 	browser->b.nr_entries = hist_browser__nr_entries(browser);
435 
436 	hists__browser_title(browser->hists, hbt, title, sizeof(title));
437 
438 	if (ui_browser__show(&browser->b, title, help) < 0)
439 		return -1;
440 
441 	while (1) {
442 		key = ui_browser__run(&browser->b, delay_secs);
443 
444 		switch (key) {
445 		case K_TIMER: {
446 			u64 nr_entries;
447 			hbt->timer(hbt->arg);
448 
449 			if (hist_browser__has_filter(browser))
450 				hist_browser__update_nr_entries(browser);
451 
452 			nr_entries = hist_browser__nr_entries(browser);
453 			ui_browser__update_nr_entries(&browser->b, nr_entries);
454 
455 			if (browser->hists->stats.nr_lost_warned !=
456 			    browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
457 				browser->hists->stats.nr_lost_warned =
458 					browser->hists->stats.nr_events[PERF_RECORD_LOST];
459 				ui_browser__warn_lost_events(&browser->b);
460 			}
461 
462 			hists__browser_title(browser->hists,
463 					     hbt, title, sizeof(title));
464 			ui_browser__show_title(&browser->b, title);
465 			continue;
466 		}
467 		case 'D': { /* Debug */
468 			static int seq;
469 			struct hist_entry *h = rb_entry(browser->b.top,
470 							struct hist_entry, rb_node);
471 			ui_helpline__pop();
472 			ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
473 					   seq++, browser->b.nr_entries,
474 					   browser->hists->nr_entries,
475 					   browser->b.rows,
476 					   browser->b.index,
477 					   browser->b.top_idx,
478 					   h->row_offset, h->nr_rows);
479 		}
480 			break;
481 		case 'C':
482 			/* Collapse the whole world. */
483 			hist_browser__set_folding(browser, false);
484 			break;
485 		case 'E':
486 			/* Expand the whole world. */
487 			hist_browser__set_folding(browser, true);
488 			break;
489 		case 'H':
490 			browser->show_headers = !browser->show_headers;
491 			hist_browser__update_rows(browser);
492 			break;
493 		case K_ENTER:
494 			if (hist_browser__toggle_fold(browser))
495 				break;
496 			/* fall thru */
497 		default:
498 			goto out;
499 		}
500 	}
501 out:
502 	ui_browser__hide(&browser->b);
503 	return key;
504 }
505 
506 struct callchain_print_arg {
507 	/* for hists browser */
508 	off_t	row_offset;
509 	bool	is_current_entry;
510 
511 	/* for file dump */
512 	FILE	*fp;
513 	int	printed;
514 };
515 
516 typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
517 					 struct callchain_list *chain,
518 					 const char *str, int offset,
519 					 unsigned short row,
520 					 struct callchain_print_arg *arg);
521 
522 static void hist_browser__show_callchain_entry(struct hist_browser *browser,
523 					       struct callchain_list *chain,
524 					       const char *str, int offset,
525 					       unsigned short row,
526 					       struct callchain_print_arg *arg)
527 {
528 	int color, width;
529 	char folded_sign = callchain_list__folded(chain);
530 	bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
531 
532 	color = HE_COLORSET_NORMAL;
533 	width = browser->b.width - (offset + 2);
534 	if (ui_browser__is_current_entry(&browser->b, row)) {
535 		browser->selection = &chain->ms;
536 		color = HE_COLORSET_SELECTED;
537 		arg->is_current_entry = true;
538 	}
539 
540 	ui_browser__set_color(&browser->b, color);
541 	hist_browser__gotorc(browser, row, 0);
542 	ui_browser__write_nstring(&browser->b, " ", offset);
543 	ui_browser__printf(&browser->b, "%c", folded_sign);
544 	ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
545 	ui_browser__write_nstring(&browser->b, str, width);
546 }
547 
548 static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
549 						  struct callchain_list *chain,
550 						  const char *str, int offset,
551 						  unsigned short row __maybe_unused,
552 						  struct callchain_print_arg *arg)
553 {
554 	char folded_sign = callchain_list__folded(chain);
555 
556 	arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
557 				folded_sign, str);
558 }
559 
560 typedef bool (*check_output_full_fn)(struct hist_browser *browser,
561 				     unsigned short row);
562 
563 static bool hist_browser__check_output_full(struct hist_browser *browser,
564 					    unsigned short row)
565 {
566 	return browser->b.rows == row;
567 }
568 
569 static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
570 					  unsigned short row __maybe_unused)
571 {
572 	return false;
573 }
574 
575 #define LEVEL_OFFSET_STEP 3
576 
577 static int hist_browser__show_callchain(struct hist_browser *browser,
578 					struct rb_root *root, int level,
579 					unsigned short row, u64 total,
580 					print_callchain_entry_fn print,
581 					struct callchain_print_arg *arg,
582 					check_output_full_fn is_output_full)
583 {
584 	struct rb_node *node;
585 	int first_row = row, offset = level * LEVEL_OFFSET_STEP;
586 	u64 new_total;
587 	bool need_percent;
588 
589 	node = rb_first(root);
590 	need_percent = node && rb_next(node);
591 
592 	while (node) {
593 		struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
594 		struct rb_node *next = rb_next(node);
595 		u64 cumul = callchain_cumul_hits(child);
596 		struct callchain_list *chain;
597 		char folded_sign = ' ';
598 		int first = true;
599 		int extra_offset = 0;
600 
601 		list_for_each_entry(chain, &child->val, list) {
602 			char bf[1024], *alloc_str;
603 			const char *str;
604 			bool was_first = first;
605 
606 			if (first)
607 				first = false;
608 			else if (need_percent)
609 				extra_offset = LEVEL_OFFSET_STEP;
610 
611 			folded_sign = callchain_list__folded(chain);
612 			if (arg->row_offset != 0) {
613 				arg->row_offset--;
614 				goto do_next;
615 			}
616 
617 			alloc_str = NULL;
618 			str = callchain_list__sym_name(chain, bf, sizeof(bf),
619 						       browser->show_dso);
620 
621 			if (was_first && need_percent) {
622 				double percent = cumul * 100.0 / total;
623 
624 				if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
625 					str = "Not enough memory!";
626 				else
627 					str = alloc_str;
628 			}
629 
630 			print(browser, chain, str, offset + extra_offset, row, arg);
631 
632 			free(alloc_str);
633 
634 			if (is_output_full(browser, ++row))
635 				goto out;
636 do_next:
637 			if (folded_sign == '+')
638 				break;
639 		}
640 
641 		if (folded_sign == '-') {
642 			const int new_level = level + (extra_offset ? 2 : 1);
643 
644 			if (callchain_param.mode == CHAIN_GRAPH_REL)
645 				new_total = child->children_hit;
646 			else
647 				new_total = total;
648 
649 			row += hist_browser__show_callchain(browser, &child->rb_root,
650 							    new_level, row, new_total,
651 							    print, arg, is_output_full);
652 		}
653 		if (is_output_full(browser, row))
654 			break;
655 		node = next;
656 	}
657 out:
658 	return row - first_row;
659 }
660 
661 struct hpp_arg {
662 	struct ui_browser *b;
663 	char folded_sign;
664 	bool current_entry;
665 };
666 
667 static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
668 {
669 	struct hpp_arg *arg = hpp->ptr;
670 	int ret, len;
671 	va_list args;
672 	double percent;
673 
674 	va_start(args, fmt);
675 	len = va_arg(args, int);
676 	percent = va_arg(args, double);
677 	va_end(args);
678 
679 	ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
680 
681 	ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
682 	ui_browser__printf(arg->b, "%s", hpp->buf);
683 
684 	advance_hpp(hpp, ret);
685 	return ret;
686 }
687 
688 #define __HPP_COLOR_PERCENT_FN(_type, _field)				\
689 static u64 __hpp_get_##_field(struct hist_entry *he)			\
690 {									\
691 	return he->stat._field;						\
692 }									\
693 									\
694 static int								\
695 hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt,		\
696 				struct perf_hpp *hpp,			\
697 				struct hist_entry *he)			\
698 {									\
699 	return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%",	\
700 			__hpp__slsmg_color_printf, true);		\
701 }
702 
703 #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)			\
704 static u64 __hpp_get_acc_##_field(struct hist_entry *he)		\
705 {									\
706 	return he->stat_acc->_field;					\
707 }									\
708 									\
709 static int								\
710 hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt,		\
711 				struct perf_hpp *hpp,			\
712 				struct hist_entry *he)			\
713 {									\
714 	if (!symbol_conf.cumulate_callchain) {				\
715 		struct hpp_arg *arg = hpp->ptr;				\
716 		int len = fmt->user_len ?: fmt->len;			\
717 		int ret = scnprintf(hpp->buf, hpp->size,		\
718 				    "%*s", len, "N/A");			\
719 		ui_browser__printf(arg->b, "%s", hpp->buf);		\
720 									\
721 		return ret;						\
722 	}								\
723 	return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field,		\
724 			" %*.2f%%", __hpp__slsmg_color_printf, true);	\
725 }
726 
727 __HPP_COLOR_PERCENT_FN(overhead, period)
728 __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
729 __HPP_COLOR_PERCENT_FN(overhead_us, period_us)
730 __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
731 __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
732 __HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
733 
734 #undef __HPP_COLOR_PERCENT_FN
735 #undef __HPP_COLOR_ACC_PERCENT_FN
736 
737 void hist_browser__init_hpp(void)
738 {
739 	perf_hpp__format[PERF_HPP__OVERHEAD].color =
740 				hist_browser__hpp_color_overhead;
741 	perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
742 				hist_browser__hpp_color_overhead_sys;
743 	perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
744 				hist_browser__hpp_color_overhead_us;
745 	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
746 				hist_browser__hpp_color_overhead_guest_sys;
747 	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
748 				hist_browser__hpp_color_overhead_guest_us;
749 	perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
750 				hist_browser__hpp_color_overhead_acc;
751 }
752 
753 static int hist_browser__show_entry(struct hist_browser *browser,
754 				    struct hist_entry *entry,
755 				    unsigned short row)
756 {
757 	char s[256];
758 	int printed = 0;
759 	int width = browser->b.width;
760 	char folded_sign = ' ';
761 	bool current_entry = ui_browser__is_current_entry(&browser->b, row);
762 	off_t row_offset = entry->row_offset;
763 	bool first = true;
764 	struct perf_hpp_fmt *fmt;
765 
766 	if (current_entry) {
767 		browser->he_selection = entry;
768 		browser->selection = &entry->ms;
769 	}
770 
771 	if (symbol_conf.use_callchain) {
772 		hist_entry__init_have_children(entry);
773 		folded_sign = hist_entry__folded(entry);
774 	}
775 
776 	if (row_offset == 0) {
777 		struct hpp_arg arg = {
778 			.b		= &browser->b,
779 			.folded_sign	= folded_sign,
780 			.current_entry	= current_entry,
781 		};
782 		struct perf_hpp hpp = {
783 			.buf		= s,
784 			.size		= sizeof(s),
785 			.ptr		= &arg,
786 		};
787 		int column = 0;
788 
789 		hist_browser__gotorc(browser, row, 0);
790 
791 		perf_hpp__for_each_format(fmt) {
792 			if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll)
793 				continue;
794 
795 			if (current_entry && browser->b.navkeypressed) {
796 				ui_browser__set_color(&browser->b,
797 						      HE_COLORSET_SELECTED);
798 			} else {
799 				ui_browser__set_color(&browser->b,
800 						      HE_COLORSET_NORMAL);
801 			}
802 
803 			if (first) {
804 				if (symbol_conf.use_callchain) {
805 					ui_browser__printf(&browser->b, "%c ", folded_sign);
806 					width -= 2;
807 				}
808 				first = false;
809 			} else {
810 				ui_browser__printf(&browser->b, "  ");
811 				width -= 2;
812 			}
813 
814 			if (fmt->color) {
815 				width -= fmt->color(fmt, &hpp, entry);
816 			} else {
817 				width -= fmt->entry(fmt, &hpp, entry);
818 				ui_browser__printf(&browser->b, "%s", s);
819 			}
820 		}
821 
822 		/* The scroll bar isn't being used */
823 		if (!browser->b.navkeypressed)
824 			width += 1;
825 
826 		ui_browser__write_nstring(&browser->b, "", width);
827 
828 		++row;
829 		++printed;
830 	} else
831 		--row_offset;
832 
833 	if (folded_sign == '-' && row != browser->b.rows) {
834 		u64 total = hists__total_period(entry->hists);
835 		struct callchain_print_arg arg = {
836 			.row_offset = row_offset,
837 			.is_current_entry = current_entry,
838 		};
839 
840 		if (callchain_param.mode == CHAIN_GRAPH_REL) {
841 			if (symbol_conf.cumulate_callchain)
842 				total = entry->stat_acc->period;
843 			else
844 				total = entry->stat.period;
845 		}
846 
847 		printed += hist_browser__show_callchain(browser,
848 					&entry->sorted_chain, 1, row, total,
849 					hist_browser__show_callchain_entry, &arg,
850 					hist_browser__check_output_full);
851 
852 		if (arg.is_current_entry)
853 			browser->he_selection = entry;
854 	}
855 
856 	return printed;
857 }
858 
859 static int advance_hpp_check(struct perf_hpp *hpp, int inc)
860 {
861 	advance_hpp(hpp, inc);
862 	return hpp->size <= 0;
863 }
864 
865 static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size)
866 {
867 	struct hists *hists = browser->hists;
868 	struct perf_hpp dummy_hpp = {
869 		.buf    = buf,
870 		.size   = size,
871 	};
872 	struct perf_hpp_fmt *fmt;
873 	size_t ret = 0;
874 	int column = 0;
875 
876 	if (symbol_conf.use_callchain) {
877 		ret = scnprintf(buf, size, "  ");
878 		if (advance_hpp_check(&dummy_hpp, ret))
879 			return ret;
880 	}
881 
882 	perf_hpp__for_each_format(fmt) {
883 		if (perf_hpp__should_skip(fmt)  || column++ < browser->b.horiz_scroll)
884 			continue;
885 
886 		ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
887 		if (advance_hpp_check(&dummy_hpp, ret))
888 			break;
889 
890 		ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "  ");
891 		if (advance_hpp_check(&dummy_hpp, ret))
892 			break;
893 	}
894 
895 	return ret;
896 }
897 
898 static void hist_browser__show_headers(struct hist_browser *browser)
899 {
900 	char headers[1024];
901 
902 	hists_browser__scnprintf_headers(browser, headers, sizeof(headers));
903 	ui_browser__gotorc(&browser->b, 0, 0);
904 	ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
905 	ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
906 }
907 
908 static void ui_browser__hists_init_top(struct ui_browser *browser)
909 {
910 	if (browser->top == NULL) {
911 		struct hist_browser *hb;
912 
913 		hb = container_of(browser, struct hist_browser, b);
914 		browser->top = rb_first(&hb->hists->entries);
915 	}
916 }
917 
918 static unsigned int hist_browser__refresh(struct ui_browser *browser)
919 {
920 	unsigned row = 0;
921 	u16 header_offset = 0;
922 	struct rb_node *nd;
923 	struct hist_browser *hb = container_of(browser, struct hist_browser, b);
924 
925 	if (hb->show_headers) {
926 		hist_browser__show_headers(hb);
927 		header_offset = 1;
928 	}
929 
930 	ui_browser__hists_init_top(browser);
931 
932 	for (nd = browser->top; nd; nd = rb_next(nd)) {
933 		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
934 		float percent;
935 
936 		if (h->filtered)
937 			continue;
938 
939 		percent = hist_entry__get_percent_limit(h);
940 		if (percent < hb->min_pcnt)
941 			continue;
942 
943 		row += hist_browser__show_entry(hb, h, row);
944 		if (row == browser->rows)
945 			break;
946 	}
947 
948 	return row + header_offset;
949 }
950 
951 static struct rb_node *hists__filter_entries(struct rb_node *nd,
952 					     float min_pcnt)
953 {
954 	while (nd != NULL) {
955 		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
956 		float percent = hist_entry__get_percent_limit(h);
957 
958 		if (!h->filtered && percent >= min_pcnt)
959 			return nd;
960 
961 		nd = rb_next(nd);
962 	}
963 
964 	return NULL;
965 }
966 
967 static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
968 						  float min_pcnt)
969 {
970 	while (nd != NULL) {
971 		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
972 		float percent = hist_entry__get_percent_limit(h);
973 
974 		if (!h->filtered && percent >= min_pcnt)
975 			return nd;
976 
977 		nd = rb_prev(nd);
978 	}
979 
980 	return NULL;
981 }
982 
983 static void ui_browser__hists_seek(struct ui_browser *browser,
984 				   off_t offset, int whence)
985 {
986 	struct hist_entry *h;
987 	struct rb_node *nd;
988 	bool first = true;
989 	struct hist_browser *hb;
990 
991 	hb = container_of(browser, struct hist_browser, b);
992 
993 	if (browser->nr_entries == 0)
994 		return;
995 
996 	ui_browser__hists_init_top(browser);
997 
998 	switch (whence) {
999 	case SEEK_SET:
1000 		nd = hists__filter_entries(rb_first(browser->entries),
1001 					   hb->min_pcnt);
1002 		break;
1003 	case SEEK_CUR:
1004 		nd = browser->top;
1005 		goto do_offset;
1006 	case SEEK_END:
1007 		nd = hists__filter_prev_entries(rb_last(browser->entries),
1008 						hb->min_pcnt);
1009 		first = false;
1010 		break;
1011 	default:
1012 		return;
1013 	}
1014 
1015 	/*
1016 	 * Moves not relative to the first visible entry invalidates its
1017 	 * row_offset:
1018 	 */
1019 	h = rb_entry(browser->top, struct hist_entry, rb_node);
1020 	h->row_offset = 0;
1021 
1022 	/*
1023 	 * Here we have to check if nd is expanded (+), if it is we can't go
1024 	 * the next top level hist_entry, instead we must compute an offset of
1025 	 * what _not_ to show and not change the first visible entry.
1026 	 *
1027 	 * This offset increments when we are going from top to bottom and
1028 	 * decreases when we're going from bottom to top.
1029 	 *
1030 	 * As we don't have backpointers to the top level in the callchains
1031 	 * structure, we need to always print the whole hist_entry callchain,
1032 	 * skipping the first ones that are before the first visible entry
1033 	 * and stop when we printed enough lines to fill the screen.
1034 	 */
1035 do_offset:
1036 	if (offset > 0) {
1037 		do {
1038 			h = rb_entry(nd, struct hist_entry, rb_node);
1039 			if (h->unfolded) {
1040 				u16 remaining = h->nr_rows - h->row_offset;
1041 				if (offset > remaining) {
1042 					offset -= remaining;
1043 					h->row_offset = 0;
1044 				} else {
1045 					h->row_offset += offset;
1046 					offset = 0;
1047 					browser->top = nd;
1048 					break;
1049 				}
1050 			}
1051 			nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
1052 			if (nd == NULL)
1053 				break;
1054 			--offset;
1055 			browser->top = nd;
1056 		} while (offset != 0);
1057 	} else if (offset < 0) {
1058 		while (1) {
1059 			h = rb_entry(nd, struct hist_entry, rb_node);
1060 			if (h->unfolded) {
1061 				if (first) {
1062 					if (-offset > h->row_offset) {
1063 						offset += h->row_offset;
1064 						h->row_offset = 0;
1065 					} else {
1066 						h->row_offset += offset;
1067 						offset = 0;
1068 						browser->top = nd;
1069 						break;
1070 					}
1071 				} else {
1072 					if (-offset > h->nr_rows) {
1073 						offset += h->nr_rows;
1074 						h->row_offset = 0;
1075 					} else {
1076 						h->row_offset = h->nr_rows + offset;
1077 						offset = 0;
1078 						browser->top = nd;
1079 						break;
1080 					}
1081 				}
1082 			}
1083 
1084 			nd = hists__filter_prev_entries(rb_prev(nd),
1085 							hb->min_pcnt);
1086 			if (nd == NULL)
1087 				break;
1088 			++offset;
1089 			browser->top = nd;
1090 			if (offset == 0) {
1091 				/*
1092 				 * Last unfiltered hist_entry, check if it is
1093 				 * unfolded, if it is then we should have
1094 				 * row_offset at its last entry.
1095 				 */
1096 				h = rb_entry(nd, struct hist_entry, rb_node);
1097 				if (h->unfolded)
1098 					h->row_offset = h->nr_rows;
1099 				break;
1100 			}
1101 			first = false;
1102 		}
1103 	} else {
1104 		browser->top = nd;
1105 		h = rb_entry(nd, struct hist_entry, rb_node);
1106 		h->row_offset = 0;
1107 	}
1108 }
1109 
1110 static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1111 					   struct hist_entry *he, FILE *fp)
1112 {
1113 	u64 total = hists__total_period(he->hists);
1114 	struct callchain_print_arg arg  = {
1115 		.fp = fp,
1116 	};
1117 
1118 	if (symbol_conf.cumulate_callchain)
1119 		total = he->stat_acc->period;
1120 
1121 	hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1122 				     hist_browser__fprintf_callchain_entry, &arg,
1123 				     hist_browser__check_dump_full);
1124 	return arg.printed;
1125 }
1126 
1127 static int hist_browser__fprintf_entry(struct hist_browser *browser,
1128 				       struct hist_entry *he, FILE *fp)
1129 {
1130 	char s[8192];
1131 	int printed = 0;
1132 	char folded_sign = ' ';
1133 	struct perf_hpp hpp = {
1134 		.buf = s,
1135 		.size = sizeof(s),
1136 	};
1137 	struct perf_hpp_fmt *fmt;
1138 	bool first = true;
1139 	int ret;
1140 
1141 	if (symbol_conf.use_callchain)
1142 		folded_sign = hist_entry__folded(he);
1143 
1144 	if (symbol_conf.use_callchain)
1145 		printed += fprintf(fp, "%c ", folded_sign);
1146 
1147 	perf_hpp__for_each_format(fmt) {
1148 		if (perf_hpp__should_skip(fmt))
1149 			continue;
1150 
1151 		if (!first) {
1152 			ret = scnprintf(hpp.buf, hpp.size, "  ");
1153 			advance_hpp(&hpp, ret);
1154 		} else
1155 			first = false;
1156 
1157 		ret = fmt->entry(fmt, &hpp, he);
1158 		advance_hpp(&hpp, ret);
1159 	}
1160 	printed += fprintf(fp, "%s\n", rtrim(s));
1161 
1162 	if (folded_sign == '-')
1163 		printed += hist_browser__fprintf_callchain(browser, he, fp);
1164 
1165 	return printed;
1166 }
1167 
1168 static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1169 {
1170 	struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
1171 						   browser->min_pcnt);
1172 	int printed = 0;
1173 
1174 	while (nd) {
1175 		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1176 
1177 		printed += hist_browser__fprintf_entry(browser, h, fp);
1178 		nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
1179 	}
1180 
1181 	return printed;
1182 }
1183 
1184 static int hist_browser__dump(struct hist_browser *browser)
1185 {
1186 	char filename[64];
1187 	FILE *fp;
1188 
1189 	while (1) {
1190 		scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1191 		if (access(filename, F_OK))
1192 			break;
1193 		/*
1194  		 * XXX: Just an arbitrary lazy upper limit
1195  		 */
1196 		if (++browser->print_seq == 8192) {
1197 			ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1198 			return -1;
1199 		}
1200 	}
1201 
1202 	fp = fopen(filename, "w");
1203 	if (fp == NULL) {
1204 		char bf[64];
1205 		const char *err = strerror_r(errno, bf, sizeof(bf));
1206 		ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
1207 		return -1;
1208 	}
1209 
1210 	++browser->print_seq;
1211 	hist_browser__fprintf(browser, fp);
1212 	fclose(fp);
1213 	ui_helpline__fpush("%s written!", filename);
1214 
1215 	return 0;
1216 }
1217 
1218 static struct hist_browser *hist_browser__new(struct hists *hists,
1219 					      struct hist_browser_timer *hbt,
1220 					      struct perf_env *env)
1221 {
1222 	struct hist_browser *browser = zalloc(sizeof(*browser));
1223 
1224 	if (browser) {
1225 		browser->hists = hists;
1226 		browser->b.refresh = hist_browser__refresh;
1227 		browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
1228 		browser->b.seek = ui_browser__hists_seek;
1229 		browser->b.use_navkeypressed = true;
1230 		browser->show_headers = symbol_conf.show_hist_headers;
1231 		browser->hbt = hbt;
1232 		browser->env = env;
1233 	}
1234 
1235 	return browser;
1236 }
1237 
1238 static void hist_browser__delete(struct hist_browser *browser)
1239 {
1240 	free(browser);
1241 }
1242 
1243 static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
1244 {
1245 	return browser->he_selection;
1246 }
1247 
1248 static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
1249 {
1250 	return browser->he_selection->thread;
1251 }
1252 
1253 /* Check whether the browser is for 'top' or 'report' */
1254 static inline bool is_report_browser(void *timer)
1255 {
1256 	return timer == NULL;
1257 }
1258 
1259 static int hists__browser_title(struct hists *hists,
1260 				struct hist_browser_timer *hbt,
1261 				char *bf, size_t size)
1262 {
1263 	char unit;
1264 	int printed;
1265 	const struct dso *dso = hists->dso_filter;
1266 	const struct thread *thread = hists->thread_filter;
1267 	int socket_id = hists->socket_filter;
1268 	unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1269 	u64 nr_events = hists->stats.total_period;
1270 	struct perf_evsel *evsel = hists_to_evsel(hists);
1271 	const char *ev_name = perf_evsel__name(evsel);
1272 	char buf[512];
1273 	size_t buflen = sizeof(buf);
1274 	char ref[30] = " show reference callgraph, ";
1275 	bool enable_ref = false;
1276 
1277 	if (symbol_conf.filter_relative) {
1278 		nr_samples = hists->stats.nr_non_filtered_samples;
1279 		nr_events = hists->stats.total_non_filtered_period;
1280 	}
1281 
1282 	if (perf_evsel__is_group_event(evsel)) {
1283 		struct perf_evsel *pos;
1284 
1285 		perf_evsel__group_desc(evsel, buf, buflen);
1286 		ev_name = buf;
1287 
1288 		for_each_group_member(pos, evsel) {
1289 			struct hists *pos_hists = evsel__hists(pos);
1290 
1291 			if (symbol_conf.filter_relative) {
1292 				nr_samples += pos_hists->stats.nr_non_filtered_samples;
1293 				nr_events += pos_hists->stats.total_non_filtered_period;
1294 			} else {
1295 				nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1296 				nr_events += pos_hists->stats.total_period;
1297 			}
1298 		}
1299 	}
1300 
1301 	if (symbol_conf.show_ref_callgraph &&
1302 	    strstr(ev_name, "call-graph=no"))
1303 		enable_ref = true;
1304 	nr_samples = convert_unit(nr_samples, &unit);
1305 	printed = scnprintf(bf, size,
1306 			   "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
1307 			   nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
1308 
1309 
1310 	if (hists->uid_filter_str)
1311 		printed += snprintf(bf + printed, size - printed,
1312 				    ", UID: %s", hists->uid_filter_str);
1313 	if (thread)
1314 		printed += scnprintf(bf + printed, size - printed,
1315 				    ", Thread: %s(%d)",
1316 				     (thread->comm_set ? thread__comm_str(thread) : ""),
1317 				    thread->tid);
1318 	if (dso)
1319 		printed += scnprintf(bf + printed, size - printed,
1320 				    ", DSO: %s", dso->short_name);
1321 	if (socket_id > -1)
1322 		printed += scnprintf(bf + printed, size - printed,
1323 				    ", Processor Socket: %d", socket_id);
1324 	if (!is_report_browser(hbt)) {
1325 		struct perf_top *top = hbt->arg;
1326 
1327 		if (top->zero)
1328 			printed += scnprintf(bf + printed, size - printed, " [z]");
1329 	}
1330 
1331 	return printed;
1332 }
1333 
1334 static inline void free_popup_options(char **options, int n)
1335 {
1336 	int i;
1337 
1338 	for (i = 0; i < n; ++i)
1339 		zfree(&options[i]);
1340 }
1341 
1342 /*
1343  * Only runtime switching of perf data file will make "input_name" point
1344  * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1345  * whether we need to call free() for current "input_name" during the switch.
1346  */
1347 static bool is_input_name_malloced = false;
1348 
1349 static int switch_data_file(void)
1350 {
1351 	char *pwd, *options[32], *abs_path[32], *tmp;
1352 	DIR *pwd_dir;
1353 	int nr_options = 0, choice = -1, ret = -1;
1354 	struct dirent *dent;
1355 
1356 	pwd = getenv("PWD");
1357 	if (!pwd)
1358 		return ret;
1359 
1360 	pwd_dir = opendir(pwd);
1361 	if (!pwd_dir)
1362 		return ret;
1363 
1364 	memset(options, 0, sizeof(options));
1365 	memset(options, 0, sizeof(abs_path));
1366 
1367 	while ((dent = readdir(pwd_dir))) {
1368 		char path[PATH_MAX];
1369 		u64 magic;
1370 		char *name = dent->d_name;
1371 		FILE *file;
1372 
1373 		if (!(dent->d_type == DT_REG))
1374 			continue;
1375 
1376 		snprintf(path, sizeof(path), "%s/%s", pwd, name);
1377 
1378 		file = fopen(path, "r");
1379 		if (!file)
1380 			continue;
1381 
1382 		if (fread(&magic, 1, 8, file) < 8)
1383 			goto close_file_and_continue;
1384 
1385 		if (is_perf_magic(magic)) {
1386 			options[nr_options] = strdup(name);
1387 			if (!options[nr_options])
1388 				goto close_file_and_continue;
1389 
1390 			abs_path[nr_options] = strdup(path);
1391 			if (!abs_path[nr_options]) {
1392 				zfree(&options[nr_options]);
1393 				ui__warning("Can't search all data files due to memory shortage.\n");
1394 				fclose(file);
1395 				break;
1396 			}
1397 
1398 			nr_options++;
1399 		}
1400 
1401 close_file_and_continue:
1402 		fclose(file);
1403 		if (nr_options >= 32) {
1404 			ui__warning("Too many perf data files in PWD!\n"
1405 				    "Only the first 32 files will be listed.\n");
1406 			break;
1407 		}
1408 	}
1409 	closedir(pwd_dir);
1410 
1411 	if (nr_options) {
1412 		choice = ui__popup_menu(nr_options, options);
1413 		if (choice < nr_options && choice >= 0) {
1414 			tmp = strdup(abs_path[choice]);
1415 			if (tmp) {
1416 				if (is_input_name_malloced)
1417 					free((void *)input_name);
1418 				input_name = tmp;
1419 				is_input_name_malloced = true;
1420 				ret = 0;
1421 			} else
1422 				ui__warning("Data switch failed due to memory shortage!\n");
1423 		}
1424 	}
1425 
1426 	free_popup_options(options, nr_options);
1427 	free_popup_options(abs_path, nr_options);
1428 	return ret;
1429 }
1430 
1431 struct popup_action {
1432 	struct thread 		*thread;
1433 	struct map_symbol 	ms;
1434 	int			socket;
1435 
1436 	int (*fn)(struct hist_browser *browser, struct popup_action *act);
1437 };
1438 
1439 static int
1440 do_annotate(struct hist_browser *browser, struct popup_action *act)
1441 {
1442 	struct perf_evsel *evsel;
1443 	struct annotation *notes;
1444 	struct hist_entry *he;
1445 	int err;
1446 
1447 	if (!objdump_path && perf_env__lookup_objdump(browser->env))
1448 		return 0;
1449 
1450 	notes = symbol__annotation(act->ms.sym);
1451 	if (!notes->src)
1452 		return 0;
1453 
1454 	evsel = hists_to_evsel(browser->hists);
1455 	err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
1456 	he = hist_browser__selected_entry(browser);
1457 	/*
1458 	 * offer option to annotate the other branch source or target
1459 	 * (if they exists) when returning from annotate
1460 	 */
1461 	if ((err == 'q' || err == CTRL('c')) && he->branch_info)
1462 		return 1;
1463 
1464 	ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1465 	if (err)
1466 		ui_browser__handle_resize(&browser->b);
1467 	return 0;
1468 }
1469 
1470 static int
1471 add_annotate_opt(struct hist_browser *browser __maybe_unused,
1472 		 struct popup_action *act, char **optstr,
1473 		 struct map *map, struct symbol *sym)
1474 {
1475 	if (sym == NULL || map->dso->annotate_warned)
1476 		return 0;
1477 
1478 	if (asprintf(optstr, "Annotate %s", sym->name) < 0)
1479 		return 0;
1480 
1481 	act->ms.map = map;
1482 	act->ms.sym = sym;
1483 	act->fn = do_annotate;
1484 	return 1;
1485 }
1486 
1487 static int
1488 do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1489 {
1490 	struct thread *thread = act->thread;
1491 
1492 	if (browser->hists->thread_filter) {
1493 		pstack__remove(browser->pstack, &browser->hists->thread_filter);
1494 		perf_hpp__set_elide(HISTC_THREAD, false);
1495 		thread__zput(browser->hists->thread_filter);
1496 		ui_helpline__pop();
1497 	} else {
1498 		ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
1499 				   thread->comm_set ? thread__comm_str(thread) : "",
1500 				   thread->tid);
1501 		browser->hists->thread_filter = thread__get(thread);
1502 		perf_hpp__set_elide(HISTC_THREAD, false);
1503 		pstack__push(browser->pstack, &browser->hists->thread_filter);
1504 	}
1505 
1506 	hists__filter_by_thread(browser->hists);
1507 	hist_browser__reset(browser);
1508 	return 0;
1509 }
1510 
1511 static int
1512 add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1513 	       char **optstr, struct thread *thread)
1514 {
1515 	if (thread == NULL)
1516 		return 0;
1517 
1518 	if (asprintf(optstr, "Zoom %s %s(%d) thread",
1519 		     browser->hists->thread_filter ? "out of" : "into",
1520 		     thread->comm_set ? thread__comm_str(thread) : "",
1521 		     thread->tid) < 0)
1522 		return 0;
1523 
1524 	act->thread = thread;
1525 	act->fn = do_zoom_thread;
1526 	return 1;
1527 }
1528 
1529 static int
1530 do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1531 {
1532 	struct map *map = act->ms.map;
1533 
1534 	if (browser->hists->dso_filter) {
1535 		pstack__remove(browser->pstack, &browser->hists->dso_filter);
1536 		perf_hpp__set_elide(HISTC_DSO, false);
1537 		browser->hists->dso_filter = NULL;
1538 		ui_helpline__pop();
1539 	} else {
1540 		if (map == NULL)
1541 			return 0;
1542 		ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
1543 				   __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
1544 		browser->hists->dso_filter = map->dso;
1545 		perf_hpp__set_elide(HISTC_DSO, true);
1546 		pstack__push(browser->pstack, &browser->hists->dso_filter);
1547 	}
1548 
1549 	hists__filter_by_dso(browser->hists);
1550 	hist_browser__reset(browser);
1551 	return 0;
1552 }
1553 
1554 static int
1555 add_dso_opt(struct hist_browser *browser, struct popup_action *act,
1556 	    char **optstr, struct map *map)
1557 {
1558 	if (map == NULL)
1559 		return 0;
1560 
1561 	if (asprintf(optstr, "Zoom %s %s DSO",
1562 		     browser->hists->dso_filter ? "out of" : "into",
1563 		     __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
1564 		return 0;
1565 
1566 	act->ms.map = map;
1567 	act->fn = do_zoom_dso;
1568 	return 1;
1569 }
1570 
1571 static int
1572 do_browse_map(struct hist_browser *browser __maybe_unused,
1573 	      struct popup_action *act)
1574 {
1575 	map__browse(act->ms.map);
1576 	return 0;
1577 }
1578 
1579 static int
1580 add_map_opt(struct hist_browser *browser __maybe_unused,
1581 	    struct popup_action *act, char **optstr, struct map *map)
1582 {
1583 	if (map == NULL)
1584 		return 0;
1585 
1586 	if (asprintf(optstr, "Browse map details") < 0)
1587 		return 0;
1588 
1589 	act->ms.map = map;
1590 	act->fn = do_browse_map;
1591 	return 1;
1592 }
1593 
1594 static int
1595 do_run_script(struct hist_browser *browser __maybe_unused,
1596 	      struct popup_action *act)
1597 {
1598 	char script_opt[64];
1599 	memset(script_opt, 0, sizeof(script_opt));
1600 
1601 	if (act->thread) {
1602 		scnprintf(script_opt, sizeof(script_opt), " -c %s ",
1603 			  thread__comm_str(act->thread));
1604 	} else if (act->ms.sym) {
1605 		scnprintf(script_opt, sizeof(script_opt), " -S %s ",
1606 			  act->ms.sym->name);
1607 	}
1608 
1609 	script_browse(script_opt);
1610 	return 0;
1611 }
1612 
1613 static int
1614 add_script_opt(struct hist_browser *browser __maybe_unused,
1615 	       struct popup_action *act, char **optstr,
1616 	       struct thread *thread, struct symbol *sym)
1617 {
1618 	if (thread) {
1619 		if (asprintf(optstr, "Run scripts for samples of thread [%s]",
1620 			     thread__comm_str(thread)) < 0)
1621 			return 0;
1622 	} else if (sym) {
1623 		if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
1624 			     sym->name) < 0)
1625 			return 0;
1626 	} else {
1627 		if (asprintf(optstr, "Run scripts for all samples") < 0)
1628 			return 0;
1629 	}
1630 
1631 	act->thread = thread;
1632 	act->ms.sym = sym;
1633 	act->fn = do_run_script;
1634 	return 1;
1635 }
1636 
1637 static int
1638 do_switch_data(struct hist_browser *browser __maybe_unused,
1639 	       struct popup_action *act __maybe_unused)
1640 {
1641 	if (switch_data_file()) {
1642 		ui__warning("Won't switch the data files due to\n"
1643 			    "no valid data file get selected!\n");
1644 		return 0;
1645 	}
1646 
1647 	return K_SWITCH_INPUT_DATA;
1648 }
1649 
1650 static int
1651 add_switch_opt(struct hist_browser *browser,
1652 	       struct popup_action *act, char **optstr)
1653 {
1654 	if (!is_report_browser(browser->hbt))
1655 		return 0;
1656 
1657 	if (asprintf(optstr, "Switch to another data file in PWD") < 0)
1658 		return 0;
1659 
1660 	act->fn = do_switch_data;
1661 	return 1;
1662 }
1663 
1664 static int
1665 do_exit_browser(struct hist_browser *browser __maybe_unused,
1666 		struct popup_action *act __maybe_unused)
1667 {
1668 	return 0;
1669 }
1670 
1671 static int
1672 add_exit_opt(struct hist_browser *browser __maybe_unused,
1673 	     struct popup_action *act, char **optstr)
1674 {
1675 	if (asprintf(optstr, "Exit") < 0)
1676 		return 0;
1677 
1678 	act->fn = do_exit_browser;
1679 	return 1;
1680 }
1681 
1682 static int
1683 do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
1684 {
1685 	if (browser->hists->socket_filter > -1) {
1686 		pstack__remove(browser->pstack, &browser->hists->socket_filter);
1687 		browser->hists->socket_filter = -1;
1688 		perf_hpp__set_elide(HISTC_SOCKET, false);
1689 	} else {
1690 		browser->hists->socket_filter = act->socket;
1691 		perf_hpp__set_elide(HISTC_SOCKET, true);
1692 		pstack__push(browser->pstack, &browser->hists->socket_filter);
1693 	}
1694 
1695 	hists__filter_by_socket(browser->hists);
1696 	hist_browser__reset(browser);
1697 	return 0;
1698 }
1699 
1700 static int
1701 add_socket_opt(struct hist_browser *browser, struct popup_action *act,
1702 	       char **optstr, int socket_id)
1703 {
1704 	if (socket_id < 0)
1705 		return 0;
1706 
1707 	if (asprintf(optstr, "Zoom %s Processor Socket %d",
1708 		     (browser->hists->socket_filter > -1) ? "out of" : "into",
1709 		     socket_id) < 0)
1710 		return 0;
1711 
1712 	act->socket = socket_id;
1713 	act->fn = do_zoom_socket;
1714 	return 1;
1715 }
1716 
1717 static void hist_browser__update_nr_entries(struct hist_browser *hb)
1718 {
1719 	u64 nr_entries = 0;
1720 	struct rb_node *nd = rb_first(&hb->hists->entries);
1721 
1722 	if (hb->min_pcnt == 0) {
1723 		hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1724 		return;
1725 	}
1726 
1727 	while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
1728 		nr_entries++;
1729 		nd = rb_next(nd);
1730 	}
1731 
1732 	hb->nr_non_filtered_entries = nr_entries;
1733 }
1734 
1735 static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1736 				    const char *helpline,
1737 				    bool left_exits,
1738 				    struct hist_browser_timer *hbt,
1739 				    float min_pcnt,
1740 				    struct perf_env *env)
1741 {
1742 	struct hists *hists = evsel__hists(evsel);
1743 	struct hist_browser *browser = hist_browser__new(hists, hbt, env);
1744 	struct branch_info *bi;
1745 #define MAX_OPTIONS  16
1746 	char *options[MAX_OPTIONS];
1747 	struct popup_action actions[MAX_OPTIONS];
1748 	int nr_options = 0;
1749 	int key = -1;
1750 	char buf[64];
1751 	int delay_secs = hbt ? hbt->refresh : 0;
1752 	struct perf_hpp_fmt *fmt;
1753 
1754 #define HIST_BROWSER_HELP_COMMON					\
1755 	"h/?/F1        Show this window\n"				\
1756 	"UP/DOWN/PGUP\n"						\
1757 	"PGDN/SPACE    Navigate\n"					\
1758 	"q/ESC/CTRL+C  Exit browser\n\n"				\
1759 	"For multiple event sessions:\n\n"				\
1760 	"TAB/UNTAB     Switch events\n\n"				\
1761 	"For symbolic views (--sort has sym):\n\n"			\
1762 	"ENTER         Zoom into DSO/Threads & Annotate current symbol\n" \
1763 	"ESC           Zoom out\n"					\
1764 	"a             Annotate current symbol\n"			\
1765 	"C             Collapse all callchains\n"			\
1766 	"d             Zoom into current DSO\n"				\
1767 	"E             Expand all callchains\n"				\
1768 	"F             Toggle percentage of filtered entries\n"		\
1769 	"H             Display column headers\n"			\
1770 	"m             Display context menu\n"				\
1771 	"S             Zoom into current Processor Socket\n"		\
1772 
1773 	/* help messages are sorted by lexical order of the hotkey */
1774 	const char report_help[] = HIST_BROWSER_HELP_COMMON
1775 	"i             Show header information\n"
1776 	"P             Print histograms to perf.hist.N\n"
1777 	"r             Run available scripts\n"
1778 	"s             Switch to another data file in PWD\n"
1779 	"t             Zoom into current Thread\n"
1780 	"V             Verbose (DSO names in callchains, etc)\n"
1781 	"/             Filter symbol by name";
1782 	const char top_help[] = HIST_BROWSER_HELP_COMMON
1783 	"P             Print histograms to perf.hist.N\n"
1784 	"t             Zoom into current Thread\n"
1785 	"V             Verbose (DSO names in callchains, etc)\n"
1786 	"z             Toggle zeroing of samples\n"
1787 	"f             Enable/Disable events\n"
1788 	"/             Filter symbol by name";
1789 
1790 	if (browser == NULL)
1791 		return -1;
1792 
1793 	/* reset abort key so that it can get Ctrl-C as a key */
1794 	SLang_reset_tty();
1795 	SLang_init_tty(0, 0, 0);
1796 
1797 	if (min_pcnt) {
1798 		browser->min_pcnt = min_pcnt;
1799 		hist_browser__update_nr_entries(browser);
1800 	}
1801 
1802 	browser->pstack = pstack__new(3);
1803 	if (browser->pstack == NULL)
1804 		goto out;
1805 
1806 	ui_helpline__push(helpline);
1807 
1808 	memset(options, 0, sizeof(options));
1809 	memset(actions, 0, sizeof(actions));
1810 
1811 	perf_hpp__for_each_format(fmt) {
1812 		perf_hpp__reset_width(fmt, hists);
1813 		/*
1814 		 * This is done just once, and activates the horizontal scrolling
1815 		 * code in the ui_browser code, it would be better to have a the
1816 		 * counter in the perf_hpp code, but I couldn't find doing it here
1817 		 * works, FIXME by setting this in hist_browser__new, for now, be
1818 		 * clever 8-)
1819 		 */
1820 		++browser->b.columns;
1821 	}
1822 
1823 	if (symbol_conf.col_width_list_str)
1824 		perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1825 
1826 	while (1) {
1827 		struct thread *thread = NULL;
1828 		struct map *map = NULL;
1829 		int choice = 0;
1830 		int socked_id = -1;
1831 
1832 		nr_options = 0;
1833 
1834 		key = hist_browser__run(browser, helpline);
1835 
1836 		if (browser->he_selection != NULL) {
1837 			thread = hist_browser__selected_thread(browser);
1838 			map = browser->selection->map;
1839 			socked_id = browser->he_selection->socket;
1840 		}
1841 		switch (key) {
1842 		case K_TAB:
1843 		case K_UNTAB:
1844 			if (nr_events == 1)
1845 				continue;
1846 			/*
1847 			 * Exit the browser, let hists__browser_tree
1848 			 * go to the next or previous
1849 			 */
1850 			goto out_free_stack;
1851 		case 'a':
1852 			if (!sort__has_sym) {
1853 				ui_browser__warning(&browser->b, delay_secs * 2,
1854 			"Annotation is only available for symbolic views, "
1855 			"include \"sym*\" in --sort to use it.");
1856 				continue;
1857 			}
1858 
1859 			if (browser->selection == NULL ||
1860 			    browser->selection->sym == NULL ||
1861 			    browser->selection->map->dso->annotate_warned)
1862 				continue;
1863 
1864 			actions->ms.map = browser->selection->map;
1865 			actions->ms.sym = browser->selection->sym;
1866 			do_annotate(browser, actions);
1867 			continue;
1868 		case 'P':
1869 			hist_browser__dump(browser);
1870 			continue;
1871 		case 'd':
1872 			actions->ms.map = map;
1873 			do_zoom_dso(browser, actions);
1874 			continue;
1875 		case 'V':
1876 			browser->show_dso = !browser->show_dso;
1877 			continue;
1878 		case 't':
1879 			actions->thread = thread;
1880 			do_zoom_thread(browser, actions);
1881 			continue;
1882 		case 'S':
1883 			actions->socket = socked_id;
1884 			do_zoom_socket(browser, actions);
1885 			continue;
1886 		case '/':
1887 			if (ui_browser__input_window("Symbol to show",
1888 					"Please enter the name of symbol you want to see.\n"
1889 					"To remove the filter later, press / + ENTER.",
1890 					buf, "ENTER: OK, ESC: Cancel",
1891 					delay_secs * 2) == K_ENTER) {
1892 				hists->symbol_filter_str = *buf ? buf : NULL;
1893 				hists__filter_by_symbol(hists);
1894 				hist_browser__reset(browser);
1895 			}
1896 			continue;
1897 		case 'r':
1898 			if (is_report_browser(hbt)) {
1899 				actions->thread = NULL;
1900 				actions->ms.sym = NULL;
1901 				do_run_script(browser, actions);
1902 			}
1903 			continue;
1904 		case 's':
1905 			if (is_report_browser(hbt)) {
1906 				key = do_switch_data(browser, actions);
1907 				if (key == K_SWITCH_INPUT_DATA)
1908 					goto out_free_stack;
1909 			}
1910 			continue;
1911 		case 'i':
1912 			/* env->arch is NULL for live-mode (i.e. perf top) */
1913 			if (env->arch)
1914 				tui__header_window(env);
1915 			continue;
1916 		case 'F':
1917 			symbol_conf.filter_relative ^= 1;
1918 			continue;
1919 		case 'z':
1920 			if (!is_report_browser(hbt)) {
1921 				struct perf_top *top = hbt->arg;
1922 
1923 				top->zero = !top->zero;
1924 			}
1925 			continue;
1926 		case K_F1:
1927 		case 'h':
1928 		case '?':
1929 			ui_browser__help_window(&browser->b,
1930 				is_report_browser(hbt) ? report_help : top_help);
1931 			continue;
1932 		case K_ENTER:
1933 		case K_RIGHT:
1934 		case 'm':
1935 			/* menu */
1936 			break;
1937 		case K_ESC:
1938 		case K_LEFT: {
1939 			const void *top;
1940 
1941 			if (pstack__empty(browser->pstack)) {
1942 				/*
1943 				 * Go back to the perf_evsel_menu__run or other user
1944 				 */
1945 				if (left_exits)
1946 					goto out_free_stack;
1947 
1948 				if (key == K_ESC &&
1949 				    ui_browser__dialog_yesno(&browser->b,
1950 							     "Do you really want to exit?"))
1951 					goto out_free_stack;
1952 
1953 				continue;
1954 			}
1955 			top = pstack__peek(browser->pstack);
1956 			if (top == &browser->hists->dso_filter) {
1957 				/*
1958 				 * No need to set actions->dso here since
1959 				 * it's just to remove the current filter.
1960 				 * Ditto for thread below.
1961 				 */
1962 				do_zoom_dso(browser, actions);
1963 			} else if (top == &browser->hists->thread_filter) {
1964 				do_zoom_thread(browser, actions);
1965 			} else if (top == &browser->hists->socket_filter) {
1966 				do_zoom_socket(browser, actions);
1967 			}
1968 			continue;
1969 		}
1970 		case 'q':
1971 		case CTRL('c'):
1972 			goto out_free_stack;
1973 		case 'f':
1974 			if (!is_report_browser(hbt)) {
1975 				struct perf_top *top = hbt->arg;
1976 
1977 				perf_evlist__toggle_enable(top->evlist);
1978 				/*
1979 				 * No need to refresh, resort/decay histogram
1980 				 * entries if we are not collecting samples:
1981 				 */
1982 				if (top->evlist->enabled) {
1983 					helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
1984 					hbt->refresh = delay_secs;
1985 				} else {
1986 					helpline = "Press 'f' again to re-enable the events";
1987 					hbt->refresh = 0;
1988 				}
1989 				continue;
1990 			}
1991 			/* Fall thru */
1992 		default:
1993 			helpline = "Press '?' for help on key bindings";
1994 			continue;
1995 		}
1996 
1997 		if (!sort__has_sym)
1998 			goto add_exit_option;
1999 
2000 		if (browser->selection == NULL)
2001 			goto skip_annotation;
2002 
2003 		if (sort__mode == SORT_MODE__BRANCH) {
2004 			bi = browser->he_selection->branch_info;
2005 
2006 			if (bi == NULL)
2007 				goto skip_annotation;
2008 
2009 			nr_options += add_annotate_opt(browser,
2010 						       &actions[nr_options],
2011 						       &options[nr_options],
2012 						       bi->from.map,
2013 						       bi->from.sym);
2014 			if (bi->to.sym != bi->from.sym)
2015 				nr_options += add_annotate_opt(browser,
2016 							&actions[nr_options],
2017 							&options[nr_options],
2018 							bi->to.map,
2019 							bi->to.sym);
2020 		} else {
2021 			nr_options += add_annotate_opt(browser,
2022 						       &actions[nr_options],
2023 						       &options[nr_options],
2024 						       browser->selection->map,
2025 						       browser->selection->sym);
2026 		}
2027 skip_annotation:
2028 		nr_options += add_thread_opt(browser, &actions[nr_options],
2029 					     &options[nr_options], thread);
2030 		nr_options += add_dso_opt(browser, &actions[nr_options],
2031 					  &options[nr_options], map);
2032 		nr_options += add_map_opt(browser, &actions[nr_options],
2033 					  &options[nr_options],
2034 					  browser->selection ?
2035 						browser->selection->map : NULL);
2036 		nr_options += add_socket_opt(browser, &actions[nr_options],
2037 					     &options[nr_options],
2038 					     socked_id);
2039 		/* perf script support */
2040 		if (browser->he_selection) {
2041 			nr_options += add_script_opt(browser,
2042 						     &actions[nr_options],
2043 						     &options[nr_options],
2044 						     thread, NULL);
2045 			/*
2046 			 * Note that browser->selection != NULL
2047 			 * when browser->he_selection is not NULL,
2048 			 * so we don't need to check browser->selection
2049 			 * before fetching browser->selection->sym like what
2050 			 * we do before fetching browser->selection->map.
2051 			 *
2052 			 * See hist_browser__show_entry.
2053 			 */
2054 			nr_options += add_script_opt(browser,
2055 						     &actions[nr_options],
2056 						     &options[nr_options],
2057 						     NULL, browser->selection->sym);
2058 		}
2059 		nr_options += add_script_opt(browser, &actions[nr_options],
2060 					     &options[nr_options], NULL, NULL);
2061 		nr_options += add_switch_opt(browser, &actions[nr_options],
2062 					     &options[nr_options]);
2063 add_exit_option:
2064 		nr_options += add_exit_opt(browser, &actions[nr_options],
2065 					   &options[nr_options]);
2066 
2067 		do {
2068 			struct popup_action *act;
2069 
2070 			choice = ui__popup_menu(nr_options, options);
2071 			if (choice == -1 || choice >= nr_options)
2072 				break;
2073 
2074 			act = &actions[choice];
2075 			key = act->fn(browser, act);
2076 		} while (key == 1);
2077 
2078 		if (key == K_SWITCH_INPUT_DATA)
2079 			break;
2080 	}
2081 out_free_stack:
2082 	pstack__delete(browser->pstack);
2083 out:
2084 	hist_browser__delete(browser);
2085 	free_popup_options(options, MAX_OPTIONS);
2086 	return key;
2087 }
2088 
2089 struct perf_evsel_menu {
2090 	struct ui_browser b;
2091 	struct perf_evsel *selection;
2092 	bool lost_events, lost_events_warned;
2093 	float min_pcnt;
2094 	struct perf_env *env;
2095 };
2096 
2097 static void perf_evsel_menu__write(struct ui_browser *browser,
2098 				   void *entry, int row)
2099 {
2100 	struct perf_evsel_menu *menu = container_of(browser,
2101 						    struct perf_evsel_menu, b);
2102 	struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2103 	struct hists *hists = evsel__hists(evsel);
2104 	bool current_entry = ui_browser__is_current_entry(browser, row);
2105 	unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2106 	const char *ev_name = perf_evsel__name(evsel);
2107 	char bf[256], unit;
2108 	const char *warn = " ";
2109 	size_t printed;
2110 
2111 	ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
2112 						       HE_COLORSET_NORMAL);
2113 
2114 	if (perf_evsel__is_group_event(evsel)) {
2115 		struct perf_evsel *pos;
2116 
2117 		ev_name = perf_evsel__group_name(evsel);
2118 
2119 		for_each_group_member(pos, evsel) {
2120 			struct hists *pos_hists = evsel__hists(pos);
2121 			nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2122 		}
2123 	}
2124 
2125 	nr_events = convert_unit(nr_events, &unit);
2126 	printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
2127 			   unit, unit == ' ' ? "" : " ", ev_name);
2128 	ui_browser__printf(browser, "%s", bf);
2129 
2130 	nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
2131 	if (nr_events != 0) {
2132 		menu->lost_events = true;
2133 		if (!current_entry)
2134 			ui_browser__set_color(browser, HE_COLORSET_TOP);
2135 		nr_events = convert_unit(nr_events, &unit);
2136 		printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
2137 				     nr_events, unit, unit == ' ' ? "" : " ");
2138 		warn = bf;
2139 	}
2140 
2141 	ui_browser__write_nstring(browser, warn, browser->width - printed);
2142 
2143 	if (current_entry)
2144 		menu->selection = evsel;
2145 }
2146 
2147 static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
2148 				int nr_events, const char *help,
2149 				struct hist_browser_timer *hbt)
2150 {
2151 	struct perf_evlist *evlist = menu->b.priv;
2152 	struct perf_evsel *pos;
2153 	const char *title = "Available samples";
2154 	int delay_secs = hbt ? hbt->refresh : 0;
2155 	int key;
2156 
2157 	if (ui_browser__show(&menu->b, title,
2158 			     "ESC: exit, ENTER|->: Browse histograms") < 0)
2159 		return -1;
2160 
2161 	while (1) {
2162 		key = ui_browser__run(&menu->b, delay_secs);
2163 
2164 		switch (key) {
2165 		case K_TIMER:
2166 			hbt->timer(hbt->arg);
2167 
2168 			if (!menu->lost_events_warned && menu->lost_events) {
2169 				ui_browser__warn_lost_events(&menu->b);
2170 				menu->lost_events_warned = true;
2171 			}
2172 			continue;
2173 		case K_RIGHT:
2174 		case K_ENTER:
2175 			if (!menu->selection)
2176 				continue;
2177 			pos = menu->selection;
2178 browse_hists:
2179 			perf_evlist__set_selected(evlist, pos);
2180 			/*
2181 			 * Give the calling tool a chance to populate the non
2182 			 * default evsel resorted hists tree.
2183 			 */
2184 			if (hbt)
2185 				hbt->timer(hbt->arg);
2186 			key = perf_evsel__hists_browse(pos, nr_events, help,
2187 						       true, hbt,
2188 						       menu->min_pcnt,
2189 						       menu->env);
2190 			ui_browser__show_title(&menu->b, title);
2191 			switch (key) {
2192 			case K_TAB:
2193 				if (pos->node.next == &evlist->entries)
2194 					pos = perf_evlist__first(evlist);
2195 				else
2196 					pos = perf_evsel__next(pos);
2197 				goto browse_hists;
2198 			case K_UNTAB:
2199 				if (pos->node.prev == &evlist->entries)
2200 					pos = perf_evlist__last(evlist);
2201 				else
2202 					pos = perf_evsel__prev(pos);
2203 				goto browse_hists;
2204 			case K_SWITCH_INPUT_DATA:
2205 			case 'q':
2206 			case CTRL('c'):
2207 				goto out;
2208 			case K_ESC:
2209 			default:
2210 				continue;
2211 			}
2212 		case K_LEFT:
2213 			continue;
2214 		case K_ESC:
2215 			if (!ui_browser__dialog_yesno(&menu->b,
2216 					       "Do you really want to exit?"))
2217 				continue;
2218 			/* Fall thru */
2219 		case 'q':
2220 		case CTRL('c'):
2221 			goto out;
2222 		default:
2223 			continue;
2224 		}
2225 	}
2226 
2227 out:
2228 	ui_browser__hide(&menu->b);
2229 	return key;
2230 }
2231 
2232 static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
2233 				 void *entry)
2234 {
2235 	struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2236 
2237 	if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2238 		return true;
2239 
2240 	return false;
2241 }
2242 
2243 static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
2244 					   int nr_entries, const char *help,
2245 					   struct hist_browser_timer *hbt,
2246 					   float min_pcnt,
2247 					   struct perf_env *env)
2248 {
2249 	struct perf_evsel *pos;
2250 	struct perf_evsel_menu menu = {
2251 		.b = {
2252 			.entries    = &evlist->entries,
2253 			.refresh    = ui_browser__list_head_refresh,
2254 			.seek	    = ui_browser__list_head_seek,
2255 			.write	    = perf_evsel_menu__write,
2256 			.filter	    = filter_group_entries,
2257 			.nr_entries = nr_entries,
2258 			.priv	    = evlist,
2259 		},
2260 		.min_pcnt = min_pcnt,
2261 		.env = env,
2262 	};
2263 
2264 	ui_helpline__push("Press ESC to exit");
2265 
2266 	evlist__for_each(evlist, pos) {
2267 		const char *ev_name = perf_evsel__name(pos);
2268 		size_t line_len = strlen(ev_name) + 7;
2269 
2270 		if (menu.b.width < line_len)
2271 			menu.b.width = line_len;
2272 	}
2273 
2274 	return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
2275 }
2276 
2277 int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
2278 				  struct hist_browser_timer *hbt,
2279 				  float min_pcnt,
2280 				  struct perf_env *env)
2281 {
2282 	int nr_entries = evlist->nr_entries;
2283 
2284 single_entry:
2285 	if (nr_entries == 1) {
2286 		struct perf_evsel *first = perf_evlist__first(evlist);
2287 
2288 		return perf_evsel__hists_browse(first, nr_entries, help,
2289 						false, hbt, min_pcnt,
2290 						env);
2291 	}
2292 
2293 	if (symbol_conf.event_group) {
2294 		struct perf_evsel *pos;
2295 
2296 		nr_entries = 0;
2297 		evlist__for_each(evlist, pos) {
2298 			if (perf_evsel__is_group_leader(pos))
2299 				nr_entries++;
2300 		}
2301 
2302 		if (nr_entries == 1)
2303 			goto single_entry;
2304 	}
2305 
2306 	return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
2307 					       hbt, min_pcnt, env);
2308 }
2309