]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - tools/perf/util/evsel.c
perf tools: Carry perf_event_attr bitfield throught different endians
[mirror_ubuntu-artful-kernel.git] / tools / perf / util / evsel.c
CommitLineData
f8a95309
ACM
1/*
2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Parts came from builtin-{top,stat,record}.c, see those files for further
5 * copyright notes.
6 *
7 * Released under the GPL v2. (and only v2, not any later version)
8 */
9
936be503
DA
10#include <byteswap.h>
11#include "asm/bug.h"
69aad6f1 12#include "evsel.h"
70082dd9 13#include "evlist.h"
69aad6f1 14#include "util.h"
86bd5e86 15#include "cpumap.h"
fd78260b 16#include "thread_map.h"
12864b31 17#include "target.h"
69aad6f1 18
c52b12ed 19#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
727ab04e 20#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
c52b12ed 21
c2a70653
ACM
22int __perf_evsel__sample_size(u64 sample_type)
23{
24 u64 mask = sample_type & PERF_SAMPLE_MASK;
25 int size = 0;
26 int i;
27
28 for (i = 0; i < 64; i++) {
29 if (mask & (1ULL << i))
30 size++;
31 }
32
33 size *= sizeof(u64);
34
35 return size;
36}
37
4bf9ce1b 38void hists__init(struct hists *hists)
0e2a5f10
ACM
39{
40 memset(hists, 0, sizeof(*hists));
41 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
42 hists->entries_in = &hists->entries_in_array[0];
43 hists->entries_collapsed = RB_ROOT;
44 hists->entries = RB_ROOT;
45 pthread_mutex_init(&hists->lock, NULL);
46}
47
ef1d1af2
ACM
48void perf_evsel__init(struct perf_evsel *evsel,
49 struct perf_event_attr *attr, int idx)
50{
51 evsel->idx = idx;
52 evsel->attr = *attr;
53 INIT_LIST_HEAD(&evsel->node);
1980c2eb 54 hists__init(&evsel->hists);
ef1d1af2
ACM
55}
56
23a2f3ab 57struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
69aad6f1
ACM
58{
59 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
60
ef1d1af2
ACM
61 if (evsel != NULL)
62 perf_evsel__init(evsel, attr, idx);
69aad6f1
ACM
63
64 return evsel;
65}
66
5090c6ae
NK
67void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
68 struct perf_evsel *first)
0f82ebc4
ACM
69{
70 struct perf_event_attr *attr = &evsel->attr;
71 int track = !evsel->idx; /* only the first counter needs these */
72
5e1c81d9 73 attr->disabled = 1;
808e1226 74 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
0f82ebc4
ACM
75 attr->inherit = !opts->no_inherit;
76 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
77 PERF_FORMAT_TOTAL_TIME_RUNNING |
78 PERF_FORMAT_ID;
79
80 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
81
82 /*
83 * We default some events to a 1 default interval. But keep
84 * it a weak assumption overridable by the user.
85 */
86 if (!attr->sample_period || (opts->user_freq != UINT_MAX &&
87 opts->user_interval != ULLONG_MAX)) {
88 if (opts->freq) {
89 attr->sample_type |= PERF_SAMPLE_PERIOD;
90 attr->freq = 1;
91 attr->sample_freq = opts->freq;
92 } else {
93 attr->sample_period = opts->default_interval;
94 }
95 }
96
97 if (opts->no_samples)
98 attr->sample_freq = 0;
99
100 if (opts->inherit_stat)
101 attr->inherit_stat = 1;
102
103 if (opts->sample_address) {
104 attr->sample_type |= PERF_SAMPLE_ADDR;
105 attr->mmap_data = track;
106 }
107
108 if (opts->call_graph)
109 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
110
e40ee742 111 if (perf_target__has_cpu(&opts->target))
0f82ebc4
ACM
112 attr->sample_type |= PERF_SAMPLE_CPU;
113
3e76ac78
AV
114 if (opts->period)
115 attr->sample_type |= PERF_SAMPLE_PERIOD;
116
808e1226 117 if (!opts->sample_id_all_missing &&
d67356e7 118 (opts->sample_time || !opts->no_inherit ||
aa22dd49 119 perf_target__has_cpu(&opts->target)))
0f82ebc4
ACM
120 attr->sample_type |= PERF_SAMPLE_TIME;
121
122 if (opts->raw_samples) {
123 attr->sample_type |= PERF_SAMPLE_TIME;
124 attr->sample_type |= PERF_SAMPLE_RAW;
125 attr->sample_type |= PERF_SAMPLE_CPU;
126 }
127
128 if (opts->no_delay) {
129 attr->watermark = 0;
130 attr->wakeup_events = 1;
131 }
bdfebd84
RAV
132 if (opts->branch_stack) {
133 attr->sample_type |= PERF_SAMPLE_BRANCH_STACK;
134 attr->branch_sample_type = opts->branch_stack;
135 }
0f82ebc4
ACM
136
137 attr->mmap = track;
138 attr->comm = track;
139
d67356e7
NK
140 if (perf_target__none(&opts->target) &&
141 (!opts->group || evsel == first)) {
0f82ebc4
ACM
142 attr->enable_on_exec = 1;
143 }
144}
145
69aad6f1
ACM
146int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
147{
4af4c955 148 int cpu, thread;
69aad6f1 149 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
4af4c955
DA
150
151 if (evsel->fd) {
152 for (cpu = 0; cpu < ncpus; cpu++) {
153 for (thread = 0; thread < nthreads; thread++) {
154 FD(evsel, cpu, thread) = -1;
155 }
156 }
157 }
158
69aad6f1
ACM
159 return evsel->fd != NULL ? 0 : -ENOMEM;
160}
161
70db7533
ACM
162int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
163{
a91e5431
ACM
164 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
165 if (evsel->sample_id == NULL)
166 return -ENOMEM;
167
168 evsel->id = zalloc(ncpus * nthreads * sizeof(u64));
169 if (evsel->id == NULL) {
170 xyarray__delete(evsel->sample_id);
171 evsel->sample_id = NULL;
172 return -ENOMEM;
173 }
174
175 return 0;
70db7533
ACM
176}
177
c52b12ed
ACM
178int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
179{
180 evsel->counts = zalloc((sizeof(*evsel->counts) +
181 (ncpus * sizeof(struct perf_counts_values))));
182 return evsel->counts != NULL ? 0 : -ENOMEM;
183}
184
69aad6f1
ACM
185void perf_evsel__free_fd(struct perf_evsel *evsel)
186{
187 xyarray__delete(evsel->fd);
188 evsel->fd = NULL;
189}
190
70db7533
ACM
191void perf_evsel__free_id(struct perf_evsel *evsel)
192{
a91e5431
ACM
193 xyarray__delete(evsel->sample_id);
194 evsel->sample_id = NULL;
195 free(evsel->id);
70db7533
ACM
196 evsel->id = NULL;
197}
198
c52b12ed
ACM
199void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
200{
201 int cpu, thread;
202
203 for (cpu = 0; cpu < ncpus; cpu++)
204 for (thread = 0; thread < nthreads; ++thread) {
205 close(FD(evsel, cpu, thread));
206 FD(evsel, cpu, thread) = -1;
207 }
208}
209
ef1d1af2 210void perf_evsel__exit(struct perf_evsel *evsel)
69aad6f1
ACM
211{
212 assert(list_empty(&evsel->node));
213 xyarray__delete(evsel->fd);
a91e5431
ACM
214 xyarray__delete(evsel->sample_id);
215 free(evsel->id);
ef1d1af2
ACM
216}
217
218void perf_evsel__delete(struct perf_evsel *evsel)
219{
220 perf_evsel__exit(evsel);
023695d9 221 close_cgroup(evsel->cgrp);
f0c55bcf 222 free(evsel->name);
69aad6f1
ACM
223 free(evsel);
224}
c52b12ed
ACM
225
226int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
227 int cpu, int thread, bool scale)
228{
229 struct perf_counts_values count;
230 size_t nv = scale ? 3 : 1;
231
232 if (FD(evsel, cpu, thread) < 0)
233 return -EINVAL;
234
4eed11d5
ACM
235 if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
236 return -ENOMEM;
237
c52b12ed
ACM
238 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
239 return -errno;
240
241 if (scale) {
242 if (count.run == 0)
243 count.val = 0;
244 else if (count.run < count.ena)
245 count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
246 } else
247 count.ena = count.run = 0;
248
249 evsel->counts->cpu[cpu] = count;
250 return 0;
251}
252
253int __perf_evsel__read(struct perf_evsel *evsel,
254 int ncpus, int nthreads, bool scale)
255{
256 size_t nv = scale ? 3 : 1;
257 int cpu, thread;
258 struct perf_counts_values *aggr = &evsel->counts->aggr, count;
259
52bcd994 260 aggr->val = aggr->ena = aggr->run = 0;
c52b12ed
ACM
261
262 for (cpu = 0; cpu < ncpus; cpu++) {
263 for (thread = 0; thread < nthreads; thread++) {
264 if (FD(evsel, cpu, thread) < 0)
265 continue;
266
267 if (readn(FD(evsel, cpu, thread),
268 &count, nv * sizeof(u64)) < 0)
269 return -errno;
270
271 aggr->val += count.val;
272 if (scale) {
273 aggr->ena += count.ena;
274 aggr->run += count.run;
275 }
276 }
277 }
278
279 evsel->counts->scaled = 0;
280 if (scale) {
281 if (aggr->run == 0) {
282 evsel->counts->scaled = -1;
283 aggr->val = 0;
284 return 0;
285 }
286
287 if (aggr->run < aggr->ena) {
288 evsel->counts->scaled = 1;
289 aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
290 }
291 } else
292 aggr->ena = aggr->run = 0;
293
294 return 0;
295}
48290609 296
0252208e 297static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
727ab04e
ACM
298 struct thread_map *threads, bool group,
299 struct xyarray *group_fds)
48290609 300{
0252208e 301 int cpu, thread;
023695d9 302 unsigned long flags = 0;
727ab04e 303 int pid = -1, err;
48290609 304
0252208e
ACM
305 if (evsel->fd == NULL &&
306 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
727ab04e 307 return -ENOMEM;
4eed11d5 308
023695d9
SE
309 if (evsel->cgrp) {
310 flags = PERF_FLAG_PID_CGROUP;
311 pid = evsel->cgrp->fd;
312 }
313
86bd5e86 314 for (cpu = 0; cpu < cpus->nr; cpu++) {
727ab04e 315 int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1;
9d04f178 316
0252208e 317 for (thread = 0; thread < threads->nr; thread++) {
023695d9
SE
318
319 if (!evsel->cgrp)
320 pid = threads->map[thread];
321
0252208e 322 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
023695d9 323 pid,
f08199d3 324 cpus->map[cpu],
023695d9 325 group_fd, flags);
727ab04e
ACM
326 if (FD(evsel, cpu, thread) < 0) {
327 err = -errno;
0252208e 328 goto out_close;
727ab04e 329 }
f08199d3
ACM
330
331 if (group && group_fd == -1)
332 group_fd = FD(evsel, cpu, thread);
0252208e 333 }
48290609
ACM
334 }
335
336 return 0;
337
338out_close:
0252208e
ACM
339 do {
340 while (--thread >= 0) {
341 close(FD(evsel, cpu, thread));
342 FD(evsel, cpu, thread) = -1;
343 }
344 thread = threads->nr;
345 } while (--cpu >= 0);
727ab04e
ACM
346 return err;
347}
348
349void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads)
350{
351 if (evsel->fd == NULL)
352 return;
353
354 perf_evsel__close_fd(evsel, ncpus, nthreads);
355 perf_evsel__free_fd(evsel);
356 evsel->fd = NULL;
48290609
ACM
357}
358
0252208e
ACM
359static struct {
360 struct cpu_map map;
361 int cpus[1];
362} empty_cpu_map = {
363 .map.nr = 1,
364 .cpus = { -1, },
365};
366
367static struct {
368 struct thread_map map;
369 int threads[1];
370} empty_thread_map = {
371 .map.nr = 1,
372 .threads = { -1, },
373};
374
f08199d3 375int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
727ab04e
ACM
376 struct thread_map *threads, bool group,
377 struct xyarray *group_fd)
48290609 378{
0252208e
ACM
379 if (cpus == NULL) {
380 /* Work around old compiler warnings about strict aliasing */
381 cpus = &empty_cpu_map.map;
48290609
ACM
382 }
383
0252208e
ACM
384 if (threads == NULL)
385 threads = &empty_thread_map.map;
48290609 386
727ab04e 387 return __perf_evsel__open(evsel, cpus, threads, group, group_fd);
48290609
ACM
388}
389
f08199d3 390int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
727ab04e
ACM
391 struct cpu_map *cpus, bool group,
392 struct xyarray *group_fd)
48290609 393{
727ab04e
ACM
394 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group,
395 group_fd);
0252208e 396}
48290609 397
f08199d3 398int perf_evsel__open_per_thread(struct perf_evsel *evsel,
727ab04e
ACM
399 struct thread_map *threads, bool group,
400 struct xyarray *group_fd)
0252208e 401{
727ab04e
ACM
402 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group,
403 group_fd);
48290609 404}
70082dd9 405
8115d60c
ACM
406static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
407 struct perf_sample *sample)
d0dd74e8
ACM
408{
409 const u64 *array = event->sample.array;
410
411 array += ((event->header.size -
412 sizeof(event->header)) / sizeof(u64)) - 1;
413
414 if (type & PERF_SAMPLE_CPU) {
415 u32 *p = (u32 *)array;
416 sample->cpu = *p;
417 array--;
418 }
419
420 if (type & PERF_SAMPLE_STREAM_ID) {
421 sample->stream_id = *array;
422 array--;
423 }
424
425 if (type & PERF_SAMPLE_ID) {
426 sample->id = *array;
427 array--;
428 }
429
430 if (type & PERF_SAMPLE_TIME) {
431 sample->time = *array;
432 array--;
433 }
434
435 if (type & PERF_SAMPLE_TID) {
436 u32 *p = (u32 *)array;
437 sample->pid = p[0];
438 sample->tid = p[1];
439 }
440
441 return 0;
442}
443
98e1da90
FW
444static bool sample_overlap(const union perf_event *event,
445 const void *offset, u64 size)
446{
447 const void *base = event;
448
449 if (offset + size > base + event->header.size)
450 return true;
451
452 return false;
453}
454
8115d60c 455int perf_event__parse_sample(const union perf_event *event, u64 type,
a2854124 456 int sample_size, bool sample_id_all,
936be503 457 struct perf_sample *data, bool swapped)
d0dd74e8
ACM
458{
459 const u64 *array;
460
936be503
DA
461 /*
462 * used for cross-endian analysis. See git commit 65014ab3
463 * for why this goofiness is needed.
464 */
465 union {
466 u64 val64;
467 u32 val32[2];
468 } u;
469
f3bda2c9 470 memset(data, 0, sizeof(*data));
d0dd74e8
ACM
471 data->cpu = data->pid = data->tid = -1;
472 data->stream_id = data->id = data->time = -1ULL;
a4a03fc7 473 data->period = 1;
d0dd74e8
ACM
474
475 if (event->header.type != PERF_RECORD_SAMPLE) {
476 if (!sample_id_all)
477 return 0;
8115d60c 478 return perf_event__parse_id_sample(event, type, data);
d0dd74e8
ACM
479 }
480
481 array = event->sample.array;
482
a2854124
FW
483 if (sample_size + sizeof(event->header) > event->header.size)
484 return -EFAULT;
485
d0dd74e8
ACM
486 if (type & PERF_SAMPLE_IP) {
487 data->ip = event->ip.ip;
488 array++;
489 }
490
491 if (type & PERF_SAMPLE_TID) {
936be503
DA
492 u.val64 = *array;
493 if (swapped) {
494 /* undo swap of u64, then swap on individual u32s */
495 u.val64 = bswap_64(u.val64);
496 u.val32[0] = bswap_32(u.val32[0]);
497 u.val32[1] = bswap_32(u.val32[1]);
498 }
499
500 data->pid = u.val32[0];
501 data->tid = u.val32[1];
d0dd74e8
ACM
502 array++;
503 }
504
505 if (type & PERF_SAMPLE_TIME) {
506 data->time = *array;
507 array++;
508 }
509
7cec0922 510 data->addr = 0;
d0dd74e8
ACM
511 if (type & PERF_SAMPLE_ADDR) {
512 data->addr = *array;
513 array++;
514 }
515
516 data->id = -1ULL;
517 if (type & PERF_SAMPLE_ID) {
518 data->id = *array;
519 array++;
520 }
521
522 if (type & PERF_SAMPLE_STREAM_ID) {
523 data->stream_id = *array;
524 array++;
525 }
526
527 if (type & PERF_SAMPLE_CPU) {
936be503
DA
528
529 u.val64 = *array;
530 if (swapped) {
531 /* undo swap of u64, then swap on individual u32s */
532 u.val64 = bswap_64(u.val64);
533 u.val32[0] = bswap_32(u.val32[0]);
534 }
535
536 data->cpu = u.val32[0];
d0dd74e8
ACM
537 array++;
538 }
539
540 if (type & PERF_SAMPLE_PERIOD) {
541 data->period = *array;
542 array++;
543 }
544
545 if (type & PERF_SAMPLE_READ) {
f9d36996 546 fprintf(stderr, "PERF_SAMPLE_READ is unsupported for now\n");
d0dd74e8
ACM
547 return -1;
548 }
549
550 if (type & PERF_SAMPLE_CALLCHAIN) {
98e1da90
FW
551 if (sample_overlap(event, array, sizeof(data->callchain->nr)))
552 return -EFAULT;
553
d0dd74e8 554 data->callchain = (struct ip_callchain *)array;
98e1da90
FW
555
556 if (sample_overlap(event, array, data->callchain->nr))
557 return -EFAULT;
558
d0dd74e8
ACM
559 array += 1 + data->callchain->nr;
560 }
561
562 if (type & PERF_SAMPLE_RAW) {
8e303f20
JO
563 const u64 *pdata;
564
936be503
DA
565 u.val64 = *array;
566 if (WARN_ONCE(swapped,
567 "Endianness of raw data not corrected!\n")) {
568 /* undo swap of u64, then swap on individual u32s */
569 u.val64 = bswap_64(u.val64);
570 u.val32[0] = bswap_32(u.val32[0]);
571 u.val32[1] = bswap_32(u.val32[1]);
572 }
98e1da90
FW
573
574 if (sample_overlap(event, array, sizeof(u32)))
575 return -EFAULT;
576
936be503 577 data->raw_size = u.val32[0];
8e303f20 578 pdata = (void *) array + sizeof(u32);
98e1da90 579
8e303f20 580 if (sample_overlap(event, pdata, data->raw_size))
98e1da90
FW
581 return -EFAULT;
582
8e303f20 583 data->raw_data = (void *) pdata;
fa30c964
SE
584
585 array = (void *)array + data->raw_size + sizeof(u32);
d0dd74e8
ACM
586 }
587
b5387528
RAV
588 if (type & PERF_SAMPLE_BRANCH_STACK) {
589 u64 sz;
590
591 data->branch_stack = (struct branch_stack *)array;
592 array++; /* nr */
593
594 sz = data->branch_stack->nr * sizeof(struct branch_entry);
595 sz /= sizeof(u64);
596 array += sz;
597 }
d0dd74e8
ACM
598 return 0;
599}
74eec26f
AV
600
601int perf_event__synthesize_sample(union perf_event *event, u64 type,
602 const struct perf_sample *sample,
603 bool swapped)
604{
605 u64 *array;
606
607 /*
608 * used for cross-endian analysis. See git commit 65014ab3
609 * for why this goofiness is needed.
610 */
611 union {
612 u64 val64;
613 u32 val32[2];
614 } u;
615
616 array = event->sample.array;
617
618 if (type & PERF_SAMPLE_IP) {
619 event->ip.ip = sample->ip;
620 array++;
621 }
622
623 if (type & PERF_SAMPLE_TID) {
624 u.val32[0] = sample->pid;
625 u.val32[1] = sample->tid;
626 if (swapped) {
627 /*
628 * Inverse of what is done in perf_event__parse_sample
629 */
630 u.val32[0] = bswap_32(u.val32[0]);
631 u.val32[1] = bswap_32(u.val32[1]);
632 u.val64 = bswap_64(u.val64);
633 }
634
635 *array = u.val64;
636 array++;
637 }
638
639 if (type & PERF_SAMPLE_TIME) {
640 *array = sample->time;
641 array++;
642 }
643
644 if (type & PERF_SAMPLE_ADDR) {
645 *array = sample->addr;
646 array++;
647 }
648
649 if (type & PERF_SAMPLE_ID) {
650 *array = sample->id;
651 array++;
652 }
653
654 if (type & PERF_SAMPLE_STREAM_ID) {
655 *array = sample->stream_id;
656 array++;
657 }
658
659 if (type & PERF_SAMPLE_CPU) {
660 u.val32[0] = sample->cpu;
661 if (swapped) {
662 /*
663 * Inverse of what is done in perf_event__parse_sample
664 */
665 u.val32[0] = bswap_32(u.val32[0]);
666 u.val64 = bswap_64(u.val64);
667 }
668 *array = u.val64;
669 array++;
670 }
671
672 if (type & PERF_SAMPLE_PERIOD) {
673 *array = sample->period;
674 array++;
675 }
676
677 return 0;
678}