aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2010-01-07 12:59:49 -0500
committerSteven Rostedt <rostedt@goodmis.org>2010-01-07 12:59:49 -0500
commit0efdbd63ff75def9d0ad3162b83a4eb44472d341 (patch)
tree556dc94c3e5874f6806d56d82bf9b5929f3f694f
parentcd6621ae612c78d9423123cb918cd1d6a149fcf4 (diff)
trace-graph: Implement event filtering for the graph
Move some of the trace-view event filtering to be generic enough and have the trace-graph use it. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--Makefile2
-rw-r--r--trace-filter.c20
-rw-r--r--trace-filter.h62
-rw-r--r--trace-graph-main.c53
-rw-r--r--trace-graph.c152
-rw-r--r--trace-graph.h16
-rw-r--r--trace-hash.c21
-rw-r--r--trace-hash.h5
-rw-r--r--trace-view-store.c1
-rw-r--r--trace-view.h52
10 files changed, 298 insertions, 86 deletions
diff --git a/Makefile b/Makefile
index 4826dd1..0a66cbb 100644
--- a/Makefile
+++ b/Makefile
@@ -52,7 +52,7 @@ trace-cmd:: trace-cmd.o trace-read.o
52trace-view:: trace-view-main.o $(TRACE_VIEW_OBJS) 52trace-view:: trace-view-main.o $(TRACE_VIEW_OBJS)
53 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS) 53 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS)
54 54
55trace-graph:: trace-graph-main.o trace-graph.o trace-compat.o trace-hash.o 55trace-graph:: trace-graph-main.o trace-graph.o trace-compat.o trace-hash.o trace-filter.o
56 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS) 56 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS)
57 57
58kernelshark:: kernel-shark.o trace-compat.o $(TRACE_VIEW_OBJS) trace-graph.o \ 58kernelshark:: kernel-shark.o trace-compat.o $(TRACE_VIEW_OBJS) trace-graph.o \
diff --git a/trace-filter.c b/trace-filter.c
index 894448e..ab30b1f 100644
--- a/trace-filter.c
+++ b/trace-filter.c
@@ -12,6 +12,26 @@
12#define DIALOG_WIDTH 400 12#define DIALOG_WIDTH 400
13#define DIALOG_HEIGHT 600 13#define DIALOG_HEIGHT 600
14 14
15int str_cmp(const void *a, const void *b)
16{
17 char * const * sa = a;
18 char * const * sb = b;
19
20 return strcmp(*sa, *sb);
21}
22
23int id_cmp(const void *a, const void *b)
24{
25 const gint *ia = a;
26 const gint *ib = b;
27
28 if (*ia > *ib)
29 return 1;
30 if (*ia < *ib)
31 return -1;
32 return 0;
33}
34
15struct dialog_helper { 35struct dialog_helper {
16 GtkWidget *dialog; 36 GtkWidget *dialog;
17 gpointer data; 37 gpointer data;
diff --git a/trace-filter.h b/trace-filter.h
new file mode 100644
index 0000000..ced654e
--- /dev/null
+++ b/trace-filter.h
@@ -0,0 +1,62 @@
1#ifndef _TRACE_FILTER_H
2#define _TRACE_FILTER_H
3
4#include <gtk/gtk.h>
5
6struct event_filter_list {
7 struct event_filter_list *next;
8 struct event *event;
9};
10
11/**
12 * trace_filter_event_cb_func - callback type for event dialog
13 * @accept: TRUE if the accept button was pressed, otherwise FALSE
14 * @all_events: TRUE if "All Events" was checked
15 * @systems: NULL or a string array of systems terminated with NULL
16 * @events: NULL or a int array of event ids terminated with -1
17 * @data: The data given passed in to the event dialog function
18 *
19 * If @accept is FALSE then @all_events, @systems, and @events
20 * should be ignored. @data is still valid.
21 *
22 * If @all_events is TRUE then @systems and @events should be ignored.
23 */
24typedef void (*trace_filter_event_cb_func)(gboolean accept,
25 gboolean all_events,
26 char **systems,
27 gint *events,
28 gpointer data);
29
30void trace_filter_event_dialog(struct tracecmd_input *handle,
31 gboolean all_events,
32 gchar **systems,
33 gint *events,
34 trace_filter_event_cb_func func,
35 gpointer data);
36
37/**
38 * trace_filter_cpu_cb_func - callback type for CPU dialog
39 * @accept: TRUE if the accept button was pressed, otherwise FALSE
40 * @all_cpus: TRUE if "All CPUS" was checked
41 * @selected_cpus: NULL or a cpu_mask with the cpus that were checked set.
42 * @data: The data given passed in to the CPU dialog function
43 *
44 * If @accept is FALSE then @all_cpus and @selected_cpus should be ignored.
45 * @data is still valid.
46 *
47 * If @all_cpus is TRUE then @selected_cpus should be ignored.
48 */
49typedef void (*trace_filter_cpu_cb_func)(gboolean accept,
50 gboolean all_cpus,
51 guint64 *selected_cpus,
52 gpointer data);
53
54void trace_filter_cpu_dialog(gboolean all_cpus, guint64 *cpu_mask_selected, gint cpus,
55 trace_filter_cpu_cb_func func, gpointer data);
56
57/* put here because there's no other place */
58
59int str_cmp(const void *a, const void *b);
60int id_cmp(const void *a, const void *b);
61
62#endif /* _TRACE_FILTER_H */
diff --git a/trace-graph-main.c b/trace-graph-main.c
index de6bd12..80907d2 100644
--- a/trace-graph-main.c
+++ b/trace-graph-main.c
@@ -5,6 +5,7 @@
5 5
6#include "trace-cmd.h" 6#include "trace-cmd.h"
7#include "trace-graph.h" 7#include "trace-graph.h"
8#include "trace-filter.h"
8 9
9#define version "0.1.1" 10#define version "0.1.1"
10 11
@@ -41,6 +42,24 @@ delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
41 return TRUE; 42 return TRUE;
42} 43}
43 44
45/* Callback for the clicked signal of the Events filter button */
46static void
47events_clicked (gpointer data)
48{
49 struct graph_info *ginfo = data;
50 gboolean all_events = TRUE;
51 gchar **systems = NULL;
52 gint *events = NULL;
53
54 all_events = ginfo->all_events;
55 systems = ginfo->systems;
56 events = ginfo->event_ids;
57
58 trace_filter_event_dialog(ginfo->handle, all_events,
59 systems, events,
60 trace_graph_event_filter_callback, ginfo);
61}
62
44void trace_graph(int argc, char **argv) 63void trace_graph(int argc, char **argv)
45{ 64{
46 struct tracecmd_input *handle; 65 struct tracecmd_input *handle;
@@ -81,6 +100,9 @@ void trace_graph(int argc, char **argv)
81 100
82 gtk_init(&argc, &argv); 101 gtk_init(&argc, &argv);
83 102
103 /* graph struct is used by handlers */
104 ginfo = trace_graph_create(handle);
105
84 /* --- Main window --- */ 106 /* --- Main window --- */
85 107
86 window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 108 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
@@ -127,6 +149,36 @@ void trace_graph(int argc, char **argv)
127 /* --- end File options --- */ 149 /* --- end File options --- */
128 150
129 151
152 /* --- Filter Option --- */
153
154 menu_item = gtk_menu_item_new_with_label("Filter");
155 gtk_widget_show(menu_item);
156
157 gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), menu_item);
158
159 menu = gtk_menu_new(); /* Don't need to show menus */
160
161
162 /* --- Filter - Events Option --- */
163
164 sub_item = gtk_menu_item_new_with_label("events");
165
166 /* Add them to the menu */
167 gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item);
168
169 /* We can attach the Quit menu item to our exit function */
170 g_signal_connect_swapped (G_OBJECT (sub_item), "activate",
171 G_CALLBACK (events_clicked),
172 (gpointer) ginfo);
173
174 /* We do need to show menu items */
175 gtk_widget_show(sub_item);
176
177
178 /* --- End Filter Options --- */
179 gtk_menu_item_set_submenu(GTK_MENU_ITEM (menu_item), menu);
180
181
130 /* --- Top Level Hbox --- */ 182 /* --- Top Level Hbox --- */
131 183
132 hbox = gtk_hbox_new(FALSE, 0); 184 hbox = gtk_hbox_new(FALSE, 0);
@@ -136,7 +188,6 @@ void trace_graph(int argc, char **argv)
136 188
137 /* --- Set up the Graph --- */ 189 /* --- Set up the Graph --- */
138 190
139 ginfo = trace_graph_create(handle);
140 widget = trace_graph_get_window(ginfo); 191 widget = trace_graph_get_window(ginfo);
141 gtk_box_pack_start(GTK_BOX (hbox), widget, TRUE, TRUE, 0); 192 gtk_box_pack_start(GTK_BOX (hbox), widget, TRUE, TRUE, 0);
142 gtk_widget_show(widget); 193 gtk_widget_show(widget);
diff --git a/trace-graph.c b/trace-graph.c
index 5f1464c..8457edf 100644
--- a/trace-graph.c
+++ b/trace-graph.c
@@ -30,6 +30,7 @@
30#include "trace-local.h" 30#include "trace-local.h"
31#include "trace-graph.h" 31#include "trace-graph.h"
32#include "trace-hash.h" 32#include "trace-hash.h"
33#include "trace-filter.h"
33 34
34#define DEBUG_LEVEL 2 35#define DEBUG_LEVEL 2
35#if DEBUG_LEVEL > 0 36#if DEBUG_LEVEL > 0
@@ -112,12 +113,69 @@ static void graph_filter_task_clear(struct graph_info *ginfo)
112 ginfo->filter_enabled = 0; 113 ginfo->filter_enabled = 0;
113} 114}
114 115
116gboolean graph_filter_system(struct graph_info *ginfo, const gchar *system)
117{
118 const gchar **sys = &system;
119
120 if (ginfo->all_events)
121 return TRUE;
122
123 if (!ginfo->systems)
124 return FALSE;
125
126 sys = bsearch(sys, ginfo->systems, ginfo->systems_size,
127 sizeof(system), str_cmp);
128
129 return sys != NULL;
130}
131
132gboolean graph_filter_event(struct graph_info *ginfo, gint event_id)
133{
134 gint *event = &event_id;
135
136 if (ginfo->all_events)
137 return TRUE;
138
139 if (!ginfo->event_ids)
140 return FALSE;
141
142 event = bsearch(event, ginfo->event_ids, ginfo->event_ids_size,
143 sizeof(event_id), id_cmp);
144
145 return event != NULL;
146}
147
148gboolean graph_filter_on_event(struct graph_info *ginfo, struct record *record)
149{
150 struct event_format *event;
151 gint event_id;
152
153 if (!record)
154 return TRUE;
155
156 if (ginfo->all_events)
157 return FALSE;
158
159 event_id = pevent_data_type(ginfo->pevent, record);
160 event = pevent_data_event_from_type(ginfo->pevent, event_id);
161 if (!event)
162 return TRUE;
163
164 if (graph_filter_system(ginfo, event->system))
165 return FALSE;
166
167 if (graph_filter_event(ginfo, event_id))
168 return FALSE;
169
170 return TRUE;
171}
172
115gboolean graph_filter_on_task(struct graph_info *ginfo, gint pid) 173gboolean graph_filter_on_task(struct graph_info *ginfo, gint pid)
116{ 174{
117 gboolean filter; 175 gboolean filter;
118 176
119 filter = FALSE; 177 filter = FALSE;
120 178
121 if (ginfo->filter_enabled && 179 if (ginfo->filter_enabled &&
122 filter_task_count(ginfo->task_filter) && 180 filter_task_count(ginfo->task_filter) &&
123 !trace_graph_filter_task_find_pid(ginfo, pid)) 181 !trace_graph_filter_task_find_pid(ginfo, pid))
@@ -1147,7 +1205,7 @@ static void draw_cpu(struct graph_info *ginfo, gint cpu,
1147 filter = graph_filter_on_task(ginfo, last_pid); 1205 filter = graph_filter_on_task(ginfo, last_pid);
1148 1206
1149 if (!filter && last_pid) 1207 if (!filter && last_pid)
1150 1208
1151 gdk_draw_rectangle(ginfo->curr_pixmap, gc, 1209 gdk_draw_rectangle(ginfo->curr_pixmap, gc,
1152 TRUE, 1210 TRUE,
1153 last_x, CPU_BOX_TOP(cpu), 1211 last_x, CPU_BOX_TOP(cpu),
@@ -1166,9 +1224,12 @@ static void draw_cpu(struct graph_info *ginfo, gint cpu,
1166 1224
1167 last_pid = pid; 1225 last_pid = pid;
1168 1226
1169 if (!filter) 1227 if (!filter) {
1170 gdk_draw_line(ginfo->curr_pixmap, gc, // ginfo->draw->style->black_gc, 1228 filter = graph_filter_on_event(ginfo, record);
1171 x, CPU_TOP(cpu), x, CPU_BOTTOM(cpu)); 1229 if (!filter)
1230 gdk_draw_line(ginfo->curr_pixmap, gc,
1231 x, CPU_TOP(cpu), x, CPU_BOTTOM(cpu));
1232 }
1172 1233
1173 if (!filter) { 1234 if (!filter) {
1174 /* Figure out if we can show the text for the previous record */ 1235 /* Figure out if we can show the text for the previous record */
@@ -1372,6 +1433,82 @@ void trace_graph_select_by_time(struct graph_info *ginfo, guint64 time)
1372 update_with_backend(ginfo, 0, 0, width, ginfo->draw_height); 1433 update_with_backend(ginfo, 0, 0, width, ginfo->draw_height);
1373} 1434}
1374 1435
1436static void graph_free_systems(struct graph_info *ginfo)
1437{
1438 gint i;
1439
1440 if (!ginfo->systems)
1441 return;
1442
1443 for (i = 0; ginfo->systems[i]; i++)
1444 g_free(ginfo->systems[i]);
1445
1446 g_free(ginfo->systems);
1447 ginfo->systems = NULL;
1448 ginfo->systems_size = 0;
1449}
1450
1451static void graph_free_events(struct graph_info *ginfo)
1452{
1453 g_free(ginfo->event_ids);
1454 ginfo->event_ids = NULL;
1455 ginfo->event_ids_size = 0;
1456}
1457
1458void trace_graph_event_filter_callback(gboolean accept,
1459 gboolean all_events,
1460 gchar **systems,
1461 gint *events,
1462 gpointer data)
1463{
1464 struct graph_info *ginfo = data;
1465 gint i;
1466
1467 if (!accept)
1468 return;
1469
1470 graph_free_systems(ginfo);
1471 graph_free_events(ginfo);
1472
1473 if (all_events) {
1474 ginfo->all_events = TRUE;
1475 redraw_graph(ginfo);
1476 return;
1477 }
1478
1479 ginfo->all_events = FALSE;
1480
1481 if (systems) {
1482 for (ginfo->systems_size = 0;
1483 systems[ginfo->systems_size];
1484 ginfo->systems_size++)
1485 ;
1486
1487 ginfo->systems = g_new(typeof(*systems), ginfo->systems_size + 1);
1488 for (i = 0; i < ginfo->systems_size; i++)
1489 ginfo->systems[i] = g_strdup(systems[i]);
1490 ginfo->systems[i] = NULL;
1491
1492 qsort(ginfo->systems, ginfo->systems_size, sizeof(gchar *), str_cmp);
1493 }
1494
1495 if (events) {
1496 for (ginfo->event_ids_size = 0;
1497 events[ginfo->event_ids_size] >= 0;
1498 ginfo->event_ids_size++)
1499 ;
1500
1501 ginfo->event_ids = g_new(typeof(*events), ginfo->event_ids_size + 1);
1502 for (i = 0; i < ginfo->event_ids_size; i++)
1503 ginfo->event_ids[i] = events[i];
1504 ginfo->event_ids[i] = -1;
1505
1506 qsort(ginfo->event_ids, ginfo->event_ids_size, sizeof(gint), id_cmp);
1507 }
1508
1509 redraw_graph(ginfo);
1510}
1511
1375static void redraw_pixmap_backend(struct graph_info *ginfo) 1512static void redraw_pixmap_backend(struct graph_info *ginfo)
1376{ 1513{
1377 GdkPixmap *old_pix; 1514 GdkPixmap *old_pix;
@@ -1436,6 +1573,9 @@ destroy_event(GtkWidget *widget, gpointer data)
1436{ 1573{
1437 struct graph_info *ginfo = data; 1574 struct graph_info *ginfo = data;
1438 1575
1576 graph_free_systems(ginfo);
1577 graph_free_events(ginfo);
1578
1439 if (ginfo->test) 1579 if (ginfo->test)
1440 dprintf(1, "test = %s\n", ginfo->test); 1580 dprintf(1, "test = %s\n", ginfo->test);
1441 1581
@@ -1556,6 +1696,8 @@ trace_graph_create_with_callbacks(struct tracecmd_input *handle,
1556 ginfo->pevent = tracecmd_get_pevent(handle); 1696 ginfo->pevent = tracecmd_get_pevent(handle);
1557 ginfo->cpus = tracecmd_cpus(handle); 1697 ginfo->cpus = tracecmd_cpus(handle);
1558 1698
1699 ginfo->all_events = TRUE;
1700
1559 ginfo->callbacks = cbs; 1701 ginfo->callbacks = cbs;
1560 1702
1561 ginfo->start_time = -1ULL; 1703 ginfo->start_time = -1ULL;
diff --git a/trace-graph.h b/trace-graph.h
index 61d17db..db15c50 100644
--- a/trace-graph.h
+++ b/trace-graph.h
@@ -48,8 +48,14 @@ struct graph_info {
48 48
49 struct graph_callbacks *callbacks; /* call back hooks for changes to graph */ 49 struct graph_callbacks *callbacks; /* call back hooks for changes to graph */
50 50
51 int filter_enabled; 51 gboolean filter_enabled;
52 int filter_available; 52 gboolean filter_available;
53
54 gboolean all_events; /* all events enabled */
55 gchar **systems; /* event systems to filter on */
56 gint *event_ids; /* events to filter on */
57 gint systems_size;
58 gint event_ids_size;
53 59
54 struct filter_task *task_filter; 60 struct filter_task *task_filter;
55 gint filter_task_selected; 61 gint filter_task_selected;
@@ -76,6 +82,12 @@ trace_graph_create_with_callbacks(struct tracecmd_input *handle,
76 struct graph_callbacks *cbs); 82 struct graph_callbacks *cbs);
77void trace_graph_select_by_time(struct graph_info *ginfo, guint64 time); 83void trace_graph_select_by_time(struct graph_info *ginfo, guint64 time);
78 84
85void trace_graph_event_filter_callback(gboolean accept,
86 gboolean all_events,
87 gchar **systems,
88 gint *events,
89 gpointer data);
90
79static inline GtkWidget *trace_graph_get_draw(struct graph_info *ginfo) 91static inline GtkWidget *trace_graph_get_draw(struct graph_info *ginfo)
80{ 92{
81 return ginfo->draw; 93 return ginfo->draw;
diff --git a/trace-hash.c b/trace-hash.c
index a41b2ce..d8cd42f 100644
--- a/trace-hash.c
+++ b/trace-hash.c
@@ -159,24 +159,3 @@ struct filter_task *filter_task_hash_copy(struct filter_task *hash)
159 159
160 return new_hash; 160 return new_hash;
161} 161}
162
163
164int str_cmp(const void *a, const void *b)
165{
166 char * const * sa = a;
167 char * const * sb = b;
168
169 return strcmp(*sa, *sb);
170}
171
172int id_cmp(const void *a, const void *b)
173{
174 const gint *ia = a;
175 const gint *ib = b;
176
177 if (*ia > *ib)
178 return 1;
179 if (*ia < *ib)
180 return -1;
181 return 0;
182}
diff --git a/trace-hash.h b/trace-hash.h
index 04543f7..9948138 100644
--- a/trace-hash.h
+++ b/trace-hash.h
@@ -29,9 +29,4 @@ static inline gint filter_task_count(struct filter_task *hash)
29 return hash->count; 29 return hash->count;
30} 30}
31 31
32/* put here because there's no other place */
33
34int str_cmp(const void *a, const void *b);
35int id_cmp(const void *a, const void *b);
36
37#endif /* _TRACE_HASH_H */ 32#endif /* _TRACE_HASH_H */
diff --git a/trace-view-store.c b/trace-view-store.c
index cc6b865..3ea7e3b 100644
--- a/trace-view-store.c
+++ b/trace-view-store.c
@@ -3,6 +3,7 @@
3#include <string.h> 3#include <string.h>
4 4
5#include "cpu.h" 5#include "cpu.h"
6#include "trace-filter.h"
6 7
7/* boring declarations of local functions */ 8/* boring declarations of local functions */
8 9
diff --git a/trace-view.h b/trace-view.h
index 44cf0d0..2b34f23 100644
--- a/trace-view.h
+++ b/trace-view.h
@@ -2,6 +2,7 @@
2#define _TRACE_VIEW_H 2#define _TRACE_VIEW_H
3 3
4#include "trace-view-store.h" 4#include "trace-view-store.h"
5#include "trace-filter.h"
5 6
6void 7void
7trace_view_load(GtkWidget *view, struct tracecmd_input *handle, 8trace_view_load(GtkWidget *view, struct tracecmd_input *handle,
@@ -12,57 +13,6 @@ void trace_view(int argc, char **argv);
12void trace_view_update_task_filter(GtkWidget *treeview, struct filter_task *filter); 13void trace_view_update_task_filter(GtkWidget *treeview, struct filter_task *filter);
13void trace_view_make_selection_visible(GtkWidget *treeview); 14void trace_view_make_selection_visible(GtkWidget *treeview);
14 15
15struct event_filter_list {
16 struct event_filter_list *next;
17 struct event *event;
18};
19
20/**
21 * trace_filter_event_cb_func - callback type for event dialog
22 * @accept: TRUE if the accept button was pressed, otherwise FALSE
23 * @all_events: TRUE if "All Events" was checked
24 * @systems: NULL or a string array of systems terminated with NULL
25 * @events: NULL or a int array of event ids terminated with -1
26 * @data: The data given passed in to the event dialog function
27 *
28 * If @accept is FALSE then @all_events, @systems, and @events
29 * should be ignored. @data is still valid.
30 *
31 * If @all_events is TRUE then @systems and @events should be ignored.
32 */
33typedef void (*trace_filter_event_cb_func)(gboolean accept,
34 gboolean all_events,
35 char **systems,
36 gint *events,
37 gpointer data);
38
39void trace_filter_event_dialog(struct tracecmd_input *handle,
40 gboolean all_events,
41 gchar **systems,
42 gint *events,
43 trace_filter_event_cb_func func,
44 gpointer data);
45
46/**
47 * trace_filter_cpu_cb_func - callback type for CPU dialog
48 * @accept: TRUE if the accept button was pressed, otherwise FALSE
49 * @all_cpus: TRUE if "All CPUS" was checked
50 * @selected_cpus: NULL or a cpu_mask with the cpus that were checked set.
51 * @data: The data given passed in to the CPU dialog function
52 *
53 * If @accept is FALSE then @all_cpus and @selected_cpus should be ignored.
54 * @data is still valid.
55 *
56 * If @all_cpus is TRUE then @selected_cpus should be ignored.
57 */
58typedef void (*trace_filter_cpu_cb_func)(gboolean accept,
59 gboolean all_cpus,
60 guint64 *selected_cpus,
61 gpointer data);
62
63void trace_filter_cpu_dialog(gboolean all_cpus, guint64 *cpu_mask_selected, gint cpus,
64 trace_filter_cpu_cb_func func, gpointer data);
65
66void trace_view_select(GtkWidget *treeview, guint64 time); 16void trace_view_select(GtkWidget *treeview, guint64 time);
67 17
68void trace_view_event_filter_callback(gboolean accept, 18void trace_view_event_filter_callback(gboolean accept,