Skip to content

Commit

Permalink
perf stat: Change and clean up sys_perf_event_open error handling
Browse files Browse the repository at this point in the history
This patch makes several changes to "perf stat":

- "perf stat" will no longer go ahead and run the application when one or
more of the specified events could not be opened.
- Use error() and die() instead of pr_err() so that the output is more
consistent with "perf top" and "perf record".
- Handle permission errors in a more robust way, and in a similar way to
"perf record" and "perf top".

In addition, the sys_perf_event_open() error handling of "perf top" and "perf
record" is made more consistent and adds the following phrase when an event
doesn't open (with something ther than an access or permission error):

"/bin/dmesg may provide additional information."

This is added because kernel code doesn't have a good way of expressing
detailed errors to user space, so its only avenue is to use printk's.  However,
many users may not think of looking at dmesg to find out why an event is being
rejected.

Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <fweisbec@gmail.com>
Cc: Ian Munsie <ianmunsi@au1.ibm.com>
Cc: Michael Ellerman <michaele@au1.ibm.com>
LKML-Reference: <1290217044-26293-1-git-send-email-cjashfor@linux.vnet.ibm.com>
Signed-off-by: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Corey Ashford authored and Arnaldo Carvalho de Melo committed Nov 20, 2010
1 parent 4aafd3f commit d9cf837
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 17 deletions.
2 changes: 1 addition & 1 deletion tools/perf/builtin-record.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ static void create_counter(int counter, int cpu)
goto try_again;
}
printf("\n");
error("perfcounter syscall returned with %d (%s)\n",
error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
fd[nr_cpu][counter][thread_index], strerror(err));

#if defined(__i386__) || defined(__x86_64__)
Expand Down
38 changes: 24 additions & 14 deletions tools/perf/builtin-stat.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,9 @@ struct stats walltime_nsecs_stats;
attrs[counter].config == PERF_COUNT_##c)

#define ERR_PERF_OPEN \
"Error: counter %d, sys_perf_event_open() syscall returned with %d (%s)\n"
"counter %d, sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information."

static int create_perf_stat_counter(int counter)
static int create_perf_stat_counter(int counter, bool *perm_err)
{
struct perf_event_attr *attr = attrs + counter;
int thread;
Expand All @@ -171,11 +171,14 @@ static int create_perf_stat_counter(int counter)
for (cpu = 0; cpu < nr_cpus; cpu++) {
fd[cpu][counter][0] = sys_perf_event_open(attr,
-1, cpumap[cpu], -1, 0);
if (fd[cpu][counter][0] < 0)
pr_debug(ERR_PERF_OPEN, counter,
if (fd[cpu][counter][0] < 0) {
if (errno == EPERM || errno == EACCES)
*perm_err = true;
error(ERR_PERF_OPEN, counter,
fd[cpu][counter][0], strerror(errno));
else
} else {
++ncreated;
}
}
} else {
attr->inherit = !no_inherit;
Expand All @@ -186,12 +189,15 @@ static int create_perf_stat_counter(int counter)
for (thread = 0; thread < thread_num; thread++) {
fd[0][counter][thread] = sys_perf_event_open(attr,
all_tids[thread], -1, -1, 0);
if (fd[0][counter][thread] < 0)
pr_debug(ERR_PERF_OPEN, counter,
if (fd[0][counter][thread] < 0) {
if (errno == EPERM || errno == EACCES)
*perm_err = true;
error(ERR_PERF_OPEN, counter,
fd[0][counter][thread],
strerror(errno));
else
} else {
++ncreated;
}
}
}

Expand Down Expand Up @@ -332,6 +338,7 @@ static int run_perf_stat(int argc __used, const char **argv)
int status = 0;
int counter, ncreated = 0;
int child_ready_pipe[2], go_pipe[2];
bool perm_err = false;
const bool forks = (argc > 0);
char buf;

Expand Down Expand Up @@ -390,12 +397,15 @@ static int run_perf_stat(int argc __used, const char **argv)
}

for (counter = 0; counter < nr_counters; counter++)
ncreated += create_perf_stat_counter(counter);

if (ncreated == 0) {
pr_err("No permission to collect %sstats.\n"
"Consider tweaking /proc/sys/kernel/perf_event_paranoid.\n",
system_wide ? "system-wide " : "");
ncreated += create_perf_stat_counter(counter, &perm_err);

if (ncreated < nr_counters) {
if (perm_err)
error("You may not have permission to collect %sstats.\n"
"\t Consider tweaking"
" /proc/sys/kernel/perf_event_paranoid or running as root.",
system_wide ? "system-wide " : "");
die("Not all events could be opened.\n");
if (child_pid != -1)
kill(child_pid, SIGTERM);
return -1;
Expand Down
6 changes: 4 additions & 2 deletions tools/perf/builtin-top.c
Original file line number Diff line number Diff line change
Expand Up @@ -1214,7 +1214,9 @@ static void start_counter(int i, int counter)
int err = errno;

if (err == EPERM || err == EACCES)
die("No permission - are you root?\n");
die("Permission error - are you root?\n"
"\t Consider tweaking"
" /proc/sys/kernel/perf_event_paranoid.\n");
/*
* If it's cycles then fall back to hrtimer
* based cpu-clock-tick sw counter, which
Expand All @@ -1231,7 +1233,7 @@ static void start_counter(int i, int counter)
goto try_again;
}
printf("\n");
error("perfcounter syscall returned with %d (%s)\n",
error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
fd[i][counter][thread_index], strerror(err));
die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
exit(-1);
Expand Down

0 comments on commit d9cf837

Please sign in to comment.