diff options
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r-- | tools/perf/builtin-trace.c | 209 |
1 files changed, 150 insertions, 59 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 2f8df45c4dcb..86cfe3800e6b 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include "util/symbol.h" | 10 | #include "util/symbol.h" |
11 | #include "util/thread.h" | 11 | #include "util/thread.h" |
12 | #include "util/trace-event.h" | 12 | #include "util/trace-event.h" |
13 | #include "util/parse-options.h" | ||
13 | #include "util/util.h" | 14 | #include "util/util.h" |
14 | 15 | ||
15 | static char const *script_name; | 16 | static char const *script_name; |
@@ -17,6 +18,7 @@ static char const *generate_script_lang; | |||
17 | static bool debug_mode; | 18 | static bool debug_mode; |
18 | static u64 last_timestamp; | 19 | static u64 last_timestamp; |
19 | static u64 nr_unordered; | 20 | static u64 nr_unordered; |
21 | extern const struct option record_options[]; | ||
20 | 22 | ||
21 | static int default_start_script(const char *script __unused, | 23 | static int default_start_script(const char *script __unused, |
22 | int argc __unused, | 24 | int argc __unused, |
@@ -328,7 +330,7 @@ static struct script_desc *script_desc__new(const char *name) | |||
328 | { | 330 | { |
329 | struct script_desc *s = zalloc(sizeof(*s)); | 331 | struct script_desc *s = zalloc(sizeof(*s)); |
330 | 332 | ||
331 | if (s != NULL) | 333 | if (s != NULL && name) |
332 | s->name = strdup(name); | 334 | s->name = strdup(name); |
333 | 335 | ||
334 | return s; | 336 | return s; |
@@ -337,6 +339,8 @@ static struct script_desc *script_desc__new(const char *name) | |||
337 | static void script_desc__delete(struct script_desc *s) | 339 | static void script_desc__delete(struct script_desc *s) |
338 | { | 340 | { |
339 | free(s->name); | 341 | free(s->name); |
342 | free(s->half_liner); | ||
343 | free(s->args); | ||
340 | free(s); | 344 | free(s); |
341 | } | 345 | } |
342 | 346 | ||
@@ -537,8 +541,40 @@ static char *get_script_path(const char *script_root, const char *suffix) | |||
537 | return path; | 541 | return path; |
538 | } | 542 | } |
539 | 543 | ||
544 | static bool is_top_script(const char *script_path) | ||
545 | { | ||
546 | return ends_with((char *)script_path, "top") == NULL ? false : true; | ||
547 | } | ||
548 | |||
549 | static int has_required_arg(char *script_path) | ||
550 | { | ||
551 | struct script_desc *desc; | ||
552 | int n_args = 0; | ||
553 | char *p; | ||
554 | |||
555 | desc = script_desc__new(NULL); | ||
556 | |||
557 | if (read_script_info(desc, script_path)) | ||
558 | goto out; | ||
559 | |||
560 | if (!desc->args) | ||
561 | goto out; | ||
562 | |||
563 | for (p = desc->args; *p; p++) | ||
564 | if (*p == '<') | ||
565 | n_args++; | ||
566 | out: | ||
567 | script_desc__delete(desc); | ||
568 | |||
569 | return n_args; | ||
570 | } | ||
571 | |||
540 | static const char * const trace_usage[] = { | 572 | static const char * const trace_usage[] = { |
541 | "perf trace [<options>] <command>", | 573 | "perf trace [<options>]", |
574 | "perf trace [<options>] record <script> [<record-options>] <command>", | ||
575 | "perf trace [<options>] report <script> [script-args]", | ||
576 | "perf trace [<options>] <script> [<record-options>] <command>", | ||
577 | "perf trace [<options>] <top-script> [script-args]", | ||
542 | NULL | 578 | NULL |
543 | }; | 579 | }; |
544 | 580 | ||
@@ -564,50 +600,81 @@ static const struct option options[] = { | |||
564 | OPT_END() | 600 | OPT_END() |
565 | }; | 601 | }; |
566 | 602 | ||
603 | static bool have_cmd(int argc, const char **argv) | ||
604 | { | ||
605 | char **__argv = malloc(sizeof(const char *) * argc); | ||
606 | |||
607 | if (!__argv) | ||
608 | die("malloc"); | ||
609 | memcpy(__argv, argv, sizeof(const char *) * argc); | ||
610 | argc = parse_options(argc, (const char **)__argv, record_options, | ||
611 | NULL, PARSE_OPT_STOP_AT_NON_OPTION); | ||
612 | free(__argv); | ||
613 | |||
614 | return argc != 0; | ||
615 | } | ||
616 | |||
567 | int cmd_trace(int argc, const char **argv, const char *prefix __used) | 617 | int cmd_trace(int argc, const char **argv, const char *prefix __used) |
568 | { | 618 | { |
619 | char *rec_script_path = NULL; | ||
620 | char *rep_script_path = NULL; | ||
569 | struct perf_session *session; | 621 | struct perf_session *session; |
570 | const char *suffix = NULL; | 622 | char *script_path = NULL; |
571 | const char **__argv; | 623 | const char **__argv; |
572 | char *script_path; | 624 | bool system_wide; |
573 | int i, err; | 625 | int i, j, err; |
574 | 626 | ||
575 | if (argc >= 2 && strncmp(argv[1], "rec", strlen("rec")) == 0) { | 627 | setup_scripting(); |
576 | if (argc < 3) { | 628 | |
577 | fprintf(stderr, | 629 | argc = parse_options(argc, argv, options, trace_usage, |
578 | "Please specify a record script\n"); | 630 | PARSE_OPT_STOP_AT_NON_OPTION); |
579 | return -1; | 631 | |
580 | } | 632 | if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { |
581 | suffix = RECORD_SUFFIX; | 633 | rec_script_path = get_script_path(argv[1], RECORD_SUFFIX); |
634 | if (!rec_script_path) | ||
635 | return cmd_record(argc, argv, NULL); | ||
582 | } | 636 | } |
583 | 637 | ||
584 | if (argc >= 2 && strncmp(argv[1], "rep", strlen("rep")) == 0) { | 638 | if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) { |
585 | if (argc < 3) { | 639 | rep_script_path = get_script_path(argv[1], REPORT_SUFFIX); |
640 | if (!rep_script_path) { | ||
586 | fprintf(stderr, | 641 | fprintf(stderr, |
587 | "Please specify a report script\n"); | 642 | "Please specify a valid report script" |
643 | "(see 'perf trace -l' for listing)\n"); | ||
588 | return -1; | 644 | return -1; |
589 | } | 645 | } |
590 | suffix = REPORT_SUFFIX; | ||
591 | } | 646 | } |
592 | 647 | ||
593 | /* make sure PERF_EXEC_PATH is set for scripts */ | 648 | /* make sure PERF_EXEC_PATH is set for scripts */ |
594 | perf_set_argv_exec_path(perf_exec_path()); | 649 | perf_set_argv_exec_path(perf_exec_path()); |
595 | 650 | ||
596 | if (!suffix && argc >= 2 && strncmp(argv[1], "-", strlen("-")) != 0) { | 651 | if (argc && !script_name && !rec_script_path && !rep_script_path) { |
597 | char *record_script_path, *report_script_path; | ||
598 | int live_pipe[2]; | 652 | int live_pipe[2]; |
653 | int rep_args; | ||
599 | pid_t pid; | 654 | pid_t pid; |
600 | 655 | ||
601 | record_script_path = get_script_path(argv[1], RECORD_SUFFIX); | 656 | rec_script_path = get_script_path(argv[0], RECORD_SUFFIX); |
602 | if (!record_script_path) { | 657 | rep_script_path = get_script_path(argv[0], REPORT_SUFFIX); |
603 | fprintf(stderr, "record script not found\n"); | 658 | |
604 | return -1; | 659 | if (!rec_script_path && !rep_script_path) { |
660 | fprintf(stderr, " Couldn't find script %s\n\n See perf" | ||
661 | " trace -l for available scripts.\n", argv[0]); | ||
662 | usage_with_options(trace_usage, options); | ||
605 | } | 663 | } |
606 | 664 | ||
607 | report_script_path = get_script_path(argv[1], REPORT_SUFFIX); | 665 | if (is_top_script(argv[0])) { |
608 | if (!report_script_path) { | 666 | rep_args = argc - 1; |
609 | fprintf(stderr, "report script not found\n"); | 667 | } else { |
610 | return -1; | 668 | int rec_args; |
669 | |||
670 | rep_args = has_required_arg(rep_script_path); | ||
671 | rec_args = (argc - 1) - rep_args; | ||
672 | if (rec_args < 0) { | ||
673 | fprintf(stderr, " %s script requires options." | ||
674 | "\n\n See perf trace -l for available " | ||
675 | "scripts and options.\n", argv[0]); | ||
676 | usage_with_options(trace_usage, options); | ||
677 | } | ||
611 | } | 678 | } |
612 | 679 | ||
613 | if (pipe(live_pipe) < 0) { | 680 | if (pipe(live_pipe) < 0) { |
@@ -622,60 +689,84 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
622 | } | 689 | } |
623 | 690 | ||
624 | if (!pid) { | 691 | if (!pid) { |
692 | system_wide = true; | ||
693 | j = 0; | ||
694 | |||
625 | dup2(live_pipe[1], 1); | 695 | dup2(live_pipe[1], 1); |
626 | close(live_pipe[0]); | 696 | close(live_pipe[0]); |
627 | 697 | ||
628 | __argv = malloc(6 * sizeof(const char *)); | 698 | if (!is_top_script(argv[0])) |
629 | __argv[0] = "/bin/sh"; | 699 | system_wide = !have_cmd(argc - rep_args, |
630 | __argv[1] = record_script_path; | 700 | &argv[rep_args]); |
631 | __argv[2] = "-q"; | 701 | |
632 | __argv[3] = "-o"; | 702 | __argv = malloc((argc + 6) * sizeof(const char *)); |
633 | __argv[4] = "-"; | 703 | if (!__argv) |
634 | __argv[5] = NULL; | 704 | die("malloc"); |
705 | |||
706 | __argv[j++] = "/bin/sh"; | ||
707 | __argv[j++] = rec_script_path; | ||
708 | if (system_wide) | ||
709 | __argv[j++] = "-a"; | ||
710 | __argv[j++] = "-q"; | ||
711 | __argv[j++] = "-o"; | ||
712 | __argv[j++] = "-"; | ||
713 | for (i = rep_args + 1; i < argc; i++) | ||
714 | __argv[j++] = argv[i]; | ||
715 | __argv[j++] = NULL; | ||
635 | 716 | ||
636 | execvp("/bin/sh", (char **)__argv); | 717 | execvp("/bin/sh", (char **)__argv); |
718 | free(__argv); | ||
637 | exit(-1); | 719 | exit(-1); |
638 | } | 720 | } |
639 | 721 | ||
640 | dup2(live_pipe[0], 0); | 722 | dup2(live_pipe[0], 0); |
641 | close(live_pipe[1]); | 723 | close(live_pipe[1]); |
642 | 724 | ||
643 | __argv = malloc((argc + 3) * sizeof(const char *)); | 725 | __argv = malloc((argc + 4) * sizeof(const char *)); |
644 | __argv[0] = "/bin/sh"; | 726 | if (!__argv) |
645 | __argv[1] = report_script_path; | 727 | die("malloc"); |
646 | for (i = 2; i < argc; i++) | 728 | j = 0; |
647 | __argv[i] = argv[i]; | 729 | __argv[j++] = "/bin/sh"; |
648 | __argv[i++] = "-i"; | 730 | __argv[j++] = rep_script_path; |
649 | __argv[i++] = "-"; | 731 | for (i = 1; i < rep_args + 1; i++) |
650 | __argv[i++] = NULL; | 732 | __argv[j++] = argv[i]; |
733 | __argv[j++] = "-i"; | ||
734 | __argv[j++] = "-"; | ||
735 | __argv[j++] = NULL; | ||
651 | 736 | ||
652 | execvp("/bin/sh", (char **)__argv); | 737 | execvp("/bin/sh", (char **)__argv); |
738 | free(__argv); | ||
653 | exit(-1); | 739 | exit(-1); |
654 | } | 740 | } |
655 | 741 | ||
656 | if (suffix) { | 742 | if (rec_script_path) |
657 | script_path = get_script_path(argv[2], suffix); | 743 | script_path = rec_script_path; |
658 | if (!script_path) { | 744 | if (rep_script_path) |
659 | fprintf(stderr, "script not found\n"); | 745 | script_path = rep_script_path; |
660 | return -1; | 746 | |
661 | } | 747 | if (script_path) { |
662 | 748 | system_wide = false; | |
663 | __argv = malloc((argc + 1) * sizeof(const char *)); | 749 | j = 0; |
664 | __argv[0] = "/bin/sh"; | 750 | |
665 | __argv[1] = script_path; | 751 | if (rec_script_path) |
666 | for (i = 3; i < argc; i++) | 752 | system_wide = !have_cmd(argc - 1, &argv[1]); |
667 | __argv[i - 1] = argv[i]; | 753 | |
668 | __argv[argc - 1] = NULL; | 754 | __argv = malloc((argc + 2) * sizeof(const char *)); |
755 | if (!__argv) | ||
756 | die("malloc"); | ||
757 | __argv[j++] = "/bin/sh"; | ||
758 | __argv[j++] = script_path; | ||
759 | if (system_wide) | ||
760 | __argv[j++] = "-a"; | ||
761 | for (i = 2; i < argc; i++) | ||
762 | __argv[j++] = argv[i]; | ||
763 | __argv[j++] = NULL; | ||
669 | 764 | ||
670 | execvp("/bin/sh", (char **)__argv); | 765 | execvp("/bin/sh", (char **)__argv); |
766 | free(__argv); | ||
671 | exit(-1); | 767 | exit(-1); |
672 | } | 768 | } |
673 | 769 | ||
674 | setup_scripting(); | ||
675 | |||
676 | argc = parse_options(argc, argv, options, trace_usage, | ||
677 | PARSE_OPT_STOP_AT_NON_OPTION); | ||
678 | |||
679 | if (symbol__init() < 0) | 770 | if (symbol__init() < 0) |
680 | return -1; | 771 | return -1; |
681 | if (!script_name) | 772 | if (!script_name) |