diff options
Diffstat (limited to 'tools/perf/ui/gtk/hists.c')
-rw-r--r-- | tools/perf/ui/gtk/hists.c | 152 |
1 files changed, 141 insertions, 11 deletions
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 4b3585eed..0f8dcfdfb 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -89,8 +89,8 @@ void perf_gtk__init_hpp(void) perf_gtk__hpp_color_overhead_acc; } -static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, - GtkTreeIter *parent, int col, u64 total) +static void perf_gtk__add_callchain_flat(struct rb_root *root, GtkTreeStore *store, + GtkTreeIter *parent, int col, u64 total) { struct rb_node *nd; bool has_single_node = (rb_first(root) == rb_last(root)); @@ -100,13 +100,132 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, struct callchain_list *chain; GtkTreeIter iter, new_parent; bool need_new_parent; - double percent; - u64 hits, child_total; node = rb_entry(nd, struct callchain_node, rb_node); - hits = callchain_cumul_hits(node); - percent = 100.0 * hits / total; + new_parent = *parent; + need_new_parent = !has_single_node; + + callchain_node__make_parent_list(node); + + list_for_each_entry(chain, &node->parent_val, list) { + char buf[128]; + + gtk_tree_store_append(store, &iter, &new_parent); + + callchain_node__scnprintf_value(node, buf, sizeof(buf), total); + gtk_tree_store_set(store, &iter, 0, buf, -1); + + callchain_list__sym_name(chain, buf, sizeof(buf), false); + gtk_tree_store_set(store, &iter, col, buf, -1); + + if (need_new_parent) { + /* + * Only show the top-most symbol in a callchain + * if it's not the only callchain. + */ + new_parent = iter; + need_new_parent = false; + } + } + + list_for_each_entry(chain, &node->val, list) { + char buf[128]; + + gtk_tree_store_append(store, &iter, &new_parent); + + callchain_node__scnprintf_value(node, buf, sizeof(buf), total); + gtk_tree_store_set(store, &iter, 0, buf, -1); + + callchain_list__sym_name(chain, buf, sizeof(buf), false); + gtk_tree_store_set(store, &iter, col, buf, -1); + + if (need_new_parent) { + /* + * Only show the top-most symbol in a callchain + * if it's not the only callchain. + */ + new_parent = iter; + need_new_parent = false; + } + } + } +} + +static void perf_gtk__add_callchain_folded(struct rb_root *root, GtkTreeStore *store, + GtkTreeIter *parent, int col, u64 total) +{ + struct rb_node *nd; + + for (nd = rb_first(root); nd; nd = rb_next(nd)) { + struct callchain_node *node; + struct callchain_list *chain; + GtkTreeIter iter; + char buf[64]; + char *str, *str_alloc = NULL; + bool first = true; + + node = rb_entry(nd, struct callchain_node, rb_node); + + callchain_node__make_parent_list(node); + + list_for_each_entry(chain, &node->parent_val, list) { + char name[1024]; + + callchain_list__sym_name(chain, name, sizeof(name), false); + + if (asprintf(&str, "%s%s%s", + first ? "" : str_alloc, + first ? "" : symbol_conf.field_sep ?: "; ", + name) < 0) + return; + + first = false; + free(str_alloc); + str_alloc = str; + } + + list_for_each_entry(chain, &node->val, list) { + char name[1024]; + + callchain_list__sym_name(chain, name, sizeof(name), false); + + if (asprintf(&str, "%s%s%s", + first ? "" : str_alloc, + first ? "" : symbol_conf.field_sep ?: "; ", + name) < 0) + return; + + first = false; + free(str_alloc); + str_alloc = str; + } + + gtk_tree_store_append(store, &iter, parent); + + callchain_node__scnprintf_value(node, buf, sizeof(buf), total); + gtk_tree_store_set(store, &iter, 0, buf, -1); + + gtk_tree_store_set(store, &iter, col, str, -1); + + free(str_alloc); + } +} + +static void perf_gtk__add_callchain_graph(struct rb_root *root, GtkTreeStore *store, + GtkTreeIter *parent, int col, u64 total) +{ + struct rb_node *nd; + bool has_single_node = (rb_first(root) == rb_last(root)); + + for (nd = rb_first(root); nd; nd = rb_next(nd)) { + struct callchain_node *node; + struct callchain_list *chain; + GtkTreeIter iter, new_parent; + bool need_new_parent; + u64 child_total; + + node = rb_entry(nd, struct callchain_node, rb_node); new_parent = *parent; need_new_parent = !has_single_node && (node->val_nr > 1); @@ -116,7 +235,7 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, gtk_tree_store_append(store, &iter, &new_parent); - scnprintf(buf, sizeof(buf), "%5.2f%%", percent); + callchain_node__scnprintf_value(node, buf, sizeof(buf), total); gtk_tree_store_set(store, &iter, 0, buf, -1); callchain_list__sym_name(chain, buf, sizeof(buf), false); @@ -138,11 +257,22 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, child_total = total; /* Now 'iter' contains info of the last callchain_list */ - perf_gtk__add_callchain(&node->rb_root, store, &iter, col, - child_total); + perf_gtk__add_callchain_graph(&node->rb_root, store, &iter, col, + child_total); } } +static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, + GtkTreeIter *parent, int col, u64 total) +{ + if (callchain_param.mode == CHAIN_FLAT) + perf_gtk__add_callchain_flat(root, store, parent, col, total); + else if (callchain_param.mode == CHAIN_FOLDED) + perf_gtk__add_callchain_folded(root, store, parent, col, total); + else + perf_gtk__add_callchain_graph(root, store, parent, col, total); +} + static void on_row_activated(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *col __maybe_unused, gpointer user_data __maybe_unused) @@ -188,7 +318,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, col_idx = 0; perf_hpp__for_each_format(fmt) { - if (perf_hpp__should_skip(fmt)) + if (perf_hpp__should_skip(fmt, hists)) continue; /* @@ -238,7 +368,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, col_idx = 0; perf_hpp__for_each_format(fmt) { - if (perf_hpp__should_skip(fmt)) + if (perf_hpp__should_skip(fmt, h->hists)) continue; if (fmt->color) |