1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2*f7a858bfSLiam Howlett #include "gtk.h"
30da41ce9SNamhyung Kim #include "../evlist.h"
4b10ba7f1SArnaldo Carvalho de Melo #include "../callchain.h"
50da41ce9SNamhyung Kim #include "../evsel.h"
60da41ce9SNamhyung Kim #include "../sort.h"
70da41ce9SNamhyung Kim #include "../hist.h"
80da41ce9SNamhyung Kim #include "../helpline.h"
9a067558eSArnaldo Carvalho de Melo #include "../string2.h"
109607ad3aSArnaldo Carvalho de Melo #include <signal.h>
11e0fcfb08SArnaldo Carvalho de Melo #include <stdlib.h>
123ca43b60SArnaldo Carvalho de Melo #include <linux/string.h>
130da41ce9SNamhyung Kim
140da41ce9SNamhyung Kim #define MAX_COLUMNS 32
150da41ce9SNamhyung Kim
__percent_color_snprintf(struct perf_hpp * hpp,const char * fmt,...)16a0088adcSNamhyung Kim static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
17843985e9SNamhyung Kim {
18843985e9SNamhyung Kim int ret = 0;
19d675107cSNamhyung Kim int len;
204a62109fSNamhyung Kim va_list args;
214a62109fSNamhyung Kim double percent;
22843985e9SNamhyung Kim const char *markup;
23a0088adcSNamhyung Kim char *buf = hpp->buf;
24a0088adcSNamhyung Kim size_t size = hpp->size;
25843985e9SNamhyung Kim
264a62109fSNamhyung Kim va_start(args, fmt);
27d675107cSNamhyung Kim len = va_arg(args, int);
284a62109fSNamhyung Kim percent = va_arg(args, double);
294a62109fSNamhyung Kim va_end(args);
304a62109fSNamhyung Kim
31843985e9SNamhyung Kim markup = perf_gtk__get_percent_color(percent);
32843985e9SNamhyung Kim if (markup)
33843985e9SNamhyung Kim ret += scnprintf(buf, size, markup);
34843985e9SNamhyung Kim
35d675107cSNamhyung Kim ret += scnprintf(buf + ret, size - ret, fmt, len, percent);
36843985e9SNamhyung Kim
37843985e9SNamhyung Kim if (markup)
38843985e9SNamhyung Kim ret += scnprintf(buf + ret, size - ret, "</span>");
39843985e9SNamhyung Kim
40843985e9SNamhyung Kim return ret;
410da41ce9SNamhyung Kim }
420da41ce9SNamhyung Kim
43843985e9SNamhyung Kim #define __HPP_COLOR_PERCENT_FN(_type, _field) \
44843985e9SNamhyung Kim static u64 he_get_##_field(struct hist_entry *he) \
45843985e9SNamhyung Kim { \
46843985e9SNamhyung Kim return he->stat._field; \
47843985e9SNamhyung Kim } \
48843985e9SNamhyung Kim \
495b591669SNamhyung Kim static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
502c5d4b4aSJiri Olsa struct perf_hpp *hpp, \
51843985e9SNamhyung Kim struct hist_entry *he) \
52843985e9SNamhyung Kim { \
535b591669SNamhyung Kim return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \
544a62109fSNamhyung Kim __percent_color_snprintf, true); \
55843985e9SNamhyung Kim }
56843985e9SNamhyung Kim
57b09955b2SNamhyung Kim #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
58b09955b2SNamhyung Kim static u64 he_get_acc_##_field(struct hist_entry *he) \
59b09955b2SNamhyung Kim { \
60b09955b2SNamhyung Kim return he->stat_acc->_field; \
61b09955b2SNamhyung Kim } \
62b09955b2SNamhyung Kim \
63b8f8eb84SArnaldo Carvalho de Melo static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
64b09955b2SNamhyung Kim struct perf_hpp *hpp, \
65b09955b2SNamhyung Kim struct hist_entry *he) \
66b09955b2SNamhyung Kim { \
675b591669SNamhyung Kim return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \
68b09955b2SNamhyung Kim __percent_color_snprintf, true); \
69b09955b2SNamhyung Kim }
70b09955b2SNamhyung Kim
__HPP_COLOR_PERCENT_FN(overhead,period)71843985e9SNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead, period)
72843985e9SNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
73843985e9SNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_us, period_us)
74843985e9SNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
75843985e9SNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
76b09955b2SNamhyung Kim __HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
77843985e9SNamhyung Kim
78843985e9SNamhyung Kim #undef __HPP_COLOR_PERCENT_FN
790da41ce9SNamhyung Kim
800da41ce9SNamhyung Kim
810da41ce9SNamhyung Kim void perf_gtk__init_hpp(void)
820da41ce9SNamhyung Kim {
830da41ce9SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD].color =
840da41ce9SNamhyung Kim perf_gtk__hpp_color_overhead;
850da41ce9SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
860da41ce9SNamhyung Kim perf_gtk__hpp_color_overhead_sys;
870da41ce9SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
880da41ce9SNamhyung Kim perf_gtk__hpp_color_overhead_us;
890da41ce9SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
900da41ce9SNamhyung Kim perf_gtk__hpp_color_overhead_guest_sys;
910da41ce9SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
920da41ce9SNamhyung Kim perf_gtk__hpp_color_overhead_guest_us;
93b09955b2SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
94b09955b2SNamhyung Kim perf_gtk__hpp_color_overhead_acc;
950da41ce9SNamhyung Kim }
960da41ce9SNamhyung Kim
perf_gtk__add_callchain_flat(struct rb_root * root,GtkTreeStore * store,GtkTreeIter * parent,int col,u64 total)973cd99dfdSNamhyung Kim static void perf_gtk__add_callchain_flat(struct rb_root *root, GtkTreeStore *store,
983cd99dfdSNamhyung Kim GtkTreeIter *parent, int col, u64 total)
993cd99dfdSNamhyung Kim {
1003cd99dfdSNamhyung Kim struct rb_node *nd;
1013cd99dfdSNamhyung Kim bool has_single_node = (rb_first(root) == rb_last(root));
1023cd99dfdSNamhyung Kim
1033cd99dfdSNamhyung Kim for (nd = rb_first(root); nd; nd = rb_next(nd)) {
1043cd99dfdSNamhyung Kim struct callchain_node *node;
1053cd99dfdSNamhyung Kim struct callchain_list *chain;
1063cd99dfdSNamhyung Kim GtkTreeIter iter, new_parent;
1073cd99dfdSNamhyung Kim bool need_new_parent;
1083cd99dfdSNamhyung Kim
1093cd99dfdSNamhyung Kim node = rb_entry(nd, struct callchain_node, rb_node);
1103cd99dfdSNamhyung Kim
1113cd99dfdSNamhyung Kim new_parent = *parent;
1123cd99dfdSNamhyung Kim need_new_parent = !has_single_node;
1133cd99dfdSNamhyung Kim
1143cd99dfdSNamhyung Kim callchain_node__make_parent_list(node);
1153cd99dfdSNamhyung Kim
1163cd99dfdSNamhyung Kim list_for_each_entry(chain, &node->parent_val, list) {
1173cd99dfdSNamhyung Kim char buf[128];
1183cd99dfdSNamhyung Kim
1193cd99dfdSNamhyung Kim gtk_tree_store_append(store, &iter, &new_parent);
1203cd99dfdSNamhyung Kim
1213cd99dfdSNamhyung Kim callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
1223cd99dfdSNamhyung Kim gtk_tree_store_set(store, &iter, 0, buf, -1);
1233cd99dfdSNamhyung Kim
1243cd99dfdSNamhyung Kim callchain_list__sym_name(chain, buf, sizeof(buf), false);
1253cd99dfdSNamhyung Kim gtk_tree_store_set(store, &iter, col, buf, -1);
1263cd99dfdSNamhyung Kim
1273cd99dfdSNamhyung Kim if (need_new_parent) {
1283cd99dfdSNamhyung Kim /*
1293cd99dfdSNamhyung Kim * Only show the top-most symbol in a callchain
1303cd99dfdSNamhyung Kim * if it's not the only callchain.
1313cd99dfdSNamhyung Kim */
1323cd99dfdSNamhyung Kim new_parent = iter;
1333cd99dfdSNamhyung Kim need_new_parent = false;
1343cd99dfdSNamhyung Kim }
1353cd99dfdSNamhyung Kim }
1363cd99dfdSNamhyung Kim
1373cd99dfdSNamhyung Kim list_for_each_entry(chain, &node->val, list) {
1383cd99dfdSNamhyung Kim char buf[128];
1393cd99dfdSNamhyung Kim
1403cd99dfdSNamhyung Kim gtk_tree_store_append(store, &iter, &new_parent);
1413cd99dfdSNamhyung Kim
1423cd99dfdSNamhyung Kim callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
1433cd99dfdSNamhyung Kim gtk_tree_store_set(store, &iter, 0, buf, -1);
1443cd99dfdSNamhyung Kim
1453cd99dfdSNamhyung Kim callchain_list__sym_name(chain, buf, sizeof(buf), false);
1463cd99dfdSNamhyung Kim gtk_tree_store_set(store, &iter, col, buf, -1);
1473cd99dfdSNamhyung Kim
1483cd99dfdSNamhyung Kim if (need_new_parent) {
1493cd99dfdSNamhyung Kim /*
1503cd99dfdSNamhyung Kim * Only show the top-most symbol in a callchain
1513cd99dfdSNamhyung Kim * if it's not the only callchain.
1523cd99dfdSNamhyung Kim */
1533cd99dfdSNamhyung Kim new_parent = iter;
1543cd99dfdSNamhyung Kim need_new_parent = false;
1553cd99dfdSNamhyung Kim }
1563cd99dfdSNamhyung Kim }
1573cd99dfdSNamhyung Kim }
1583cd99dfdSNamhyung Kim }
1593cd99dfdSNamhyung Kim
perf_gtk__add_callchain_folded(struct rb_root * root,GtkTreeStore * store,GtkTreeIter * parent,int col,u64 total)1602c6caff2SNamhyung Kim static void perf_gtk__add_callchain_folded(struct rb_root *root, GtkTreeStore *store,
1612c6caff2SNamhyung Kim GtkTreeIter *parent, int col, u64 total)
1622c6caff2SNamhyung Kim {
1632c6caff2SNamhyung Kim struct rb_node *nd;
1642c6caff2SNamhyung Kim
1652c6caff2SNamhyung Kim for (nd = rb_first(root); nd; nd = rb_next(nd)) {
1662c6caff2SNamhyung Kim struct callchain_node *node;
1672c6caff2SNamhyung Kim struct callchain_list *chain;
1682c6caff2SNamhyung Kim GtkTreeIter iter;
1692c6caff2SNamhyung Kim char buf[64];
1702c6caff2SNamhyung Kim char *str, *str_alloc = NULL;
1712c6caff2SNamhyung Kim bool first = true;
1722c6caff2SNamhyung Kim
1732c6caff2SNamhyung Kim node = rb_entry(nd, struct callchain_node, rb_node);
1742c6caff2SNamhyung Kim
1752c6caff2SNamhyung Kim callchain_node__make_parent_list(node);
1762c6caff2SNamhyung Kim
1772c6caff2SNamhyung Kim list_for_each_entry(chain, &node->parent_val, list) {
1782c6caff2SNamhyung Kim char name[1024];
1792c6caff2SNamhyung Kim
1802c6caff2SNamhyung Kim callchain_list__sym_name(chain, name, sizeof(name), false);
1812c6caff2SNamhyung Kim
1822c6caff2SNamhyung Kim if (asprintf(&str, "%s%s%s",
1832c6caff2SNamhyung Kim first ? "" : str_alloc,
1842c6caff2SNamhyung Kim first ? "" : symbol_conf.field_sep ?: "; ",
1852c6caff2SNamhyung Kim name) < 0)
1862c6caff2SNamhyung Kim return;
1872c6caff2SNamhyung Kim
1882c6caff2SNamhyung Kim first = false;
1892c6caff2SNamhyung Kim free(str_alloc);
1902c6caff2SNamhyung Kim str_alloc = str;
1912c6caff2SNamhyung Kim }
1922c6caff2SNamhyung Kim
1932c6caff2SNamhyung Kim list_for_each_entry(chain, &node->val, list) {
1942c6caff2SNamhyung Kim char name[1024];
1952c6caff2SNamhyung Kim
1962c6caff2SNamhyung Kim callchain_list__sym_name(chain, name, sizeof(name), false);
1972c6caff2SNamhyung Kim
1982c6caff2SNamhyung Kim if (asprintf(&str, "%s%s%s",
1992c6caff2SNamhyung Kim first ? "" : str_alloc,
2002c6caff2SNamhyung Kim first ? "" : symbol_conf.field_sep ?: "; ",
2012c6caff2SNamhyung Kim name) < 0)
2022c6caff2SNamhyung Kim return;
2032c6caff2SNamhyung Kim
2042c6caff2SNamhyung Kim first = false;
2052c6caff2SNamhyung Kim free(str_alloc);
2062c6caff2SNamhyung Kim str_alloc = str;
2072c6caff2SNamhyung Kim }
2082c6caff2SNamhyung Kim
2092c6caff2SNamhyung Kim gtk_tree_store_append(store, &iter, parent);
2102c6caff2SNamhyung Kim
2112c6caff2SNamhyung Kim callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
2122c6caff2SNamhyung Kim gtk_tree_store_set(store, &iter, 0, buf, -1);
2132c6caff2SNamhyung Kim
2142c6caff2SNamhyung Kim gtk_tree_store_set(store, &iter, col, str, -1);
2152c6caff2SNamhyung Kim
2162c6caff2SNamhyung Kim free(str_alloc);
2172c6caff2SNamhyung Kim }
2182c6caff2SNamhyung Kim }
2192c6caff2SNamhyung Kim
perf_gtk__add_callchain_graph(struct rb_root * root,GtkTreeStore * store,GtkTreeIter * parent,int col,u64 total)2203cd99dfdSNamhyung Kim static void perf_gtk__add_callchain_graph(struct rb_root *root, GtkTreeStore *store,
221cc60f24eSNamhyung Kim GtkTreeIter *parent, int col, u64 total)
2222bbc5874SNamhyung Kim {
2232bbc5874SNamhyung Kim struct rb_node *nd;
2242bbc5874SNamhyung Kim bool has_single_node = (rb_first(root) == rb_last(root));
2252bbc5874SNamhyung Kim
2262bbc5874SNamhyung Kim for (nd = rb_first(root); nd; nd = rb_next(nd)) {
2272bbc5874SNamhyung Kim struct callchain_node *node;
2282bbc5874SNamhyung Kim struct callchain_list *chain;
2292bbc5874SNamhyung Kim GtkTreeIter iter, new_parent;
2302bbc5874SNamhyung Kim bool need_new_parent;
2315ab250caSNamhyung Kim u64 child_total;
2322bbc5874SNamhyung Kim
2332bbc5874SNamhyung Kim node = rb_entry(nd, struct callchain_node, rb_node);
2342bbc5874SNamhyung Kim
2352bbc5874SNamhyung Kim new_parent = *parent;
2362bbc5874SNamhyung Kim need_new_parent = !has_single_node && (node->val_nr > 1);
2372bbc5874SNamhyung Kim
2382bbc5874SNamhyung Kim list_for_each_entry(chain, &node->val, list) {
2392bbc5874SNamhyung Kim char buf[128];
2402bbc5874SNamhyung Kim
2412bbc5874SNamhyung Kim gtk_tree_store_append(store, &iter, &new_parent);
2422bbc5874SNamhyung Kim
2435ab250caSNamhyung Kim callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
244cc60f24eSNamhyung Kim gtk_tree_store_set(store, &iter, 0, buf, -1);
245cc60f24eSNamhyung Kim
2462989ccaaSAndi Kleen callchain_list__sym_name(chain, buf, sizeof(buf), false);
2472bbc5874SNamhyung Kim gtk_tree_store_set(store, &iter, col, buf, -1);
2482bbc5874SNamhyung Kim
2492bbc5874SNamhyung Kim if (need_new_parent) {
2502bbc5874SNamhyung Kim /*
2512bbc5874SNamhyung Kim * Only show the top-most symbol in a callchain
2522bbc5874SNamhyung Kim * if it's not the only callchain.
2532bbc5874SNamhyung Kim */
2542bbc5874SNamhyung Kim new_parent = iter;
2552bbc5874SNamhyung Kim need_new_parent = false;
2562bbc5874SNamhyung Kim }
2572bbc5874SNamhyung Kim }
2582bbc5874SNamhyung Kim
259cc60f24eSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL)
260cc60f24eSNamhyung Kim child_total = node->children_hit;
261cc60f24eSNamhyung Kim else
262cc60f24eSNamhyung Kim child_total = total;
263cc60f24eSNamhyung Kim
2642bbc5874SNamhyung Kim /* Now 'iter' contains info of the last callchain_list */
2653cd99dfdSNamhyung Kim perf_gtk__add_callchain_graph(&node->rb_root, store, &iter, col,
266cc60f24eSNamhyung Kim child_total);
2672bbc5874SNamhyung Kim }
2682bbc5874SNamhyung Kim }
2692bbc5874SNamhyung Kim
perf_gtk__add_callchain(struct rb_root * root,GtkTreeStore * store,GtkTreeIter * parent,int col,u64 total)2703cd99dfdSNamhyung Kim static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
2713cd99dfdSNamhyung Kim GtkTreeIter *parent, int col, u64 total)
2723cd99dfdSNamhyung Kim {
2733cd99dfdSNamhyung Kim if (callchain_param.mode == CHAIN_FLAT)
2743cd99dfdSNamhyung Kim perf_gtk__add_callchain_flat(root, store, parent, col, total);
2752c6caff2SNamhyung Kim else if (callchain_param.mode == CHAIN_FOLDED)
2762c6caff2SNamhyung Kim perf_gtk__add_callchain_folded(root, store, parent, col, total);
2773cd99dfdSNamhyung Kim else
2783cd99dfdSNamhyung Kim perf_gtk__add_callchain_graph(root, store, parent, col, total);
2793cd99dfdSNamhyung Kim }
2803cd99dfdSNamhyung Kim
on_row_activated(GtkTreeView * view,GtkTreePath * path,GtkTreeViewColumn * col __maybe_unused,gpointer user_data __maybe_unused)281450f390aSNamhyung Kim static void on_row_activated(GtkTreeView *view, GtkTreePath *path,
282450f390aSNamhyung Kim GtkTreeViewColumn *col __maybe_unused,
283450f390aSNamhyung Kim gpointer user_data __maybe_unused)
284450f390aSNamhyung Kim {
285450f390aSNamhyung Kim bool expanded = gtk_tree_view_row_expanded(view, path);
286450f390aSNamhyung Kim
287450f390aSNamhyung Kim if (expanded)
288450f390aSNamhyung Kim gtk_tree_view_collapse_row(view, path);
289450f390aSNamhyung Kim else
290450f390aSNamhyung Kim gtk_tree_view_expand_row(view, path, FALSE);
291450f390aSNamhyung Kim }
292450f390aSNamhyung Kim
perf_gtk__show_hists(GtkWidget * window,struct hists * hists,float min_pcnt)293064f1981SNamhyung Kim static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
294064f1981SNamhyung Kim float min_pcnt)
2950da41ce9SNamhyung Kim {
2960da41ce9SNamhyung Kim struct perf_hpp_fmt *fmt;
2970da41ce9SNamhyung Kim GType col_types[MAX_COLUMNS];
2980da41ce9SNamhyung Kim GtkCellRenderer *renderer;
299f1d9a530SNamhyung Kim GtkTreeStore *store;
3000da41ce9SNamhyung Kim struct rb_node *nd;
3010da41ce9SNamhyung Kim GtkWidget *view;
3020da41ce9SNamhyung Kim int col_idx;
3032bbc5874SNamhyung Kim int sym_col = -1;
3040da41ce9SNamhyung Kim int nr_cols;
3050da41ce9SNamhyung Kim char s[512];
3060da41ce9SNamhyung Kim
3070da41ce9SNamhyung Kim struct perf_hpp hpp = {
3080da41ce9SNamhyung Kim .buf = s,
3090da41ce9SNamhyung Kim .size = sizeof(s),
3100da41ce9SNamhyung Kim };
3110da41ce9SNamhyung Kim
3120da41ce9SNamhyung Kim nr_cols = 0;
3130da41ce9SNamhyung Kim
314f0786af5SJiri Olsa hists__for_each_format(hists, fmt)
3150da41ce9SNamhyung Kim col_types[nr_cols++] = G_TYPE_STRING;
3160da41ce9SNamhyung Kim
317f1d9a530SNamhyung Kim store = gtk_tree_store_newv(nr_cols, col_types);
3180da41ce9SNamhyung Kim
3190da41ce9SNamhyung Kim view = gtk_tree_view_new();
3200da41ce9SNamhyung Kim
3210da41ce9SNamhyung Kim renderer = gtk_cell_renderer_text_new();
3220da41ce9SNamhyung Kim
3230da41ce9SNamhyung Kim col_idx = 0;
3240da41ce9SNamhyung Kim
325f0786af5SJiri Olsa hists__for_each_format(hists, fmt) {
326361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, hists))
327e67d49a7SNamhyung Kim continue;
328e67d49a7SNamhyung Kim
329e4cf6f88SNamhyung Kim /*
330e4cf6f88SNamhyung Kim * XXX no way to determine where symcol column is..
331e4cf6f88SNamhyung Kim * Just use last column for now.
332e4cf6f88SNamhyung Kim */
333e4cf6f88SNamhyung Kim if (perf_hpp__is_sort_entry(fmt))
334e4cf6f88SNamhyung Kim sym_col = col_idx;
335e4cf6f88SNamhyung Kim
3360da41ce9SNamhyung Kim gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
3371ecd4453SNamhyung Kim -1, fmt->name,
3380da41ce9SNamhyung Kim renderer, "markup",
3390da41ce9SNamhyung Kim col_idx++, NULL);
3400da41ce9SNamhyung Kim }
3410da41ce9SNamhyung Kim
3421a309426SNamhyung Kim for (col_idx = 0; col_idx < nr_cols; col_idx++) {
3432bbc5874SNamhyung Kim GtkTreeViewColumn *column;
3442bbc5874SNamhyung Kim
3451a309426SNamhyung Kim column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
3461a309426SNamhyung Kim gtk_tree_view_column_set_resizable(column, TRUE);
3471a309426SNamhyung Kim
3481a309426SNamhyung Kim if (col_idx == sym_col) {
3491a309426SNamhyung Kim gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
3501a309426SNamhyung Kim column);
3511a309426SNamhyung Kim }
3522bbc5874SNamhyung Kim }
3532bbc5874SNamhyung Kim
3540da41ce9SNamhyung Kim gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
3550da41ce9SNamhyung Kim
3560da41ce9SNamhyung Kim g_object_unref(GTK_TREE_MODEL(store));
3570da41ce9SNamhyung Kim
3582eb3d689SDavidlohr Bueso for (nd = rb_first_cached(&hists->entries); nd; nd = rb_next(nd)) {
3590da41ce9SNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
3600da41ce9SNamhyung Kim GtkTreeIter iter;
361f2148330SNamhyung Kim u64 total = hists__total_period(h->hists);
36214135663SNamhyung Kim float percent;
3630da41ce9SNamhyung Kim
3640da41ce9SNamhyung Kim if (h->filtered)
3650da41ce9SNamhyung Kim continue;
3660da41ce9SNamhyung Kim
36714135663SNamhyung Kim percent = hist_entry__get_percent_limit(h);
368064f1981SNamhyung Kim if (percent < min_pcnt)
369064f1981SNamhyung Kim continue;
370064f1981SNamhyung Kim
371f1d9a530SNamhyung Kim gtk_tree_store_append(store, &iter, NULL);
3720da41ce9SNamhyung Kim
3730da41ce9SNamhyung Kim col_idx = 0;
3740da41ce9SNamhyung Kim
375f0786af5SJiri Olsa hists__for_each_format(hists, fmt) {
376361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, h->hists))
377e67d49a7SNamhyung Kim continue;
378e67d49a7SNamhyung Kim
3790da41ce9SNamhyung Kim if (fmt->color)
3802c5d4b4aSJiri Olsa fmt->color(fmt, &hpp, h);
3810da41ce9SNamhyung Kim else
3822c5d4b4aSJiri Olsa fmt->entry(fmt, &hpp, h);
3830da41ce9SNamhyung Kim
384f1d9a530SNamhyung Kim gtk_tree_store_set(store, &iter, col_idx++, s, -1);
3850da41ce9SNamhyung Kim }
3860da41ce9SNamhyung Kim
38729f9fcddSArnaldo Carvalho de Melo if (hist_entry__has_callchains(h) &&
388fabd37b8SArnaldo Carvalho de Melo symbol_conf.use_callchain && hists__has(hists, sym)) {
389cc60f24eSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL)
390e4cf6f88SNamhyung Kim total = symbol_conf.cumulate_callchain ?
391e4cf6f88SNamhyung Kim h->stat_acc->period : h->stat.period;
392cc60f24eSNamhyung Kim
3932bbc5874SNamhyung Kim perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
394cc60f24eSNamhyung Kim sym_col, total);
3952bbc5874SNamhyung Kim }
3960da41ce9SNamhyung Kim }
3970da41ce9SNamhyung Kim
3989d58d2f6SNamhyung Kim gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
3999d58d2f6SNamhyung Kim
400450f390aSNamhyung Kim g_signal_connect(view, "row-activated",
401450f390aSNamhyung Kim G_CALLBACK(on_row_activated), NULL);
4020da41ce9SNamhyung Kim gtk_container_add(GTK_CONTAINER(window), view);
4030da41ce9SNamhyung Kim }
4040da41ce9SNamhyung Kim
perf_gtk__add_hierarchy_entries(struct hists * hists,struct rb_root_cached * root,GtkTreeStore * store,GtkTreeIter * parent,struct perf_hpp * hpp,float min_pcnt)405e311ec1eSNamhyung Kim static void perf_gtk__add_hierarchy_entries(struct hists *hists,
4062eb3d689SDavidlohr Bueso struct rb_root_cached *root,
407e311ec1eSNamhyung Kim GtkTreeStore *store,
408e311ec1eSNamhyung Kim GtkTreeIter *parent,
409e311ec1eSNamhyung Kim struct perf_hpp *hpp,
410e311ec1eSNamhyung Kim float min_pcnt)
411e311ec1eSNamhyung Kim {
412e311ec1eSNamhyung Kim int col_idx = 0;
413e311ec1eSNamhyung Kim struct rb_node *node;
414e311ec1eSNamhyung Kim struct hist_entry *he;
415e311ec1eSNamhyung Kim struct perf_hpp_fmt *fmt;
41658ecd33bSNamhyung Kim struct perf_hpp_list_node *fmt_node;
417e311ec1eSNamhyung Kim u64 total = hists__total_period(hists);
41858ecd33bSNamhyung Kim int size;
419e311ec1eSNamhyung Kim
4202eb3d689SDavidlohr Bueso for (node = rb_first_cached(root); node; node = rb_next(node)) {
421e311ec1eSNamhyung Kim GtkTreeIter iter;
422e311ec1eSNamhyung Kim float percent;
4231b2dbbf4SNamhyung Kim char *bf;
424e311ec1eSNamhyung Kim
425e311ec1eSNamhyung Kim he = rb_entry(node, struct hist_entry, rb_node);
426e311ec1eSNamhyung Kim if (he->filtered)
427e311ec1eSNamhyung Kim continue;
428e311ec1eSNamhyung Kim
429e311ec1eSNamhyung Kim percent = hist_entry__get_percent_limit(he);
430e311ec1eSNamhyung Kim if (percent < min_pcnt)
431e311ec1eSNamhyung Kim continue;
432e311ec1eSNamhyung Kim
433e311ec1eSNamhyung Kim gtk_tree_store_append(store, &iter, parent);
434e311ec1eSNamhyung Kim
435e311ec1eSNamhyung Kim col_idx = 0;
436e311ec1eSNamhyung Kim
43758ecd33bSNamhyung Kim /* the first hpp_list_node is for overhead columns */
43858ecd33bSNamhyung Kim fmt_node = list_first_entry(&hists->hpp_formats,
43958ecd33bSNamhyung Kim struct perf_hpp_list_node, list);
44058ecd33bSNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
441e311ec1eSNamhyung Kim if (fmt->color)
442e311ec1eSNamhyung Kim fmt->color(fmt, hpp, he);
443e311ec1eSNamhyung Kim else
444e311ec1eSNamhyung Kim fmt->entry(fmt, hpp, he);
445e311ec1eSNamhyung Kim
446e311ec1eSNamhyung Kim gtk_tree_store_set(store, &iter, col_idx++, hpp->buf, -1);
447e311ec1eSNamhyung Kim }
448e311ec1eSNamhyung Kim
4491b2dbbf4SNamhyung Kim bf = hpp->buf;
45058ecd33bSNamhyung Kim size = hpp->size;
4511b2dbbf4SNamhyung Kim perf_hpp_list__for_each_format(he->hpp_list, fmt) {
4521b2dbbf4SNamhyung Kim int ret;
453e311ec1eSNamhyung Kim
4541b2dbbf4SNamhyung Kim if (fmt->color)
4551b2dbbf4SNamhyung Kim ret = fmt->color(fmt, hpp, he);
4561b2dbbf4SNamhyung Kim else
4571b2dbbf4SNamhyung Kim ret = fmt->entry(fmt, hpp, he);
4581b2dbbf4SNamhyung Kim
4591b2dbbf4SNamhyung Kim snprintf(hpp->buf + ret, hpp->size - ret, " ");
4601b2dbbf4SNamhyung Kim advance_hpp(hpp, ret + 2);
4611b2dbbf4SNamhyung Kim }
4621b2dbbf4SNamhyung Kim
4633ca43b60SArnaldo Carvalho de Melo gtk_tree_store_set(store, &iter, col_idx, strim(bf), -1);
464e311ec1eSNamhyung Kim
465e311ec1eSNamhyung Kim if (!he->leaf) {
46658ecd33bSNamhyung Kim hpp->buf = bf;
46758ecd33bSNamhyung Kim hpp->size = size;
46858ecd33bSNamhyung Kim
469e311ec1eSNamhyung Kim perf_gtk__add_hierarchy_entries(hists, &he->hroot_out,
470e311ec1eSNamhyung Kim store, &iter, hpp,
471e311ec1eSNamhyung Kim min_pcnt);
4722ddda792SNamhyung Kim
4732ddda792SNamhyung Kim if (!hist_entry__has_hierarchy_children(he, min_pcnt)) {
4742ddda792SNamhyung Kim char buf[32];
4752ddda792SNamhyung Kim GtkTreeIter child;
4762ddda792SNamhyung Kim
4772ddda792SNamhyung Kim snprintf(buf, sizeof(buf), "no entry >= %.2f%%",
4782ddda792SNamhyung Kim min_pcnt);
4792ddda792SNamhyung Kim
4802ddda792SNamhyung Kim gtk_tree_store_append(store, &child, &iter);
4812ddda792SNamhyung Kim gtk_tree_store_set(store, &child, col_idx, buf, -1);
4822ddda792SNamhyung Kim }
483e311ec1eSNamhyung Kim }
484e311ec1eSNamhyung Kim
485fabd37b8SArnaldo Carvalho de Melo if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
486e311ec1eSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL)
487e311ec1eSNamhyung Kim total = symbol_conf.cumulate_callchain ?
488e311ec1eSNamhyung Kim he->stat_acc->period : he->stat.period;
489e311ec1eSNamhyung Kim
490e311ec1eSNamhyung Kim perf_gtk__add_callchain(&he->sorted_chain, store, &iter,
491e311ec1eSNamhyung Kim col_idx, total);
492e311ec1eSNamhyung Kim }
493e311ec1eSNamhyung Kim }
494e311ec1eSNamhyung Kim
495e311ec1eSNamhyung Kim }
496e311ec1eSNamhyung Kim
perf_gtk__show_hierarchy(GtkWidget * window,struct hists * hists,float min_pcnt)497e311ec1eSNamhyung Kim static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
498e311ec1eSNamhyung Kim float min_pcnt)
499e311ec1eSNamhyung Kim {
500e311ec1eSNamhyung Kim struct perf_hpp_fmt *fmt;
50158ecd33bSNamhyung Kim struct perf_hpp_list_node *fmt_node;
502e311ec1eSNamhyung Kim GType col_types[MAX_COLUMNS];
503e311ec1eSNamhyung Kim GtkCellRenderer *renderer;
504e311ec1eSNamhyung Kim GtkTreeStore *store;
505e311ec1eSNamhyung Kim GtkWidget *view;
506e311ec1eSNamhyung Kim int col_idx;
507e311ec1eSNamhyung Kim int nr_cols = 0;
508e311ec1eSNamhyung Kim char s[512];
509e311ec1eSNamhyung Kim char buf[512];
51058ecd33bSNamhyung Kim bool first_node, first_col;
511e311ec1eSNamhyung Kim struct perf_hpp hpp = {
512e311ec1eSNamhyung Kim .buf = s,
513e311ec1eSNamhyung Kim .size = sizeof(s),
514e311ec1eSNamhyung Kim };
515e311ec1eSNamhyung Kim
516e311ec1eSNamhyung Kim hists__for_each_format(hists, fmt) {
517e311ec1eSNamhyung Kim if (perf_hpp__is_sort_entry(fmt) ||
518e311ec1eSNamhyung Kim perf_hpp__is_dynamic_entry(fmt))
519e311ec1eSNamhyung Kim break;
520e311ec1eSNamhyung Kim
521e311ec1eSNamhyung Kim col_types[nr_cols++] = G_TYPE_STRING;
522e311ec1eSNamhyung Kim }
523e311ec1eSNamhyung Kim col_types[nr_cols++] = G_TYPE_STRING;
524e311ec1eSNamhyung Kim
525e311ec1eSNamhyung Kim store = gtk_tree_store_newv(nr_cols, col_types);
526e311ec1eSNamhyung Kim view = gtk_tree_view_new();
527e311ec1eSNamhyung Kim renderer = gtk_cell_renderer_text_new();
528e311ec1eSNamhyung Kim
529e311ec1eSNamhyung Kim col_idx = 0;
530e311ec1eSNamhyung Kim
53158ecd33bSNamhyung Kim /* the first hpp_list_node is for overhead columns */
53258ecd33bSNamhyung Kim fmt_node = list_first_entry(&hists->hpp_formats,
53358ecd33bSNamhyung Kim struct perf_hpp_list_node, list);
53458ecd33bSNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
535e311ec1eSNamhyung Kim gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
536e311ec1eSNamhyung Kim -1, fmt->name,
537e311ec1eSNamhyung Kim renderer, "markup",
538e311ec1eSNamhyung Kim col_idx++, NULL);
539e311ec1eSNamhyung Kim }
540e311ec1eSNamhyung Kim
541e311ec1eSNamhyung Kim /* construct merged column header since sort keys share single column */
542e311ec1eSNamhyung Kim buf[0] = '\0';
54358ecd33bSNamhyung Kim first_node = true;
54458ecd33bSNamhyung Kim list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
54558ecd33bSNamhyung Kim if (!first_node)
54658ecd33bSNamhyung Kim strcat(buf, " / ");
54758ecd33bSNamhyung Kim first_node = false;
54858ecd33bSNamhyung Kim
54958ecd33bSNamhyung Kim first_col = true;
55058ecd33bSNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp ,fmt) {
551e311ec1eSNamhyung Kim if (perf_hpp__should_skip(fmt, hists))
552e311ec1eSNamhyung Kim continue;
553e311ec1eSNamhyung Kim
55458ecd33bSNamhyung Kim if (!first_col)
55558ecd33bSNamhyung Kim strcat(buf, "+");
55658ecd33bSNamhyung Kim first_col = false;
557e311ec1eSNamhyung Kim
55829659ab4SJiri Olsa fmt->header(fmt, &hpp, hists, 0, NULL);
5593ca43b60SArnaldo Carvalho de Melo strcat(buf, strim(hpp.buf));
56058ecd33bSNamhyung Kim }
561e311ec1eSNamhyung Kim }
562e311ec1eSNamhyung Kim
563e311ec1eSNamhyung Kim gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
564e311ec1eSNamhyung Kim -1, buf,
565e311ec1eSNamhyung Kim renderer, "markup",
566e311ec1eSNamhyung Kim col_idx++, NULL);
567e311ec1eSNamhyung Kim
568e311ec1eSNamhyung Kim for (col_idx = 0; col_idx < nr_cols; col_idx++) {
569e311ec1eSNamhyung Kim GtkTreeViewColumn *column;
570e311ec1eSNamhyung Kim
571e311ec1eSNamhyung Kim column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
572e311ec1eSNamhyung Kim gtk_tree_view_column_set_resizable(column, TRUE);
573e311ec1eSNamhyung Kim
574e311ec1eSNamhyung Kim if (col_idx == 0) {
575e311ec1eSNamhyung Kim gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
576e311ec1eSNamhyung Kim column);
577e311ec1eSNamhyung Kim }
578e311ec1eSNamhyung Kim }
579e311ec1eSNamhyung Kim
580e311ec1eSNamhyung Kim gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
581e311ec1eSNamhyung Kim g_object_unref(GTK_TREE_MODEL(store));
582e311ec1eSNamhyung Kim
583e311ec1eSNamhyung Kim perf_gtk__add_hierarchy_entries(hists, &hists->entries, store,
584e311ec1eSNamhyung Kim NULL, &hpp, min_pcnt);
585e311ec1eSNamhyung Kim
586e311ec1eSNamhyung Kim gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
587e311ec1eSNamhyung Kim
588e311ec1eSNamhyung Kim g_signal_connect(view, "row-activated",
589e311ec1eSNamhyung Kim G_CALLBACK(on_row_activated), NULL);
590e311ec1eSNamhyung Kim gtk_container_add(GTK_CONTAINER(window), view);
591e311ec1eSNamhyung Kim }
592e311ec1eSNamhyung Kim
evlist__gtk_browse_hists(struct evlist * evlist,const char * help,struct hist_browser_timer * hbt __maybe_unused,float min_pcnt)593f4bd0b4aSArnaldo Carvalho de Melo int evlist__gtk_browse_hists(struct evlist *evlist, const char *help,
594f4bd0b4aSArnaldo Carvalho de Melo struct hist_browser_timer *hbt __maybe_unused, float min_pcnt)
5950da41ce9SNamhyung Kim {
59632dcd021SJiri Olsa struct evsel *pos;
5970da41ce9SNamhyung Kim GtkWidget *vbox;
5980da41ce9SNamhyung Kim GtkWidget *notebook;
5990da41ce9SNamhyung Kim GtkWidget *info_bar;
6000da41ce9SNamhyung Kim GtkWidget *statbar;
6010da41ce9SNamhyung Kim GtkWidget *window;
6020da41ce9SNamhyung Kim
6030da41ce9SNamhyung Kim signal(SIGSEGV, perf_gtk__signal);
6040da41ce9SNamhyung Kim signal(SIGFPE, perf_gtk__signal);
6050da41ce9SNamhyung Kim signal(SIGINT, perf_gtk__signal);
6060da41ce9SNamhyung Kim signal(SIGQUIT, perf_gtk__signal);
6070da41ce9SNamhyung Kim signal(SIGTERM, perf_gtk__signal);
6080da41ce9SNamhyung Kim
6090da41ce9SNamhyung Kim window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
6100da41ce9SNamhyung Kim
6110da41ce9SNamhyung Kim gtk_window_set_title(GTK_WINDOW(window), "perf report");
6120da41ce9SNamhyung Kim
6130da41ce9SNamhyung Kim g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
6140da41ce9SNamhyung Kim
6150da41ce9SNamhyung Kim pgctx = perf_gtk__activate_context(window);
6160da41ce9SNamhyung Kim if (!pgctx)
6170da41ce9SNamhyung Kim return -1;
6180da41ce9SNamhyung Kim
6190da41ce9SNamhyung Kim vbox = gtk_vbox_new(FALSE, 0);
6200da41ce9SNamhyung Kim
6210da41ce9SNamhyung Kim notebook = gtk_notebook_new();
6220da41ce9SNamhyung Kim
6236bf1a295SNamhyung Kim gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
6246bf1a295SNamhyung Kim
6256bf1a295SNamhyung Kim info_bar = perf_gtk__setup_info_bar();
6266bf1a295SNamhyung Kim if (info_bar)
6276bf1a295SNamhyung Kim gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
6286bf1a295SNamhyung Kim
6296bf1a295SNamhyung Kim statbar = perf_gtk__setup_statusbar();
6306bf1a295SNamhyung Kim gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
6316bf1a295SNamhyung Kim
6326bf1a295SNamhyung Kim gtk_container_add(GTK_CONTAINER(window), vbox);
6336bf1a295SNamhyung Kim
634e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist, pos) {
6354ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(pos);
6368ab2e96dSArnaldo Carvalho de Melo const char *evname = evsel__name(pos);
6370da41ce9SNamhyung Kim GtkWidget *scrolled_window;
6380da41ce9SNamhyung Kim GtkWidget *tab_label;
639717e263fSNamhyung Kim char buf[512];
640717e263fSNamhyung Kim size_t size = sizeof(buf);
6410da41ce9SNamhyung Kim
642717e263fSNamhyung Kim if (symbol_conf.event_group) {
643c754c382SArnaldo Carvalho de Melo if (!evsel__is_group_leader(pos))
644fc24d7c2SNamhyung Kim continue;
645fc24d7c2SNamhyung Kim
6465643b1a5SJiri Olsa if (pos->core.nr_members > 1) {
647347c751aSArnaldo Carvalho de Melo evsel__group_desc(pos, buf, size);
648717e263fSNamhyung Kim evname = buf;
649717e263fSNamhyung Kim }
650717e263fSNamhyung Kim }
651717e263fSNamhyung Kim
6520da41ce9SNamhyung Kim scrolled_window = gtk_scrolled_window_new(NULL, NULL);
6530da41ce9SNamhyung Kim
6540da41ce9SNamhyung Kim gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
6550da41ce9SNamhyung Kim GTK_POLICY_AUTOMATIC,
6560da41ce9SNamhyung Kim GTK_POLICY_AUTOMATIC);
6570da41ce9SNamhyung Kim
658e311ec1eSNamhyung Kim if (symbol_conf.report_hierarchy)
659e311ec1eSNamhyung Kim perf_gtk__show_hierarchy(scrolled_window, hists, min_pcnt);
660e311ec1eSNamhyung Kim else
661064f1981SNamhyung Kim perf_gtk__show_hists(scrolled_window, hists, min_pcnt);
6620da41ce9SNamhyung Kim
6630da41ce9SNamhyung Kim tab_label = gtk_label_new(evname);
6640da41ce9SNamhyung Kim
6650da41ce9SNamhyung Kim gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
6660da41ce9SNamhyung Kim }
6670da41ce9SNamhyung Kim
6680da41ce9SNamhyung Kim gtk_widget_show_all(window);
6690da41ce9SNamhyung Kim
6700da41ce9SNamhyung Kim perf_gtk__resize_window(window);
6710da41ce9SNamhyung Kim
6720da41ce9SNamhyung Kim gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
6730da41ce9SNamhyung Kim
6740da41ce9SNamhyung Kim ui_helpline__push(help);
6750da41ce9SNamhyung Kim
6760da41ce9SNamhyung Kim gtk_main();
6770da41ce9SNamhyung Kim
6780da41ce9SNamhyung Kim perf_gtk__deactivate_context(&pgctx);
6790da41ce9SNamhyung Kim
6800da41ce9SNamhyung Kim return 0;
6810da41ce9SNamhyung Kim }
682