diff options
author | Namhyung Kim <namhyung.kim@lge.com> | 2013-06-04 05:22:13 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2013-07-12 12:52:38 -0400 |
commit | 2bbc5874251830fee170a0fc97fa5788717d2fd9 (patch) | |
tree | 1d17cbb47f945bed98ff7fbae3b1b5550a44cfab | |
parent | f1d9a530553eed9e598d1597a2a348f01810dd4a (diff) |
perf gtk/hists: Add support for callchains
Display callchain information in the symbol column. It's only enabled
when recorded with -g and has symbol sort key.
Reviewed-by: Pekka Enberg <penberg@kernel.org>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1370337737-30812-3-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/ui/gtk/hists.c | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index cb6a9b45f789..226c7e10f3cc 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c | |||
@@ -124,6 +124,55 @@ void perf_gtk__init_hpp(void) | |||
124 | perf_gtk__hpp_color_overhead_guest_us; | 124 | perf_gtk__hpp_color_overhead_guest_us; |
125 | } | 125 | } |
126 | 126 | ||
127 | static void callchain_list__sym_name(struct callchain_list *cl, | ||
128 | char *bf, size_t bfsize) | ||
129 | { | ||
130 | if (cl->ms.sym) | ||
131 | scnprintf(bf, bfsize, "%s", cl->ms.sym->name); | ||
132 | else | ||
133 | scnprintf(bf, bfsize, "%#" PRIx64, cl->ip); | ||
134 | } | ||
135 | |||
136 | static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, | ||
137 | GtkTreeIter *parent, int col) | ||
138 | { | ||
139 | struct rb_node *nd; | ||
140 | bool has_single_node = (rb_first(root) == rb_last(root)); | ||
141 | |||
142 | for (nd = rb_first(root); nd; nd = rb_next(nd)) { | ||
143 | struct callchain_node *node; | ||
144 | struct callchain_list *chain; | ||
145 | GtkTreeIter iter, new_parent; | ||
146 | bool need_new_parent; | ||
147 | |||
148 | node = rb_entry(nd, struct callchain_node, rb_node); | ||
149 | |||
150 | new_parent = *parent; | ||
151 | need_new_parent = !has_single_node && (node->val_nr > 1); | ||
152 | |||
153 | list_for_each_entry(chain, &node->val, list) { | ||
154 | char buf[128]; | ||
155 | |||
156 | gtk_tree_store_append(store, &iter, &new_parent); | ||
157 | |||
158 | callchain_list__sym_name(chain, buf, sizeof(buf)); | ||
159 | gtk_tree_store_set(store, &iter, col, buf, -1); | ||
160 | |||
161 | if (need_new_parent) { | ||
162 | /* | ||
163 | * Only show the top-most symbol in a callchain | ||
164 | * if it's not the only callchain. | ||
165 | */ | ||
166 | new_parent = iter; | ||
167 | need_new_parent = false; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | /* Now 'iter' contains info of the last callchain_list */ | ||
172 | perf_gtk__add_callchain(&node->rb_root, store, &iter, col); | ||
173 | } | ||
174 | } | ||
175 | |||
127 | static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | 176 | static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, |
128 | float min_pcnt) | 177 | float min_pcnt) |
129 | { | 178 | { |
@@ -135,6 +184,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | |||
135 | struct rb_node *nd; | 184 | struct rb_node *nd; |
136 | GtkWidget *view; | 185 | GtkWidget *view; |
137 | int col_idx; | 186 | int col_idx; |
187 | int sym_col = -1; | ||
138 | int nr_cols; | 188 | int nr_cols; |
139 | char s[512]; | 189 | char s[512]; |
140 | 190 | ||
@@ -153,6 +203,9 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | |||
153 | if (se->elide) | 203 | if (se->elide) |
154 | continue; | 204 | continue; |
155 | 205 | ||
206 | if (se == &sort_sym) | ||
207 | sym_col = nr_cols; | ||
208 | |||
156 | col_types[nr_cols++] = G_TYPE_STRING; | 209 | col_types[nr_cols++] = G_TYPE_STRING; |
157 | } | 210 | } |
158 | 211 | ||
@@ -183,6 +236,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | |||
183 | col_idx++, NULL); | 236 | col_idx++, NULL); |
184 | } | 237 | } |
185 | 238 | ||
239 | if (symbol_conf.use_callchain && sort__has_sym) { | ||
240 | GtkTreeViewColumn *column; | ||
241 | |||
242 | column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), sym_col); | ||
243 | gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view), column); | ||
244 | } | ||
245 | |||
186 | gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); | 246 | gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); |
187 | 247 | ||
188 | g_object_unref(GTK_TREE_MODEL(store)); | 248 | g_object_unref(GTK_TREE_MODEL(store)); |
@@ -221,6 +281,11 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | |||
221 | 281 | ||
222 | gtk_tree_store_set(store, &iter, col_idx++, s, -1); | 282 | gtk_tree_store_set(store, &iter, col_idx++, s, -1); |
223 | } | 283 | } |
284 | |||
285 | if (symbol_conf.use_callchain && sort__has_sym) { | ||
286 | perf_gtk__add_callchain(&h->sorted_chain, store, &iter, | ||
287 | sym_col); | ||
288 | } | ||
224 | } | 289 | } |
225 | 290 | ||
226 | gtk_container_add(GTK_CONTAINER(window), view); | 291 | gtk_container_add(GTK_CONTAINER(window), view); |