Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 48290609 authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo
Browse files

perf evsel: Introduce per cpu and per thread open helpers



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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent c52b12ed
Loading
Loading
Loading
Loading
+26 −58
Original line number Diff line number Diff line
@@ -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[] = {
@@ -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;
	if (system_wide)
		return perf_evsel__open_per_cpu(evsel, nr_cpus, cpumap);

		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;
			}
		}
	}

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

/*
@@ -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;

@@ -349,20 +313,24 @@ 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)
	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 " : "");
		die("Not all events could be opened.\n");
			} 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;
		}
	}

	/*
	 * Enable counters and exec the command:
+52 −0
Original line number Diff line number Diff line
#include "evsel.h"
#include "../perf.h"
#include "util.h"

#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
@@ -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 −0
Original line number Diff line number Diff line
@@ -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)