diff options
Diffstat (limited to 'kernel-shark.c')
-rw-r--r-- | kernel-shark.c | 309 |
1 files changed, 279 insertions, 30 deletions
diff --git a/kernel-shark.c b/kernel-shark.c index 87e4c40..5823934 100644 --- a/kernel-shark.c +++ b/kernel-shark.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <string.h> | 23 | #include <string.h> |
24 | #include <stdarg.h> | 24 | #include <stdarg.h> |
25 | #include <fcntl.h> | 25 | #include <fcntl.h> |
26 | #include <dirent.h> | ||
26 | #include <sys/types.h> | 27 | #include <sys/types.h> |
27 | #include <sys/stat.h> | 28 | #include <sys/stat.h> |
28 | #include <unistd.h> | 29 | #include <unistd.h> |
@@ -35,6 +36,7 @@ | |||
35 | #include "trace-cmd.h" | 36 | #include "trace-cmd.h" |
36 | #include "trace-gui.h" | 37 | #include "trace-gui.h" |
37 | #include "kernel-shark.h" | 38 | #include "kernel-shark.h" |
39 | #include "util.h" | ||
38 | #include "version.h" | 40 | #include "version.h" |
39 | 41 | ||
40 | #define ___stringify(X) #X | 42 | #define ___stringify(X) #X |
@@ -211,6 +213,7 @@ static void free_info(struct shark_info *info) | |||
211 | 213 | ||
212 | kernel_shark_clear_capture(info); | 214 | kernel_shark_clear_capture(info); |
213 | 215 | ||
216 | free(info->current_filter); | ||
214 | free(info->ginfo); | 217 | free(info->ginfo); |
215 | free(info); | 218 | free(info); |
216 | } | 219 | } |
@@ -335,7 +338,8 @@ load_clicked (gpointer data) | |||
335 | struct shark_info *info = data; | 338 | struct shark_info *info = data; |
336 | gchar *filename; | 339 | gchar *filename; |
337 | 340 | ||
338 | filename = trace_get_file_dialog("Load File", NULL, FALSE); | 341 | filename = trace_get_file_dialog_filter("Load File", NULL, |
342 | TRACE_DIALOG_FILTER_DATA, FALSE); | ||
339 | if (!filename) | 343 | if (!filename) |
340 | return; | 344 | return; |
341 | 345 | ||
@@ -344,11 +348,52 @@ load_clicked (gpointer data) | |||
344 | g_free(filename); | 348 | g_free(filename); |
345 | } | 349 | } |
346 | 350 | ||
347 | /* Callback for the clicked signal of the Load Filters button */ | 351 | static GString *get_home_filters_new(void) |
348 | static void | 352 | { |
349 | load_filters_clicked (gpointer data) | 353 | char *path = getenv("HOME"); |
354 | GString *str; | ||
355 | |||
356 | str = g_string_new(path); | ||
357 | g_string_append(str, "/.trace-cmd/filters/"); | ||
358 | return str; | ||
359 | } | ||
360 | |||
361 | static int create_home_filters(void) | ||
362 | { | ||
363 | char *path = getenv("HOME"); | ||
364 | GString *str; | ||
365 | struct stat st; | ||
366 | int ret; | ||
367 | |||
368 | str = g_string_new(path); | ||
369 | g_string_append(str, "/.trace-cmd"); | ||
370 | ret = stat(str->str, &st); | ||
371 | if (ret < 0) { | ||
372 | ret = mkdir(str->str, 0755); | ||
373 | if (ret < 0) { | ||
374 | warning("Can not create %s", str->str); | ||
375 | goto out; | ||
376 | } | ||
377 | } | ||
378 | |||
379 | g_string_append(str, "/filters"); | ||
380 | ret = stat(str->str, &st); | ||
381 | if (ret < 0) { | ||
382 | ret = mkdir(str->str, 0755); | ||
383 | if (ret < 0) { | ||
384 | warning("Can not create %s", str->str); | ||
385 | goto out; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | ret = 0; | ||
390 | out: | ||
391 | g_string_free(str, TRUE); | ||
392 | return ret; | ||
393 | } | ||
394 | |||
395 | static void load_filter(struct shark_info *info, const char *filename) | ||
350 | { | 396 | { |
351 | struct shark_info *info = data; | ||
352 | struct graph_info *ginfo = info->ginfo; | 397 | struct graph_info *ginfo = info->ginfo; |
353 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); | 398 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); |
354 | GtkTreeModel *model; | 399 | GtkTreeModel *model; |
@@ -357,17 +402,12 @@ load_filters_clicked (gpointer data) | |||
357 | struct filter_task *task_filter; | 402 | struct filter_task *task_filter; |
358 | struct filter_task *hide_tasks; | 403 | struct filter_task *hide_tasks; |
359 | struct event_filter *event_filter; | 404 | struct event_filter *event_filter; |
360 | gchar *filename; | ||
361 | int ret; | 405 | int ret; |
362 | 406 | ||
363 | filename = trace_get_file_dialog("Load Filters", NULL, FALSE); | ||
364 | if (!filename) | ||
365 | return; | ||
366 | |||
367 | handle = tracecmd_xml_open(filename); | 407 | handle = tracecmd_xml_open(filename); |
368 | if (!handle) { | 408 | if (!handle) { |
369 | warning("Could not open %s", filename); | 409 | warning("Could not open %s", filename); |
370 | goto out; | 410 | return; |
371 | } | 411 | } |
372 | 412 | ||
373 | /* Unsync the list and graph filters */ | 413 | /* Unsync the list and graph filters */ |
@@ -421,39 +461,61 @@ load_filters_clicked (gpointer data) | |||
421 | 461 | ||
422 | model = gtk_tree_view_get_model(trace_tree); | 462 | model = gtk_tree_view_get_model(trace_tree); |
423 | if (!model) | 463 | if (!model) |
424 | goto out; | 464 | return; |
425 | 465 | ||
426 | store = TRACE_VIEW_STORE(model); | 466 | store = TRACE_VIEW_STORE(model); |
427 | event_filter = trace_view_store_get_event_filter(store); | 467 | event_filter = trace_view_store_get_event_filter(store); |
428 | 468 | ||
429 | if (pevent_filter_compare(event_filter, ginfo->event_filter)) | 469 | if (pevent_filter_compare(event_filter, ginfo->event_filter)) |
430 | sync_event_filters(info); | 470 | sync_event_filters(info); |
471 | } | ||
431 | 472 | ||
432 | out: | 473 | static void load_filter_clicked(GtkMenuItem *item, gpointer data) |
433 | g_free(filename); | 474 | { |
475 | struct shark_info *info = data; | ||
476 | const char *name; | ||
477 | GString *path; | ||
478 | |||
479 | name = gtk_menu_item_get_label(item); | ||
480 | |||
481 | path = get_home_filters_new(); | ||
482 | g_string_append_printf(path, "/%s.ksf", name); | ||
434 | 483 | ||
484 | load_filter(info, path->str); | ||
485 | g_string_free(path, TRUE); | ||
486 | |||
487 | free(info->current_filter); | ||
488 | info->current_filter = strdup(name); | ||
435 | } | 489 | } |
436 | 490 | ||
437 | /* Callback for the clicked signal of the Save Filters button */ | 491 | /* Callback for the clicked signal of the Load Filters button */ |
438 | static void | 492 | static void |
439 | save_filters_clicked (gpointer data) | 493 | import_filters_clicked (gpointer data) |
440 | { | 494 | { |
441 | struct shark_info *info = data; | 495 | struct shark_info *info = data; |
496 | gchar *filename; | ||
497 | |||
498 | filename = trace_get_file_dialog_filter("Load Filters", NULL, | ||
499 | TRACE_DIALOG_FILTER_FILTER, FALSE); | ||
500 | if (!filename) | ||
501 | return; | ||
502 | |||
503 | load_filter(info, filename); | ||
504 | } | ||
505 | |||
506 | static void save_filters(struct shark_info *info, const char *filename) | ||
507 | { | ||
442 | struct graph_info *ginfo = info->ginfo; | 508 | struct graph_info *ginfo = info->ginfo; |
443 | struct tracecmd_xml_handle *handle; | 509 | struct tracecmd_xml_handle *handle; |
444 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); | 510 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); |
445 | struct filter_task *task_filter; | 511 | struct filter_task *task_filter; |
446 | struct filter_task *hide_tasks; | 512 | struct filter_task *hide_tasks; |
447 | gchar *filename; | ||
448 | |||
449 | filename = trace_get_file_dialog("Save Filters", "Save", TRUE); | ||
450 | if (!filename) | ||
451 | return; | ||
452 | 513 | ||
453 | handle = tracecmd_xml_create(filename, VERSION_STRING); | 514 | handle = tracecmd_xml_create(filename, VERSION_STRING); |
454 | if (!handle) | 515 | if (!handle) { |
455 | warning("Could not create %s", filename); | 516 | warning("Could not create %s", filename); |
456 | g_free(filename); | 517 | return; |
518 | } | ||
457 | 519 | ||
458 | trace_view_save_filters(handle, trace_tree); | 520 | trace_view_save_filters(handle, trace_tree); |
459 | trace_graph_save_filters(ginfo, handle); | 521 | trace_graph_save_filters(ginfo, handle); |
@@ -478,6 +540,178 @@ save_filters_clicked (gpointer data) | |||
478 | tracecmd_xml_close(handle); | 540 | tracecmd_xml_close(handle); |
479 | } | 541 | } |
480 | 542 | ||
543 | /* Callback for the clicked signal of the Save Filters button */ | ||
544 | static void | ||
545 | export_filters_clicked (gpointer data) | ||
546 | { | ||
547 | struct shark_info *info = data; | ||
548 | gchar *filename; | ||
549 | |||
550 | filename = trace_get_file_dialog_filter("Save Filters", "Save", | ||
551 | TRACE_DIALOG_FILTER_FILTER, TRUE); | ||
552 | if (!filename) | ||
553 | return; | ||
554 | |||
555 | save_filters(info, filename); | ||
556 | g_free(filename); | ||
557 | } | ||
558 | |||
559 | static void update_load_filter(struct shark_info *info) | ||
560 | { | ||
561 | struct dirent *dent; | ||
562 | struct stat st; | ||
563 | DIR *dir; | ||
564 | GtkWidget *menu; | ||
565 | GtkWidget *sub_item; | ||
566 | GString *path; | ||
567 | int ret; | ||
568 | |||
569 | path = get_home_filters_new(); | ||
570 | |||
571 | menu = gtk_menu_new(); | ||
572 | |||
573 | ret = stat(path->str, &st); | ||
574 | if (ret < 0 || !S_ISDIR(st.st_mode)) | ||
575 | goto update_rest; | ||
576 | |||
577 | dir = opendir(path->str); | ||
578 | if (!dir) | ||
579 | goto update_rest; | ||
580 | |||
581 | while ((dent = readdir(dir))) { | ||
582 | const char *name = dent->d_name; | ||
583 | GString *file; | ||
584 | gchar *item; | ||
585 | |||
586 | if (strcmp(name, ".") == 0 || | ||
587 | strcmp(name, "..") == 0) | ||
588 | continue; | ||
589 | |||
590 | if (strcmp(name + strlen(name) - 4, ".ksf") != 0) | ||
591 | continue; | ||
592 | |||
593 | file = g_string_new(path->str); | ||
594 | g_string_append_printf(file, "/%s", name); | ||
595 | |||
596 | /* Save the file name but remove the .kss extention */ | ||
597 | item = g_strdup(name); | ||
598 | item[strlen(name) - 4] = 0; | ||
599 | |||
600 | sub_item = gtk_menu_item_new_with_label(item); | ||
601 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
602 | gtk_widget_show(sub_item); | ||
603 | |||
604 | g_signal_connect(G_OBJECT (sub_item), "activate", | ||
605 | G_CALLBACK (load_filter_clicked), | ||
606 | (gpointer) info); | ||
607 | |||
608 | g_free(item); | ||
609 | g_string_free(file, TRUE); | ||
610 | } | ||
611 | |||
612 | update_rest: | ||
613 | g_string_free(path, TRUE); | ||
614 | |||
615 | /* --- File - Load Filter - Filters --- */ | ||
616 | |||
617 | sub_item = gtk_menu_item_new_with_label("Import Filter"); | ||
618 | |||
619 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
620 | G_CALLBACK (import_filters_clicked), | ||
621 | (gpointer) info); | ||
622 | |||
623 | /* Add them to the menu */ | ||
624 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
625 | |||
626 | /* We do need to show menu items */ | ||
627 | gtk_widget_show(sub_item); | ||
628 | |||
629 | gtk_menu_item_set_submenu(GTK_MENU_ITEM (info->load_filter_menu), menu); | ||
630 | |||
631 | } | ||
632 | |||
633 | /* Callback for the clicked signal of the Save Filters button */ | ||
634 | static void | ||
635 | save_filter_clicked (gpointer data) | ||
636 | { | ||
637 | struct shark_info *info = data; | ||
638 | struct stat st; | ||
639 | GtkWidget *dialog; | ||
640 | GtkWidget *hbox; | ||
641 | GtkWidget *label; | ||
642 | GtkWidget *entry; | ||
643 | GString *file; | ||
644 | const char *name; | ||
645 | gint result; | ||
646 | int ret; | ||
647 | |||
648 | dialog = gtk_dialog_new_with_buttons("Save Filter", | ||
649 | NULL, | ||
650 | GTK_DIALOG_MODAL, | ||
651 | GTK_STOCK_OK, | ||
652 | GTK_RESPONSE_ACCEPT, | ||
653 | GTK_STOCK_CANCEL, | ||
654 | GTK_RESPONSE_REJECT, | ||
655 | NULL); | ||
656 | |||
657 | hbox = gtk_hbox_new(FALSE, 0); | ||
658 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, FALSE, FALSE, 0); | ||
659 | gtk_widget_show(hbox); | ||
660 | |||
661 | label = gtk_label_new("Filter Name: "); | ||
662 | gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | ||
663 | gtk_widget_show(label); | ||
664 | |||
665 | entry = gtk_entry_new(); | ||
666 | gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0); | ||
667 | gtk_widget_show(entry); | ||
668 | |||
669 | if (info->current_filter) | ||
670 | gtk_entry_set_text(GTK_ENTRY(entry), info->current_filter); | ||
671 | |||
672 | again: | ||
673 | result = gtk_dialog_run(GTK_DIALOG(dialog)); | ||
674 | switch (result) { | ||
675 | case GTK_RESPONSE_ACCEPT: | ||
676 | name = gtk_entry_get_text(GTK_ENTRY(entry)); | ||
677 | if (!name || !has_text(name)) { | ||
678 | warning("Must enter a name"); | ||
679 | goto again; | ||
680 | } | ||
681 | /* Make sure home settings exists */ | ||
682 | if (create_home_filters() < 0) | ||
683 | break; | ||
684 | file = get_home_filters_new(); | ||
685 | g_string_append_printf(file, "/%s.ksf", name); | ||
686 | ret = stat(file->str, &st); | ||
687 | if (ret >= 0) { | ||
688 | ret = trace_dialog(GTK_WINDOW(dialog), TRACE_GUI_ASK, | ||
689 | "The Filter '%s' already exists.\n" | ||
690 | "Are you sure you want to replace it", | ||
691 | name); | ||
692 | if (ret == GTK_RESPONSE_NO) { | ||
693 | g_string_free(file, TRUE); | ||
694 | goto again; | ||
695 | } | ||
696 | } | ||
697 | save_filters(info, file->str); | ||
698 | |||
699 | free(info->current_filter); | ||
700 | info->current_filter = strdup(name); | ||
701 | |||
702 | update_load_filter(info); | ||
703 | g_string_free(file, TRUE); | ||
704 | break; | ||
705 | |||
706 | case GTK_RESPONSE_REJECT: | ||
707 | break; | ||
708 | default: | ||
709 | break; | ||
710 | }; | ||
711 | |||
712 | gtk_widget_destroy(dialog); | ||
713 | } | ||
714 | |||
481 | /* Callback for the clicked signal of the Exit button */ | 715 | /* Callback for the clicked signal of the Exit button */ |
482 | static void | 716 | static void |
483 | exit_clicked (gpointer data) | 717 | exit_clicked (gpointer data) |
@@ -1630,30 +1864,45 @@ void kernel_shark(int argc, char **argv) | |||
1630 | gtk_widget_show(sub_item); | 1864 | gtk_widget_show(sub_item); |
1631 | 1865 | ||
1632 | 1866 | ||
1633 | /* --- File - Load Filter Option --- */ | 1867 | /* --- File - Load Filter --- */ |
1634 | 1868 | ||
1635 | sub_item = gtk_menu_item_new_with_label("Load filters"); | 1869 | sub_item = gtk_menu_item_new_with_label("Load filter"); |
1636 | 1870 | ||
1637 | /* Add them to the menu */ | 1871 | /* Add them to the menu */ |
1638 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | 1872 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); |
1639 | 1873 | ||
1640 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | 1874 | info->load_filter_menu = sub_item; |
1641 | G_CALLBACK (load_filters_clicked), | ||
1642 | (gpointer) info); | ||
1643 | 1875 | ||
1644 | /* We do need to show menu items */ | 1876 | /* We do need to show menu items */ |
1645 | gtk_widget_show(sub_item); | 1877 | gtk_widget_show(sub_item); |
1646 | 1878 | ||
1879 | update_load_filter(info); | ||
1880 | |||
1647 | 1881 | ||
1648 | /* --- File - Save Filter Option --- */ | 1882 | /* --- File - Save Filter Option --- */ |
1649 | 1883 | ||
1650 | sub_item = gtk_menu_item_new_with_label("Save filters"); | 1884 | sub_item = gtk_menu_item_new_with_label("Save filter"); |
1885 | |||
1886 | /* Add them to the menu */ | ||
1887 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
1888 | |||
1889 | /* We do need to show menu items */ | ||
1890 | gtk_widget_show(sub_item); | ||
1891 | |||
1892 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
1893 | G_CALLBACK (save_filter_clicked), | ||
1894 | (gpointer) info); | ||
1895 | |||
1896 | |||
1897 | /* --- File - Export Filter Option --- */ | ||
1898 | |||
1899 | sub_item = gtk_menu_item_new_with_label("Export filters"); | ||
1651 | 1900 | ||
1652 | /* Add them to the menu */ | 1901 | /* Add them to the menu */ |
1653 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | 1902 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); |
1654 | 1903 | ||
1655 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | 1904 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", |
1656 | G_CALLBACK (save_filters_clicked), | 1905 | G_CALLBACK (export_filters_clicked), |
1657 | (gpointer) info); | 1906 | (gpointer) info); |
1658 | 1907 | ||
1659 | /* We do need to show menu items */ | 1908 | /* We do need to show menu items */ |