evsel.c 3.7 KB
Newer Older
1
#include "evsel.h"
2
#include "../perf.h"
3
#include "util.h"
4 5
#include "cpumap.h"
#include "thread.h"
6

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

9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
struct perf_evsel *perf_evsel__new(u32 type, u64 config, int idx)
{
	struct perf_evsel *evsel = zalloc(sizeof(*evsel));

	if (evsel != NULL) {
		evsel->idx	   = idx;
		evsel->attr.type   = type;
		evsel->attr.config = config;
		INIT_LIST_HEAD(&evsel->node);
	}

	return evsel;
}

int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
{
	evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
	return evsel->fd != NULL ? 0 : -ENOMEM;
}

29 30 31 32 33 34 35
int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
{
	evsel->counts = zalloc((sizeof(*evsel->counts) +
				(ncpus * sizeof(struct perf_counts_values))));
	return evsel->counts != NULL ? 0 : -ENOMEM;
}

36 37 38 39 40 41
void perf_evsel__free_fd(struct perf_evsel *evsel)
{
	xyarray__delete(evsel->fd);
	evsel->fd = NULL;
}

42 43 44 45 46 47 48 49 50 51 52
void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
{
	int cpu, thread;

	for (cpu = 0; cpu < ncpus; cpu++)
		for (thread = 0; thread < nthreads; ++thread) {
			close(FD(evsel, cpu, thread));
			FD(evsel, cpu, thread) = -1;
		}
}

53 54 55 56 57 58
void perf_evsel__delete(struct perf_evsel *evsel)
{
	assert(list_empty(&evsel->node));
	xyarray__delete(evsel->fd);
	free(evsel);
}
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126

int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
			      int cpu, int thread, bool scale)
{
	struct perf_counts_values count;
	size_t nv = scale ? 3 : 1;

	if (FD(evsel, cpu, thread) < 0)
		return -EINVAL;

	if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
		return -errno;

	if (scale) {
		if (count.run == 0)
			count.val = 0;
		else if (count.run < count.ena)
			count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
	} else
		count.ena = count.run = 0;

	evsel->counts->cpu[cpu] = count;
	return 0;
}

int __perf_evsel__read(struct perf_evsel *evsel,
		       int ncpus, int nthreads, bool scale)
{
	size_t nv = scale ? 3 : 1;
	int cpu, thread;
	struct perf_counts_values *aggr = &evsel->counts->aggr, count;

	aggr->val = 0;

	for (cpu = 0; cpu < ncpus; cpu++) {
		for (thread = 0; thread < nthreads; thread++) {
			if (FD(evsel, cpu, thread) < 0)
				continue;

			if (readn(FD(evsel, cpu, thread),
				  &count, nv * sizeof(u64)) < 0)
				return -errno;

			aggr->val += count.val;
			if (scale) {
				aggr->ena += count.ena;
				aggr->run += count.run;
			}
		}
	}

	evsel->counts->scaled = 0;
	if (scale) {
		if (aggr->run == 0) {
			evsel->counts->scaled = -1;
			aggr->val = 0;
			return 0;
		}

		if (aggr->run < aggr->ena) {
			evsel->counts->scaled = 1;
			aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
		}
	} else
		aggr->ena = aggr->run = 0;

	return 0;
}
127

128
int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus)
129 130 131
{
	int cpu;

132
	for (cpu = 0; cpu < cpus->nr; cpu++) {
133
		FD(evsel, cpu, 0) = sys_perf_event_open(&evsel->attr, -1,
134
							cpus->map[cpu], -1, 0);
135 136 137 138 139 140 141 142 143 144 145 146 147 148
		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;
}

149
int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads)
150 151 152
{
	int thread;

153
	for (thread = 0; thread < threads->nr; thread++) {
154
		FD(evsel, 0, thread) = sys_perf_event_open(&evsel->attr,
155
							   threads->map[thread], -1, -1, 0);
156 157 158 159 160 161 162 163 164 165 166 167 168 169
		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;
}

170 171
int perf_evsel__open(struct perf_evsel *evsel, 
		     struct cpu_map *cpus, struct thread_map *threads)
172
{
173 174
	if (threads == NULL)
		return perf_evsel__open_per_cpu(evsel, cpus);
175

176
	return perf_evsel__open_per_thread(evsel, threads);
177
}