diff options
Diffstat (limited to 'tools/perf/ui/gtk/hists.c')
-rw-r--r-- | tools/perf/ui/gtk/hists.c | 128 |
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 | \ |
94 | static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp, \ | 94 | static 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 | ||
109 | void perf_gtk__init_hpp(void) | 110 | void 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 | ||
126 | static 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 | |||
135 | static 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 | |||
189 | static 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 | |||
127 | static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | 201 | static 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 | ||