diff options
Diffstat (limited to 'tools/perf')
20 files changed, 302 insertions, 114 deletions
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index 122ec9dc4853..26aff6bf9e50 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt | |||
@@ -8,7 +8,11 @@ perf-trace - Read perf.data (created by perf record) and display trace output | |||
8 | SYNOPSIS | 8 | SYNOPSIS |
9 | -------- | 9 | -------- |
10 | [verse] | 10 | [verse] |
11 | 'perf trace' {record <script> | report <script> [args] } | 11 | 'perf trace' [<options>] |
12 | 'perf trace' [<options>] record <script> [<record-options>] <command> | ||
13 | 'perf trace' [<options>] report <script> [script-args] | ||
14 | 'perf trace' [<options>] <script> <required-script-args> [<record-options>] <command> | ||
15 | 'perf trace' [<options>] <top-script> [script-args] | ||
12 | 16 | ||
13 | DESCRIPTION | 17 | DESCRIPTION |
14 | ----------- | 18 | ----------- |
@@ -24,23 +28,53 @@ There are several variants of perf trace: | |||
24 | available via 'perf trace -l'). The following variants allow you to | 28 | available via 'perf trace -l'). The following variants allow you to |
25 | record and run those scripts: | 29 | record and run those scripts: |
26 | 30 | ||
27 | 'perf trace record <script>' to record the events required for 'perf | 31 | 'perf trace record <script> <command>' to record the events required |
28 | trace report'. <script> is the name displayed in the output of | 32 | for 'perf trace report'. <script> is the name displayed in the |
29 | 'perf trace --list' i.e. the actual script name minus any language | 33 | output of 'perf trace --list' i.e. the actual script name minus any |
30 | extension. | 34 | language extension. If <command> is not specified, the events are |
35 | recorded using the -a (system-wide) 'perf record' option. | ||
31 | 36 | ||
32 | 'perf trace report <script>' to run and display the results of | 37 | 'perf trace report <script> [args]' to run and display the results |
33 | <script>. <script> is the name displayed in the output of 'perf | 38 | of <script>. <script> is the name displayed in the output of 'perf |
34 | trace --list' i.e. the actual script name minus any language | 39 | trace --list' i.e. the actual script name minus any language |
35 | extension. The perf.data output from a previous run of 'perf trace | 40 | extension. The perf.data output from a previous run of 'perf trace |
36 | record <script>' is used and should be present for this command to | 41 | record <script>' is used and should be present for this command to |
37 | succeed. | 42 | succeed. [args] refers to the (mainly optional) args expected by |
43 | the script. | ||
44 | |||
45 | 'perf trace <script> <required-script-args> <command>' to both | ||
46 | record the events required for <script> and to run the <script> | ||
47 | using 'live-mode' i.e. without writing anything to disk. <script> | ||
48 | is the name displayed in the output of 'perf trace --list' i.e. the | ||
49 | actual script name minus any language extension. If <command> is | ||
50 | not specified, the events are recorded using the -a (system-wide) | ||
51 | 'perf record' option. If <script> has any required args, they | ||
52 | should be specified before <command>. This mode doesn't allow for | ||
53 | optional script args to be specified; if optional script args are | ||
54 | desired, they can be specified using separate 'perf trace record' | ||
55 | and 'perf trace report' commands, with the stdout of the record step | ||
56 | piped to the stdin of the report script, using the '-o -' and '-i -' | ||
57 | options of the corresponding commands. | ||
58 | |||
59 | 'perf trace <top-script>' to both record the events required for | ||
60 | <top-script> and to run the <top-script> using 'live-mode' | ||
61 | i.e. without writing anything to disk. <top-script> is the name | ||
62 | displayed in the output of 'perf trace --list' i.e. the actual | ||
63 | script name minus any language extension; a <top-script> is defined | ||
64 | as any script name ending with the string 'top'. | ||
65 | |||
66 | [<record-options>] can be passed to the record steps of 'perf trace | ||
67 | record' and 'live-mode' variants; this isn't possible however for | ||
68 | <top-script> 'live-mode' or 'perf trace report' variants. | ||
38 | 69 | ||
39 | See the 'SEE ALSO' section for links to language-specific | 70 | See the 'SEE ALSO' section for links to language-specific |
40 | information on how to write and run your own trace scripts. | 71 | information on how to write and run your own trace scripts. |
41 | 72 | ||
42 | OPTIONS | 73 | OPTIONS |
43 | ------- | 74 | ------- |
75 | <command>...:: | ||
76 | Any command you can specify in a shell. | ||
77 | |||
44 | -D:: | 78 | -D:: |
45 | --dump-raw-trace=:: | 79 | --dump-raw-trace=:: |
46 | Display verbose dump of the trace data. | 80 | Display verbose dump of the trace data. |
@@ -64,6 +98,13 @@ OPTIONS | |||
64 | Generate perf-trace.[ext] starter script for given language, | 98 | Generate perf-trace.[ext] starter script for given language, |
65 | using current perf.data. | 99 | using current perf.data. |
66 | 100 | ||
101 | -a:: | ||
102 | Force system-wide collection. Scripts run without a <command> | ||
103 | normally use -a by default, while scripts run with a <command> | ||
104 | normally don't - this option allows the latter to be run in | ||
105 | system-wide mode. | ||
106 | |||
107 | |||
67 | SEE ALSO | 108 | SEE ALSO |
68 | -------- | 109 | -------- |
69 | linkperf:perf-record[1], linkperf:perf-trace-perl[1], | 110 | linkperf:perf-record[1], linkperf:perf-trace-perl[1], |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 4e75583ddd6d..564491fa18b2 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -197,7 +197,7 @@ static void sig_atexit(void) | |||
197 | if (child_pid > 0) | 197 | if (child_pid > 0) |
198 | kill(child_pid, SIGTERM); | 198 | kill(child_pid, SIGTERM); |
199 | 199 | ||
200 | if (signr == -1) | 200 | if (signr == -1 || signr == SIGUSR1) |
201 | return; | 201 | return; |
202 | 202 | ||
203 | signal(signr, SIG_DFL); | 203 | signal(signr, SIG_DFL); |
@@ -515,6 +515,7 @@ static int __cmd_record(int argc, const char **argv) | |||
515 | atexit(sig_atexit); | 515 | atexit(sig_atexit); |
516 | signal(SIGCHLD, sig_handler); | 516 | signal(SIGCHLD, sig_handler); |
517 | signal(SIGINT, sig_handler); | 517 | signal(SIGINT, sig_handler); |
518 | signal(SIGUSR1, sig_handler); | ||
518 | 519 | ||
519 | if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { | 520 | if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { |
520 | perror("failed to create pipes"); | 521 | perror("failed to create pipes"); |
@@ -606,6 +607,7 @@ static int __cmd_record(int argc, const char **argv) | |||
606 | execvp(argv[0], (char **)argv); | 607 | execvp(argv[0], (char **)argv); |
607 | 608 | ||
608 | perror(argv[0]); | 609 | perror(argv[0]); |
610 | kill(getppid(), SIGUSR1); | ||
609 | exit(-1); | 611 | exit(-1); |
610 | } | 612 | } |
611 | 613 | ||
@@ -697,17 +699,18 @@ static int __cmd_record(int argc, const char **argv) | |||
697 | if (err < 0) | 699 | if (err < 0) |
698 | err = event__synthesize_kernel_mmap(process_synthesized_event, | 700 | err = event__synthesize_kernel_mmap(process_synthesized_event, |
699 | session, machine, "_stext"); | 701 | session, machine, "_stext"); |
700 | if (err < 0) { | 702 | if (err < 0) |
701 | pr_err("Couldn't record kernel reference relocation symbol.\n"); | 703 | pr_err("Couldn't record kernel reference relocation symbol\n" |
702 | return err; | 704 | "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" |
703 | } | 705 | "Check /proc/kallsyms permission or run as root.\n"); |
704 | 706 | ||
705 | err = event__synthesize_modules(process_synthesized_event, | 707 | err = event__synthesize_modules(process_synthesized_event, |
706 | session, machine); | 708 | session, machine); |
707 | if (err < 0) { | 709 | if (err < 0) |
708 | pr_err("Couldn't record kernel reference relocation symbol.\n"); | 710 | pr_err("Couldn't record kernel module information.\n" |
709 | return err; | 711 | "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" |
710 | } | 712 | "Check /proc/modules permission or run as root.\n"); |
713 | |||
711 | if (perf_guest) | 714 | if (perf_guest) |
712 | perf_session__process_machines(session, event__synthesize_guest_os); | 715 | perf_session__process_machines(session, event__synthesize_guest_os); |
713 | 716 | ||
@@ -761,7 +764,7 @@ static int __cmd_record(int argc, const char **argv) | |||
761 | } | 764 | } |
762 | } | 765 | } |
763 | 766 | ||
764 | if (quiet) | 767 | if (quiet || signr == SIGUSR1) |
765 | return 0; | 768 | return 0; |
766 | 769 | ||
767 | fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); | 770 | fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); |
@@ -790,7 +793,7 @@ static const char * const record_usage[] = { | |||
790 | 793 | ||
791 | static bool force, append_file; | 794 | static bool force, append_file; |
792 | 795 | ||
793 | static const struct option options[] = { | 796 | const struct option record_options[] = { |
794 | OPT_CALLBACK('e', "event", NULL, "event", | 797 | OPT_CALLBACK('e', "event", NULL, "event", |
795 | "event selector. use 'perf list' to list available events", | 798 | "event selector. use 'perf list' to list available events", |
796 | parse_events), | 799 | parse_events), |
@@ -839,16 +842,16 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
839 | { | 842 | { |
840 | int i, j, err = -ENOMEM; | 843 | int i, j, err = -ENOMEM; |
841 | 844 | ||
842 | argc = parse_options(argc, argv, options, record_usage, | 845 | argc = parse_options(argc, argv, record_options, record_usage, |
843 | PARSE_OPT_STOP_AT_NON_OPTION); | 846 | PARSE_OPT_STOP_AT_NON_OPTION); |
844 | if (!argc && target_pid == -1 && target_tid == -1 && | 847 | if (!argc && target_pid == -1 && target_tid == -1 && |
845 | !system_wide && !cpu_list) | 848 | !system_wide && !cpu_list) |
846 | usage_with_options(record_usage, options); | 849 | usage_with_options(record_usage, record_options); |
847 | 850 | ||
848 | if (force && append_file) { | 851 | if (force && append_file) { |
849 | fprintf(stderr, "Can't overwrite and append at the same time." | 852 | fprintf(stderr, "Can't overwrite and append at the same time." |
850 | " You need to choose between -f and -A"); | 853 | " You need to choose between -f and -A"); |
851 | usage_with_options(record_usage, options); | 854 | usage_with_options(record_usage, record_options); |
852 | } else if (append_file) { | 855 | } else if (append_file) { |
853 | write_mode = WRITE_APPEND; | 856 | write_mode = WRITE_APPEND; |
854 | } else { | 857 | } else { |
@@ -871,7 +874,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
871 | if (thread_num <= 0) { | 874 | if (thread_num <= 0) { |
872 | fprintf(stderr, "Can't find all threads of pid %d\n", | 875 | fprintf(stderr, "Can't find all threads of pid %d\n", |
873 | target_pid); | 876 | target_pid); |
874 | usage_with_options(record_usage, options); | 877 | usage_with_options(record_usage, record_options); |
875 | } | 878 | } |
876 | } else { | 879 | } else { |
877 | all_tids=malloc(sizeof(pid_t)); | 880 | all_tids=malloc(sizeof(pid_t)); |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index b513e40974f4..dd625808c2a5 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -69,7 +69,6 @@ static int target_tid = -1; | |||
69 | static pid_t *all_tids = NULL; | 69 | static pid_t *all_tids = NULL; |
70 | static int thread_num = 0; | 70 | static int thread_num = 0; |
71 | static bool inherit = false; | 71 | static bool inherit = false; |
72 | static int profile_cpu = -1; | ||
73 | static int nr_cpus = 0; | 72 | static int nr_cpus = 0; |
74 | static int realtime_prio = 0; | 73 | static int realtime_prio = 0; |
75 | static bool group = false; | 74 | static bool group = false; |
@@ -558,13 +557,13 @@ static void print_sym_table(void) | |||
558 | else | 557 | else |
559 | printf(" (all"); | 558 | printf(" (all"); |
560 | 559 | ||
561 | if (profile_cpu != -1) | 560 | if (cpu_list) |
562 | printf(", cpu: %d)\n", profile_cpu); | 561 | printf(", CPU%s: %s)\n", nr_cpus > 1 ? "s" : "", cpu_list); |
563 | else { | 562 | else { |
564 | if (target_tid != -1) | 563 | if (target_tid != -1) |
565 | printf(")\n"); | 564 | printf(")\n"); |
566 | else | 565 | else |
567 | printf(", %d CPUs)\n", nr_cpus); | 566 | printf(", %d CPU%s)\n", nr_cpus, nr_cpus > 1 ? "s" : ""); |
568 | } | 567 | } |
569 | 568 | ||
570 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); | 569 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); |
@@ -1187,11 +1186,10 @@ int group_fd; | |||
1187 | static void start_counter(int i, int counter) | 1186 | static void start_counter(int i, int counter) |
1188 | { | 1187 | { |
1189 | struct perf_event_attr *attr; | 1188 | struct perf_event_attr *attr; |
1190 | int cpu; | 1189 | int cpu = -1; |
1191 | int thread_index; | 1190 | int thread_index; |
1192 | 1191 | ||
1193 | cpu = profile_cpu; | 1192 | if (target_tid == -1) |
1194 | if (target_tid == -1 && profile_cpu == -1) | ||
1195 | cpu = cpumap[i]; | 1193 | cpu = cpumap[i]; |
1196 | 1194 | ||
1197 | attr = attrs + counter; | 1195 | attr = attrs + counter; |
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) |
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-record b/tools/perf/scripts/perl/bin/failed-syscalls-record index eb5846bcb565..8104895a7b67 100644 --- a/tools/perf/scripts/perl/bin/failed-syscalls-record +++ b/tools/perf/scripts/perl/bin/failed-syscalls-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -a -e raw_syscalls:sys_exit $@ | 2 | perf record -e raw_syscalls:sys_exit $@ |
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-record b/tools/perf/scripts/perl/bin/rw-by-file-record index 5bfaae5a6cba..33efc8673aae 100644 --- a/tools/perf/scripts/perl/bin/rw-by-file-record +++ b/tools/perf/scripts/perl/bin/rw-by-file-record | |||
@@ -1,3 +1,3 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -a -e syscalls:sys_enter_read -e syscalls:sys_enter_write $@ | 2 | perf record -e syscalls:sys_enter_read -e syscalls:sys_enter_write $@ |
3 | 3 | ||
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-record b/tools/perf/scripts/perl/bin/rw-by-pid-record index 6e0b2f7755ac..7cb9db230448 100644 --- a/tools/perf/scripts/perl/bin/rw-by-pid-record +++ b/tools/perf/scripts/perl/bin/rw-by-pid-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -a -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@ | 2 | perf record -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@ |
diff --git a/tools/perf/scripts/perl/bin/rwtop-record b/tools/perf/scripts/perl/bin/rwtop-record index 6e0b2f7755ac..7cb9db230448 100644 --- a/tools/perf/scripts/perl/bin/rwtop-record +++ b/tools/perf/scripts/perl/bin/rwtop-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -a -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@ | 2 | perf record -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@ |
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-record b/tools/perf/scripts/perl/bin/wakeup-latency-record index 9f2acaaae9f0..464251a1bd7e 100644 --- a/tools/perf/scripts/perl/bin/wakeup-latency-record +++ b/tools/perf/scripts/perl/bin/wakeup-latency-record | |||
@@ -1,5 +1,5 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -a -e sched:sched_switch -e sched:sched_wakeup $@ | 2 | perf record -e sched:sched_switch -e sched:sched_wakeup $@ |
3 | 3 | ||
4 | 4 | ||
5 | 5 | ||
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record index 85301f2471ff..8edda9078d5d 100644 --- a/tools/perf/scripts/perl/bin/workqueue-stats-record +++ b/tools/perf/scripts/perl/bin/workqueue-stats-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -a -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@ | 2 | perf record -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@ |
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record index eb5846bcb565..8104895a7b67 100644 --- a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record +++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -a -e raw_syscalls:sys_exit $@ | 2 | perf record -e raw_syscalls:sys_exit $@ |
diff --git a/tools/perf/scripts/python/bin/futex-contention-record b/tools/perf/scripts/python/bin/futex-contention-record index 5ecbb433caf4..b1495c9a9b20 100644 --- a/tools/perf/scripts/python/bin/futex-contention-record +++ b/tools/perf/scripts/python/bin/futex-contention-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -a -e syscalls:sys_enter_futex -e syscalls:sys_exit_futex $@ | 2 | perf record -e syscalls:sys_enter_futex -e syscalls:sys_exit_futex $@ |
diff --git a/tools/perf/scripts/python/bin/netdev-times-record b/tools/perf/scripts/python/bin/netdev-times-record index d931a828126b..558754b840a9 100644 --- a/tools/perf/scripts/python/bin/netdev-times-record +++ b/tools/perf/scripts/python/bin/netdev-times-record | |||
@@ -1,5 +1,5 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -a -e net:net_dev_xmit -e net:net_dev_queue \ | 2 | perf record -e net:net_dev_xmit -e net:net_dev_queue \ |
3 | -e net:netif_receive_skb -e net:netif_rx \ | 3 | -e net:netif_receive_skb -e net:netif_rx \ |
4 | -e skb:consume_skb -e skb:kfree_skb \ | 4 | -e skb:consume_skb -e skb:kfree_skb \ |
5 | -e skb:skb_copy_datagram_iovec -e napi:napi_poll \ | 5 | -e skb:skb_copy_datagram_iovec -e napi:napi_poll \ |
diff --git a/tools/perf/scripts/python/bin/sched-migration-record b/tools/perf/scripts/python/bin/sched-migration-record index 17a3e9bd9e8f..7493fddbe995 100644 --- a/tools/perf/scripts/python/bin/sched-migration-record +++ b/tools/perf/scripts/python/bin/sched-migration-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -m 16384 -a -e sched:sched_wakeup -e sched:sched_wakeup_new -e sched:sched_switch -e sched:sched_migrate_task $@ | 2 | perf record -m 16384 -e sched:sched_wakeup -e sched:sched_wakeup_new -e sched:sched_switch -e sched:sched_migrate_task $@ |
diff --git a/tools/perf/scripts/python/bin/sctop-record b/tools/perf/scripts/python/bin/sctop-record index 1fc5998b721d..4efbfaa7f6a5 100644 --- a/tools/perf/scripts/python/bin/sctop-record +++ b/tools/perf/scripts/python/bin/sctop-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -a -e raw_syscalls:sys_enter $@ | 2 | perf record -e raw_syscalls:sys_enter $@ |
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record index 1fc5998b721d..4efbfaa7f6a5 100644 --- a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record +++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -a -e raw_syscalls:sys_enter $@ | 2 | perf record -e raw_syscalls:sys_enter $@ |
diff --git a/tools/perf/scripts/python/bin/syscall-counts-record b/tools/perf/scripts/python/bin/syscall-counts-record index 1fc5998b721d..4efbfaa7f6a5 100644 --- a/tools/perf/scripts/python/bin/syscall-counts-record +++ b/tools/perf/scripts/python/bin/syscall-counts-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -a -e raw_syscalls:sys_enter $@ | 2 | perf record -e raw_syscalls:sys_enter $@ |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index d7e67b167ea3..64a85bafde63 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -946,11 +946,16 @@ perf_header__find_attr(u64 id, struct perf_header *header) | |||
946 | 946 | ||
947 | /* | 947 | /* |
948 | * We set id to -1 if the data file doesn't contain sample | 948 | * We set id to -1 if the data file doesn't contain sample |
949 | * ids. Check for this and avoid walking through the entire | 949 | * ids. This can happen when the data file contains one type |
950 | * list of ids which may be large. | 950 | * of event and in that case, the header can still store the |
951 | * event attribute information. Check for this and avoid | ||
952 | * walking through the entire list of ids which may be large. | ||
951 | */ | 953 | */ |
952 | if (id == -1ULL) | 954 | if (id == -1ULL) { |
955 | if (header->attrs > 0) | ||
956 | return &header->attr[0]->attr; | ||
953 | return NULL; | 957 | return NULL; |
958 | } | ||
954 | 959 | ||
955 | for (i = 0; i < header->attrs; i++) { | 960 | for (i = 0; i < header->attrs; i++) { |
956 | struct perf_header_attr *attr = header->attr[i]; | 961 | struct perf_header_attr *attr = header->attr[i]; |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b39f499e575a..d628c8d1cf5e 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -295,7 +295,9 @@ static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) | |||
295 | { | 295 | { |
296 | struct rb_node **p = &self->rb_node; | 296 | struct rb_node **p = &self->rb_node; |
297 | struct rb_node *parent = NULL; | 297 | struct rb_node *parent = NULL; |
298 | struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s; | 298 | struct symbol_name_rb_node *symn, *s; |
299 | |||
300 | symn = container_of(sym, struct symbol_name_rb_node, sym); | ||
299 | 301 | ||
300 | while (*p != NULL) { | 302 | while (*p != NULL) { |
301 | parent = *p; | 303 | parent = *p; |
@@ -530,7 +532,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, | |||
530 | struct machine *machine = kmaps->machine; | 532 | struct machine *machine = kmaps->machine; |
531 | struct map *curr_map = map; | 533 | struct map *curr_map = map; |
532 | struct symbol *pos; | 534 | struct symbol *pos; |
533 | int count = 0; | 535 | int count = 0, moved = 0; |
534 | struct rb_root *root = &self->symbols[map->type]; | 536 | struct rb_root *root = &self->symbols[map->type]; |
535 | struct rb_node *next = rb_first(root); | 537 | struct rb_node *next = rb_first(root); |
536 | int kernel_range = 0; | 538 | int kernel_range = 0; |
@@ -588,6 +590,11 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, | |||
588 | char dso_name[PATH_MAX]; | 590 | char dso_name[PATH_MAX]; |
589 | struct dso *dso; | 591 | struct dso *dso; |
590 | 592 | ||
593 | if (count == 0) { | ||
594 | curr_map = map; | ||
595 | goto filter_symbol; | ||
596 | } | ||
597 | |||
591 | if (self->kernel == DSO_TYPE_GUEST_KERNEL) | 598 | if (self->kernel == DSO_TYPE_GUEST_KERNEL) |
592 | snprintf(dso_name, sizeof(dso_name), | 599 | snprintf(dso_name, sizeof(dso_name), |
593 | "[guest.kernel].%d", | 600 | "[guest.kernel].%d", |
@@ -613,7 +620,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, | |||
613 | map_groups__insert(kmaps, curr_map); | 620 | map_groups__insert(kmaps, curr_map); |
614 | ++kernel_range; | 621 | ++kernel_range; |
615 | } | 622 | } |
616 | 623 | filter_symbol: | |
617 | if (filter && filter(curr_map, pos)) { | 624 | if (filter && filter(curr_map, pos)) { |
618 | discard_symbol: rb_erase(&pos->rb_node, root); | 625 | discard_symbol: rb_erase(&pos->rb_node, root); |
619 | symbol__delete(pos); | 626 | symbol__delete(pos); |
@@ -621,8 +628,9 @@ discard_symbol: rb_erase(&pos->rb_node, root); | |||
621 | if (curr_map != map) { | 628 | if (curr_map != map) { |
622 | rb_erase(&pos->rb_node, root); | 629 | rb_erase(&pos->rb_node, root); |
623 | symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); | 630 | symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); |
624 | } | 631 | ++moved; |
625 | count++; | 632 | } else |
633 | ++count; | ||
626 | } | 634 | } |
627 | } | 635 | } |
628 | 636 | ||
@@ -632,7 +640,7 @@ discard_symbol: rb_erase(&pos->rb_node, root); | |||
632 | dso__set_loaded(curr_map->dso, curr_map->type); | 640 | dso__set_loaded(curr_map->dso, curr_map->type); |
633 | } | 641 | } |
634 | 642 | ||
635 | return count; | 643 | return count + moved; |
636 | } | 644 | } |
637 | 645 | ||
638 | int dso__load_kallsyms(struct dso *self, const char *filename, | 646 | int dso__load_kallsyms(struct dso *self, const char *filename, |
@@ -2123,14 +2131,55 @@ static struct dso *machine__create_kernel(struct machine *self) | |||
2123 | return kernel; | 2131 | return kernel; |
2124 | } | 2132 | } |
2125 | 2133 | ||
2134 | struct process_args { | ||
2135 | u64 start; | ||
2136 | }; | ||
2137 | |||
2138 | static int symbol__in_kernel(void *arg, const char *name, | ||
2139 | char type __used, u64 start) | ||
2140 | { | ||
2141 | struct process_args *args = arg; | ||
2142 | |||
2143 | if (strchr(name, '[')) | ||
2144 | return 0; | ||
2145 | |||
2146 | args->start = start; | ||
2147 | return 1; | ||
2148 | } | ||
2149 | |||
2150 | /* Figure out the start address of kernel map from /proc/kallsyms */ | ||
2151 | static u64 machine__get_kernel_start_addr(struct machine *machine) | ||
2152 | { | ||
2153 | const char *filename; | ||
2154 | char path[PATH_MAX]; | ||
2155 | struct process_args args; | ||
2156 | |||
2157 | if (machine__is_host(machine)) { | ||
2158 | filename = "/proc/kallsyms"; | ||
2159 | } else { | ||
2160 | if (machine__is_default_guest(machine)) | ||
2161 | filename = (char *)symbol_conf.default_guest_kallsyms; | ||
2162 | else { | ||
2163 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); | ||
2164 | filename = path; | ||
2165 | } | ||
2166 | } | ||
2167 | |||
2168 | if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) | ||
2169 | return 0; | ||
2170 | |||
2171 | return args.start; | ||
2172 | } | ||
2173 | |||
2126 | int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) | 2174 | int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) |
2127 | { | 2175 | { |
2128 | enum map_type type; | 2176 | enum map_type type; |
2177 | u64 start = machine__get_kernel_start_addr(self); | ||
2129 | 2178 | ||
2130 | for (type = 0; type < MAP__NR_TYPES; ++type) { | 2179 | for (type = 0; type < MAP__NR_TYPES; ++type) { |
2131 | struct kmap *kmap; | 2180 | struct kmap *kmap; |
2132 | 2181 | ||
2133 | self->vmlinux_maps[type] = map__new2(0, kernel, type); | 2182 | self->vmlinux_maps[type] = map__new2(start, kernel, type); |
2134 | if (self->vmlinux_maps[type] == NULL) | 2183 | if (self->vmlinux_maps[type] == NULL) |
2135 | return -1; | 2184 | return -1; |
2136 | 2185 | ||
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c index 9706d9d40279..056c69521a38 100644 --- a/tools/perf/util/ui/util.c +++ b/tools/perf/util/ui/util.c | |||
@@ -104,9 +104,10 @@ out_destroy_form: | |||
104 | return rc; | 104 | return rc; |
105 | } | 105 | } |
106 | 106 | ||
107 | static const char yes[] = "Yes", no[] = "No"; | ||
108 | |||
107 | bool ui__dialog_yesno(const char *msg) | 109 | bool ui__dialog_yesno(const char *msg) |
108 | { | 110 | { |
109 | /* newtWinChoice should really be accepting const char pointers... */ | 111 | /* newtWinChoice should really be accepting const char pointers... */ |
110 | char yes[] = "Yes", no[] = "No"; | 112 | return newtWinChoice(NULL, (char *)yes, (char *)no, (char *)msg) == 1; |
111 | return newtWinChoice(NULL, yes, no, (char *)msg) == 1; | ||
112 | } | 113 | } |