perf ui/gtk: Support flat callchains
authorNamhyung Kim <namhyung@kernel.org>
Mon, 9 Nov 2015 05:45:45 +0000 (14:45 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 19 Nov 2015 16:19:25 +0000 (13:19 -0300)
The flat callchain mode is to print all chains in a simple flat
hierarchy so make it easy to see.

Currently perf report --gtk doesn't show flat callchains properly.  With
flat callchains, only leaf nodes are added to the final rbtree so it
should show entries in parent nodes.  To do that, add parent_val list to
struct callchain_node and show them along with the (normal) val list.

See the previous commit on TUI support for more information.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Tested-by: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Kan Liang <kan.liang@intel.com>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1447047946-1691-10-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/ui/gtk/hists.c

index cff7bb9d9632b579bec481cb6b7a73486dccbc47..0b24cd6d38a4bff1536792355479a3e5471e49eb 100644 (file)
@@ -89,8 +89,71 @@ 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));
+
+       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;
+
+               node = rb_entry(nd, struct callchain_node, rb_node);
+
+               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_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));
@@ -134,11 +197,20 @@ 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
+               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)