diff options
author | Steven Rostedt <srostedt@redhat.com> | 2010-06-10 10:15:15 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2010-06-10 10:15:15 -0400 |
commit | 200cb94dd4a1f1f47c86a82c1dc665a67f426214 (patch) | |
tree | ff4c473da5835684cf9407506924b5cedf0266c1 | |
parent | 77441ff111de0fb54e4d00df57532333915be2e9 (diff) |
kernelshark: Add list and graph task filter menu
Add a list and graph task filter menu to the menu bar.
The tasks added to this filter are enabled by default.
This also adds a nice feature that you can pick and choose
tasks to filter from a dialog box.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r-- | kernel-shark.c | 208 | ||||
-rw-r--r-- | kernel-shark.h | 2 | ||||
-rw-r--r-- | trace-graph.c | 9 |
3 files changed, 198 insertions, 21 deletions
diff --git a/kernel-shark.c b/kernel-shark.c index e591657..7b13bdc 100644 --- a/kernel-shark.c +++ b/kernel-shark.c | |||
@@ -126,6 +126,23 @@ static int trace_sync_select_menu(const gchar *title, | |||
126 | return result; | 126 | return result; |
127 | } | 127 | } |
128 | 128 | ||
129 | static void update_tree_view_filters(struct shark_info *info, | ||
130 | struct filter_task *task_filter, | ||
131 | struct filter_task *hide_tasks) | ||
132 | { | ||
133 | if (info->list_filter_enabled) | ||
134 | trace_view_update_filters(info->treeview, | ||
135 | task_filter, hide_tasks); | ||
136 | |||
137 | if (filter_task_count(task_filter) || | ||
138 | filter_task_count(hide_tasks)) | ||
139 | info->list_filter_available = 1; | ||
140 | else { | ||
141 | info->list_filter_enabled = 0; | ||
142 | info->list_filter_available = 0; | ||
143 | } | ||
144 | } | ||
145 | |||
129 | /* graph callbacks */ | 146 | /* graph callbacks */ |
130 | 147 | ||
131 | /* convert_nano() and print_time() are copied from trace-graph.c for debugging | 148 | /* convert_nano() and print_time() are copied from trace-graph.c for debugging |
@@ -178,17 +195,7 @@ static void ks_graph_filter(struct graph_info *ginfo, | |||
178 | if (!info->sync_task_filters) | 195 | if (!info->sync_task_filters) |
179 | return; | 196 | return; |
180 | 197 | ||
181 | if (info->list_filter_enabled) | 198 | update_tree_view_filters(info, task_filter, hide_tasks); |
182 | trace_view_update_filters(info->treeview, | ||
183 | task_filter, hide_tasks); | ||
184 | |||
185 | if (filter_task_count(task_filter) || | ||
186 | filter_task_count(hide_tasks)) | ||
187 | info->list_filter_available = 1; | ||
188 | else { | ||
189 | info->list_filter_enabled = 0; | ||
190 | info->list_filter_available = 0; | ||
191 | } | ||
192 | } | 199 | } |
193 | 200 | ||
194 | static void free_info(struct shark_info *info) | 201 | static void free_info(struct shark_info *info) |
@@ -342,6 +349,10 @@ sync_task_filter_clicked (GtkWidget *subitem, gpointer data) | |||
342 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->task_sync_menu), | 349 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->task_sync_menu), |
343 | "Sync Graph and List Task Filters"); | 350 | "Sync Graph and List Task Filters"); |
344 | 351 | ||
352 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->graph_task_menu), | ||
353 | "graph task filter"); | ||
354 | gtk_widget_show(info->list_task_menu); | ||
355 | |||
345 | /* The list now uses its own hash */ | 356 | /* The list now uses its own hash */ |
346 | info->list_task_filter = filter_task_hash_copy(info->ginfo->task_filter); | 357 | info->list_task_filter = filter_task_hash_copy(info->ginfo->task_filter); |
347 | info->list_hide_tasks = filter_task_hash_copy(info->ginfo->hide_tasks); | 358 | info->list_hide_tasks = filter_task_hash_copy(info->ginfo->hide_tasks); |
@@ -375,16 +386,7 @@ sync_task_filter_clicked (GtkWidget *subitem, gpointer data) | |||
375 | info->list_hide_tasks = filter_task_hash_copy(hide_tasks); | 386 | info->list_hide_tasks = filter_task_hash_copy(hide_tasks); |
376 | } | 387 | } |
377 | 388 | ||
378 | if (info->list_filter_enabled) | 389 | update_tree_view_filters(info, task_filter, hide_tasks); |
379 | trace_view_update_filters(info->treeview, | ||
380 | task_filter, hide_tasks); | ||
381 | |||
382 | if (!filter_task_count(task_filter) && | ||
383 | !filter_task_count(hide_tasks)) { | ||
384 | info->list_filter_enabled = 0; | ||
385 | info->list_filter_available = 0; | ||
386 | } else | ||
387 | info->list_filter_available = 1; | ||
388 | 390 | ||
389 | break; | 391 | break; |
390 | case 1: | 392 | case 1: |
@@ -409,7 +411,136 @@ sync_task_filter_clicked (GtkWidget *subitem, gpointer data) | |||
409 | info->sync_task_filters = 1; | 411 | info->sync_task_filters = 1; |
410 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->task_sync_menu), | 412 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->task_sync_menu), |
411 | "Unsync Graph and List Task Filters"); | 413 | "Unsync Graph and List Task Filters"); |
414 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->graph_task_menu), | ||
415 | "task filter"); | ||
416 | gtk_widget_hide(info->list_task_menu); | ||
417 | } | ||
418 | } | ||
419 | |||
420 | static void filter_list_enable_clicked (gpointer data); | ||
421 | |||
422 | static void | ||
423 | update_list_task_filter_callback(gboolean accept, | ||
424 | gint *selected, | ||
425 | gint *non_select, | ||
426 | gpointer data) | ||
427 | { | ||
428 | struct shark_info *info = data; | ||
429 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); | ||
430 | GtkTreeModel *model; | ||
431 | TraceViewStore *store; | ||
432 | int i; | ||
433 | |||
434 | if (!accept) | ||
435 | return; | ||
436 | |||
437 | model = gtk_tree_view_get_model(trace_tree); | ||
438 | if (!model) | ||
439 | return; | ||
440 | |||
441 | store = TRACE_VIEW_STORE(model); | ||
442 | |||
443 | filter_task_clear(info->list_task_filter); | ||
444 | |||
445 | if (selected) { | ||
446 | for (i = 0; selected[i] >= 0; i++) | ||
447 | filter_task_add_pid(info->list_task_filter, selected[i]); | ||
412 | } | 448 | } |
449 | |||
450 | update_tree_view_filters(info, info->list_task_filter, info->list_hide_tasks); | ||
451 | |||
452 | /* | ||
453 | * The menu filters always enable the filters. | ||
454 | */ | ||
455 | if (info->list_filter_available && !info->list_filter_enabled) | ||
456 | filter_list_enable_clicked(info); | ||
457 | } | ||
458 | |||
459 | /* Callback for the clicked signal of the List Tasks filter button */ | ||
460 | static void | ||
461 | list_tasks_clicked (gpointer data) | ||
462 | { | ||
463 | struct shark_info *info = data; | ||
464 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); | ||
465 | struct graph_info *ginfo = info->ginfo; | ||
466 | GtkTreeModel *model; | ||
467 | TraceViewStore *store; | ||
468 | gint *selected; | ||
469 | gint *tasks; | ||
470 | |||
471 | if (!ginfo->handle) | ||
472 | return; | ||
473 | |||
474 | model = gtk_tree_view_get_model(trace_tree); | ||
475 | if (!model) | ||
476 | return; | ||
477 | |||
478 | store = TRACE_VIEW_STORE(model); | ||
479 | |||
480 | tasks = trace_graph_task_list(ginfo); | ||
481 | selected = filter_task_pids(info->list_task_filter); | ||
482 | |||
483 | trace_task_dialog(info->handle, tasks, selected, | ||
484 | update_list_task_filter_callback, info); | ||
485 | |||
486 | free(tasks); | ||
487 | free(selected); | ||
488 | } | ||
489 | |||
490 | static void | ||
491 | update_graph_task_filter_callback(gboolean accept, | ||
492 | gint *selected, | ||
493 | gint *non_select, | ||
494 | gpointer data) | ||
495 | { | ||
496 | struct shark_info *info = data; | ||
497 | struct graph_info *ginfo = info->ginfo; | ||
498 | int i; | ||
499 | |||
500 | if (!accept) | ||
501 | return; | ||
502 | |||
503 | filter_task_clear(ginfo->task_filter); | ||
504 | |||
505 | if (selected) { | ||
506 | for (i = 0; selected[i] >= 0; i++) | ||
507 | filter_task_add_pid(ginfo->task_filter, selected[i]); | ||
508 | } | ||
509 | |||
510 | trace_graph_refresh_filters(ginfo); | ||
511 | |||
512 | /* | ||
513 | * The menu filters always enable the filters. | ||
514 | */ | ||
515 | if (ginfo->filter_available) { | ||
516 | if (!ginfo->filter_enabled) | ||
517 | trace_graph_filter_toggle(info->ginfo); | ||
518 | |||
519 | if (info->sync_task_filters && !info->list_filter_enabled) | ||
520 | filter_list_enable_clicked(info); | ||
521 | } | ||
522 | } | ||
523 | |||
524 | /* Callback for the clicked signal of the Tasks filter button */ | ||
525 | static void | ||
526 | graph_tasks_clicked (gpointer data) | ||
527 | { | ||
528 | struct shark_info *info = data; | ||
529 | struct graph_info *ginfo = info->ginfo; | ||
530 | gint *selected; | ||
531 | gint *tasks; | ||
532 | |||
533 | if (!ginfo->handle) | ||
534 | return; | ||
535 | |||
536 | tasks = trace_graph_task_list(ginfo); | ||
537 | selected = filter_task_pids(ginfo->task_filter); | ||
538 | |||
539 | trace_task_dialog(ginfo->handle, tasks, selected, | ||
540 | update_graph_task_filter_callback, info); | ||
541 | |||
542 | free(tasks); | ||
543 | free(selected); | ||
413 | } | 544 | } |
414 | 545 | ||
415 | /* Callback for the clicked signal of the Events filter button */ | 546 | /* Callback for the clicked signal of the Events filter button */ |
@@ -1247,6 +1378,41 @@ void kernel_shark(int argc, char **argv) | |||
1247 | gtk_widget_show(sub_item); | 1378 | gtk_widget_show(sub_item); |
1248 | 1379 | ||
1249 | 1380 | ||
1381 | /* --- Filter - List Tasks Option --- */ | ||
1382 | |||
1383 | sub_item = gtk_menu_item_new_with_label("list task filter"); | ||
1384 | |||
1385 | /* Add them to the menu */ | ||
1386 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
1387 | |||
1388 | /* We can attach the Quit menu item to our exit function */ | ||
1389 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
1390 | G_CALLBACK (list_tasks_clicked), | ||
1391 | (gpointer) info); | ||
1392 | |||
1393 | info->list_task_menu = sub_item; | ||
1394 | |||
1395 | /* Only show this item when list and graph tasks are not synced */ | ||
1396 | |||
1397 | |||
1398 | /* --- Filter - Graph Tasks Option --- */ | ||
1399 | |||
1400 | sub_item = gtk_menu_item_new_with_label("task filter"); | ||
1401 | |||
1402 | /* Add them to the menu */ | ||
1403 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
1404 | |||
1405 | /* We can attach the Quit menu item to our exit function */ | ||
1406 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
1407 | G_CALLBACK (graph_tasks_clicked), | ||
1408 | (gpointer) info); | ||
1409 | |||
1410 | info->graph_task_menu = sub_item; | ||
1411 | |||
1412 | /* We do need to show menu items */ | ||
1413 | gtk_widget_show(sub_item); | ||
1414 | |||
1415 | |||
1250 | /* --- Filter - List Events Option --- */ | 1416 | /* --- Filter - List Events Option --- */ |
1251 | 1417 | ||
1252 | sub_item = gtk_menu_item_new_with_label("list events"); | 1418 | sub_item = gtk_menu_item_new_with_label("list events"); |
diff --git a/kernel-shark.h b/kernel-shark.h index f931406..d537332 100644 --- a/kernel-shark.h +++ b/kernel-shark.h | |||
@@ -31,6 +31,8 @@ struct shark_info { | |||
31 | GtkWidget *treeview; | 31 | GtkWidget *treeview; |
32 | GtkWidget *spin; | 32 | GtkWidget *spin; |
33 | GtkWidget *task_sync_menu; | 33 | GtkWidget *task_sync_menu; |
34 | GtkWidget *list_task_menu; | ||
35 | GtkWidget *graph_task_menu; | ||
34 | struct graph_callbacks graph_cbs; | 36 | struct graph_callbacks graph_cbs; |
35 | gint selected_task; | 37 | gint selected_task; |
36 | gboolean list_filter_enabled; | 38 | gboolean list_filter_enabled; |
diff --git a/trace-graph.c b/trace-graph.c index 319b159..04e2439 100644 --- a/trace-graph.c +++ b/trace-graph.c | |||
@@ -569,6 +569,15 @@ void trace_graph_update_filters(struct graph_info *ginfo, | |||
569 | 569 | ||
570 | if (ginfo->filter_enabled) | 570 | if (ginfo->filter_enabled) |
571 | redraw_graph(ginfo); | 571 | redraw_graph(ginfo); |
572 | |||
573 | if (filter_task_count(ginfo->task_filter) || | ||
574 | filter_task_count(ginfo->hide_tasks)) | ||
575 | ginfo->filter_available = 1; | ||
576 | else { | ||
577 | ginfo->filter_enabled = 0; | ||
578 | ginfo->filter_available = 0; | ||
579 | } | ||
580 | |||
572 | } | 581 | } |
573 | 582 | ||
574 | void trace_graph_refresh_filters(struct graph_info *ginfo) | 583 | void trace_graph_refresh_filters(struct graph_info *ginfo) |