Skip to content

Commit

Permalink
perf evsel: Introduce per cpu and per thread open helpers
Browse files Browse the repository at this point in the history
Abstracting away the loops needed to create the various event fd handlers.

The users have to pass a confiruged perf->evsel.attr field, which is already
usable after perf_evsel__new (constructor) time, using defaults.

Comes out of the ad-hoc routines in builtin-stat, that now uses it.

Fixed a small silly bug where we were die()ing before killing our
children, dysfunctional family this one 8-)

Cc: Frederic 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: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Arnaldo Carvalho de Melo committed Jan 4, 2011
1 parent c52b12e commit 4829060
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 58 deletions.
84 changes: 26 additions & 58 deletions tools/perf/builtin-stat.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@
#include <math.h>
#include <locale.h>

#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))

#define DEFAULT_SEPARATOR " "

static struct perf_event_attr default_attrs[] = {
Expand Down Expand Up @@ -160,56 +158,24 @@ struct stats runtime_cycles_stats[MAX_NR_CPUS];
struct stats runtime_branches_stats[MAX_NR_CPUS];
struct stats walltime_nsecs_stats;

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

static int create_perf_stat_counter(struct perf_evsel *evsel, bool *perm_err)
static int create_perf_stat_counter(struct perf_evsel *evsel)
{
struct perf_event_attr *attr = &evsel->attr;
int thread;
int ncreated = 0;

if (scale)
attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
PERF_FORMAT_TOTAL_TIME_RUNNING;

if (system_wide) {
int cpu;

for (cpu = 0; cpu < nr_cpus; cpu++) {
FD(evsel, cpu, 0) = sys_perf_event_open(attr,
-1, cpumap[cpu], -1, 0);
if (FD(evsel, cpu, 0) < 0) {
if (errno == EPERM || errno == EACCES)
*perm_err = true;
error(ERR_PERF_OPEN, evsel->idx,
FD(evsel, cpu, 0), strerror(errno));
} else {
++ncreated;
}
}
} else {
attr->inherit = !no_inherit;
if (target_pid == -1 && target_tid == -1) {
attr->disabled = 1;
attr->enable_on_exec = 1;
}
for (thread = 0; thread < thread_num; thread++) {
FD(evsel, 0, thread) = sys_perf_event_open(attr,
all_tids[thread], -1, -1, 0);
if (FD(evsel, 0, thread) < 0) {
if (errno == EPERM || errno == EACCES)
*perm_err = true;
error(ERR_PERF_OPEN, evsel->idx,
FD(evsel, 0, thread),
strerror(errno));
} else {
++ncreated;
}
}
if (system_wide)
return perf_evsel__open_per_cpu(evsel, nr_cpus, cpumap);

attr->inherit = !no_inherit;
if (target_pid == -1 && target_tid == -1) {
attr->disabled = 1;
attr->enable_on_exec = 1;
}

return ncreated;
return perf_evsel__open_per_thread(evsel, thread_num, all_tids);
}

/*
Expand Down Expand Up @@ -289,9 +255,7 @@ static int run_perf_stat(int argc __used, const char **argv)
unsigned long long t0, t1;
struct perf_evsel *counter;
int status = 0;
int 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 @@ -349,19 +313,23 @@ static int run_perf_stat(int argc __used, const char **argv)
close(child_ready_pipe[0]);
}

list_for_each_entry(counter, &evsel_list, node)
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;
list_for_each_entry(counter, &evsel_list, node) {
if (create_perf_stat_counter(counter) < 0) {
if (errno == -EPERM || errno == -EACCES) {
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 " : "");
} else {
error("open_counter returned with %d (%s). "
"/bin/dmesg may provide additional information.\n",
errno, strerror(errno));
}
if (child_pid != -1)
kill(child_pid, SIGTERM);
die("Not all events could be opened.\n");
return -1;
}
}

/*
Expand Down
52 changes: 52 additions & 0 deletions tools/perf/util/evsel.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "evsel.h"
#include "../perf.h"
#include "util.h"

#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
Expand Down Expand Up @@ -121,3 +122,54 @@ int __perf_evsel__read(struct perf_evsel *evsel,

return 0;
}

int perf_evsel__open_per_cpu(struct perf_evsel *evsel, int ncpus, int *cpu_map)
{
int cpu;

for (cpu = 0; cpu < ncpus; cpu++) {
FD(evsel, cpu, 0) = sys_perf_event_open(&evsel->attr, -1,
cpu_map[cpu], -1, 0);
if (FD(evsel, cpu, 0) < 0)
goto out_close;
}

return 0;

out_close:
while (--cpu >= 0) {
close(FD(evsel, cpu, 0));
FD(evsel, cpu, 0) = -1;
}
return -1;
}

int perf_evsel__open_per_thread(struct perf_evsel *evsel, int nthreads, int *thread_map)
{
int thread;

for (thread = 0; thread < nthreads; thread++) {
FD(evsel, 0, thread) = sys_perf_event_open(&evsel->attr,
thread_map[thread], -1, -1, 0);
if (FD(evsel, 0, thread) < 0)
goto out_close;
}

return 0;

out_close:
while (--thread >= 0) {
close(FD(evsel, 0, thread));
FD(evsel, 0, thread) = -1;
}
return -1;
}

int perf_evsel__open(struct perf_evsel *evsel, int ncpus, int nthreads,
int *cpu_map, int *thread_map)
{
if (nthreads < 0)
return perf_evsel__open_per_cpu(evsel, ncpus, cpu_map);

return perf_evsel__open_per_thread(evsel, nthreads, thread_map);
}
5 changes: 5 additions & 0 deletions tools/perf/util/evsel.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
void perf_evsel__free_fd(struct perf_evsel *evsel);
void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);

int perf_evsel__open_per_cpu(struct perf_evsel *evsel, int ncpus, int *cpu_map);
int perf_evsel__open_per_thread(struct perf_evsel *evsel, int nthreads, int *thread_map);
int perf_evsel__open(struct perf_evsel *evsel, int ncpus, int nthreads,
int *cpu_map, int *thread_map);

#define perf_evsel__match(evsel, t, c) \
(evsel->attr.type == PERF_TYPE_##t && \
evsel->attr.config == PERF_COUNT_##c)
Expand Down

0 comments on commit 4829060

Please sign in to comment.