diff options
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | kernel-shark.c | 77 | ||||
-rw-r--r-- | kernel-shark.h | 1 | ||||
-rw-r--r-- | trace-view-store.c | 37 | ||||
-rw-r--r-- | trace-view-store.h | 3 | ||||
-rw-r--r-- | trace-view.c | 95 | ||||
-rw-r--r-- | trace-view.h | 2 |
7 files changed, 201 insertions, 19 deletions
@@ -28,7 +28,7 @@ all: $(TARGETS) | |||
28 | 28 | ||
29 | LIB_FILE = libtracecmd.a | 29 | LIB_FILE = libtracecmd.a |
30 | 30 | ||
31 | HEADERS = parse-events.h trace-cmd.h trace-local.h | 31 | HEADERS = parse-events.h trace-cmd.h trace-local.h trace-hash.h |
32 | 32 | ||
33 | trace-read.o:: $(HEADERS) | 33 | trace-read.o:: $(HEADERS) |
34 | trace-cmd.o:: $(HEADERS) $(LIB_FILE) | 34 | trace-cmd.o:: $(HEADERS) $(LIB_FILE) |
@@ -43,7 +43,8 @@ trace-graph.o:: $(HEADERS) trace-graph.h | |||
43 | trace-graph-main.o:: $(HEADERS) trace-graph.h | 43 | trace-graph-main.o:: $(HEADERS) trace-graph.h |
44 | kernel-shark.o:: $(HEADERS) kernel-shark.h | 44 | kernel-shark.o:: $(HEADERS) kernel-shark.h |
45 | 45 | ||
46 | TRACE_VIEW_OBJS = trace-view.o trace-view-store.o trace-filter.o trace-compat.o | 46 | TRACE_VIEW_OBJS = trace-view.o trace-view-store.o trace-filter.o trace-compat.o \ |
47 | trace-hash.o | ||
47 | 48 | ||
48 | trace-cmd:: trace-cmd.o trace-read.o | 49 | trace-cmd:: trace-cmd.o trace-read.o |
49 | $(CC) $^ -rdynamic -o $@ $(LIBS) | 50 | $(CC) $^ -rdynamic -o $@ $(LIBS) |
diff --git a/kernel-shark.c b/kernel-shark.c index 9cbc45a..fbc5a5f 100644 --- a/kernel-shark.c +++ b/kernel-shark.c | |||
@@ -156,7 +156,7 @@ static void row_double_clicked(GtkTreeView *treeview, | |||
156 | } | 156 | } |
157 | 157 | ||
158 | static void | 158 | static void |
159 | filter_enable_clicked (gpointer data) | 159 | filter_graph_enable_clicked (gpointer data) |
160 | { | 160 | { |
161 | struct shark_info *info = data; | 161 | struct shark_info *info = data; |
162 | 162 | ||
@@ -164,11 +164,36 @@ filter_enable_clicked (gpointer data) | |||
164 | } | 164 | } |
165 | 165 | ||
166 | static void | 166 | static void |
167 | filter_list_enable_clicked (gpointer data) | ||
168 | { | ||
169 | struct shark_info *info = data; | ||
170 | |||
171 | info->list_filter_enabled ^= 1; | ||
172 | |||
173 | if (info->list_filter_enabled) | ||
174 | trace_view_update_task_filter(info->treeview, | ||
175 | info->ginfo->task_filter); | ||
176 | else | ||
177 | trace_view_update_task_filter(info->treeview, NULL); | ||
178 | } | ||
179 | |||
180 | static void | ||
167 | filter_add_task_clicked (gpointer data) | 181 | filter_add_task_clicked (gpointer data) |
168 | { | 182 | { |
169 | struct shark_info *info = data; | 183 | struct shark_info *info = data; |
170 | 184 | ||
171 | trace_graph_filter_add_remove_task(info->ginfo, info->selected_task); | 185 | trace_graph_filter_add_remove_task(info->ginfo, info->selected_task); |
186 | |||
187 | if (info->list_filter_enabled) { | ||
188 | if (filter_task_count(info->ginfo->task_filter)) | ||
189 | trace_view_update_task_filter(info->treeview, | ||
190 | info->ginfo->task_filter); | ||
191 | else | ||
192 | trace_view_update_task_filter(info->treeview, NULL); | ||
193 | } | ||
194 | |||
195 | if (!filter_task_count(info->ginfo->task_filter)) | ||
196 | info->list_filter_enabled = 0; | ||
172 | } | 197 | } |
173 | 198 | ||
174 | static void | 199 | static void |
@@ -177,6 +202,11 @@ filter_clear_tasks_clicked (gpointer data) | |||
177 | struct shark_info *info = data; | 202 | struct shark_info *info = data; |
178 | 203 | ||
179 | trace_graph_clear_tasks(info->ginfo); | 204 | trace_graph_clear_tasks(info->ginfo); |
205 | |||
206 | if (info->list_filter_enabled) | ||
207 | trace_view_update_task_filter(info->treeview, NULL); | ||
208 | |||
209 | info->list_filter_enabled = 0; | ||
180 | } | 210 | } |
181 | 211 | ||
182 | static gboolean | 212 | static gboolean |
@@ -185,7 +215,8 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
185 | struct shark_info *info = data; | 215 | struct shark_info *info = data; |
186 | struct graph_info *ginfo = info->ginfo; | 216 | struct graph_info *ginfo = info->ginfo; |
187 | static GtkWidget *menu; | 217 | static GtkWidget *menu; |
188 | static GtkWidget *menu_filter_enable; | 218 | static GtkWidget *menu_filter_graph_enable; |
219 | static GtkWidget *menu_filter_list_enable; | ||
189 | static GtkWidget *menu_filter_add_task; | 220 | static GtkWidget *menu_filter_add_task; |
190 | static GtkWidget *menu_filter_clear_tasks; | 221 | static GtkWidget *menu_filter_clear_tasks; |
191 | struct record *record; | 222 | struct record *record; |
@@ -205,12 +236,20 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
205 | 236 | ||
206 | if (!menu) { | 237 | if (!menu) { |
207 | menu = gtk_menu_new(); | 238 | menu = gtk_menu_new(); |
208 | menu_filter_enable = gtk_menu_item_new_with_label("Enable Filter"); | 239 | menu_filter_graph_enable = gtk_menu_item_new_with_label("Enable Graph Filter"); |
209 | gtk_widget_show(menu_filter_enable); | 240 | gtk_widget_show(menu_filter_graph_enable); |
210 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_enable); | 241 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_graph_enable); |
211 | 242 | ||
212 | g_signal_connect_swapped (G_OBJECT (menu_filter_enable), "activate", | 243 | g_signal_connect_swapped (G_OBJECT (menu_filter_graph_enable), "activate", |
213 | G_CALLBACK (filter_enable_clicked), | 244 | G_CALLBACK (filter_graph_enable_clicked), |
245 | data); | ||
246 | |||
247 | menu_filter_list_enable = gtk_menu_item_new_with_label("Enable List Filter"); | ||
248 | gtk_widget_show(menu_filter_list_enable); | ||
249 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_list_enable); | ||
250 | |||
251 | g_signal_connect_swapped (G_OBJECT (menu_filter_list_enable), "activate", | ||
252 | G_CALLBACK (filter_list_enable_clicked), | ||
214 | data); | 253 | data); |
215 | 254 | ||
216 | menu_filter_add_task = gtk_menu_item_new_with_label("Add Task"); | 255 | menu_filter_add_task = gtk_menu_item_new_with_label("Add Task"); |
@@ -276,16 +315,26 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
276 | gtk_widget_hide(menu_filter_add_task); | 315 | gtk_widget_hide(menu_filter_add_task); |
277 | 316 | ||
278 | if (ginfo->filter_enabled) | 317 | if (ginfo->filter_enabled) |
279 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_enable), | 318 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_graph_enable), |
280 | "Disable Filter"); | 319 | "Disable Graph Filter"); |
281 | else | 320 | else |
282 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_enable), | 321 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_graph_enable), |
283 | "Enable Filter"); | 322 | "Enable Graph Filter"); |
284 | 323 | ||
285 | if (ginfo->filter_available) | 324 | if (info->list_filter_enabled) |
286 | gtk_widget_set_sensitive(menu_filter_enable, TRUE); | 325 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_list_enable), |
326 | "Disable List Filter"); | ||
287 | else | 327 | else |
288 | gtk_widget_set_sensitive(menu_filter_enable, FALSE); | 328 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_list_enable), |
329 | "Enable List Filter"); | ||
330 | |||
331 | if (ginfo->filter_available) { | ||
332 | gtk_widget_set_sensitive(menu_filter_graph_enable, TRUE); | ||
333 | gtk_widget_set_sensitive(menu_filter_list_enable, TRUE); | ||
334 | } else { | ||
335 | gtk_widget_set_sensitive(menu_filter_graph_enable, FALSE); | ||
336 | gtk_widget_set_sensitive(menu_filter_list_enable, FALSE); | ||
337 | } | ||
289 | 338 | ||
290 | if (filter_task_count(ginfo->task_filter)) | 339 | if (filter_task_count(ginfo->task_filter)) |
291 | gtk_widget_set_sensitive(menu_filter_clear_tasks, TRUE); | 340 | gtk_widget_set_sensitive(menu_filter_clear_tasks, TRUE); |
diff --git a/kernel-shark.h b/kernel-shark.h index 59d7b7a..34b2031 100644 --- a/kernel-shark.h +++ b/kernel-shark.h | |||
@@ -11,6 +11,7 @@ struct shark_info { | |||
11 | GtkWidget *treeview; | 11 | GtkWidget *treeview; |
12 | struct graph_callbacks graph_cbs; | 12 | struct graph_callbacks graph_cbs; |
13 | gint selected_task; | 13 | gint selected_task; |
14 | gboolean list_filter_enabled; | ||
14 | }; | 15 | }; |
15 | 16 | ||
16 | #define offset_of(type, field) (long)(&((type *)0)->field) | 17 | #define offset_of(type, field) (long)(&((type *)0)->field) |
diff --git a/trace-view-store.c b/trace-view-store.c index 04debbb..1f1e952 100644 --- a/trace-view-store.c +++ b/trace-view-store.c | |||
@@ -1075,6 +1075,43 @@ guint64 trace_view_store_get_offset_from_row(TraceViewStore *store, gint row) | |||
1075 | return store->rows[row]->offset; | 1075 | return store->rows[row]->offset; |
1076 | } | 1076 | } |
1077 | 1077 | ||
1078 | void trace_view_store_filter_tasks(TraceViewStore *store, struct filter_task *filter) | ||
1079 | { | ||
1080 | struct tracecmd_input *handle; | ||
1081 | struct pevent *pevent; | ||
1082 | struct record *record; | ||
1083 | gint pid; | ||
1084 | gint cpu; | ||
1085 | gint i; | ||
1086 | |||
1087 | g_return_if_fail (TRACE_VIEW_IS_LIST (store)); | ||
1088 | |||
1089 | handle = store->handle; | ||
1090 | pevent = tracecmd_get_pevent(store->handle); | ||
1091 | |||
1092 | for (cpu = 0; cpu < store->cpus; cpu++) { | ||
1093 | record = tracecmd_read_cpu_first(handle, cpu); | ||
1094 | |||
1095 | for (i = 0; i < store->cpu_items[cpu]; i++) { | ||
1096 | |||
1097 | g_assert(record->offset == store->cpu_list[cpu][i].offset); | ||
1098 | |||
1099 | /* TODO: put event filter check here */ | ||
1100 | pid = pevent_data_pid(pevent, record); | ||
1101 | if (!filter || filter_task_find_pid(filter, pid)) | ||
1102 | store->cpu_list[cpu][i].visible = 1; | ||
1103 | else | ||
1104 | store->cpu_list[cpu][i].visible = 0; | ||
1105 | |||
1106 | free_record(record); | ||
1107 | record = tracecmd_read_data(handle, cpu); | ||
1108 | } | ||
1109 | g_assert(record == NULL); | ||
1110 | } | ||
1111 | |||
1112 | merge_sort_rows_ts(store); | ||
1113 | } | ||
1114 | |||
1078 | /***************************************************************************** | 1115 | /***************************************************************************** |
1079 | * | 1116 | * |
1080 | * trace_view_store_append_record: Empty lists are boring. This function can | 1117 | * 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 687a946..c7738da 100644 --- a/trace-view-store.h +++ b/trace-view-store.h | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include <gtk/gtk.h> | 4 | #include <gtk/gtk.h> |
5 | #include "trace-cmd.h" | 5 | #include "trace-cmd.h" |
6 | #include "trace-hash.h" | ||
6 | 7 | ||
7 | /* Some boilerplate GObject defines. 'klass' is used | 8 | /* Some boilerplate GObject defines. 'klass' is used |
8 | * instead of 'class', because 'class' is a C++ keyword */ | 9 | * instead of 'class', because 'class' is a C++ keyword */ |
@@ -118,6 +119,8 @@ guint64 trace_view_store_get_time_from_row(TraceViewStore *store, gint row); | |||
118 | 119 | ||
119 | guint64 trace_view_store_get_offset_from_row(TraceViewStore *store, gint row); | 120 | guint64 trace_view_store_get_offset_from_row(TraceViewStore *store, gint row); |
120 | 121 | ||
122 | void trace_view_store_filter_tasks(TraceViewStore *store, struct filter_task *filter); | ||
123 | |||
121 | /* TraceViewStoreClass: more boilerplate GObject stuff */ | 124 | /* TraceViewStoreClass: more boilerplate GObject stuff */ |
122 | 125 | ||
123 | struct _TraceViewStoreClass | 126 | struct _TraceViewStoreClass |
diff --git a/trace-view.c b/trace-view.c index 6dd72ee..f9083f4 100644 --- a/trace-view.c +++ b/trace-view.c | |||
@@ -207,6 +207,96 @@ trace_view_load(GtkWidget *view, struct tracecmd_input *handle, | |||
207 | g_object_unref(model); /* destroy model automatically with view */ | 207 | g_object_unref(model); /* destroy model automatically with view */ |
208 | } | 208 | } |
209 | 209 | ||
210 | /** | ||
211 | * trace_view_get_selected_row - return the selected row | ||
212 | * @treeview: The tree view | ||
213 | * | ||
214 | * Returns the selected row number (or -1 if none is selected) | ||
215 | */ | ||
216 | gint trace_view_get_selected_row(GtkWidget *treeview) | ||
217 | { | ||
218 | GtkTreeView *tree = GTK_TREE_VIEW(treeview); | ||
219 | GtkTreeSelection *selection; | ||
220 | GtkTreeModel *model; | ||
221 | GtkTreePath *path; | ||
222 | gchar *spath; | ||
223 | GList *glist; | ||
224 | gint row; | ||
225 | |||
226 | model = gtk_tree_view_get_model(tree); | ||
227 | if (!model) | ||
228 | return -1; | ||
229 | |||
230 | selection = gtk_tree_view_get_selection(tree); | ||
231 | glist = gtk_tree_selection_get_selected_rows(selection, &model); | ||
232 | if (!glist) | ||
233 | return -1; | ||
234 | |||
235 | /* Only one row may be selected */ | ||
236 | path = glist->data; | ||
237 | spath = gtk_tree_path_to_string(path); | ||
238 | row = atoi(spath); | ||
239 | g_free(spath); | ||
240 | |||
241 | gtk_tree_path_free(path); | ||
242 | g_list_free(glist); | ||
243 | |||
244 | return row; | ||
245 | } | ||
246 | |||
247 | void trace_view_make_selection_visible(GtkWidget *treeview) | ||
248 | { | ||
249 | GtkTreeView *tree = GTK_TREE_VIEW(treeview); | ||
250 | GtkTreePath *path; | ||
251 | gchar *spath; | ||
252 | GString *gstr; | ||
253 | gint row; | ||
254 | |||
255 | row = trace_view_get_selected_row(treeview); | ||
256 | if (row < 0) | ||
257 | return; | ||
258 | |||
259 | gstr = g_string_new(""); | ||
260 | g_string_printf(gstr, "%d", row); | ||
261 | spath = g_string_free(gstr, FALSE); | ||
262 | |||
263 | path = gtk_tree_path_new_from_string(spath); | ||
264 | g_free(spath); | ||
265 | |||
266 | gtk_tree_view_scroll_to_cell(tree, path, NULL, TRUE, 0.5, 0.0); | ||
267 | |||
268 | gtk_tree_path_free(path); | ||
269 | } | ||
270 | |||
271 | void trace_view_update_task_filter(GtkWidget *treeview, struct filter_task *filter) | ||
272 | { | ||
273 | GtkTreeView *tree = GTK_TREE_VIEW(treeview); | ||
274 | GtkTreeModel *model; | ||
275 | guint64 time; | ||
276 | gint row; | ||
277 | |||
278 | model = gtk_tree_view_get_model(tree); | ||
279 | if (!model) | ||
280 | return; | ||
281 | |||
282 | /* Keep track of the currently selected row */ | ||
283 | row = trace_view_get_selected_row(treeview); | ||
284 | if (row >= 0) | ||
285 | time = trace_view_store_get_time_from_row(TRACE_VIEW_STORE(model), row); | ||
286 | |||
287 | g_object_ref(model); | ||
288 | gtk_tree_view_set_model(tree, NULL); | ||
289 | |||
290 | trace_view_store_filter_tasks(TRACE_VIEW_STORE(model), filter); | ||
291 | |||
292 | gtk_tree_view_set_model(tree, model); | ||
293 | g_object_unref(model); | ||
294 | |||
295 | /* Keep selection near previous selection */ | ||
296 | if (row >= 0) | ||
297 | trace_view_select(treeview, time); | ||
298 | } | ||
299 | |||
210 | void trace_view_select(GtkWidget *treeview, guint64 time) | 300 | void trace_view_select(GtkWidget *treeview, guint64 time) |
211 | { | 301 | { |
212 | GtkTreeView *tree = GTK_TREE_VIEW(treeview); | 302 | GtkTreeView *tree = GTK_TREE_VIEW(treeview); |
@@ -251,9 +341,8 @@ void trace_view_select(GtkWidget *treeview, guint64 time) | |||
251 | 341 | ||
252 | selection = gtk_tree_view_get_selection(tree); | 342 | selection = gtk_tree_view_get_selection(tree); |
253 | gtk_tree_selection_select_path(selection, path); | 343 | gtk_tree_selection_select_path(selection, path); |
344 | gtk_tree_path_free(path); | ||
254 | 345 | ||
255 | /* finally, make it visible */ | 346 | /* finally, make it visible */ |
256 | gtk_tree_view_scroll_to_cell(tree, path, NULL, TRUE, 0.5, 0.0); | 347 | trace_view_make_selection_visible(treeview); |
257 | |||
258 | gtk_tree_path_free(path); | ||
259 | } | 348 | } |
diff --git a/trace-view.h b/trace-view.h index 57662df..03d331c 100644 --- a/trace-view.h +++ b/trace-view.h | |||
@@ -9,6 +9,8 @@ trace_view_load(GtkWidget *view, struct tracecmd_input *handle, | |||
9 | 9 | ||
10 | void trace_view(int argc, char **argv); | 10 | void trace_view(int argc, char **argv); |
11 | 11 | ||
12 | void trace_view_update_task_filter(GtkWidget *treeview, struct filter_task *filter); | ||
13 | void trace_view_make_selection_visible(GtkWidget *treeview); | ||
12 | 14 | ||
13 | /* We use void because this can be used by non gtk files */ | 15 | /* We use void because this can be used by non gtk files */ |
14 | void trace_filter_event_dialog(void *traceview); | 16 | void trace_filter_event_dialog(void *traceview); |