blob: f5006958f8daaaacfff7e787a4f25282551e887c [file] [log] [blame]
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -02001#include "evsel.h"
Arnaldo Carvalho de Melo70082dd2011-01-12 17:03:24 -02002#include "evlist.h"
Arnaldo Carvalho de Melo48290602011-01-03 17:48:12 -02003#include "../perf.h"
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -02004#include "util.h"
Arnaldo Carvalho de Melo86bd5e82011-01-03 23:09:46 -02005#include "cpumap.h"
6#include "thread.h"
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -02007
Arnaldo Carvalho de Melo70082dd2011-01-12 17:03:24 -02008#include <unistd.h>
9#include <sys/mman.h>
10
Arnaldo Carvalho de Meloc52b12e2011-01-03 17:45:52 -020011#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
12
Lin Ming23a2f3a2011-01-07 11:11:09 +080013struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -020014{
15 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
16
17 if (evsel != NULL) {
18 evsel->idx = idx;
Lin Ming23a2f3a2011-01-07 11:11:09 +080019 evsel->attr = *attr;
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -020020 INIT_LIST_HEAD(&evsel->node);
21 }
22
23 return evsel;
24}
25
26int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
27{
28 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
29 return evsel->fd != NULL ? 0 : -ENOMEM;
30}
31
Arnaldo Carvalho de Meloc52b12e2011-01-03 17:45:52 -020032int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
33{
34 evsel->counts = zalloc((sizeof(*evsel->counts) +
35 (ncpus * sizeof(struct perf_counts_values))));
36 return evsel->counts != NULL ? 0 : -ENOMEM;
37}
38
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -020039void perf_evsel__free_fd(struct perf_evsel *evsel)
40{
41 xyarray__delete(evsel->fd);
42 evsel->fd = NULL;
43}
44
Arnaldo Carvalho de Meloc52b12e2011-01-03 17:45:52 -020045void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
46{
47 int cpu, thread;
48
49 for (cpu = 0; cpu < ncpus; cpu++)
50 for (thread = 0; thread < nthreads; ++thread) {
51 close(FD(evsel, cpu, thread));
52 FD(evsel, cpu, thread) = -1;
53 }
54}
55
Arnaldo Carvalho de Melo70082dd2011-01-12 17:03:24 -020056void perf_evsel__munmap(struct perf_evsel *evsel, int ncpus, int nthreads)
57{
58 struct perf_mmap *mm;
59 int cpu, thread;
60
61 for (cpu = 0; cpu < ncpus; cpu++)
62 for (thread = 0; thread < nthreads; ++thread) {
63 mm = xyarray__entry(evsel->mmap, cpu, thread);
64 if (mm->base != NULL) {
65 munmap(mm->base, evsel->mmap_len);
66 mm->base = NULL;
67 }
68 }
69}
70
71int perf_evsel__alloc_mmap(struct perf_evsel *evsel, int ncpus, int nthreads)
72{
73 evsel->mmap = xyarray__new(ncpus, nthreads, sizeof(struct perf_mmap));
74 return evsel->mmap != NULL ? 0 : -ENOMEM;
75}
76
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -020077void perf_evsel__delete(struct perf_evsel *evsel)
78{
79 assert(list_empty(&evsel->node));
80 xyarray__delete(evsel->fd);
Arnaldo Carvalho de Melo70082dd2011-01-12 17:03:24 -020081 xyarray__delete(evsel->mmap);
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -020082 free(evsel);
83}
Arnaldo Carvalho de Meloc52b12e2011-01-03 17:45:52 -020084
85int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
86 int cpu, int thread, bool scale)
87{
88 struct perf_counts_values count;
89 size_t nv = scale ? 3 : 1;
90
91 if (FD(evsel, cpu, thread) < 0)
92 return -EINVAL;
93
Arnaldo Carvalho de Melo4eed11d2011-01-04 00:13:17 -020094 if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
95 return -ENOMEM;
96
Arnaldo Carvalho de Meloc52b12e2011-01-03 17:45:52 -020097 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
98 return -errno;
99
100 if (scale) {
101 if (count.run == 0)
102 count.val = 0;
103 else if (count.run < count.ena)
104 count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
105 } else
106 count.ena = count.run = 0;
107
108 evsel->counts->cpu[cpu] = count;
109 return 0;
110}
111
112int __perf_evsel__read(struct perf_evsel *evsel,
113 int ncpus, int nthreads, bool scale)
114{
115 size_t nv = scale ? 3 : 1;
116 int cpu, thread;
117 struct perf_counts_values *aggr = &evsel->counts->aggr, count;
118
119 aggr->val = 0;
120
121 for (cpu = 0; cpu < ncpus; cpu++) {
122 for (thread = 0; thread < nthreads; thread++) {
123 if (FD(evsel, cpu, thread) < 0)
124 continue;
125
126 if (readn(FD(evsel, cpu, thread),
127 &count, nv * sizeof(u64)) < 0)
128 return -errno;
129
130 aggr->val += count.val;
131 if (scale) {
132 aggr->ena += count.ena;
133 aggr->run += count.run;
134 }
135 }
136 }
137
138 evsel->counts->scaled = 0;
139 if (scale) {
140 if (aggr->run == 0) {
141 evsel->counts->scaled = -1;
142 aggr->val = 0;
143 return 0;
144 }
145
146 if (aggr->run < aggr->ena) {
147 evsel->counts->scaled = 1;
148 aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
149 }
150 } else
151 aggr->ena = aggr->run = 0;
152
153 return 0;
154}
Arnaldo Carvalho de Melo48290602011-01-03 17:48:12 -0200155
Arnaldo Carvalho de Melo02522082011-01-04 11:55:27 -0200156static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
Arnaldo Carvalho de Melo9d04f172011-01-12 00:08:18 -0200157 struct thread_map *threads, bool group, bool inherit)
Arnaldo Carvalho de Melo48290602011-01-03 17:48:12 -0200158{
Arnaldo Carvalho de Melo02522082011-01-04 11:55:27 -0200159 int cpu, thread;
Arnaldo Carvalho de Melo48290602011-01-03 17:48:12 -0200160
Arnaldo Carvalho de Melo02522082011-01-04 11:55:27 -0200161 if (evsel->fd == NULL &&
162 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
Arnaldo Carvalho de Melo4eed11d2011-01-04 00:13:17 -0200163 return -1;
164
Arnaldo Carvalho de Melo86bd5e82011-01-03 23:09:46 -0200165 for (cpu = 0; cpu < cpus->nr; cpu++) {
Arnaldo Carvalho de Melof08199d2011-01-11 23:42:19 -0200166 int group_fd = -1;
167
Arnaldo Carvalho de Melo9d04f172011-01-12 00:08:18 -0200168 evsel->attr.inherit = (cpus->map[cpu] < 0) && inherit;
169
Arnaldo Carvalho de Melo02522082011-01-04 11:55:27 -0200170 for (thread = 0; thread < threads->nr; thread++) {
171 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
172 threads->map[thread],
Arnaldo Carvalho de Melof08199d2011-01-11 23:42:19 -0200173 cpus->map[cpu],
174 group_fd, 0);
Arnaldo Carvalho de Melo02522082011-01-04 11:55:27 -0200175 if (FD(evsel, cpu, thread) < 0)
176 goto out_close;
Arnaldo Carvalho de Melof08199d2011-01-11 23:42:19 -0200177
178 if (group && group_fd == -1)
179 group_fd = FD(evsel, cpu, thread);
Arnaldo Carvalho de Melo02522082011-01-04 11:55:27 -0200180 }
Arnaldo Carvalho de Melo48290602011-01-03 17:48:12 -0200181 }
182
183 return 0;
184
185out_close:
Arnaldo Carvalho de Melo02522082011-01-04 11:55:27 -0200186 do {
187 while (--thread >= 0) {
188 close(FD(evsel, cpu, thread));
189 FD(evsel, cpu, thread) = -1;
190 }
191 thread = threads->nr;
192 } while (--cpu >= 0);
Arnaldo Carvalho de Melo48290602011-01-03 17:48:12 -0200193 return -1;
194}
195
Arnaldo Carvalho de Melo02522082011-01-04 11:55:27 -0200196static struct {
197 struct cpu_map map;
198 int cpus[1];
199} empty_cpu_map = {
200 .map.nr = 1,
201 .cpus = { -1, },
202};
203
204static struct {
205 struct thread_map map;
206 int threads[1];
207} empty_thread_map = {
208 .map.nr = 1,
209 .threads = { -1, },
210};
211
Arnaldo Carvalho de Melof08199d2011-01-11 23:42:19 -0200212int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
Arnaldo Carvalho de Melo9d04f172011-01-12 00:08:18 -0200213 struct thread_map *threads, bool group, bool inherit)
Arnaldo Carvalho de Melo02522082011-01-04 11:55:27 -0200214{
Arnaldo Carvalho de Melo02522082011-01-04 11:55:27 -0200215 if (cpus == NULL) {
216 /* Work around old compiler warnings about strict aliasing */
217 cpus = &empty_cpu_map.map;
218 }
219
220 if (threads == NULL)
221 threads = &empty_thread_map.map;
222
Arnaldo Carvalho de Melo9d04f172011-01-12 00:08:18 -0200223 return __perf_evsel__open(evsel, cpus, threads, group, inherit);
Arnaldo Carvalho de Melo02522082011-01-04 11:55:27 -0200224}
225
Arnaldo Carvalho de Melof08199d2011-01-11 23:42:19 -0200226int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
Arnaldo Carvalho de Melo9d04f172011-01-12 00:08:18 -0200227 struct cpu_map *cpus, bool group, bool inherit)
Arnaldo Carvalho de Melo02522082011-01-04 11:55:27 -0200228{
Arnaldo Carvalho de Melo9d04f172011-01-12 00:08:18 -0200229 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, inherit);
Arnaldo Carvalho de Melo02522082011-01-04 11:55:27 -0200230}
231
Arnaldo Carvalho de Melof08199d2011-01-11 23:42:19 -0200232int perf_evsel__open_per_thread(struct perf_evsel *evsel,
Arnaldo Carvalho de Melo9d04f172011-01-12 00:08:18 -0200233 struct thread_map *threads, bool group, bool inherit)
Arnaldo Carvalho de Melo48290602011-01-03 17:48:12 -0200234{
Arnaldo Carvalho de Melo9d04f172011-01-12 00:08:18 -0200235 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, inherit);
Arnaldo Carvalho de Melo48290602011-01-03 17:48:12 -0200236}
Arnaldo Carvalho de Melo70082dd2011-01-12 17:03:24 -0200237
238int perf_evsel__mmap(struct perf_evsel *evsel, struct cpu_map *cpus,
239 struct thread_map *threads, int pages,
240 struct perf_evlist *evlist)
241{
242 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
243 int mask = pages * page_size - 1, cpu;
244 struct perf_mmap *mm;
245 int thread;
246
247 if (evsel->mmap == NULL &&
248 perf_evsel__alloc_mmap(evsel, cpus->nr, threads->nr) < 0)
249 return -ENOMEM;
250
251 evsel->mmap_len = (pages + 1) * page_size;
252
253 for (cpu = 0; cpu < cpus->nr; cpu++) {
254 for (thread = 0; thread < threads->nr; thread++) {
255 mm = xyarray__entry(evsel->mmap, cpu, thread);
256 mm->prev = 0;
257 mm->mask = mask;
258 mm->base = mmap(NULL, evsel->mmap_len, PROT_READ,
259 MAP_SHARED, FD(evsel, cpu, thread), 0);
260 if (mm->base == MAP_FAILED)
261 goto out_unmap;
262
263 if (evlist != NULL)
264 perf_evlist__add_pollfd(evlist, FD(evsel, cpu, thread));
265 }
266 }
267
268 return 0;
269
270out_unmap:
271 do {
272 while (--thread >= 0) {
273 mm = xyarray__entry(evsel->mmap, cpu, thread);
274 munmap(mm->base, evsel->mmap_len);
275 mm->base = NULL;
276 }
277 thread = threads->nr;
278 } while (--cpu >= 0);
279
280 return -1;
281}