Commit c45c6ea2e5c57960dc67e00294c2b78e9540c007

Authored by Stephane Eranian
Committed by Arnaldo Carvalho de Melo
1 parent 761844b9c6

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>

Showing 8 changed files with 110 additions and 24 deletions Side-by-side Diff

tools/perf/Documentation/perf-record.txt
... ... @@ -103,6 +103,13 @@
103 103 --raw-samples::
104 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 113 SEE ALSO
107 114 --------
108 115 linkperf:perf-stat[1], linkperf:perf-list[1]
tools/perf/Documentation/perf-stat.txt
... ... @@ -46,6 +46,13 @@
46 46 -B::
47 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 56 EXAMPLES
50 57 --------
51 58  
tools/perf/Documentation/perf-top.txt
... ... @@ -25,9 +25,11 @@
25 25 --count=<count>::
26 26 Event period to sample.
27 27  
28   --C <cpu>::
29   ---CPU=<cpu>::
30   - CPU to profile.
  28 +-C <cpu-list>::
  29 +--cpu=<cpu>::
  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 34 -d <seconds>::
33 35 --delay=<seconds>::
tools/perf/builtin-record.c
... ... @@ -49,7 +49,6 @@
49 49 static int realtime_prio = 0;
50 50 static bool raw_samples = false;
51 51 static bool system_wide = false;
52   -static int profile_cpu = -1;
53 52 static pid_t target_pid = -1;
54 53 static pid_t target_tid = -1;
55 54 static pid_t *all_tids = NULL;
... ... @@ -74,6 +73,7 @@
74 73 static off_t post_processing_offset;
75 74  
76 75 static struct perf_session *session;
  76 +static const char *cpu_list;
77 77  
78 78 struct mmap_data {
79 79 int counter;
... ... @@ -300,7 +300,7 @@
300 300 die("Permission error - are you root?\n"
301 301 "\t Consider tweaking"
302 302 " /proc/sys/kernel/perf_event_paranoid.\n");
303   - else if (err == ENODEV && profile_cpu != -1) {
  303 + else if (err == ENODEV && cpu_list) {
304 304 die("No such device - did you specify"
305 305 " an out-of-range profile CPU?\n");
306 306 }
307 307  
... ... @@ -622,10 +622,15 @@
622 622 close(child_ready_pipe[0]);
623 623 }
624 624  
625   - if ((!system_wide && no_inherit) || profile_cpu != -1) {
626   - open_counters(profile_cpu);
  625 + nr_cpus = read_cpu_map(cpu_list);
  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 633 } else {
628   - nr_cpus = read_cpu_map();
629 634 for (i = 0; i < nr_cpus; i++)
630 635 open_counters(cpumap[i]);
631 636 }
... ... @@ -704,7 +709,7 @@
704 709 if (perf_guest)
705 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 713 event__synthesize_thread(target_tid, process_synthesized_event,
709 714 session);
710 715 else
... ... @@ -794,8 +799,8 @@
794 799 "system-wide collection from all CPUs"),
795 800 OPT_BOOLEAN('A', "append", &append_file,
796 801 "append to the output file to do incremental profiling"),
797   - OPT_INTEGER('C', "profile_cpu", &profile_cpu,
798   - "CPU to profile on"),
  802 + OPT_STRING('C', "cpu", &cpu_list, "cpu",
  803 + "list of cpus to monitor"),
799 804 OPT_BOOLEAN('f', "force", &force,
800 805 "overwrite existing data file (deprecated)"),
801 806 OPT_U64('c', "count", &user_interval, "event period to sample"),
... ... @@ -825,7 +830,7 @@
825 830 argc = parse_options(argc, argv, options, record_usage,
826 831 PARSE_OPT_STOP_AT_NON_OPTION);
827 832 if (!argc && target_pid == -1 && target_tid == -1 &&
828   - !system_wide && profile_cpu == -1)
  833 + !system_wide && !cpu_list)
829 834 usage_with_options(record_usage, options);
830 835  
831 836 if (force && append_file) {
tools/perf/builtin-stat.c
... ... @@ -69,7 +69,7 @@
69 69 };
70 70  
71 71 static bool system_wide = false;
72   -static unsigned int nr_cpus = 0;
  72 +static int nr_cpus = 0;
73 73 static int run_idx = 0;
74 74  
75 75 static int run_count = 1;
... ... @@ -82,6 +82,7 @@
82 82 static pid_t child_pid = -1;
83 83 static bool null_run = false;
84 84 static bool big_num = false;
  85 +static const char *cpu_list;
85 86  
86 87  
87 88 static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
... ... @@ -158,7 +159,7 @@
158 159 PERF_FORMAT_TOTAL_TIME_RUNNING;
159 160  
160 161 if (system_wide) {
161   - unsigned int cpu;
  162 + int cpu;
162 163  
163 164 for (cpu = 0; cpu < nr_cpus; cpu++) {
164 165 fd[cpu][counter][0] = sys_perf_event_open(attr,
... ... @@ -208,7 +209,7 @@
208 209 static void read_counter(int counter)
209 210 {
210 211 u64 count[3], single_count[3];
211   - unsigned int cpu;
  212 + int cpu;
212 213 size_t res, nv;
213 214 int scaled;
214 215 int i, thread;
... ... @@ -542,6 +543,8 @@
542 543 "null run - dont start any counters"),
543 544 OPT_BOOLEAN('B', "big-num", &big_num,
544 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 548 OPT_END()
546 549 };
547 550  
548 551  
... ... @@ -566,9 +569,12 @@
566 569 }
567 570  
568 571 if (system_wide)
569   - nr_cpus = read_cpu_map();
  572 + nr_cpus = read_cpu_map(cpu_list);
570 573 else
571 574 nr_cpus = 1;
  575 +
  576 + if (nr_cpus < 1)
  577 + usage_with_options(stat_usage, options);
572 578  
573 579 if (target_pid != -1) {
574 580 target_tid = target_pid;
tools/perf/builtin-top.c
... ... @@ -102,6 +102,7 @@
102 102 static int sym_pcnt_filter = 5;
103 103 static int sym_counter = 0;
104 104 static int display_weighted = -1;
  105 +static const char *cpu_list;
105 106  
106 107 /*
107 108 * Symbols
... ... @@ -1351,8 +1352,8 @@
1351 1352 "profile events on existing thread id"),
1352 1353 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1353 1354 "system-wide collection from all CPUs"),
1354   - OPT_INTEGER('C', "CPU", &profile_cpu,
1355   - "CPU to profile on"),
  1355 + OPT_STRING('C', "cpu", &cpu_list, "cpu",
  1356 + "list of cpus to monitor"),
1356 1357 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1357 1358 "file", "vmlinux pathname"),
1358 1359 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols,
1359 1360  
... ... @@ -1428,10 +1429,10 @@
1428 1429 return -ENOMEM;
1429 1430  
1430 1431 /* CPU and PID are mutually exclusive */
1431   - if (target_tid > 0 && profile_cpu != -1) {
  1432 + if (target_tid > 0 && cpu_list) {
1432 1433 printf("WARNING: PID switch overriding CPU\n");
1433 1434 sleep(1);
1434   - profile_cpu = -1;
  1435 + cpu_list = NULL;
1435 1436 }
1436 1437  
1437 1438 if (!nr_counters)
1438 1439  
... ... @@ -1469,10 +1470,13 @@
1469 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 1474 nr_cpus = 1;
1474 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 1481 get_term_dimensions(&winsize);
1478 1482 if (print_entries == 0) {
tools/perf/util/cpumap.c
... ... @@ -20,7 +20,7 @@
20 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 25 FILE *onlnf;
26 26 int nr_cpus = 0;
... ... @@ -56,5 +56,60 @@
56 56 return nr_cpus;
57 57  
58 58 return default_cpu_map();
  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;
59 114 }
tools/perf/util/cpumap.h
1 1 #ifndef __PERF_CPUMAP_H
2 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 5 extern int cpumap[];
6 6  
7 7 #endif /* __PERF_CPUMAP_H */