aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/ui/gtk/hists.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/ui/gtk/hists.c')
-rw-r--r--tools/perf/ui/gtk/hists.c128
1 files changed, 117 insertions, 11 deletions
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 9708dd5fb8f3..2ca66cc1160f 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -91,7 +91,8 @@ static u64 he_get_##_field(struct hist_entry *he) \
91 return he->stat._field; \ 91 return he->stat._field; \
92} \ 92} \
93 \ 93 \
94static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp, \ 94static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
95 struct perf_hpp *hpp, \
95 struct hist_entry *he) \ 96 struct hist_entry *he) \
96{ \ 97{ \
97 return __hpp__color_fmt(hpp, he, he_get_##_field); \ 98 return __hpp__color_fmt(hpp, he, he_get_##_field); \
@@ -108,8 +109,6 @@ __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
108 109
109void perf_gtk__init_hpp(void) 110void perf_gtk__init_hpp(void)
110{ 111{
111 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
112
113 perf_hpp__init(); 112 perf_hpp__init();
114 113
115 perf_hpp__format[PERF_HPP__OVERHEAD].color = 114 perf_hpp__format[PERF_HPP__OVERHEAD].color =
@@ -124,6 +123,81 @@ void perf_gtk__init_hpp(void)
124 perf_gtk__hpp_color_overhead_guest_us; 123 perf_gtk__hpp_color_overhead_guest_us;
125} 124}
126 125
126static void callchain_list__sym_name(struct callchain_list *cl,
127 char *bf, size_t bfsize)
128{
129 if (cl->ms.sym)
130 scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
131 else
132 scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
133}
134
135static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
136 GtkTreeIter *parent, int col, u64 total)
137{
138 struct rb_node *nd;
139 bool has_single_node = (rb_first(root) == rb_last(root));
140
141 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
142 struct callchain_node *node;
143 struct callchain_list *chain;
144 GtkTreeIter iter, new_parent;
145 bool need_new_parent;
146 double percent;
147 u64 hits, child_total;
148
149 node = rb_entry(nd, struct callchain_node, rb_node);
150
151 hits = callchain_cumul_hits(node);
152 percent = 100.0 * hits / total;
153
154 new_parent = *parent;
155 need_new_parent = !has_single_node && (node->val_nr > 1);
156
157 list_for_each_entry(chain, &node->val, list) {
158 char buf[128];
159
160 gtk_tree_store_append(store, &iter, &new_parent);
161
162 scnprintf(buf, sizeof(buf), "%5.2f%%", percent);
163 gtk_tree_store_set(store, &iter, 0, buf, -1);
164
165 callchain_list__sym_name(chain, buf, sizeof(buf));
166 gtk_tree_store_set(store, &iter, col, buf, -1);
167
168 if (need_new_parent) {
169 /*
170 * Only show the top-most symbol in a callchain
171 * if it's not the only callchain.
172 */
173 new_parent = iter;
174 need_new_parent = false;
175 }
176 }
177
178 if (callchain_param.mode == CHAIN_GRAPH_REL)
179 child_total = node->children_hit;
180 else
181 child_total = total;
182
183 /* Now 'iter' contains info of the last callchain_list */
184 perf_gtk__add_callchain(&node->rb_root, store, &iter, col,
185 child_total);
186 }
187}
188
189static void on_row_activated(GtkTreeView *view, GtkTreePath *path,
190 GtkTreeViewColumn *col __maybe_unused,
191 gpointer user_data __maybe_unused)
192{
193 bool expanded = gtk_tree_view_row_expanded(view, path);
194
195 if (expanded)
196 gtk_tree_view_collapse_row(view, path);
197 else
198 gtk_tree_view_expand_row(view, path, FALSE);
199}
200
127static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, 201static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
128 float min_pcnt) 202 float min_pcnt)
129{ 203{
@@ -131,10 +205,11 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
131 GType col_types[MAX_COLUMNS]; 205 GType col_types[MAX_COLUMNS];
132 GtkCellRenderer *renderer; 206 GtkCellRenderer *renderer;
133 struct sort_entry *se; 207 struct sort_entry *se;
134 GtkListStore *store; 208 GtkTreeStore *store;
135 struct rb_node *nd; 209 struct rb_node *nd;
136 GtkWidget *view; 210 GtkWidget *view;
137 int col_idx; 211 int col_idx;
212 int sym_col = -1;
138 int nr_cols; 213 int nr_cols;
139 char s[512]; 214 char s[512];
140 215
@@ -153,10 +228,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
153 if (se->elide) 228 if (se->elide)
154 continue; 229 continue;
155 230
231 if (se == &sort_sym)
232 sym_col = nr_cols;
233
156 col_types[nr_cols++] = G_TYPE_STRING; 234 col_types[nr_cols++] = G_TYPE_STRING;
157 } 235 }
158 236
159 store = gtk_list_store_newv(nr_cols, col_types); 237 store = gtk_tree_store_newv(nr_cols, col_types);
160 238
161 view = gtk_tree_view_new(); 239 view = gtk_tree_view_new();
162 240
@@ -165,7 +243,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
165 col_idx = 0; 243 col_idx = 0;
166 244
167 perf_hpp__for_each_format(fmt) { 245 perf_hpp__for_each_format(fmt) {
168 fmt->header(&hpp); 246 fmt->header(fmt, &hpp);
169 247
170 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), 248 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
171 -1, ltrim(s), 249 -1, ltrim(s),
@@ -183,6 +261,18 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
183 col_idx++, NULL); 261 col_idx++, NULL);
184 } 262 }
185 263
264 for (col_idx = 0; col_idx < nr_cols; col_idx++) {
265 GtkTreeViewColumn *column;
266
267 column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
268 gtk_tree_view_column_set_resizable(column, TRUE);
269
270 if (col_idx == sym_col) {
271 gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
272 column);
273 }
274 }
275
186 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); 276 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
187 277
188 g_object_unref(GTK_TREE_MODEL(store)); 278 g_object_unref(GTK_TREE_MODEL(store));
@@ -199,17 +289,17 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
199 if (percent < min_pcnt) 289 if (percent < min_pcnt)
200 continue; 290 continue;
201 291
202 gtk_list_store_append(store, &iter); 292 gtk_tree_store_append(store, &iter, NULL);
203 293
204 col_idx = 0; 294 col_idx = 0;
205 295
206 perf_hpp__for_each_format(fmt) { 296 perf_hpp__for_each_format(fmt) {
207 if (fmt->color) 297 if (fmt->color)
208 fmt->color(&hpp, h); 298 fmt->color(fmt, &hpp, h);
209 else 299 else
210 fmt->entry(&hpp, h); 300 fmt->entry(fmt, &hpp, h);
211 301
212 gtk_list_store_set(store, &iter, col_idx++, s, -1); 302 gtk_tree_store_set(store, &iter, col_idx++, s, -1);
213 } 303 }
214 304
215 list_for_each_entry(se, &hist_entry__sort_list, list) { 305 list_for_each_entry(se, &hist_entry__sort_list, list) {
@@ -219,10 +309,26 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
219 se->se_snprintf(h, s, ARRAY_SIZE(s), 309 se->se_snprintf(h, s, ARRAY_SIZE(s),
220 hists__col_len(hists, se->se_width_idx)); 310 hists__col_len(hists, se->se_width_idx));
221 311
222 gtk_list_store_set(store, &iter, col_idx++, s, -1); 312 gtk_tree_store_set(store, &iter, col_idx++, s, -1);
313 }
314
315 if (symbol_conf.use_callchain && sort__has_sym) {
316 u64 total;
317
318 if (callchain_param.mode == CHAIN_GRAPH_REL)
319 total = h->stat.period;
320 else
321 total = hists->stats.total_period;
322
323 perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
324 sym_col, total);
223 } 325 }
224 } 326 }
225 327
328 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
329
330 g_signal_connect(view, "row-activated",
331 G_CALLBACK(on_row_activated), NULL);
226 gtk_container_add(GTK_CONTAINER(window), view); 332 gtk_container_add(GTK_CONTAINER(window), view);
227} 333}
228 334