diff options
| author | Steven Rostedt <srostedt@redhat.com> | 2010-01-04 15:13:04 -0500 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2010-01-04 15:13:04 -0500 |
| commit | 39baeecb4afb317f8a20187f4edb280f4448e4df (patch) | |
| tree | 6032f09dadc800715275eb8d156b1b1225ff7cfd | |
| parent | f4541daee0c39a10bb886d38cf9f742fa7acc2a3 (diff) | |
kernel-shark: Enabled filtering of tasks for list and graph
The list and graph can now filter tasks.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
| -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); |
