diff options
-rw-r--r-- | trace-compat.h | 2 | ||||
-rw-r--r-- | trace-filter.c | 264 | ||||
-rw-r--r-- | trace-graph.c | 10 | ||||
-rw-r--r-- | trace-hash.c | 44 | ||||
-rw-r--r-- | trace-hash.h | 2 | ||||
-rw-r--r-- | trace-view-main.c | 3 | ||||
-rw-r--r-- | trace-view-store.c | 221 | ||||
-rw-r--r-- | trace-view-store.h | 38 |
8 files changed, 570 insertions, 14 deletions
diff --git a/trace-compat.h b/trace-compat.h index 8f8ad11..1d9099c 100644 --- a/trace-compat.h +++ b/trace-compat.h | |||
@@ -16,7 +16,7 @@ void gtk_cell_renderer_get_padding(GtkCellRenderer *cell, | |||
16 | 16 | ||
17 | void gtk_menu_item_set_label(GtkMenuItem *menu_item, const gchar *label); | 17 | void gtk_menu_item_set_label(GtkMenuItem *menu_item, const gchar *label); |
18 | 18 | ||
19 | #endif /* version < 2.18.0 */ | 19 | #endif /* version < 2.16.0 */ |
20 | 20 | ||
21 | #if GTK_VERSION < CALC_GTK_VERSION(2,14,0) | 21 | #if GTK_VERSION < CALC_GTK_VERSION(2,14,0) |
22 | 22 | ||
diff --git a/trace-filter.c b/trace-filter.c index 3c1e23b..ba3b0fd 100644 --- a/trace-filter.c +++ b/trace-filter.c | |||
@@ -35,6 +35,9 @@ struct dialog_helper { | |||
35 | 35 | ||
36 | enum { | 36 | enum { |
37 | COL_EVENT, | 37 | COL_EVENT, |
38 | COL_ACTIVE, | ||
39 | COL_ACTIVE_START, | ||
40 | COL_EVENT_ID, | ||
38 | NUM_EVENT_COLS, | 41 | NUM_EVENT_COLS, |
39 | }; | 42 | }; |
40 | 43 | ||
@@ -49,18 +52,27 @@ create_tree_event_model(GtkWidget *tree_view) | |||
49 | struct event_format **events; | 52 | struct event_format **events; |
50 | struct event_format *event; | 53 | struct event_format *event; |
51 | char *last_system = NULL; | 54 | char *last_system = NULL; |
55 | gboolean all_events; | ||
56 | gboolean sysactive; | ||
57 | gboolean active; | ||
52 | gint i; | 58 | gint i; |
53 | 59 | ||
54 | model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)); | 60 | model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)); |
55 | trace_view = TRACE_VIEW_STORE(model); | 61 | trace_view = TRACE_VIEW_STORE(model); |
56 | 62 | ||
63 | all_events = trace_view_store_get_all_events_enabled(trace_view); | ||
64 | |||
57 | pevent = tracecmd_get_pevent(trace_view->handle); | 65 | pevent = tracecmd_get_pevent(trace_view->handle); |
58 | 66 | ||
59 | treestore = gtk_tree_store_new(NUM_EVENT_COLS, G_TYPE_STRING); | 67 | treestore = gtk_tree_store_new(NUM_EVENT_COLS, G_TYPE_STRING, |
68 | G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, | ||
69 | G_TYPE_INT); | ||
60 | 70 | ||
61 | gtk_tree_store_append(treestore, &iter_all, NULL); | 71 | gtk_tree_store_append(treestore, &iter_all, NULL); |
62 | gtk_tree_store_set(treestore, &iter_all, | 72 | gtk_tree_store_set(treestore, &iter_all, |
63 | COL_EVENT, "All", | 73 | COL_EVENT, "All", |
74 | COL_ACTIVE, all_events, | ||
75 | COL_ACTIVE_START, FALSE, | ||
64 | -1); | 76 | -1); |
65 | 77 | ||
66 | events = pevent_list_events(pevent, EVENT_SORT_SYSTEM); | 78 | events = pevent_list_events(pevent, EVENT_SORT_SYSTEM); |
@@ -71,15 +83,22 @@ create_tree_event_model(GtkWidget *tree_view) | |||
71 | event = events[i]; | 83 | event = events[i]; |
72 | if (!last_system || strcmp(last_system, event->system) != 0) { | 84 | if (!last_system || strcmp(last_system, event->system) != 0) { |
73 | gtk_tree_store_append(treestore, &iter_sys, &iter_all); | 85 | gtk_tree_store_append(treestore, &iter_sys, &iter_all); |
86 | sysactive = all_events || | ||
87 | trace_view_store_system_enabled(trace_view, event->system); | ||
74 | gtk_tree_store_set(treestore, &iter_sys, | 88 | gtk_tree_store_set(treestore, &iter_sys, |
75 | COL_EVENT, event->system, | 89 | COL_EVENT, event->system, |
90 | COL_ACTIVE, sysactive, | ||
76 | -1); | 91 | -1); |
77 | last_system = event->system; | 92 | last_system = event->system; |
78 | } | 93 | } |
79 | 94 | ||
95 | active = all_events || sysactive || | ||
96 | trace_view_store_event_enabled(trace_view, event->id); | ||
80 | gtk_tree_store_append(treestore, &iter_events, &iter_sys); | 97 | gtk_tree_store_append(treestore, &iter_events, &iter_sys); |
81 | gtk_tree_store_set(treestore, &iter_events, | 98 | gtk_tree_store_set(treestore, &iter_events, |
82 | COL_EVENT, event->name, | 99 | COL_EVENT, event->name, |
100 | COL_ACTIVE, active, | ||
101 | COL_EVENT_ID, event->id, | ||
83 | -1); | 102 | -1); |
84 | 103 | ||
85 | } | 104 | } |
@@ -87,10 +106,134 @@ create_tree_event_model(GtkWidget *tree_view) | |||
87 | return GTK_TREE_MODEL(treestore); | 106 | return GTK_TREE_MODEL(treestore); |
88 | } | 107 | } |
89 | 108 | ||
109 | static void update_active_events(GtkTreeModel *model, GtkTreeIter *parent, | ||
110 | gboolean active) | ||
111 | { | ||
112 | GtkTreeIter event; | ||
113 | |||
114 | if (!gtk_tree_model_iter_children(model, &event, parent)) | ||
115 | return; | ||
116 | |||
117 | for (;;) { | ||
118 | gtk_tree_store_set(GTK_TREE_STORE(model), &event, | ||
119 | COL_ACTIVE, active, | ||
120 | -1); | ||
121 | |||
122 | if (!gtk_tree_model_iter_next(model, &event)) | ||
123 | break; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | static void update_active_systems(GtkTreeModel *model, GtkTreeIter *parent, | ||
128 | gboolean active) | ||
129 | { | ||
130 | GtkTreeIter sys; | ||
131 | |||
132 | if (!gtk_tree_model_iter_children(model, &sys, parent)) | ||
133 | return; | ||
134 | |||
135 | for (;;) { | ||
136 | gtk_tree_store_set(GTK_TREE_STORE(model), &sys, | ||
137 | COL_ACTIVE, active, | ||
138 | -1); | ||
139 | |||
140 | update_active_events(model, &sys, active); | ||
141 | |||
142 | if (!gtk_tree_model_iter_next(model, &sys)) | ||
143 | break; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | static void event_cursor_changed(GtkTreeView *treeview, gpointer data) | ||
148 | { | ||
149 | GtkTreeModel *model; | ||
150 | GtkTreePath *path; | ||
151 | GtkTreeIter iter, parent, grandparent; | ||
152 | gboolean active, start; | ||
153 | gint depth; | ||
154 | |||
155 | model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); | ||
156 | if (!model) | ||
157 | return; | ||
158 | |||
159 | gtk_tree_view_get_cursor(treeview, &path, NULL); | ||
160 | if (!path) | ||
161 | return; | ||
162 | |||
163 | if (!gtk_tree_model_get_iter(model, &iter, path)) | ||
164 | goto free; | ||
165 | |||
166 | depth = gtk_tree_path_get_depth(path); | ||
167 | |||
168 | if (depth == 1) { | ||
169 | /* | ||
170 | * The first time we start up, the cursor will | ||
171 | * select the "All Events" row, and call | ||
172 | * this routine. But we don't want to do anything. | ||
173 | * Check and activate. | ||
174 | */ | ||
175 | gtk_tree_model_get(model, &iter, | ||
176 | COL_ACTIVE_START, &start, | ||
177 | -1); | ||
178 | if (!start) { | ||
179 | gtk_tree_store_set(GTK_TREE_STORE(model), &iter, | ||
180 | COL_ACTIVE_START, TRUE, | ||
181 | -1); | ||
182 | goto free; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | gtk_tree_model_get(model, &iter, | ||
187 | COL_ACTIVE, &active, | ||
188 | -1); | ||
189 | |||
190 | active = active ? FALSE : TRUE; | ||
191 | |||
192 | gtk_tree_store_set(GTK_TREE_STORE(model), &iter, | ||
193 | COL_ACTIVE, active, | ||
194 | -1); | ||
195 | |||
196 | if (depth == 1) { | ||
197 | |||
198 | if (active) | ||
199 | /* Set all rows */ | ||
200 | update_active_systems(model, &iter, TRUE); | ||
201 | |||
202 | } else if (depth == 2) { | ||
203 | if (active) { | ||
204 | /* set this system */ | ||
205 | update_active_events(model, &iter, TRUE); | ||
206 | } else { | ||
207 | /* disable the all events toggle */ | ||
208 | gtk_tree_model_iter_parent(model, &parent, &iter); | ||
209 | gtk_tree_store_set(GTK_TREE_STORE(model), &parent, | ||
210 | COL_ACTIVE, FALSE, | ||
211 | -1); | ||
212 | } | ||
213 | |||
214 | } else { | ||
215 | if (!active) { | ||
216 | /* disable system and all events toggles */ | ||
217 | gtk_tree_model_iter_parent(model, &parent, &iter); | ||
218 | gtk_tree_store_set(GTK_TREE_STORE(model), &parent, | ||
219 | COL_ACTIVE, FALSE, | ||
220 | -1); | ||
221 | gtk_tree_model_iter_parent(model, &grandparent, &parent); | ||
222 | gtk_tree_store_set(GTK_TREE_STORE(model), &grandparent, | ||
223 | COL_ACTIVE, FALSE, | ||
224 | -1); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | free: | ||
229 | gtk_tree_path_free(path); | ||
230 | } | ||
231 | |||
90 | static GtkWidget *create_event_list_view(GtkWidget *tree_view) | 232 | static GtkWidget *create_event_list_view(GtkWidget *tree_view) |
91 | { | 233 | { |
92 | GtkTreeViewColumn *col; | 234 | GtkTreeViewColumn *col; |
93 | GtkCellRenderer *renderer; | 235 | GtkCellRenderer *renderer; |
236 | GtkCellRenderer *togrend; | ||
94 | GtkWidget *view; | 237 | GtkWidget *view; |
95 | GtkTreeModel *model; | 238 | GtkTreeModel *model; |
96 | 239 | ||
@@ -106,7 +249,11 @@ static GtkWidget *create_event_list_view(GtkWidget *tree_view) | |||
106 | 249 | ||
107 | renderer = gtk_cell_renderer_text_new(); | 250 | renderer = gtk_cell_renderer_text_new(); |
108 | 251 | ||
109 | gtk_tree_view_column_pack_start(col, renderer, TRUE); | 252 | togrend = gtk_cell_renderer_toggle_new(); |
253 | |||
254 | gtk_tree_view_column_pack_start(col, togrend, FALSE); | ||
255 | gtk_tree_view_column_pack_start(col, renderer, FALSE); | ||
256 | gtk_tree_view_column_add_attribute(col, togrend, "active", COL_ACTIVE); | ||
110 | 257 | ||
111 | gtk_tree_view_column_add_attribute(col, renderer, "text", COL_EVENT); | 258 | gtk_tree_view_column_add_attribute(col, renderer, "text", COL_EVENT); |
112 | 259 | ||
@@ -117,23 +264,125 @@ static GtkWidget *create_event_list_view(GtkWidget *tree_view) | |||
117 | g_object_unref(model); | 264 | g_object_unref(model); |
118 | 265 | ||
119 | gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(view)), | 266 | gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(view)), |
120 | GTK_SELECTION_MULTIPLE); | 267 | GTK_SELECTION_NONE); |
121 | 268 | ||
122 | gtk_tree_view_expand_all(GTK_TREE_VIEW(view)); | 269 | gtk_tree_view_expand_all(GTK_TREE_VIEW(view)); |
123 | 270 | ||
271 | g_signal_connect_swapped (view, "cursor-changed", | ||
272 | G_CALLBACK (event_cursor_changed), | ||
273 | (gpointer) view); | ||
274 | |||
124 | return view; | 275 | return view; |
125 | } | 276 | } |
126 | 277 | ||
278 | static void update_events(TraceViewStore *store, | ||
279 | GtkTreeModel *model, | ||
280 | GtkTreeIter *parent) | ||
281 | { | ||
282 | GtkTreeIter event; | ||
283 | gboolean active; | ||
284 | gint id; | ||
285 | |||
286 | if (!gtk_tree_model_iter_children(model, &event, parent)) | ||
287 | return; | ||
288 | |||
289 | for (;;) { | ||
290 | |||
291 | gtk_tree_model_get(model, &event, | ||
292 | COL_ACTIVE, &active, | ||
293 | COL_EVENT_ID, &id, | ||
294 | -1); | ||
295 | |||
296 | if (active) | ||
297 | trace_view_store_set_event_enabled(store, id); | ||
298 | |||
299 | if (!gtk_tree_model_iter_next(model, &event)) | ||
300 | break; | ||
301 | } | ||
302 | } | ||
303 | |||
304 | static void update_system_events(TraceViewStore *store, | ||
305 | GtkTreeModel *model, | ||
306 | GtkTreeIter *parent) | ||
307 | { | ||
308 | GtkTreeIter sys; | ||
309 | gboolean active; | ||
310 | gchar *system; | ||
311 | |||
312 | if (!gtk_tree_model_iter_children(model, &sys, parent)) | ||
313 | return; | ||
314 | |||
315 | for (;;) { | ||
316 | |||
317 | gtk_tree_model_get(model, &sys, | ||
318 | COL_ACTIVE, &active, | ||
319 | COL_EVENT, &system, | ||
320 | -1); | ||
321 | |||
322 | if (active) | ||
323 | trace_view_store_set_system_enabled(store, system); | ||
324 | else | ||
325 | update_events(store, model, &sys); | ||
326 | |||
327 | g_free(system); | ||
328 | |||
329 | if (!gtk_tree_model_iter_next(model, &sys)) | ||
330 | break; | ||
331 | } | ||
332 | } | ||
333 | |||
334 | static void accept_events(GtkWidget *trace_tree_view, GtkTreeView *view) | ||
335 | { | ||
336 | GtkTreeModel *model; | ||
337 | TraceViewStore *store; | ||
338 | GtkTreeIter iter; | ||
339 | gboolean active; | ||
340 | |||
341 | model = gtk_tree_view_get_model(GTK_TREE_VIEW(trace_tree_view)); | ||
342 | if (!model) | ||
343 | return; | ||
344 | |||
345 | store = TRACE_VIEW_STORE(model); | ||
346 | |||
347 | model = gtk_tree_view_get_model(view); | ||
348 | if (!model) | ||
349 | return; | ||
350 | |||
351 | if (!gtk_tree_model_get_iter_first(model, &iter)) | ||
352 | return; | ||
353 | |||
354 | gtk_tree_model_get(model, &iter, | ||
355 | COL_ACTIVE, &active, | ||
356 | -1); | ||
357 | |||
358 | if (active) { | ||
359 | if (trace_view_store_get_all_events_enabled(store)) | ||
360 | return; | ||
361 | |||
362 | trace_view_store_set_all_events_enabled(store); | ||
363 | } else | ||
364 | update_system_events(store, model, &iter); | ||
365 | |||
366 | /* Force an update */ | ||
367 | g_object_ref(store); | ||
368 | gtk_tree_view_set_model(GTK_TREE_VIEW(trace_tree_view), NULL); | ||
369 | trace_view_store_update_filter(store); | ||
370 | gtk_tree_view_set_model(GTK_TREE_VIEW(trace_tree_view), GTK_TREE_MODEL(store)); | ||
371 | g_object_unref(store); | ||
372 | |||
373 | } | ||
127 | 374 | ||
128 | /* Callback for the clicked signal of the Events filter button */ | 375 | /* Callback for the clicked signal of the Events filter button */ |
129 | static void | 376 | static void |
130 | event_dialog_response (gpointer data, gint response_id) | 377 | event_dialog_response (gpointer data, gint response_id) |
131 | { | 378 | { |
132 | struct dialog_helper *helper = data; | 379 | struct dialog_helper *helper = data; |
380 | GtkTreeView *view = helper->data; | ||
133 | 381 | ||
134 | switch (response_id) { | 382 | switch (response_id) { |
135 | case GTK_RESPONSE_ACCEPT: | 383 | case GTK_RESPONSE_ACCEPT: |
136 | printf("accept!\n"); | 384 | printf("accept!\n"); |
385 | accept_events(helper->trace_tree, view); | ||
137 | break; | 386 | break; |
138 | case GTK_RESPONSE_REJECT: | 387 | case GTK_RESPONSE_REJECT: |
139 | printf("reject!\n"); | 388 | printf("reject!\n"); |
@@ -177,7 +426,11 @@ void trace_filter_event_dialog(void *trace_tree) | |||
177 | (gpointer) helper); | 426 | (gpointer) helper); |
178 | 427 | ||
179 | scrollwin = gtk_scrolled_window_new(NULL, NULL); | 428 | scrollwin = gtk_scrolled_window_new(NULL, NULL); |
429 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), | ||
430 | GTK_POLICY_AUTOMATIC, | ||
431 | GTK_POLICY_AUTOMATIC); | ||
180 | view = create_event_list_view(tree_view); | 432 | view = create_event_list_view(tree_view); |
433 | helper->data = view; | ||
181 | 434 | ||
182 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), scrollwin, TRUE, TRUE, 0); | 435 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), scrollwin, TRUE, TRUE, 0); |
183 | gtk_container_add(GTK_CONTAINER(scrollwin), view); | 436 | gtk_container_add(GTK_CONTAINER(scrollwin), view); |
@@ -341,6 +594,9 @@ void trace_filter_cpu_dialog(void *trace_tree) | |||
341 | (gpointer) helper); | 594 | (gpointer) helper); |
342 | 595 | ||
343 | scrollwin = gtk_scrolled_window_new(NULL, NULL); | 596 | scrollwin = gtk_scrolled_window_new(NULL, NULL); |
597 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), | ||
598 | GTK_POLICY_AUTOMATIC, | ||
599 | GTK_POLICY_AUTOMATIC); | ||
344 | 600 | ||
345 | viewport = gtk_viewport_new(NULL, NULL); | 601 | viewport = gtk_viewport_new(NULL, NULL); |
346 | gtk_widget_show(viewport); | 602 | gtk_widget_show(viewport); |
diff --git a/trace-graph.c b/trace-graph.c index 0500e35..5f1464c 100644 --- a/trace-graph.c +++ b/trace-graph.c | |||
@@ -1078,6 +1078,7 @@ static void draw_cpu(struct graph_info *ginfo, gint cpu, | |||
1078 | gint last_event_id = 0; | 1078 | gint last_event_id = 0; |
1079 | gint event_id; | 1079 | gint event_id; |
1080 | gboolean filter; | 1080 | gboolean filter; |
1081 | gboolean is_sched_switch; | ||
1081 | const char *comm; | 1082 | const char *comm; |
1082 | 1083 | ||
1083 | /* Calculate the size of 16 characters */ | 1084 | /* Calculate the size of 16 characters */ |
@@ -1118,8 +1119,10 @@ static void draw_cpu(struct graph_info *ginfo, gint cpu, | |||
1118 | 1119 | ||
1119 | x = (gint)((gdouble)ts * ginfo->resolution); | 1120 | x = (gint)((gdouble)ts * ginfo->resolution); |
1120 | 1121 | ||
1122 | is_sched_switch = FALSE; | ||
1121 | 1123 | ||
1122 | if (check_sched_switch(ginfo, record, &pid, &comm)) { | 1124 | if (check_sched_switch(ginfo, record, &pid, &comm)) { |
1125 | is_sched_switch = TRUE; | ||
1123 | if (read_comms) { | 1126 | if (read_comms) { |
1124 | /* | 1127 | /* |
1125 | * First time through, register any missing | 1128 | * First time through, register any missing |
@@ -1151,13 +1154,18 @@ static void draw_cpu(struct graph_info *ginfo, gint cpu, | |||
1151 | x - last_x, CPU_BOX_SIZE); | 1154 | x - last_x, CPU_BOX_SIZE); |
1152 | 1155 | ||
1153 | last_x = x; | 1156 | last_x = x; |
1154 | last_pid = pid; | ||
1155 | 1157 | ||
1156 | set_color_by_pid(ginfo->draw, gc, pid); | 1158 | set_color_by_pid(ginfo->draw, gc, pid); |
1157 | } | 1159 | } |
1158 | 1160 | ||
1159 | filter = graph_filter_on_task(ginfo, pid); | 1161 | filter = graph_filter_on_task(ginfo, pid); |
1160 | 1162 | ||
1163 | /* Also show the task switching out */ | ||
1164 | if (filter && is_sched_switch) | ||
1165 | filter = graph_filter_on_task(ginfo, last_pid); | ||
1166 | |||
1167 | last_pid = pid; | ||
1168 | |||
1161 | if (!filter) | 1169 | if (!filter) |
1162 | gdk_draw_line(ginfo->curr_pixmap, gc, // ginfo->draw->style->black_gc, | 1170 | gdk_draw_line(ginfo->curr_pixmap, gc, // ginfo->draw->style->black_gc, |
1163 | x, CPU_TOP(cpu), x, CPU_BOTTOM(cpu)); | 1171 | x, CPU_TOP(cpu), x, CPU_BOTTOM(cpu)); |
diff --git a/trace-hash.c b/trace-hash.c index 99b9feb..8435e6c 100644 --- a/trace-hash.c +++ b/trace-hash.c | |||
@@ -116,3 +116,47 @@ struct filter_task *filter_task_hash_alloc(void) | |||
116 | 116 | ||
117 | return hash; | 117 | return hash; |
118 | } | 118 | } |
119 | |||
120 | void filter_task_hash_free(struct filter_task *hash) | ||
121 | { | ||
122 | if (!hash) | ||
123 | return; | ||
124 | |||
125 | filter_task_clear(hash); | ||
126 | g_free(hash->hash); | ||
127 | g_free(hash); | ||
128 | } | ||
129 | |||
130 | struct filter_task *filter_task_hash_copy(struct filter_task *hash) | ||
131 | { | ||
132 | struct filter_task *new_hash; | ||
133 | struct filter_task_item *task, **ptask; | ||
134 | gint i; | ||
135 | |||
136 | if (!hash) | ||
137 | return NULL; | ||
138 | |||
139 | new_hash = filter_task_hash_alloc(); | ||
140 | g_assert(new_hash); | ||
141 | |||
142 | for (i = 0; i < FILTER_TASK_HASH_SIZE; i++) { | ||
143 | task = hash->hash[i]; | ||
144 | if (!task) | ||
145 | continue; | ||
146 | |||
147 | ptask = &new_hash->hash[i]; | ||
148 | |||
149 | while (task) { | ||
150 | |||
151 | *ptask = g_new0(typeof(*task), 1); | ||
152 | g_assert(*ptask); | ||
153 | **ptask = *task; | ||
154 | |||
155 | ptask = &(*ptask)->next; | ||
156 | task = task->next; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | return new_hash; | ||
161 | } | ||
162 | |||
diff --git a/trace-hash.h b/trace-hash.h index cab6195..9948138 100644 --- a/trace-hash.h +++ b/trace-hash.h | |||
@@ -21,6 +21,8 @@ void filter_task_add_pid(struct filter_task *hash, gint pid); | |||
21 | void filter_task_remove_pid(struct filter_task *hash, gint pid); | 21 | void filter_task_remove_pid(struct filter_task *hash, gint pid); |
22 | void filter_task_clear(struct filter_task *hash); | 22 | void filter_task_clear(struct filter_task *hash); |
23 | struct filter_task *filter_task_hash_alloc(void); | 23 | struct filter_task *filter_task_hash_alloc(void); |
24 | void filter_task_hash_free(struct filter_task *hash); | ||
25 | struct filter_task *filter_task_hash_copy(struct filter_task *hash); | ||
24 | 26 | ||
25 | static inline gint filter_task_count(struct filter_task *hash) | 27 | static inline gint filter_task_count(struct filter_task *hash) |
26 | { | 28 | { |
diff --git a/trace-view-main.c b/trace-view-main.c index 5b6eb7b..2f4042e 100644 --- a/trace-view-main.c +++ b/trace-view-main.c | |||
@@ -248,8 +248,7 @@ void trace_view(int argc, char **argv) | |||
248 | 248 | ||
249 | trace_view_load(trace_tree, handle, spin); | 249 | trace_view_load(trace_tree, handle, spin); |
250 | 250 | ||
251 | gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollwin), | 251 | gtk_container_add(GTK_CONTAINER(scrollwin), trace_tree); |
252 | trace_tree); | ||
253 | gtk_widget_show(trace_tree); | 252 | gtk_widget_show(trace_tree); |
254 | 253 | ||
255 | 254 | ||
diff --git a/trace-view-store.c b/trace-view-store.c index be86662..9ad2073 100644 --- a/trace-view-store.c +++ b/trace-view-store.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include "trace-view-store.h" | 1 | #include "trace-view-store.h" |
2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include <string.h> | ||
3 | 4 | ||
4 | #include "cpu.h" | 5 | #include "cpu.h" |
5 | 6 | ||
@@ -207,6 +208,8 @@ trace_view_store_finalize (GObject *object) | |||
207 | g_free(store->rows); | 208 | g_free(store->rows); |
208 | g_free(store->cpu_items); | 209 | g_free(store->cpu_items); |
209 | 210 | ||
211 | filter_task_hash_free(store->task_filter); | ||
212 | |||
210 | if (store->spin) { | 213 | if (store->spin) { |
211 | gtk_widget_destroy(store->spin); | 214 | gtk_widget_destroy(store->spin); |
212 | store->spin = NULL; | 215 | store->spin = NULL; |
@@ -490,6 +493,183 @@ trace_view_store_get_value (GtkTreeModel *tree_model, | |||
490 | } | 493 | } |
491 | } | 494 | } |
492 | 495 | ||
496 | int str_cmp(const void *a, const void *b) | ||
497 | { | ||
498 | char * const * sa = a; | ||
499 | char * const * sb = b; | ||
500 | |||
501 | return strcmp(*sa, *sb); | ||
502 | } | ||
503 | |||
504 | int id_cmp(const void *a, const void *b) | ||
505 | { | ||
506 | const gint *ia = a; | ||
507 | const gint *ib = b; | ||
508 | |||
509 | if (*ia > *ib) | ||
510 | return 1; | ||
511 | if (*ia < *ib) | ||
512 | return -1; | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | gboolean trace_view_store_system_enabled(TraceViewStore *store, const gchar *system) | ||
517 | { | ||
518 | const gchar **sys = &system; | ||
519 | |||
520 | g_return_val_if_fail (TRACE_VIEW_IS_LIST (store), FALSE); | ||
521 | |||
522 | if (store->all_events) | ||
523 | return TRUE; | ||
524 | |||
525 | if (!store->systems) | ||
526 | return FALSE; | ||
527 | |||
528 | sys = bsearch(sys, store->systems, store->systems_size, | ||
529 | sizeof(system), str_cmp); | ||
530 | |||
531 | return sys != NULL; | ||
532 | } | ||
533 | |||
534 | gboolean trace_view_store_event_enabled(TraceViewStore *store, gint event_id) | ||
535 | { | ||
536 | gint key = event_id; | ||
537 | gint *ret; | ||
538 | |||
539 | g_return_val_if_fail (TRACE_VIEW_IS_LIST (store), FALSE); | ||
540 | |||
541 | if (store->all_events) | ||
542 | return TRUE; | ||
543 | |||
544 | /* TODO: search for the system of the event? */ | ||
545 | |||
546 | if (!store->event_types) | ||
547 | return FALSE; | ||
548 | |||
549 | ret = bsearch(&key, store->event_types, store->event_types_size, | ||
550 | sizeof(gint), id_cmp); | ||
551 | |||
552 | return ret != NULL; | ||
553 | } | ||
554 | |||
555 | void trace_view_store_set_all_events_enabled(TraceViewStore *store) | ||
556 | { | ||
557 | gint i; | ||
558 | |||
559 | g_return_if_fail (TRACE_VIEW_IS_LIST (store)); | ||
560 | |||
561 | if (store->all_events) | ||
562 | return; | ||
563 | |||
564 | if (store->systems_size) { | ||
565 | for (i = 0; i < store->systems_size; i++) | ||
566 | g_free(store->systems[i]); | ||
567 | |||
568 | g_free(store->systems); | ||
569 | store->systems = NULL; | ||
570 | store->systems_size = 0; | ||
571 | } | ||
572 | |||
573 | g_free(store->event_types); | ||
574 | store->event_types = NULL; | ||
575 | store->event_types_size = 0; | ||
576 | |||
577 | store->all_events = 1; | ||
578 | } | ||
579 | |||
580 | static void remove_system(TraceViewStore *store, const gchar *system) | ||
581 | { | ||
582 | const gchar **sys = &system; | ||
583 | |||
584 | if (!store->systems) | ||
585 | return; | ||
586 | |||
587 | sys = bsearch(sys, store->systems, store->systems_size, | ||
588 | sizeof(system), str_cmp); | ||
589 | |||
590 | if (!sys) | ||
591 | return; | ||
592 | |||
593 | g_free(*((gchar **)sys)); | ||
594 | |||
595 | g_memmove(sys, sys+1, sizeof(*sys) * (store->systems_size - | ||
596 | ((gchar **)sys - store->systems))); | ||
597 | store->systems_size--; | ||
598 | store->systems[store->systems_size] = NULL; | ||
599 | } | ||
600 | |||
601 | void trace_view_store_set_system_enabled(TraceViewStore *store, const gchar *system) | ||
602 | { | ||
603 | g_return_if_fail (TRACE_VIEW_IS_LIST (store)); | ||
604 | |||
605 | if (store->all_events) | ||
606 | /* | ||
607 | * We are adding a new filter, so this is the | ||
608 | * only system enabled. | ||
609 | */ | ||
610 | store->all_events = 0; | ||
611 | |||
612 | if (trace_view_store_system_enabled(store, system)) | ||
613 | return; | ||
614 | |||
615 | if (!store->systems) { | ||
616 | store->systems = g_new0(gchar *, 2); | ||
617 | store->systems[0] = g_strdup(system); | ||
618 | store->systems_size++; | ||
619 | return; | ||
620 | } | ||
621 | |||
622 | store->systems_size++; | ||
623 | store->systems = g_realloc(store->systems, | ||
624 | sizeof(*store->systems) * (store->systems_size+1)); | ||
625 | store->systems[store->systems_size - 1] = g_strdup(system); | ||
626 | store->systems[store->systems_size] = NULL; | ||
627 | |||
628 | qsort(store->systems, store->systems_size, sizeof(gchar *), str_cmp); | ||
629 | } | ||
630 | |||
631 | |||
632 | void trace_view_store_set_event_enabled(TraceViewStore *store, gint event_id) | ||
633 | { | ||
634 | struct pevent *pevent; | ||
635 | struct event_format *event; | ||
636 | |||
637 | g_return_if_fail (TRACE_VIEW_IS_LIST (store)); | ||
638 | |||
639 | pevent = tracecmd_get_pevent(store->handle); | ||
640 | event = pevent_find_event(pevent, event_id); | ||
641 | if (!event) | ||
642 | return; | ||
643 | |||
644 | if (store->all_events) | ||
645 | /* | ||
646 | * We are adding a new filter, so this is the | ||
647 | * only system enabled. | ||
648 | */ | ||
649 | store->all_events = 0; | ||
650 | |||
651 | remove_system(store, event->system); | ||
652 | |||
653 | if (trace_view_store_event_enabled(store, event_id)) | ||
654 | return; | ||
655 | |||
656 | if (!store->event_types) { | ||
657 | store->event_types = g_new0(gint, 2); | ||
658 | store->event_types[0] = event_id; | ||
659 | store->event_types[1] = -1; | ||
660 | store->event_types_size++; | ||
661 | return; | ||
662 | } | ||
663 | |||
664 | store->event_types_size++; | ||
665 | store->event_types = g_realloc(store->event_types, | ||
666 | sizeof(*store->event_types) * (store->event_types_size+1)); | ||
667 | store->event_types[store->event_types_size - 1] = event_id; | ||
668 | store->event_types[store->event_types_size] = -1; | ||
669 | |||
670 | qsort(store->event_types, store->event_types_size, sizeof(gint), id_cmp); | ||
671 | } | ||
672 | |||
493 | 673 | ||
494 | /***************************************************************************** | 674 | /***************************************************************************** |
495 | * | 675 | * |
@@ -1059,7 +1239,7 @@ gint get_next_pid(TraceViewStore *store, struct pevent *pevent, struct record *r | |||
1059 | unsigned long long val; | 1239 | unsigned long long val; |
1060 | int ret; | 1240 | int ret; |
1061 | 1241 | ||
1062 | ret = pevent_read_number_field(store->sched_switch_next_field, record, &val); | 1242 | ret = pevent_read_number_field(store->sched_switch_next_field, record->data, &val); |
1063 | 1243 | ||
1064 | return val; | 1244 | return val; |
1065 | } | 1245 | } |
@@ -1067,14 +1247,23 @@ gint get_next_pid(TraceViewStore *store, struct pevent *pevent, struct record *r | |||
1067 | void trace_view_store_filter_tasks(TraceViewStore *store, struct filter_task *filter) | 1247 | void trace_view_store_filter_tasks(TraceViewStore *store, struct filter_task *filter) |
1068 | { | 1248 | { |
1069 | struct tracecmd_input *handle; | 1249 | struct tracecmd_input *handle; |
1250 | struct event_format *event; | ||
1070 | struct pevent *pevent; | 1251 | struct pevent *pevent; |
1071 | struct record *record; | 1252 | struct record *record; |
1253 | gint last_event_id = -1; | ||
1254 | gint event_id; | ||
1072 | gint pid; | 1255 | gint pid; |
1073 | gint cpu; | 1256 | gint cpu; |
1074 | gint i; | 1257 | gint i; |
1075 | 1258 | ||
1076 | g_return_if_fail (TRACE_VIEW_IS_LIST (store)); | 1259 | g_return_if_fail (TRACE_VIEW_IS_LIST (store)); |
1077 | 1260 | ||
1261 | /* We may pass in the store->task_filter. Don't free it if we do */ | ||
1262 | if (store->task_filter && store->task_filter != filter) | ||
1263 | filter_task_hash_free(store->task_filter); | ||
1264 | |||
1265 | store->task_filter = filter_task_hash_copy(filter); | ||
1266 | |||
1078 | handle = store->handle; | 1267 | handle = store->handle; |
1079 | pevent = tracecmd_get_pevent(store->handle); | 1268 | pevent = tracecmd_get_pevent(store->handle); |
1080 | 1269 | ||
@@ -1094,7 +1283,22 @@ void trace_view_store_filter_tasks(TraceViewStore *store, struct filter_task *fi | |||
1094 | 1283 | ||
1095 | g_assert(record->offset == store->cpu_list[cpu][i].offset); | 1284 | g_assert(record->offset == store->cpu_list[cpu][i].offset); |
1096 | 1285 | ||
1097 | /* TODO: put event filter check here */ | 1286 | /* The record may be filtered by the events */ |
1287 | if (!store->all_events) { | ||
1288 | event_id = pevent_data_type(pevent, record); | ||
1289 | if (last_event_id != event_id) { | ||
1290 | /* optimize: only search event when new */ | ||
1291 | event = pevent_find_event(pevent, event_id); | ||
1292 | g_assert(event); | ||
1293 | } | ||
1294 | last_event_id = event_id; | ||
1295 | if (!trace_view_store_system_enabled(store, event->system) && | ||
1296 | !trace_view_store_event_enabled(store, event_id)) { | ||
1297 | store->cpu_list[cpu][i].visible = 0; | ||
1298 | goto skip; | ||
1299 | } | ||
1300 | } | ||
1301 | |||
1098 | pid = pevent_data_pid(pevent, record); | 1302 | pid = pevent_data_pid(pevent, record); |
1099 | if (!filter || filter_task_find_pid(filter, pid)) | 1303 | if (!filter || filter_task_find_pid(filter, pid)) |
1100 | store->cpu_list[cpu][i].visible = 1; | 1304 | store->cpu_list[cpu][i].visible = 1; |
@@ -1108,10 +1312,11 @@ void trace_view_store_filter_tasks(TraceViewStore *store, struct filter_task *fi | |||
1108 | store->cpu_list[cpu][i].visible = 1; | 1312 | store->cpu_list[cpu][i].visible = 1; |
1109 | else | 1313 | else |
1110 | store->cpu_list[cpu][i].visible = 0; | 1314 | store->cpu_list[cpu][i].visible = 0; |
1111 | } | 1315 | } else |
1112 | store->cpu_list[cpu][i].visible = 0; | 1316 | store->cpu_list[cpu][i].visible = 0; |
1113 | } | 1317 | } |
1114 | 1318 | ||
1319 | skip: | ||
1115 | free_record(record); | 1320 | free_record(record); |
1116 | record = tracecmd_read_data(handle, cpu); | 1321 | record = tracecmd_read_data(handle, cpu); |
1117 | } | 1322 | } |
@@ -1121,6 +1326,14 @@ void trace_view_store_filter_tasks(TraceViewStore *store, struct filter_task *fi | |||
1121 | merge_sort_rows_ts(store); | 1326 | merge_sort_rows_ts(store); |
1122 | } | 1327 | } |
1123 | 1328 | ||
1329 | void trace_view_store_update_filter(TraceViewStore *store) | ||
1330 | { | ||
1331 | g_return_if_fail (TRACE_VIEW_IS_LIST (store)); | ||
1332 | |||
1333 | trace_view_store_filter_tasks(store, store->task_filter); | ||
1334 | } | ||
1335 | |||
1336 | |||
1124 | /***************************************************************************** | 1337 | /***************************************************************************** |
1125 | * | 1338 | * |
1126 | * trace_view_store_append_record: Empty lists are boring. This function can | 1339 | * trace_view_store_append_record: Empty lists are boring. This function can |
diff --git a/trace-view-store.h b/trace-view-store.h index 08caf3f..60f90a5 100644 --- a/trace-view-store.h +++ b/trace-view-store.h | |||
@@ -94,7 +94,10 @@ struct trace_view_store | |||
94 | gint all_events; /* set 1 when all events are enabled */ | 94 | gint all_events; /* set 1 when all events are enabled */ |
95 | /* else */ | 95 | /* else */ |
96 | gchar **systems; /* sorted list of systems that are enabled */ | 96 | gchar **systems; /* sorted list of systems that are enabled */ |
97 | gint **event_types; /* sorted list of events that are enabled */ | 97 | gint *event_types; /* sorted list of events that are enabled */ |
98 | gint systems_size; /* size of systems array */ | ||
99 | gint event_types_size; /* size of event_types array */ | ||
100 | struct filter_task *task_filter; /* hash of tasks to filter on */ | ||
98 | 101 | ||
99 | gint all_cpus; /* set 1 when all cpus are enabled */ | 102 | gint all_cpus; /* set 1 when all cpus are enabled */ |
100 | /* else */ | 103 | /* else */ |
@@ -121,7 +124,19 @@ void trace_view_store_filter_tasks(TraceViewStore *store, struct filter_task *fi | |||
121 | 124 | ||
122 | TraceViewRecord *trace_view_store_get_row(TraceViewStore *store, gint row); | 125 | TraceViewRecord *trace_view_store_get_row(TraceViewStore *store, gint row); |
123 | 126 | ||
124 | /* TraceViewStore methos */ | 127 | gboolean trace_view_store_system_enabled(TraceViewStore *store, const gchar *system); |
128 | |||
129 | gboolean trace_view_store_event_enabled(TraceViewStore *store, gint event_id); | ||
130 | |||
131 | void trace_view_store_set_all_events_enabled(TraceViewStore *store); | ||
132 | |||
133 | void trace_view_store_set_system_enabled(TraceViewStore *store, const gchar *system); | ||
134 | |||
135 | void trace_view_store_set_event_enabled(TraceViewStore *store, gint event_id); | ||
136 | |||
137 | void trace_view_store_update_filter(TraceViewStore *store); | ||
138 | |||
139 | /* TraceViewStore methods */ | ||
125 | GtkTreeModelFlags trace_view_store_get_flags (GtkTreeModel *tree_model); | 140 | GtkTreeModelFlags trace_view_store_get_flags (GtkTreeModel *tree_model); |
126 | 141 | ||
127 | gint trace_view_store_get_n_columns (GtkTreeModel *tree_model); | 142 | gint trace_view_store_get_n_columns (GtkTreeModel *tree_model); |
@@ -187,4 +202,23 @@ static inline GtkWidget *trace_view_store_get_spin(TraceViewStore *store) | |||
187 | return store->spin; | 202 | return store->spin; |
188 | } | 203 | } |
189 | 204 | ||
205 | static inline gboolean trace_view_store_get_all_events_enabled(TraceViewStore *store) | ||
206 | { | ||
207 | g_return_val_if_fail (TRACE_VIEW_IS_LIST (store), FALSE); | ||
208 | return store->all_events; | ||
209 | } | ||
210 | |||
211 | static inline gchar **trace_view_store_get_systems_enabled(TraceViewStore *store) | ||
212 | { | ||
213 | g_return_val_if_fail (TRACE_VIEW_IS_LIST (store), NULL); | ||
214 | return store->systems; | ||
215 | } | ||
216 | |||
217 | static inline gint *trace_view_store_get_events_enabled(TraceViewStore *store) | ||
218 | { | ||
219 | g_return_val_if_fail (TRACE_VIEW_IS_LIST (store), NULL); | ||
220 | return store->event_types; | ||
221 | } | ||
222 | |||
223 | |||
190 | #endif /* _trace_view_store_h_included_ */ | 224 | #endif /* _trace_view_store_h_included_ */ |