diff options
-rw-r--r-- | kernel-shark.c | 448 | ||||
-rw-r--r-- | kernel-shark.h | 5 | ||||
-rw-r--r-- | trace-graph.c | 14 | ||||
-rw-r--r-- | trace-graph.h | 3 | ||||
-rw-r--r-- | trace-view-store.c | 1 |
5 files changed, 424 insertions, 47 deletions
diff --git a/kernel-shark.c b/kernel-shark.c index b056420..e591657 100644 --- a/kernel-shark.c +++ b/kernel-shark.c | |||
@@ -64,6 +64,68 @@ void usage(char *prog) | |||
64 | printf(" -i input_file, default is %s\n", default_input_file); | 64 | printf(" -i input_file, default is %s\n", default_input_file); |
65 | } | 65 | } |
66 | 66 | ||
67 | /* | ||
68 | * trace_sync_select_menu - helper function to the syncing of list and graph filters | ||
69 | * | ||
70 | * Creates a pop up dialog with the selections given. The selections will be | ||
71 | * radio buttons to the user. The keep is a value that will be set to the check | ||
72 | * box (default on) if the user wants to keep the selection persistant. | ||
73 | */ | ||
74 | static int trace_sync_select_menu(const gchar *title, | ||
75 | gchar **selections, gboolean *keep) | ||
76 | { | ||
77 | GtkWidget *dialog; | ||
78 | GtkWidget *radio; | ||
79 | GtkWidget *check; | ||
80 | GSList *group; | ||
81 | int result; | ||
82 | int i; | ||
83 | |||
84 | dialog = gtk_dialog_new_with_buttons(title, | ||
85 | NULL, | ||
86 | GTK_DIALOG_MODAL, | ||
87 | "OK", GTK_RESPONSE_ACCEPT, | ||
88 | GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | ||
89 | NULL); | ||
90 | |||
91 | radio = gtk_radio_button_new_with_label(NULL, selections[0]); | ||
92 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), radio, TRUE, TRUE, 0); | ||
93 | gtk_widget_show(radio); | ||
94 | |||
95 | group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio)); | ||
96 | |||
97 | for (i = 1; selections[i]; i++) { | ||
98 | radio = gtk_radio_button_new_with_label(group, selections[i]); | ||
99 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), radio, TRUE, TRUE, 0); | ||
100 | gtk_widget_show(radio); | ||
101 | } | ||
102 | |||
103 | check = gtk_check_button_new_with_label("Keep the filters in sync?"); | ||
104 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), check, TRUE, TRUE, 0); | ||
105 | gtk_widget_show(check); | ||
106 | |||
107 | gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE); | ||
108 | |||
109 | result = gtk_dialog_run(GTK_DIALOG(dialog)); | ||
110 | switch (result) { | ||
111 | case GTK_RESPONSE_ACCEPT: | ||
112 | i = 0; | ||
113 | for (i = 0; group; i++, group = g_slist_next(group)) { | ||
114 | radio = group->data; | ||
115 | if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio))) | ||
116 | break; | ||
117 | } | ||
118 | result = i; | ||
119 | *keep = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check)); | ||
120 | break; | ||
121 | default: | ||
122 | result = -1; | ||
123 | } | ||
124 | |||
125 | gtk_widget_destroy(dialog); | ||
126 | return result; | ||
127 | } | ||
128 | |||
67 | /* graph callbacks */ | 129 | /* graph callbacks */ |
68 | 130 | ||
69 | /* convert_nano() and print_time() are copied from trace-graph.c for debugging | 131 | /* convert_nano() and print_time() are copied from trace-graph.c for debugging |
@@ -113,15 +175,30 @@ static void ks_graph_filter(struct graph_info *ginfo, | |||
113 | cbs = trace_graph_get_callbacks(ginfo); | 175 | cbs = trace_graph_get_callbacks(ginfo); |
114 | info = container_of(cbs, struct shark_info, graph_cbs); | 176 | info = container_of(cbs, struct shark_info, graph_cbs); |
115 | 177 | ||
178 | if (!info->sync_task_filters) | ||
179 | return; | ||
180 | |||
116 | if (info->list_filter_enabled) | 181 | if (info->list_filter_enabled) |
117 | trace_view_update_filters(info->treeview, | 182 | trace_view_update_filters(info->treeview, |
118 | task_filter, hide_tasks); | 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 | } | ||
119 | } | 192 | } |
120 | 193 | ||
121 | static void free_info(struct shark_info *info) | 194 | static void free_info(struct shark_info *info) |
122 | { | 195 | { |
123 | tracecmd_close(info->handle); | 196 | tracecmd_close(info->handle); |
124 | trace_graph_free_info(info->ginfo); | 197 | trace_graph_free_info(info->ginfo); |
198 | |||
199 | filter_task_hash_free(info->list_task_filter); | ||
200 | filter_task_hash_free(info->list_hide_tasks); | ||
201 | |||
125 | free(info->ginfo); | 202 | free(info->ginfo); |
126 | free(info); | 203 | free(info); |
127 | } | 204 | } |
@@ -244,6 +321,99 @@ delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) | |||
244 | 321 | ||
245 | /* Callback for the clicked signal of the Events filter button */ | 322 | /* Callback for the clicked signal of the Events filter button */ |
246 | static void | 323 | static void |
324 | sync_task_filter_clicked (GtkWidget *subitem, gpointer data) | ||
325 | { | ||
326 | struct shark_info *info = data; | ||
327 | struct filter_task *task_filter; | ||
328 | struct filter_task *hide_tasks; | ||
329 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); | ||
330 | GtkTreeModel *model; | ||
331 | TraceViewStore *store; | ||
332 | gboolean keep; | ||
333 | gchar *selections[] = { "Sync List Filter with Graph Filter", | ||
334 | "Sync Graph Filter with List Filter", | ||
335 | NULL }; | ||
336 | int result; | ||
337 | |||
338 | if (info->sync_task_filters) { | ||
339 | /* Separate the List and Graph filters */ | ||
340 | |||
341 | info->sync_task_filters = 0; | ||
342 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->task_sync_menu), | ||
343 | "Sync Graph and List Task Filters"); | ||
344 | |||
345 | /* The list now uses its own hash */ | ||
346 | 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); | ||
348 | return; | ||
349 | } | ||
350 | |||
351 | model = gtk_tree_view_get_model(trace_tree); | ||
352 | if (!model) | ||
353 | return; | ||
354 | |||
355 | store = TRACE_VIEW_STORE(model); | ||
356 | |||
357 | /* Ask user which way to sync */ | ||
358 | result = trace_sync_select_menu("Sync Task Filters", | ||
359 | selections, &keep); | ||
360 | |||
361 | switch (result) { | ||
362 | case 0: | ||
363 | /* Sync List Filter with Graph Filter */ | ||
364 | filter_task_hash_free(info->list_task_filter); | ||
365 | filter_task_hash_free(info->list_hide_tasks); | ||
366 | |||
367 | info->list_task_filter = NULL; | ||
368 | info->list_hide_tasks = NULL; | ||
369 | |||
370 | task_filter = info->ginfo->task_filter; | ||
371 | hide_tasks = info->ginfo->hide_tasks; | ||
372 | |||
373 | if (!keep) { | ||
374 | info->list_task_filter = filter_task_hash_copy(task_filter); | ||
375 | info->list_hide_tasks = filter_task_hash_copy(hide_tasks); | ||
376 | } | ||
377 | |||
378 | if (info->list_filter_enabled) | ||
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 | |||
389 | break; | ||
390 | case 1: | ||
391 | /* Sync Graph Filter with List Filter */ | ||
392 | trace_graph_update_filters(info->ginfo, | ||
393 | info->list_task_filter, | ||
394 | info->list_hide_tasks); | ||
395 | |||
396 | if (keep) { | ||
397 | filter_task_hash_free(info->list_task_filter); | ||
398 | filter_task_hash_free(info->list_hide_tasks); | ||
399 | |||
400 | info->list_task_filter = NULL; | ||
401 | info->list_hide_tasks = NULL; | ||
402 | } | ||
403 | break; | ||
404 | default: | ||
405 | keep = 0; | ||
406 | } | ||
407 | |||
408 | if (keep) { | ||
409 | info->sync_task_filters = 1; | ||
410 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->task_sync_menu), | ||
411 | "Unsync Graph and List Task Filters"); | ||
412 | } | ||
413 | } | ||
414 | |||
415 | /* Callback for the clicked signal of the Events filter button */ | ||
416 | static void | ||
247 | list_events_clicked (gpointer data) | 417 | list_events_clicked (gpointer data) |
248 | { | 418 | { |
249 | struct shark_info *info = data; | 419 | struct shark_info *info = data; |
@@ -510,26 +680,70 @@ static void | |||
510 | filter_list_enable_clicked (gpointer data) | 680 | filter_list_enable_clicked (gpointer data) |
511 | { | 681 | { |
512 | struct shark_info *info = data; | 682 | struct shark_info *info = data; |
683 | struct filter_task *task_filter; | ||
684 | struct filter_task *hide_tasks; | ||
513 | 685 | ||
514 | info->list_filter_enabled ^= 1; | 686 | info->list_filter_enabled ^= 1; |
515 | 687 | ||
688 | if (info->sync_task_filters) { | ||
689 | task_filter = info->ginfo->task_filter; | ||
690 | hide_tasks = info->ginfo->hide_tasks; | ||
691 | } else { | ||
692 | task_filter = info->list_task_filter; | ||
693 | hide_tasks = info->list_hide_tasks; | ||
694 | } | ||
695 | |||
516 | if (info->list_filter_enabled) | 696 | if (info->list_filter_enabled) |
517 | trace_view_update_filters(info->treeview, | 697 | trace_view_update_filters(info->treeview, |
518 | info->ginfo->task_filter, | 698 | task_filter, hide_tasks); |
519 | info->ginfo->hide_tasks); | ||
520 | else | 699 | else |
521 | trace_view_update_filters(info->treeview, NULL, NULL); | 700 | trace_view_update_filters(info->treeview, NULL, NULL); |
522 | } | 701 | } |
523 | 702 | ||
524 | static void | 703 | static void |
704 | filter_update_list_filter(struct shark_info *info, | ||
705 | struct filter_task *filter, | ||
706 | struct filter_task *other_filter) | ||
707 | { | ||
708 | struct filter_task_item *task; | ||
709 | int pid = info->selected_task; | ||
710 | |||
711 | task = filter_task_find_pid(filter, pid); | ||
712 | if (task) { | ||
713 | filter_task_remove_pid(filter, pid); | ||
714 | if (!filter_task_count(filter) && | ||
715 | !filter_task_count(other_filter)) { | ||
716 | info->list_filter_enabled = 0; | ||
717 | info->list_filter_available = 0; | ||
718 | } | ||
719 | } else { | ||
720 | filter_task_add_pid(filter, pid); | ||
721 | info->list_filter_available = 1; | ||
722 | } | ||
723 | } | ||
724 | |||
725 | static void | ||
525 | filter_add_task_clicked (gpointer data) | 726 | filter_add_task_clicked (gpointer data) |
526 | { | 727 | { |
527 | struct shark_info *info = data; | 728 | struct shark_info *info = data; |
729 | int pid = info->selected_task; | ||
528 | 730 | ||
529 | trace_graph_filter_add_remove_task(info->ginfo, info->selected_task); | 731 | if (info->sync_task_filters) { |
732 | trace_graph_filter_add_remove_task(info->ginfo, pid); | ||
733 | return; | ||
734 | } | ||
530 | 735 | ||
531 | if (!filter_task_count(info->ginfo->task_filter)) | 736 | filter_update_list_filter(info, info->list_task_filter, info->list_hide_tasks); |
532 | info->list_filter_enabled = 0; | 737 | trace_view_update_filters(info->treeview, |
738 | info->list_task_filter, info->list_hide_tasks); | ||
739 | } | ||
740 | |||
741 | static void | ||
742 | filter_graph_add_task_clicked (gpointer data) | ||
743 | { | ||
744 | struct shark_info *info = data; | ||
745 | |||
746 | trace_graph_filter_add_remove_task(info->ginfo, info->selected_task); | ||
533 | } | 747 | } |
534 | 748 | ||
535 | static void | 749 | static void |
@@ -537,11 +751,22 @@ filter_hide_task_clicked (gpointer data) | |||
537 | { | 751 | { |
538 | struct shark_info *info = data; | 752 | struct shark_info *info = data; |
539 | 753 | ||
540 | trace_graph_filter_hide_show_task(info->ginfo, info->selected_task); | 754 | if (info->sync_task_filters) { |
755 | trace_graph_filter_hide_show_task(info->ginfo, info->selected_task); | ||
756 | return; | ||
757 | } | ||
541 | 758 | ||
542 | if (!filter_task_count(info->ginfo->task_filter) && | 759 | filter_update_list_filter(info, info->list_hide_tasks, info->list_task_filter); |
543 | !filter_task_count(info->ginfo->hide_tasks)) | 760 | trace_view_update_filters(info->treeview, |
544 | info->list_filter_enabled = 0; | 761 | info->list_task_filter, info->list_hide_tasks); |
762 | } | ||
763 | |||
764 | static void | ||
765 | filter_graph_hide_task_clicked (gpointer data) | ||
766 | { | ||
767 | struct shark_info *info = data; | ||
768 | |||
769 | trace_graph_filter_hide_show_task(info->ginfo, info->selected_task); | ||
545 | } | 770 | } |
546 | 771 | ||
547 | static void | 772 | static void |
@@ -549,11 +774,27 @@ filter_clear_tasks_clicked (gpointer data) | |||
549 | { | 774 | { |
550 | struct shark_info *info = data; | 775 | struct shark_info *info = data; |
551 | 776 | ||
552 | trace_graph_clear_tasks(info->ginfo); | 777 | if (info->sync_task_filters) { |
778 | trace_graph_clear_tasks(info->ginfo); | ||
779 | return; | ||
780 | } | ||
553 | 781 | ||
782 | filter_task_clear(info->list_task_filter); | ||
783 | filter_task_clear(info->list_hide_tasks); | ||
784 | trace_view_update_filters(info->treeview, NULL, NULL); | ||
785 | |||
786 | info->list_filter_available = 0; | ||
554 | info->list_filter_enabled = 0; | 787 | info->list_filter_enabled = 0; |
555 | } | 788 | } |
556 | 789 | ||
790 | static void | ||
791 | filter_graph_clear_tasks_clicked (gpointer data) | ||
792 | { | ||
793 | struct shark_info *info = data; | ||
794 | |||
795 | trace_graph_clear_tasks(info->ginfo); | ||
796 | } | ||
797 | |||
557 | static void graph_check_toggle(gpointer data, GtkWidget *widget) | 798 | static void graph_check_toggle(gpointer data, GtkWidget *widget) |
558 | { | 799 | { |
559 | struct shark_info *info = data; | 800 | struct shark_info *info = data; |
@@ -561,6 +802,17 @@ static void graph_check_toggle(gpointer data, GtkWidget *widget) | |||
561 | info->graph_follows = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); | 802 | info->graph_follows = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); |
562 | } | 803 | } |
563 | 804 | ||
805 | static void set_menu_label(GtkWidget *menu, const char *comm, int pid, | ||
806 | const char *fmt) | ||
807 | { | ||
808 | int len = strlen(comm) + strlen(fmt) + 50; | ||
809 | char text[len]; | ||
810 | |||
811 | snprintf(text, len, fmt, comm, pid); | ||
812 | |||
813 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu), text); | ||
814 | } | ||
815 | |||
564 | static gboolean | 816 | static gboolean |
565 | do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | 817 | do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) |
566 | { | 818 | { |
@@ -572,11 +824,13 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
572 | static GtkWidget *menu_filter_add_task; | 824 | static GtkWidget *menu_filter_add_task; |
573 | static GtkWidget *menu_filter_hide_task; | 825 | static GtkWidget *menu_filter_hide_task; |
574 | static GtkWidget *menu_filter_clear_tasks; | 826 | static GtkWidget *menu_filter_clear_tasks; |
827 | static GtkWidget *menu_filter_graph_add_task; | ||
828 | static GtkWidget *menu_filter_graph_hide_task; | ||
829 | static GtkWidget *menu_filter_graph_clear_tasks; | ||
575 | struct record *record; | 830 | struct record *record; |
576 | TraceViewRecord *vrec; | 831 | TraceViewRecord *vrec; |
577 | GtkTreeModel *model; | 832 | GtkTreeModel *model; |
578 | const char *comm; | 833 | const char *comm; |
579 | gchar *text; | ||
580 | gint pid; | 834 | gint pid; |
581 | gint len; | 835 | gint len; |
582 | guint64 offset; | 836 | guint64 offset; |
@@ -585,7 +839,7 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
585 | 839 | ||
586 | if (!menu) { | 840 | if (!menu) { |
587 | menu = gtk_menu_new(); | 841 | menu = gtk_menu_new(); |
588 | menu_filter_graph_enable = gtk_menu_item_new_with_label("Enable Graph Filter"); | 842 | menu_filter_graph_enable = gtk_menu_item_new_with_label("Enable Graph Task Filter"); |
589 | gtk_widget_show(menu_filter_graph_enable); | 843 | gtk_widget_show(menu_filter_graph_enable); |
590 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_graph_enable); | 844 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_graph_enable); |
591 | 845 | ||
@@ -593,7 +847,7 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
593 | G_CALLBACK (filter_graph_enable_clicked), | 847 | G_CALLBACK (filter_graph_enable_clicked), |
594 | data); | 848 | data); |
595 | 849 | ||
596 | menu_filter_list_enable = gtk_menu_item_new_with_label("Enable List Filter"); | 850 | menu_filter_list_enable = gtk_menu_item_new_with_label("Enable List Task Filter"); |
597 | gtk_widget_show(menu_filter_list_enable); | 851 | gtk_widget_show(menu_filter_list_enable); |
598 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_list_enable); | 852 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_list_enable); |
599 | 853 | ||
@@ -609,6 +863,14 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
609 | G_CALLBACK (filter_add_task_clicked), | 863 | G_CALLBACK (filter_add_task_clicked), |
610 | data); | 864 | data); |
611 | 865 | ||
866 | menu_filter_graph_add_task = gtk_menu_item_new_with_label("Add Task to Graph"); | ||
867 | gtk_widget_show(menu_filter_graph_add_task); | ||
868 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_graph_add_task); | ||
869 | |||
870 | g_signal_connect_swapped (G_OBJECT (menu_filter_graph_add_task), "activate", | ||
871 | G_CALLBACK (filter_graph_add_task_clicked), | ||
872 | data); | ||
873 | |||
612 | menu_filter_hide_task = gtk_menu_item_new_with_label("Hide Task"); | 874 | menu_filter_hide_task = gtk_menu_item_new_with_label("Hide Task"); |
613 | gtk_widget_show(menu_filter_hide_task); | 875 | gtk_widget_show(menu_filter_hide_task); |
614 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_hide_task); | 876 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_hide_task); |
@@ -617,6 +879,14 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
617 | G_CALLBACK (filter_hide_task_clicked), | 879 | G_CALLBACK (filter_hide_task_clicked), |
618 | data); | 880 | data); |
619 | 881 | ||
882 | menu_filter_graph_hide_task = gtk_menu_item_new_with_label("Hide Task from Graph"); | ||
883 | gtk_widget_show(menu_filter_graph_hide_task); | ||
884 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_graph_hide_task); | ||
885 | |||
886 | g_signal_connect_swapped (G_OBJECT (menu_filter_graph_hide_task), "activate", | ||
887 | G_CALLBACK (filter_graph_hide_task_clicked), | ||
888 | data); | ||
889 | |||
620 | menu_filter_clear_tasks = gtk_menu_item_new_with_label("Clear Task Filter"); | 890 | menu_filter_clear_tasks = gtk_menu_item_new_with_label("Clear Task Filter"); |
621 | gtk_widget_show(menu_filter_clear_tasks); | 891 | gtk_widget_show(menu_filter_clear_tasks); |
622 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_clear_tasks); | 892 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_clear_tasks); |
@@ -625,6 +895,15 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
625 | G_CALLBACK (filter_clear_tasks_clicked), | 895 | G_CALLBACK (filter_clear_tasks_clicked), |
626 | data); | 896 | data); |
627 | 897 | ||
898 | menu_filter_graph_clear_tasks = | ||
899 | gtk_menu_item_new_with_label("Clear Graph Task Filter"); | ||
900 | gtk_widget_show(menu_filter_graph_clear_tasks); | ||
901 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_graph_clear_tasks); | ||
902 | |||
903 | g_signal_connect_swapped (G_OBJECT (menu_filter_graph_clear_tasks), "activate", | ||
904 | G_CALLBACK (filter_graph_clear_tasks_clicked), | ||
905 | data); | ||
906 | |||
628 | } | 907 | } |
629 | 908 | ||
630 | row = trace_view_get_selected_row(GTK_WIDGET(info->treeview)); | 909 | row = trace_view_get_selected_row(GTK_WIDGET(info->treeview)); |
@@ -642,29 +921,59 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
642 | 921 | ||
643 | len = strlen(comm) + 50; | 922 | len = strlen(comm) + 50; |
644 | 923 | ||
645 | text = g_malloc(len); | 924 | if (info->sync_task_filters) { |
646 | g_assert(text); | 925 | if (trace_graph_filter_task_find_pid(ginfo, pid)) |
647 | 926 | set_menu_label(menu_filter_add_task, comm, pid, | |
648 | if (trace_graph_filter_task_find_pid(ginfo, pid)) | 927 | "Remove %s-%d from filters"); |
649 | snprintf(text, len, "Remove %s-%d from filter", comm, pid); | 928 | else |
650 | else | 929 | set_menu_label(menu_filter_add_task, comm, pid, |
651 | snprintf(text, len, "Add %s-%d to filter", comm, pid); | 930 | "Add %s-%d to filters"); |
931 | |||
932 | if (trace_graph_hide_task_find_pid(ginfo, pid)) | ||
933 | set_menu_label(menu_filter_hide_task, comm, pid, | ||
934 | "Show %s-%d"); | ||
935 | else | ||
936 | set_menu_label(menu_filter_hide_task, comm, pid, | ||
937 | "Hide %s-%d"); | ||
938 | |||
939 | gtk_widget_hide(menu_filter_graph_add_task); | ||
940 | gtk_widget_hide(menu_filter_graph_hide_task); | ||
941 | |||
942 | } else { | ||
943 | if (filter_task_find_pid(info->list_task_filter, pid)) | ||
944 | set_menu_label(menu_filter_add_task, comm, pid, | ||
945 | "Remove %s-%d from List filter"); | ||
946 | else | ||
947 | set_menu_label(menu_filter_add_task, comm, pid, | ||
948 | "Add %s-%d to List filter"); | ||
949 | |||
950 | if (filter_task_find_pid(info->list_hide_tasks, pid)) | ||
951 | set_menu_label(menu_filter_hide_task, comm, pid, | ||
952 | "Show %s-%d in List"); | ||
953 | else | ||
954 | set_menu_label(menu_filter_hide_task, comm, pid, | ||
955 | "Hide %s-%d from List"); | ||
956 | |||
957 | if (trace_graph_filter_task_find_pid(ginfo, pid)) | ||
958 | set_menu_label(menu_filter_graph_add_task, comm, pid, | ||
959 | "Remove %s-%d from Graph filter"); | ||
960 | else | ||
961 | set_menu_label(menu_filter_graph_add_task, comm, pid, | ||
962 | "Add %s-%d to Graph filter"); | ||
963 | |||
964 | if (trace_graph_hide_task_find_pid(ginfo, pid)) | ||
965 | set_menu_label(menu_filter_graph_hide_task, comm, pid, | ||
966 | "Show %s-%d in Graph"); | ||
967 | else | ||
968 | set_menu_label(menu_filter_graph_hide_task, comm, pid, | ||
969 | "Hide %s-%d from Graph"); | ||
970 | |||
971 | gtk_widget_show(menu_filter_graph_add_task); | ||
972 | gtk_widget_show(menu_filter_graph_hide_task); | ||
973 | } | ||
652 | 974 | ||
653 | ginfo->filter_task_selected = pid; | 975 | ginfo->filter_task_selected = pid; |
654 | 976 | ||
655 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_add_task), | ||
656 | text); | ||
657 | |||
658 | if (trace_graph_hide_task_find_pid(ginfo, pid)) | ||
659 | snprintf(text, len, "Show %s-%d", comm, pid); | ||
660 | else | ||
661 | snprintf(text, len, "Hide %s-%d", comm, pid); | ||
662 | |||
663 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_hide_task), | ||
664 | text); | ||
665 | |||
666 | g_free(text); | ||
667 | |||
668 | info->selected_task = pid; | 977 | info->selected_task = pid; |
669 | 978 | ||
670 | gtk_widget_show(menu_filter_add_task); | 979 | gtk_widget_show(menu_filter_add_task); |
@@ -674,35 +983,62 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
674 | } else { | 983 | } else { |
675 | gtk_widget_hide(menu_filter_add_task); | 984 | gtk_widget_hide(menu_filter_add_task); |
676 | gtk_widget_hide(menu_filter_hide_task); | 985 | gtk_widget_hide(menu_filter_hide_task); |
986 | gtk_widget_hide(menu_filter_graph_add_task); | ||
987 | gtk_widget_hide(menu_filter_graph_hide_task); | ||
677 | } | 988 | } |
678 | 989 | ||
679 | if (ginfo->filter_enabled) | 990 | if (ginfo->filter_enabled) |
680 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_graph_enable), | 991 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_graph_enable), |
681 | "Disable Graph Filter"); | 992 | "Disable Graph Task Filter"); |
682 | else | 993 | else |
683 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_graph_enable), | 994 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_graph_enable), |
684 | "Enable Graph Filter"); | 995 | "Enable Graph Task Filter"); |
685 | 996 | ||
686 | if (info->list_filter_enabled) | 997 | if (info->list_filter_enabled) |
687 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_list_enable), | 998 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_list_enable), |
688 | "Disable List Filter"); | 999 | "Disable List Task Filter"); |
689 | else | 1000 | else |
690 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_list_enable), | 1001 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_list_enable), |
691 | "Enable List Filter"); | 1002 | "Enable List Task Filter"); |
692 | 1003 | ||
693 | if (ginfo->filter_available) { | 1004 | if (ginfo->filter_available) |
694 | gtk_widget_set_sensitive(menu_filter_graph_enable, TRUE); | 1005 | gtk_widget_set_sensitive(menu_filter_graph_enable, TRUE); |
695 | gtk_widget_set_sensitive(menu_filter_list_enable, TRUE); | 1006 | else |
696 | } else { | ||
697 | gtk_widget_set_sensitive(menu_filter_graph_enable, FALSE); | 1007 | gtk_widget_set_sensitive(menu_filter_graph_enable, FALSE); |
698 | gtk_widget_set_sensitive(menu_filter_list_enable, FALSE); | ||
699 | } | ||
700 | 1008 | ||
701 | if (filter_task_count(ginfo->task_filter) || | 1009 | if ((info->sync_task_filters && ginfo->filter_available) || |
702 | filter_task_count(ginfo->hide_tasks)) | 1010 | (!info->sync_task_filters && info->list_filter_available)) |
703 | gtk_widget_set_sensitive(menu_filter_clear_tasks, TRUE); | 1011 | gtk_widget_set_sensitive(menu_filter_list_enable, TRUE); |
704 | else | 1012 | else |
705 | gtk_widget_set_sensitive(menu_filter_clear_tasks, FALSE); | 1013 | gtk_widget_set_sensitive(menu_filter_list_enable, FALSE); |
1014 | |||
1015 | if (info->sync_task_filters) { | ||
1016 | if (filter_task_count(ginfo->task_filter) || | ||
1017 | filter_task_count(ginfo->hide_tasks)) | ||
1018 | gtk_widget_set_sensitive(menu_filter_clear_tasks, TRUE); | ||
1019 | else | ||
1020 | gtk_widget_set_sensitive(menu_filter_clear_tasks, FALSE); | ||
1021 | |||
1022 | set_menu_label(menu_filter_clear_tasks, comm, pid, | ||
1023 | "Clear Task Filter"); | ||
1024 | gtk_widget_hide(menu_filter_graph_clear_tasks); | ||
1025 | } else { | ||
1026 | if (filter_task_count(ginfo->task_filter) || | ||
1027 | filter_task_count(ginfo->hide_tasks)) | ||
1028 | gtk_widget_set_sensitive(menu_filter_graph_clear_tasks, TRUE); | ||
1029 | else | ||
1030 | gtk_widget_set_sensitive(menu_filter_graph_clear_tasks, FALSE); | ||
1031 | |||
1032 | if (filter_task_count(info->list_task_filter) || | ||
1033 | filter_task_count(info->list_hide_tasks)) | ||
1034 | gtk_widget_set_sensitive(menu_filter_clear_tasks, TRUE); | ||
1035 | else | ||
1036 | gtk_widget_set_sensitive(menu_filter_clear_tasks, FALSE); | ||
1037 | |||
1038 | set_menu_label(menu_filter_clear_tasks, comm, pid, | ||
1039 | "Clear List Task Filter"); | ||
1040 | gtk_widget_show(menu_filter_graph_clear_tasks); | ||
1041 | } | ||
706 | 1042 | ||
707 | gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, | 1043 | gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, |
708 | gtk_get_current_event_time()); | 1044 | gtk_get_current_event_time()); |
@@ -785,6 +1121,7 @@ void kernel_shark(int argc, char **argv) | |||
785 | handle = NULL; | 1121 | handle = NULL; |
786 | 1122 | ||
787 | info->handle = handle; | 1123 | info->handle = handle; |
1124 | info->sync_task_filters = TRUE; | ||
788 | 1125 | ||
789 | /* --- Main window --- */ | 1126 | /* --- Main window --- */ |
790 | 1127 | ||
@@ -891,6 +1228,25 @@ void kernel_shark(int argc, char **argv) | |||
891 | menu = gtk_menu_new(); /* Don't need to show menus */ | 1228 | menu = gtk_menu_new(); /* Don't need to show menus */ |
892 | 1229 | ||
893 | 1230 | ||
1231 | |||
1232 | /* --- Filter - Sync task Option --- */ | ||
1233 | |||
1234 | sub_item = gtk_menu_item_new_with_label("Unsync Graph and List Task Filters"); | ||
1235 | |||
1236 | info->task_sync_menu = sub_item; | ||
1237 | |||
1238 | /* Add them to the menu */ | ||
1239 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
1240 | |||
1241 | /* We can attach the Quit menu item to our exit function */ | ||
1242 | g_signal_connect (G_OBJECT (sub_item), "activate", | ||
1243 | G_CALLBACK (sync_task_filter_clicked), | ||
1244 | (gpointer) info); | ||
1245 | |||
1246 | /* We do need to show menu items */ | ||
1247 | gtk_widget_show(sub_item); | ||
1248 | |||
1249 | |||
894 | /* --- Filter - List Events Option --- */ | 1250 | /* --- Filter - List Events Option --- */ |
895 | 1251 | ||
896 | sub_item = gtk_menu_item_new_with_label("list events"); | 1252 | sub_item = gtk_menu_item_new_with_label("list events"); |
diff --git a/kernel-shark.h b/kernel-shark.h index edb3787..f931406 100644 --- a/kernel-shark.h +++ b/kernel-shark.h | |||
@@ -30,10 +30,15 @@ struct shark_info { | |||
30 | struct tracecmd_input *handle; | 30 | struct tracecmd_input *handle; |
31 | GtkWidget *treeview; | 31 | GtkWidget *treeview; |
32 | GtkWidget *spin; | 32 | GtkWidget *spin; |
33 | GtkWidget *task_sync_menu; | ||
33 | struct graph_callbacks graph_cbs; | 34 | struct graph_callbacks graph_cbs; |
34 | gint selected_task; | 35 | gint selected_task; |
35 | gboolean list_filter_enabled; | 36 | gboolean list_filter_enabled; |
37 | gboolean list_filter_available; | ||
36 | gboolean graph_follows; | 38 | gboolean graph_follows; |
39 | gboolean sync_task_filters; | ||
40 | struct filter_task *list_task_filter; | ||
41 | struct filter_task *list_hide_tasks; | ||
37 | }; | 42 | }; |
38 | 43 | ||
39 | #define offset_of(type, field) (long)(&((type *)0)->field) | 44 | #define offset_of(type, field) (long)(&((type *)0)->field) |
diff --git a/trace-graph.c b/trace-graph.c index 9e5cd19..2bbe73f 100644 --- a/trace-graph.c +++ b/trace-graph.c | |||
@@ -548,6 +548,20 @@ void trace_graph_clear_tasks(struct graph_info *ginfo) | |||
548 | redraw_graph(ginfo); | 548 | redraw_graph(ginfo); |
549 | } | 549 | } |
550 | 550 | ||
551 | void trace_graph_update_filters(struct graph_info *ginfo, | ||
552 | struct filter_task *task_filter, | ||
553 | struct filter_task *hide_tasks) | ||
554 | { | ||
555 | filter_task_hash_free(ginfo->task_filter); | ||
556 | filter_task_hash_free(ginfo->hide_tasks); | ||
557 | |||
558 | ginfo->task_filter = filter_task_hash_copy(task_filter); | ||
559 | ginfo->hide_tasks = filter_task_hash_copy(hide_tasks); | ||
560 | |||
561 | if (ginfo->filter_enabled) | ||
562 | redraw_graph(ginfo); | ||
563 | } | ||
564 | |||
551 | static void | 565 | static void |
552 | filter_clear_tasks_clicked (gpointer data) | 566 | filter_clear_tasks_clicked (gpointer data) |
553 | { | 567 | { |
diff --git a/trace-graph.h b/trace-graph.h index 916ad50..91194c1 100644 --- a/trace-graph.h +++ b/trace-graph.h | |||
@@ -311,6 +311,9 @@ int trace_graph_load_filters(struct graph_info *ginfo, | |||
311 | struct tracecmd_xml_handle *handle); | 311 | struct tracecmd_xml_handle *handle); |
312 | int trace_graph_save_filters(struct graph_info *ginfo, | 312 | int trace_graph_save_filters(struct graph_info *ginfo, |
313 | struct tracecmd_xml_handle *handle); | 313 | struct tracecmd_xml_handle *handle); |
314 | void trace_graph_update_filters(struct graph_info *ginfo, | ||
315 | struct filter_task *task_filter, | ||
316 | struct filter_task *hide_tasks); | ||
314 | 317 | ||
315 | /* plots */ | 318 | /* plots */ |
316 | void trace_graph_plot_free(struct graph_info *ginfo); | 319 | void trace_graph_plot_free(struct graph_info *ginfo); |
diff --git a/trace-view-store.c b/trace-view-store.c index ba40aad..6f70ca5 100644 --- a/trace-view-store.c +++ b/trace-view-store.c | |||
@@ -1330,7 +1330,6 @@ void trace_view_store_assign_filters(TraceViewStore *store, | |||
1330 | 1330 | ||
1331 | if (store->task_filter != task_filter) | 1331 | if (store->task_filter != task_filter) |
1332 | store->task_filter = filter_task_hash_copy(task_filter); | 1332 | store->task_filter = filter_task_hash_copy(task_filter); |
1333 | |||
1334 | } | 1333 | } |
1335 | 1334 | ||
1336 | 1335 | ||