diff options
author | Steven Rostedt <srostedt@redhat.com> | 2010-01-29 23:27:34 -0500 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2010-02-01 22:29:29 -0500 |
commit | 65b7fed7c15c602afe6d1e5d17b9ca1665aec9a5 (patch) | |
tree | ec89fdd9977bc1f84396dfc269d1b7a260624aa6 | |
parent | 088b2483d397179b5d5e0b3bbd1c8e15b409f14b (diff) |
trace-cmd: Add filtering of events
Add the option "-f filter" to come after an event, to enable a filter.
trace-cmd record -e sched_switch -f next_pid==2314
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r-- | trace-cmd.c | 109 |
1 files changed, 100 insertions, 9 deletions
diff --git a/trace-cmd.c b/trace-cmd.c index a82d8ce..5e394a6 100644 --- a/trace-cmd.c +++ b/trace-cmd.c | |||
@@ -60,6 +60,7 @@ static int *pids; | |||
60 | struct event_list { | 60 | struct event_list { |
61 | struct event_list *next; | 61 | struct event_list *next; |
62 | const char *event; | 62 | const char *event; |
63 | char *filter; | ||
63 | int neg; | 64 | int neg; |
64 | }; | 65 | }; |
65 | 66 | ||
@@ -389,10 +390,35 @@ static void old_enable_events(const char *name) | |||
389 | return; | 390 | return; |
390 | } | 391 | } |
391 | 392 | ||
392 | static int enable_glob(const char *name) | 393 | static void write_filter(const char *file, const char *filter) |
394 | { | ||
395 | char buf[BUFSIZ]; | ||
396 | int fd; | ||
397 | int ret; | ||
398 | |||
399 | fd = open(file, O_WRONLY); | ||
400 | if (fd < 0) | ||
401 | die("opening to '%s'", file); | ||
402 | ret = write(fd, filter, strlen(filter)); | ||
403 | close(fd); | ||
404 | if (ret < 0) { | ||
405 | /* filter failed */ | ||
406 | fd = open(file, O_RDONLY); | ||
407 | if (fd < 0) | ||
408 | die("writing to '%s'", file); | ||
409 | /* the filter has the error */ | ||
410 | while ((ret = read(fd, buf, BUFSIZ)) > 0) | ||
411 | fprintf(stderr, "%.*s", ret, buf); | ||
412 | die("Failed filter of %s\n", file); | ||
413 | close(fd); | ||
414 | } | ||
415 | } | ||
416 | |||
417 | static int enable_glob(const char *name, const char *filter) | ||
393 | { | 418 | { |
394 | glob_t globbuf; | 419 | glob_t globbuf; |
395 | FILE *fp; | 420 | FILE *fp; |
421 | char *filter_file; | ||
396 | char *path; | 422 | char *path; |
397 | char *str; | 423 | char *str; |
398 | int len; | 424 | int len; |
@@ -416,6 +442,19 @@ static int enable_glob(const char *name) | |||
416 | for (i = 0; i < globbuf.gl_pathc; i++) { | 442 | for (i = 0; i < globbuf.gl_pathc; i++) { |
417 | path = globbuf.gl_pathv[i]; | 443 | path = globbuf.gl_pathv[i]; |
418 | 444 | ||
445 | filter_file = strdup(path); | ||
446 | if (!filter_file) | ||
447 | die("Allocating memory"); | ||
448 | |||
449 | /* s/enable/filter/ */ | ||
450 | memcpy(filter_file + strlen(filter_file) - 6, | ||
451 | "filter", 6); | ||
452 | if (filter) | ||
453 | write_filter(filter_file, filter); | ||
454 | else | ||
455 | write_filter(filter_file, "0"); | ||
456 | free(filter_file); | ||
457 | |||
419 | fp = fopen(path, "w"); | 458 | fp = fopen(path, "w"); |
420 | if (!fp) | 459 | if (!fp) |
421 | die("writing to '%s'", path); | 460 | die("writing to '%s'", path); |
@@ -430,7 +469,30 @@ static int enable_glob(const char *name) | |||
430 | return count; | 469 | return count; |
431 | } | 470 | } |
432 | 471 | ||
433 | static void enable_event(const char *name) | 472 | static void filter_all_systems(const char *filter) |
473 | { | ||
474 | glob_t globbuf; | ||
475 | char *path; | ||
476 | int ret; | ||
477 | int i; | ||
478 | |||
479 | path = get_tracing_file("events/*/filter"); | ||
480 | |||
481 | globbuf.gl_offs = 0; | ||
482 | ret = glob(path, 0, NULL, &globbuf); | ||
483 | put_tracing_file(path); | ||
484 | if (ret < 0) | ||
485 | die("No filters found"); | ||
486 | |||
487 | for (i = 0; i < globbuf.gl_pathc; i++) { | ||
488 | path = globbuf.gl_pathv[i]; | ||
489 | |||
490 | write_filter(path, filter); | ||
491 | } | ||
492 | globfree(&globbuf); | ||
493 | } | ||
494 | |||
495 | static void enable_event(const char *name, const char *filter) | ||
434 | { | 496 | { |
435 | struct stat st; | 497 | struct stat st; |
436 | FILE *fp; | 498 | FILE *fp; |
@@ -456,6 +518,11 @@ static void enable_event(const char *name) | |||
456 | /* We allow the user to use "all" to enable all events */ | 518 | /* We allow the user to use "all" to enable all events */ |
457 | 519 | ||
458 | if (strcmp(name, "all") == 0) { | 520 | if (strcmp(name, "all") == 0) { |
521 | if (filter) | ||
522 | filter_all_systems(filter); | ||
523 | else | ||
524 | filter_all_systems("0"); | ||
525 | |||
459 | fp = fopen(path, "w"); | 526 | fp = fopen(path, "w"); |
460 | if (!fp) | 527 | if (!fp) |
461 | die("writing to '%s'", path); | 528 | die("writing to '%s'", path); |
@@ -477,7 +544,7 @@ static void enable_event(const char *name) | |||
477 | str[len] = 0; | 544 | str[len] = 0; |
478 | ptr++; | 545 | ptr++; |
479 | if (!strlen(ptr) || strcmp(ptr, "*") == 0) { | 546 | if (!strlen(ptr) || strcmp(ptr, "*") == 0) { |
480 | ret = enable_glob(str); | 547 | ret = enable_glob(str, filter); |
481 | free(str); | 548 | free(str); |
482 | put_tracing_file(path); | 549 | put_tracing_file(path); |
483 | if (!ret) | 550 | if (!ret) |
@@ -487,7 +554,7 @@ static void enable_event(const char *name) | |||
487 | 554 | ||
488 | str[len] = '/'; | 555 | str[len] = '/'; |
489 | 556 | ||
490 | ret = enable_glob(str); | 557 | ret = enable_glob(str, filter); |
491 | free(str); | 558 | free(str); |
492 | if (!ret) | 559 | if (!ret) |
493 | die("No events enabled with %s", name); | 560 | die("No events enabled with %s", name); |
@@ -495,12 +562,12 @@ static void enable_event(const char *name) | |||
495 | } | 562 | } |
496 | 563 | ||
497 | /* No ':' so enable all matching systems and events */ | 564 | /* No ':' so enable all matching systems and events */ |
498 | ret = enable_glob(name); | 565 | ret = enable_glob(name, filter); |
499 | 566 | ||
500 | len = strlen(name) + strlen("*/") + 1; | 567 | len = strlen(name) + strlen("*/") + 1; |
501 | str = malloc_or_die(len); | 568 | str = malloc_or_die(len); |
502 | snprintf(str, len, "*/%s", name); | 569 | snprintf(str, len, "*/%s", name); |
503 | ret2 = enable_glob(str); | 570 | ret2 = enable_glob(str, filter); |
504 | free(str); | 571 | free(str); |
505 | 572 | ||
506 | if (!ret && !ret2) | 573 | if (!ret && !ret2) |
@@ -636,7 +703,7 @@ static void enable_events(void) | |||
636 | 703 | ||
637 | for (event = event_selection; event; event = event->next) { | 704 | for (event = event_selection; event; event = event->next) { |
638 | if (!event->neg) | 705 | if (!event->neg) |
639 | enable_event(event->event); | 706 | enable_event(event->event, event->filter); |
640 | } | 707 | } |
641 | 708 | ||
642 | /* Now disable any events */ | 709 | /* Now disable any events */ |
@@ -822,8 +889,9 @@ void usage(char **argv) | |||
822 | printf("\n" | 889 | printf("\n" |
823 | "%s version %s\n\n" | 890 | "%s version %s\n\n" |
824 | "usage:\n" | 891 | "usage:\n" |
825 | " %s record [-v][-e event][-p plugin][-d][-o file][-s usecs][-O option ] [command ...]\n" | 892 | " %s record [-v][-e event [-f filter]][-p plugin][-d][-o file][-s usecs][-O option ] [command ...]\n" |
826 | " -e run command with event enabled\n" | 893 | " -e run command with event enabled\n" |
894 | " -f filter for previous -e event\n" | ||
827 | " -p run command with plugin enabled\n" | 895 | " -p run command with plugin enabled\n" |
828 | " -v will negate all -e after it (disable those events)\n" | 896 | " -v will negate all -e after it (disable those events)\n" |
829 | " -d disable function tracer when running\n" | 897 | " -d disable function tracer when running\n" |
@@ -883,6 +951,7 @@ int main (int argc, char **argv) | |||
883 | const char *output = NULL; | 951 | const char *output = NULL; |
884 | const char *option; | 952 | const char *option; |
885 | struct event_list *event; | 953 | struct event_list *event; |
954 | struct event_list *last_event; | ||
886 | struct trace_seq s; | 955 | struct trace_seq s; |
887 | int disable = 0; | 956 | int disable = 0; |
888 | int plug = 0; | 957 | int plug = 0; |
@@ -912,7 +981,7 @@ int main (int argc, char **argv) | |||
912 | (strcmp(argv[1], "start") == 0) || | 981 | (strcmp(argv[1], "start") == 0) || |
913 | ((extract = strcmp(argv[1], "extract") == 0))) { | 982 | ((extract = strcmp(argv[1], "extract") == 0))) { |
914 | 983 | ||
915 | while ((c = getopt(argc-1, argv+1, "+he:p:do:O:s:v")) >= 0) { | 984 | while ((c = getopt(argc-1, argv+1, "+he:f:p:do:O:s:v")) >= 0) { |
916 | switch (c) { | 985 | switch (c) { |
917 | case 'h': | 986 | case 'h': |
918 | usage(argv); | 987 | usage(argv); |
@@ -926,7 +995,29 @@ int main (int argc, char **argv) | |||
926 | event->next = event_selection; | 995 | event->next = event_selection; |
927 | event->neg = neg_event; | 996 | event->neg = neg_event; |
928 | event_selection = event; | 997 | event_selection = event; |
998 | event->filter = NULL; | ||
999 | last_event = event; | ||
929 | break; | 1000 | break; |
1001 | case 'f': | ||
1002 | if (!last_event) | ||
1003 | die("filter must come after event"); | ||
1004 | if (last_event->filter) { | ||
1005 | last_event->filter = | ||
1006 | realloc(last_event->filter, | ||
1007 | strlen(last_event->filter) + | ||
1008 | strlen("&&()") + | ||
1009 | strlen(optarg) + 1); | ||
1010 | strcat(last_event->filter, "&&("); | ||
1011 | strcat(last_event->filter, optarg); | ||
1012 | strcat(last_event->filter, ")"); | ||
1013 | } else { | ||
1014 | last_event->filter = | ||
1015 | malloc_or_die(strlen(optarg) + | ||
1016 | strlen("()") + 1); | ||
1017 | sprintf(last_event->filter, "(%s)", optarg); | ||
1018 | } | ||
1019 | break; | ||
1020 | |||
930 | case 'v': | 1021 | case 'v': |
931 | if (extract) | 1022 | if (extract) |
932 | usage(argv); | 1023 | usage(argv); |