mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
parent
761844b9c6
commit
c45c6ea2e5
|
@ -103,6 +103,13 @@ OPTIONS
|
|||
--raw-samples::
|
||||
Collect raw sample records from all opened counters (default for tracepoint counters).
|
||||
|
||||
-C::
|
||||
--cpu::
|
||||
Collect samples only on the list of cpus provided. Multiple CPUs can be provided as a
|
||||
comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
|
||||
In per-thread mode with inheritance mode on (default), samples are captured only when
|
||||
the thread executes on the designated CPUs. Default is to monitor all CPUs.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkperf:perf-stat[1], linkperf:perf-list[1]
|
||||
|
|
|
@ -46,6 +46,13 @@ OPTIONS
|
|||
-B::
|
||||
print large numbers with thousands' separators according to locale
|
||||
|
||||
-C::
|
||||
--cpu=::
|
||||
Count only on the list of cpus provided. Multiple CPUs can be provided as a
|
||||
comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
|
||||
In per-thread mode, this option is ignored. The -a option is still necessary
|
||||
to activate system-wide monitoring. Default is to count on all CPUs.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
|
|
|
@ -25,9 +25,11 @@ OPTIONS
|
|||
--count=<count>::
|
||||
Event period to sample.
|
||||
|
||||
-C <cpu>::
|
||||
--CPU=<cpu>::
|
||||
CPU to profile.
|
||||
-C <cpu-list>::
|
||||
--cpu=<cpu>::
|
||||
Monitor only on the list of cpus provided. Multiple CPUs can be provided as a
|
||||
comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
|
||||
Default is to monitor all CPUS.
|
||||
|
||||
-d <seconds>::
|
||||
--delay=<seconds>::
|
||||
|
|
|
@ -49,7 +49,6 @@ static int group = 0;
|
|||
static int realtime_prio = 0;
|
||||
static bool raw_samples = false;
|
||||
static bool system_wide = false;
|
||||
static int profile_cpu = -1;
|
||||
static pid_t target_pid = -1;
|
||||
static pid_t target_tid = -1;
|
||||
static pid_t *all_tids = NULL;
|
||||
|
@ -74,6 +73,7 @@ static int file_new = 1;
|
|||
static off_t post_processing_offset;
|
||||
|
||||
static struct perf_session *session;
|
||||
static const char *cpu_list;
|
||||
|
||||
struct mmap_data {
|
||||
int counter;
|
||||
|
@ -300,7 +300,7 @@ static void create_counter(int counter, int cpu)
|
|||
die("Permission error - are you root?\n"
|
||||
"\t Consider tweaking"
|
||||
" /proc/sys/kernel/perf_event_paranoid.\n");
|
||||
else if (err == ENODEV && profile_cpu != -1) {
|
||||
else if (err == ENODEV && cpu_list) {
|
||||
die("No such device - did you specify"
|
||||
" an out-of-range profile CPU?\n");
|
||||
}
|
||||
|
@ -622,10 +622,15 @@ static int __cmd_record(int argc, const char **argv)
|
|||
close(child_ready_pipe[0]);
|
||||
}
|
||||
|
||||
if ((!system_wide && no_inherit) || profile_cpu != -1) {
|
||||
open_counters(profile_cpu);
|
||||
nr_cpus = read_cpu_map(cpu_list);
|
||||
if (nr_cpus < 1) {
|
||||
perror("failed to collect number of CPUs\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!system_wide && no_inherit && !cpu_list) {
|
||||
open_counters(-1);
|
||||
} else {
|
||||
nr_cpus = read_cpu_map();
|
||||
for (i = 0; i < nr_cpus; i++)
|
||||
open_counters(cpumap[i]);
|
||||
}
|
||||
|
@ -704,7 +709,7 @@ static int __cmd_record(int argc, const char **argv)
|
|||
if (perf_guest)
|
||||
perf_session__process_machines(session, event__synthesize_guest_os);
|
||||
|
||||
if (!system_wide && profile_cpu == -1)
|
||||
if (!system_wide && cpu_list)
|
||||
event__synthesize_thread(target_tid, process_synthesized_event,
|
||||
session);
|
||||
else
|
||||
|
@ -794,8 +799,8 @@ static const struct option options[] = {
|
|||
"system-wide collection from all CPUs"),
|
||||
OPT_BOOLEAN('A', "append", &append_file,
|
||||
"append to the output file to do incremental profiling"),
|
||||
OPT_INTEGER('C', "profile_cpu", &profile_cpu,
|
||||
"CPU to profile on"),
|
||||
OPT_STRING('C', "cpu", &cpu_list, "cpu",
|
||||
"list of cpus to monitor"),
|
||||
OPT_BOOLEAN('f', "force", &force,
|
||||
"overwrite existing data file (deprecated)"),
|
||||
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)
|
|||
argc = parse_options(argc, argv, options, record_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
if (!argc && target_pid == -1 && target_tid == -1 &&
|
||||
!system_wide && profile_cpu == -1)
|
||||
!system_wide && !cpu_list)
|
||||
usage_with_options(record_usage, options);
|
||||
|
||||
if (force && append_file) {
|
||||
|
|
|
@ -69,7 +69,7 @@ static struct perf_event_attr default_attrs[] = {
|
|||
};
|
||||
|
||||
static bool system_wide = false;
|
||||
static unsigned int nr_cpus = 0;
|
||||
static int nr_cpus = 0;
|
||||
static int run_idx = 0;
|
||||
|
||||
static int run_count = 1;
|
||||
|
@ -82,6 +82,7 @@ static int thread_num = 0;
|
|||
static pid_t child_pid = -1;
|
||||
static bool null_run = false;
|
||||
static bool big_num = false;
|
||||
static const char *cpu_list;
|
||||
|
||||
|
||||
static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
|
||||
|
@ -158,7 +159,7 @@ static int create_perf_stat_counter(int counter)
|
|||
PERF_FORMAT_TOTAL_TIME_RUNNING;
|
||||
|
||||
if (system_wide) {
|
||||
unsigned int cpu;
|
||||
int cpu;
|
||||
|
||||
for (cpu = 0; cpu < nr_cpus; cpu++) {
|
||||
fd[cpu][counter][0] = sys_perf_event_open(attr,
|
||||
|
@ -208,7 +209,7 @@ static inline int nsec_counter(int counter)
|
|||
static void read_counter(int counter)
|
||||
{
|
||||
u64 count[3], single_count[3];
|
||||
unsigned int cpu;
|
||||
int cpu;
|
||||
size_t res, nv;
|
||||
int scaled;
|
||||
int i, thread;
|
||||
|
@ -542,6 +543,8 @@ static const struct option options[] = {
|
|||
"null run - dont start any counters"),
|
||||
OPT_BOOLEAN('B', "big-num", &big_num,
|
||||
"print large numbers with thousands\' separators"),
|
||||
OPT_STRING('C', "cpu", &cpu_list, "cpu",
|
||||
"list of cpus to monitor in system-wide"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
@ -566,10 +569,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
|
|||
}
|
||||
|
||||
if (system_wide)
|
||||
nr_cpus = read_cpu_map();
|
||||
nr_cpus = read_cpu_map(cpu_list);
|
||||
else
|
||||
nr_cpus = 1;
|
||||
|
||||
if (nr_cpus < 1)
|
||||
usage_with_options(stat_usage, options);
|
||||
|
||||
if (target_pid != -1) {
|
||||
target_tid = target_pid;
|
||||
thread_num = find_all_tid(target_pid, &all_tids);
|
||||
|
|
|
@ -102,6 +102,7 @@ struct sym_entry *sym_filter_entry_sched = NULL;
|
|||
static int sym_pcnt_filter = 5;
|
||||
static int sym_counter = 0;
|
||||
static int display_weighted = -1;
|
||||
static const char *cpu_list;
|
||||
|
||||
/*
|
||||
* Symbols
|
||||
|
@ -1351,8 +1352,8 @@ static const struct option options[] = {
|
|||
"profile events on existing thread id"),
|
||||
OPT_BOOLEAN('a', "all-cpus", &system_wide,
|
||||
"system-wide collection from all CPUs"),
|
||||
OPT_INTEGER('C', "CPU", &profile_cpu,
|
||||
"CPU to profile on"),
|
||||
OPT_STRING('C', "cpu", &cpu_list, "cpu",
|
||||
"list of cpus to monitor"),
|
||||
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
|
||||
"file", "vmlinux pathname"),
|
||||
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)
|
|||
return -ENOMEM;
|
||||
|
||||
/* CPU and PID are mutually exclusive */
|
||||
if (target_tid > 0 && profile_cpu != -1) {
|
||||
if (target_tid > 0 && cpu_list) {
|
||||
printf("WARNING: PID switch overriding CPU\n");
|
||||
sleep(1);
|
||||
profile_cpu = -1;
|
||||
cpu_list = NULL;
|
||||
}
|
||||
|
||||
if (!nr_counters)
|
||||
|
@ -1469,10 +1470,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
|
|||
attrs[counter].sample_period = default_interval;
|
||||
}
|
||||
|
||||
if (target_tid != -1 || profile_cpu != -1)
|
||||
if (target_tid != -1)
|
||||
nr_cpus = 1;
|
||||
else
|
||||
nr_cpus = read_cpu_map();
|
||||
nr_cpus = read_cpu_map(cpu_list);
|
||||
|
||||
if (nr_cpus < 1)
|
||||
usage_with_options(top_usage, options);
|
||||
|
||||
get_term_dimensions(&winsize);
|
||||
if (print_entries == 0) {
|
||||
|
|
|
@ -20,7 +20,7 @@ static int default_cpu_map(void)
|
|||
return nr_cpus;
|
||||
}
|
||||
|
||||
int read_cpu_map(void)
|
||||
static int read_all_cpu_map(void)
|
||||
{
|
||||
FILE *onlnf;
|
||||
int nr_cpus = 0;
|
||||
|
@ -57,3 +57,58 @@ int read_cpu_map(void)
|
|||
|
||||
return default_cpu_map();
|
||||
}
|
||||
|
||||
int read_cpu_map(const char *cpu_list)
|
||||
{
|
||||
unsigned long start_cpu, end_cpu = 0;
|
||||
char *p = NULL;
|
||||
int i, nr_cpus = 0;
|
||||
|
||||
if (!cpu_list)
|
||||
return read_all_cpu_map();
|
||||
|
||||
if (!isdigit(*cpu_list))
|
||||
goto invalid;
|
||||
|
||||
while (isdigit(*cpu_list)) {
|
||||
p = NULL;
|
||||
start_cpu = strtoul(cpu_list, &p, 0);
|
||||
if (start_cpu >= INT_MAX
|
||||
|| (*p != '\0' && *p != ',' && *p != '-'))
|
||||
goto invalid;
|
||||
|
||||
if (*p == '-') {
|
||||
cpu_list = ++p;
|
||||
p = NULL;
|
||||
end_cpu = strtoul(cpu_list, &p, 0);
|
||||
|
||||
if (end_cpu >= INT_MAX || (*p != '\0' && *p != ','))
|
||||
goto invalid;
|
||||
|
||||
if (end_cpu < start_cpu)
|
||||
goto invalid;
|
||||
} else {
|
||||
end_cpu = start_cpu;
|
||||
}
|
||||
|
||||
for (; start_cpu <= end_cpu; start_cpu++) {
|
||||
/* check for duplicates */
|
||||
for (i = 0; i < nr_cpus; i++)
|
||||
if (cpumap[i] == (int)start_cpu)
|
||||
goto invalid;
|
||||
|
||||
assert(nr_cpus < MAX_NR_CPUS);
|
||||
cpumap[nr_cpus++] = (int)start_cpu;
|
||||
}
|
||||
if (*p)
|
||||
++p;
|
||||
|
||||
cpu_list = p;
|
||||
}
|
||||
if (nr_cpus > 0)
|
||||
return nr_cpus;
|
||||
|
||||
return default_cpu_map();
|
||||
invalid:
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __PERF_CPUMAP_H
|
||||
#define __PERF_CPUMAP_H
|
||||
|
||||
extern int read_cpu_map(void);
|
||||
extern int read_cpu_map(const char *cpu_list);
|
||||
extern int cpumap[];
|
||||
|
||||
#endif /* __PERF_CPUMAP_H */
|
||||
|
|
Loading…
Reference in New Issue