xref: /kernel/linux/linux-6.6/tools/perf/ui/gtk/hists.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include "gtk.h"
362306a36Sopenharmony_ci#include "../evlist.h"
462306a36Sopenharmony_ci#include "../callchain.h"
562306a36Sopenharmony_ci#include "../evsel.h"
662306a36Sopenharmony_ci#include "../sort.h"
762306a36Sopenharmony_ci#include "../hist.h"
862306a36Sopenharmony_ci#include "../helpline.h"
962306a36Sopenharmony_ci#include "../string2.h"
1062306a36Sopenharmony_ci#include <signal.h>
1162306a36Sopenharmony_ci#include <stdlib.h>
1262306a36Sopenharmony_ci#include <linux/string.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define MAX_COLUMNS			32
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	int ret = 0;
1962306a36Sopenharmony_ci	int len;
2062306a36Sopenharmony_ci	va_list args;
2162306a36Sopenharmony_ci	double percent;
2262306a36Sopenharmony_ci	const char *markup;
2362306a36Sopenharmony_ci	char *buf = hpp->buf;
2462306a36Sopenharmony_ci	size_t size = hpp->size;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	va_start(args, fmt);
2762306a36Sopenharmony_ci	len = va_arg(args, int);
2862306a36Sopenharmony_ci	percent = va_arg(args, double);
2962306a36Sopenharmony_ci	va_end(args);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	markup = perf_gtk__get_percent_color(percent);
3262306a36Sopenharmony_ci	if (markup)
3362306a36Sopenharmony_ci		ret += scnprintf(buf, size, markup);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	ret += scnprintf(buf + ret, size - ret, fmt, len, percent);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (markup)
3862306a36Sopenharmony_ci		ret += scnprintf(buf + ret, size - ret, "</span>");
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	return ret;
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define __HPP_COLOR_PERCENT_FN(_type, _field)					\
4462306a36Sopenharmony_cistatic u64 he_get_##_field(struct hist_entry *he)				\
4562306a36Sopenharmony_ci{										\
4662306a36Sopenharmony_ci	return he->stat._field;							\
4762306a36Sopenharmony_ci}										\
4862306a36Sopenharmony_ci										\
4962306a36Sopenharmony_cistatic int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt,		\
5062306a36Sopenharmony_ci				       struct perf_hpp *hpp,			\
5162306a36Sopenharmony_ci				       struct hist_entry *he)			\
5262306a36Sopenharmony_ci{										\
5362306a36Sopenharmony_ci	return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%",		\
5462306a36Sopenharmony_ci			__percent_color_snprintf, true);			\
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)				\
5862306a36Sopenharmony_cistatic u64 he_get_acc_##_field(struct hist_entry *he)				\
5962306a36Sopenharmony_ci{										\
6062306a36Sopenharmony_ci	return he->stat_acc->_field;						\
6162306a36Sopenharmony_ci}										\
6262306a36Sopenharmony_ci										\
6362306a36Sopenharmony_cistatic int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt,		\
6462306a36Sopenharmony_ci				       struct perf_hpp *hpp,			\
6562306a36Sopenharmony_ci				       struct hist_entry *he)			\
6662306a36Sopenharmony_ci{										\
6762306a36Sopenharmony_ci	return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", 	\
6862306a36Sopenharmony_ci			    __percent_color_snprintf, true);			\
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci__HPP_COLOR_PERCENT_FN(overhead, period)
7262306a36Sopenharmony_ci__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
7362306a36Sopenharmony_ci__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
7462306a36Sopenharmony_ci__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
7562306a36Sopenharmony_ci__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
7662306a36Sopenharmony_ci__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#undef __HPP_COLOR_PERCENT_FN
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_civoid perf_gtk__init_hpp(void)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	perf_hpp__format[PERF_HPP__OVERHEAD].color =
8462306a36Sopenharmony_ci				perf_gtk__hpp_color_overhead;
8562306a36Sopenharmony_ci	perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
8662306a36Sopenharmony_ci				perf_gtk__hpp_color_overhead_sys;
8762306a36Sopenharmony_ci	perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
8862306a36Sopenharmony_ci				perf_gtk__hpp_color_overhead_us;
8962306a36Sopenharmony_ci	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
9062306a36Sopenharmony_ci				perf_gtk__hpp_color_overhead_guest_sys;
9162306a36Sopenharmony_ci	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
9262306a36Sopenharmony_ci				perf_gtk__hpp_color_overhead_guest_us;
9362306a36Sopenharmony_ci	perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
9462306a36Sopenharmony_ci				perf_gtk__hpp_color_overhead_acc;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic void perf_gtk__add_callchain_flat(struct rb_root *root, GtkTreeStore *store,
9862306a36Sopenharmony_ci					 GtkTreeIter *parent, int col, u64 total)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	struct rb_node *nd;
10162306a36Sopenharmony_ci	bool has_single_node = (rb_first(root) == rb_last(root));
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	for (nd = rb_first(root); nd; nd = rb_next(nd)) {
10462306a36Sopenharmony_ci		struct callchain_node *node;
10562306a36Sopenharmony_ci		struct callchain_list *chain;
10662306a36Sopenharmony_ci		GtkTreeIter iter, new_parent;
10762306a36Sopenharmony_ci		bool need_new_parent;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		node = rb_entry(nd, struct callchain_node, rb_node);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci		new_parent = *parent;
11262306a36Sopenharmony_ci		need_new_parent = !has_single_node;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci		callchain_node__make_parent_list(node);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci		list_for_each_entry(chain, &node->parent_val, list) {
11762306a36Sopenharmony_ci			char buf[128];
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci			gtk_tree_store_append(store, &iter, &new_parent);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci			callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
12262306a36Sopenharmony_ci			gtk_tree_store_set(store, &iter, 0, buf, -1);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci			callchain_list__sym_name(chain, buf, sizeof(buf), false);
12562306a36Sopenharmony_ci			gtk_tree_store_set(store, &iter, col, buf, -1);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci			if (need_new_parent) {
12862306a36Sopenharmony_ci				/*
12962306a36Sopenharmony_ci				 * Only show the top-most symbol in a callchain
13062306a36Sopenharmony_ci				 * if it's not the only callchain.
13162306a36Sopenharmony_ci				 */
13262306a36Sopenharmony_ci				new_parent = iter;
13362306a36Sopenharmony_ci				need_new_parent = false;
13462306a36Sopenharmony_ci			}
13562306a36Sopenharmony_ci		}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci		list_for_each_entry(chain, &node->val, list) {
13862306a36Sopenharmony_ci			char buf[128];
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci			gtk_tree_store_append(store, &iter, &new_parent);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci			callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
14362306a36Sopenharmony_ci			gtk_tree_store_set(store, &iter, 0, buf, -1);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci			callchain_list__sym_name(chain, buf, sizeof(buf), false);
14662306a36Sopenharmony_ci			gtk_tree_store_set(store, &iter, col, buf, -1);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci			if (need_new_parent) {
14962306a36Sopenharmony_ci				/*
15062306a36Sopenharmony_ci				 * Only show the top-most symbol in a callchain
15162306a36Sopenharmony_ci				 * if it's not the only callchain.
15262306a36Sopenharmony_ci				 */
15362306a36Sopenharmony_ci				new_parent = iter;
15462306a36Sopenharmony_ci				need_new_parent = false;
15562306a36Sopenharmony_ci			}
15662306a36Sopenharmony_ci		}
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic void perf_gtk__add_callchain_folded(struct rb_root *root, GtkTreeStore *store,
16162306a36Sopenharmony_ci					   GtkTreeIter *parent, int col, u64 total)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	struct rb_node *nd;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	for (nd = rb_first(root); nd; nd = rb_next(nd)) {
16662306a36Sopenharmony_ci		struct callchain_node *node;
16762306a36Sopenharmony_ci		struct callchain_list *chain;
16862306a36Sopenharmony_ci		GtkTreeIter iter;
16962306a36Sopenharmony_ci		char buf[64];
17062306a36Sopenharmony_ci		char *str, *str_alloc = NULL;
17162306a36Sopenharmony_ci		bool first = true;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci		node = rb_entry(nd, struct callchain_node, rb_node);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci		callchain_node__make_parent_list(node);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci		list_for_each_entry(chain, &node->parent_val, list) {
17862306a36Sopenharmony_ci			char name[1024];
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci			callchain_list__sym_name(chain, name, sizeof(name), false);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci			if (asprintf(&str, "%s%s%s",
18362306a36Sopenharmony_ci				     first ? "" : str_alloc,
18462306a36Sopenharmony_ci				     first ? "" : symbol_conf.field_sep ?: "; ",
18562306a36Sopenharmony_ci				     name) < 0)
18662306a36Sopenharmony_ci				return;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci			first = false;
18962306a36Sopenharmony_ci			free(str_alloc);
19062306a36Sopenharmony_ci			str_alloc = str;
19162306a36Sopenharmony_ci		}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci		list_for_each_entry(chain, &node->val, list) {
19462306a36Sopenharmony_ci			char name[1024];
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci			callchain_list__sym_name(chain, name, sizeof(name), false);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci			if (asprintf(&str, "%s%s%s",
19962306a36Sopenharmony_ci				     first ? "" : str_alloc,
20062306a36Sopenharmony_ci				     first ? "" : symbol_conf.field_sep ?: "; ",
20162306a36Sopenharmony_ci				     name) < 0)
20262306a36Sopenharmony_ci				return;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci			first = false;
20562306a36Sopenharmony_ci			free(str_alloc);
20662306a36Sopenharmony_ci			str_alloc = str;
20762306a36Sopenharmony_ci		}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci		gtk_tree_store_append(store, &iter, parent);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci		callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
21262306a36Sopenharmony_ci		gtk_tree_store_set(store, &iter, 0, buf, -1);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci		gtk_tree_store_set(store, &iter, col, str, -1);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		free(str_alloc);
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic void perf_gtk__add_callchain_graph(struct rb_root *root, GtkTreeStore *store,
22162306a36Sopenharmony_ci					  GtkTreeIter *parent, int col, u64 total)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	struct rb_node *nd;
22462306a36Sopenharmony_ci	bool has_single_node = (rb_first(root) == rb_last(root));
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	for (nd = rb_first(root); nd; nd = rb_next(nd)) {
22762306a36Sopenharmony_ci		struct callchain_node *node;
22862306a36Sopenharmony_ci		struct callchain_list *chain;
22962306a36Sopenharmony_ci		GtkTreeIter iter, new_parent;
23062306a36Sopenharmony_ci		bool need_new_parent;
23162306a36Sopenharmony_ci		u64 child_total;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci		node = rb_entry(nd, struct callchain_node, rb_node);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci		new_parent = *parent;
23662306a36Sopenharmony_ci		need_new_parent = !has_single_node && (node->val_nr > 1);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci		list_for_each_entry(chain, &node->val, list) {
23962306a36Sopenharmony_ci			char buf[128];
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci			gtk_tree_store_append(store, &iter, &new_parent);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci			callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
24462306a36Sopenharmony_ci			gtk_tree_store_set(store, &iter, 0, buf, -1);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci			callchain_list__sym_name(chain, buf, sizeof(buf), false);
24762306a36Sopenharmony_ci			gtk_tree_store_set(store, &iter, col, buf, -1);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci			if (need_new_parent) {
25062306a36Sopenharmony_ci				/*
25162306a36Sopenharmony_ci				 * Only show the top-most symbol in a callchain
25262306a36Sopenharmony_ci				 * if it's not the only callchain.
25362306a36Sopenharmony_ci				 */
25462306a36Sopenharmony_ci				new_parent = iter;
25562306a36Sopenharmony_ci				need_new_parent = false;
25662306a36Sopenharmony_ci			}
25762306a36Sopenharmony_ci		}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		if (callchain_param.mode == CHAIN_GRAPH_REL)
26062306a36Sopenharmony_ci			child_total = node->children_hit;
26162306a36Sopenharmony_ci		else
26262306a36Sopenharmony_ci			child_total = total;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		/* Now 'iter' contains info of the last callchain_list */
26562306a36Sopenharmony_ci		perf_gtk__add_callchain_graph(&node->rb_root, store, &iter, col,
26662306a36Sopenharmony_ci					      child_total);
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
27162306a36Sopenharmony_ci				    GtkTreeIter *parent, int col, u64 total)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	if (callchain_param.mode == CHAIN_FLAT)
27462306a36Sopenharmony_ci		perf_gtk__add_callchain_flat(root, store, parent, col, total);
27562306a36Sopenharmony_ci	else if (callchain_param.mode == CHAIN_FOLDED)
27662306a36Sopenharmony_ci		perf_gtk__add_callchain_folded(root, store, parent, col, total);
27762306a36Sopenharmony_ci	else
27862306a36Sopenharmony_ci		perf_gtk__add_callchain_graph(root, store, parent, col, total);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic void on_row_activated(GtkTreeView *view, GtkTreePath *path,
28262306a36Sopenharmony_ci			     GtkTreeViewColumn *col __maybe_unused,
28362306a36Sopenharmony_ci			     gpointer user_data __maybe_unused)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	bool expanded = gtk_tree_view_row_expanded(view, path);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	if (expanded)
28862306a36Sopenharmony_ci		gtk_tree_view_collapse_row(view, path);
28962306a36Sopenharmony_ci	else
29062306a36Sopenharmony_ci		gtk_tree_view_expand_row(view, path, FALSE);
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
29462306a36Sopenharmony_ci				 float min_pcnt)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
29762306a36Sopenharmony_ci	GType col_types[MAX_COLUMNS];
29862306a36Sopenharmony_ci	GtkCellRenderer *renderer;
29962306a36Sopenharmony_ci	GtkTreeStore *store;
30062306a36Sopenharmony_ci	struct rb_node *nd;
30162306a36Sopenharmony_ci	GtkWidget *view;
30262306a36Sopenharmony_ci	int col_idx;
30362306a36Sopenharmony_ci	int sym_col = -1;
30462306a36Sopenharmony_ci	int nr_cols;
30562306a36Sopenharmony_ci	char s[512];
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	struct perf_hpp hpp = {
30862306a36Sopenharmony_ci		.buf		= s,
30962306a36Sopenharmony_ci		.size		= sizeof(s),
31062306a36Sopenharmony_ci	};
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	nr_cols = 0;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	hists__for_each_format(hists, fmt)
31562306a36Sopenharmony_ci		col_types[nr_cols++] = G_TYPE_STRING;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	store = gtk_tree_store_newv(nr_cols, col_types);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	view = gtk_tree_view_new();
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	renderer = gtk_cell_renderer_text_new();
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	col_idx = 0;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	hists__for_each_format(hists, fmt) {
32662306a36Sopenharmony_ci		if (perf_hpp__should_skip(fmt, hists))
32762306a36Sopenharmony_ci			continue;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci		/*
33062306a36Sopenharmony_ci		 * XXX no way to determine where symcol column is..
33162306a36Sopenharmony_ci		 *     Just use last column for now.
33262306a36Sopenharmony_ci		 */
33362306a36Sopenharmony_ci		if (perf_hpp__is_sort_entry(fmt))
33462306a36Sopenharmony_ci			sym_col = col_idx;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
33762306a36Sopenharmony_ci							    -1, fmt->name,
33862306a36Sopenharmony_ci							    renderer, "markup",
33962306a36Sopenharmony_ci							    col_idx++, NULL);
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	for (col_idx = 0; col_idx < nr_cols; col_idx++) {
34362306a36Sopenharmony_ci		GtkTreeViewColumn *column;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci		column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
34662306a36Sopenharmony_ci		gtk_tree_view_column_set_resizable(column, TRUE);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		if (col_idx == sym_col) {
34962306a36Sopenharmony_ci			gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
35062306a36Sopenharmony_ci							  column);
35162306a36Sopenharmony_ci		}
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	g_object_unref(GTK_TREE_MODEL(store));
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	for (nd = rb_first_cached(&hists->entries); nd; nd = rb_next(nd)) {
35962306a36Sopenharmony_ci		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
36062306a36Sopenharmony_ci		GtkTreeIter iter;
36162306a36Sopenharmony_ci		u64 total = hists__total_period(h->hists);
36262306a36Sopenharmony_ci		float percent;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci		if (h->filtered)
36562306a36Sopenharmony_ci			continue;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		percent = hist_entry__get_percent_limit(h);
36862306a36Sopenharmony_ci		if (percent < min_pcnt)
36962306a36Sopenharmony_ci			continue;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci		gtk_tree_store_append(store, &iter, NULL);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		col_idx = 0;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci		hists__for_each_format(hists, fmt) {
37662306a36Sopenharmony_ci			if (perf_hpp__should_skip(fmt, h->hists))
37762306a36Sopenharmony_ci				continue;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci			if (fmt->color)
38062306a36Sopenharmony_ci				fmt->color(fmt, &hpp, h);
38162306a36Sopenharmony_ci			else
38262306a36Sopenharmony_ci				fmt->entry(fmt, &hpp, h);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci			gtk_tree_store_set(store, &iter, col_idx++, s, -1);
38562306a36Sopenharmony_ci		}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci		if (hist_entry__has_callchains(h) &&
38862306a36Sopenharmony_ci		    symbol_conf.use_callchain && hists__has(hists, sym)) {
38962306a36Sopenharmony_ci			if (callchain_param.mode == CHAIN_GRAPH_REL)
39062306a36Sopenharmony_ci				total = symbol_conf.cumulate_callchain ?
39162306a36Sopenharmony_ci					h->stat_acc->period : h->stat.period;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci			perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
39462306a36Sopenharmony_ci						sym_col, total);
39562306a36Sopenharmony_ci		}
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	g_signal_connect(view, "row-activated",
40162306a36Sopenharmony_ci			 G_CALLBACK(on_row_activated), NULL);
40262306a36Sopenharmony_ci	gtk_container_add(GTK_CONTAINER(window), view);
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic void perf_gtk__add_hierarchy_entries(struct hists *hists,
40662306a36Sopenharmony_ci					    struct rb_root_cached *root,
40762306a36Sopenharmony_ci					    GtkTreeStore *store,
40862306a36Sopenharmony_ci					    GtkTreeIter *parent,
40962306a36Sopenharmony_ci					    struct perf_hpp *hpp,
41062306a36Sopenharmony_ci					    float min_pcnt)
41162306a36Sopenharmony_ci{
41262306a36Sopenharmony_ci	int col_idx = 0;
41362306a36Sopenharmony_ci	struct rb_node *node;
41462306a36Sopenharmony_ci	struct hist_entry *he;
41562306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
41662306a36Sopenharmony_ci	struct perf_hpp_list_node *fmt_node;
41762306a36Sopenharmony_ci	u64 total = hists__total_period(hists);
41862306a36Sopenharmony_ci	int size;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	for (node = rb_first_cached(root); node; node = rb_next(node)) {
42162306a36Sopenharmony_ci		GtkTreeIter iter;
42262306a36Sopenharmony_ci		float percent;
42362306a36Sopenharmony_ci		char *bf;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci		he = rb_entry(node, struct hist_entry, rb_node);
42662306a36Sopenharmony_ci		if (he->filtered)
42762306a36Sopenharmony_ci			continue;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci		percent = hist_entry__get_percent_limit(he);
43062306a36Sopenharmony_ci		if (percent < min_pcnt)
43162306a36Sopenharmony_ci			continue;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci		gtk_tree_store_append(store, &iter, parent);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci		col_idx = 0;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci		/* the first hpp_list_node is for overhead columns */
43862306a36Sopenharmony_ci		fmt_node = list_first_entry(&hists->hpp_formats,
43962306a36Sopenharmony_ci					    struct perf_hpp_list_node, list);
44062306a36Sopenharmony_ci		perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
44162306a36Sopenharmony_ci			if (fmt->color)
44262306a36Sopenharmony_ci				fmt->color(fmt, hpp, he);
44362306a36Sopenharmony_ci			else
44462306a36Sopenharmony_ci				fmt->entry(fmt, hpp, he);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci			gtk_tree_store_set(store, &iter, col_idx++, hpp->buf, -1);
44762306a36Sopenharmony_ci		}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci		bf = hpp->buf;
45062306a36Sopenharmony_ci		size = hpp->size;
45162306a36Sopenharmony_ci		perf_hpp_list__for_each_format(he->hpp_list, fmt) {
45262306a36Sopenharmony_ci			int ret;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci			if (fmt->color)
45562306a36Sopenharmony_ci				ret = fmt->color(fmt, hpp, he);
45662306a36Sopenharmony_ci			else
45762306a36Sopenharmony_ci				ret = fmt->entry(fmt, hpp, he);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci			snprintf(hpp->buf + ret, hpp->size - ret, "  ");
46062306a36Sopenharmony_ci			advance_hpp(hpp, ret + 2);
46162306a36Sopenharmony_ci		}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci		gtk_tree_store_set(store, &iter, col_idx, strim(bf), -1);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci		if (!he->leaf) {
46662306a36Sopenharmony_ci			hpp->buf = bf;
46762306a36Sopenharmony_ci			hpp->size = size;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci			perf_gtk__add_hierarchy_entries(hists, &he->hroot_out,
47062306a36Sopenharmony_ci							store, &iter, hpp,
47162306a36Sopenharmony_ci							min_pcnt);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci			if (!hist_entry__has_hierarchy_children(he, min_pcnt)) {
47462306a36Sopenharmony_ci				char buf[32];
47562306a36Sopenharmony_ci				GtkTreeIter child;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci				snprintf(buf, sizeof(buf), "no entry >= %.2f%%",
47862306a36Sopenharmony_ci					 min_pcnt);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci				gtk_tree_store_append(store, &child, &iter);
48162306a36Sopenharmony_ci				gtk_tree_store_set(store, &child, col_idx, buf, -1);
48262306a36Sopenharmony_ci			}
48362306a36Sopenharmony_ci		}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci		if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
48662306a36Sopenharmony_ci			if (callchain_param.mode == CHAIN_GRAPH_REL)
48762306a36Sopenharmony_ci				total = symbol_conf.cumulate_callchain ?
48862306a36Sopenharmony_ci					he->stat_acc->period : he->stat.period;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci			perf_gtk__add_callchain(&he->sorted_chain, store, &iter,
49162306a36Sopenharmony_ci						col_idx, total);
49262306a36Sopenharmony_ci		}
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cistatic void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
49862306a36Sopenharmony_ci				     float min_pcnt)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
50162306a36Sopenharmony_ci	struct perf_hpp_list_node *fmt_node;
50262306a36Sopenharmony_ci	GType col_types[MAX_COLUMNS];
50362306a36Sopenharmony_ci	GtkCellRenderer *renderer;
50462306a36Sopenharmony_ci	GtkTreeStore *store;
50562306a36Sopenharmony_ci	GtkWidget *view;
50662306a36Sopenharmony_ci	int col_idx;
50762306a36Sopenharmony_ci	int nr_cols = 0;
50862306a36Sopenharmony_ci	char s[512];
50962306a36Sopenharmony_ci	char buf[512];
51062306a36Sopenharmony_ci	bool first_node, first_col;
51162306a36Sopenharmony_ci	struct perf_hpp hpp = {
51262306a36Sopenharmony_ci		.buf		= s,
51362306a36Sopenharmony_ci		.size		= sizeof(s),
51462306a36Sopenharmony_ci	};
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	hists__for_each_format(hists, fmt) {
51762306a36Sopenharmony_ci		if (perf_hpp__is_sort_entry(fmt) ||
51862306a36Sopenharmony_ci		    perf_hpp__is_dynamic_entry(fmt))
51962306a36Sopenharmony_ci			break;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci		col_types[nr_cols++] = G_TYPE_STRING;
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci	col_types[nr_cols++] = G_TYPE_STRING;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	store = gtk_tree_store_newv(nr_cols, col_types);
52662306a36Sopenharmony_ci	view = gtk_tree_view_new();
52762306a36Sopenharmony_ci	renderer = gtk_cell_renderer_text_new();
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	col_idx = 0;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* the first hpp_list_node is for overhead columns */
53262306a36Sopenharmony_ci	fmt_node = list_first_entry(&hists->hpp_formats,
53362306a36Sopenharmony_ci				    struct perf_hpp_list_node, list);
53462306a36Sopenharmony_ci	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
53562306a36Sopenharmony_ci		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
53662306a36Sopenharmony_ci							    -1, fmt->name,
53762306a36Sopenharmony_ci							    renderer, "markup",
53862306a36Sopenharmony_ci							    col_idx++, NULL);
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	/* construct merged column header since sort keys share single column */
54262306a36Sopenharmony_ci	buf[0] = '\0';
54362306a36Sopenharmony_ci	first_node = true;
54462306a36Sopenharmony_ci	list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
54562306a36Sopenharmony_ci		if (!first_node)
54662306a36Sopenharmony_ci			strcat(buf, " / ");
54762306a36Sopenharmony_ci		first_node = false;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci		first_col = true;
55062306a36Sopenharmony_ci		perf_hpp_list__for_each_format(&fmt_node->hpp ,fmt) {
55162306a36Sopenharmony_ci			if (perf_hpp__should_skip(fmt, hists))
55262306a36Sopenharmony_ci				continue;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci			if (!first_col)
55562306a36Sopenharmony_ci				strcat(buf, "+");
55662306a36Sopenharmony_ci			first_col = false;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci			fmt->header(fmt, &hpp, hists, 0, NULL);
55962306a36Sopenharmony_ci			strcat(buf, strim(hpp.buf));
56062306a36Sopenharmony_ci		}
56162306a36Sopenharmony_ci	}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
56462306a36Sopenharmony_ci						    -1, buf,
56562306a36Sopenharmony_ci						    renderer, "markup",
56662306a36Sopenharmony_ci						    col_idx++, NULL);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	for (col_idx = 0; col_idx < nr_cols; col_idx++) {
56962306a36Sopenharmony_ci		GtkTreeViewColumn *column;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci		column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
57262306a36Sopenharmony_ci		gtk_tree_view_column_set_resizable(column, TRUE);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci		if (col_idx == 0) {
57562306a36Sopenharmony_ci			gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
57662306a36Sopenharmony_ci							  column);
57762306a36Sopenharmony_ci		}
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
58162306a36Sopenharmony_ci	g_object_unref(GTK_TREE_MODEL(store));
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	perf_gtk__add_hierarchy_entries(hists, &hists->entries, store,
58462306a36Sopenharmony_ci					NULL, &hpp, min_pcnt);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	g_signal_connect(view, "row-activated",
58962306a36Sopenharmony_ci			 G_CALLBACK(on_row_activated), NULL);
59062306a36Sopenharmony_ci	gtk_container_add(GTK_CONTAINER(window), view);
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ciint evlist__gtk_browse_hists(struct evlist *evlist, const char *help,
59462306a36Sopenharmony_ci			     struct hist_browser_timer *hbt __maybe_unused, float min_pcnt)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	struct evsel *pos;
59762306a36Sopenharmony_ci	GtkWidget *vbox;
59862306a36Sopenharmony_ci	GtkWidget *notebook;
59962306a36Sopenharmony_ci	GtkWidget *info_bar;
60062306a36Sopenharmony_ci	GtkWidget *statbar;
60162306a36Sopenharmony_ci	GtkWidget *window;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	signal(SIGSEGV, perf_gtk__signal);
60462306a36Sopenharmony_ci	signal(SIGFPE,  perf_gtk__signal);
60562306a36Sopenharmony_ci	signal(SIGINT,  perf_gtk__signal);
60662306a36Sopenharmony_ci	signal(SIGQUIT, perf_gtk__signal);
60762306a36Sopenharmony_ci	signal(SIGTERM, perf_gtk__signal);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	gtk_window_set_title(GTK_WINDOW(window), "perf report");
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	pgctx = perf_gtk__activate_context(window);
61662306a36Sopenharmony_ci	if (!pgctx)
61762306a36Sopenharmony_ci		return -1;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	vbox = gtk_vbox_new(FALSE, 0);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	notebook = gtk_notebook_new();
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	info_bar = perf_gtk__setup_info_bar();
62662306a36Sopenharmony_ci	if (info_bar)
62762306a36Sopenharmony_ci		gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	statbar = perf_gtk__setup_statusbar();
63062306a36Sopenharmony_ci	gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	gtk_container_add(GTK_CONTAINER(window), vbox);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
63562306a36Sopenharmony_ci		struct hists *hists = evsel__hists(pos);
63662306a36Sopenharmony_ci		const char *evname = evsel__name(pos);
63762306a36Sopenharmony_ci		GtkWidget *scrolled_window;
63862306a36Sopenharmony_ci		GtkWidget *tab_label;
63962306a36Sopenharmony_ci		char buf[512];
64062306a36Sopenharmony_ci		size_t size = sizeof(buf);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci		if (symbol_conf.event_group) {
64362306a36Sopenharmony_ci			if (!evsel__is_group_leader(pos))
64462306a36Sopenharmony_ci				continue;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci			if (pos->core.nr_members > 1) {
64762306a36Sopenharmony_ci				evsel__group_desc(pos, buf, size);
64862306a36Sopenharmony_ci				evname = buf;
64962306a36Sopenharmony_ci			}
65062306a36Sopenharmony_ci		}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci		scrolled_window = gtk_scrolled_window_new(NULL, NULL);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
65562306a36Sopenharmony_ci							GTK_POLICY_AUTOMATIC,
65662306a36Sopenharmony_ci							GTK_POLICY_AUTOMATIC);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci		if (symbol_conf.report_hierarchy)
65962306a36Sopenharmony_ci			perf_gtk__show_hierarchy(scrolled_window, hists, min_pcnt);
66062306a36Sopenharmony_ci		else
66162306a36Sopenharmony_ci			perf_gtk__show_hists(scrolled_window, hists, min_pcnt);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci		tab_label = gtk_label_new(evname);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci		gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
66662306a36Sopenharmony_ci	}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	gtk_widget_show_all(window);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	perf_gtk__resize_window(window);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	ui_helpline__push(help);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	gtk_main();
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	perf_gtk__deactivate_context(&pgctx);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	return 0;
68162306a36Sopenharmony_ci}
682