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 /tools/perf | |
| 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>
Diffstat (limited to 'tools/perf')
| -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 */ |
