mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-17 18:56:24 +00:00
perf record: Fall back to cpu-clock-ticks if no PMU
On architectures/CPUs without PMU support but with perfcounters enabled 'perf record' currently fails because it cannot create a cycle based hw-perfcounter. Fall back to the cpu-clock-tick sw-perfcounter in this case, which is hrtimer based and will always work (as long as perfcounters are enabled). Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
716c69feca
commit
3da297a60f
@ -37,6 +37,7 @@ static pid_t target_pid = -1;
|
|||||||
static int inherit = 1;
|
static int inherit = 1;
|
||||||
static int force = 0;
|
static int force = 0;
|
||||||
static int append_file = 0;
|
static int append_file = 0;
|
||||||
|
static int verbose = 0;
|
||||||
|
|
||||||
static long samples;
|
static long samples;
|
||||||
static struct timeval last_read;
|
static struct timeval last_read;
|
||||||
@ -349,17 +350,35 @@ static void create_counter(int counter, int cpu, pid_t pid)
|
|||||||
|
|
||||||
track = 0; /* only the first counter needs these */
|
track = 0; /* only the first counter needs these */
|
||||||
|
|
||||||
|
try_again:
|
||||||
fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0);
|
fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0);
|
||||||
|
|
||||||
if (fd[nr_cpu][counter] < 0) {
|
if (fd[nr_cpu][counter] < 0) {
|
||||||
int err = errno;
|
int err = errno;
|
||||||
|
|
||||||
error("syscall returned with %d (%s)\n",
|
if (verbose)
|
||||||
|
error("sys_perf_counter_open() syscall returned with %d (%s)\n",
|
||||||
fd[nr_cpu][counter], strerror(err));
|
fd[nr_cpu][counter], strerror(err));
|
||||||
if (err == EPERM)
|
if (err == EPERM)
|
||||||
printf("Are you root?\n");
|
die("Permission error - are you root?\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If it's cycles then fall back to hrtimer
|
||||||
|
* based cpu-clock-tick sw counter, which
|
||||||
|
* is always available even if no PMU support:
|
||||||
|
*/
|
||||||
|
if (attr->type == PERF_TYPE_HARDWARE
|
||||||
|
&& attr->config == PERF_COUNT_CPU_CYCLES) {
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
warning(" ... trying to fall back to cpu-clock-ticks\n");
|
||||||
|
attr->type = PERF_TYPE_SOFTWARE;
|
||||||
|
attr->config = PERF_COUNT_CPU_CLOCK;
|
||||||
|
goto try_again;
|
||||||
|
}
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(fd[nr_cpu][counter] >= 0);
|
assert(fd[nr_cpu][counter] >= 0);
|
||||||
fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
|
fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
|
||||||
|
|
||||||
@ -519,6 +538,8 @@ static const struct option options[] = {
|
|||||||
"profile at this frequency"),
|
"profile at this frequency"),
|
||||||
OPT_INTEGER('m', "mmap-pages", &mmap_pages,
|
OPT_INTEGER('m', "mmap-pages", &mmap_pages,
|
||||||
"number of mmap data pages"),
|
"number of mmap data pages"),
|
||||||
|
OPT_BOOLEAN('v', "verbose", &verbose,
|
||||||
|
"be more verbose (show counter open errors, etc)"),
|
||||||
OPT_END()
|
OPT_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -65,6 +65,7 @@ static int group = 0;
|
|||||||
static unsigned int page_size;
|
static unsigned int page_size;
|
||||||
static unsigned int mmap_pages = 16;
|
static unsigned int mmap_pages = 16;
|
||||||
static int freq = 0;
|
static int freq = 0;
|
||||||
|
static int verbose = 0;
|
||||||
|
|
||||||
static char *sym_filter;
|
static char *sym_filter;
|
||||||
static unsigned long filter_start;
|
static unsigned long filter_start;
|
||||||
@ -550,11 +551,12 @@ try_again:
|
|||||||
if (fd[i][counter] < 0) {
|
if (fd[i][counter] < 0) {
|
||||||
int err = errno;
|
int err = errno;
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
error("sys_perf_counter_open() syscall returned with %d (%s)\n",
|
error("sys_perf_counter_open() syscall returned with %d (%s)\n",
|
||||||
fd[i][counter], strerror(err));
|
fd[i][counter], strerror(err));
|
||||||
|
|
||||||
if (err == EPERM)
|
if (err == EPERM)
|
||||||
die(" No permission - are you root?\n");
|
die("No permission - are you root?\n");
|
||||||
/*
|
/*
|
||||||
* If it's cycles then fall back to hrtimer
|
* If it's cycles then fall back to hrtimer
|
||||||
* based cpu-clock-tick sw counter, which
|
* based cpu-clock-tick sw counter, which
|
||||||
@ -563,7 +565,9 @@ try_again:
|
|||||||
if (attr->type == PERF_TYPE_HARDWARE
|
if (attr->type == PERF_TYPE_HARDWARE
|
||||||
&& attr->config == PERF_COUNT_CPU_CYCLES) {
|
&& attr->config == PERF_COUNT_CPU_CYCLES) {
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
warning(" ... trying to fall back to cpu-clock-ticks\n");
|
warning(" ... trying to fall back to cpu-clock-ticks\n");
|
||||||
|
|
||||||
attr->type = PERF_TYPE_SOFTWARE;
|
attr->type = PERF_TYPE_SOFTWARE;
|
||||||
attr->config = PERF_COUNT_CPU_CLOCK;
|
attr->config = PERF_COUNT_CPU_CLOCK;
|
||||||
goto try_again;
|
goto try_again;
|
||||||
@ -673,6 +677,8 @@ static const struct option options[] = {
|
|||||||
"profile at this frequency"),
|
"profile at this frequency"),
|
||||||
OPT_INTEGER('E', "entries", &print_entries,
|
OPT_INTEGER('E', "entries", &print_entries,
|
||||||
"display this many functions"),
|
"display this many functions"),
|
||||||
|
OPT_BOOLEAN('v', "verbose", &verbose,
|
||||||
|
"be more verbose (show counter open errors, etc)"),
|
||||||
OPT_END()
|
OPT_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user