aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2009-12-31 15:38:36 -0500
committerSteven Rostedt <rostedt@goodmis.org>2009-12-31 15:38:36 -0500
commite16a1edd19467530e2a3b5649b200d97a64c5675 (patch)
tree13ad71d9589d34fc70fbcea2dc98bc2c79ee269c
parent12d78ef3bbb5cce5085ade12b197c211d26531eb (diff)
trace-graph: Add task filtering popup menus
Add popup menus to graph that allows the use to add or remove tasks from the filter, as well as to enable or disable the filter. This only adds the popup menus, the filtering is not actually done yet. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--trace-compat.c17
-rw-r--r--trace-compat.h6
-rw-r--r--trace-graph.c293
-rw-r--r--trace-graph.h10
4 files changed, 310 insertions, 16 deletions
diff --git a/trace-compat.c b/trace-compat.c
index 9c1d7e3..118a826 100644
--- a/trace-compat.c
+++ b/trace-compat.c
@@ -2,6 +2,9 @@
2 2
3#if GTK_VERSION < CALC_GTK_VERSION(2,18,0) 3#if GTK_VERSION < CALC_GTK_VERSION(2,18,0)
4 4
5#warning Using compat functions for older GTK library
6#warning Please upgrade your GTK to at least 2.18
7
5void gtk_cell_renderer_get_padding(GtkCellRenderer *cell, 8void gtk_cell_renderer_get_padding(GtkCellRenderer *cell,
6 gint *xpad, gint *ypad) 9 gint *xpad, gint *ypad)
7{ 10{
@@ -13,6 +16,20 @@ void gtk_cell_renderer_get_padding(GtkCellRenderer *cell,
13 16
14#endif /* version < 2.18.0 */ 17#endif /* version < 2.18.0 */
15 18
19#if GTK_VERSION < CALC_GTK_VERSION(2,16,0)
20
21void gtk_menu_item_set_label(GtkMenuItem *menu_item, const gchar *label)
22{
23 g_return_if_fail(GTK_IS_MENU_ITEM(menu_item));
24
25 if (GTK_IS_LABEL(GTK_BIN(menu_item)->child)) {
26 gtk_label_set_label(GTK_LABEL(GTK_BIN(menu_item)->child),
27 label ? label : "");
28 }
29}
30
31#endif /* version < 2.18.0 */
32
16#if GTK_VERSION < CALC_GTK_VERSION(2,14,0) 33#if GTK_VERSION < CALC_GTK_VERSION(2,14,0)
17 34
18gdouble gtk_adjustment_get_page_size(GtkAdjustment *adj) 35gdouble gtk_adjustment_get_page_size(GtkAdjustment *adj)
diff --git a/trace-compat.h b/trace-compat.h
index 381fc6c..8f8ad11 100644
--- a/trace-compat.h
+++ b/trace-compat.h
@@ -12,6 +12,12 @@ void gtk_cell_renderer_get_padding(GtkCellRenderer *cell,
12 12
13#endif /* version < 2.18.0 */ 13#endif /* version < 2.18.0 */
14 14
15#if GTK_VERSION < CALC_GTK_VERSION(2,16,0)
16
17void gtk_menu_item_set_label(GtkMenuItem *menu_item, const gchar *label);
18
19#endif /* version < 2.18.0 */
20
15#if GTK_VERSION < CALC_GTK_VERSION(2,14,0) 21#if GTK_VERSION < CALC_GTK_VERSION(2,14,0)
16 22
17gdouble gtk_adjustment_get_page_size(GtkAdjustment *adj); 23gdouble gtk_adjustment_get_page_size(GtkAdjustment *adj);
diff --git a/trace-graph.c b/trace-graph.c
index b70e27d..504eb36 100644
--- a/trace-graph.c
+++ b/trace-graph.c
@@ -55,12 +55,20 @@
55#define CPU_LABEL(cpu) (CPU_TOP(cpu)) 55#define CPU_LABEL(cpu) (CPU_TOP(cpu))
56#define CPU_X 5 56#define CPU_X 5
57 57
58#define FILTER_TASK_HASH_SIZE 256
59
60struct filter_task {
61 struct filter_task *next;
62 gint pid;
63};
64
58static gint ftrace_sched_switch_id = -1; 65static gint ftrace_sched_switch_id = -1;
59static gint event_sched_switch_id = -1; 66static gint event_sched_switch_id = -1;
60 67
61static gint largest_cpu_label = 0; 68static gint largest_cpu_label = 0;
62 69
63static void redraw_pixmap_backend(struct graph_info *ginfo); 70static void redraw_pixmap_backend(struct graph_info *ginfo);
71static gint do_hash(gint val);
64 72
65static void convert_nano(unsigned long long time, unsigned long *sec, 73static void convert_nano(unsigned long long time, unsigned long *sec,
66 unsigned long *usec) 74 unsigned long *usec)
@@ -80,6 +88,87 @@ static void print_time(unsigned long long time)
80 printf("%lu.%06lu", sec, usec); 88 printf("%lu.%06lu", sec, usec);
81} 89}
82 90
91static struct filter_task *
92filter_task_find_pid(struct graph_info *ginfo, gint pid)
93{
94 gint key = do_hash(pid) % FILTER_TASK_HASH_SIZE;
95 struct filter_task *task = ginfo->filter_task_hash[key];
96
97 while (task) {
98 if (task->pid == pid)
99 break;
100 task = task->next;
101 }
102 return task;
103}
104
105static void filter_task_add_pid(struct graph_info *ginfo, gint pid)
106{
107 gint key = do_hash(pid) % FILTER_TASK_HASH_SIZE;
108 struct filter_task *task;
109
110 task = g_new0(typeof(*task), 1);
111 g_assert(task);
112
113 task->pid = pid;
114 task->next = ginfo->filter_task_hash[key];
115 ginfo->filter_task_hash[key] = task;
116
117 ginfo->filter_task_count++;
118 ginfo->filter_available = 1;
119}
120
121static void filter_task_remove_pid(struct graph_info *ginfo, gint pid)
122{
123 gint key = do_hash(pid) % FILTER_TASK_HASH_SIZE;
124 struct filter_task **next = &ginfo->filter_task_hash[key];
125 struct filter_task *task;
126
127 while (*next) {
128 if ((*next)->pid == pid)
129 break;
130 next = &(*next)->next;
131 }
132 if (!*next)
133 return;
134
135 task = *next;
136
137 *next = task->next;
138
139 g_free(task);
140
141 if (--ginfo->filter_task_count)
142 return;
143
144 ginfo->filter_available = 0;
145}
146
147static void filter_task_clear(struct graph_info *ginfo)
148{
149 struct filter_task *task, *next;;
150 gint i;
151
152 if (!ginfo->filter_task_count)
153 return;
154
155 for (i = 0; i < FILTER_TASK_HASH_SIZE; i++) {
156 next = ginfo->filter_task_hash[i];
157 if (!next)
158 continue;
159
160 ginfo->filter_task_hash[i] = NULL;
161 while (next) {
162 task = next;
163 next = task->next;
164 g_free(task);
165 }
166 }
167
168 ginfo->filter_task_count = 0;
169 ginfo->filter_available = 0;
170}
171
83static void __update_with_backend(struct graph_info *ginfo, 172static void __update_with_backend(struct graph_info *ginfo,
84 gint x, gint y, 173 gint x, gint y,
85 gint width, gint height) 174 gint width, gint height)
@@ -146,16 +235,188 @@ static void clear_last_line(GtkWidget *widget, struct graph_info *ginfo)
146 update_with_backend(ginfo, x, 0, x+2, widget->allocation.height); 235 update_with_backend(ginfo, x, 0, x+2, widget->allocation.height);
147} 236}
148 237
238static struct record *
239find_record_on_cpu(struct graph_info *ginfo, gint cpu, guint64 time)
240{
241 struct record *record = NULL;
242 guint64 offset = 0;
243
244 tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, time);
245 do {
246 if (record) {
247 offset = record->offset;
248 free_record(record);
249 }
250 record = tracecmd_read_data(ginfo->handle, cpu);
251 } while (record && record->ts <= (time - 1 / ginfo->resolution));
252
253 if (record) {
254
255 if (record->ts > (time + 1 / ginfo->resolution) && offset) {
256 dprintf(3, "old ts = %llu!\n", record->ts);
257 free_record(record);
258 record = tracecmd_read_at(ginfo->handle, offset, NULL);
259 }
260 }
261
262 return record;
263}
264
265static void
266filter_enable_clicked (gpointer data)
267{
268 struct graph_info *ginfo = data;
269
270 ginfo->filter_enabled ^= 1;
271}
272
273static void
274filter_add_task_clicked (gpointer data)
275{
276 struct graph_info *ginfo = data;
277 struct filter_task *task;
278
279 task = filter_task_find_pid(ginfo, ginfo->filter_task_selected);
280
281 if (task)
282 filter_task_remove_pid(ginfo, task->pid);
283 else
284 filter_task_add_pid(ginfo, ginfo->filter_task_selected);
285}
286
287static void
288filter_clear_tasks_clicked (gpointer data)
289{
290 struct graph_info *ginfo = data;
291
292 filter_task_clear(ginfo);
293}
294
295static gboolean
296do_pop_up(GtkWidget *widget, GdkEventButton *event, gpointer data)
297{
298 struct graph_info *ginfo = data;
299 static GtkWidget *menu;
300 static GtkWidget *menu_filter_enable;
301 static GtkWidget *menu_filter_add_task;
302 static GtkWidget *menu_filter_clear_tasks;
303 struct record *record = NULL;
304 const char *comm;
305 guint64 time;
306 gchar *text;
307 gint pid;
308 gint len;
309 gint x, y;
310 gint cpu;
311
312 x = event->x;
313 y = event->y;
314
315 if (!menu) {
316 menu = gtk_menu_new();
317 menu_filter_enable = gtk_menu_item_new_with_label("Enable Filter");
318 gtk_widget_show(menu_filter_enable);
319 gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_enable);
320
321 g_signal_connect_swapped (G_OBJECT (menu_filter_enable), "activate",
322 G_CALLBACK (filter_enable_clicked),
323 data);
324
325 menu_filter_add_task = gtk_menu_item_new_with_label("Add Task");
326 gtk_widget_show(menu_filter_add_task);
327 gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_add_task);
328
329 g_signal_connect_swapped (G_OBJECT (menu_filter_add_task), "activate",
330 G_CALLBACK (filter_add_task_clicked),
331 data);
332
333 menu_filter_clear_tasks = gtk_menu_item_new_with_label("Clear Task Filter");
334 gtk_widget_show(menu_filter_clear_tasks);
335 gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_clear_tasks);
336
337 g_signal_connect_swapped (G_OBJECT (menu_filter_clear_tasks), "activate",
338 G_CALLBACK (filter_clear_tasks_clicked),
339 data);
340
341 }
342
343 if (ginfo->filter_enabled)
344 gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_enable),
345 "Disable Filter");
346 else
347 gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_enable),
348 "Enable Filter");
349
350 if (ginfo->filter_available)
351 gtk_widget_set_sensitive(menu_filter_enable, TRUE);
352 else
353 gtk_widget_set_sensitive(menu_filter_enable, FALSE);
354
355 if (ginfo->filter_task_count)
356 gtk_widget_set_sensitive(menu_filter_clear_tasks, TRUE);
357 else
358 gtk_widget_set_sensitive(menu_filter_clear_tasks, FALSE);
359
360 time = (x / ginfo->resolution) + ginfo->view_start_time;
361
362 for (cpu = 0; cpu < ginfo->cpus; cpu++) {
363 if (y >= (CPU_TOP(cpu) - CPU_GIVE) &&
364 y <= (CPU_BOTTOM(cpu) + CPU_GIVE)) {
365 record = find_record_on_cpu(ginfo, cpu, time);
366 break;
367 }
368 }
369
370 if (record) {
371 pid = pevent_data_pid(ginfo->pevent, record);
372 comm = pevent_data_comm_from_pid(ginfo->pevent, pid);
373
374 len = strlen(comm) + 50;
375
376 text = g_malloc(len);
377 g_assert(text);
378
379 if (filter_task_find_pid(ginfo, pid))
380 snprintf(text, len, "Remove %s-%d to filter", comm, pid);
381 else
382 snprintf(text, len, "Add %s-%d to filter", comm, pid);
383
384 ginfo->filter_task_selected = pid;
385
386 gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_add_task),
387 text);
388 g_free(text);
389
390 gtk_widget_set_sensitive(menu_filter_add_task, TRUE);
391
392 free_record(record);
393 } else {
394 gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_add_task),
395 "Add task to filter");
396 gtk_widget_set_sensitive(menu_filter_add_task, FALSE);
397 }
398
399
400 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3,
401 gtk_get_current_event_time());
402
403
404 return TRUE;
405}
406
149static gboolean 407static gboolean
150button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data) 408button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
151{ 409{
152 struct graph_info *ginfo = data; 410 struct graph_info *ginfo = data;
153 411
412 if (event->button == 3)
413 return do_pop_up(widget, event, data);
414
154 if (event->button != 1) 415 if (event->button != 1)
155 return TRUE; 416 return TRUE;
156 417
157 /* check for double click */ 418 /* check for double click */
158 if (event->type==GDK_2BUTTON_PRESS) { 419 if (event->type == GDK_2BUTTON_PRESS) {
159 if (ginfo->line_active) { 420 if (ginfo->line_active) {
160 ginfo->line_active = FALSE; 421 ginfo->line_active = FALSE;
161 clear_last_line(widget, ginfo); 422 clear_last_line(widget, ginfo);
@@ -309,22 +570,10 @@ static void draw_cpu_info(struct graph_info *ginfo, gint cpu, gint x, gint y)
309 trace_seq_init(&s); 570 trace_seq_init(&s);
310 571
311 dprintf(3, "start=%zu end=%zu time=%lu\n", ginfo->start_time, ginfo->end_time, time); 572 dprintf(3, "start=%zu end=%zu time=%lu\n", ginfo->start_time, ginfo->end_time, time);
312 tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, time);
313 do {
314 if (record) {
315 offset = record->offset;
316 free_record(record);
317 }
318 record = tracecmd_read_data(ginfo->handle, cpu);
319 } while (record && record->ts <= (time - 1 / ginfo->resolution));
320 573
321 if (record) { 574 record = find_record_on_cpu(ginfo, cpu, time);
322 575
323 if (record->ts > (time + 1 / ginfo->resolution) && offset) { 576 if (record) {
324 dprintf(3, "old ts = %llu!\n", record->ts);
325 free_record(record);
326 record = tracecmd_read_at(ginfo->handle, offset, NULL);
327 }
328 577
329 if (!check_sched_switch(ginfo, record, &pid, &comm)) { 578 if (!check_sched_switch(ginfo, record, &pid, &comm)) {
330 pid = pevent_data_pid(ginfo->pevent, record); 579 pid = pevent_data_pid(ginfo->pevent, record);
@@ -763,10 +1012,19 @@ static gint do_hash(gint val)
763 return hash; 1012 return hash;
764} 1013}
765 1014
1015static gint hash_pid(gint val)
1016{
1017 /* idle always gets black */
1018 if (!val)
1019 return 0;
1020
1021 return do_hash(val);
1022}
1023
766static void set_color_by_pid(GtkWidget *widget, GdkGC *gc, gint pid) 1024static void set_color_by_pid(GtkWidget *widget, GdkGC *gc, gint pid)
767{ 1025{
768 GdkColor color; 1026 GdkColor color;
769 gint hash = do_hash(pid); 1027 gint hash = hash_pid(pid);
770 static gint last_pid = -1; 1028 static gint last_pid = -1;
771 1029
772 if (!(hash & 0xffffff) && last_pid != pid) { 1030 if (!(hash & 0xffffff) && last_pid != pid) {
@@ -1317,6 +1575,9 @@ trace_graph_create_with_callbacks(struct tracecmd_input *handle,
1317 ginfo->start_time = -1ULL; 1575 ginfo->start_time = -1ULL;
1318 ginfo->end_time = 0; 1576 ginfo->end_time = 0;
1319 1577
1578 ginfo->filter_task_hash = g_new0(typeof(*ginfo->filter_task_hash),
1579 FILTER_TASK_HASH_SIZE);
1580
1320 ginfo->widget = gtk_hbox_new(FALSE, 0); 1581 ginfo->widget = gtk_hbox_new(FALSE, 0);
1321 gtk_widget_show(ginfo->widget); 1582 gtk_widget_show(ginfo->widget);
1322 1583
diff --git a/trace-graph.h b/trace-graph.h
index a9d7293..a3d3901 100644
--- a/trace-graph.h
+++ b/trace-graph.h
@@ -11,6 +11,8 @@ struct graph_callbacks {
11 graph_select_cb *select; 11 graph_select_cb *select;
12}; 12};
13 13
14struct filter_task;
15
14struct graph_info { 16struct graph_info {
15 struct tracecmd_input *handle; 17 struct tracecmd_input *handle;
16 struct pevent *pevent; 18 struct pevent *pevent;
@@ -47,6 +49,14 @@ struct graph_info {
47 49
48 struct graph_callbacks *callbacks; /* call back hooks for changes to graph */ 50 struct graph_callbacks *callbacks; /* call back hooks for changes to graph */
49 51
52 int filter_enabled;
53 int filter_available;
54
55 struct filter_task **filter_task_hash;
56 gint filter_task_count;
57 gint filter_task_selected;
58
59
50 /* Box info for CPU data info window */ 60 /* Box info for CPU data info window */
51 gint cpu_data_x; 61 gint cpu_data_x;
52 gint cpu_data_y; 62 gint cpu_data_y;