diff options
Diffstat (limited to 'tools/perf/ui/gtk/hists.c')
-rw-r--r-- | tools/perf/ui/gtk/hists.c | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c new file mode 100644 index 000000000000..1e764a8ad259 --- /dev/null +++ b/tools/perf/ui/gtk/hists.c | |||
@@ -0,0 +1,312 @@ | |||
1 | #include "../evlist.h" | ||
2 | #include "../cache.h" | ||
3 | #include "../evsel.h" | ||
4 | #include "../sort.h" | ||
5 | #include "../hist.h" | ||
6 | #include "../helpline.h" | ||
7 | #include "gtk.h" | ||
8 | |||
9 | #define MAX_COLUMNS 32 | ||
10 | |||
11 | static int __percent_color_snprintf(char *buf, size_t size, double percent) | ||
12 | { | ||
13 | int ret = 0; | ||
14 | const char *markup; | ||
15 | |||
16 | markup = perf_gtk__get_percent_color(percent); | ||
17 | if (markup) | ||
18 | ret += scnprintf(buf, size, markup); | ||
19 | |||
20 | ret += scnprintf(buf + ret, size - ret, " %6.2f%%", percent); | ||
21 | |||
22 | if (markup) | ||
23 | ret += scnprintf(buf + ret, size - ret, "</span>"); | ||
24 | |||
25 | return ret; | ||
26 | } | ||
27 | |||
28 | |||
29 | static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he, | ||
30 | u64 (*get_field)(struct hist_entry *)) | ||
31 | { | ||
32 | int ret; | ||
33 | double percent = 0.0; | ||
34 | struct hists *hists = he->hists; | ||
35 | |||
36 | if (hists->stats.total_period) | ||
37 | percent = 100.0 * get_field(he) / hists->stats.total_period; | ||
38 | |||
39 | ret = __percent_color_snprintf(hpp->buf, hpp->size, percent); | ||
40 | |||
41 | if (symbol_conf.event_group) { | ||
42 | int prev_idx, idx_delta; | ||
43 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
44 | struct hist_entry *pair; | ||
45 | int nr_members = evsel->nr_members; | ||
46 | |||
47 | if (nr_members <= 1) | ||
48 | return ret; | ||
49 | |||
50 | prev_idx = perf_evsel__group_idx(evsel); | ||
51 | |||
52 | list_for_each_entry(pair, &he->pairs.head, pairs.node) { | ||
53 | u64 period = get_field(pair); | ||
54 | u64 total = pair->hists->stats.total_period; | ||
55 | |||
56 | evsel = hists_to_evsel(pair->hists); | ||
57 | idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1; | ||
58 | |||
59 | while (idx_delta--) { | ||
60 | /* | ||
61 | * zero-fill group members in the middle which | ||
62 | * have no sample | ||
63 | */ | ||
64 | ret += __percent_color_snprintf(hpp->buf + ret, | ||
65 | hpp->size - ret, | ||
66 | 0.0); | ||
67 | } | ||
68 | |||
69 | percent = 100.0 * period / total; | ||
70 | ret += __percent_color_snprintf(hpp->buf + ret, | ||
71 | hpp->size - ret, | ||
72 | percent); | ||
73 | |||
74 | prev_idx = perf_evsel__group_idx(evsel); | ||
75 | } | ||
76 | |||
77 | idx_delta = nr_members - prev_idx - 1; | ||
78 | |||
79 | while (idx_delta--) { | ||
80 | /* | ||
81 | * zero-fill group members at last which have no sample | ||
82 | */ | ||
83 | ret += __percent_color_snprintf(hpp->buf + ret, | ||
84 | hpp->size - ret, | ||
85 | 0.0); | ||
86 | } | ||
87 | } | ||
88 | return ret; | ||
89 | } | ||
90 | |||
91 | #define __HPP_COLOR_PERCENT_FN(_type, _field) \ | ||
92 | static u64 he_get_##_field(struct hist_entry *he) \ | ||
93 | { \ | ||
94 | return he->stat._field; \ | ||
95 | } \ | ||
96 | \ | ||
97 | static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp, \ | ||
98 | struct hist_entry *he) \ | ||
99 | { \ | ||
100 | return __hpp__color_fmt(hpp, he, he_get_##_field); \ | ||
101 | } | ||
102 | |||
103 | __HPP_COLOR_PERCENT_FN(overhead, period) | ||
104 | __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) | ||
105 | __HPP_COLOR_PERCENT_FN(overhead_us, period_us) | ||
106 | __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) | ||
107 | __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) | ||
108 | |||
109 | #undef __HPP_COLOR_PERCENT_FN | ||
110 | |||
111 | |||
112 | void perf_gtk__init_hpp(void) | ||
113 | { | ||
114 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
115 | |||
116 | perf_hpp__init(); | ||
117 | |||
118 | perf_hpp__format[PERF_HPP__OVERHEAD].color = | ||
119 | perf_gtk__hpp_color_overhead; | ||
120 | perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = | ||
121 | perf_gtk__hpp_color_overhead_sys; | ||
122 | perf_hpp__format[PERF_HPP__OVERHEAD_US].color = | ||
123 | perf_gtk__hpp_color_overhead_us; | ||
124 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = | ||
125 | perf_gtk__hpp_color_overhead_guest_sys; | ||
126 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = | ||
127 | perf_gtk__hpp_color_overhead_guest_us; | ||
128 | } | ||
129 | |||
130 | static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) | ||
131 | { | ||
132 | struct perf_hpp_fmt *fmt; | ||
133 | GType col_types[MAX_COLUMNS]; | ||
134 | GtkCellRenderer *renderer; | ||
135 | struct sort_entry *se; | ||
136 | GtkListStore *store; | ||
137 | struct rb_node *nd; | ||
138 | GtkWidget *view; | ||
139 | int col_idx; | ||
140 | int nr_cols; | ||
141 | char s[512]; | ||
142 | |||
143 | struct perf_hpp hpp = { | ||
144 | .buf = s, | ||
145 | .size = sizeof(s), | ||
146 | .ptr = hists_to_evsel(hists), | ||
147 | }; | ||
148 | |||
149 | nr_cols = 0; | ||
150 | |||
151 | perf_hpp__for_each_format(fmt) | ||
152 | col_types[nr_cols++] = G_TYPE_STRING; | ||
153 | |||
154 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
155 | if (se->elide) | ||
156 | continue; | ||
157 | |||
158 | col_types[nr_cols++] = G_TYPE_STRING; | ||
159 | } | ||
160 | |||
161 | store = gtk_list_store_newv(nr_cols, col_types); | ||
162 | |||
163 | view = gtk_tree_view_new(); | ||
164 | |||
165 | renderer = gtk_cell_renderer_text_new(); | ||
166 | |||
167 | col_idx = 0; | ||
168 | |||
169 | perf_hpp__for_each_format(fmt) { | ||
170 | fmt->header(&hpp); | ||
171 | |||
172 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
173 | -1, ltrim(s), | ||
174 | renderer, "markup", | ||
175 | col_idx++, NULL); | ||
176 | } | ||
177 | |||
178 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
179 | if (se->elide) | ||
180 | continue; | ||
181 | |||
182 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
183 | -1, se->se_header, | ||
184 | renderer, "text", | ||
185 | col_idx++, NULL); | ||
186 | } | ||
187 | |||
188 | gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); | ||
189 | |||
190 | g_object_unref(GTK_TREE_MODEL(store)); | ||
191 | |||
192 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { | ||
193 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | ||
194 | GtkTreeIter iter; | ||
195 | |||
196 | if (h->filtered) | ||
197 | continue; | ||
198 | |||
199 | gtk_list_store_append(store, &iter); | ||
200 | |||
201 | col_idx = 0; | ||
202 | |||
203 | perf_hpp__for_each_format(fmt) { | ||
204 | if (fmt->color) | ||
205 | fmt->color(&hpp, h); | ||
206 | else | ||
207 | fmt->entry(&hpp, h); | ||
208 | |||
209 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | ||
210 | } | ||
211 | |||
212 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
213 | if (se->elide) | ||
214 | continue; | ||
215 | |||
216 | se->se_snprintf(h, s, ARRAY_SIZE(s), | ||
217 | hists__col_len(hists, se->se_width_idx)); | ||
218 | |||
219 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | gtk_container_add(GTK_CONTAINER(window), view); | ||
224 | } | ||
225 | |||
226 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, | ||
227 | const char *help, | ||
228 | struct hist_browser_timer *hbt __maybe_unused) | ||
229 | { | ||
230 | struct perf_evsel *pos; | ||
231 | GtkWidget *vbox; | ||
232 | GtkWidget *notebook; | ||
233 | GtkWidget *info_bar; | ||
234 | GtkWidget *statbar; | ||
235 | GtkWidget *window; | ||
236 | |||
237 | signal(SIGSEGV, perf_gtk__signal); | ||
238 | signal(SIGFPE, perf_gtk__signal); | ||
239 | signal(SIGINT, perf_gtk__signal); | ||
240 | signal(SIGQUIT, perf_gtk__signal); | ||
241 | signal(SIGTERM, perf_gtk__signal); | ||
242 | |||
243 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | ||
244 | |||
245 | gtk_window_set_title(GTK_WINDOW(window), "perf report"); | ||
246 | |||
247 | g_signal_connect(window, "delete_event", gtk_main_quit, NULL); | ||
248 | |||
249 | pgctx = perf_gtk__activate_context(window); | ||
250 | if (!pgctx) | ||
251 | return -1; | ||
252 | |||
253 | vbox = gtk_vbox_new(FALSE, 0); | ||
254 | |||
255 | notebook = gtk_notebook_new(); | ||
256 | |||
257 | gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); | ||
258 | |||
259 | info_bar = perf_gtk__setup_info_bar(); | ||
260 | if (info_bar) | ||
261 | gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0); | ||
262 | |||
263 | statbar = perf_gtk__setup_statusbar(); | ||
264 | gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); | ||
265 | |||
266 | gtk_container_add(GTK_CONTAINER(window), vbox); | ||
267 | |||
268 | list_for_each_entry(pos, &evlist->entries, node) { | ||
269 | struct hists *hists = &pos->hists; | ||
270 | const char *evname = perf_evsel__name(pos); | ||
271 | GtkWidget *scrolled_window; | ||
272 | GtkWidget *tab_label; | ||
273 | char buf[512]; | ||
274 | size_t size = sizeof(buf); | ||
275 | |||
276 | if (symbol_conf.event_group) { | ||
277 | if (!perf_evsel__is_group_leader(pos)) | ||
278 | continue; | ||
279 | |||
280 | if (pos->nr_members > 1) { | ||
281 | perf_evsel__group_desc(pos, buf, size); | ||
282 | evname = buf; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | scrolled_window = gtk_scrolled_window_new(NULL, NULL); | ||
287 | |||
288 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), | ||
289 | GTK_POLICY_AUTOMATIC, | ||
290 | GTK_POLICY_AUTOMATIC); | ||
291 | |||
292 | perf_gtk__show_hists(scrolled_window, hists); | ||
293 | |||
294 | tab_label = gtk_label_new(evname); | ||
295 | |||
296 | gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label); | ||
297 | } | ||
298 | |||
299 | gtk_widget_show_all(window); | ||
300 | |||
301 | perf_gtk__resize_window(window); | ||
302 | |||
303 | gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); | ||
304 | |||
305 | ui_helpline__push(help); | ||
306 | |||
307 | gtk_main(); | ||
308 | |||
309 | perf_gtk__deactivate_context(&pgctx); | ||
310 | |||
311 | return 0; | ||
312 | } | ||