aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/evsel.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/evsel.c')
-rw-r--r--tools/perf/util/evsel.c318
1 files changed, 301 insertions, 17 deletions
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index f5cfed60af98..76ab553637d6 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1,20 +1,33 @@
1#include "evsel.h" 1#include "evsel.h"
2#include "evlist.h"
2#include "../perf.h" 3#include "../perf.h"
3#include "util.h" 4#include "util.h"
4#include "cpumap.h" 5#include "cpumap.h"
5#include "thread.h" 6#include "thread_map.h"
7
8#include <unistd.h>
9#include <sys/mman.h>
10
11#include <linux/bitops.h>
12#include <linux/hash.h>
6 13
7#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 14#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
15#define SID(e, x, y) xyarray__entry(e->id, x, y)
16
17void perf_evsel__init(struct perf_evsel *evsel,
18 struct perf_event_attr *attr, int idx)
19{
20 evsel->idx = idx;
21 evsel->attr = *attr;
22 INIT_LIST_HEAD(&evsel->node);
23}
8 24
9struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 25struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
10{ 26{
11 struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 27 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
12 28
13 if (evsel != NULL) { 29 if (evsel != NULL)
14 evsel->idx = idx; 30 perf_evsel__init(evsel, attr, idx);
15 evsel->attr = *attr;
16 INIT_LIST_HEAD(&evsel->node);
17 }
18 31
19 return evsel; 32 return evsel;
20} 33}
@@ -25,6 +38,12 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
25 return evsel->fd != NULL ? 0 : -ENOMEM; 38 return evsel->fd != NULL ? 0 : -ENOMEM;
26} 39}
27 40
41int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
42{
43 evsel->id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
44 return evsel->id != NULL ? 0 : -ENOMEM;
45}
46
28int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) 47int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
29{ 48{
30 evsel->counts = zalloc((sizeof(*evsel->counts) + 49 evsel->counts = zalloc((sizeof(*evsel->counts) +
@@ -38,6 +57,12 @@ void perf_evsel__free_fd(struct perf_evsel *evsel)
38 evsel->fd = NULL; 57 evsel->fd = NULL;
39} 58}
40 59
60void perf_evsel__free_id(struct perf_evsel *evsel)
61{
62 xyarray__delete(evsel->id);
63 evsel->id = NULL;
64}
65
41void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 66void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
42{ 67{
43 int cpu, thread; 68 int cpu, thread;
@@ -49,10 +74,34 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
49 } 74 }
50} 75}
51 76
52void perf_evsel__delete(struct perf_evsel *evsel) 77void perf_evlist__munmap(struct perf_evlist *evlist, int ncpus)
78{
79 int cpu;
80
81 for (cpu = 0; cpu < ncpus; cpu++) {
82 if (evlist->mmap[cpu].base != NULL) {
83 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
84 evlist->mmap[cpu].base = NULL;
85 }
86 }
87}
88
89int perf_evlist__alloc_mmap(struct perf_evlist *evlist, int ncpus)
90{
91 evlist->mmap = zalloc(ncpus * sizeof(struct perf_mmap));
92 return evlist->mmap != NULL ? 0 : -ENOMEM;
93}
94
95void perf_evsel__exit(struct perf_evsel *evsel)
53{ 96{
54 assert(list_empty(&evsel->node)); 97 assert(list_empty(&evsel->node));
55 xyarray__delete(evsel->fd); 98 xyarray__delete(evsel->fd);
99 xyarray__delete(evsel->id);
100}
101
102void perf_evsel__delete(struct perf_evsel *evsel)
103{
104 perf_evsel__exit(evsel);
56 free(evsel); 105 free(evsel);
57} 106}
58 107
@@ -128,7 +177,7 @@ int __perf_evsel__read(struct perf_evsel *evsel,
128} 177}
129 178
130static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 179static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
131 struct thread_map *threads) 180 struct thread_map *threads, bool group, bool inherit)
132{ 181{
133 int cpu, thread; 182 int cpu, thread;
134 183
@@ -137,12 +186,20 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
137 return -1; 186 return -1;
138 187
139 for (cpu = 0; cpu < cpus->nr; cpu++) { 188 for (cpu = 0; cpu < cpus->nr; cpu++) {
189 int group_fd = -1;
190
191 evsel->attr.inherit = (cpus->map[cpu] < 0) && inherit;
192
140 for (thread = 0; thread < threads->nr; thread++) { 193 for (thread = 0; thread < threads->nr; thread++) {
141 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, 194 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
142 threads->map[thread], 195 threads->map[thread],
143 cpus->map[cpu], -1, 0); 196 cpus->map[cpu],
197 group_fd, 0);
144 if (FD(evsel, cpu, thread) < 0) 198 if (FD(evsel, cpu, thread) < 0)
145 goto out_close; 199 goto out_close;
200
201 if (group && group_fd == -1)
202 group_fd = FD(evsel, cpu, thread);
146 } 203 }
147 } 204 }
148 205
@@ -175,10 +232,9 @@ static struct {
175 .threads = { -1, }, 232 .threads = { -1, },
176}; 233};
177 234
178int perf_evsel__open(struct perf_evsel *evsel, 235int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
179 struct cpu_map *cpus, struct thread_map *threads) 236 struct thread_map *threads, bool group, bool inherit)
180{ 237{
181
182 if (cpus == NULL) { 238 if (cpus == NULL) {
183 /* Work around old compiler warnings about strict aliasing */ 239 /* Work around old compiler warnings about strict aliasing */
184 cpus = &empty_cpu_map.map; 240 cpus = &empty_cpu_map.map;
@@ -187,15 +243,243 @@ int perf_evsel__open(struct perf_evsel *evsel,
187 if (threads == NULL) 243 if (threads == NULL)
188 threads = &empty_thread_map.map; 244 threads = &empty_thread_map.map;
189 245
190 return __perf_evsel__open(evsel, cpus, threads); 246 return __perf_evsel__open(evsel, cpus, threads, group, inherit);
247}
248
249int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
250 struct cpu_map *cpus, bool group, bool inherit)
251{
252 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, inherit);
253}
254
255int perf_evsel__open_per_thread(struct perf_evsel *evsel,
256 struct thread_map *threads, bool group, bool inherit)
257{
258 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, inherit);
259}
260
261static int __perf_evlist__mmap(struct perf_evlist *evlist, int cpu, int prot,
262 int mask, int fd)
263{
264 evlist->mmap[cpu].prev = 0;
265 evlist->mmap[cpu].mask = mask;
266 evlist->mmap[cpu].base = mmap(NULL, evlist->mmap_len, prot,
267 MAP_SHARED, fd, 0);
268 if (evlist->mmap[cpu].base == MAP_FAILED)
269 return -1;
270
271 perf_evlist__add_pollfd(evlist, fd);
272 return 0;
273}
274
275static int perf_evlist__id_hash(struct perf_evlist *evlist, struct perf_evsel *evsel,
276 int cpu, int thread, int fd)
277{
278 struct perf_sample_id *sid;
279 u64 read_data[4] = { 0, };
280 int hash, id_idx = 1; /* The first entry is the counter value */
281
282 if (!(evsel->attr.read_format & PERF_FORMAT_ID) ||
283 read(fd, &read_data, sizeof(read_data)) == -1)
284 return -1;
285
286 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
287 ++id_idx;
288 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
289 ++id_idx;
290
291 sid = SID(evsel, cpu, thread);
292 sid->id = read_data[id_idx];
293 sid->evsel = evsel;
294 hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS);
295 hlist_add_head(&sid->node, &evlist->heads[hash]);
296 return 0;
297}
298
299/** perf_evlist__mmap - Create per cpu maps to receive events
300 *
301 * @evlist - list of events
302 * @cpus - cpu map being monitored
303 * @threads - threads map being monitored
304 * @pages - map length in pages
305 * @overwrite - overwrite older events?
306 *
307 * If overwrite is false the user needs to signal event consuption using:
308 *
309 * struct perf_mmap *m = &evlist->mmap[cpu];
310 * unsigned int head = perf_mmap__read_head(m);
311 *
312 * perf_mmap__write_tail(m, head)
313 */
314int perf_evlist__mmap(struct perf_evlist *evlist, struct cpu_map *cpus,
315 struct thread_map *threads, int pages, bool overwrite)
316{
317 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
318 int mask = pages * page_size - 1, cpu;
319 struct perf_evsel *first_evsel, *evsel;
320 int thread, prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
321
322 if (evlist->mmap == NULL &&
323 perf_evlist__alloc_mmap(evlist, cpus->nr) < 0)
324 return -ENOMEM;
325
326 if (evlist->pollfd == NULL &&
327 perf_evlist__alloc_pollfd(evlist, cpus->nr, threads->nr) < 0)
328 return -ENOMEM;
329
330 evlist->mmap_len = (pages + 1) * page_size;
331 first_evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
332
333 list_for_each_entry(evsel, &evlist->entries, node) {
334 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
335 evsel->id == NULL &&
336 perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0)
337 return -ENOMEM;
338
339 for (cpu = 0; cpu < cpus->nr; cpu++) {
340 for (thread = 0; thread < threads->nr; thread++) {
341 int fd = FD(evsel, cpu, thread);
342
343 if (evsel->idx || thread) {
344 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT,
345 FD(first_evsel, cpu, 0)) != 0)
346 goto out_unmap;
347 } else if (__perf_evlist__mmap(evlist, cpu, prot, mask, fd) < 0)
348 goto out_unmap;
349
350 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
351 perf_evlist__id_hash(evlist, evsel, cpu, thread, fd) < 0)
352 goto out_unmap;
353 }
354 }
355 }
356
357 return 0;
358
359out_unmap:
360 for (cpu = 0; cpu < cpus->nr; cpu++) {
361 if (evlist->mmap[cpu].base != NULL) {
362 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
363 evlist->mmap[cpu].base = NULL;
364 }
365 }
366 return -1;
191} 367}
192 368
193int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus) 369static int event__parse_id_sample(const event_t *event, u64 type,
370 struct sample_data *sample)
194{ 371{
195 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map); 372 const u64 *array = event->sample.array;
373
374 array += ((event->header.size -
375 sizeof(event->header)) / sizeof(u64)) - 1;
376
377 if (type & PERF_SAMPLE_CPU) {
378 u32 *p = (u32 *)array;
379 sample->cpu = *p;
380 array--;
381 }
382
383 if (type & PERF_SAMPLE_STREAM_ID) {
384 sample->stream_id = *array;
385 array--;
386 }
387
388 if (type & PERF_SAMPLE_ID) {
389 sample->id = *array;
390 array--;
391 }
392
393 if (type & PERF_SAMPLE_TIME) {
394 sample->time = *array;
395 array--;
396 }
397
398 if (type & PERF_SAMPLE_TID) {
399 u32 *p = (u32 *)array;
400 sample->pid = p[0];
401 sample->tid = p[1];
402 }
403
404 return 0;
196} 405}
197 406
198int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads) 407int event__parse_sample(const event_t *event, u64 type, bool sample_id_all,
408 struct sample_data *data)
199{ 409{
200 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads); 410 const u64 *array;
411
412 data->cpu = data->pid = data->tid = -1;
413 data->stream_id = data->id = data->time = -1ULL;
414
415 if (event->header.type != PERF_RECORD_SAMPLE) {
416 if (!sample_id_all)
417 return 0;
418 return event__parse_id_sample(event, type, data);
419 }
420
421 array = event->sample.array;
422
423 if (type & PERF_SAMPLE_IP) {
424 data->ip = event->ip.ip;
425 array++;
426 }
427
428 if (type & PERF_SAMPLE_TID) {
429 u32 *p = (u32 *)array;
430 data->pid = p[0];
431 data->tid = p[1];
432 array++;
433 }
434
435 if (type & PERF_SAMPLE_TIME) {
436 data->time = *array;
437 array++;
438 }
439
440 if (type & PERF_SAMPLE_ADDR) {
441 data->addr = *array;
442 array++;
443 }
444
445 data->id = -1ULL;
446 if (type & PERF_SAMPLE_ID) {
447 data->id = *array;
448 array++;
449 }
450
451 if (type & PERF_SAMPLE_STREAM_ID) {
452 data->stream_id = *array;
453 array++;
454 }
455
456 if (type & PERF_SAMPLE_CPU) {
457 u32 *p = (u32 *)array;
458 data->cpu = *p;
459 array++;
460 }
461
462 if (type & PERF_SAMPLE_PERIOD) {
463 data->period = *array;
464 array++;
465 }
466
467 if (type & PERF_SAMPLE_READ) {
468 fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n");
469 return -1;
470 }
471
472 if (type & PERF_SAMPLE_CALLCHAIN) {
473 data->callchain = (struct ip_callchain *)array;
474 array += 1 + data->callchain->nr;
475 }
476
477 if (type & PERF_SAMPLE_RAW) {
478 u32 *p = (u32 *)array;
479 data->raw_size = *p;
480 p++;
481 data->raw_data = p;
482 }
483
484 return 0;
201} 485}