18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <dirent.h>
38c2ecf20Sopenharmony_ci#include <errno.h>
48c2ecf20Sopenharmony_ci#include <inttypes.h>
58c2ecf20Sopenharmony_ci#include <stdio.h>
68c2ecf20Sopenharmony_ci#include <stdlib.h>
78c2ecf20Sopenharmony_ci#include <string.h>
88c2ecf20Sopenharmony_ci#include <linux/rbtree.h>
98c2ecf20Sopenharmony_ci#include <linux/string.h>
108c2ecf20Sopenharmony_ci#include <sys/ttydefaults.h>
118c2ecf20Sopenharmony_ci#include <linux/time64.h>
128c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "../../util/debug.h"
158c2ecf20Sopenharmony_ci#include "../../util/dso.h"
168c2ecf20Sopenharmony_ci#include "../../util/callchain.h"
178c2ecf20Sopenharmony_ci#include "../../util/evsel.h"
188c2ecf20Sopenharmony_ci#include "../../util/evlist.h"
198c2ecf20Sopenharmony_ci#include "../../util/header.h"
208c2ecf20Sopenharmony_ci#include "../../util/hist.h"
218c2ecf20Sopenharmony_ci#include "../../util/machine.h"
228c2ecf20Sopenharmony_ci#include "../../util/map.h"
238c2ecf20Sopenharmony_ci#include "../../util/maps.h"
248c2ecf20Sopenharmony_ci#include "../../util/symbol.h"
258c2ecf20Sopenharmony_ci#include "../../util/map_symbol.h"
268c2ecf20Sopenharmony_ci#include "../../util/branch.h"
278c2ecf20Sopenharmony_ci#include "../../util/pstack.h"
288c2ecf20Sopenharmony_ci#include "../../util/sort.h"
298c2ecf20Sopenharmony_ci#include "../../util/top.h"
308c2ecf20Sopenharmony_ci#include "../../util/thread.h"
318c2ecf20Sopenharmony_ci#include "../../util/block-info.h"
328c2ecf20Sopenharmony_ci#include "../../arch/common.h"
338c2ecf20Sopenharmony_ci#include "../../perf.h"
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include "../browsers/hists.h"
368c2ecf20Sopenharmony_ci#include "../helpline.h"
378c2ecf20Sopenharmony_ci#include "../util.h"
388c2ecf20Sopenharmony_ci#include "../ui.h"
398c2ecf20Sopenharmony_ci#include "map.h"
408c2ecf20Sopenharmony_ci#include "annotate.h"
418c2ecf20Sopenharmony_ci#include "srcline.h"
428c2ecf20Sopenharmony_ci#include "string2.h"
438c2ecf20Sopenharmony_ci#include "units.h"
448c2ecf20Sopenharmony_ci#include "time-utils.h"
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#include <linux/ctype.h>
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ciextern void hist_browser__init_hpp(void);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size);
518c2ecf20Sopenharmony_cistatic void hist_browser__update_nr_entries(struct hist_browser *hb);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic struct rb_node *hists__filter_entries(struct rb_node *nd,
548c2ecf20Sopenharmony_ci					     float min_pcnt);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic bool hist_browser__has_filter(struct hist_browser *hb)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic int hist_browser__get_folding(struct hist_browser *browser)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	struct rb_node *nd;
648c2ecf20Sopenharmony_ci	struct hists *hists = browser->hists;
658c2ecf20Sopenharmony_ci	int unfolded_rows = 0;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	for (nd = rb_first_cached(&hists->entries);
688c2ecf20Sopenharmony_ci	     (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
698c2ecf20Sopenharmony_ci	     nd = rb_hierarchy_next(nd)) {
708c2ecf20Sopenharmony_ci		struct hist_entry *he =
718c2ecf20Sopenharmony_ci			rb_entry(nd, struct hist_entry, rb_node);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci		if (he->leaf && he->unfolded)
748c2ecf20Sopenharmony_ci			unfolded_rows += he->nr_rows;
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci	return unfolded_rows;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic void hist_browser__set_title_space(struct hist_browser *hb)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	struct ui_browser *browser = &hb->b;
828c2ecf20Sopenharmony_ci	struct hists *hists = hb->hists;
838c2ecf20Sopenharmony_ci	struct perf_hpp_list *hpp_list = hists->hpp_list;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	browser->extra_title_lines = hb->show_headers ? hpp_list->nr_header_lines : 0;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic u32 hist_browser__nr_entries(struct hist_browser *hb)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	u32 nr_entries;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (symbol_conf.report_hierarchy)
938c2ecf20Sopenharmony_ci		nr_entries = hb->nr_hierarchy_entries;
948c2ecf20Sopenharmony_ci	else if (hist_browser__has_filter(hb))
958c2ecf20Sopenharmony_ci		nr_entries = hb->nr_non_filtered_entries;
968c2ecf20Sopenharmony_ci	else
978c2ecf20Sopenharmony_ci		nr_entries = hb->hists->nr_entries;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	hb->nr_callchain_rows = hist_browser__get_folding(hb);
1008c2ecf20Sopenharmony_ci	return nr_entries + hb->nr_callchain_rows;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic void hist_browser__update_rows(struct hist_browser *hb)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	struct ui_browser *browser = &hb->b;
1068c2ecf20Sopenharmony_ci	struct hists *hists = hb->hists;
1078c2ecf20Sopenharmony_ci	struct perf_hpp_list *hpp_list = hists->hpp_list;
1088c2ecf20Sopenharmony_ci	u16 index_row;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	if (!hb->show_headers) {
1118c2ecf20Sopenharmony_ci		browser->rows += browser->extra_title_lines;
1128c2ecf20Sopenharmony_ci		browser->extra_title_lines = 0;
1138c2ecf20Sopenharmony_ci		return;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	browser->extra_title_lines = hpp_list->nr_header_lines;
1178c2ecf20Sopenharmony_ci	browser->rows -= browser->extra_title_lines;
1188c2ecf20Sopenharmony_ci	/*
1198c2ecf20Sopenharmony_ci	 * Verify if we were at the last line and that line isn't
1208c2ecf20Sopenharmony_ci	 * visibe because we now show the header line(s).
1218c2ecf20Sopenharmony_ci	 */
1228c2ecf20Sopenharmony_ci	index_row = browser->index - browser->top_idx;
1238c2ecf20Sopenharmony_ci	if (index_row >= browser->rows)
1248c2ecf20Sopenharmony_ci		browser->index -= index_row - browser->rows + 1;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic void hist_browser__refresh_dimensions(struct ui_browser *browser)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	struct hist_browser *hb = container_of(browser, struct hist_browser, b);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/* 3 == +/- toggle symbol before actual hist_entry rendering */
1328c2ecf20Sopenharmony_ci	browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
1338c2ecf20Sopenharmony_ci	/*
1348c2ecf20Sopenharmony_ci 	 * FIXME: Just keeping existing behaviour, but this really should be
1358c2ecf20Sopenharmony_ci 	 *	  before updating browser->width, as it will invalidate the
1368c2ecf20Sopenharmony_ci 	 *	  calculation above. Fix this and the fallout in another
1378c2ecf20Sopenharmony_ci 	 *	  changeset.
1388c2ecf20Sopenharmony_ci 	 */
1398c2ecf20Sopenharmony_ci	ui_browser__refresh_dimensions(browser);
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic void hist_browser__reset(struct hist_browser *browser)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	/*
1458c2ecf20Sopenharmony_ci	 * The hists__remove_entry_filter() already folds non-filtered
1468c2ecf20Sopenharmony_ci	 * entries so we can assume it has 0 callchain rows.
1478c2ecf20Sopenharmony_ci	 */
1488c2ecf20Sopenharmony_ci	browser->nr_callchain_rows = 0;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	hist_browser__update_nr_entries(browser);
1518c2ecf20Sopenharmony_ci	browser->b.nr_entries = hist_browser__nr_entries(browser);
1528c2ecf20Sopenharmony_ci	hist_browser__refresh_dimensions(&browser->b);
1538c2ecf20Sopenharmony_ci	ui_browser__reset_index(&browser->b);
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic char tree__folded_sign(bool unfolded)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	return unfolded ? '-' : '+';
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic char hist_entry__folded(const struct hist_entry *he)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic char callchain_list__folded(const struct callchain_list *cl)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	cl->unfolded = unfold ? cl->has_children : false;
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic int callchain_node__count_rows_rb_tree(struct callchain_node *node)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	int n = 0;
1798c2ecf20Sopenharmony_ci	struct rb_node *nd;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
1828c2ecf20Sopenharmony_ci		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
1838c2ecf20Sopenharmony_ci		struct callchain_list *chain;
1848c2ecf20Sopenharmony_ci		char folded_sign = ' '; /* No children */
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci		list_for_each_entry(chain, &child->val, list) {
1878c2ecf20Sopenharmony_ci			++n;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci			/* We need this because we may not have children */
1908c2ecf20Sopenharmony_ci			folded_sign = callchain_list__folded(chain);
1918c2ecf20Sopenharmony_ci			if (folded_sign == '+')
1928c2ecf20Sopenharmony_ci				break;
1938c2ecf20Sopenharmony_ci		}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci		if (folded_sign == '-') /* Have children and they're unfolded */
1968c2ecf20Sopenharmony_ci			n += callchain_node__count_rows_rb_tree(child);
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	return n;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic int callchain_node__count_flat_rows(struct callchain_node *node)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	struct callchain_list *chain;
2058c2ecf20Sopenharmony_ci	char folded_sign = 0;
2068c2ecf20Sopenharmony_ci	int n = 0;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	list_for_each_entry(chain, &node->parent_val, list) {
2098c2ecf20Sopenharmony_ci		if (!folded_sign) {
2108c2ecf20Sopenharmony_ci			/* only check first chain list entry */
2118c2ecf20Sopenharmony_ci			folded_sign = callchain_list__folded(chain);
2128c2ecf20Sopenharmony_ci			if (folded_sign == '+')
2138c2ecf20Sopenharmony_ci				return 1;
2148c2ecf20Sopenharmony_ci		}
2158c2ecf20Sopenharmony_ci		n++;
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	list_for_each_entry(chain, &node->val, list) {
2198c2ecf20Sopenharmony_ci		if (!folded_sign) {
2208c2ecf20Sopenharmony_ci			/* node->parent_val list might be empty */
2218c2ecf20Sopenharmony_ci			folded_sign = callchain_list__folded(chain);
2228c2ecf20Sopenharmony_ci			if (folded_sign == '+')
2238c2ecf20Sopenharmony_ci				return 1;
2248c2ecf20Sopenharmony_ci		}
2258c2ecf20Sopenharmony_ci		n++;
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	return n;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	return 1;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic int callchain_node__count_rows(struct callchain_node *node)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	struct callchain_list *chain;
2398c2ecf20Sopenharmony_ci	bool unfolded = false;
2408c2ecf20Sopenharmony_ci	int n = 0;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	if (callchain_param.mode == CHAIN_FLAT)
2438c2ecf20Sopenharmony_ci		return callchain_node__count_flat_rows(node);
2448c2ecf20Sopenharmony_ci	else if (callchain_param.mode == CHAIN_FOLDED)
2458c2ecf20Sopenharmony_ci		return callchain_node__count_folded_rows(node);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	list_for_each_entry(chain, &node->val, list) {
2488c2ecf20Sopenharmony_ci		++n;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci		unfolded = chain->unfolded;
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	if (unfolded)
2548c2ecf20Sopenharmony_ci		n += callchain_node__count_rows_rb_tree(node);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	return n;
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic int callchain__count_rows(struct rb_root *chain)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	struct rb_node *nd;
2628c2ecf20Sopenharmony_ci	int n = 0;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
2658c2ecf20Sopenharmony_ci		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
2668c2ecf20Sopenharmony_ci		n += callchain_node__count_rows(node);
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	return n;
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
2738c2ecf20Sopenharmony_ci				bool include_children)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	int count = 0;
2768c2ecf20Sopenharmony_ci	struct rb_node *node;
2778c2ecf20Sopenharmony_ci	struct hist_entry *child;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	if (he->leaf)
2808c2ecf20Sopenharmony_ci		return callchain__count_rows(&he->sorted_chain);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	if (he->has_no_entry)
2838c2ecf20Sopenharmony_ci		return 1;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	node = rb_first_cached(&he->hroot_out);
2868c2ecf20Sopenharmony_ci	while (node) {
2878c2ecf20Sopenharmony_ci		float percent;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci		child = rb_entry(node, struct hist_entry, rb_node);
2908c2ecf20Sopenharmony_ci		percent = hist_entry__get_percent_limit(child);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci		if (!child->filtered && percent >= hb->min_pcnt) {
2938c2ecf20Sopenharmony_ci			count++;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci			if (include_children && child->unfolded)
2968c2ecf20Sopenharmony_ci				count += hierarchy_count_rows(hb, child, true);
2978c2ecf20Sopenharmony_ci		}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci		node = rb_next(node);
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci	return count;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic bool hist_entry__toggle_fold(struct hist_entry *he)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	if (!he)
3078c2ecf20Sopenharmony_ci		return false;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	if (!he->has_children)
3108c2ecf20Sopenharmony_ci		return false;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	he->unfolded = !he->unfolded;
3138c2ecf20Sopenharmony_ci	return true;
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic bool callchain_list__toggle_fold(struct callchain_list *cl)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	if (!cl)
3198c2ecf20Sopenharmony_ci		return false;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if (!cl->has_children)
3228c2ecf20Sopenharmony_ci		return false;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	cl->unfolded = !cl->unfolded;
3258c2ecf20Sopenharmony_ci	return true;
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cistatic void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	struct rb_node *nd = rb_first(&node->rb_root);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
3338c2ecf20Sopenharmony_ci		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
3348c2ecf20Sopenharmony_ci		struct callchain_list *chain;
3358c2ecf20Sopenharmony_ci		bool first = true;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci		list_for_each_entry(chain, &child->val, list) {
3388c2ecf20Sopenharmony_ci			if (first) {
3398c2ecf20Sopenharmony_ci				first = false;
3408c2ecf20Sopenharmony_ci				chain->has_children = chain->list.next != &child->val ||
3418c2ecf20Sopenharmony_ci							 !RB_EMPTY_ROOT(&child->rb_root);
3428c2ecf20Sopenharmony_ci			} else
3438c2ecf20Sopenharmony_ci				chain->has_children = chain->list.next == &child->val &&
3448c2ecf20Sopenharmony_ci							 !RB_EMPTY_ROOT(&child->rb_root);
3458c2ecf20Sopenharmony_ci		}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci		callchain_node__init_have_children_rb_tree(child);
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_cistatic void callchain_node__init_have_children(struct callchain_node *node,
3528c2ecf20Sopenharmony_ci					       bool has_sibling)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	struct callchain_list *chain;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	chain = list_entry(node->val.next, struct callchain_list, list);
3578c2ecf20Sopenharmony_ci	chain->has_children = has_sibling;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (!list_empty(&node->val)) {
3608c2ecf20Sopenharmony_ci		chain = list_entry(node->val.prev, struct callchain_list, list);
3618c2ecf20Sopenharmony_ci		chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	callchain_node__init_have_children_rb_tree(node);
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_cistatic void callchain__init_have_children(struct rb_root *root)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	struct rb_node *nd = rb_first(root);
3708c2ecf20Sopenharmony_ci	bool has_sibling = nd && rb_next(nd);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	for (nd = rb_first(root); nd; nd = rb_next(nd)) {
3738c2ecf20Sopenharmony_ci		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
3748c2ecf20Sopenharmony_ci		callchain_node__init_have_children(node, has_sibling);
3758c2ecf20Sopenharmony_ci		if (callchain_param.mode == CHAIN_FLAT ||
3768c2ecf20Sopenharmony_ci		    callchain_param.mode == CHAIN_FOLDED)
3778c2ecf20Sopenharmony_ci			callchain_node__make_parent_list(node);
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic void hist_entry__init_have_children(struct hist_entry *he)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	if (he->init_have_children)
3848c2ecf20Sopenharmony_ci		return;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	if (he->leaf) {
3878c2ecf20Sopenharmony_ci		he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
3888c2ecf20Sopenharmony_ci		callchain__init_have_children(&he->sorted_chain);
3898c2ecf20Sopenharmony_ci	} else {
3908c2ecf20Sopenharmony_ci		he->has_children = !RB_EMPTY_ROOT(&he->hroot_out.rb_root);
3918c2ecf20Sopenharmony_ci	}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	he->init_have_children = true;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_cistatic bool hist_browser__selection_has_children(struct hist_browser *browser)
3978c2ecf20Sopenharmony_ci{
3988c2ecf20Sopenharmony_ci	struct hist_entry *he = browser->he_selection;
3998c2ecf20Sopenharmony_ci	struct map_symbol *ms = browser->selection;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	if (!he || !ms)
4028c2ecf20Sopenharmony_ci		return false;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	if (ms == &he->ms)
4058c2ecf20Sopenharmony_ci	       return he->has_children;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	return container_of(ms, struct callchain_list, ms)->has_children;
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_cistatic bool hist_browser__selection_unfolded(struct hist_browser *browser)
4118c2ecf20Sopenharmony_ci{
4128c2ecf20Sopenharmony_ci	struct hist_entry *he = browser->he_selection;
4138c2ecf20Sopenharmony_ci	struct map_symbol *ms = browser->selection;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	if (!he || !ms)
4168c2ecf20Sopenharmony_ci		return false;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	if (ms == &he->ms)
4198c2ecf20Sopenharmony_ci	       return he->unfolded;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	return container_of(ms, struct callchain_list, ms)->unfolded;
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cistatic char *hist_browser__selection_sym_name(struct hist_browser *browser, char *bf, size_t size)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	struct hist_entry *he = browser->he_selection;
4278c2ecf20Sopenharmony_ci	struct map_symbol *ms = browser->selection;
4288c2ecf20Sopenharmony_ci	struct callchain_list *callchain_entry;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	if (!he || !ms)
4318c2ecf20Sopenharmony_ci		return NULL;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	if (ms == &he->ms) {
4348c2ecf20Sopenharmony_ci	       hist_entry__sym_snprintf(he, bf, size, 0);
4358c2ecf20Sopenharmony_ci	       return bf + 4; // skip the level, e.g. '[k] '
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	callchain_entry = container_of(ms, struct callchain_list, ms);
4398c2ecf20Sopenharmony_ci	return callchain_list__sym_name(callchain_entry, bf, size, browser->show_dso);
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic bool hist_browser__toggle_fold(struct hist_browser *browser)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	struct hist_entry *he = browser->he_selection;
4458c2ecf20Sopenharmony_ci	struct map_symbol *ms = browser->selection;
4468c2ecf20Sopenharmony_ci	struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
4478c2ecf20Sopenharmony_ci	bool has_children;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	if (!he || !ms)
4508c2ecf20Sopenharmony_ci		return false;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	if (ms == &he->ms)
4538c2ecf20Sopenharmony_ci		has_children = hist_entry__toggle_fold(he);
4548c2ecf20Sopenharmony_ci	else
4558c2ecf20Sopenharmony_ci		has_children = callchain_list__toggle_fold(cl);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	if (has_children) {
4588c2ecf20Sopenharmony_ci		int child_rows = 0;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci		hist_entry__init_have_children(he);
4618c2ecf20Sopenharmony_ci		browser->b.nr_entries -= he->nr_rows;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci		if (he->leaf)
4648c2ecf20Sopenharmony_ci			browser->nr_callchain_rows -= he->nr_rows;
4658c2ecf20Sopenharmony_ci		else
4668c2ecf20Sopenharmony_ci			browser->nr_hierarchy_entries -= he->nr_rows;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci		if (symbol_conf.report_hierarchy)
4698c2ecf20Sopenharmony_ci			child_rows = hierarchy_count_rows(browser, he, true);
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci		if (he->unfolded) {
4728c2ecf20Sopenharmony_ci			if (he->leaf)
4738c2ecf20Sopenharmony_ci				he->nr_rows = callchain__count_rows(
4748c2ecf20Sopenharmony_ci						&he->sorted_chain);
4758c2ecf20Sopenharmony_ci			else
4768c2ecf20Sopenharmony_ci				he->nr_rows = hierarchy_count_rows(browser, he, false);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci			/* account grand children */
4798c2ecf20Sopenharmony_ci			if (symbol_conf.report_hierarchy)
4808c2ecf20Sopenharmony_ci				browser->b.nr_entries += child_rows - he->nr_rows;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci			if (!he->leaf && he->nr_rows == 0) {
4838c2ecf20Sopenharmony_ci				he->has_no_entry = true;
4848c2ecf20Sopenharmony_ci				he->nr_rows = 1;
4858c2ecf20Sopenharmony_ci			}
4868c2ecf20Sopenharmony_ci		} else {
4878c2ecf20Sopenharmony_ci			if (symbol_conf.report_hierarchy)
4888c2ecf20Sopenharmony_ci				browser->b.nr_entries -= child_rows - he->nr_rows;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci			if (he->has_no_entry)
4918c2ecf20Sopenharmony_ci				he->has_no_entry = false;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci			he->nr_rows = 0;
4948c2ecf20Sopenharmony_ci		}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci		browser->b.nr_entries += he->nr_rows;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci		if (he->leaf)
4998c2ecf20Sopenharmony_ci			browser->nr_callchain_rows += he->nr_rows;
5008c2ecf20Sopenharmony_ci		else
5018c2ecf20Sopenharmony_ci			browser->nr_hierarchy_entries += he->nr_rows;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci		return true;
5048c2ecf20Sopenharmony_ci	}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	/* If it doesn't have children, no toggling performed */
5078c2ecf20Sopenharmony_ci	return false;
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	int n = 0;
5138c2ecf20Sopenharmony_ci	struct rb_node *nd;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
5168c2ecf20Sopenharmony_ci		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
5178c2ecf20Sopenharmony_ci		struct callchain_list *chain;
5188c2ecf20Sopenharmony_ci		bool has_children = false;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci		list_for_each_entry(chain, &child->val, list) {
5218c2ecf20Sopenharmony_ci			++n;
5228c2ecf20Sopenharmony_ci			callchain_list__set_folding(chain, unfold);
5238c2ecf20Sopenharmony_ci			has_children = chain->has_children;
5248c2ecf20Sopenharmony_ci		}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci		if (has_children)
5278c2ecf20Sopenharmony_ci			n += callchain_node__set_folding_rb_tree(child, unfold);
5288c2ecf20Sopenharmony_ci	}
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	return n;
5318c2ecf20Sopenharmony_ci}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_cistatic int callchain_node__set_folding(struct callchain_node *node, bool unfold)
5348c2ecf20Sopenharmony_ci{
5358c2ecf20Sopenharmony_ci	struct callchain_list *chain;
5368c2ecf20Sopenharmony_ci	bool has_children = false;
5378c2ecf20Sopenharmony_ci	int n = 0;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	list_for_each_entry(chain, &node->val, list) {
5408c2ecf20Sopenharmony_ci		++n;
5418c2ecf20Sopenharmony_ci		callchain_list__set_folding(chain, unfold);
5428c2ecf20Sopenharmony_ci		has_children = chain->has_children;
5438c2ecf20Sopenharmony_ci	}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	if (has_children)
5468c2ecf20Sopenharmony_ci		n += callchain_node__set_folding_rb_tree(node, unfold);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	return n;
5498c2ecf20Sopenharmony_ci}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_cistatic int callchain__set_folding(struct rb_root *chain, bool unfold)
5528c2ecf20Sopenharmony_ci{
5538c2ecf20Sopenharmony_ci	struct rb_node *nd;
5548c2ecf20Sopenharmony_ci	int n = 0;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
5578c2ecf20Sopenharmony_ci		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
5588c2ecf20Sopenharmony_ci		n += callchain_node__set_folding(node, unfold);
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	return n;
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_cistatic int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
5658c2ecf20Sopenharmony_ci				 bool unfold __maybe_unused)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	float percent;
5688c2ecf20Sopenharmony_ci	struct rb_node *nd;
5698c2ecf20Sopenharmony_ci	struct hist_entry *child;
5708c2ecf20Sopenharmony_ci	int n = 0;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	for (nd = rb_first_cached(&he->hroot_out); nd; nd = rb_next(nd)) {
5738c2ecf20Sopenharmony_ci		child = rb_entry(nd, struct hist_entry, rb_node);
5748c2ecf20Sopenharmony_ci		percent = hist_entry__get_percent_limit(child);
5758c2ecf20Sopenharmony_ci		if (!child->filtered && percent >= hb->min_pcnt)
5768c2ecf20Sopenharmony_ci			n++;
5778c2ecf20Sopenharmony_ci	}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	return n;
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_cistatic void hist_entry__set_folding(struct hist_entry *he,
5838c2ecf20Sopenharmony_ci				    struct hist_browser *hb, bool unfold)
5848c2ecf20Sopenharmony_ci{
5858c2ecf20Sopenharmony_ci	hist_entry__init_have_children(he);
5868c2ecf20Sopenharmony_ci	he->unfolded = unfold ? he->has_children : false;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	if (he->has_children) {
5898c2ecf20Sopenharmony_ci		int n;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci		if (he->leaf)
5928c2ecf20Sopenharmony_ci			n = callchain__set_folding(&he->sorted_chain, unfold);
5938c2ecf20Sopenharmony_ci		else
5948c2ecf20Sopenharmony_ci			n = hierarchy_set_folding(hb, he, unfold);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci		he->nr_rows = unfold ? n : 0;
5978c2ecf20Sopenharmony_ci	} else
5988c2ecf20Sopenharmony_ci		he->nr_rows = 0;
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cistatic void
6028c2ecf20Sopenharmony_ci__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
6038c2ecf20Sopenharmony_ci{
6048c2ecf20Sopenharmony_ci	struct rb_node *nd;
6058c2ecf20Sopenharmony_ci	struct hist_entry *he;
6068c2ecf20Sopenharmony_ci	double percent;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	nd = rb_first_cached(&browser->hists->entries);
6098c2ecf20Sopenharmony_ci	while (nd) {
6108c2ecf20Sopenharmony_ci		he = rb_entry(nd, struct hist_entry, rb_node);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci		/* set folding state even if it's currently folded */
6138c2ecf20Sopenharmony_ci		nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci		hist_entry__set_folding(he, browser, unfold);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci		percent = hist_entry__get_percent_limit(he);
6188c2ecf20Sopenharmony_ci		if (he->filtered || percent < browser->min_pcnt)
6198c2ecf20Sopenharmony_ci			continue;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci		if (!he->depth || unfold)
6228c2ecf20Sopenharmony_ci			browser->nr_hierarchy_entries++;
6238c2ecf20Sopenharmony_ci		if (he->leaf)
6248c2ecf20Sopenharmony_ci			browser->nr_callchain_rows += he->nr_rows;
6258c2ecf20Sopenharmony_ci		else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
6268c2ecf20Sopenharmony_ci			browser->nr_hierarchy_entries++;
6278c2ecf20Sopenharmony_ci			he->has_no_entry = true;
6288c2ecf20Sopenharmony_ci			he->nr_rows = 1;
6298c2ecf20Sopenharmony_ci		} else
6308c2ecf20Sopenharmony_ci			he->has_no_entry = false;
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_cistatic void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
6358c2ecf20Sopenharmony_ci{
6368c2ecf20Sopenharmony_ci	browser->nr_hierarchy_entries = 0;
6378c2ecf20Sopenharmony_ci	browser->nr_callchain_rows = 0;
6388c2ecf20Sopenharmony_ci	__hist_browser__set_folding(browser, unfold);
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	browser->b.nr_entries = hist_browser__nr_entries(browser);
6418c2ecf20Sopenharmony_ci	/* Go to the start, we may be way after valid entries after a collapse */
6428c2ecf20Sopenharmony_ci	ui_browser__reset_index(&browser->b);
6438c2ecf20Sopenharmony_ci}
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_cistatic void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold)
6468c2ecf20Sopenharmony_ci{
6478c2ecf20Sopenharmony_ci	if (!browser->he_selection)
6488c2ecf20Sopenharmony_ci		return;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	if (unfold == browser->he_selection->unfolded)
6518c2ecf20Sopenharmony_ci		return;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	hist_browser__toggle_fold(browser);
6548c2ecf20Sopenharmony_ci}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_cistatic void ui_browser__warn_lost_events(struct ui_browser *browser)
6578c2ecf20Sopenharmony_ci{
6588c2ecf20Sopenharmony_ci	ui_browser__warning(browser, 4,
6598c2ecf20Sopenharmony_ci		"Events are being lost, check IO/CPU overload!\n\n"
6608c2ecf20Sopenharmony_ci		"You may want to run 'perf' using a RT scheduler policy:\n\n"
6618c2ecf20Sopenharmony_ci		" perf top -r 80\n\n"
6628c2ecf20Sopenharmony_ci		"Or reduce the sampling frequency.");
6638c2ecf20Sopenharmony_ci}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_cistatic int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	return browser->title ? browser->title(browser, bf, size) : 0;
6688c2ecf20Sopenharmony_ci}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_cistatic int hist_browser__handle_hotkey(struct hist_browser *browser, bool warn_lost_event, char *title, size_t size, int key)
6718c2ecf20Sopenharmony_ci{
6728c2ecf20Sopenharmony_ci	switch (key) {
6738c2ecf20Sopenharmony_ci	case K_TIMER: {
6748c2ecf20Sopenharmony_ci		struct hist_browser_timer *hbt = browser->hbt;
6758c2ecf20Sopenharmony_ci		u64 nr_entries;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci		WARN_ON_ONCE(!hbt);
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci		if (hbt)
6808c2ecf20Sopenharmony_ci			hbt->timer(hbt->arg);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci		if (hist_browser__has_filter(browser) || symbol_conf.report_hierarchy)
6838c2ecf20Sopenharmony_ci			hist_browser__update_nr_entries(browser);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci		nr_entries = hist_browser__nr_entries(browser);
6868c2ecf20Sopenharmony_ci		ui_browser__update_nr_entries(&browser->b, nr_entries);
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci		if (warn_lost_event &&
6898c2ecf20Sopenharmony_ci		    (browser->hists->stats.nr_lost_warned !=
6908c2ecf20Sopenharmony_ci		    browser->hists->stats.nr_events[PERF_RECORD_LOST])) {
6918c2ecf20Sopenharmony_ci			browser->hists->stats.nr_lost_warned =
6928c2ecf20Sopenharmony_ci				browser->hists->stats.nr_events[PERF_RECORD_LOST];
6938c2ecf20Sopenharmony_ci			ui_browser__warn_lost_events(&browser->b);
6948c2ecf20Sopenharmony_ci		}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci		hist_browser__title(browser, title, size);
6978c2ecf20Sopenharmony_ci		ui_browser__show_title(&browser->b, title);
6988c2ecf20Sopenharmony_ci		break;
6998c2ecf20Sopenharmony_ci	}
7008c2ecf20Sopenharmony_ci	case 'D': { /* Debug */
7018c2ecf20Sopenharmony_ci		struct hist_entry *h = rb_entry(browser->b.top, struct hist_entry, rb_node);
7028c2ecf20Sopenharmony_ci		static int seq;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci		ui_helpline__pop();
7058c2ecf20Sopenharmony_ci		ui_helpline__fpush("%d: nr_ent=(%d,%d), etl: %d, rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
7068c2ecf20Sopenharmony_ci				   seq++, browser->b.nr_entries, browser->hists->nr_entries,
7078c2ecf20Sopenharmony_ci				   browser->b.extra_title_lines, browser->b.rows,
7088c2ecf20Sopenharmony_ci				   browser->b.index, browser->b.top_idx, h->row_offset, h->nr_rows);
7098c2ecf20Sopenharmony_ci	}
7108c2ecf20Sopenharmony_ci		break;
7118c2ecf20Sopenharmony_ci	case 'C':
7128c2ecf20Sopenharmony_ci		/* Collapse the whole world. */
7138c2ecf20Sopenharmony_ci		hist_browser__set_folding(browser, false);
7148c2ecf20Sopenharmony_ci		break;
7158c2ecf20Sopenharmony_ci	case 'c':
7168c2ecf20Sopenharmony_ci		/* Collapse the selected entry. */
7178c2ecf20Sopenharmony_ci		hist_browser__set_folding_selected(browser, false);
7188c2ecf20Sopenharmony_ci		break;
7198c2ecf20Sopenharmony_ci	case 'E':
7208c2ecf20Sopenharmony_ci		/* Expand the whole world. */
7218c2ecf20Sopenharmony_ci		hist_browser__set_folding(browser, true);
7228c2ecf20Sopenharmony_ci		break;
7238c2ecf20Sopenharmony_ci	case 'e':
7248c2ecf20Sopenharmony_ci		/* Toggle expand/collapse the selected entry. */
7258c2ecf20Sopenharmony_ci		hist_browser__toggle_fold(browser);
7268c2ecf20Sopenharmony_ci		break;
7278c2ecf20Sopenharmony_ci	case 'H':
7288c2ecf20Sopenharmony_ci		browser->show_headers = !browser->show_headers;
7298c2ecf20Sopenharmony_ci		hist_browser__update_rows(browser);
7308c2ecf20Sopenharmony_ci		break;
7318c2ecf20Sopenharmony_ci	case '+':
7328c2ecf20Sopenharmony_ci		if (hist_browser__toggle_fold(browser))
7338c2ecf20Sopenharmony_ci			break;
7348c2ecf20Sopenharmony_ci		/* fall thru */
7358c2ecf20Sopenharmony_ci	default:
7368c2ecf20Sopenharmony_ci		return -1;
7378c2ecf20Sopenharmony_ci	}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	return 0;
7408c2ecf20Sopenharmony_ci}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ciint hist_browser__run(struct hist_browser *browser, const char *help,
7438c2ecf20Sopenharmony_ci		      bool warn_lost_event, int key)
7448c2ecf20Sopenharmony_ci{
7458c2ecf20Sopenharmony_ci	char title[160];
7468c2ecf20Sopenharmony_ci	struct hist_browser_timer *hbt = browser->hbt;
7478c2ecf20Sopenharmony_ci	int delay_secs = hbt ? hbt->refresh : 0;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	browser->b.entries = &browser->hists->entries;
7508c2ecf20Sopenharmony_ci	browser->b.nr_entries = hist_browser__nr_entries(browser);
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	hist_browser__title(browser, title, sizeof(title));
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	if (ui_browser__show(&browser->b, title, "%s", help) < 0)
7558c2ecf20Sopenharmony_ci		return -1;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	if (key && hist_browser__handle_hotkey(browser, warn_lost_event, title, sizeof(title), key))
7588c2ecf20Sopenharmony_ci		goto out;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	while (1) {
7618c2ecf20Sopenharmony_ci		key = ui_browser__run(&browser->b, delay_secs);
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci		if (hist_browser__handle_hotkey(browser, warn_lost_event, title, sizeof(title), key))
7648c2ecf20Sopenharmony_ci			break;
7658c2ecf20Sopenharmony_ci	}
7668c2ecf20Sopenharmony_ciout:
7678c2ecf20Sopenharmony_ci	ui_browser__hide(&browser->b);
7688c2ecf20Sopenharmony_ci	return key;
7698c2ecf20Sopenharmony_ci}
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_cistruct callchain_print_arg {
7728c2ecf20Sopenharmony_ci	/* for hists browser */
7738c2ecf20Sopenharmony_ci	off_t	row_offset;
7748c2ecf20Sopenharmony_ci	bool	is_current_entry;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	/* for file dump */
7778c2ecf20Sopenharmony_ci	FILE	*fp;
7788c2ecf20Sopenharmony_ci	int	printed;
7798c2ecf20Sopenharmony_ci};
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_citypedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
7828c2ecf20Sopenharmony_ci					 struct callchain_list *chain,
7838c2ecf20Sopenharmony_ci					 const char *str, int offset,
7848c2ecf20Sopenharmony_ci					 unsigned short row,
7858c2ecf20Sopenharmony_ci					 struct callchain_print_arg *arg);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_cistatic void hist_browser__show_callchain_entry(struct hist_browser *browser,
7888c2ecf20Sopenharmony_ci					       struct callchain_list *chain,
7898c2ecf20Sopenharmony_ci					       const char *str, int offset,
7908c2ecf20Sopenharmony_ci					       unsigned short row,
7918c2ecf20Sopenharmony_ci					       struct callchain_print_arg *arg)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	int color, width;
7948c2ecf20Sopenharmony_ci	char folded_sign = callchain_list__folded(chain);
7958c2ecf20Sopenharmony_ci	bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	color = HE_COLORSET_NORMAL;
7988c2ecf20Sopenharmony_ci	width = browser->b.width - (offset + 2);
7998c2ecf20Sopenharmony_ci	if (ui_browser__is_current_entry(&browser->b, row)) {
8008c2ecf20Sopenharmony_ci		browser->selection = &chain->ms;
8018c2ecf20Sopenharmony_ci		color = HE_COLORSET_SELECTED;
8028c2ecf20Sopenharmony_ci		arg->is_current_entry = true;
8038c2ecf20Sopenharmony_ci	}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	ui_browser__set_color(&browser->b, color);
8068c2ecf20Sopenharmony_ci	ui_browser__gotorc(&browser->b, row, 0);
8078c2ecf20Sopenharmony_ci	ui_browser__write_nstring(&browser->b, " ", offset);
8088c2ecf20Sopenharmony_ci	ui_browser__printf(&browser->b, "%c", folded_sign);
8098c2ecf20Sopenharmony_ci	ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
8108c2ecf20Sopenharmony_ci	ui_browser__write_nstring(&browser->b, str, width);
8118c2ecf20Sopenharmony_ci}
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_cistatic void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
8148c2ecf20Sopenharmony_ci						  struct callchain_list *chain,
8158c2ecf20Sopenharmony_ci						  const char *str, int offset,
8168c2ecf20Sopenharmony_ci						  unsigned short row __maybe_unused,
8178c2ecf20Sopenharmony_ci						  struct callchain_print_arg *arg)
8188c2ecf20Sopenharmony_ci{
8198c2ecf20Sopenharmony_ci	char folded_sign = callchain_list__folded(chain);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
8228c2ecf20Sopenharmony_ci				folded_sign, str);
8238c2ecf20Sopenharmony_ci}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_citypedef bool (*check_output_full_fn)(struct hist_browser *browser,
8268c2ecf20Sopenharmony_ci				     unsigned short row);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_cistatic bool hist_browser__check_output_full(struct hist_browser *browser,
8298c2ecf20Sopenharmony_ci					    unsigned short row)
8308c2ecf20Sopenharmony_ci{
8318c2ecf20Sopenharmony_ci	return browser->b.rows == row;
8328c2ecf20Sopenharmony_ci}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_cistatic bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
8358c2ecf20Sopenharmony_ci					  unsigned short row __maybe_unused)
8368c2ecf20Sopenharmony_ci{
8378c2ecf20Sopenharmony_ci	return false;
8388c2ecf20Sopenharmony_ci}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci#define LEVEL_OFFSET_STEP 3
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_cistatic int hist_browser__show_callchain_list(struct hist_browser *browser,
8438c2ecf20Sopenharmony_ci					     struct callchain_node *node,
8448c2ecf20Sopenharmony_ci					     struct callchain_list *chain,
8458c2ecf20Sopenharmony_ci					     unsigned short row, u64 total,
8468c2ecf20Sopenharmony_ci					     bool need_percent, int offset,
8478c2ecf20Sopenharmony_ci					     print_callchain_entry_fn print,
8488c2ecf20Sopenharmony_ci					     struct callchain_print_arg *arg)
8498c2ecf20Sopenharmony_ci{
8508c2ecf20Sopenharmony_ci	char bf[1024], *alloc_str;
8518c2ecf20Sopenharmony_ci	char buf[64], *alloc_str2;
8528c2ecf20Sopenharmony_ci	const char *str;
8538c2ecf20Sopenharmony_ci	int ret = 1;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	if (arg->row_offset != 0) {
8568c2ecf20Sopenharmony_ci		arg->row_offset--;
8578c2ecf20Sopenharmony_ci		return 0;
8588c2ecf20Sopenharmony_ci	}
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	alloc_str = NULL;
8618c2ecf20Sopenharmony_ci	alloc_str2 = NULL;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	str = callchain_list__sym_name(chain, bf, sizeof(bf),
8648c2ecf20Sopenharmony_ci				       browser->show_dso);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	if (symbol_conf.show_branchflag_count) {
8678c2ecf20Sopenharmony_ci		callchain_list_counts__printf_value(chain, NULL,
8688c2ecf20Sopenharmony_ci						    buf, sizeof(buf));
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci		if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
8718c2ecf20Sopenharmony_ci			str = "Not enough memory!";
8728c2ecf20Sopenharmony_ci		else
8738c2ecf20Sopenharmony_ci			str = alloc_str2;
8748c2ecf20Sopenharmony_ci	}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	if (need_percent) {
8778c2ecf20Sopenharmony_ci		callchain_node__scnprintf_value(node, buf, sizeof(buf),
8788c2ecf20Sopenharmony_ci						total);
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci		if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
8818c2ecf20Sopenharmony_ci			str = "Not enough memory!";
8828c2ecf20Sopenharmony_ci		else
8838c2ecf20Sopenharmony_ci			str = alloc_str;
8848c2ecf20Sopenharmony_ci	}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	print(browser, chain, str, offset, row, arg);
8878c2ecf20Sopenharmony_ci	free(alloc_str);
8888c2ecf20Sopenharmony_ci	free(alloc_str2);
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	return ret;
8918c2ecf20Sopenharmony_ci}
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_cistatic bool check_percent_display(struct rb_node *node, u64 parent_total)
8948c2ecf20Sopenharmony_ci{
8958c2ecf20Sopenharmony_ci	struct callchain_node *child;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	if (node == NULL)
8988c2ecf20Sopenharmony_ci		return false;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	if (rb_next(node))
9018c2ecf20Sopenharmony_ci		return true;
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	child = rb_entry(node, struct callchain_node, rb_node);
9048c2ecf20Sopenharmony_ci	return callchain_cumul_hits(child) != parent_total;
9058c2ecf20Sopenharmony_ci}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_cistatic int hist_browser__show_callchain_flat(struct hist_browser *browser,
9088c2ecf20Sopenharmony_ci					     struct rb_root *root,
9098c2ecf20Sopenharmony_ci					     unsigned short row, u64 total,
9108c2ecf20Sopenharmony_ci					     u64 parent_total,
9118c2ecf20Sopenharmony_ci					     print_callchain_entry_fn print,
9128c2ecf20Sopenharmony_ci					     struct callchain_print_arg *arg,
9138c2ecf20Sopenharmony_ci					     check_output_full_fn is_output_full)
9148c2ecf20Sopenharmony_ci{
9158c2ecf20Sopenharmony_ci	struct rb_node *node;
9168c2ecf20Sopenharmony_ci	int first_row = row, offset = LEVEL_OFFSET_STEP;
9178c2ecf20Sopenharmony_ci	bool need_percent;
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	node = rb_first(root);
9208c2ecf20Sopenharmony_ci	need_percent = check_percent_display(node, parent_total);
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	while (node) {
9238c2ecf20Sopenharmony_ci		struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
9248c2ecf20Sopenharmony_ci		struct rb_node *next = rb_next(node);
9258c2ecf20Sopenharmony_ci		struct callchain_list *chain;
9268c2ecf20Sopenharmony_ci		char folded_sign = ' ';
9278c2ecf20Sopenharmony_ci		int first = true;
9288c2ecf20Sopenharmony_ci		int extra_offset = 0;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci		list_for_each_entry(chain, &child->parent_val, list) {
9318c2ecf20Sopenharmony_ci			bool was_first = first;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci			if (first)
9348c2ecf20Sopenharmony_ci				first = false;
9358c2ecf20Sopenharmony_ci			else if (need_percent)
9368c2ecf20Sopenharmony_ci				extra_offset = LEVEL_OFFSET_STEP;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci			folded_sign = callchain_list__folded(chain);
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci			row += hist_browser__show_callchain_list(browser, child,
9418c2ecf20Sopenharmony_ci							chain, row, total,
9428c2ecf20Sopenharmony_ci							was_first && need_percent,
9438c2ecf20Sopenharmony_ci							offset + extra_offset,
9448c2ecf20Sopenharmony_ci							print, arg);
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci			if (is_output_full(browser, row))
9478c2ecf20Sopenharmony_ci				goto out;
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci			if (folded_sign == '+')
9508c2ecf20Sopenharmony_ci				goto next;
9518c2ecf20Sopenharmony_ci		}
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci		list_for_each_entry(chain, &child->val, list) {
9548c2ecf20Sopenharmony_ci			bool was_first = first;
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci			if (first)
9578c2ecf20Sopenharmony_ci				first = false;
9588c2ecf20Sopenharmony_ci			else if (need_percent)
9598c2ecf20Sopenharmony_ci				extra_offset = LEVEL_OFFSET_STEP;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci			folded_sign = callchain_list__folded(chain);
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci			row += hist_browser__show_callchain_list(browser, child,
9648c2ecf20Sopenharmony_ci							chain, row, total,
9658c2ecf20Sopenharmony_ci							was_first && need_percent,
9668c2ecf20Sopenharmony_ci							offset + extra_offset,
9678c2ecf20Sopenharmony_ci							print, arg);
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci			if (is_output_full(browser, row))
9708c2ecf20Sopenharmony_ci				goto out;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci			if (folded_sign == '+')
9738c2ecf20Sopenharmony_ci				break;
9748c2ecf20Sopenharmony_ci		}
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_cinext:
9778c2ecf20Sopenharmony_ci		if (is_output_full(browser, row))
9788c2ecf20Sopenharmony_ci			break;
9798c2ecf20Sopenharmony_ci		node = next;
9808c2ecf20Sopenharmony_ci	}
9818c2ecf20Sopenharmony_ciout:
9828c2ecf20Sopenharmony_ci	return row - first_row;
9838c2ecf20Sopenharmony_ci}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_cistatic char *hist_browser__folded_callchain_str(struct hist_browser *browser,
9868c2ecf20Sopenharmony_ci						struct callchain_list *chain,
9878c2ecf20Sopenharmony_ci						char *value_str, char *old_str)
9888c2ecf20Sopenharmony_ci{
9898c2ecf20Sopenharmony_ci	char bf[1024];
9908c2ecf20Sopenharmony_ci	const char *str;
9918c2ecf20Sopenharmony_ci	char *new;
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	str = callchain_list__sym_name(chain, bf, sizeof(bf),
9948c2ecf20Sopenharmony_ci				       browser->show_dso);
9958c2ecf20Sopenharmony_ci	if (old_str) {
9968c2ecf20Sopenharmony_ci		if (asprintf(&new, "%s%s%s", old_str,
9978c2ecf20Sopenharmony_ci			     symbol_conf.field_sep ?: ";", str) < 0)
9988c2ecf20Sopenharmony_ci			new = NULL;
9998c2ecf20Sopenharmony_ci	} else {
10008c2ecf20Sopenharmony_ci		if (value_str) {
10018c2ecf20Sopenharmony_ci			if (asprintf(&new, "%s %s", value_str, str) < 0)
10028c2ecf20Sopenharmony_ci				new = NULL;
10038c2ecf20Sopenharmony_ci		} else {
10048c2ecf20Sopenharmony_ci			if (asprintf(&new, "%s", str) < 0)
10058c2ecf20Sopenharmony_ci				new = NULL;
10068c2ecf20Sopenharmony_ci		}
10078c2ecf20Sopenharmony_ci	}
10088c2ecf20Sopenharmony_ci	return new;
10098c2ecf20Sopenharmony_ci}
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_cistatic int hist_browser__show_callchain_folded(struct hist_browser *browser,
10128c2ecf20Sopenharmony_ci					       struct rb_root *root,
10138c2ecf20Sopenharmony_ci					       unsigned short row, u64 total,
10148c2ecf20Sopenharmony_ci					       u64 parent_total,
10158c2ecf20Sopenharmony_ci					       print_callchain_entry_fn print,
10168c2ecf20Sopenharmony_ci					       struct callchain_print_arg *arg,
10178c2ecf20Sopenharmony_ci					       check_output_full_fn is_output_full)
10188c2ecf20Sopenharmony_ci{
10198c2ecf20Sopenharmony_ci	struct rb_node *node;
10208c2ecf20Sopenharmony_ci	int first_row = row, offset = LEVEL_OFFSET_STEP;
10218c2ecf20Sopenharmony_ci	bool need_percent;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	node = rb_first(root);
10248c2ecf20Sopenharmony_ci	need_percent = check_percent_display(node, parent_total);
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	while (node) {
10278c2ecf20Sopenharmony_ci		struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
10288c2ecf20Sopenharmony_ci		struct rb_node *next = rb_next(node);
10298c2ecf20Sopenharmony_ci		struct callchain_list *chain, *first_chain = NULL;
10308c2ecf20Sopenharmony_ci		int first = true;
10318c2ecf20Sopenharmony_ci		char *value_str = NULL, *value_str_alloc = NULL;
10328c2ecf20Sopenharmony_ci		char *chain_str = NULL, *chain_str_alloc = NULL;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci		if (arg->row_offset != 0) {
10358c2ecf20Sopenharmony_ci			arg->row_offset--;
10368c2ecf20Sopenharmony_ci			goto next;
10378c2ecf20Sopenharmony_ci		}
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci		if (need_percent) {
10408c2ecf20Sopenharmony_ci			char buf[64];
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci			callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
10438c2ecf20Sopenharmony_ci			if (asprintf(&value_str, "%s", buf) < 0) {
10448c2ecf20Sopenharmony_ci				value_str = (char *)"<...>";
10458c2ecf20Sopenharmony_ci				goto do_print;
10468c2ecf20Sopenharmony_ci			}
10478c2ecf20Sopenharmony_ci			value_str_alloc = value_str;
10488c2ecf20Sopenharmony_ci		}
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci		list_for_each_entry(chain, &child->parent_val, list) {
10518c2ecf20Sopenharmony_ci			chain_str = hist_browser__folded_callchain_str(browser,
10528c2ecf20Sopenharmony_ci						chain, value_str, chain_str);
10538c2ecf20Sopenharmony_ci			if (first) {
10548c2ecf20Sopenharmony_ci				first = false;
10558c2ecf20Sopenharmony_ci				first_chain = chain;
10568c2ecf20Sopenharmony_ci			}
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci			if (chain_str == NULL) {
10598c2ecf20Sopenharmony_ci				chain_str = (char *)"Not enough memory!";
10608c2ecf20Sopenharmony_ci				goto do_print;
10618c2ecf20Sopenharmony_ci			}
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci			chain_str_alloc = chain_str;
10648c2ecf20Sopenharmony_ci		}
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci		list_for_each_entry(chain, &child->val, list) {
10678c2ecf20Sopenharmony_ci			chain_str = hist_browser__folded_callchain_str(browser,
10688c2ecf20Sopenharmony_ci						chain, value_str, chain_str);
10698c2ecf20Sopenharmony_ci			if (first) {
10708c2ecf20Sopenharmony_ci				first = false;
10718c2ecf20Sopenharmony_ci				first_chain = chain;
10728c2ecf20Sopenharmony_ci			}
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci			if (chain_str == NULL) {
10758c2ecf20Sopenharmony_ci				chain_str = (char *)"Not enough memory!";
10768c2ecf20Sopenharmony_ci				goto do_print;
10778c2ecf20Sopenharmony_ci			}
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci			chain_str_alloc = chain_str;
10808c2ecf20Sopenharmony_ci		}
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_cido_print:
10838c2ecf20Sopenharmony_ci		print(browser, first_chain, chain_str, offset, row++, arg);
10848c2ecf20Sopenharmony_ci		free(value_str_alloc);
10858c2ecf20Sopenharmony_ci		free(chain_str_alloc);
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_cinext:
10888c2ecf20Sopenharmony_ci		if (is_output_full(browser, row))
10898c2ecf20Sopenharmony_ci			break;
10908c2ecf20Sopenharmony_ci		node = next;
10918c2ecf20Sopenharmony_ci	}
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	return row - first_row;
10948c2ecf20Sopenharmony_ci}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_cistatic int hist_browser__show_callchain_graph(struct hist_browser *browser,
10978c2ecf20Sopenharmony_ci					struct rb_root *root, int level,
10988c2ecf20Sopenharmony_ci					unsigned short row, u64 total,
10998c2ecf20Sopenharmony_ci					u64 parent_total,
11008c2ecf20Sopenharmony_ci					print_callchain_entry_fn print,
11018c2ecf20Sopenharmony_ci					struct callchain_print_arg *arg,
11028c2ecf20Sopenharmony_ci					check_output_full_fn is_output_full)
11038c2ecf20Sopenharmony_ci{
11048c2ecf20Sopenharmony_ci	struct rb_node *node;
11058c2ecf20Sopenharmony_ci	int first_row = row, offset = level * LEVEL_OFFSET_STEP;
11068c2ecf20Sopenharmony_ci	bool need_percent;
11078c2ecf20Sopenharmony_ci	u64 percent_total = total;
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	if (callchain_param.mode == CHAIN_GRAPH_REL)
11108c2ecf20Sopenharmony_ci		percent_total = parent_total;
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	node = rb_first(root);
11138c2ecf20Sopenharmony_ci	need_percent = check_percent_display(node, parent_total);
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	while (node) {
11168c2ecf20Sopenharmony_ci		struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
11178c2ecf20Sopenharmony_ci		struct rb_node *next = rb_next(node);
11188c2ecf20Sopenharmony_ci		struct callchain_list *chain;
11198c2ecf20Sopenharmony_ci		char folded_sign = ' ';
11208c2ecf20Sopenharmony_ci		int first = true;
11218c2ecf20Sopenharmony_ci		int extra_offset = 0;
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci		list_for_each_entry(chain, &child->val, list) {
11248c2ecf20Sopenharmony_ci			bool was_first = first;
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci			if (first)
11278c2ecf20Sopenharmony_ci				first = false;
11288c2ecf20Sopenharmony_ci			else if (need_percent)
11298c2ecf20Sopenharmony_ci				extra_offset = LEVEL_OFFSET_STEP;
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci			folded_sign = callchain_list__folded(chain);
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci			row += hist_browser__show_callchain_list(browser, child,
11348c2ecf20Sopenharmony_ci							chain, row, percent_total,
11358c2ecf20Sopenharmony_ci							was_first && need_percent,
11368c2ecf20Sopenharmony_ci							offset + extra_offset,
11378c2ecf20Sopenharmony_ci							print, arg);
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci			if (is_output_full(browser, row))
11408c2ecf20Sopenharmony_ci				goto out;
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci			if (folded_sign == '+')
11438c2ecf20Sopenharmony_ci				break;
11448c2ecf20Sopenharmony_ci		}
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci		if (folded_sign == '-') {
11478c2ecf20Sopenharmony_ci			const int new_level = level + (extra_offset ? 2 : 1);
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci			row += hist_browser__show_callchain_graph(browser, &child->rb_root,
11508c2ecf20Sopenharmony_ci							    new_level, row, total,
11518c2ecf20Sopenharmony_ci							    child->children_hit,
11528c2ecf20Sopenharmony_ci							    print, arg, is_output_full);
11538c2ecf20Sopenharmony_ci		}
11548c2ecf20Sopenharmony_ci		if (is_output_full(browser, row))
11558c2ecf20Sopenharmony_ci			break;
11568c2ecf20Sopenharmony_ci		node = next;
11578c2ecf20Sopenharmony_ci	}
11588c2ecf20Sopenharmony_ciout:
11598c2ecf20Sopenharmony_ci	return row - first_row;
11608c2ecf20Sopenharmony_ci}
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_cistatic int hist_browser__show_callchain(struct hist_browser *browser,
11638c2ecf20Sopenharmony_ci					struct hist_entry *entry, int level,
11648c2ecf20Sopenharmony_ci					unsigned short row,
11658c2ecf20Sopenharmony_ci					print_callchain_entry_fn print,
11668c2ecf20Sopenharmony_ci					struct callchain_print_arg *arg,
11678c2ecf20Sopenharmony_ci					check_output_full_fn is_output_full)
11688c2ecf20Sopenharmony_ci{
11698c2ecf20Sopenharmony_ci	u64 total = hists__total_period(entry->hists);
11708c2ecf20Sopenharmony_ci	u64 parent_total;
11718c2ecf20Sopenharmony_ci	int printed;
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	if (symbol_conf.cumulate_callchain)
11748c2ecf20Sopenharmony_ci		parent_total = entry->stat_acc->period;
11758c2ecf20Sopenharmony_ci	else
11768c2ecf20Sopenharmony_ci		parent_total = entry->stat.period;
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	if (callchain_param.mode == CHAIN_FLAT) {
11798c2ecf20Sopenharmony_ci		printed = hist_browser__show_callchain_flat(browser,
11808c2ecf20Sopenharmony_ci						&entry->sorted_chain, row,
11818c2ecf20Sopenharmony_ci						total, parent_total, print, arg,
11828c2ecf20Sopenharmony_ci						is_output_full);
11838c2ecf20Sopenharmony_ci	} else if (callchain_param.mode == CHAIN_FOLDED) {
11848c2ecf20Sopenharmony_ci		printed = hist_browser__show_callchain_folded(browser,
11858c2ecf20Sopenharmony_ci						&entry->sorted_chain, row,
11868c2ecf20Sopenharmony_ci						total, parent_total, print, arg,
11878c2ecf20Sopenharmony_ci						is_output_full);
11888c2ecf20Sopenharmony_ci	} else {
11898c2ecf20Sopenharmony_ci		printed = hist_browser__show_callchain_graph(browser,
11908c2ecf20Sopenharmony_ci						&entry->sorted_chain, level, row,
11918c2ecf20Sopenharmony_ci						total, parent_total, print, arg,
11928c2ecf20Sopenharmony_ci						is_output_full);
11938c2ecf20Sopenharmony_ci	}
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	if (arg->is_current_entry)
11968c2ecf20Sopenharmony_ci		browser->he_selection = entry;
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	return printed;
11998c2ecf20Sopenharmony_ci}
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_cistruct hpp_arg {
12028c2ecf20Sopenharmony_ci	struct ui_browser *b;
12038c2ecf20Sopenharmony_ci	char folded_sign;
12048c2ecf20Sopenharmony_ci	bool current_entry;
12058c2ecf20Sopenharmony_ci};
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ciint __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
12088c2ecf20Sopenharmony_ci{
12098c2ecf20Sopenharmony_ci	struct hpp_arg *arg = hpp->ptr;
12108c2ecf20Sopenharmony_ci	int ret, len;
12118c2ecf20Sopenharmony_ci	va_list args;
12128c2ecf20Sopenharmony_ci	double percent;
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	va_start(args, fmt);
12158c2ecf20Sopenharmony_ci	len = va_arg(args, int);
12168c2ecf20Sopenharmony_ci	percent = va_arg(args, double);
12178c2ecf20Sopenharmony_ci	va_end(args);
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
12228c2ecf20Sopenharmony_ci	ui_browser__printf(arg->b, "%s", hpp->buf);
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	return ret;
12258c2ecf20Sopenharmony_ci}
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci#define __HPP_COLOR_PERCENT_FN(_type, _field)				\
12288c2ecf20Sopenharmony_cistatic u64 __hpp_get_##_field(struct hist_entry *he)			\
12298c2ecf20Sopenharmony_ci{									\
12308c2ecf20Sopenharmony_ci	return he->stat._field;						\
12318c2ecf20Sopenharmony_ci}									\
12328c2ecf20Sopenharmony_ci									\
12338c2ecf20Sopenharmony_cistatic int								\
12348c2ecf20Sopenharmony_cihist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt,		\
12358c2ecf20Sopenharmony_ci				struct perf_hpp *hpp,			\
12368c2ecf20Sopenharmony_ci				struct hist_entry *he)			\
12378c2ecf20Sopenharmony_ci{									\
12388c2ecf20Sopenharmony_ci	return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%",	\
12398c2ecf20Sopenharmony_ci			__hpp__slsmg_color_printf, true);		\
12408c2ecf20Sopenharmony_ci}
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)			\
12438c2ecf20Sopenharmony_cistatic u64 __hpp_get_acc_##_field(struct hist_entry *he)		\
12448c2ecf20Sopenharmony_ci{									\
12458c2ecf20Sopenharmony_ci	return he->stat_acc->_field;					\
12468c2ecf20Sopenharmony_ci}									\
12478c2ecf20Sopenharmony_ci									\
12488c2ecf20Sopenharmony_cistatic int								\
12498c2ecf20Sopenharmony_cihist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt,		\
12508c2ecf20Sopenharmony_ci				struct perf_hpp *hpp,			\
12518c2ecf20Sopenharmony_ci				struct hist_entry *he)			\
12528c2ecf20Sopenharmony_ci{									\
12538c2ecf20Sopenharmony_ci	if (!symbol_conf.cumulate_callchain) {				\
12548c2ecf20Sopenharmony_ci		struct hpp_arg *arg = hpp->ptr;				\
12558c2ecf20Sopenharmony_ci		int len = fmt->user_len ?: fmt->len;			\
12568c2ecf20Sopenharmony_ci		int ret = scnprintf(hpp->buf, hpp->size,		\
12578c2ecf20Sopenharmony_ci				    "%*s", len, "N/A");			\
12588c2ecf20Sopenharmony_ci		ui_browser__printf(arg->b, "%s", hpp->buf);		\
12598c2ecf20Sopenharmony_ci									\
12608c2ecf20Sopenharmony_ci		return ret;						\
12618c2ecf20Sopenharmony_ci	}								\
12628c2ecf20Sopenharmony_ci	return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field,		\
12638c2ecf20Sopenharmony_ci			" %*.2f%%", __hpp__slsmg_color_printf, true);	\
12648c2ecf20Sopenharmony_ci}
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci__HPP_COLOR_PERCENT_FN(overhead, period)
12678c2ecf20Sopenharmony_ci__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
12688c2ecf20Sopenharmony_ci__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
12698c2ecf20Sopenharmony_ci__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
12708c2ecf20Sopenharmony_ci__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
12718c2ecf20Sopenharmony_ci__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci#undef __HPP_COLOR_PERCENT_FN
12748c2ecf20Sopenharmony_ci#undef __HPP_COLOR_ACC_PERCENT_FN
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_civoid hist_browser__init_hpp(void)
12778c2ecf20Sopenharmony_ci{
12788c2ecf20Sopenharmony_ci	perf_hpp__format[PERF_HPP__OVERHEAD].color =
12798c2ecf20Sopenharmony_ci				hist_browser__hpp_color_overhead;
12808c2ecf20Sopenharmony_ci	perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
12818c2ecf20Sopenharmony_ci				hist_browser__hpp_color_overhead_sys;
12828c2ecf20Sopenharmony_ci	perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
12838c2ecf20Sopenharmony_ci				hist_browser__hpp_color_overhead_us;
12848c2ecf20Sopenharmony_ci	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
12858c2ecf20Sopenharmony_ci				hist_browser__hpp_color_overhead_guest_sys;
12868c2ecf20Sopenharmony_ci	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
12878c2ecf20Sopenharmony_ci				hist_browser__hpp_color_overhead_guest_us;
12888c2ecf20Sopenharmony_ci	perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
12898c2ecf20Sopenharmony_ci				hist_browser__hpp_color_overhead_acc;
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci	res_sample_init();
12928c2ecf20Sopenharmony_ci}
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_cistatic int hist_browser__show_entry(struct hist_browser *browser,
12958c2ecf20Sopenharmony_ci				    struct hist_entry *entry,
12968c2ecf20Sopenharmony_ci				    unsigned short row)
12978c2ecf20Sopenharmony_ci{
12988c2ecf20Sopenharmony_ci	int printed = 0;
12998c2ecf20Sopenharmony_ci	int width = browser->b.width;
13008c2ecf20Sopenharmony_ci	char folded_sign = ' ';
13018c2ecf20Sopenharmony_ci	bool current_entry = ui_browser__is_current_entry(&browser->b, row);
13028c2ecf20Sopenharmony_ci	bool use_callchain = hist_entry__has_callchains(entry) && symbol_conf.use_callchain;
13038c2ecf20Sopenharmony_ci	off_t row_offset = entry->row_offset;
13048c2ecf20Sopenharmony_ci	bool first = true;
13058c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt;
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	if (current_entry) {
13088c2ecf20Sopenharmony_ci		browser->he_selection = entry;
13098c2ecf20Sopenharmony_ci		browser->selection = &entry->ms;
13108c2ecf20Sopenharmony_ci	}
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	if (use_callchain) {
13138c2ecf20Sopenharmony_ci		hist_entry__init_have_children(entry);
13148c2ecf20Sopenharmony_ci		folded_sign = hist_entry__folded(entry);
13158c2ecf20Sopenharmony_ci	}
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	if (row_offset == 0) {
13188c2ecf20Sopenharmony_ci		struct hpp_arg arg = {
13198c2ecf20Sopenharmony_ci			.b		= &browser->b,
13208c2ecf20Sopenharmony_ci			.folded_sign	= folded_sign,
13218c2ecf20Sopenharmony_ci			.current_entry	= current_entry,
13228c2ecf20Sopenharmony_ci		};
13238c2ecf20Sopenharmony_ci		int column = 0;
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci		ui_browser__gotorc(&browser->b, row, 0);
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci		hists__for_each_format(browser->hists, fmt) {
13288c2ecf20Sopenharmony_ci			char s[2048];
13298c2ecf20Sopenharmony_ci			struct perf_hpp hpp = {
13308c2ecf20Sopenharmony_ci				.buf	= s,
13318c2ecf20Sopenharmony_ci				.size	= sizeof(s),
13328c2ecf20Sopenharmony_ci				.ptr	= &arg,
13338c2ecf20Sopenharmony_ci			};
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci			if (perf_hpp__should_skip(fmt, entry->hists) ||
13368c2ecf20Sopenharmony_ci			    column++ < browser->b.horiz_scroll)
13378c2ecf20Sopenharmony_ci				continue;
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci			if (current_entry && browser->b.navkeypressed) {
13408c2ecf20Sopenharmony_ci				ui_browser__set_color(&browser->b,
13418c2ecf20Sopenharmony_ci						      HE_COLORSET_SELECTED);
13428c2ecf20Sopenharmony_ci			} else {
13438c2ecf20Sopenharmony_ci				ui_browser__set_color(&browser->b,
13448c2ecf20Sopenharmony_ci						      HE_COLORSET_NORMAL);
13458c2ecf20Sopenharmony_ci			}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci			if (first) {
13488c2ecf20Sopenharmony_ci				if (use_callchain) {
13498c2ecf20Sopenharmony_ci					ui_browser__printf(&browser->b, "%c ", folded_sign);
13508c2ecf20Sopenharmony_ci					width -= 2;
13518c2ecf20Sopenharmony_ci				}
13528c2ecf20Sopenharmony_ci				first = false;
13538c2ecf20Sopenharmony_ci			} else {
13548c2ecf20Sopenharmony_ci				ui_browser__printf(&browser->b, "  ");
13558c2ecf20Sopenharmony_ci				width -= 2;
13568c2ecf20Sopenharmony_ci			}
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci			if (fmt->color) {
13598c2ecf20Sopenharmony_ci				int ret = fmt->color(fmt, &hpp, entry);
13608c2ecf20Sopenharmony_ci				hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
13618c2ecf20Sopenharmony_ci				/*
13628c2ecf20Sopenharmony_ci				 * fmt->color() already used ui_browser to
13638c2ecf20Sopenharmony_ci				 * print the non alignment bits, skip it (+ret):
13648c2ecf20Sopenharmony_ci				 */
13658c2ecf20Sopenharmony_ci				ui_browser__printf(&browser->b, "%s", s + ret);
13668c2ecf20Sopenharmony_ci			} else {
13678c2ecf20Sopenharmony_ci				hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
13688c2ecf20Sopenharmony_ci				ui_browser__printf(&browser->b, "%s", s);
13698c2ecf20Sopenharmony_ci			}
13708c2ecf20Sopenharmony_ci			width -= hpp.buf - s;
13718c2ecf20Sopenharmony_ci		}
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci		/* The scroll bar isn't being used */
13748c2ecf20Sopenharmony_ci		if (!browser->b.navkeypressed)
13758c2ecf20Sopenharmony_ci			width += 1;
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci		ui_browser__write_nstring(&browser->b, "", width);
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci		++row;
13808c2ecf20Sopenharmony_ci		++printed;
13818c2ecf20Sopenharmony_ci	} else
13828c2ecf20Sopenharmony_ci		--row_offset;
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci	if (folded_sign == '-' && row != browser->b.rows) {
13858c2ecf20Sopenharmony_ci		struct callchain_print_arg arg = {
13868c2ecf20Sopenharmony_ci			.row_offset = row_offset,
13878c2ecf20Sopenharmony_ci			.is_current_entry = current_entry,
13888c2ecf20Sopenharmony_ci		};
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci		printed += hist_browser__show_callchain(browser,
13918c2ecf20Sopenharmony_ci				entry, 1, row,
13928c2ecf20Sopenharmony_ci				hist_browser__show_callchain_entry,
13938c2ecf20Sopenharmony_ci				&arg,
13948c2ecf20Sopenharmony_ci				hist_browser__check_output_full);
13958c2ecf20Sopenharmony_ci	}
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	return printed;
13988c2ecf20Sopenharmony_ci}
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_cistatic int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
14018c2ecf20Sopenharmony_ci					      struct hist_entry *entry,
14028c2ecf20Sopenharmony_ci					      unsigned short row,
14038c2ecf20Sopenharmony_ci					      int level)
14048c2ecf20Sopenharmony_ci{
14058c2ecf20Sopenharmony_ci	int printed = 0;
14068c2ecf20Sopenharmony_ci	int width = browser->b.width;
14078c2ecf20Sopenharmony_ci	char folded_sign = ' ';
14088c2ecf20Sopenharmony_ci	bool current_entry = ui_browser__is_current_entry(&browser->b, row);
14098c2ecf20Sopenharmony_ci	off_t row_offset = entry->row_offset;
14108c2ecf20Sopenharmony_ci	bool first = true;
14118c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt;
14128c2ecf20Sopenharmony_ci	struct perf_hpp_list_node *fmt_node;
14138c2ecf20Sopenharmony_ci	struct hpp_arg arg = {
14148c2ecf20Sopenharmony_ci		.b		= &browser->b,
14158c2ecf20Sopenharmony_ci		.current_entry	= current_entry,
14168c2ecf20Sopenharmony_ci	};
14178c2ecf20Sopenharmony_ci	int column = 0;
14188c2ecf20Sopenharmony_ci	int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	if (current_entry) {
14218c2ecf20Sopenharmony_ci		browser->he_selection = entry;
14228c2ecf20Sopenharmony_ci		browser->selection = &entry->ms;
14238c2ecf20Sopenharmony_ci	}
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	hist_entry__init_have_children(entry);
14268c2ecf20Sopenharmony_ci	folded_sign = hist_entry__folded(entry);
14278c2ecf20Sopenharmony_ci	arg.folded_sign = folded_sign;
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	if (entry->leaf && row_offset) {
14308c2ecf20Sopenharmony_ci		row_offset--;
14318c2ecf20Sopenharmony_ci		goto show_callchain;
14328c2ecf20Sopenharmony_ci	}
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	ui_browser__gotorc(&browser->b, row, 0);
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	if (current_entry && browser->b.navkeypressed)
14378c2ecf20Sopenharmony_ci		ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
14388c2ecf20Sopenharmony_ci	else
14398c2ecf20Sopenharmony_ci		ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
14428c2ecf20Sopenharmony_ci	width -= level * HIERARCHY_INDENT;
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	/* the first hpp_list_node is for overhead columns */
14458c2ecf20Sopenharmony_ci	fmt_node = list_first_entry(&entry->hists->hpp_formats,
14468c2ecf20Sopenharmony_ci				    struct perf_hpp_list_node, list);
14478c2ecf20Sopenharmony_ci	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
14488c2ecf20Sopenharmony_ci		char s[2048];
14498c2ecf20Sopenharmony_ci		struct perf_hpp hpp = {
14508c2ecf20Sopenharmony_ci			.buf		= s,
14518c2ecf20Sopenharmony_ci			.size		= sizeof(s),
14528c2ecf20Sopenharmony_ci			.ptr		= &arg,
14538c2ecf20Sopenharmony_ci		};
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci		if (perf_hpp__should_skip(fmt, entry->hists) ||
14568c2ecf20Sopenharmony_ci		    column++ < browser->b.horiz_scroll)
14578c2ecf20Sopenharmony_ci			continue;
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci		if (current_entry && browser->b.navkeypressed) {
14608c2ecf20Sopenharmony_ci			ui_browser__set_color(&browser->b,
14618c2ecf20Sopenharmony_ci					      HE_COLORSET_SELECTED);
14628c2ecf20Sopenharmony_ci		} else {
14638c2ecf20Sopenharmony_ci			ui_browser__set_color(&browser->b,
14648c2ecf20Sopenharmony_ci					      HE_COLORSET_NORMAL);
14658c2ecf20Sopenharmony_ci		}
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci		if (first) {
14688c2ecf20Sopenharmony_ci			ui_browser__printf(&browser->b, "%c ", folded_sign);
14698c2ecf20Sopenharmony_ci			width -= 2;
14708c2ecf20Sopenharmony_ci			first = false;
14718c2ecf20Sopenharmony_ci		} else {
14728c2ecf20Sopenharmony_ci			ui_browser__printf(&browser->b, "  ");
14738c2ecf20Sopenharmony_ci			width -= 2;
14748c2ecf20Sopenharmony_ci		}
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci		if (fmt->color) {
14778c2ecf20Sopenharmony_ci			int ret = fmt->color(fmt, &hpp, entry);
14788c2ecf20Sopenharmony_ci			hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
14798c2ecf20Sopenharmony_ci			/*
14808c2ecf20Sopenharmony_ci			 * fmt->color() already used ui_browser to
14818c2ecf20Sopenharmony_ci			 * print the non alignment bits, skip it (+ret):
14828c2ecf20Sopenharmony_ci			 */
14838c2ecf20Sopenharmony_ci			ui_browser__printf(&browser->b, "%s", s + ret);
14848c2ecf20Sopenharmony_ci		} else {
14858c2ecf20Sopenharmony_ci			int ret = fmt->entry(fmt, &hpp, entry);
14868c2ecf20Sopenharmony_ci			hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
14878c2ecf20Sopenharmony_ci			ui_browser__printf(&browser->b, "%s", s);
14888c2ecf20Sopenharmony_ci		}
14898c2ecf20Sopenharmony_ci		width -= hpp.buf - s;
14908c2ecf20Sopenharmony_ci	}
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	if (!first) {
14938c2ecf20Sopenharmony_ci		ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
14948c2ecf20Sopenharmony_ci		width -= hierarchy_indent;
14958c2ecf20Sopenharmony_ci	}
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci	if (column >= browser->b.horiz_scroll) {
14988c2ecf20Sopenharmony_ci		char s[2048];
14998c2ecf20Sopenharmony_ci		struct perf_hpp hpp = {
15008c2ecf20Sopenharmony_ci			.buf		= s,
15018c2ecf20Sopenharmony_ci			.size		= sizeof(s),
15028c2ecf20Sopenharmony_ci			.ptr		= &arg,
15038c2ecf20Sopenharmony_ci		};
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci		if (current_entry && browser->b.navkeypressed) {
15068c2ecf20Sopenharmony_ci			ui_browser__set_color(&browser->b,
15078c2ecf20Sopenharmony_ci					      HE_COLORSET_SELECTED);
15088c2ecf20Sopenharmony_ci		} else {
15098c2ecf20Sopenharmony_ci			ui_browser__set_color(&browser->b,
15108c2ecf20Sopenharmony_ci					      HE_COLORSET_NORMAL);
15118c2ecf20Sopenharmony_ci		}
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci		perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
15148c2ecf20Sopenharmony_ci			if (first) {
15158c2ecf20Sopenharmony_ci				ui_browser__printf(&browser->b, "%c ", folded_sign);
15168c2ecf20Sopenharmony_ci				first = false;
15178c2ecf20Sopenharmony_ci			} else {
15188c2ecf20Sopenharmony_ci				ui_browser__write_nstring(&browser->b, "", 2);
15198c2ecf20Sopenharmony_ci			}
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci			width -= 2;
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci			/*
15248c2ecf20Sopenharmony_ci			 * No need to call hist_entry__snprintf_alignment()
15258c2ecf20Sopenharmony_ci			 * since this fmt is always the last column in the
15268c2ecf20Sopenharmony_ci			 * hierarchy mode.
15278c2ecf20Sopenharmony_ci			 */
15288c2ecf20Sopenharmony_ci			if (fmt->color) {
15298c2ecf20Sopenharmony_ci				width -= fmt->color(fmt, &hpp, entry);
15308c2ecf20Sopenharmony_ci			} else {
15318c2ecf20Sopenharmony_ci				int i = 0;
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci				width -= fmt->entry(fmt, &hpp, entry);
15348c2ecf20Sopenharmony_ci				ui_browser__printf(&browser->b, "%s", skip_spaces(s));
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci				while (isspace(s[i++]))
15378c2ecf20Sopenharmony_ci					width++;
15388c2ecf20Sopenharmony_ci			}
15398c2ecf20Sopenharmony_ci		}
15408c2ecf20Sopenharmony_ci	}
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	/* The scroll bar isn't being used */
15438c2ecf20Sopenharmony_ci	if (!browser->b.navkeypressed)
15448c2ecf20Sopenharmony_ci		width += 1;
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci	ui_browser__write_nstring(&browser->b, "", width);
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	++row;
15498c2ecf20Sopenharmony_ci	++printed;
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_cishow_callchain:
15528c2ecf20Sopenharmony_ci	if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
15538c2ecf20Sopenharmony_ci		struct callchain_print_arg carg = {
15548c2ecf20Sopenharmony_ci			.row_offset = row_offset,
15558c2ecf20Sopenharmony_ci		};
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci		printed += hist_browser__show_callchain(browser, entry,
15588c2ecf20Sopenharmony_ci					level + 1, row,
15598c2ecf20Sopenharmony_ci					hist_browser__show_callchain_entry, &carg,
15608c2ecf20Sopenharmony_ci					hist_browser__check_output_full);
15618c2ecf20Sopenharmony_ci	}
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	return printed;
15648c2ecf20Sopenharmony_ci}
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_cistatic int hist_browser__show_no_entry(struct hist_browser *browser,
15678c2ecf20Sopenharmony_ci				       unsigned short row, int level)
15688c2ecf20Sopenharmony_ci{
15698c2ecf20Sopenharmony_ci	int width = browser->b.width;
15708c2ecf20Sopenharmony_ci	bool current_entry = ui_browser__is_current_entry(&browser->b, row);
15718c2ecf20Sopenharmony_ci	bool first = true;
15728c2ecf20Sopenharmony_ci	int column = 0;
15738c2ecf20Sopenharmony_ci	int ret;
15748c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt;
15758c2ecf20Sopenharmony_ci	struct perf_hpp_list_node *fmt_node;
15768c2ecf20Sopenharmony_ci	int indent = browser->hists->nr_hpp_node - 2;
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	if (current_entry) {
15798c2ecf20Sopenharmony_ci		browser->he_selection = NULL;
15808c2ecf20Sopenharmony_ci		browser->selection = NULL;
15818c2ecf20Sopenharmony_ci	}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	ui_browser__gotorc(&browser->b, row, 0);
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	if (current_entry && browser->b.navkeypressed)
15868c2ecf20Sopenharmony_ci		ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
15878c2ecf20Sopenharmony_ci	else
15888c2ecf20Sopenharmony_ci		ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci	ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
15918c2ecf20Sopenharmony_ci	width -= level * HIERARCHY_INDENT;
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci	/* the first hpp_list_node is for overhead columns */
15948c2ecf20Sopenharmony_ci	fmt_node = list_first_entry(&browser->hists->hpp_formats,
15958c2ecf20Sopenharmony_ci				    struct perf_hpp_list_node, list);
15968c2ecf20Sopenharmony_ci	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
15978c2ecf20Sopenharmony_ci		if (perf_hpp__should_skip(fmt, browser->hists) ||
15988c2ecf20Sopenharmony_ci		    column++ < browser->b.horiz_scroll)
15998c2ecf20Sopenharmony_ci			continue;
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci		ret = fmt->width(fmt, NULL, browser->hists);
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci		if (first) {
16048c2ecf20Sopenharmony_ci			/* for folded sign */
16058c2ecf20Sopenharmony_ci			first = false;
16068c2ecf20Sopenharmony_ci			ret++;
16078c2ecf20Sopenharmony_ci		} else {
16088c2ecf20Sopenharmony_ci			/* space between columns */
16098c2ecf20Sopenharmony_ci			ret += 2;
16108c2ecf20Sopenharmony_ci		}
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci		ui_browser__write_nstring(&browser->b, "", ret);
16138c2ecf20Sopenharmony_ci		width -= ret;
16148c2ecf20Sopenharmony_ci	}
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci	ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
16178c2ecf20Sopenharmony_ci	width -= indent * HIERARCHY_INDENT;
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci	if (column >= browser->b.horiz_scroll) {
16208c2ecf20Sopenharmony_ci		char buf[32];
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci		ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
16238c2ecf20Sopenharmony_ci		ui_browser__printf(&browser->b, "  %s", buf);
16248c2ecf20Sopenharmony_ci		width -= ret + 2;
16258c2ecf20Sopenharmony_ci	}
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci	/* The scroll bar isn't being used */
16288c2ecf20Sopenharmony_ci	if (!browser->b.navkeypressed)
16298c2ecf20Sopenharmony_ci		width += 1;
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci	ui_browser__write_nstring(&browser->b, "", width);
16328c2ecf20Sopenharmony_ci	return 1;
16338c2ecf20Sopenharmony_ci}
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_cistatic int advance_hpp_check(struct perf_hpp *hpp, int inc)
16368c2ecf20Sopenharmony_ci{
16378c2ecf20Sopenharmony_ci	advance_hpp(hpp, inc);
16388c2ecf20Sopenharmony_ci	return hpp->size <= 0;
16398c2ecf20Sopenharmony_ci}
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_cistatic int
16428c2ecf20Sopenharmony_cihists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
16438c2ecf20Sopenharmony_ci				 size_t size, int line)
16448c2ecf20Sopenharmony_ci{
16458c2ecf20Sopenharmony_ci	struct hists *hists = browser->hists;
16468c2ecf20Sopenharmony_ci	struct perf_hpp dummy_hpp = {
16478c2ecf20Sopenharmony_ci		.buf    = buf,
16488c2ecf20Sopenharmony_ci		.size   = size,
16498c2ecf20Sopenharmony_ci	};
16508c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt;
16518c2ecf20Sopenharmony_ci	size_t ret = 0;
16528c2ecf20Sopenharmony_ci	int column = 0;
16538c2ecf20Sopenharmony_ci	int span = 0;
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci	if (hists__has_callchains(hists) && symbol_conf.use_callchain) {
16568c2ecf20Sopenharmony_ci		ret = scnprintf(buf, size, "  ");
16578c2ecf20Sopenharmony_ci		if (advance_hpp_check(&dummy_hpp, ret))
16588c2ecf20Sopenharmony_ci			return ret;
16598c2ecf20Sopenharmony_ci	}
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci	hists__for_each_format(browser->hists, fmt) {
16628c2ecf20Sopenharmony_ci		if (perf_hpp__should_skip(fmt, hists)  || column++ < browser->b.horiz_scroll)
16638c2ecf20Sopenharmony_ci			continue;
16648c2ecf20Sopenharmony_ci
16658c2ecf20Sopenharmony_ci		ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
16668c2ecf20Sopenharmony_ci		if (advance_hpp_check(&dummy_hpp, ret))
16678c2ecf20Sopenharmony_ci			break;
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci		if (span)
16708c2ecf20Sopenharmony_ci			continue;
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci		ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "  ");
16738c2ecf20Sopenharmony_ci		if (advance_hpp_check(&dummy_hpp, ret))
16748c2ecf20Sopenharmony_ci			break;
16758c2ecf20Sopenharmony_ci	}
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci	return ret;
16788c2ecf20Sopenharmony_ci}
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_cistatic int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
16818c2ecf20Sopenharmony_ci{
16828c2ecf20Sopenharmony_ci	struct hists *hists = browser->hists;
16838c2ecf20Sopenharmony_ci	struct perf_hpp dummy_hpp = {
16848c2ecf20Sopenharmony_ci		.buf    = buf,
16858c2ecf20Sopenharmony_ci		.size   = size,
16868c2ecf20Sopenharmony_ci	};
16878c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt;
16888c2ecf20Sopenharmony_ci	struct perf_hpp_list_node *fmt_node;
16898c2ecf20Sopenharmony_ci	size_t ret = 0;
16908c2ecf20Sopenharmony_ci	int column = 0;
16918c2ecf20Sopenharmony_ci	int indent = hists->nr_hpp_node - 2;
16928c2ecf20Sopenharmony_ci	bool first_node, first_col;
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	ret = scnprintf(buf, size, "  ");
16958c2ecf20Sopenharmony_ci	if (advance_hpp_check(&dummy_hpp, ret))
16968c2ecf20Sopenharmony_ci		return ret;
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	first_node = true;
16998c2ecf20Sopenharmony_ci	/* the first hpp_list_node is for overhead columns */
17008c2ecf20Sopenharmony_ci	fmt_node = list_first_entry(&hists->hpp_formats,
17018c2ecf20Sopenharmony_ci				    struct perf_hpp_list_node, list);
17028c2ecf20Sopenharmony_ci	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
17038c2ecf20Sopenharmony_ci		if (column++ < browser->b.horiz_scroll)
17048c2ecf20Sopenharmony_ci			continue;
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci		ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
17078c2ecf20Sopenharmony_ci		if (advance_hpp_check(&dummy_hpp, ret))
17088c2ecf20Sopenharmony_ci			break;
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci		ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "  ");
17118c2ecf20Sopenharmony_ci		if (advance_hpp_check(&dummy_hpp, ret))
17128c2ecf20Sopenharmony_ci			break;
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci		first_node = false;
17158c2ecf20Sopenharmony_ci	}
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci	if (!first_node) {
17188c2ecf20Sopenharmony_ci		ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
17198c2ecf20Sopenharmony_ci				indent * HIERARCHY_INDENT, "");
17208c2ecf20Sopenharmony_ci		if (advance_hpp_check(&dummy_hpp, ret))
17218c2ecf20Sopenharmony_ci			return ret;
17228c2ecf20Sopenharmony_ci	}
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	first_node = true;
17258c2ecf20Sopenharmony_ci	list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
17268c2ecf20Sopenharmony_ci		if (!first_node) {
17278c2ecf20Sopenharmony_ci			ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
17288c2ecf20Sopenharmony_ci			if (advance_hpp_check(&dummy_hpp, ret))
17298c2ecf20Sopenharmony_ci				break;
17308c2ecf20Sopenharmony_ci		}
17318c2ecf20Sopenharmony_ci		first_node = false;
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci		first_col = true;
17348c2ecf20Sopenharmony_ci		perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
17358c2ecf20Sopenharmony_ci			char *start;
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci			if (perf_hpp__should_skip(fmt, hists))
17388c2ecf20Sopenharmony_ci				continue;
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci			if (!first_col) {
17418c2ecf20Sopenharmony_ci				ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
17428c2ecf20Sopenharmony_ci				if (advance_hpp_check(&dummy_hpp, ret))
17438c2ecf20Sopenharmony_ci					break;
17448c2ecf20Sopenharmony_ci			}
17458c2ecf20Sopenharmony_ci			first_col = false;
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci			ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
17488c2ecf20Sopenharmony_ci			dummy_hpp.buf[ret] = '\0';
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci			start = strim(dummy_hpp.buf);
17518c2ecf20Sopenharmony_ci			ret = strlen(start);
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci			if (start != dummy_hpp.buf)
17548c2ecf20Sopenharmony_ci				memmove(dummy_hpp.buf, start, ret + 1);
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci			if (advance_hpp_check(&dummy_hpp, ret))
17578c2ecf20Sopenharmony_ci				break;
17588c2ecf20Sopenharmony_ci		}
17598c2ecf20Sopenharmony_ci	}
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	return ret;
17628c2ecf20Sopenharmony_ci}
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_cistatic void hists_browser__hierarchy_headers(struct hist_browser *browser)
17658c2ecf20Sopenharmony_ci{
17668c2ecf20Sopenharmony_ci	char headers[1024];
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	hists_browser__scnprintf_hierarchy_headers(browser, headers,
17698c2ecf20Sopenharmony_ci						   sizeof(headers));
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	ui_browser__gotorc_title(&browser->b, 0, 0);
17728c2ecf20Sopenharmony_ci	ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
17738c2ecf20Sopenharmony_ci	ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
17748c2ecf20Sopenharmony_ci}
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_cistatic void hists_browser__headers(struct hist_browser *browser)
17778c2ecf20Sopenharmony_ci{
17788c2ecf20Sopenharmony_ci	struct hists *hists = browser->hists;
17798c2ecf20Sopenharmony_ci	struct perf_hpp_list *hpp_list = hists->hpp_list;
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci	int line;
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci	for (line = 0; line < hpp_list->nr_header_lines; line++) {
17848c2ecf20Sopenharmony_ci		char headers[1024];
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci		hists_browser__scnprintf_headers(browser, headers,
17878c2ecf20Sopenharmony_ci						 sizeof(headers), line);
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_ci		ui_browser__gotorc_title(&browser->b, line, 0);
17908c2ecf20Sopenharmony_ci		ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
17918c2ecf20Sopenharmony_ci		ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
17928c2ecf20Sopenharmony_ci	}
17938c2ecf20Sopenharmony_ci}
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_cistatic void hist_browser__show_headers(struct hist_browser *browser)
17968c2ecf20Sopenharmony_ci{
17978c2ecf20Sopenharmony_ci	if (symbol_conf.report_hierarchy)
17988c2ecf20Sopenharmony_ci		hists_browser__hierarchy_headers(browser);
17998c2ecf20Sopenharmony_ci	else
18008c2ecf20Sopenharmony_ci		hists_browser__headers(browser);
18018c2ecf20Sopenharmony_ci}
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_cistatic void ui_browser__hists_init_top(struct ui_browser *browser)
18048c2ecf20Sopenharmony_ci{
18058c2ecf20Sopenharmony_ci	if (browser->top == NULL) {
18068c2ecf20Sopenharmony_ci		struct hist_browser *hb;
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci		hb = container_of(browser, struct hist_browser, b);
18098c2ecf20Sopenharmony_ci		browser->top = rb_first_cached(&hb->hists->entries);
18108c2ecf20Sopenharmony_ci	}
18118c2ecf20Sopenharmony_ci}
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_cistatic unsigned int hist_browser__refresh(struct ui_browser *browser)
18148c2ecf20Sopenharmony_ci{
18158c2ecf20Sopenharmony_ci	unsigned row = 0;
18168c2ecf20Sopenharmony_ci	struct rb_node *nd;
18178c2ecf20Sopenharmony_ci	struct hist_browser *hb = container_of(browser, struct hist_browser, b);
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	if (hb->show_headers)
18208c2ecf20Sopenharmony_ci		hist_browser__show_headers(hb);
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	ui_browser__hists_init_top(browser);
18238c2ecf20Sopenharmony_ci	hb->he_selection = NULL;
18248c2ecf20Sopenharmony_ci	hb->selection = NULL;
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci	for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
18278c2ecf20Sopenharmony_ci		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
18288c2ecf20Sopenharmony_ci		float percent;
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci		if (h->filtered) {
18318c2ecf20Sopenharmony_ci			/* let it move to sibling */
18328c2ecf20Sopenharmony_ci			h->unfolded = false;
18338c2ecf20Sopenharmony_ci			continue;
18348c2ecf20Sopenharmony_ci		}
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci		if (symbol_conf.report_individual_block)
18378c2ecf20Sopenharmony_ci			percent = block_info__total_cycles_percent(h);
18388c2ecf20Sopenharmony_ci		else
18398c2ecf20Sopenharmony_ci			percent = hist_entry__get_percent_limit(h);
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci		if (percent < hb->min_pcnt)
18428c2ecf20Sopenharmony_ci			continue;
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci		if (symbol_conf.report_hierarchy) {
18458c2ecf20Sopenharmony_ci			row += hist_browser__show_hierarchy_entry(hb, h, row,
18468c2ecf20Sopenharmony_ci								  h->depth);
18478c2ecf20Sopenharmony_ci			if (row == browser->rows)
18488c2ecf20Sopenharmony_ci				break;
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci			if (h->has_no_entry) {
18518c2ecf20Sopenharmony_ci				hist_browser__show_no_entry(hb, row, h->depth + 1);
18528c2ecf20Sopenharmony_ci				row++;
18538c2ecf20Sopenharmony_ci			}
18548c2ecf20Sopenharmony_ci		} else {
18558c2ecf20Sopenharmony_ci			row += hist_browser__show_entry(hb, h, row);
18568c2ecf20Sopenharmony_ci		}
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci		if (row == browser->rows)
18598c2ecf20Sopenharmony_ci			break;
18608c2ecf20Sopenharmony_ci	}
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_ci	return row;
18638c2ecf20Sopenharmony_ci}
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_cistatic struct rb_node *hists__filter_entries(struct rb_node *nd,
18668c2ecf20Sopenharmony_ci					     float min_pcnt)
18678c2ecf20Sopenharmony_ci{
18688c2ecf20Sopenharmony_ci	while (nd != NULL) {
18698c2ecf20Sopenharmony_ci		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
18708c2ecf20Sopenharmony_ci		float percent = hist_entry__get_percent_limit(h);
18718c2ecf20Sopenharmony_ci
18728c2ecf20Sopenharmony_ci		if (!h->filtered && percent >= min_pcnt)
18738c2ecf20Sopenharmony_ci			return nd;
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci		/*
18768c2ecf20Sopenharmony_ci		 * If it's filtered, its all children also were filtered.
18778c2ecf20Sopenharmony_ci		 * So move to sibling node.
18788c2ecf20Sopenharmony_ci		 */
18798c2ecf20Sopenharmony_ci		if (rb_next(nd))
18808c2ecf20Sopenharmony_ci			nd = rb_next(nd);
18818c2ecf20Sopenharmony_ci		else
18828c2ecf20Sopenharmony_ci			nd = rb_hierarchy_next(nd);
18838c2ecf20Sopenharmony_ci	}
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci	return NULL;
18868c2ecf20Sopenharmony_ci}
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_cistatic struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
18898c2ecf20Sopenharmony_ci						  float min_pcnt)
18908c2ecf20Sopenharmony_ci{
18918c2ecf20Sopenharmony_ci	while (nd != NULL) {
18928c2ecf20Sopenharmony_ci		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
18938c2ecf20Sopenharmony_ci		float percent = hist_entry__get_percent_limit(h);
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci		if (!h->filtered && percent >= min_pcnt)
18968c2ecf20Sopenharmony_ci			return nd;
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci		nd = rb_hierarchy_prev(nd);
18998c2ecf20Sopenharmony_ci	}
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_ci	return NULL;
19028c2ecf20Sopenharmony_ci}
19038c2ecf20Sopenharmony_ci
19048c2ecf20Sopenharmony_cistatic void ui_browser__hists_seek(struct ui_browser *browser,
19058c2ecf20Sopenharmony_ci				   off_t offset, int whence)
19068c2ecf20Sopenharmony_ci{
19078c2ecf20Sopenharmony_ci	struct hist_entry *h;
19088c2ecf20Sopenharmony_ci	struct rb_node *nd;
19098c2ecf20Sopenharmony_ci	bool first = true;
19108c2ecf20Sopenharmony_ci	struct hist_browser *hb;
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_ci	hb = container_of(browser, struct hist_browser, b);
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	if (browser->nr_entries == 0)
19158c2ecf20Sopenharmony_ci		return;
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci	ui_browser__hists_init_top(browser);
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	switch (whence) {
19208c2ecf20Sopenharmony_ci	case SEEK_SET:
19218c2ecf20Sopenharmony_ci		nd = hists__filter_entries(rb_first(browser->entries),
19228c2ecf20Sopenharmony_ci					   hb->min_pcnt);
19238c2ecf20Sopenharmony_ci		break;
19248c2ecf20Sopenharmony_ci	case SEEK_CUR:
19258c2ecf20Sopenharmony_ci		nd = browser->top;
19268c2ecf20Sopenharmony_ci		goto do_offset;
19278c2ecf20Sopenharmony_ci	case SEEK_END:
19288c2ecf20Sopenharmony_ci		nd = rb_hierarchy_last(rb_last(browser->entries));
19298c2ecf20Sopenharmony_ci		nd = hists__filter_prev_entries(nd, hb->min_pcnt);
19308c2ecf20Sopenharmony_ci		first = false;
19318c2ecf20Sopenharmony_ci		break;
19328c2ecf20Sopenharmony_ci	default:
19338c2ecf20Sopenharmony_ci		return;
19348c2ecf20Sopenharmony_ci	}
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci	/*
19378c2ecf20Sopenharmony_ci	 * Moves not relative to the first visible entry invalidates its
19388c2ecf20Sopenharmony_ci	 * row_offset:
19398c2ecf20Sopenharmony_ci	 */
19408c2ecf20Sopenharmony_ci	h = rb_entry(browser->top, struct hist_entry, rb_node);
19418c2ecf20Sopenharmony_ci	h->row_offset = 0;
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ci	/*
19448c2ecf20Sopenharmony_ci	 * Here we have to check if nd is expanded (+), if it is we can't go
19458c2ecf20Sopenharmony_ci	 * the next top level hist_entry, instead we must compute an offset of
19468c2ecf20Sopenharmony_ci	 * what _not_ to show and not change the first visible entry.
19478c2ecf20Sopenharmony_ci	 *
19488c2ecf20Sopenharmony_ci	 * This offset increments when we are going from top to bottom and
19498c2ecf20Sopenharmony_ci	 * decreases when we're going from bottom to top.
19508c2ecf20Sopenharmony_ci	 *
19518c2ecf20Sopenharmony_ci	 * As we don't have backpointers to the top level in the callchains
19528c2ecf20Sopenharmony_ci	 * structure, we need to always print the whole hist_entry callchain,
19538c2ecf20Sopenharmony_ci	 * skipping the first ones that are before the first visible entry
19548c2ecf20Sopenharmony_ci	 * and stop when we printed enough lines to fill the screen.
19558c2ecf20Sopenharmony_ci	 */
19568c2ecf20Sopenharmony_cido_offset:
19578c2ecf20Sopenharmony_ci	if (!nd)
19588c2ecf20Sopenharmony_ci		return;
19598c2ecf20Sopenharmony_ci
19608c2ecf20Sopenharmony_ci	if (offset > 0) {
19618c2ecf20Sopenharmony_ci		do {
19628c2ecf20Sopenharmony_ci			h = rb_entry(nd, struct hist_entry, rb_node);
19638c2ecf20Sopenharmony_ci			if (h->unfolded && h->leaf) {
19648c2ecf20Sopenharmony_ci				u16 remaining = h->nr_rows - h->row_offset;
19658c2ecf20Sopenharmony_ci				if (offset > remaining) {
19668c2ecf20Sopenharmony_ci					offset -= remaining;
19678c2ecf20Sopenharmony_ci					h->row_offset = 0;
19688c2ecf20Sopenharmony_ci				} else {
19698c2ecf20Sopenharmony_ci					h->row_offset += offset;
19708c2ecf20Sopenharmony_ci					offset = 0;
19718c2ecf20Sopenharmony_ci					browser->top = nd;
19728c2ecf20Sopenharmony_ci					break;
19738c2ecf20Sopenharmony_ci				}
19748c2ecf20Sopenharmony_ci			}
19758c2ecf20Sopenharmony_ci			nd = hists__filter_entries(rb_hierarchy_next(nd),
19768c2ecf20Sopenharmony_ci						   hb->min_pcnt);
19778c2ecf20Sopenharmony_ci			if (nd == NULL)
19788c2ecf20Sopenharmony_ci				break;
19798c2ecf20Sopenharmony_ci			--offset;
19808c2ecf20Sopenharmony_ci			browser->top = nd;
19818c2ecf20Sopenharmony_ci		} while (offset != 0);
19828c2ecf20Sopenharmony_ci	} else if (offset < 0) {
19838c2ecf20Sopenharmony_ci		while (1) {
19848c2ecf20Sopenharmony_ci			h = rb_entry(nd, struct hist_entry, rb_node);
19858c2ecf20Sopenharmony_ci			if (h->unfolded && h->leaf) {
19868c2ecf20Sopenharmony_ci				if (first) {
19878c2ecf20Sopenharmony_ci					if (-offset > h->row_offset) {
19888c2ecf20Sopenharmony_ci						offset += h->row_offset;
19898c2ecf20Sopenharmony_ci						h->row_offset = 0;
19908c2ecf20Sopenharmony_ci					} else {
19918c2ecf20Sopenharmony_ci						h->row_offset += offset;
19928c2ecf20Sopenharmony_ci						offset = 0;
19938c2ecf20Sopenharmony_ci						browser->top = nd;
19948c2ecf20Sopenharmony_ci						break;
19958c2ecf20Sopenharmony_ci					}
19968c2ecf20Sopenharmony_ci				} else {
19978c2ecf20Sopenharmony_ci					if (-offset > h->nr_rows) {
19988c2ecf20Sopenharmony_ci						offset += h->nr_rows;
19998c2ecf20Sopenharmony_ci						h->row_offset = 0;
20008c2ecf20Sopenharmony_ci					} else {
20018c2ecf20Sopenharmony_ci						h->row_offset = h->nr_rows + offset;
20028c2ecf20Sopenharmony_ci						offset = 0;
20038c2ecf20Sopenharmony_ci						browser->top = nd;
20048c2ecf20Sopenharmony_ci						break;
20058c2ecf20Sopenharmony_ci					}
20068c2ecf20Sopenharmony_ci				}
20078c2ecf20Sopenharmony_ci			}
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci			nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
20108c2ecf20Sopenharmony_ci							hb->min_pcnt);
20118c2ecf20Sopenharmony_ci			if (nd == NULL)
20128c2ecf20Sopenharmony_ci				break;
20138c2ecf20Sopenharmony_ci			++offset;
20148c2ecf20Sopenharmony_ci			browser->top = nd;
20158c2ecf20Sopenharmony_ci			if (offset == 0) {
20168c2ecf20Sopenharmony_ci				/*
20178c2ecf20Sopenharmony_ci				 * Last unfiltered hist_entry, check if it is
20188c2ecf20Sopenharmony_ci				 * unfolded, if it is then we should have
20198c2ecf20Sopenharmony_ci				 * row_offset at its last entry.
20208c2ecf20Sopenharmony_ci				 */
20218c2ecf20Sopenharmony_ci				h = rb_entry(nd, struct hist_entry, rb_node);
20228c2ecf20Sopenharmony_ci				if (h->unfolded && h->leaf)
20238c2ecf20Sopenharmony_ci					h->row_offset = h->nr_rows;
20248c2ecf20Sopenharmony_ci				break;
20258c2ecf20Sopenharmony_ci			}
20268c2ecf20Sopenharmony_ci			first = false;
20278c2ecf20Sopenharmony_ci		}
20288c2ecf20Sopenharmony_ci	} else {
20298c2ecf20Sopenharmony_ci		browser->top = nd;
20308c2ecf20Sopenharmony_ci		h = rb_entry(nd, struct hist_entry, rb_node);
20318c2ecf20Sopenharmony_ci		h->row_offset = 0;
20328c2ecf20Sopenharmony_ci	}
20338c2ecf20Sopenharmony_ci}
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_cistatic int hist_browser__fprintf_callchain(struct hist_browser *browser,
20368c2ecf20Sopenharmony_ci					   struct hist_entry *he, FILE *fp,
20378c2ecf20Sopenharmony_ci					   int level)
20388c2ecf20Sopenharmony_ci{
20398c2ecf20Sopenharmony_ci	struct callchain_print_arg arg  = {
20408c2ecf20Sopenharmony_ci		.fp = fp,
20418c2ecf20Sopenharmony_ci	};
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci	hist_browser__show_callchain(browser, he, level, 0,
20448c2ecf20Sopenharmony_ci				     hist_browser__fprintf_callchain_entry, &arg,
20458c2ecf20Sopenharmony_ci				     hist_browser__check_dump_full);
20468c2ecf20Sopenharmony_ci	return arg.printed;
20478c2ecf20Sopenharmony_ci}
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_cistatic int hist_browser__fprintf_entry(struct hist_browser *browser,
20508c2ecf20Sopenharmony_ci				       struct hist_entry *he, FILE *fp)
20518c2ecf20Sopenharmony_ci{
20528c2ecf20Sopenharmony_ci	char s[8192];
20538c2ecf20Sopenharmony_ci	int printed = 0;
20548c2ecf20Sopenharmony_ci	char folded_sign = ' ';
20558c2ecf20Sopenharmony_ci	struct perf_hpp hpp = {
20568c2ecf20Sopenharmony_ci		.buf = s,
20578c2ecf20Sopenharmony_ci		.size = sizeof(s),
20588c2ecf20Sopenharmony_ci	};
20598c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt;
20608c2ecf20Sopenharmony_ci	bool first = true;
20618c2ecf20Sopenharmony_ci	int ret;
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci	if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
20648c2ecf20Sopenharmony_ci		folded_sign = hist_entry__folded(he);
20658c2ecf20Sopenharmony_ci		printed += fprintf(fp, "%c ", folded_sign);
20668c2ecf20Sopenharmony_ci	}
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci	hists__for_each_format(browser->hists, fmt) {
20698c2ecf20Sopenharmony_ci		if (perf_hpp__should_skip(fmt, he->hists))
20708c2ecf20Sopenharmony_ci			continue;
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ci		if (!first) {
20738c2ecf20Sopenharmony_ci			ret = scnprintf(hpp.buf, hpp.size, "  ");
20748c2ecf20Sopenharmony_ci			advance_hpp(&hpp, ret);
20758c2ecf20Sopenharmony_ci		} else
20768c2ecf20Sopenharmony_ci			first = false;
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci		ret = fmt->entry(fmt, &hpp, he);
20798c2ecf20Sopenharmony_ci		ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
20808c2ecf20Sopenharmony_ci		advance_hpp(&hpp, ret);
20818c2ecf20Sopenharmony_ci	}
20828c2ecf20Sopenharmony_ci	printed += fprintf(fp, "%s\n", s);
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci	if (folded_sign == '-')
20858c2ecf20Sopenharmony_ci		printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_ci	return printed;
20888c2ecf20Sopenharmony_ci}
20898c2ecf20Sopenharmony_ci
20908c2ecf20Sopenharmony_ci
20918c2ecf20Sopenharmony_cistatic int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
20928c2ecf20Sopenharmony_ci						 struct hist_entry *he,
20938c2ecf20Sopenharmony_ci						 FILE *fp, int level)
20948c2ecf20Sopenharmony_ci{
20958c2ecf20Sopenharmony_ci	char s[8192];
20968c2ecf20Sopenharmony_ci	int printed = 0;
20978c2ecf20Sopenharmony_ci	char folded_sign = ' ';
20988c2ecf20Sopenharmony_ci	struct perf_hpp hpp = {
20998c2ecf20Sopenharmony_ci		.buf = s,
21008c2ecf20Sopenharmony_ci		.size = sizeof(s),
21018c2ecf20Sopenharmony_ci	};
21028c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt;
21038c2ecf20Sopenharmony_ci	struct perf_hpp_list_node *fmt_node;
21048c2ecf20Sopenharmony_ci	bool first = true;
21058c2ecf20Sopenharmony_ci	int ret;
21068c2ecf20Sopenharmony_ci	int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci	printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_ci	folded_sign = hist_entry__folded(he);
21118c2ecf20Sopenharmony_ci	printed += fprintf(fp, "%c", folded_sign);
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_ci	/* the first hpp_list_node is for overhead columns */
21148c2ecf20Sopenharmony_ci	fmt_node = list_first_entry(&he->hists->hpp_formats,
21158c2ecf20Sopenharmony_ci				    struct perf_hpp_list_node, list);
21168c2ecf20Sopenharmony_ci	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
21178c2ecf20Sopenharmony_ci		if (!first) {
21188c2ecf20Sopenharmony_ci			ret = scnprintf(hpp.buf, hpp.size, "  ");
21198c2ecf20Sopenharmony_ci			advance_hpp(&hpp, ret);
21208c2ecf20Sopenharmony_ci		} else
21218c2ecf20Sopenharmony_ci			first = false;
21228c2ecf20Sopenharmony_ci
21238c2ecf20Sopenharmony_ci		ret = fmt->entry(fmt, &hpp, he);
21248c2ecf20Sopenharmony_ci		advance_hpp(&hpp, ret);
21258c2ecf20Sopenharmony_ci	}
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci	ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
21288c2ecf20Sopenharmony_ci	advance_hpp(&hpp, ret);
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci	perf_hpp_list__for_each_format(he->hpp_list, fmt) {
21318c2ecf20Sopenharmony_ci		ret = scnprintf(hpp.buf, hpp.size, "  ");
21328c2ecf20Sopenharmony_ci		advance_hpp(&hpp, ret);
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci		ret = fmt->entry(fmt, &hpp, he);
21358c2ecf20Sopenharmony_ci		advance_hpp(&hpp, ret);
21368c2ecf20Sopenharmony_ci	}
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci	strim(s);
21398c2ecf20Sopenharmony_ci	printed += fprintf(fp, "%s\n", s);
21408c2ecf20Sopenharmony_ci
21418c2ecf20Sopenharmony_ci	if (he->leaf && folded_sign == '-') {
21428c2ecf20Sopenharmony_ci		printed += hist_browser__fprintf_callchain(browser, he, fp,
21438c2ecf20Sopenharmony_ci							   he->depth + 1);
21448c2ecf20Sopenharmony_ci	}
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci	return printed;
21478c2ecf20Sopenharmony_ci}
21488c2ecf20Sopenharmony_ci
21498c2ecf20Sopenharmony_cistatic int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
21508c2ecf20Sopenharmony_ci{
21518c2ecf20Sopenharmony_ci	struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
21528c2ecf20Sopenharmony_ci						   browser->min_pcnt);
21538c2ecf20Sopenharmony_ci	int printed = 0;
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	while (nd) {
21568c2ecf20Sopenharmony_ci		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_ci		if (symbol_conf.report_hierarchy) {
21598c2ecf20Sopenharmony_ci			printed += hist_browser__fprintf_hierarchy_entry(browser,
21608c2ecf20Sopenharmony_ci									 h, fp,
21618c2ecf20Sopenharmony_ci									 h->depth);
21628c2ecf20Sopenharmony_ci		} else {
21638c2ecf20Sopenharmony_ci			printed += hist_browser__fprintf_entry(browser, h, fp);
21648c2ecf20Sopenharmony_ci		}
21658c2ecf20Sopenharmony_ci
21668c2ecf20Sopenharmony_ci		nd = hists__filter_entries(rb_hierarchy_next(nd),
21678c2ecf20Sopenharmony_ci					   browser->min_pcnt);
21688c2ecf20Sopenharmony_ci	}
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_ci	return printed;
21718c2ecf20Sopenharmony_ci}
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_cistatic int hist_browser__dump(struct hist_browser *browser)
21748c2ecf20Sopenharmony_ci{
21758c2ecf20Sopenharmony_ci	char filename[64];
21768c2ecf20Sopenharmony_ci	FILE *fp;
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci	while (1) {
21798c2ecf20Sopenharmony_ci		scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
21808c2ecf20Sopenharmony_ci		if (access(filename, F_OK))
21818c2ecf20Sopenharmony_ci			break;
21828c2ecf20Sopenharmony_ci		/*
21838c2ecf20Sopenharmony_ci 		 * XXX: Just an arbitrary lazy upper limit
21848c2ecf20Sopenharmony_ci 		 */
21858c2ecf20Sopenharmony_ci		if (++browser->print_seq == 8192) {
21868c2ecf20Sopenharmony_ci			ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
21878c2ecf20Sopenharmony_ci			return -1;
21888c2ecf20Sopenharmony_ci		}
21898c2ecf20Sopenharmony_ci	}
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci	fp = fopen(filename, "w");
21928c2ecf20Sopenharmony_ci	if (fp == NULL) {
21938c2ecf20Sopenharmony_ci		char bf[64];
21948c2ecf20Sopenharmony_ci		const char *err = str_error_r(errno, bf, sizeof(bf));
21958c2ecf20Sopenharmony_ci		ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
21968c2ecf20Sopenharmony_ci		return -1;
21978c2ecf20Sopenharmony_ci	}
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_ci	++browser->print_seq;
22008c2ecf20Sopenharmony_ci	hist_browser__fprintf(browser, fp);
22018c2ecf20Sopenharmony_ci	fclose(fp);
22028c2ecf20Sopenharmony_ci	ui_helpline__fpush("%s written!", filename);
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci	return 0;
22058c2ecf20Sopenharmony_ci}
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_civoid hist_browser__init(struct hist_browser *browser,
22088c2ecf20Sopenharmony_ci			struct hists *hists)
22098c2ecf20Sopenharmony_ci{
22108c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt;
22118c2ecf20Sopenharmony_ci
22128c2ecf20Sopenharmony_ci	browser->hists			= hists;
22138c2ecf20Sopenharmony_ci	browser->b.refresh		= hist_browser__refresh;
22148c2ecf20Sopenharmony_ci	browser->b.refresh_dimensions	= hist_browser__refresh_dimensions;
22158c2ecf20Sopenharmony_ci	browser->b.seek			= ui_browser__hists_seek;
22168c2ecf20Sopenharmony_ci	browser->b.use_navkeypressed	= true;
22178c2ecf20Sopenharmony_ci	browser->show_headers		= symbol_conf.show_hist_headers;
22188c2ecf20Sopenharmony_ci	hist_browser__set_title_space(browser);
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_ci	if (symbol_conf.report_hierarchy) {
22218c2ecf20Sopenharmony_ci		struct perf_hpp_list_node *fmt_node;
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci		/* count overhead columns (in the first node) */
22248c2ecf20Sopenharmony_ci		fmt_node = list_first_entry(&hists->hpp_formats,
22258c2ecf20Sopenharmony_ci					    struct perf_hpp_list_node, list);
22268c2ecf20Sopenharmony_ci		perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
22278c2ecf20Sopenharmony_ci			++browser->b.columns;
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_ci		/* add a single column for whole hierarchy sort keys*/
22308c2ecf20Sopenharmony_ci		++browser->b.columns;
22318c2ecf20Sopenharmony_ci	} else {
22328c2ecf20Sopenharmony_ci		hists__for_each_format(hists, fmt)
22338c2ecf20Sopenharmony_ci			++browser->b.columns;
22348c2ecf20Sopenharmony_ci	}
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_ci	hists__reset_column_width(hists);
22378c2ecf20Sopenharmony_ci}
22388c2ecf20Sopenharmony_ci
22398c2ecf20Sopenharmony_cistruct hist_browser *hist_browser__new(struct hists *hists)
22408c2ecf20Sopenharmony_ci{
22418c2ecf20Sopenharmony_ci	struct hist_browser *browser = zalloc(sizeof(*browser));
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_ci	if (browser)
22448c2ecf20Sopenharmony_ci		hist_browser__init(browser, hists);
22458c2ecf20Sopenharmony_ci
22468c2ecf20Sopenharmony_ci	return browser;
22478c2ecf20Sopenharmony_ci}
22488c2ecf20Sopenharmony_ci
22498c2ecf20Sopenharmony_cistatic struct hist_browser *
22508c2ecf20Sopenharmony_ciperf_evsel_browser__new(struct evsel *evsel,
22518c2ecf20Sopenharmony_ci			struct hist_browser_timer *hbt,
22528c2ecf20Sopenharmony_ci			struct perf_env *env,
22538c2ecf20Sopenharmony_ci			struct annotation_options *annotation_opts)
22548c2ecf20Sopenharmony_ci{
22558c2ecf20Sopenharmony_ci	struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	if (browser) {
22588c2ecf20Sopenharmony_ci		browser->hbt   = hbt;
22598c2ecf20Sopenharmony_ci		browser->env   = env;
22608c2ecf20Sopenharmony_ci		browser->title = hists_browser__scnprintf_title;
22618c2ecf20Sopenharmony_ci		browser->annotation_opts = annotation_opts;
22628c2ecf20Sopenharmony_ci	}
22638c2ecf20Sopenharmony_ci	return browser;
22648c2ecf20Sopenharmony_ci}
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_civoid hist_browser__delete(struct hist_browser *browser)
22678c2ecf20Sopenharmony_ci{
22688c2ecf20Sopenharmony_ci	free(browser);
22698c2ecf20Sopenharmony_ci}
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_cistatic struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
22728c2ecf20Sopenharmony_ci{
22738c2ecf20Sopenharmony_ci	return browser->he_selection;
22748c2ecf20Sopenharmony_ci}
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_cistatic struct thread *hist_browser__selected_thread(struct hist_browser *browser)
22778c2ecf20Sopenharmony_ci{
22788c2ecf20Sopenharmony_ci	return browser->he_selection->thread;
22798c2ecf20Sopenharmony_ci}
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_cistatic struct res_sample *hist_browser__selected_res_sample(struct hist_browser *browser)
22828c2ecf20Sopenharmony_ci{
22838c2ecf20Sopenharmony_ci	return browser->he_selection ? browser->he_selection->res_samples : NULL;
22848c2ecf20Sopenharmony_ci}
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_ci/* Check whether the browser is for 'top' or 'report' */
22878c2ecf20Sopenharmony_cistatic inline bool is_report_browser(void *timer)
22888c2ecf20Sopenharmony_ci{
22898c2ecf20Sopenharmony_ci	return timer == NULL;
22908c2ecf20Sopenharmony_ci}
22918c2ecf20Sopenharmony_ci
22928c2ecf20Sopenharmony_cistatic int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size)
22938c2ecf20Sopenharmony_ci{
22948c2ecf20Sopenharmony_ci	struct hist_browser_timer *hbt = browser->hbt;
22958c2ecf20Sopenharmony_ci	int printed = __hists__scnprintf_title(browser->hists, bf, size, !is_report_browser(hbt));
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci	if (!is_report_browser(hbt)) {
22988c2ecf20Sopenharmony_ci		struct perf_top *top = hbt->arg;
22998c2ecf20Sopenharmony_ci
23008c2ecf20Sopenharmony_ci		printed += scnprintf(bf + printed, size - printed,
23018c2ecf20Sopenharmony_ci				     " lost: %" PRIu64 "/%" PRIu64,
23028c2ecf20Sopenharmony_ci				     top->lost, top->lost_total);
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci		printed += scnprintf(bf + printed, size - printed,
23058c2ecf20Sopenharmony_ci				     " drop: %" PRIu64 "/%" PRIu64,
23068c2ecf20Sopenharmony_ci				     top->drop, top->drop_total);
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_ci		if (top->zero)
23098c2ecf20Sopenharmony_ci			printed += scnprintf(bf + printed, size - printed, " [z]");
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci		perf_top__reset_sample_counters(top);
23128c2ecf20Sopenharmony_ci	}
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ci
23158c2ecf20Sopenharmony_ci	return printed;
23168c2ecf20Sopenharmony_ci}
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_cistatic inline void free_popup_options(char **options, int n)
23198c2ecf20Sopenharmony_ci{
23208c2ecf20Sopenharmony_ci	int i;
23218c2ecf20Sopenharmony_ci
23228c2ecf20Sopenharmony_ci	for (i = 0; i < n; ++i)
23238c2ecf20Sopenharmony_ci		zfree(&options[i]);
23248c2ecf20Sopenharmony_ci}
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_ci/*
23278c2ecf20Sopenharmony_ci * Only runtime switching of perf data file will make "input_name" point
23288c2ecf20Sopenharmony_ci * to a malloced buffer. So add "is_input_name_malloced" flag to decide
23298c2ecf20Sopenharmony_ci * whether we need to call free() for current "input_name" during the switch.
23308c2ecf20Sopenharmony_ci */
23318c2ecf20Sopenharmony_cistatic bool is_input_name_malloced = false;
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_cistatic int switch_data_file(void)
23348c2ecf20Sopenharmony_ci{
23358c2ecf20Sopenharmony_ci	char *pwd, *options[32], *abs_path[32], *tmp;
23368c2ecf20Sopenharmony_ci	DIR *pwd_dir;
23378c2ecf20Sopenharmony_ci	int nr_options = 0, choice = -1, ret = -1;
23388c2ecf20Sopenharmony_ci	struct dirent *dent;
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_ci	pwd = getenv("PWD");
23418c2ecf20Sopenharmony_ci	if (!pwd)
23428c2ecf20Sopenharmony_ci		return ret;
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci	pwd_dir = opendir(pwd);
23458c2ecf20Sopenharmony_ci	if (!pwd_dir)
23468c2ecf20Sopenharmony_ci		return ret;
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci	memset(options, 0, sizeof(options));
23498c2ecf20Sopenharmony_ci	memset(abs_path, 0, sizeof(abs_path));
23508c2ecf20Sopenharmony_ci
23518c2ecf20Sopenharmony_ci	while ((dent = readdir(pwd_dir))) {
23528c2ecf20Sopenharmony_ci		char path[PATH_MAX];
23538c2ecf20Sopenharmony_ci		u64 magic;
23548c2ecf20Sopenharmony_ci		char *name = dent->d_name;
23558c2ecf20Sopenharmony_ci		FILE *file;
23568c2ecf20Sopenharmony_ci
23578c2ecf20Sopenharmony_ci		if (!(dent->d_type == DT_REG))
23588c2ecf20Sopenharmony_ci			continue;
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci		snprintf(path, sizeof(path), "%s/%s", pwd, name);
23618c2ecf20Sopenharmony_ci
23628c2ecf20Sopenharmony_ci		file = fopen(path, "r");
23638c2ecf20Sopenharmony_ci		if (!file)
23648c2ecf20Sopenharmony_ci			continue;
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ci		if (fread(&magic, 1, 8, file) < 8)
23678c2ecf20Sopenharmony_ci			goto close_file_and_continue;
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci		if (is_perf_magic(magic)) {
23708c2ecf20Sopenharmony_ci			options[nr_options] = strdup(name);
23718c2ecf20Sopenharmony_ci			if (!options[nr_options])
23728c2ecf20Sopenharmony_ci				goto close_file_and_continue;
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci			abs_path[nr_options] = strdup(path);
23758c2ecf20Sopenharmony_ci			if (!abs_path[nr_options]) {
23768c2ecf20Sopenharmony_ci				zfree(&options[nr_options]);
23778c2ecf20Sopenharmony_ci				ui__warning("Can't search all data files due to memory shortage.\n");
23788c2ecf20Sopenharmony_ci				fclose(file);
23798c2ecf20Sopenharmony_ci				break;
23808c2ecf20Sopenharmony_ci			}
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_ci			nr_options++;
23838c2ecf20Sopenharmony_ci		}
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_ciclose_file_and_continue:
23868c2ecf20Sopenharmony_ci		fclose(file);
23878c2ecf20Sopenharmony_ci		if (nr_options >= 32) {
23888c2ecf20Sopenharmony_ci			ui__warning("Too many perf data files in PWD!\n"
23898c2ecf20Sopenharmony_ci				    "Only the first 32 files will be listed.\n");
23908c2ecf20Sopenharmony_ci			break;
23918c2ecf20Sopenharmony_ci		}
23928c2ecf20Sopenharmony_ci	}
23938c2ecf20Sopenharmony_ci	closedir(pwd_dir);
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_ci	if (nr_options) {
23968c2ecf20Sopenharmony_ci		choice = ui__popup_menu(nr_options, options, NULL);
23978c2ecf20Sopenharmony_ci		if (choice < nr_options && choice >= 0) {
23988c2ecf20Sopenharmony_ci			tmp = strdup(abs_path[choice]);
23998c2ecf20Sopenharmony_ci			if (tmp) {
24008c2ecf20Sopenharmony_ci				if (is_input_name_malloced)
24018c2ecf20Sopenharmony_ci					free((void *)input_name);
24028c2ecf20Sopenharmony_ci				input_name = tmp;
24038c2ecf20Sopenharmony_ci				is_input_name_malloced = true;
24048c2ecf20Sopenharmony_ci				ret = 0;
24058c2ecf20Sopenharmony_ci			} else
24068c2ecf20Sopenharmony_ci				ui__warning("Data switch failed due to memory shortage!\n");
24078c2ecf20Sopenharmony_ci		}
24088c2ecf20Sopenharmony_ci	}
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_ci	free_popup_options(options, nr_options);
24118c2ecf20Sopenharmony_ci	free_popup_options(abs_path, nr_options);
24128c2ecf20Sopenharmony_ci	return ret;
24138c2ecf20Sopenharmony_ci}
24148c2ecf20Sopenharmony_ci
24158c2ecf20Sopenharmony_cistruct popup_action {
24168c2ecf20Sopenharmony_ci	unsigned long		time;
24178c2ecf20Sopenharmony_ci	struct thread 		*thread;
24188c2ecf20Sopenharmony_ci	struct map_symbol 	ms;
24198c2ecf20Sopenharmony_ci	int			socket;
24208c2ecf20Sopenharmony_ci	struct evsel	*evsel;
24218c2ecf20Sopenharmony_ci	enum rstype		rstype;
24228c2ecf20Sopenharmony_ci
24238c2ecf20Sopenharmony_ci	int (*fn)(struct hist_browser *browser, struct popup_action *act);
24248c2ecf20Sopenharmony_ci};
24258c2ecf20Sopenharmony_ci
24268c2ecf20Sopenharmony_cistatic int
24278c2ecf20Sopenharmony_cido_annotate(struct hist_browser *browser, struct popup_action *act)
24288c2ecf20Sopenharmony_ci{
24298c2ecf20Sopenharmony_ci	struct evsel *evsel;
24308c2ecf20Sopenharmony_ci	struct annotation *notes;
24318c2ecf20Sopenharmony_ci	struct hist_entry *he;
24328c2ecf20Sopenharmony_ci	int err;
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci	if (!browser->annotation_opts->objdump_path &&
24358c2ecf20Sopenharmony_ci	    perf_env__lookup_objdump(browser->env, &browser->annotation_opts->objdump_path))
24368c2ecf20Sopenharmony_ci		return 0;
24378c2ecf20Sopenharmony_ci
24388c2ecf20Sopenharmony_ci	notes = symbol__annotation(act->ms.sym);
24398c2ecf20Sopenharmony_ci	if (!notes->src)
24408c2ecf20Sopenharmony_ci		return 0;
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci	if (browser->block_evsel)
24438c2ecf20Sopenharmony_ci		evsel = browser->block_evsel;
24448c2ecf20Sopenharmony_ci	else
24458c2ecf20Sopenharmony_ci		evsel = hists_to_evsel(browser->hists);
24468c2ecf20Sopenharmony_ci
24478c2ecf20Sopenharmony_ci	err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt,
24488c2ecf20Sopenharmony_ci				       browser->annotation_opts);
24498c2ecf20Sopenharmony_ci	he = hist_browser__selected_entry(browser);
24508c2ecf20Sopenharmony_ci	/*
24518c2ecf20Sopenharmony_ci	 * offer option to annotate the other branch source or target
24528c2ecf20Sopenharmony_ci	 * (if they exists) when returning from annotate
24538c2ecf20Sopenharmony_ci	 */
24548c2ecf20Sopenharmony_ci	if ((err == 'q' || err == CTRL('c')) && he->branch_info)
24558c2ecf20Sopenharmony_ci		return 1;
24568c2ecf20Sopenharmony_ci
24578c2ecf20Sopenharmony_ci	ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
24588c2ecf20Sopenharmony_ci	if (err)
24598c2ecf20Sopenharmony_ci		ui_browser__handle_resize(&browser->b);
24608c2ecf20Sopenharmony_ci	return 0;
24618c2ecf20Sopenharmony_ci}
24628c2ecf20Sopenharmony_ci
24638c2ecf20Sopenharmony_cistatic struct symbol *symbol__new_unresolved(u64 addr, struct map *map)
24648c2ecf20Sopenharmony_ci{
24658c2ecf20Sopenharmony_ci	struct annotated_source *src;
24668c2ecf20Sopenharmony_ci	struct symbol *sym;
24678c2ecf20Sopenharmony_ci	char name[64];
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ci	snprintf(name, sizeof(name), "%.*" PRIx64, BITS_PER_LONG / 4, addr);
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_ci	sym = symbol__new(addr, ANNOTATION_DUMMY_LEN, 0, 0, name);
24728c2ecf20Sopenharmony_ci	if (sym) {
24738c2ecf20Sopenharmony_ci		src = symbol__hists(sym, 1);
24748c2ecf20Sopenharmony_ci		if (!src) {
24758c2ecf20Sopenharmony_ci			symbol__delete(sym);
24768c2ecf20Sopenharmony_ci			return NULL;
24778c2ecf20Sopenharmony_ci		}
24788c2ecf20Sopenharmony_ci
24798c2ecf20Sopenharmony_ci		dso__insert_symbol(map->dso, sym);
24808c2ecf20Sopenharmony_ci	}
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_ci	return sym;
24838c2ecf20Sopenharmony_ci}
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_cistatic int
24868c2ecf20Sopenharmony_ciadd_annotate_opt(struct hist_browser *browser __maybe_unused,
24878c2ecf20Sopenharmony_ci		 struct popup_action *act, char **optstr,
24888c2ecf20Sopenharmony_ci		 struct map_symbol *ms,
24898c2ecf20Sopenharmony_ci		 u64 addr)
24908c2ecf20Sopenharmony_ci{
24918c2ecf20Sopenharmony_ci	if (!ms->map || !ms->map->dso || ms->map->dso->annotate_warned)
24928c2ecf20Sopenharmony_ci		return 0;
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci	if (!ms->sym)
24958c2ecf20Sopenharmony_ci		ms->sym = symbol__new_unresolved(addr, ms->map);
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_ci	if (ms->sym == NULL || symbol__annotation(ms->sym)->src == NULL)
24988c2ecf20Sopenharmony_ci		return 0;
24998c2ecf20Sopenharmony_ci
25008c2ecf20Sopenharmony_ci	if (asprintf(optstr, "Annotate %s", ms->sym->name) < 0)
25018c2ecf20Sopenharmony_ci		return 0;
25028c2ecf20Sopenharmony_ci
25038c2ecf20Sopenharmony_ci	act->ms = *ms;
25048c2ecf20Sopenharmony_ci	act->fn = do_annotate;
25058c2ecf20Sopenharmony_ci	return 1;
25068c2ecf20Sopenharmony_ci}
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_cistatic int
25098c2ecf20Sopenharmony_cido_zoom_thread(struct hist_browser *browser, struct popup_action *act)
25108c2ecf20Sopenharmony_ci{
25118c2ecf20Sopenharmony_ci	struct thread *thread = act->thread;
25128c2ecf20Sopenharmony_ci
25138c2ecf20Sopenharmony_ci	if ((!hists__has(browser->hists, thread) &&
25148c2ecf20Sopenharmony_ci	     !hists__has(browser->hists, comm)) || thread == NULL)
25158c2ecf20Sopenharmony_ci		return 0;
25168c2ecf20Sopenharmony_ci
25178c2ecf20Sopenharmony_ci	if (browser->hists->thread_filter) {
25188c2ecf20Sopenharmony_ci		pstack__remove(browser->pstack, &browser->hists->thread_filter);
25198c2ecf20Sopenharmony_ci		perf_hpp__set_elide(HISTC_THREAD, false);
25208c2ecf20Sopenharmony_ci		thread__zput(browser->hists->thread_filter);
25218c2ecf20Sopenharmony_ci		ui_helpline__pop();
25228c2ecf20Sopenharmony_ci	} else {
25238c2ecf20Sopenharmony_ci		if (hists__has(browser->hists, thread)) {
25248c2ecf20Sopenharmony_ci			ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
25258c2ecf20Sopenharmony_ci					   thread->comm_set ? thread__comm_str(thread) : "",
25268c2ecf20Sopenharmony_ci					   thread->tid);
25278c2ecf20Sopenharmony_ci		} else {
25288c2ecf20Sopenharmony_ci			ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
25298c2ecf20Sopenharmony_ci					   thread->comm_set ? thread__comm_str(thread) : "");
25308c2ecf20Sopenharmony_ci		}
25318c2ecf20Sopenharmony_ci
25328c2ecf20Sopenharmony_ci		browser->hists->thread_filter = thread__get(thread);
25338c2ecf20Sopenharmony_ci		perf_hpp__set_elide(HISTC_THREAD, false);
25348c2ecf20Sopenharmony_ci		pstack__push(browser->pstack, &browser->hists->thread_filter);
25358c2ecf20Sopenharmony_ci	}
25368c2ecf20Sopenharmony_ci
25378c2ecf20Sopenharmony_ci	hists__filter_by_thread(browser->hists);
25388c2ecf20Sopenharmony_ci	hist_browser__reset(browser);
25398c2ecf20Sopenharmony_ci	return 0;
25408c2ecf20Sopenharmony_ci}
25418c2ecf20Sopenharmony_ci
25428c2ecf20Sopenharmony_cistatic int
25438c2ecf20Sopenharmony_ciadd_thread_opt(struct hist_browser *browser, struct popup_action *act,
25448c2ecf20Sopenharmony_ci	       char **optstr, struct thread *thread)
25458c2ecf20Sopenharmony_ci{
25468c2ecf20Sopenharmony_ci	int ret;
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_ci	if ((!hists__has(browser->hists, thread) &&
25498c2ecf20Sopenharmony_ci	     !hists__has(browser->hists, comm)) || thread == NULL)
25508c2ecf20Sopenharmony_ci		return 0;
25518c2ecf20Sopenharmony_ci
25528c2ecf20Sopenharmony_ci	if (hists__has(browser->hists, thread)) {
25538c2ecf20Sopenharmony_ci		ret = asprintf(optstr, "Zoom %s %s(%d) thread",
25548c2ecf20Sopenharmony_ci			       browser->hists->thread_filter ? "out of" : "into",
25558c2ecf20Sopenharmony_ci			       thread->comm_set ? thread__comm_str(thread) : "",
25568c2ecf20Sopenharmony_ci			       thread->tid);
25578c2ecf20Sopenharmony_ci	} else {
25588c2ecf20Sopenharmony_ci		ret = asprintf(optstr, "Zoom %s %s thread",
25598c2ecf20Sopenharmony_ci			       browser->hists->thread_filter ? "out of" : "into",
25608c2ecf20Sopenharmony_ci			       thread->comm_set ? thread__comm_str(thread) : "");
25618c2ecf20Sopenharmony_ci	}
25628c2ecf20Sopenharmony_ci	if (ret < 0)
25638c2ecf20Sopenharmony_ci		return 0;
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_ci	act->thread = thread;
25668c2ecf20Sopenharmony_ci	act->fn = do_zoom_thread;
25678c2ecf20Sopenharmony_ci	return 1;
25688c2ecf20Sopenharmony_ci}
25698c2ecf20Sopenharmony_ci
25708c2ecf20Sopenharmony_cistatic int hists_browser__zoom_map(struct hist_browser *browser, struct map *map)
25718c2ecf20Sopenharmony_ci{
25728c2ecf20Sopenharmony_ci	if (!hists__has(browser->hists, dso) || map == NULL)
25738c2ecf20Sopenharmony_ci		return 0;
25748c2ecf20Sopenharmony_ci
25758c2ecf20Sopenharmony_ci	if (browser->hists->dso_filter) {
25768c2ecf20Sopenharmony_ci		pstack__remove(browser->pstack, &browser->hists->dso_filter);
25778c2ecf20Sopenharmony_ci		perf_hpp__set_elide(HISTC_DSO, false);
25788c2ecf20Sopenharmony_ci		browser->hists->dso_filter = NULL;
25798c2ecf20Sopenharmony_ci		ui_helpline__pop();
25808c2ecf20Sopenharmony_ci	} else {
25818c2ecf20Sopenharmony_ci		ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
25828c2ecf20Sopenharmony_ci				   __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
25838c2ecf20Sopenharmony_ci		browser->hists->dso_filter = map->dso;
25848c2ecf20Sopenharmony_ci		perf_hpp__set_elide(HISTC_DSO, true);
25858c2ecf20Sopenharmony_ci		pstack__push(browser->pstack, &browser->hists->dso_filter);
25868c2ecf20Sopenharmony_ci	}
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci	hists__filter_by_dso(browser->hists);
25898c2ecf20Sopenharmony_ci	hist_browser__reset(browser);
25908c2ecf20Sopenharmony_ci	return 0;
25918c2ecf20Sopenharmony_ci}
25928c2ecf20Sopenharmony_ci
25938c2ecf20Sopenharmony_cistatic int
25948c2ecf20Sopenharmony_cido_zoom_dso(struct hist_browser *browser, struct popup_action *act)
25958c2ecf20Sopenharmony_ci{
25968c2ecf20Sopenharmony_ci	return hists_browser__zoom_map(browser, act->ms.map);
25978c2ecf20Sopenharmony_ci}
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_cistatic int
26008c2ecf20Sopenharmony_ciadd_dso_opt(struct hist_browser *browser, struct popup_action *act,
26018c2ecf20Sopenharmony_ci	    char **optstr, struct map *map)
26028c2ecf20Sopenharmony_ci{
26038c2ecf20Sopenharmony_ci	if (!hists__has(browser->hists, dso) || map == NULL)
26048c2ecf20Sopenharmony_ci		return 0;
26058c2ecf20Sopenharmony_ci
26068c2ecf20Sopenharmony_ci	if (asprintf(optstr, "Zoom %s %s DSO (use the 'k' hotkey to zoom directly into the kernel)",
26078c2ecf20Sopenharmony_ci		     browser->hists->dso_filter ? "out of" : "into",
26088c2ecf20Sopenharmony_ci		     __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
26098c2ecf20Sopenharmony_ci		return 0;
26108c2ecf20Sopenharmony_ci
26118c2ecf20Sopenharmony_ci	act->ms.map = map;
26128c2ecf20Sopenharmony_ci	act->fn = do_zoom_dso;
26138c2ecf20Sopenharmony_ci	return 1;
26148c2ecf20Sopenharmony_ci}
26158c2ecf20Sopenharmony_ci
26168c2ecf20Sopenharmony_cistatic int do_toggle_callchain(struct hist_browser *browser, struct popup_action *act __maybe_unused)
26178c2ecf20Sopenharmony_ci{
26188c2ecf20Sopenharmony_ci	hist_browser__toggle_fold(browser);
26198c2ecf20Sopenharmony_ci	return 0;
26208c2ecf20Sopenharmony_ci}
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_cistatic int add_callchain_toggle_opt(struct hist_browser *browser, struct popup_action *act, char **optstr)
26238c2ecf20Sopenharmony_ci{
26248c2ecf20Sopenharmony_ci	char sym_name[512];
26258c2ecf20Sopenharmony_ci
26268c2ecf20Sopenharmony_ci        if (!hist_browser__selection_has_children(browser))
26278c2ecf20Sopenharmony_ci                return 0;
26288c2ecf20Sopenharmony_ci
26298c2ecf20Sopenharmony_ci	if (asprintf(optstr, "%s [%s] callchain (one level, same as '+' hotkey, use 'e'/'c' for the whole main level entry)",
26308c2ecf20Sopenharmony_ci		     hist_browser__selection_unfolded(browser) ? "Collapse" : "Expand",
26318c2ecf20Sopenharmony_ci		     hist_browser__selection_sym_name(browser, sym_name, sizeof(sym_name))) < 0)
26328c2ecf20Sopenharmony_ci		return 0;
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_ci	act->fn = do_toggle_callchain;
26358c2ecf20Sopenharmony_ci	return 1;
26368c2ecf20Sopenharmony_ci}
26378c2ecf20Sopenharmony_ci
26388c2ecf20Sopenharmony_cistatic int
26398c2ecf20Sopenharmony_cido_browse_map(struct hist_browser *browser __maybe_unused,
26408c2ecf20Sopenharmony_ci	      struct popup_action *act)
26418c2ecf20Sopenharmony_ci{
26428c2ecf20Sopenharmony_ci	map__browse(act->ms.map);
26438c2ecf20Sopenharmony_ci	return 0;
26448c2ecf20Sopenharmony_ci}
26458c2ecf20Sopenharmony_ci
26468c2ecf20Sopenharmony_cistatic int
26478c2ecf20Sopenharmony_ciadd_map_opt(struct hist_browser *browser,
26488c2ecf20Sopenharmony_ci	    struct popup_action *act, char **optstr, struct map *map)
26498c2ecf20Sopenharmony_ci{
26508c2ecf20Sopenharmony_ci	if (!hists__has(browser->hists, dso) || map == NULL)
26518c2ecf20Sopenharmony_ci		return 0;
26528c2ecf20Sopenharmony_ci
26538c2ecf20Sopenharmony_ci	if (asprintf(optstr, "Browse map details") < 0)
26548c2ecf20Sopenharmony_ci		return 0;
26558c2ecf20Sopenharmony_ci
26568c2ecf20Sopenharmony_ci	act->ms.map = map;
26578c2ecf20Sopenharmony_ci	act->fn = do_browse_map;
26588c2ecf20Sopenharmony_ci	return 1;
26598c2ecf20Sopenharmony_ci}
26608c2ecf20Sopenharmony_ci
26618c2ecf20Sopenharmony_cistatic int
26628c2ecf20Sopenharmony_cido_run_script(struct hist_browser *browser __maybe_unused,
26638c2ecf20Sopenharmony_ci	      struct popup_action *act)
26648c2ecf20Sopenharmony_ci{
26658c2ecf20Sopenharmony_ci	char *script_opt;
26668c2ecf20Sopenharmony_ci	int len;
26678c2ecf20Sopenharmony_ci	int n = 0;
26688c2ecf20Sopenharmony_ci
26698c2ecf20Sopenharmony_ci	len = 100;
26708c2ecf20Sopenharmony_ci	if (act->thread)
26718c2ecf20Sopenharmony_ci		len += strlen(thread__comm_str(act->thread));
26728c2ecf20Sopenharmony_ci	else if (act->ms.sym)
26738c2ecf20Sopenharmony_ci		len += strlen(act->ms.sym->name);
26748c2ecf20Sopenharmony_ci	script_opt = malloc(len);
26758c2ecf20Sopenharmony_ci	if (!script_opt)
26768c2ecf20Sopenharmony_ci		return -1;
26778c2ecf20Sopenharmony_ci
26788c2ecf20Sopenharmony_ci	script_opt[0] = 0;
26798c2ecf20Sopenharmony_ci	if (act->thread) {
26808c2ecf20Sopenharmony_ci		n = scnprintf(script_opt, len, " -c %s ",
26818c2ecf20Sopenharmony_ci			  thread__comm_str(act->thread));
26828c2ecf20Sopenharmony_ci	} else if (act->ms.sym) {
26838c2ecf20Sopenharmony_ci		n = scnprintf(script_opt, len, " -S %s ",
26848c2ecf20Sopenharmony_ci			  act->ms.sym->name);
26858c2ecf20Sopenharmony_ci	}
26868c2ecf20Sopenharmony_ci
26878c2ecf20Sopenharmony_ci	if (act->time) {
26888c2ecf20Sopenharmony_ci		char start[32], end[32];
26898c2ecf20Sopenharmony_ci		unsigned long starttime = act->time;
26908c2ecf20Sopenharmony_ci		unsigned long endtime = act->time + symbol_conf.time_quantum;
26918c2ecf20Sopenharmony_ci
26928c2ecf20Sopenharmony_ci		if (starttime == endtime) { /* Display 1ms as fallback */
26938c2ecf20Sopenharmony_ci			starttime -= 1*NSEC_PER_MSEC;
26948c2ecf20Sopenharmony_ci			endtime += 1*NSEC_PER_MSEC;
26958c2ecf20Sopenharmony_ci		}
26968c2ecf20Sopenharmony_ci		timestamp__scnprintf_usec(starttime, start, sizeof start);
26978c2ecf20Sopenharmony_ci		timestamp__scnprintf_usec(endtime, end, sizeof end);
26988c2ecf20Sopenharmony_ci		n += snprintf(script_opt + n, len - n, " --time %s,%s", start, end);
26998c2ecf20Sopenharmony_ci	}
27008c2ecf20Sopenharmony_ci
27018c2ecf20Sopenharmony_ci	script_browse(script_opt, act->evsel);
27028c2ecf20Sopenharmony_ci	free(script_opt);
27038c2ecf20Sopenharmony_ci	return 0;
27048c2ecf20Sopenharmony_ci}
27058c2ecf20Sopenharmony_ci
27068c2ecf20Sopenharmony_cistatic int
27078c2ecf20Sopenharmony_cido_res_sample_script(struct hist_browser *browser __maybe_unused,
27088c2ecf20Sopenharmony_ci		     struct popup_action *act)
27098c2ecf20Sopenharmony_ci{
27108c2ecf20Sopenharmony_ci	struct hist_entry *he;
27118c2ecf20Sopenharmony_ci
27128c2ecf20Sopenharmony_ci	he = hist_browser__selected_entry(browser);
27138c2ecf20Sopenharmony_ci	res_sample_browse(he->res_samples, he->num_res, act->evsel, act->rstype);
27148c2ecf20Sopenharmony_ci	return 0;
27158c2ecf20Sopenharmony_ci}
27168c2ecf20Sopenharmony_ci
27178c2ecf20Sopenharmony_cistatic int
27188c2ecf20Sopenharmony_ciadd_script_opt_2(struct hist_browser *browser __maybe_unused,
27198c2ecf20Sopenharmony_ci	       struct popup_action *act, char **optstr,
27208c2ecf20Sopenharmony_ci	       struct thread *thread, struct symbol *sym,
27218c2ecf20Sopenharmony_ci	       struct evsel *evsel, const char *tstr)
27228c2ecf20Sopenharmony_ci{
27238c2ecf20Sopenharmony_ci
27248c2ecf20Sopenharmony_ci	if (thread) {
27258c2ecf20Sopenharmony_ci		if (asprintf(optstr, "Run scripts for samples of thread [%s]%s",
27268c2ecf20Sopenharmony_ci			     thread__comm_str(thread), tstr) < 0)
27278c2ecf20Sopenharmony_ci			return 0;
27288c2ecf20Sopenharmony_ci	} else if (sym) {
27298c2ecf20Sopenharmony_ci		if (asprintf(optstr, "Run scripts for samples of symbol [%s]%s",
27308c2ecf20Sopenharmony_ci			     sym->name, tstr) < 0)
27318c2ecf20Sopenharmony_ci			return 0;
27328c2ecf20Sopenharmony_ci	} else {
27338c2ecf20Sopenharmony_ci		if (asprintf(optstr, "Run scripts for all samples%s", tstr) < 0)
27348c2ecf20Sopenharmony_ci			return 0;
27358c2ecf20Sopenharmony_ci	}
27368c2ecf20Sopenharmony_ci
27378c2ecf20Sopenharmony_ci	act->thread = thread;
27388c2ecf20Sopenharmony_ci	act->ms.sym = sym;
27398c2ecf20Sopenharmony_ci	act->evsel = evsel;
27408c2ecf20Sopenharmony_ci	act->fn = do_run_script;
27418c2ecf20Sopenharmony_ci	return 1;
27428c2ecf20Sopenharmony_ci}
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_cistatic int
27458c2ecf20Sopenharmony_ciadd_script_opt(struct hist_browser *browser,
27468c2ecf20Sopenharmony_ci	       struct popup_action *act, char **optstr,
27478c2ecf20Sopenharmony_ci	       struct thread *thread, struct symbol *sym,
27488c2ecf20Sopenharmony_ci	       struct evsel *evsel)
27498c2ecf20Sopenharmony_ci{
27508c2ecf20Sopenharmony_ci	int n, j;
27518c2ecf20Sopenharmony_ci	struct hist_entry *he;
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ci	n = add_script_opt_2(browser, act, optstr, thread, sym, evsel, "");
27548c2ecf20Sopenharmony_ci
27558c2ecf20Sopenharmony_ci	he = hist_browser__selected_entry(browser);
27568c2ecf20Sopenharmony_ci	if (sort_order && strstr(sort_order, "time")) {
27578c2ecf20Sopenharmony_ci		char tstr[128];
27588c2ecf20Sopenharmony_ci
27598c2ecf20Sopenharmony_ci		optstr++;
27608c2ecf20Sopenharmony_ci		act++;
27618c2ecf20Sopenharmony_ci		j = sprintf(tstr, " in ");
27628c2ecf20Sopenharmony_ci		j += timestamp__scnprintf_usec(he->time, tstr + j,
27638c2ecf20Sopenharmony_ci					       sizeof tstr - j);
27648c2ecf20Sopenharmony_ci		j += sprintf(tstr + j, "-");
27658c2ecf20Sopenharmony_ci		timestamp__scnprintf_usec(he->time + symbol_conf.time_quantum,
27668c2ecf20Sopenharmony_ci				          tstr + j, sizeof tstr - j);
27678c2ecf20Sopenharmony_ci		n += add_script_opt_2(browser, act, optstr, thread, sym,
27688c2ecf20Sopenharmony_ci					  evsel, tstr);
27698c2ecf20Sopenharmony_ci		act->time = he->time;
27708c2ecf20Sopenharmony_ci	}
27718c2ecf20Sopenharmony_ci	return n;
27728c2ecf20Sopenharmony_ci}
27738c2ecf20Sopenharmony_ci
27748c2ecf20Sopenharmony_cistatic int
27758c2ecf20Sopenharmony_ciadd_res_sample_opt(struct hist_browser *browser __maybe_unused,
27768c2ecf20Sopenharmony_ci		   struct popup_action *act, char **optstr,
27778c2ecf20Sopenharmony_ci		   struct res_sample *res_sample,
27788c2ecf20Sopenharmony_ci		   struct evsel *evsel,
27798c2ecf20Sopenharmony_ci		   enum rstype type)
27808c2ecf20Sopenharmony_ci{
27818c2ecf20Sopenharmony_ci	if (!res_sample)
27828c2ecf20Sopenharmony_ci		return 0;
27838c2ecf20Sopenharmony_ci
27848c2ecf20Sopenharmony_ci	if (asprintf(optstr, "Show context for individual samples %s",
27858c2ecf20Sopenharmony_ci		type == A_ASM ? "with assembler" :
27868c2ecf20Sopenharmony_ci		type == A_SOURCE ? "with source" : "") < 0)
27878c2ecf20Sopenharmony_ci		return 0;
27888c2ecf20Sopenharmony_ci
27898c2ecf20Sopenharmony_ci	act->fn = do_res_sample_script;
27908c2ecf20Sopenharmony_ci	act->evsel = evsel;
27918c2ecf20Sopenharmony_ci	act->rstype = type;
27928c2ecf20Sopenharmony_ci	return 1;
27938c2ecf20Sopenharmony_ci}
27948c2ecf20Sopenharmony_ci
27958c2ecf20Sopenharmony_cistatic int
27968c2ecf20Sopenharmony_cido_switch_data(struct hist_browser *browser __maybe_unused,
27978c2ecf20Sopenharmony_ci	       struct popup_action *act __maybe_unused)
27988c2ecf20Sopenharmony_ci{
27998c2ecf20Sopenharmony_ci	if (switch_data_file()) {
28008c2ecf20Sopenharmony_ci		ui__warning("Won't switch the data files due to\n"
28018c2ecf20Sopenharmony_ci			    "no valid data file get selected!\n");
28028c2ecf20Sopenharmony_ci		return 0;
28038c2ecf20Sopenharmony_ci	}
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ci	return K_SWITCH_INPUT_DATA;
28068c2ecf20Sopenharmony_ci}
28078c2ecf20Sopenharmony_ci
28088c2ecf20Sopenharmony_cistatic int
28098c2ecf20Sopenharmony_ciadd_switch_opt(struct hist_browser *browser,
28108c2ecf20Sopenharmony_ci	       struct popup_action *act, char **optstr)
28118c2ecf20Sopenharmony_ci{
28128c2ecf20Sopenharmony_ci	if (!is_report_browser(browser->hbt))
28138c2ecf20Sopenharmony_ci		return 0;
28148c2ecf20Sopenharmony_ci
28158c2ecf20Sopenharmony_ci	if (asprintf(optstr, "Switch to another data file in PWD") < 0)
28168c2ecf20Sopenharmony_ci		return 0;
28178c2ecf20Sopenharmony_ci
28188c2ecf20Sopenharmony_ci	act->fn = do_switch_data;
28198c2ecf20Sopenharmony_ci	return 1;
28208c2ecf20Sopenharmony_ci}
28218c2ecf20Sopenharmony_ci
28228c2ecf20Sopenharmony_cistatic int
28238c2ecf20Sopenharmony_cido_exit_browser(struct hist_browser *browser __maybe_unused,
28248c2ecf20Sopenharmony_ci		struct popup_action *act __maybe_unused)
28258c2ecf20Sopenharmony_ci{
28268c2ecf20Sopenharmony_ci	return 0;
28278c2ecf20Sopenharmony_ci}
28288c2ecf20Sopenharmony_ci
28298c2ecf20Sopenharmony_cistatic int
28308c2ecf20Sopenharmony_ciadd_exit_opt(struct hist_browser *browser __maybe_unused,
28318c2ecf20Sopenharmony_ci	     struct popup_action *act, char **optstr)
28328c2ecf20Sopenharmony_ci{
28338c2ecf20Sopenharmony_ci	if (asprintf(optstr, "Exit") < 0)
28348c2ecf20Sopenharmony_ci		return 0;
28358c2ecf20Sopenharmony_ci
28368c2ecf20Sopenharmony_ci	act->fn = do_exit_browser;
28378c2ecf20Sopenharmony_ci	return 1;
28388c2ecf20Sopenharmony_ci}
28398c2ecf20Sopenharmony_ci
28408c2ecf20Sopenharmony_cistatic int
28418c2ecf20Sopenharmony_cido_zoom_socket(struct hist_browser *browser, struct popup_action *act)
28428c2ecf20Sopenharmony_ci{
28438c2ecf20Sopenharmony_ci	if (!hists__has(browser->hists, socket) || act->socket < 0)
28448c2ecf20Sopenharmony_ci		return 0;
28458c2ecf20Sopenharmony_ci
28468c2ecf20Sopenharmony_ci	if (browser->hists->socket_filter > -1) {
28478c2ecf20Sopenharmony_ci		pstack__remove(browser->pstack, &browser->hists->socket_filter);
28488c2ecf20Sopenharmony_ci		browser->hists->socket_filter = -1;
28498c2ecf20Sopenharmony_ci		perf_hpp__set_elide(HISTC_SOCKET, false);
28508c2ecf20Sopenharmony_ci	} else {
28518c2ecf20Sopenharmony_ci		browser->hists->socket_filter = act->socket;
28528c2ecf20Sopenharmony_ci		perf_hpp__set_elide(HISTC_SOCKET, true);
28538c2ecf20Sopenharmony_ci		pstack__push(browser->pstack, &browser->hists->socket_filter);
28548c2ecf20Sopenharmony_ci	}
28558c2ecf20Sopenharmony_ci
28568c2ecf20Sopenharmony_ci	hists__filter_by_socket(browser->hists);
28578c2ecf20Sopenharmony_ci	hist_browser__reset(browser);
28588c2ecf20Sopenharmony_ci	return 0;
28598c2ecf20Sopenharmony_ci}
28608c2ecf20Sopenharmony_ci
28618c2ecf20Sopenharmony_cistatic int
28628c2ecf20Sopenharmony_ciadd_socket_opt(struct hist_browser *browser, struct popup_action *act,
28638c2ecf20Sopenharmony_ci	       char **optstr, int socket_id)
28648c2ecf20Sopenharmony_ci{
28658c2ecf20Sopenharmony_ci	if (!hists__has(browser->hists, socket) || socket_id < 0)
28668c2ecf20Sopenharmony_ci		return 0;
28678c2ecf20Sopenharmony_ci
28688c2ecf20Sopenharmony_ci	if (asprintf(optstr, "Zoom %s Processor Socket %d",
28698c2ecf20Sopenharmony_ci		     (browser->hists->socket_filter > -1) ? "out of" : "into",
28708c2ecf20Sopenharmony_ci		     socket_id) < 0)
28718c2ecf20Sopenharmony_ci		return 0;
28728c2ecf20Sopenharmony_ci
28738c2ecf20Sopenharmony_ci	act->socket = socket_id;
28748c2ecf20Sopenharmony_ci	act->fn = do_zoom_socket;
28758c2ecf20Sopenharmony_ci	return 1;
28768c2ecf20Sopenharmony_ci}
28778c2ecf20Sopenharmony_ci
28788c2ecf20Sopenharmony_cistatic void hist_browser__update_nr_entries(struct hist_browser *hb)
28798c2ecf20Sopenharmony_ci{
28808c2ecf20Sopenharmony_ci	u64 nr_entries = 0;
28818c2ecf20Sopenharmony_ci	struct rb_node *nd = rb_first_cached(&hb->hists->entries);
28828c2ecf20Sopenharmony_ci
28838c2ecf20Sopenharmony_ci	if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
28848c2ecf20Sopenharmony_ci		hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
28858c2ecf20Sopenharmony_ci		return;
28868c2ecf20Sopenharmony_ci	}
28878c2ecf20Sopenharmony_ci
28888c2ecf20Sopenharmony_ci	while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
28898c2ecf20Sopenharmony_ci		nr_entries++;
28908c2ecf20Sopenharmony_ci		nd = rb_hierarchy_next(nd);
28918c2ecf20Sopenharmony_ci	}
28928c2ecf20Sopenharmony_ci
28938c2ecf20Sopenharmony_ci	hb->nr_non_filtered_entries = nr_entries;
28948c2ecf20Sopenharmony_ci	hb->nr_hierarchy_entries = nr_entries;
28958c2ecf20Sopenharmony_ci}
28968c2ecf20Sopenharmony_ci
28978c2ecf20Sopenharmony_cistatic void hist_browser__update_percent_limit(struct hist_browser *hb,
28988c2ecf20Sopenharmony_ci					       double percent)
28998c2ecf20Sopenharmony_ci{
29008c2ecf20Sopenharmony_ci	struct hist_entry *he;
29018c2ecf20Sopenharmony_ci	struct rb_node *nd = rb_first_cached(&hb->hists->entries);
29028c2ecf20Sopenharmony_ci	u64 total = hists__total_period(hb->hists);
29038c2ecf20Sopenharmony_ci	u64 min_callchain_hits = total * (percent / 100);
29048c2ecf20Sopenharmony_ci
29058c2ecf20Sopenharmony_ci	hb->min_pcnt = callchain_param.min_percent = percent;
29068c2ecf20Sopenharmony_ci
29078c2ecf20Sopenharmony_ci	while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
29088c2ecf20Sopenharmony_ci		he = rb_entry(nd, struct hist_entry, rb_node);
29098c2ecf20Sopenharmony_ci
29108c2ecf20Sopenharmony_ci		if (he->has_no_entry) {
29118c2ecf20Sopenharmony_ci			he->has_no_entry = false;
29128c2ecf20Sopenharmony_ci			he->nr_rows = 0;
29138c2ecf20Sopenharmony_ci		}
29148c2ecf20Sopenharmony_ci
29158c2ecf20Sopenharmony_ci		if (!he->leaf || !hist_entry__has_callchains(he) || !symbol_conf.use_callchain)
29168c2ecf20Sopenharmony_ci			goto next;
29178c2ecf20Sopenharmony_ci
29188c2ecf20Sopenharmony_ci		if (callchain_param.mode == CHAIN_GRAPH_REL) {
29198c2ecf20Sopenharmony_ci			total = he->stat.period;
29208c2ecf20Sopenharmony_ci
29218c2ecf20Sopenharmony_ci			if (symbol_conf.cumulate_callchain)
29228c2ecf20Sopenharmony_ci				total = he->stat_acc->period;
29238c2ecf20Sopenharmony_ci
29248c2ecf20Sopenharmony_ci			min_callchain_hits = total * (percent / 100);
29258c2ecf20Sopenharmony_ci		}
29268c2ecf20Sopenharmony_ci
29278c2ecf20Sopenharmony_ci		callchain_param.sort(&he->sorted_chain, he->callchain,
29288c2ecf20Sopenharmony_ci				     min_callchain_hits, &callchain_param);
29298c2ecf20Sopenharmony_ci
29308c2ecf20Sopenharmony_cinext:
29318c2ecf20Sopenharmony_ci		nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
29328c2ecf20Sopenharmony_ci
29338c2ecf20Sopenharmony_ci		/* force to re-evaluate folding state of callchains */
29348c2ecf20Sopenharmony_ci		he->init_have_children = false;
29358c2ecf20Sopenharmony_ci		hist_entry__set_folding(he, hb, false);
29368c2ecf20Sopenharmony_ci	}
29378c2ecf20Sopenharmony_ci}
29388c2ecf20Sopenharmony_ci
29398c2ecf20Sopenharmony_cistatic int perf_evsel__hists_browse(struct evsel *evsel, int nr_events,
29408c2ecf20Sopenharmony_ci				    const char *helpline,
29418c2ecf20Sopenharmony_ci				    bool left_exits,
29428c2ecf20Sopenharmony_ci				    struct hist_browser_timer *hbt,
29438c2ecf20Sopenharmony_ci				    float min_pcnt,
29448c2ecf20Sopenharmony_ci				    struct perf_env *env,
29458c2ecf20Sopenharmony_ci				    bool warn_lost_event,
29468c2ecf20Sopenharmony_ci				    struct annotation_options *annotation_opts)
29478c2ecf20Sopenharmony_ci{
29488c2ecf20Sopenharmony_ci	struct hists *hists = evsel__hists(evsel);
29498c2ecf20Sopenharmony_ci	struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env, annotation_opts);
29508c2ecf20Sopenharmony_ci	struct branch_info *bi = NULL;
29518c2ecf20Sopenharmony_ci#define MAX_OPTIONS  16
29528c2ecf20Sopenharmony_ci	char *options[MAX_OPTIONS];
29538c2ecf20Sopenharmony_ci	struct popup_action actions[MAX_OPTIONS];
29548c2ecf20Sopenharmony_ci	int nr_options = 0;
29558c2ecf20Sopenharmony_ci	int key = -1;
29568c2ecf20Sopenharmony_ci	char buf[128];
29578c2ecf20Sopenharmony_ci	int delay_secs = hbt ? hbt->refresh : 0;
29588c2ecf20Sopenharmony_ci
29598c2ecf20Sopenharmony_ci#define HIST_BROWSER_HELP_COMMON					\
29608c2ecf20Sopenharmony_ci	"h/?/F1        Show this window\n"				\
29618c2ecf20Sopenharmony_ci	"UP/DOWN/PGUP\n"						\
29628c2ecf20Sopenharmony_ci	"PGDN/SPACE    Navigate\n"					\
29638c2ecf20Sopenharmony_ci	"q/ESC/CTRL+C  Exit browser or go back to previous screen\n\n"	\
29648c2ecf20Sopenharmony_ci	"For multiple event sessions:\n\n"				\
29658c2ecf20Sopenharmony_ci	"TAB/UNTAB     Switch events\n\n"				\
29668c2ecf20Sopenharmony_ci	"For symbolic views (--sort has sym):\n\n"			\
29678c2ecf20Sopenharmony_ci	"ENTER         Zoom into DSO/Threads & Annotate current symbol\n" \
29688c2ecf20Sopenharmony_ci	"ESC           Zoom out\n"					\
29698c2ecf20Sopenharmony_ci	"+             Expand/Collapse one callchain level\n"		\
29708c2ecf20Sopenharmony_ci	"a             Annotate current symbol\n"			\
29718c2ecf20Sopenharmony_ci	"C             Collapse all callchains\n"			\
29728c2ecf20Sopenharmony_ci	"d             Zoom into current DSO\n"				\
29738c2ecf20Sopenharmony_ci	"e             Expand/Collapse main entry callchains\n"	\
29748c2ecf20Sopenharmony_ci	"E             Expand all callchains\n"				\
29758c2ecf20Sopenharmony_ci	"F             Toggle percentage of filtered entries\n"		\
29768c2ecf20Sopenharmony_ci	"H             Display column headers\n"			\
29778c2ecf20Sopenharmony_ci	"k             Zoom into the kernel map\n"			\
29788c2ecf20Sopenharmony_ci	"L             Change percent limit\n"				\
29798c2ecf20Sopenharmony_ci	"m             Display context menu\n"				\
29808c2ecf20Sopenharmony_ci	"S             Zoom into current Processor Socket\n"		\
29818c2ecf20Sopenharmony_ci
29828c2ecf20Sopenharmony_ci	/* help messages are sorted by lexical order of the hotkey */
29838c2ecf20Sopenharmony_ci	static const char report_help[] = HIST_BROWSER_HELP_COMMON
29848c2ecf20Sopenharmony_ci	"i             Show header information\n"
29858c2ecf20Sopenharmony_ci	"P             Print histograms to perf.hist.N\n"
29868c2ecf20Sopenharmony_ci	"r             Run available scripts\n"
29878c2ecf20Sopenharmony_ci	"s             Switch to another data file in PWD\n"
29888c2ecf20Sopenharmony_ci	"t             Zoom into current Thread\n"
29898c2ecf20Sopenharmony_ci	"V             Verbose (DSO names in callchains, etc)\n"
29908c2ecf20Sopenharmony_ci	"/             Filter symbol by name\n"
29918c2ecf20Sopenharmony_ci	"0-9           Sort by event n in group";
29928c2ecf20Sopenharmony_ci	static const char top_help[] = HIST_BROWSER_HELP_COMMON
29938c2ecf20Sopenharmony_ci	"P             Print histograms to perf.hist.N\n"
29948c2ecf20Sopenharmony_ci	"t             Zoom into current Thread\n"
29958c2ecf20Sopenharmony_ci	"V             Verbose (DSO names in callchains, etc)\n"
29968c2ecf20Sopenharmony_ci	"z             Toggle zeroing of samples\n"
29978c2ecf20Sopenharmony_ci	"f             Enable/Disable events\n"
29988c2ecf20Sopenharmony_ci	"/             Filter symbol by name";
29998c2ecf20Sopenharmony_ci
30008c2ecf20Sopenharmony_ci	if (browser == NULL)
30018c2ecf20Sopenharmony_ci		return -1;
30028c2ecf20Sopenharmony_ci
30038c2ecf20Sopenharmony_ci	/* reset abort key so that it can get Ctrl-C as a key */
30048c2ecf20Sopenharmony_ci	SLang_reset_tty();
30058c2ecf20Sopenharmony_ci	SLang_init_tty(0, 0, 0);
30068c2ecf20Sopenharmony_ci
30078c2ecf20Sopenharmony_ci	if (min_pcnt)
30088c2ecf20Sopenharmony_ci		browser->min_pcnt = min_pcnt;
30098c2ecf20Sopenharmony_ci	hist_browser__update_nr_entries(browser);
30108c2ecf20Sopenharmony_ci
30118c2ecf20Sopenharmony_ci	browser->pstack = pstack__new(3);
30128c2ecf20Sopenharmony_ci	if (browser->pstack == NULL)
30138c2ecf20Sopenharmony_ci		goto out;
30148c2ecf20Sopenharmony_ci
30158c2ecf20Sopenharmony_ci	ui_helpline__push(helpline);
30168c2ecf20Sopenharmony_ci
30178c2ecf20Sopenharmony_ci	memset(options, 0, sizeof(options));
30188c2ecf20Sopenharmony_ci	memset(actions, 0, sizeof(actions));
30198c2ecf20Sopenharmony_ci
30208c2ecf20Sopenharmony_ci	if (symbol_conf.col_width_list_str)
30218c2ecf20Sopenharmony_ci		perf_hpp__set_user_width(symbol_conf.col_width_list_str);
30228c2ecf20Sopenharmony_ci
30238c2ecf20Sopenharmony_ci	if (!is_report_browser(hbt))
30248c2ecf20Sopenharmony_ci		browser->b.no_samples_msg = "Collecting samples...";
30258c2ecf20Sopenharmony_ci
30268c2ecf20Sopenharmony_ci	while (1) {
30278c2ecf20Sopenharmony_ci		struct thread *thread = NULL;
30288c2ecf20Sopenharmony_ci		struct map *map = NULL;
30298c2ecf20Sopenharmony_ci		int choice;
30308c2ecf20Sopenharmony_ci		int socked_id = -1;
30318c2ecf20Sopenharmony_ci
30328c2ecf20Sopenharmony_ci		key = 0; // reset key
30338c2ecf20Sopenharmony_cido_hotkey:		 // key came straight from options ui__popup_menu()
30348c2ecf20Sopenharmony_ci		choice = nr_options = 0;
30358c2ecf20Sopenharmony_ci		key = hist_browser__run(browser, helpline, warn_lost_event, key);
30368c2ecf20Sopenharmony_ci
30378c2ecf20Sopenharmony_ci		if (browser->he_selection != NULL) {
30388c2ecf20Sopenharmony_ci			thread = hist_browser__selected_thread(browser);
30398c2ecf20Sopenharmony_ci			map = browser->selection->map;
30408c2ecf20Sopenharmony_ci			socked_id = browser->he_selection->socket;
30418c2ecf20Sopenharmony_ci		}
30428c2ecf20Sopenharmony_ci		switch (key) {
30438c2ecf20Sopenharmony_ci		case K_TAB:
30448c2ecf20Sopenharmony_ci		case K_UNTAB:
30458c2ecf20Sopenharmony_ci			if (nr_events == 1)
30468c2ecf20Sopenharmony_ci				continue;
30478c2ecf20Sopenharmony_ci			/*
30488c2ecf20Sopenharmony_ci			 * Exit the browser, let hists__browser_tree
30498c2ecf20Sopenharmony_ci			 * go to the next or previous
30508c2ecf20Sopenharmony_ci			 */
30518c2ecf20Sopenharmony_ci			goto out_free_stack;
30528c2ecf20Sopenharmony_ci		case '0' ... '9':
30538c2ecf20Sopenharmony_ci			if (!symbol_conf.event_group ||
30548c2ecf20Sopenharmony_ci			    evsel->core.nr_members < 2) {
30558c2ecf20Sopenharmony_ci				snprintf(buf, sizeof(buf),
30568c2ecf20Sopenharmony_ci					 "Sort by index only available with group events!");
30578c2ecf20Sopenharmony_ci				helpline = buf;
30588c2ecf20Sopenharmony_ci				continue;
30598c2ecf20Sopenharmony_ci			}
30608c2ecf20Sopenharmony_ci
30618c2ecf20Sopenharmony_ci			if (key - '0' == symbol_conf.group_sort_idx)
30628c2ecf20Sopenharmony_ci				continue;
30638c2ecf20Sopenharmony_ci
30648c2ecf20Sopenharmony_ci			symbol_conf.group_sort_idx = key - '0';
30658c2ecf20Sopenharmony_ci
30668c2ecf20Sopenharmony_ci			if (symbol_conf.group_sort_idx >= evsel->core.nr_members) {
30678c2ecf20Sopenharmony_ci				snprintf(buf, sizeof(buf),
30688c2ecf20Sopenharmony_ci					 "Max event group index to sort is %d (index from 0 to %d)",
30698c2ecf20Sopenharmony_ci					 evsel->core.nr_members - 1,
30708c2ecf20Sopenharmony_ci					 evsel->core.nr_members - 1);
30718c2ecf20Sopenharmony_ci				helpline = buf;
30728c2ecf20Sopenharmony_ci				continue;
30738c2ecf20Sopenharmony_ci			}
30748c2ecf20Sopenharmony_ci
30758c2ecf20Sopenharmony_ci			key = K_RELOAD;
30768c2ecf20Sopenharmony_ci			goto out_free_stack;
30778c2ecf20Sopenharmony_ci		case 'a':
30788c2ecf20Sopenharmony_ci			if (!hists__has(hists, sym)) {
30798c2ecf20Sopenharmony_ci				ui_browser__warning(&browser->b, delay_secs * 2,
30808c2ecf20Sopenharmony_ci			"Annotation is only available for symbolic views, "
30818c2ecf20Sopenharmony_ci			"include \"sym*\" in --sort to use it.");
30828c2ecf20Sopenharmony_ci				continue;
30838c2ecf20Sopenharmony_ci			}
30848c2ecf20Sopenharmony_ci
30858c2ecf20Sopenharmony_ci			if (!browser->selection ||
30868c2ecf20Sopenharmony_ci			    !browser->selection->map ||
30878c2ecf20Sopenharmony_ci			    !browser->selection->map->dso ||
30888c2ecf20Sopenharmony_ci			    browser->selection->map->dso->annotate_warned) {
30898c2ecf20Sopenharmony_ci				continue;
30908c2ecf20Sopenharmony_ci			}
30918c2ecf20Sopenharmony_ci
30928c2ecf20Sopenharmony_ci			if (!browser->selection->sym) {
30938c2ecf20Sopenharmony_ci				if (!browser->he_selection)
30948c2ecf20Sopenharmony_ci					continue;
30958c2ecf20Sopenharmony_ci
30968c2ecf20Sopenharmony_ci				if (sort__mode == SORT_MODE__BRANCH) {
30978c2ecf20Sopenharmony_ci					bi = browser->he_selection->branch_info;
30988c2ecf20Sopenharmony_ci					if (!bi || !bi->to.ms.map)
30998c2ecf20Sopenharmony_ci						continue;
31008c2ecf20Sopenharmony_ci
31018c2ecf20Sopenharmony_ci					actions->ms.sym = symbol__new_unresolved(bi->to.al_addr, bi->to.ms.map);
31028c2ecf20Sopenharmony_ci					actions->ms.map = bi->to.ms.map;
31038c2ecf20Sopenharmony_ci				} else {
31048c2ecf20Sopenharmony_ci					actions->ms.sym = symbol__new_unresolved(browser->he_selection->ip,
31058c2ecf20Sopenharmony_ci										 browser->selection->map);
31068c2ecf20Sopenharmony_ci					actions->ms.map = browser->selection->map;
31078c2ecf20Sopenharmony_ci				}
31088c2ecf20Sopenharmony_ci
31098c2ecf20Sopenharmony_ci				if (!actions->ms.sym)
31108c2ecf20Sopenharmony_ci					continue;
31118c2ecf20Sopenharmony_ci			} else {
31128c2ecf20Sopenharmony_ci				if (symbol__annotation(browser->selection->sym)->src == NULL) {
31138c2ecf20Sopenharmony_ci					ui_browser__warning(&browser->b, delay_secs * 2,
31148c2ecf20Sopenharmony_ci						"No samples for the \"%s\" symbol.\n\n"
31158c2ecf20Sopenharmony_ci						"Probably appeared just in a callchain",
31168c2ecf20Sopenharmony_ci						browser->selection->sym->name);
31178c2ecf20Sopenharmony_ci					continue;
31188c2ecf20Sopenharmony_ci				}
31198c2ecf20Sopenharmony_ci
31208c2ecf20Sopenharmony_ci				actions->ms.map = browser->selection->map;
31218c2ecf20Sopenharmony_ci				actions->ms.sym = browser->selection->sym;
31228c2ecf20Sopenharmony_ci			}
31238c2ecf20Sopenharmony_ci
31248c2ecf20Sopenharmony_ci			do_annotate(browser, actions);
31258c2ecf20Sopenharmony_ci			continue;
31268c2ecf20Sopenharmony_ci		case 'P':
31278c2ecf20Sopenharmony_ci			hist_browser__dump(browser);
31288c2ecf20Sopenharmony_ci			continue;
31298c2ecf20Sopenharmony_ci		case 'd':
31308c2ecf20Sopenharmony_ci			actions->ms.map = map;
31318c2ecf20Sopenharmony_ci			do_zoom_dso(browser, actions);
31328c2ecf20Sopenharmony_ci			continue;
31338c2ecf20Sopenharmony_ci		case 'k':
31348c2ecf20Sopenharmony_ci			if (browser->selection != NULL)
31358c2ecf20Sopenharmony_ci				hists_browser__zoom_map(browser, browser->selection->maps->machine->vmlinux_map);
31368c2ecf20Sopenharmony_ci			continue;
31378c2ecf20Sopenharmony_ci		case 'V':
31388c2ecf20Sopenharmony_ci			verbose = (verbose + 1) % 4;
31398c2ecf20Sopenharmony_ci			browser->show_dso = verbose > 0;
31408c2ecf20Sopenharmony_ci			ui_helpline__fpush("Verbosity level set to %d\n",
31418c2ecf20Sopenharmony_ci					   verbose);
31428c2ecf20Sopenharmony_ci			continue;
31438c2ecf20Sopenharmony_ci		case 't':
31448c2ecf20Sopenharmony_ci			actions->thread = thread;
31458c2ecf20Sopenharmony_ci			do_zoom_thread(browser, actions);
31468c2ecf20Sopenharmony_ci			continue;
31478c2ecf20Sopenharmony_ci		case 'S':
31488c2ecf20Sopenharmony_ci			actions->socket = socked_id;
31498c2ecf20Sopenharmony_ci			do_zoom_socket(browser, actions);
31508c2ecf20Sopenharmony_ci			continue;
31518c2ecf20Sopenharmony_ci		case '/':
31528c2ecf20Sopenharmony_ci			if (ui_browser__input_window("Symbol to show",
31538c2ecf20Sopenharmony_ci					"Please enter the name of symbol you want to see.\n"
31548c2ecf20Sopenharmony_ci					"To remove the filter later, press / + ENTER.",
31558c2ecf20Sopenharmony_ci					buf, "ENTER: OK, ESC: Cancel",
31568c2ecf20Sopenharmony_ci					delay_secs * 2) == K_ENTER) {
31578c2ecf20Sopenharmony_ci				hists->symbol_filter_str = *buf ? buf : NULL;
31588c2ecf20Sopenharmony_ci				hists__filter_by_symbol(hists);
31598c2ecf20Sopenharmony_ci				hist_browser__reset(browser);
31608c2ecf20Sopenharmony_ci			}
31618c2ecf20Sopenharmony_ci			continue;
31628c2ecf20Sopenharmony_ci		case 'r':
31638c2ecf20Sopenharmony_ci			if (is_report_browser(hbt)) {
31648c2ecf20Sopenharmony_ci				actions->thread = NULL;
31658c2ecf20Sopenharmony_ci				actions->ms.sym = NULL;
31668c2ecf20Sopenharmony_ci				do_run_script(browser, actions);
31678c2ecf20Sopenharmony_ci			}
31688c2ecf20Sopenharmony_ci			continue;
31698c2ecf20Sopenharmony_ci		case 's':
31708c2ecf20Sopenharmony_ci			if (is_report_browser(hbt)) {
31718c2ecf20Sopenharmony_ci				key = do_switch_data(browser, actions);
31728c2ecf20Sopenharmony_ci				if (key == K_SWITCH_INPUT_DATA)
31738c2ecf20Sopenharmony_ci					goto out_free_stack;
31748c2ecf20Sopenharmony_ci			}
31758c2ecf20Sopenharmony_ci			continue;
31768c2ecf20Sopenharmony_ci		case 'i':
31778c2ecf20Sopenharmony_ci			/* env->arch is NULL for live-mode (i.e. perf top) */
31788c2ecf20Sopenharmony_ci			if (env->arch)
31798c2ecf20Sopenharmony_ci				tui__header_window(env);
31808c2ecf20Sopenharmony_ci			continue;
31818c2ecf20Sopenharmony_ci		case 'F':
31828c2ecf20Sopenharmony_ci			symbol_conf.filter_relative ^= 1;
31838c2ecf20Sopenharmony_ci			continue;
31848c2ecf20Sopenharmony_ci		case 'z':
31858c2ecf20Sopenharmony_ci			if (!is_report_browser(hbt)) {
31868c2ecf20Sopenharmony_ci				struct perf_top *top = hbt->arg;
31878c2ecf20Sopenharmony_ci
31888c2ecf20Sopenharmony_ci				top->zero = !top->zero;
31898c2ecf20Sopenharmony_ci			}
31908c2ecf20Sopenharmony_ci			continue;
31918c2ecf20Sopenharmony_ci		case 'L':
31928c2ecf20Sopenharmony_ci			if (ui_browser__input_window("Percent Limit",
31938c2ecf20Sopenharmony_ci					"Please enter the value you want to hide entries under that percent.",
31948c2ecf20Sopenharmony_ci					buf, "ENTER: OK, ESC: Cancel",
31958c2ecf20Sopenharmony_ci					delay_secs * 2) == K_ENTER) {
31968c2ecf20Sopenharmony_ci				char *end;
31978c2ecf20Sopenharmony_ci				double new_percent = strtod(buf, &end);
31988c2ecf20Sopenharmony_ci
31998c2ecf20Sopenharmony_ci				if (new_percent < 0 || new_percent > 100) {
32008c2ecf20Sopenharmony_ci					ui_browser__warning(&browser->b, delay_secs * 2,
32018c2ecf20Sopenharmony_ci						"Invalid percent: %.2f", new_percent);
32028c2ecf20Sopenharmony_ci					continue;
32038c2ecf20Sopenharmony_ci				}
32048c2ecf20Sopenharmony_ci
32058c2ecf20Sopenharmony_ci				hist_browser__update_percent_limit(browser, new_percent);
32068c2ecf20Sopenharmony_ci				hist_browser__reset(browser);
32078c2ecf20Sopenharmony_ci			}
32088c2ecf20Sopenharmony_ci			continue;
32098c2ecf20Sopenharmony_ci		case K_F1:
32108c2ecf20Sopenharmony_ci		case 'h':
32118c2ecf20Sopenharmony_ci		case '?':
32128c2ecf20Sopenharmony_ci			ui_browser__help_window(&browser->b,
32138c2ecf20Sopenharmony_ci				is_report_browser(hbt) ? report_help : top_help);
32148c2ecf20Sopenharmony_ci			continue;
32158c2ecf20Sopenharmony_ci		case K_ENTER:
32168c2ecf20Sopenharmony_ci		case K_RIGHT:
32178c2ecf20Sopenharmony_ci		case 'm':
32188c2ecf20Sopenharmony_ci			/* menu */
32198c2ecf20Sopenharmony_ci			break;
32208c2ecf20Sopenharmony_ci		case K_ESC:
32218c2ecf20Sopenharmony_ci		case K_LEFT: {
32228c2ecf20Sopenharmony_ci			const void *top;
32238c2ecf20Sopenharmony_ci
32248c2ecf20Sopenharmony_ci			if (pstack__empty(browser->pstack)) {
32258c2ecf20Sopenharmony_ci				/*
32268c2ecf20Sopenharmony_ci				 * Go back to the perf_evsel_menu__run or other user
32278c2ecf20Sopenharmony_ci				 */
32288c2ecf20Sopenharmony_ci				if (left_exits)
32298c2ecf20Sopenharmony_ci					goto out_free_stack;
32308c2ecf20Sopenharmony_ci
32318c2ecf20Sopenharmony_ci				if (key == K_ESC &&
32328c2ecf20Sopenharmony_ci				    ui_browser__dialog_yesno(&browser->b,
32338c2ecf20Sopenharmony_ci							     "Do you really want to exit?"))
32348c2ecf20Sopenharmony_ci					goto out_free_stack;
32358c2ecf20Sopenharmony_ci
32368c2ecf20Sopenharmony_ci				continue;
32378c2ecf20Sopenharmony_ci			}
32388c2ecf20Sopenharmony_ci			actions->ms.map = map;
32398c2ecf20Sopenharmony_ci			top = pstack__peek(browser->pstack);
32408c2ecf20Sopenharmony_ci			if (top == &browser->hists->dso_filter) {
32418c2ecf20Sopenharmony_ci				/*
32428c2ecf20Sopenharmony_ci				 * No need to set actions->dso here since
32438c2ecf20Sopenharmony_ci				 * it's just to remove the current filter.
32448c2ecf20Sopenharmony_ci				 * Ditto for thread below.
32458c2ecf20Sopenharmony_ci				 */
32468c2ecf20Sopenharmony_ci				do_zoom_dso(browser, actions);
32478c2ecf20Sopenharmony_ci			} else if (top == &browser->hists->thread_filter) {
32488c2ecf20Sopenharmony_ci				do_zoom_thread(browser, actions);
32498c2ecf20Sopenharmony_ci			} else if (top == &browser->hists->socket_filter) {
32508c2ecf20Sopenharmony_ci				do_zoom_socket(browser, actions);
32518c2ecf20Sopenharmony_ci			}
32528c2ecf20Sopenharmony_ci			continue;
32538c2ecf20Sopenharmony_ci		}
32548c2ecf20Sopenharmony_ci		case 'q':
32558c2ecf20Sopenharmony_ci		case CTRL('c'):
32568c2ecf20Sopenharmony_ci			goto out_free_stack;
32578c2ecf20Sopenharmony_ci		case 'f':
32588c2ecf20Sopenharmony_ci			if (!is_report_browser(hbt)) {
32598c2ecf20Sopenharmony_ci				struct perf_top *top = hbt->arg;
32608c2ecf20Sopenharmony_ci
32618c2ecf20Sopenharmony_ci				perf_evlist__toggle_enable(top->evlist);
32628c2ecf20Sopenharmony_ci				/*
32638c2ecf20Sopenharmony_ci				 * No need to refresh, resort/decay histogram
32648c2ecf20Sopenharmony_ci				 * entries if we are not collecting samples:
32658c2ecf20Sopenharmony_ci				 */
32668c2ecf20Sopenharmony_ci				if (top->evlist->enabled) {
32678c2ecf20Sopenharmony_ci					helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
32688c2ecf20Sopenharmony_ci					hbt->refresh = delay_secs;
32698c2ecf20Sopenharmony_ci				} else {
32708c2ecf20Sopenharmony_ci					helpline = "Press 'f' again to re-enable the events";
32718c2ecf20Sopenharmony_ci					hbt->refresh = 0;
32728c2ecf20Sopenharmony_ci				}
32738c2ecf20Sopenharmony_ci				continue;
32748c2ecf20Sopenharmony_ci			}
32758c2ecf20Sopenharmony_ci			/* Fall thru */
32768c2ecf20Sopenharmony_ci		default:
32778c2ecf20Sopenharmony_ci			helpline = "Press '?' for help on key bindings";
32788c2ecf20Sopenharmony_ci			continue;
32798c2ecf20Sopenharmony_ci		}
32808c2ecf20Sopenharmony_ci
32818c2ecf20Sopenharmony_ci		if (!hists__has(hists, sym) || browser->selection == NULL)
32828c2ecf20Sopenharmony_ci			goto skip_annotation;
32838c2ecf20Sopenharmony_ci
32848c2ecf20Sopenharmony_ci		if (sort__mode == SORT_MODE__BRANCH) {
32858c2ecf20Sopenharmony_ci
32868c2ecf20Sopenharmony_ci			if (browser->he_selection)
32878c2ecf20Sopenharmony_ci				bi = browser->he_selection->branch_info;
32888c2ecf20Sopenharmony_ci
32898c2ecf20Sopenharmony_ci			if (bi == NULL)
32908c2ecf20Sopenharmony_ci				goto skip_annotation;
32918c2ecf20Sopenharmony_ci
32928c2ecf20Sopenharmony_ci			nr_options += add_annotate_opt(browser,
32938c2ecf20Sopenharmony_ci						       &actions[nr_options],
32948c2ecf20Sopenharmony_ci						       &options[nr_options],
32958c2ecf20Sopenharmony_ci						       &bi->from.ms,
32968c2ecf20Sopenharmony_ci						       bi->from.al_addr);
32978c2ecf20Sopenharmony_ci			if (bi->to.ms.sym != bi->from.ms.sym)
32988c2ecf20Sopenharmony_ci				nr_options += add_annotate_opt(browser,
32998c2ecf20Sopenharmony_ci							&actions[nr_options],
33008c2ecf20Sopenharmony_ci							&options[nr_options],
33018c2ecf20Sopenharmony_ci							&bi->to.ms,
33028c2ecf20Sopenharmony_ci							bi->to.al_addr);
33038c2ecf20Sopenharmony_ci		} else {
33048c2ecf20Sopenharmony_ci			nr_options += add_annotate_opt(browser,
33058c2ecf20Sopenharmony_ci						       &actions[nr_options],
33068c2ecf20Sopenharmony_ci						       &options[nr_options],
33078c2ecf20Sopenharmony_ci						       browser->selection,
33088c2ecf20Sopenharmony_ci						       browser->he_selection->ip);
33098c2ecf20Sopenharmony_ci		}
33108c2ecf20Sopenharmony_ciskip_annotation:
33118c2ecf20Sopenharmony_ci		nr_options += add_thread_opt(browser, &actions[nr_options],
33128c2ecf20Sopenharmony_ci					     &options[nr_options], thread);
33138c2ecf20Sopenharmony_ci		nr_options += add_dso_opt(browser, &actions[nr_options],
33148c2ecf20Sopenharmony_ci					  &options[nr_options], map);
33158c2ecf20Sopenharmony_ci		nr_options += add_callchain_toggle_opt(browser, &actions[nr_options], &options[nr_options]);
33168c2ecf20Sopenharmony_ci		nr_options += add_map_opt(browser, &actions[nr_options],
33178c2ecf20Sopenharmony_ci					  &options[nr_options],
33188c2ecf20Sopenharmony_ci					  browser->selection ?
33198c2ecf20Sopenharmony_ci						browser->selection->map : NULL);
33208c2ecf20Sopenharmony_ci		nr_options += add_socket_opt(browser, &actions[nr_options],
33218c2ecf20Sopenharmony_ci					     &options[nr_options],
33228c2ecf20Sopenharmony_ci					     socked_id);
33238c2ecf20Sopenharmony_ci		/* perf script support */
33248c2ecf20Sopenharmony_ci		if (!is_report_browser(hbt))
33258c2ecf20Sopenharmony_ci			goto skip_scripting;
33268c2ecf20Sopenharmony_ci
33278c2ecf20Sopenharmony_ci		if (browser->he_selection) {
33288c2ecf20Sopenharmony_ci			if (hists__has(hists, thread) && thread) {
33298c2ecf20Sopenharmony_ci				nr_options += add_script_opt(browser,
33308c2ecf20Sopenharmony_ci							     &actions[nr_options],
33318c2ecf20Sopenharmony_ci							     &options[nr_options],
33328c2ecf20Sopenharmony_ci							     thread, NULL, evsel);
33338c2ecf20Sopenharmony_ci			}
33348c2ecf20Sopenharmony_ci			/*
33358c2ecf20Sopenharmony_ci			 * Note that browser->selection != NULL
33368c2ecf20Sopenharmony_ci			 * when browser->he_selection is not NULL,
33378c2ecf20Sopenharmony_ci			 * so we don't need to check browser->selection
33388c2ecf20Sopenharmony_ci			 * before fetching browser->selection->sym like what
33398c2ecf20Sopenharmony_ci			 * we do before fetching browser->selection->map.
33408c2ecf20Sopenharmony_ci			 *
33418c2ecf20Sopenharmony_ci			 * See hist_browser__show_entry.
33428c2ecf20Sopenharmony_ci			 */
33438c2ecf20Sopenharmony_ci			if (hists__has(hists, sym) && browser->selection->sym) {
33448c2ecf20Sopenharmony_ci				nr_options += add_script_opt(browser,
33458c2ecf20Sopenharmony_ci							     &actions[nr_options],
33468c2ecf20Sopenharmony_ci							     &options[nr_options],
33478c2ecf20Sopenharmony_ci							     NULL, browser->selection->sym,
33488c2ecf20Sopenharmony_ci							     evsel);
33498c2ecf20Sopenharmony_ci			}
33508c2ecf20Sopenharmony_ci		}
33518c2ecf20Sopenharmony_ci		nr_options += add_script_opt(browser, &actions[nr_options],
33528c2ecf20Sopenharmony_ci					     &options[nr_options], NULL, NULL, evsel);
33538c2ecf20Sopenharmony_ci		nr_options += add_res_sample_opt(browser, &actions[nr_options],
33548c2ecf20Sopenharmony_ci						 &options[nr_options],
33558c2ecf20Sopenharmony_ci						 hist_browser__selected_res_sample(browser),
33568c2ecf20Sopenharmony_ci						 evsel, A_NORMAL);
33578c2ecf20Sopenharmony_ci		nr_options += add_res_sample_opt(browser, &actions[nr_options],
33588c2ecf20Sopenharmony_ci						 &options[nr_options],
33598c2ecf20Sopenharmony_ci						 hist_browser__selected_res_sample(browser),
33608c2ecf20Sopenharmony_ci						 evsel, A_ASM);
33618c2ecf20Sopenharmony_ci		nr_options += add_res_sample_opt(browser, &actions[nr_options],
33628c2ecf20Sopenharmony_ci						 &options[nr_options],
33638c2ecf20Sopenharmony_ci						 hist_browser__selected_res_sample(browser),
33648c2ecf20Sopenharmony_ci						 evsel, A_SOURCE);
33658c2ecf20Sopenharmony_ci		nr_options += add_switch_opt(browser, &actions[nr_options],
33668c2ecf20Sopenharmony_ci					     &options[nr_options]);
33678c2ecf20Sopenharmony_ciskip_scripting:
33688c2ecf20Sopenharmony_ci		nr_options += add_exit_opt(browser, &actions[nr_options],
33698c2ecf20Sopenharmony_ci					   &options[nr_options]);
33708c2ecf20Sopenharmony_ci
33718c2ecf20Sopenharmony_ci		do {
33728c2ecf20Sopenharmony_ci			struct popup_action *act;
33738c2ecf20Sopenharmony_ci
33748c2ecf20Sopenharmony_ci			choice = ui__popup_menu(nr_options, options, &key);
33758c2ecf20Sopenharmony_ci			if (choice == -1)
33768c2ecf20Sopenharmony_ci				break;
33778c2ecf20Sopenharmony_ci
33788c2ecf20Sopenharmony_ci			if (choice == nr_options)
33798c2ecf20Sopenharmony_ci				goto do_hotkey;
33808c2ecf20Sopenharmony_ci
33818c2ecf20Sopenharmony_ci			act = &actions[choice];
33828c2ecf20Sopenharmony_ci			key = act->fn(browser, act);
33838c2ecf20Sopenharmony_ci		} while (key == 1);
33848c2ecf20Sopenharmony_ci
33858c2ecf20Sopenharmony_ci		if (key == K_SWITCH_INPUT_DATA)
33868c2ecf20Sopenharmony_ci			break;
33878c2ecf20Sopenharmony_ci	}
33888c2ecf20Sopenharmony_ciout_free_stack:
33898c2ecf20Sopenharmony_ci	pstack__delete(browser->pstack);
33908c2ecf20Sopenharmony_ciout:
33918c2ecf20Sopenharmony_ci	hist_browser__delete(browser);
33928c2ecf20Sopenharmony_ci	free_popup_options(options, MAX_OPTIONS);
33938c2ecf20Sopenharmony_ci	return key;
33948c2ecf20Sopenharmony_ci}
33958c2ecf20Sopenharmony_ci
33968c2ecf20Sopenharmony_cistruct evsel_menu {
33978c2ecf20Sopenharmony_ci	struct ui_browser b;
33988c2ecf20Sopenharmony_ci	struct evsel *selection;
33998c2ecf20Sopenharmony_ci	struct annotation_options *annotation_opts;
34008c2ecf20Sopenharmony_ci	bool lost_events, lost_events_warned;
34018c2ecf20Sopenharmony_ci	float min_pcnt;
34028c2ecf20Sopenharmony_ci	struct perf_env *env;
34038c2ecf20Sopenharmony_ci};
34048c2ecf20Sopenharmony_ci
34058c2ecf20Sopenharmony_cistatic void perf_evsel_menu__write(struct ui_browser *browser,
34068c2ecf20Sopenharmony_ci				   void *entry, int row)
34078c2ecf20Sopenharmony_ci{
34088c2ecf20Sopenharmony_ci	struct evsel_menu *menu = container_of(browser,
34098c2ecf20Sopenharmony_ci						    struct evsel_menu, b);
34108c2ecf20Sopenharmony_ci	struct evsel *evsel = list_entry(entry, struct evsel, core.node);
34118c2ecf20Sopenharmony_ci	struct hists *hists = evsel__hists(evsel);
34128c2ecf20Sopenharmony_ci	bool current_entry = ui_browser__is_current_entry(browser, row);
34138c2ecf20Sopenharmony_ci	unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
34148c2ecf20Sopenharmony_ci	const char *ev_name = evsel__name(evsel);
34158c2ecf20Sopenharmony_ci	char bf[256], unit;
34168c2ecf20Sopenharmony_ci	const char *warn = " ";
34178c2ecf20Sopenharmony_ci	size_t printed;
34188c2ecf20Sopenharmony_ci
34198c2ecf20Sopenharmony_ci	ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
34208c2ecf20Sopenharmony_ci						       HE_COLORSET_NORMAL);
34218c2ecf20Sopenharmony_ci
34228c2ecf20Sopenharmony_ci	if (evsel__is_group_event(evsel)) {
34238c2ecf20Sopenharmony_ci		struct evsel *pos;
34248c2ecf20Sopenharmony_ci
34258c2ecf20Sopenharmony_ci		ev_name = evsel__group_name(evsel);
34268c2ecf20Sopenharmony_ci
34278c2ecf20Sopenharmony_ci		for_each_group_member(pos, evsel) {
34288c2ecf20Sopenharmony_ci			struct hists *pos_hists = evsel__hists(pos);
34298c2ecf20Sopenharmony_ci			nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
34308c2ecf20Sopenharmony_ci		}
34318c2ecf20Sopenharmony_ci	}
34328c2ecf20Sopenharmony_ci
34338c2ecf20Sopenharmony_ci	nr_events = convert_unit(nr_events, &unit);
34348c2ecf20Sopenharmony_ci	printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
34358c2ecf20Sopenharmony_ci			   unit, unit == ' ' ? "" : " ", ev_name);
34368c2ecf20Sopenharmony_ci	ui_browser__printf(browser, "%s", bf);
34378c2ecf20Sopenharmony_ci
34388c2ecf20Sopenharmony_ci	nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
34398c2ecf20Sopenharmony_ci	if (nr_events != 0) {
34408c2ecf20Sopenharmony_ci		menu->lost_events = true;
34418c2ecf20Sopenharmony_ci		if (!current_entry)
34428c2ecf20Sopenharmony_ci			ui_browser__set_color(browser, HE_COLORSET_TOP);
34438c2ecf20Sopenharmony_ci		nr_events = convert_unit(nr_events, &unit);
34448c2ecf20Sopenharmony_ci		printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
34458c2ecf20Sopenharmony_ci				     nr_events, unit, unit == ' ' ? "" : " ");
34468c2ecf20Sopenharmony_ci		warn = bf;
34478c2ecf20Sopenharmony_ci	}
34488c2ecf20Sopenharmony_ci
34498c2ecf20Sopenharmony_ci	ui_browser__write_nstring(browser, warn, browser->width - printed);
34508c2ecf20Sopenharmony_ci
34518c2ecf20Sopenharmony_ci	if (current_entry)
34528c2ecf20Sopenharmony_ci		menu->selection = evsel;
34538c2ecf20Sopenharmony_ci}
34548c2ecf20Sopenharmony_ci
34558c2ecf20Sopenharmony_cistatic int perf_evsel_menu__run(struct evsel_menu *menu,
34568c2ecf20Sopenharmony_ci				int nr_events, const char *help,
34578c2ecf20Sopenharmony_ci				struct hist_browser_timer *hbt,
34588c2ecf20Sopenharmony_ci				bool warn_lost_event)
34598c2ecf20Sopenharmony_ci{
34608c2ecf20Sopenharmony_ci	struct evlist *evlist = menu->b.priv;
34618c2ecf20Sopenharmony_ci	struct evsel *pos;
34628c2ecf20Sopenharmony_ci	const char *title = "Available samples";
34638c2ecf20Sopenharmony_ci	int delay_secs = hbt ? hbt->refresh : 0;
34648c2ecf20Sopenharmony_ci	int key;
34658c2ecf20Sopenharmony_ci
34668c2ecf20Sopenharmony_ci	if (ui_browser__show(&menu->b, title,
34678c2ecf20Sopenharmony_ci			     "ESC: exit, ENTER|->: Browse histograms") < 0)
34688c2ecf20Sopenharmony_ci		return -1;
34698c2ecf20Sopenharmony_ci
34708c2ecf20Sopenharmony_ci	while (1) {
34718c2ecf20Sopenharmony_ci		key = ui_browser__run(&menu->b, delay_secs);
34728c2ecf20Sopenharmony_ci
34738c2ecf20Sopenharmony_ci		switch (key) {
34748c2ecf20Sopenharmony_ci		case K_TIMER:
34758c2ecf20Sopenharmony_ci			if (hbt)
34768c2ecf20Sopenharmony_ci				hbt->timer(hbt->arg);
34778c2ecf20Sopenharmony_ci
34788c2ecf20Sopenharmony_ci			if (!menu->lost_events_warned &&
34798c2ecf20Sopenharmony_ci			    menu->lost_events &&
34808c2ecf20Sopenharmony_ci			    warn_lost_event) {
34818c2ecf20Sopenharmony_ci				ui_browser__warn_lost_events(&menu->b);
34828c2ecf20Sopenharmony_ci				menu->lost_events_warned = true;
34838c2ecf20Sopenharmony_ci			}
34848c2ecf20Sopenharmony_ci			continue;
34858c2ecf20Sopenharmony_ci		case K_RIGHT:
34868c2ecf20Sopenharmony_ci		case K_ENTER:
34878c2ecf20Sopenharmony_ci			if (!menu->selection)
34888c2ecf20Sopenharmony_ci				continue;
34898c2ecf20Sopenharmony_ci			pos = menu->selection;
34908c2ecf20Sopenharmony_cibrowse_hists:
34918c2ecf20Sopenharmony_ci			perf_evlist__set_selected(evlist, pos);
34928c2ecf20Sopenharmony_ci			/*
34938c2ecf20Sopenharmony_ci			 * Give the calling tool a chance to populate the non
34948c2ecf20Sopenharmony_ci			 * default evsel resorted hists tree.
34958c2ecf20Sopenharmony_ci			 */
34968c2ecf20Sopenharmony_ci			if (hbt)
34978c2ecf20Sopenharmony_ci				hbt->timer(hbt->arg);
34988c2ecf20Sopenharmony_ci			key = perf_evsel__hists_browse(pos, nr_events, help,
34998c2ecf20Sopenharmony_ci						       true, hbt,
35008c2ecf20Sopenharmony_ci						       menu->min_pcnt,
35018c2ecf20Sopenharmony_ci						       menu->env,
35028c2ecf20Sopenharmony_ci						       warn_lost_event,
35038c2ecf20Sopenharmony_ci						       menu->annotation_opts);
35048c2ecf20Sopenharmony_ci			ui_browser__show_title(&menu->b, title);
35058c2ecf20Sopenharmony_ci			switch (key) {
35068c2ecf20Sopenharmony_ci			case K_TAB:
35078c2ecf20Sopenharmony_ci				if (pos->core.node.next == &evlist->core.entries)
35088c2ecf20Sopenharmony_ci					pos = evlist__first(evlist);
35098c2ecf20Sopenharmony_ci				else
35108c2ecf20Sopenharmony_ci					pos = evsel__next(pos);
35118c2ecf20Sopenharmony_ci				goto browse_hists;
35128c2ecf20Sopenharmony_ci			case K_UNTAB:
35138c2ecf20Sopenharmony_ci				if (pos->core.node.prev == &evlist->core.entries)
35148c2ecf20Sopenharmony_ci					pos = evlist__last(evlist);
35158c2ecf20Sopenharmony_ci				else
35168c2ecf20Sopenharmony_ci					pos = evsel__prev(pos);
35178c2ecf20Sopenharmony_ci				goto browse_hists;
35188c2ecf20Sopenharmony_ci			case K_SWITCH_INPUT_DATA:
35198c2ecf20Sopenharmony_ci			case K_RELOAD:
35208c2ecf20Sopenharmony_ci			case 'q':
35218c2ecf20Sopenharmony_ci			case CTRL('c'):
35228c2ecf20Sopenharmony_ci				goto out;
35238c2ecf20Sopenharmony_ci			case K_ESC:
35248c2ecf20Sopenharmony_ci			default:
35258c2ecf20Sopenharmony_ci				continue;
35268c2ecf20Sopenharmony_ci			}
35278c2ecf20Sopenharmony_ci		case K_LEFT:
35288c2ecf20Sopenharmony_ci			continue;
35298c2ecf20Sopenharmony_ci		case K_ESC:
35308c2ecf20Sopenharmony_ci			if (!ui_browser__dialog_yesno(&menu->b,
35318c2ecf20Sopenharmony_ci					       "Do you really want to exit?"))
35328c2ecf20Sopenharmony_ci				continue;
35338c2ecf20Sopenharmony_ci			/* Fall thru */
35348c2ecf20Sopenharmony_ci		case 'q':
35358c2ecf20Sopenharmony_ci		case CTRL('c'):
35368c2ecf20Sopenharmony_ci			goto out;
35378c2ecf20Sopenharmony_ci		default:
35388c2ecf20Sopenharmony_ci			continue;
35398c2ecf20Sopenharmony_ci		}
35408c2ecf20Sopenharmony_ci	}
35418c2ecf20Sopenharmony_ci
35428c2ecf20Sopenharmony_ciout:
35438c2ecf20Sopenharmony_ci	ui_browser__hide(&menu->b);
35448c2ecf20Sopenharmony_ci	return key;
35458c2ecf20Sopenharmony_ci}
35468c2ecf20Sopenharmony_ci
35478c2ecf20Sopenharmony_cistatic bool filter_group_entries(struct ui_browser *browser __maybe_unused,
35488c2ecf20Sopenharmony_ci				 void *entry)
35498c2ecf20Sopenharmony_ci{
35508c2ecf20Sopenharmony_ci	struct evsel *evsel = list_entry(entry, struct evsel, core.node);
35518c2ecf20Sopenharmony_ci
35528c2ecf20Sopenharmony_ci	if (symbol_conf.event_group && !evsel__is_group_leader(evsel))
35538c2ecf20Sopenharmony_ci		return true;
35548c2ecf20Sopenharmony_ci
35558c2ecf20Sopenharmony_ci	return false;
35568c2ecf20Sopenharmony_ci}
35578c2ecf20Sopenharmony_ci
35588c2ecf20Sopenharmony_cistatic int __perf_evlist__tui_browse_hists(struct evlist *evlist,
35598c2ecf20Sopenharmony_ci					   int nr_entries, const char *help,
35608c2ecf20Sopenharmony_ci					   struct hist_browser_timer *hbt,
35618c2ecf20Sopenharmony_ci					   float min_pcnt,
35628c2ecf20Sopenharmony_ci					   struct perf_env *env,
35638c2ecf20Sopenharmony_ci					   bool warn_lost_event,
35648c2ecf20Sopenharmony_ci					   struct annotation_options *annotation_opts)
35658c2ecf20Sopenharmony_ci{
35668c2ecf20Sopenharmony_ci	struct evsel *pos;
35678c2ecf20Sopenharmony_ci	struct evsel_menu menu = {
35688c2ecf20Sopenharmony_ci		.b = {
35698c2ecf20Sopenharmony_ci			.entries    = &evlist->core.entries,
35708c2ecf20Sopenharmony_ci			.refresh    = ui_browser__list_head_refresh,
35718c2ecf20Sopenharmony_ci			.seek	    = ui_browser__list_head_seek,
35728c2ecf20Sopenharmony_ci			.write	    = perf_evsel_menu__write,
35738c2ecf20Sopenharmony_ci			.filter	    = filter_group_entries,
35748c2ecf20Sopenharmony_ci			.nr_entries = nr_entries,
35758c2ecf20Sopenharmony_ci			.priv	    = evlist,
35768c2ecf20Sopenharmony_ci		},
35778c2ecf20Sopenharmony_ci		.min_pcnt = min_pcnt,
35788c2ecf20Sopenharmony_ci		.env = env,
35798c2ecf20Sopenharmony_ci		.annotation_opts = annotation_opts,
35808c2ecf20Sopenharmony_ci	};
35818c2ecf20Sopenharmony_ci
35828c2ecf20Sopenharmony_ci	ui_helpline__push("Press ESC to exit");
35838c2ecf20Sopenharmony_ci
35848c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
35858c2ecf20Sopenharmony_ci		const char *ev_name = evsel__name(pos);
35868c2ecf20Sopenharmony_ci		size_t line_len = strlen(ev_name) + 7;
35878c2ecf20Sopenharmony_ci
35888c2ecf20Sopenharmony_ci		if (menu.b.width < line_len)
35898c2ecf20Sopenharmony_ci			menu.b.width = line_len;
35908c2ecf20Sopenharmony_ci	}
35918c2ecf20Sopenharmony_ci
35928c2ecf20Sopenharmony_ci	return perf_evsel_menu__run(&menu, nr_entries, help,
35938c2ecf20Sopenharmony_ci				    hbt, warn_lost_event);
35948c2ecf20Sopenharmony_ci}
35958c2ecf20Sopenharmony_ci
35968c2ecf20Sopenharmony_cistatic bool perf_evlist__single_entry(struct evlist *evlist)
35978c2ecf20Sopenharmony_ci{
35988c2ecf20Sopenharmony_ci	int nr_entries = evlist->core.nr_entries;
35998c2ecf20Sopenharmony_ci
36008c2ecf20Sopenharmony_ci	if (nr_entries == 1)
36018c2ecf20Sopenharmony_ci	       return true;
36028c2ecf20Sopenharmony_ci
36038c2ecf20Sopenharmony_ci	if (nr_entries == 2) {
36048c2ecf20Sopenharmony_ci		struct evsel *last = evlist__last(evlist);
36058c2ecf20Sopenharmony_ci
36068c2ecf20Sopenharmony_ci		if (evsel__is_dummy_event(last))
36078c2ecf20Sopenharmony_ci			return true;
36088c2ecf20Sopenharmony_ci	}
36098c2ecf20Sopenharmony_ci
36108c2ecf20Sopenharmony_ci	return false;
36118c2ecf20Sopenharmony_ci}
36128c2ecf20Sopenharmony_ci
36138c2ecf20Sopenharmony_ciint perf_evlist__tui_browse_hists(struct evlist *evlist, const char *help,
36148c2ecf20Sopenharmony_ci				  struct hist_browser_timer *hbt,
36158c2ecf20Sopenharmony_ci				  float min_pcnt,
36168c2ecf20Sopenharmony_ci				  struct perf_env *env,
36178c2ecf20Sopenharmony_ci				  bool warn_lost_event,
36188c2ecf20Sopenharmony_ci				  struct annotation_options *annotation_opts)
36198c2ecf20Sopenharmony_ci{
36208c2ecf20Sopenharmony_ci	int nr_entries = evlist->core.nr_entries;
36218c2ecf20Sopenharmony_ci
36228c2ecf20Sopenharmony_ci	if (perf_evlist__single_entry(evlist)) {
36238c2ecf20Sopenharmony_cisingle_entry: {
36248c2ecf20Sopenharmony_ci		struct evsel *first = evlist__first(evlist);
36258c2ecf20Sopenharmony_ci
36268c2ecf20Sopenharmony_ci		return perf_evsel__hists_browse(first, nr_entries, help,
36278c2ecf20Sopenharmony_ci						false, hbt, min_pcnt,
36288c2ecf20Sopenharmony_ci						env, warn_lost_event,
36298c2ecf20Sopenharmony_ci						annotation_opts);
36308c2ecf20Sopenharmony_ci	}
36318c2ecf20Sopenharmony_ci	}
36328c2ecf20Sopenharmony_ci
36338c2ecf20Sopenharmony_ci	if (symbol_conf.event_group) {
36348c2ecf20Sopenharmony_ci		struct evsel *pos;
36358c2ecf20Sopenharmony_ci
36368c2ecf20Sopenharmony_ci		nr_entries = 0;
36378c2ecf20Sopenharmony_ci		evlist__for_each_entry(evlist, pos) {
36388c2ecf20Sopenharmony_ci			if (evsel__is_group_leader(pos))
36398c2ecf20Sopenharmony_ci				nr_entries++;
36408c2ecf20Sopenharmony_ci		}
36418c2ecf20Sopenharmony_ci
36428c2ecf20Sopenharmony_ci		if (nr_entries == 1)
36438c2ecf20Sopenharmony_ci			goto single_entry;
36448c2ecf20Sopenharmony_ci	}
36458c2ecf20Sopenharmony_ci
36468c2ecf20Sopenharmony_ci	return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
36478c2ecf20Sopenharmony_ci					       hbt, min_pcnt, env,
36488c2ecf20Sopenharmony_ci					       warn_lost_event,
36498c2ecf20Sopenharmony_ci					       annotation_opts);
36508c2ecf20Sopenharmony_ci}
36518c2ecf20Sopenharmony_ci
36528c2ecf20Sopenharmony_cistatic int block_hists_browser__title(struct hist_browser *browser, char *bf,
36538c2ecf20Sopenharmony_ci				      size_t size)
36548c2ecf20Sopenharmony_ci{
36558c2ecf20Sopenharmony_ci	struct hists *hists = evsel__hists(browser->block_evsel);
36568c2ecf20Sopenharmony_ci	const char *evname = evsel__name(browser->block_evsel);
36578c2ecf20Sopenharmony_ci	unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
36588c2ecf20Sopenharmony_ci	int ret;
36598c2ecf20Sopenharmony_ci
36608c2ecf20Sopenharmony_ci	ret = scnprintf(bf, size, "# Samples: %lu", nr_samples);
36618c2ecf20Sopenharmony_ci	if (evname)
36628c2ecf20Sopenharmony_ci		scnprintf(bf + ret, size -  ret, " of event '%s'", evname);
36638c2ecf20Sopenharmony_ci
36648c2ecf20Sopenharmony_ci	return 0;
36658c2ecf20Sopenharmony_ci}
36668c2ecf20Sopenharmony_ci
36678c2ecf20Sopenharmony_ciint block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,
36688c2ecf20Sopenharmony_ci			   float min_percent, struct perf_env *env,
36698c2ecf20Sopenharmony_ci			   struct annotation_options *annotation_opts)
36708c2ecf20Sopenharmony_ci{
36718c2ecf20Sopenharmony_ci	struct hists *hists = &bh->block_hists;
36728c2ecf20Sopenharmony_ci	struct hist_browser *browser;
36738c2ecf20Sopenharmony_ci	int key = -1;
36748c2ecf20Sopenharmony_ci	struct popup_action action;
36758c2ecf20Sopenharmony_ci	static const char help[] =
36768c2ecf20Sopenharmony_ci	" q             Quit \n";
36778c2ecf20Sopenharmony_ci
36788c2ecf20Sopenharmony_ci	browser = hist_browser__new(hists);
36798c2ecf20Sopenharmony_ci	if (!browser)
36808c2ecf20Sopenharmony_ci		return -1;
36818c2ecf20Sopenharmony_ci
36828c2ecf20Sopenharmony_ci	browser->block_evsel = evsel;
36838c2ecf20Sopenharmony_ci	browser->title = block_hists_browser__title;
36848c2ecf20Sopenharmony_ci	browser->min_pcnt = min_percent;
36858c2ecf20Sopenharmony_ci	browser->env = env;
36868c2ecf20Sopenharmony_ci	browser->annotation_opts = annotation_opts;
36878c2ecf20Sopenharmony_ci
36888c2ecf20Sopenharmony_ci	/* reset abort key so that it can get Ctrl-C as a key */
36898c2ecf20Sopenharmony_ci	SLang_reset_tty();
36908c2ecf20Sopenharmony_ci	SLang_init_tty(0, 0, 0);
36918c2ecf20Sopenharmony_ci
36928c2ecf20Sopenharmony_ci	memset(&action, 0, sizeof(action));
36938c2ecf20Sopenharmony_ci
36948c2ecf20Sopenharmony_ci	while (1) {
36958c2ecf20Sopenharmony_ci		key = hist_browser__run(browser, "? - help", true, 0);
36968c2ecf20Sopenharmony_ci
36978c2ecf20Sopenharmony_ci		switch (key) {
36988c2ecf20Sopenharmony_ci		case 'q':
36998c2ecf20Sopenharmony_ci			goto out;
37008c2ecf20Sopenharmony_ci		case '?':
37018c2ecf20Sopenharmony_ci			ui_browser__help_window(&browser->b, help);
37028c2ecf20Sopenharmony_ci			break;
37038c2ecf20Sopenharmony_ci		case 'a':
37048c2ecf20Sopenharmony_ci		case K_ENTER:
37058c2ecf20Sopenharmony_ci			if (!browser->selection ||
37068c2ecf20Sopenharmony_ci			    !browser->selection->sym) {
37078c2ecf20Sopenharmony_ci				continue;
37088c2ecf20Sopenharmony_ci			}
37098c2ecf20Sopenharmony_ci
37108c2ecf20Sopenharmony_ci			action.ms.map = browser->selection->map;
37118c2ecf20Sopenharmony_ci			action.ms.sym = browser->selection->sym;
37128c2ecf20Sopenharmony_ci			do_annotate(browser, &action);
37138c2ecf20Sopenharmony_ci			continue;
37148c2ecf20Sopenharmony_ci		default:
37158c2ecf20Sopenharmony_ci			break;
37168c2ecf20Sopenharmony_ci		}
37178c2ecf20Sopenharmony_ci	}
37188c2ecf20Sopenharmony_ci
37198c2ecf20Sopenharmony_ciout:
37208c2ecf20Sopenharmony_ci	hist_browser__delete(browser);
37218c2ecf20Sopenharmony_ci	return 0;
37228c2ecf20Sopenharmony_ci}
3723