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