aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-trace.c
diff options
context:
space:
mode:
authorTom Zanussi <tom.zanussi@linux.intel.com>2010-11-10 09:16:51 -0500
committerTom Zanussi <tom.zanussi@linux.intel.com>2010-11-10 09:16:51 -0500
commitb5b8731219ddd007c229feacbfe745d1be070e6a (patch)
treec9e5b7bf73da3a963664d28dbc7ed25c1f313aee /tools/perf/builtin-trace.c
parent34c86ea97ed811bb40ee4db63f710eb522162c77 (diff)
perf trace: live-mode command-line cleanup
This patch attempts to make the perf trace command-line for live-mode commands more user-friendly and consistent with other perf commands. The main change it makes is to allow <commands> to be run as part of perf trace live-mode commands, as other perf commands do, instead of the system-wide traces they're currently hard-coded to by the shell scripts. With this patch, the following live-mode trace now works as expected: $ perf trace rw-by-pid ls -al The previous system-wide behavior for this command would still be available by explicitly specifying -a: $ perf trace rw-by-pid -a ls -al and if no <command> is specified, the output is also system-wide: $ perf trace rw-by-pid Because live-mode requires both record and report steps to be invoked, it isn't always possible to know which args to send to the report and which to send to the record steps - mainly this is the case for report scripts with optional args - in those cases it would be necessary to use separate 'perf trace record' and 'perf trace report' steps. For example: $ perf trace syscall-counts ls Here we can't decide whether ls should be passed as a param to the syscall-counts script or whether we should invoke ls as a <command>. In these cases, we just say that we'll ignore optional script params and always interpret the extra arguments as a <command>. If the user instead wants the other interpretation, that can be accomplished by using separate record and report commands explicitly: $ perf trace record syscall-counts $ perf trace report syscall-counts ls So the rules that this patch implements, which seem to make the most intuitive sense for live-mode commands: - for commands with optional args and commands with no args, no args are sent to the report script, all are sent to the record step - for 'top' commands i.e. that end with 'top', <commands> can't be used - all extra args are send to the report script as params - for commands with required args, the n required args are taken to be the first n args after the script name and sent to the report script, and the rest are sent to the record step Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com> Acked-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r--tools/perf/builtin-trace.c165
1 files changed, 108 insertions, 57 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 0de7fcb90965..0483e28fa60d 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -330,7 +330,7 @@ static struct script_desc *script_desc__new(const char *name)
330{ 330{
331 struct script_desc *s = zalloc(sizeof(*s)); 331 struct script_desc *s = zalloc(sizeof(*s));
332 332
333 if (s != NULL) 333 if (s != NULL && name)
334 s->name = strdup(name); 334 s->name = strdup(name);
335 335
336 return s; 336 return s;
@@ -541,6 +541,34 @@ static char *get_script_path(const char *script_root, const char *suffix)
541 return path; 541 return path;
542} 542}
543 543
544static bool is_top_script(const char *script_path)
545{
546 return ends_with((char *)script_path, "top") == NULL ? false : true;
547}
548
549static 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++;
566out:
567 script_desc__delete(desc);
568
569 return n_args;
570}
571
544static const char * const trace_usage[] = { 572static const char * const trace_usage[] = {
545 "perf trace [<options>] <command>", 573 "perf trace [<options>] <command>",
546 NULL 574 NULL
@@ -584,48 +612,65 @@ static bool have_cmd(int argc, const char **argv)
584 612
585int cmd_trace(int argc, const char **argv, const char *prefix __used) 613int cmd_trace(int argc, const char **argv, const char *prefix __used)
586{ 614{
615 char *rec_script_path = NULL;
616 char *rep_script_path = NULL;
587 struct perf_session *session; 617 struct perf_session *session;
588 const char *suffix = NULL; 618 char *script_path = NULL;
589 const char **__argv; 619 const char **__argv;
590 char *script_path; 620 bool system_wide;
591 int i, err; 621 int i, j, err;
592 622
593 if (argc >= 2 && strncmp(argv[1], "rec", strlen("rec")) == 0) { 623 setup_scripting();
594 if (argc < 3) { 624
595 fprintf(stderr, 625 argc = parse_options(argc, argv, options, trace_usage,
596 "Please specify a record script\n"); 626 PARSE_OPT_STOP_AT_NON_OPTION);
597 return -1; 627
598 } 628 if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
599 suffix = RECORD_SUFFIX; 629 rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
630 if (!rec_script_path)
631 return cmd_record(argc, argv, NULL);
600 } 632 }
601 633
602 if (argc >= 2 && strncmp(argv[1], "rep", strlen("rep")) == 0) { 634 if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) {
603 if (argc < 3) { 635 rep_script_path = get_script_path(argv[1], REPORT_SUFFIX);
636 if (!rep_script_path) {
604 fprintf(stderr, 637 fprintf(stderr,
605 "Please specify a report script\n"); 638 "Please specify a valid report script"
639 "(see 'perf trace -l' for listing)\n");
606 return -1; 640 return -1;
607 } 641 }
608 suffix = REPORT_SUFFIX;
609 } 642 }
610 643
611 /* make sure PERF_EXEC_PATH is set for scripts */ 644 /* make sure PERF_EXEC_PATH is set for scripts */
612 perf_set_argv_exec_path(perf_exec_path()); 645 perf_set_argv_exec_path(perf_exec_path());
613 646
614 if (!suffix && argc >= 2 && strncmp(argv[1], "-", strlen("-")) != 0) { 647 if (argc && !script_name && !rec_script_path && !rep_script_path) {
615 char *record_script_path, *report_script_path;
616 int live_pipe[2]; 648 int live_pipe[2];
649 int rep_args;
617 pid_t pid; 650 pid_t pid;
618 651
619 record_script_path = get_script_path(argv[1], RECORD_SUFFIX); 652 rec_script_path = get_script_path(argv[0], RECORD_SUFFIX);
620 if (!record_script_path) { 653 rep_script_path = get_script_path(argv[0], REPORT_SUFFIX);
621 fprintf(stderr, "record script not found\n"); 654
622 return -1; 655 if (!rec_script_path && !rep_script_path) {
656 fprintf(stderr, " Couldn't find script %s\n\n See perf"
657 " trace -l for available scripts.\n", argv[0]);
658 usage_with_options(trace_usage, options);
623 } 659 }
624 660
625 report_script_path = get_script_path(argv[1], REPORT_SUFFIX); 661 if (is_top_script(argv[0])) {
626 if (!report_script_path) { 662 rep_args = argc - 1;
627 fprintf(stderr, "report script not found\n"); 663 } else {
628 return -1; 664 int rec_args;
665
666 rep_args = has_required_arg(rep_script_path);
667 rec_args = (argc - 1) - rep_args;
668 if (rec_args < 0) {
669 fprintf(stderr, " %s script requires options."
670 "\n\n See perf trace -l for available "
671 "scripts and options.\n", argv[0]);
672 usage_with_options(trace_usage, options);
673 }
629 } 674 }
630 675
631 if (pipe(live_pipe) < 0) { 676 if (pipe(live_pipe) < 0) {
@@ -640,19 +685,30 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
640 } 685 }
641 686
642 if (!pid) { 687 if (!pid) {
688 system_wide = true;
689 j = 0;
690
643 dup2(live_pipe[1], 1); 691 dup2(live_pipe[1], 1);
644 close(live_pipe[0]); 692 close(live_pipe[0]);
645 693
646 __argv = malloc(6 * sizeof(const char *)); 694 if (!is_top_script(argv[0]))
695 system_wide = !have_cmd(argc - rep_args,
696 &argv[rep_args]);
697
698 __argv = malloc((argc + 6) * sizeof(const char *));
647 if (!__argv) 699 if (!__argv)
648 die("malloc"); 700 die("malloc");
649 701
650 __argv[0] = "/bin/sh"; 702 __argv[j++] = "/bin/sh";
651 __argv[1] = record_script_path; 703 __argv[j++] = rec_script_path;
652 __argv[2] = "-q"; 704 if (system_wide)
653 __argv[3] = "-o"; 705 __argv[j++] = "-a";
654 __argv[4] = "-"; 706 __argv[j++] = "-q";
655 __argv[5] = NULL; 707 __argv[j++] = "-o";
708 __argv[j++] = "-";
709 for (i = rep_args + 1; i < argc; i++)
710 __argv[j++] = argv[i];
711 __argv[j++] = NULL;
656 712
657 execvp("/bin/sh", (char **)__argv); 713 execvp("/bin/sh", (char **)__argv);
658 free(__argv); 714 free(__argv);
@@ -662,43 +718,43 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
662 dup2(live_pipe[0], 0); 718 dup2(live_pipe[0], 0);
663 close(live_pipe[1]); 719 close(live_pipe[1]);
664 720
665 __argv = malloc((argc + 3) * sizeof(const char *)); 721 __argv = malloc((argc + 4) * sizeof(const char *));
666 if (!__argv) 722 if (!__argv)
667 die("malloc"); 723 die("malloc");
668 __argv[0] = "/bin/sh"; 724 j = 0;
669 __argv[1] = report_script_path; 725 __argv[j++] = "/bin/sh";
670 for (i = 2; i < argc; i++) 726 __argv[j++] = rep_script_path;
671 __argv[i] = argv[i]; 727 for (i = 1; i < rep_args + 1; i++)
672 __argv[i++] = "-i"; 728 __argv[j++] = argv[i];
673 __argv[i++] = "-"; 729 __argv[j++] = "-i";
674 __argv[i++] = NULL; 730 __argv[j++] = "-";
731 __argv[j++] = NULL;
675 732
676 execvp("/bin/sh", (char **)__argv); 733 execvp("/bin/sh", (char **)__argv);
677 free(__argv); 734 free(__argv);
678 exit(-1); 735 exit(-1);
679 } 736 }
680 737
681 if (suffix) { 738 if (rec_script_path)
682 bool system_wide = false; 739 script_path = rec_script_path;
683 int j = 0; 740 if (rep_script_path)
741 script_path = rep_script_path;
684 742
685 script_path = get_script_path(argv[2], suffix); 743 if (script_path) {
686 if (!script_path) { 744 system_wide = false;
687 fprintf(stderr, "script not found\n"); 745 j = 0;
688 return -1;
689 }
690 746
691 if (!strcmp(suffix, RECORD_SUFFIX)) 747 if (rec_script_path)
692 system_wide = !have_cmd(argc - 2, &argv[2]); 748 system_wide = !have_cmd(argc - 1, &argv[1]);
693 749
694 __argv = malloc((argc + 1) * sizeof(const char *)); 750 __argv = malloc((argc + 2) * sizeof(const char *));
695 if (!__argv) 751 if (!__argv)
696 die("malloc"); 752 die("malloc");
697 __argv[j++] = "/bin/sh"; 753 __argv[j++] = "/bin/sh";
698 __argv[j++] = script_path; 754 __argv[j++] = script_path;
699 if (system_wide) 755 if (system_wide)
700 __argv[j++] = "-a"; 756 __argv[j++] = "-a";
701 for (i = 3; i < argc; i++) 757 for (i = 2; i < argc; i++)
702 __argv[j++] = argv[i]; 758 __argv[j++] = argv[i];
703 __argv[j++] = NULL; 759 __argv[j++] = NULL;
704 760
@@ -707,11 +763,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
707 exit(-1); 763 exit(-1);
708 } 764 }
709 765
710 setup_scripting();
711
712 argc = parse_options(argc, argv, options, trace_usage,
713 PARSE_OPT_STOP_AT_NON_OPTION);
714
715 if (symbol__init() < 0) 766 if (symbol__init() < 0)
716 return -1; 767 return -1;
717 if (!script_name) 768 if (!script_name)