diff options
author | Stephane Eranian <eranian@google.com> | 2010-05-28 06:00:01 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2010-06-05 08:33:01 -0400 |
commit | c45c6ea2e5c57960dc67e00294c2b78e9540c007 (patch) | |
tree | 27c56577862cbb95fb8db4b34cfe99878d5dc9a0 | |
parent | 761844b9c68b3c67b085265f92ac0675706cc3b3 (diff) |
perf tools: Add the ability to specify list of cpus to monitor
This patch adds a -C option to stat, record, top to designate a list of CPUs to
monitor. CPUs can be specified as a comma-separated list or ranges, no space
allowed.
Examples:
$ perf record -a -C0-1,4-7 sleep 1
$ perf top -C0-4
$ perf stat -a -C1,2,3,4 sleep 1
With perf record in per-thread mode with inherit mode on, samples are collected
only when the thread runs on the designated CPUs.
The -C option does not turn on system-wide mode automatically.
Cc: David S. Miller <davem@davemloft.net>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <4bff9496.d345d80a.41fe.7b00@mx.google.com>
Signed-off-by: Stephane Eranian <eranian@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/Documentation/perf-record.txt | 7 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-stat.txt | 7 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-top.txt | 8 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 23 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 14 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 16 | ||||
-rw-r--r-- | tools/perf/util/cpumap.c | 57 | ||||
-rw-r--r-- | tools/perf/util/cpumap.h | 2 |
8 files changed, 110 insertions, 24 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 34e255fc3e2f..25576b477c83 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -103,6 +103,13 @@ OPTIONS | |||
103 | --raw-samples:: | 103 | --raw-samples:: |
104 | Collect raw sample records from all opened counters (default for tracepoint counters). | 104 | Collect raw sample records from all opened counters (default for tracepoint counters). |
105 | 105 | ||
106 | -C:: | ||
107 | --cpu:: | ||
108 | Collect samples only on the list of cpus provided. Multiple CPUs can be provided as a | ||
109 | comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. | ||
110 | In per-thread mode with inheritance mode on (default), samples are captured only when | ||
111 | the thread executes on the designated CPUs. Default is to monitor all CPUs. | ||
112 | |||
106 | SEE ALSO | 113 | SEE ALSO |
107 | -------- | 114 | -------- |
108 | linkperf:perf-stat[1], linkperf:perf-list[1] | 115 | linkperf:perf-stat[1], linkperf:perf-list[1] |
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 909fa766fa1c..4b3a2d46b437 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt | |||
@@ -46,6 +46,13 @@ OPTIONS | |||
46 | -B:: | 46 | -B:: |
47 | print large numbers with thousands' separators according to locale | 47 | print large numbers with thousands' separators according to locale |
48 | 48 | ||
49 | -C:: | ||
50 | --cpu=:: | ||
51 | Count only on the list of cpus provided. Multiple CPUs can be provided as a | ||
52 | comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. | ||
53 | In per-thread mode, this option is ignored. The -a option is still necessary | ||
54 | to activate system-wide monitoring. Default is to count on all CPUs. | ||
55 | |||
49 | EXAMPLES | 56 | EXAMPLES |
50 | -------- | 57 | -------- |
51 | 58 | ||
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 785b9fc32a46..1f9687663f2a 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
@@ -25,9 +25,11 @@ OPTIONS | |||
25 | --count=<count>:: | 25 | --count=<count>:: |
26 | Event period to sample. | 26 | Event period to sample. |
27 | 27 | ||
28 | -C <cpu>:: | 28 | -C <cpu-list>:: |
29 | --CPU=<cpu>:: | 29 | --cpu=<cpu>:: |
30 | CPU to profile. | 30 | Monitor only on the list of cpus provided. Multiple CPUs can be provided as a |
31 | comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. | ||
32 | Default is to monitor all CPUS. | ||
31 | 33 | ||
32 | -d <seconds>:: | 34 | -d <seconds>:: |
33 | --delay=<seconds>:: | 35 | --delay=<seconds>:: |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index dc3435e18bde..f28c4bbd801f 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -49,7 +49,6 @@ static int group = 0; | |||
49 | static int realtime_prio = 0; | 49 | static int realtime_prio = 0; |
50 | static bool raw_samples = false; | 50 | static bool raw_samples = false; |
51 | static bool system_wide = false; | 51 | static bool system_wide = false; |
52 | static int profile_cpu = -1; | ||
53 | static pid_t target_pid = -1; | 52 | static pid_t target_pid = -1; |
54 | static pid_t target_tid = -1; | 53 | static pid_t target_tid = -1; |
55 | static pid_t *all_tids = NULL; | 54 | static pid_t *all_tids = NULL; |
@@ -74,6 +73,7 @@ static int file_new = 1; | |||
74 | static off_t post_processing_offset; | 73 | static off_t post_processing_offset; |
75 | 74 | ||
76 | static struct perf_session *session; | 75 | static struct perf_session *session; |
76 | static const char *cpu_list; | ||
77 | 77 | ||
78 | struct mmap_data { | 78 | struct mmap_data { |
79 | int counter; | 79 | int counter; |
@@ -300,7 +300,7 @@ try_again: | |||
300 | die("Permission error - are you root?\n" | 300 | die("Permission error - are you root?\n" |
301 | "\t Consider tweaking" | 301 | "\t Consider tweaking" |
302 | " /proc/sys/kernel/perf_event_paranoid.\n"); | 302 | " /proc/sys/kernel/perf_event_paranoid.\n"); |
303 | else if (err == ENODEV && profile_cpu != -1) { | 303 | else if (err == ENODEV && cpu_list) { |
304 | die("No such device - did you specify" | 304 | die("No such device - did you specify" |
305 | " an out-of-range profile CPU?\n"); | 305 | " an out-of-range profile CPU?\n"); |
306 | } | 306 | } |
@@ -622,10 +622,15 @@ static int __cmd_record(int argc, const char **argv) | |||
622 | close(child_ready_pipe[0]); | 622 | close(child_ready_pipe[0]); |
623 | } | 623 | } |
624 | 624 | ||
625 | if ((!system_wide && no_inherit) || profile_cpu != -1) { | 625 | nr_cpus = read_cpu_map(cpu_list); |
626 | open_counters(profile_cpu); | 626 | if (nr_cpus < 1) { |
627 | perror("failed to collect number of CPUs\n"); | ||
628 | return -1; | ||
629 | } | ||
630 | |||
631 | if (!system_wide && no_inherit && !cpu_list) { | ||
632 | open_counters(-1); | ||
627 | } else { | 633 | } else { |
628 | nr_cpus = read_cpu_map(); | ||
629 | for (i = 0; i < nr_cpus; i++) | 634 | for (i = 0; i < nr_cpus; i++) |
630 | open_counters(cpumap[i]); | 635 | open_counters(cpumap[i]); |
631 | } | 636 | } |
@@ -704,7 +709,7 @@ static int __cmd_record(int argc, const char **argv) | |||
704 | if (perf_guest) | 709 | if (perf_guest) |
705 | perf_session__process_machines(session, event__synthesize_guest_os); | 710 | perf_session__process_machines(session, event__synthesize_guest_os); |
706 | 711 | ||
707 | if (!system_wide && profile_cpu == -1) | 712 | if (!system_wide && cpu_list) |
708 | event__synthesize_thread(target_tid, process_synthesized_event, | 713 | event__synthesize_thread(target_tid, process_synthesized_event, |
709 | session); | 714 | session); |
710 | else | 715 | else |
@@ -794,8 +799,8 @@ static const struct option options[] = { | |||
794 | "system-wide collection from all CPUs"), | 799 | "system-wide collection from all CPUs"), |
795 | OPT_BOOLEAN('A', "append", &append_file, | 800 | OPT_BOOLEAN('A', "append", &append_file, |
796 | "append to the output file to do incremental profiling"), | 801 | "append to the output file to do incremental profiling"), |
797 | OPT_INTEGER('C', "profile_cpu", &profile_cpu, | 802 | OPT_STRING('C', "cpu", &cpu_list, "cpu", |
798 | "CPU to profile on"), | 803 | "list of cpus to monitor"), |
799 | OPT_BOOLEAN('f', "force", &force, | 804 | OPT_BOOLEAN('f', "force", &force, |
800 | "overwrite existing data file (deprecated)"), | 805 | "overwrite existing data file (deprecated)"), |
801 | OPT_U64('c', "count", &user_interval, "event period to sample"), | 806 | OPT_U64('c', "count", &user_interval, "event period to sample"), |
@@ -825,7 +830,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
825 | argc = parse_options(argc, argv, options, record_usage, | 830 | argc = parse_options(argc, argv, options, record_usage, |
826 | PARSE_OPT_STOP_AT_NON_OPTION); | 831 | PARSE_OPT_STOP_AT_NON_OPTION); |
827 | if (!argc && target_pid == -1 && target_tid == -1 && | 832 | if (!argc && target_pid == -1 && target_tid == -1 && |
828 | !system_wide && profile_cpu == -1) | 833 | !system_wide && !cpu_list) |
829 | usage_with_options(record_usage, options); | 834 | usage_with_options(record_usage, options); |
830 | 835 | ||
831 | if (force && append_file) { | 836 | if (force && append_file) { |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 9a39ca3c3ac4..a6b4d44f9502 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -69,7 +69,7 @@ static struct perf_event_attr default_attrs[] = { | |||
69 | }; | 69 | }; |
70 | 70 | ||
71 | static bool system_wide = false; | 71 | static bool system_wide = false; |
72 | static unsigned int nr_cpus = 0; | 72 | static int nr_cpus = 0; |
73 | static int run_idx = 0; | 73 | static int run_idx = 0; |
74 | 74 | ||
75 | static int run_count = 1; | 75 | static int run_count = 1; |
@@ -82,6 +82,7 @@ static int thread_num = 0; | |||
82 | static pid_t child_pid = -1; | 82 | static pid_t child_pid = -1; |
83 | static bool null_run = false; | 83 | static bool null_run = false; |
84 | static bool big_num = false; | 84 | static bool big_num = false; |
85 | static const char *cpu_list; | ||
85 | 86 | ||
86 | 87 | ||
87 | static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; | 88 | static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; |
@@ -158,7 +159,7 @@ static int create_perf_stat_counter(int counter) | |||
158 | PERF_FORMAT_TOTAL_TIME_RUNNING; | 159 | PERF_FORMAT_TOTAL_TIME_RUNNING; |
159 | 160 | ||
160 | if (system_wide) { | 161 | if (system_wide) { |
161 | unsigned int cpu; | 162 | int cpu; |
162 | 163 | ||
163 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 164 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
164 | fd[cpu][counter][0] = sys_perf_event_open(attr, | 165 | fd[cpu][counter][0] = sys_perf_event_open(attr, |
@@ -208,7 +209,7 @@ static inline int nsec_counter(int counter) | |||
208 | static void read_counter(int counter) | 209 | static void read_counter(int counter) |
209 | { | 210 | { |
210 | u64 count[3], single_count[3]; | 211 | u64 count[3], single_count[3]; |
211 | unsigned int cpu; | 212 | int cpu; |
212 | size_t res, nv; | 213 | size_t res, nv; |
213 | int scaled; | 214 | int scaled; |
214 | int i, thread; | 215 | int i, thread; |
@@ -542,6 +543,8 @@ static const struct option options[] = { | |||
542 | "null run - dont start any counters"), | 543 | "null run - dont start any counters"), |
543 | OPT_BOOLEAN('B', "big-num", &big_num, | 544 | OPT_BOOLEAN('B', "big-num", &big_num, |
544 | "print large numbers with thousands\' separators"), | 545 | "print large numbers with thousands\' separators"), |
546 | OPT_STRING('C', "cpu", &cpu_list, "cpu", | ||
547 | "list of cpus to monitor in system-wide"), | ||
545 | OPT_END() | 548 | OPT_END() |
546 | }; | 549 | }; |
547 | 550 | ||
@@ -566,10 +569,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
566 | } | 569 | } |
567 | 570 | ||
568 | if (system_wide) | 571 | if (system_wide) |
569 | nr_cpus = read_cpu_map(); | 572 | nr_cpus = read_cpu_map(cpu_list); |
570 | else | 573 | else |
571 | nr_cpus = 1; | 574 | nr_cpus = 1; |
572 | 575 | ||
576 | if (nr_cpus < 1) | ||
577 | usage_with_options(stat_usage, options); | ||
578 | |||
573 | if (target_pid != -1) { | 579 | if (target_pid != -1) { |
574 | target_tid = target_pid; | 580 | target_tid = target_pid; |
575 | thread_num = find_all_tid(target_pid, &all_tids); | 581 | thread_num = find_all_tid(target_pid, &all_tids); |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index a66f4272b994..45014ef11059 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -102,6 +102,7 @@ struct sym_entry *sym_filter_entry_sched = NULL; | |||
102 | static int sym_pcnt_filter = 5; | 102 | static int sym_pcnt_filter = 5; |
103 | static int sym_counter = 0; | 103 | static int sym_counter = 0; |
104 | static int display_weighted = -1; | 104 | static int display_weighted = -1; |
105 | static const char *cpu_list; | ||
105 | 106 | ||
106 | /* | 107 | /* |
107 | * Symbols | 108 | * Symbols |
@@ -1351,8 +1352,8 @@ static const struct option options[] = { | |||
1351 | "profile events on existing thread id"), | 1352 | "profile events on existing thread id"), |
1352 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 1353 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
1353 | "system-wide collection from all CPUs"), | 1354 | "system-wide collection from all CPUs"), |
1354 | OPT_INTEGER('C', "CPU", &profile_cpu, | 1355 | OPT_STRING('C', "cpu", &cpu_list, "cpu", |
1355 | "CPU to profile on"), | 1356 | "list of cpus to monitor"), |
1356 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 1357 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
1357 | "file", "vmlinux pathname"), | 1358 | "file", "vmlinux pathname"), |
1358 | OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, | 1359 | OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, |
@@ -1428,10 +1429,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1428 | return -ENOMEM; | 1429 | return -ENOMEM; |
1429 | 1430 | ||
1430 | /* CPU and PID are mutually exclusive */ | 1431 | /* CPU and PID are mutually exclusive */ |
1431 | if (target_tid > 0 && profile_cpu != -1) { | 1432 | if (target_tid > 0 && cpu_list) { |
1432 | printf("WARNING: PID switch overriding CPU\n"); | 1433 | printf("WARNING: PID switch overriding CPU\n"); |
1433 | sleep(1); | 1434 | sleep(1); |
1434 | profile_cpu = -1; | 1435 | cpu_list = NULL; |
1435 | } | 1436 | } |
1436 | 1437 | ||
1437 | if (!nr_counters) | 1438 | if (!nr_counters) |
@@ -1469,10 +1470,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1469 | attrs[counter].sample_period = default_interval; | 1470 | attrs[counter].sample_period = default_interval; |
1470 | } | 1471 | } |
1471 | 1472 | ||
1472 | if (target_tid != -1 || profile_cpu != -1) | 1473 | if (target_tid != -1) |
1473 | nr_cpus = 1; | 1474 | nr_cpus = 1; |
1474 | else | 1475 | else |
1475 | nr_cpus = read_cpu_map(); | 1476 | nr_cpus = read_cpu_map(cpu_list); |
1477 | |||
1478 | if (nr_cpus < 1) | ||
1479 | usage_with_options(top_usage, options); | ||
1476 | 1480 | ||
1477 | get_term_dimensions(&winsize); | 1481 | get_term_dimensions(&winsize); |
1478 | if (print_entries == 0) { | 1482 | if (print_entries == 0) { |
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 4e01490e51e5..0f9b8d7a7d7e 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c | |||
@@ -20,7 +20,7 @@ static int default_cpu_map(void) | |||
20 | return nr_cpus; | 20 | return nr_cpus; |
21 | } | 21 | } |
22 | 22 | ||
23 | int read_cpu_map(void) | 23 | static int read_all_cpu_map(void) |
24 | { | 24 | { |
25 | FILE *onlnf; | 25 | FILE *onlnf; |
26 | int nr_cpus = 0; | 26 | int nr_cpus = 0; |
@@ -57,3 +57,58 @@ int read_cpu_map(void) | |||
57 | 57 | ||
58 | return default_cpu_map(); | 58 | return default_cpu_map(); |
59 | } | 59 | } |
60 | |||
61 | int read_cpu_map(const char *cpu_list) | ||
62 | { | ||
63 | unsigned long start_cpu, end_cpu = 0; | ||
64 | char *p = NULL; | ||
65 | int i, nr_cpus = 0; | ||
66 | |||
67 | if (!cpu_list) | ||
68 | return read_all_cpu_map(); | ||
69 | |||
70 | if (!isdigit(*cpu_list)) | ||
71 | goto invalid; | ||
72 | |||
73 | while (isdigit(*cpu_list)) { | ||
74 | p = NULL; | ||
75 | start_cpu = strtoul(cpu_list, &p, 0); | ||
76 | if (start_cpu >= INT_MAX | ||
77 | || (*p != '\0' && *p != ',' && *p != '-')) | ||
78 | goto invalid; | ||
79 | |||
80 | if (*p == '-') { | ||
81 | cpu_list = ++p; | ||
82 | p = NULL; | ||
83 | end_cpu = strtoul(cpu_list, &p, 0); | ||
84 | |||
85 | if (end_cpu >= INT_MAX || (*p != '\0' && *p != ',')) | ||
86 | goto invalid; | ||
87 | |||
88 | if (end_cpu < start_cpu) | ||
89 | goto invalid; | ||
90 | } else { | ||
91 | end_cpu = start_cpu; | ||
92 | } | ||
93 | |||
94 | for (; start_cpu <= end_cpu; start_cpu++) { | ||
95 | /* check for duplicates */ | ||
96 | for (i = 0; i < nr_cpus; i++) | ||
97 | if (cpumap[i] == (int)start_cpu) | ||
98 | goto invalid; | ||
99 | |||
100 | assert(nr_cpus < MAX_NR_CPUS); | ||
101 | cpumap[nr_cpus++] = (int)start_cpu; | ||
102 | } | ||
103 | if (*p) | ||
104 | ++p; | ||
105 | |||
106 | cpu_list = p; | ||
107 | } | ||
108 | if (nr_cpus > 0) | ||
109 | return nr_cpus; | ||
110 | |||
111 | return default_cpu_map(); | ||
112 | invalid: | ||
113 | return -1; | ||
114 | } | ||
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 86c78bb33098..3e60f56e490e 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #ifndef __PERF_CPUMAP_H | 1 | #ifndef __PERF_CPUMAP_H |
2 | #define __PERF_CPUMAP_H | 2 | #define __PERF_CPUMAP_H |
3 | 3 | ||
4 | extern int read_cpu_map(void); | 4 | extern int read_cpu_map(const char *cpu_list); |
5 | extern int cpumap[]; | 5 | extern int cpumap[]; |
6 | 6 | ||
7 | #endif /* __PERF_CPUMAP_H */ | 7 | #endif /* __PERF_CPUMAP_H */ |