perf scripting: Avoid leaking the scripting_context variable
[pandora-kernel.git] / tools / perf / util / evsel.c
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
10 #include <byteswap.h>
11 #include "asm/bug.h"
12 #include "evsel.h"
13 #include "evlist.h"
14 #include "util.h"
15 #include "cpumap.h"
16 #include "thread_map.h"
17
18 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
19 #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
20
21 int __perf_evsel__sample_size(u64 sample_type)
22 {
23         u64 mask = sample_type & PERF_SAMPLE_MASK;
24         int size = 0;
25         int i;
26
27         for (i = 0; i < 64; i++) {
28                 if (mask & (1ULL << i))
29                         size++;
30         }
31
32         size *= sizeof(u64);
33
34         return size;
35 }
36
37 static void hists__init(struct hists *hists)
38 {
39         memset(hists, 0, sizeof(*hists));
40         hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
41         hists->entries_in = &hists->entries_in_array[0];
42         hists->entries_collapsed = RB_ROOT;
43         hists->entries = RB_ROOT;
44         pthread_mutex_init(&hists->lock, NULL);
45 }
46
47 void perf_evsel__init(struct perf_evsel *evsel,
48                       struct perf_event_attr *attr, int idx)
49 {
50         evsel->idx         = idx;
51         evsel->attr        = *attr;
52         INIT_LIST_HEAD(&evsel->node);
53         hists__init(&evsel->hists);
54 }
55
56 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
57 {
58         struct perf_evsel *evsel = zalloc(sizeof(*evsel));
59
60         if (evsel != NULL)
61                 perf_evsel__init(evsel, attr, idx);
62
63         return evsel;
64 }
65
66 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
67 {
68         int cpu, thread;
69         evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
70
71         if (evsel->fd) {
72                 for (cpu = 0; cpu < ncpus; cpu++) {
73                         for (thread = 0; thread < nthreads; thread++) {
74                                 FD(evsel, cpu, thread) = -1;
75                         }
76                 }
77         }
78
79         return evsel->fd != NULL ? 0 : -ENOMEM;
80 }
81
82 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
83 {
84         evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
85         if (evsel->sample_id == NULL)
86                 return -ENOMEM;
87
88         evsel->id = zalloc(ncpus * nthreads * sizeof(u64));
89         if (evsel->id == NULL) {
90                 xyarray__delete(evsel->sample_id);
91                 evsel->sample_id = NULL;
92                 return -ENOMEM;
93         }
94
95         return 0;
96 }
97
98 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
99 {
100         evsel->counts = zalloc((sizeof(*evsel->counts) +
101                                 (ncpus * sizeof(struct perf_counts_values))));
102         return evsel->counts != NULL ? 0 : -ENOMEM;
103 }
104
105 void perf_evsel__free_fd(struct perf_evsel *evsel)
106 {
107         xyarray__delete(evsel->fd);
108         evsel->fd = NULL;
109 }
110
111 void perf_evsel__free_id(struct perf_evsel *evsel)
112 {
113         xyarray__delete(evsel->sample_id);
114         evsel->sample_id = NULL;
115         free(evsel->id);
116         evsel->id = NULL;
117 }
118
119 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
120 {
121         int cpu, thread;
122
123         for (cpu = 0; cpu < ncpus; cpu++)
124                 for (thread = 0; thread < nthreads; ++thread) {
125                         close(FD(evsel, cpu, thread));
126                         FD(evsel, cpu, thread) = -1;
127                 }
128 }
129
130 void perf_evsel__exit(struct perf_evsel *evsel)
131 {
132         assert(list_empty(&evsel->node));
133         xyarray__delete(evsel->fd);
134         xyarray__delete(evsel->sample_id);
135         free(evsel->id);
136 }
137
138 void perf_evsel__delete(struct perf_evsel *evsel)
139 {
140         perf_evsel__exit(evsel);
141         close_cgroup(evsel->cgrp);
142         free(evsel->name);
143         free(evsel);
144 }
145
146 int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
147                               int cpu, int thread, bool scale)
148 {
149         struct perf_counts_values count;
150         size_t nv = scale ? 3 : 1;
151
152         if (FD(evsel, cpu, thread) < 0)
153                 return -EINVAL;
154
155         if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
156                 return -ENOMEM;
157
158         if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
159                 return -errno;
160
161         if (scale) {
162                 if (count.run == 0)
163                         count.val = 0;
164                 else if (count.run < count.ena)
165                         count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
166         } else
167                 count.ena = count.run = 0;
168
169         evsel->counts->cpu[cpu] = count;
170         return 0;
171 }
172
173 int __perf_evsel__read(struct perf_evsel *evsel,
174                        int ncpus, int nthreads, bool scale)
175 {
176         size_t nv = scale ? 3 : 1;
177         int cpu, thread;
178         struct perf_counts_values *aggr = &evsel->counts->aggr, count;
179
180         aggr->val = aggr->ena = aggr->run = 0;
181
182         for (cpu = 0; cpu < ncpus; cpu++) {
183                 for (thread = 0; thread < nthreads; thread++) {
184                         if (FD(evsel, cpu, thread) < 0)
185                                 continue;
186
187                         if (readn(FD(evsel, cpu, thread),
188                                   &count, nv * sizeof(u64)) < 0)
189                                 return -errno;
190
191                         aggr->val += count.val;
192                         if (scale) {
193                                 aggr->ena += count.ena;
194                                 aggr->run += count.run;
195                         }
196                 }
197         }
198
199         evsel->counts->scaled = 0;
200         if (scale) {
201                 if (aggr->run == 0) {
202                         evsel->counts->scaled = -1;
203                         aggr->val = 0;
204                         return 0;
205                 }
206
207                 if (aggr->run < aggr->ena) {
208                         evsel->counts->scaled = 1;
209                         aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
210                 }
211         } else
212                 aggr->ena = aggr->run = 0;
213
214         return 0;
215 }
216
217 static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
218                               struct thread_map *threads, bool group,
219                               struct xyarray *group_fds)
220 {
221         int cpu, thread;
222         unsigned long flags = 0;
223         int pid = -1, err;
224
225         if (evsel->fd == NULL &&
226             perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
227                 return -ENOMEM;
228
229         if (evsel->cgrp) {
230                 flags = PERF_FLAG_PID_CGROUP;
231                 pid = evsel->cgrp->fd;
232         }
233
234         for (cpu = 0; cpu < cpus->nr; cpu++) {
235                 int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1;
236
237                 for (thread = 0; thread < threads->nr; thread++) {
238
239                         if (!evsel->cgrp)
240                                 pid = threads->map[thread];
241
242                         FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
243                                                                      pid,
244                                                                      cpus->map[cpu],
245                                                                      group_fd, flags);
246                         if (FD(evsel, cpu, thread) < 0) {
247                                 err = -errno;
248                                 goto out_close;
249                         }
250
251                         if (group && group_fd == -1)
252                                 group_fd = FD(evsel, cpu, thread);
253                 }
254         }
255
256         return 0;
257
258 out_close:
259         do {
260                 while (--thread >= 0) {
261                         close(FD(evsel, cpu, thread));
262                         FD(evsel, cpu, thread) = -1;
263                 }
264                 thread = threads->nr;
265         } while (--cpu >= 0);
266         return err;
267 }
268
269 void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads)
270 {
271         if (evsel->fd == NULL)
272                 return;
273
274         perf_evsel__close_fd(evsel, ncpus, nthreads);
275         perf_evsel__free_fd(evsel);
276         evsel->fd = NULL;
277 }
278
279 static struct {
280         struct cpu_map map;
281         int cpus[1];
282 } empty_cpu_map = {
283         .map.nr = 1,
284         .cpus   = { -1, },
285 };
286
287 static struct {
288         struct thread_map map;
289         int threads[1];
290 } empty_thread_map = {
291         .map.nr  = 1,
292         .threads = { -1, },
293 };
294
295 int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
296                      struct thread_map *threads, bool group,
297                      struct xyarray *group_fd)
298 {
299         if (cpus == NULL) {
300                 /* Work around old compiler warnings about strict aliasing */
301                 cpus = &empty_cpu_map.map;
302         }
303
304         if (threads == NULL)
305                 threads = &empty_thread_map.map;
306
307         return __perf_evsel__open(evsel, cpus, threads, group, group_fd);
308 }
309
310 int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
311                              struct cpu_map *cpus, bool group,
312                              struct xyarray *group_fd)
313 {
314         return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group,
315                                   group_fd);
316 }
317
318 int perf_evsel__open_per_thread(struct perf_evsel *evsel,
319                                 struct thread_map *threads, bool group,
320                                 struct xyarray *group_fd)
321 {
322         return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group,
323                                   group_fd);
324 }
325
326 static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
327                                        struct perf_sample *sample)
328 {
329         const u64 *array = event->sample.array;
330
331         array += ((event->header.size -
332                    sizeof(event->header)) / sizeof(u64)) - 1;
333
334         if (type & PERF_SAMPLE_CPU) {
335                 u32 *p = (u32 *)array;
336                 sample->cpu = *p;
337                 array--;
338         }
339
340         if (type & PERF_SAMPLE_STREAM_ID) {
341                 sample->stream_id = *array;
342                 array--;
343         }
344
345         if (type & PERF_SAMPLE_ID) {
346                 sample->id = *array;
347                 array--;
348         }
349
350         if (type & PERF_SAMPLE_TIME) {
351                 sample->time = *array;
352                 array--;
353         }
354
355         if (type & PERF_SAMPLE_TID) {
356                 u32 *p = (u32 *)array;
357                 sample->pid = p[0];
358                 sample->tid = p[1];
359         }
360
361         return 0;
362 }
363
364 static bool sample_overlap(const union perf_event *event,
365                            const void *offset, u64 size)
366 {
367         const void *base = event;
368
369         if (offset + size > base + event->header.size)
370                 return true;
371
372         return false;
373 }
374
375 int perf_event__parse_sample(const union perf_event *event, u64 type,
376                              int sample_size, bool sample_id_all,
377                              struct perf_sample *data, bool swapped)
378 {
379         const u64 *array;
380
381         /*
382          * used for cross-endian analysis. See git commit 65014ab3
383          * for why this goofiness is needed.
384          */
385         union {
386                 u64 val64;
387                 u32 val32[2];
388         } u;
389
390
391         data->cpu = data->pid = data->tid = -1;
392         data->stream_id = data->id = data->time = -1ULL;
393         data->period = 1;
394
395         if (event->header.type != PERF_RECORD_SAMPLE) {
396                 if (!sample_id_all)
397                         return 0;
398                 return perf_event__parse_id_sample(event, type, data);
399         }
400
401         array = event->sample.array;
402
403         if (sample_size + sizeof(event->header) > event->header.size)
404                 return -EFAULT;
405
406         if (type & PERF_SAMPLE_IP) {
407                 data->ip = event->ip.ip;
408                 array++;
409         }
410
411         if (type & PERF_SAMPLE_TID) {
412                 u.val64 = *array;
413                 if (swapped) {
414                         /* undo swap of u64, then swap on individual u32s */
415                         u.val64 = bswap_64(u.val64);
416                         u.val32[0] = bswap_32(u.val32[0]);
417                         u.val32[1] = bswap_32(u.val32[1]);
418                 }
419
420                 data->pid = u.val32[0];
421                 data->tid = u.val32[1];
422                 array++;
423         }
424
425         if (type & PERF_SAMPLE_TIME) {
426                 data->time = *array;
427                 array++;
428         }
429
430         data->addr = 0;
431         if (type & PERF_SAMPLE_ADDR) {
432                 data->addr = *array;
433                 array++;
434         }
435
436         data->id = -1ULL;
437         if (type & PERF_SAMPLE_ID) {
438                 data->id = *array;
439                 array++;
440         }
441
442         if (type & PERF_SAMPLE_STREAM_ID) {
443                 data->stream_id = *array;
444                 array++;
445         }
446
447         if (type & PERF_SAMPLE_CPU) {
448
449                 u.val64 = *array;
450                 if (swapped) {
451                         /* undo swap of u64, then swap on individual u32s */
452                         u.val64 = bswap_64(u.val64);
453                         u.val32[0] = bswap_32(u.val32[0]);
454                 }
455
456                 data->cpu = u.val32[0];
457                 array++;
458         }
459
460         if (type & PERF_SAMPLE_PERIOD) {
461                 data->period = *array;
462                 array++;
463         }
464
465         if (type & PERF_SAMPLE_READ) {
466                 fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n");
467                 return -1;
468         }
469
470         if (type & PERF_SAMPLE_CALLCHAIN) {
471                 if (sample_overlap(event, array, sizeof(data->callchain->nr)))
472                         return -EFAULT;
473
474                 data->callchain = (struct ip_callchain *)array;
475
476                 if (sample_overlap(event, array, data->callchain->nr))
477                         return -EFAULT;
478
479                 array += 1 + data->callchain->nr;
480         }
481
482         if (type & PERF_SAMPLE_RAW) {
483                 const u64 *pdata;
484
485                 u.val64 = *array;
486                 if (WARN_ONCE(swapped,
487                               "Endianness of raw data not corrected!\n")) {
488                         /* undo swap of u64, then swap on individual u32s */
489                         u.val64 = bswap_64(u.val64);
490                         u.val32[0] = bswap_32(u.val32[0]);
491                         u.val32[1] = bswap_32(u.val32[1]);
492                 }
493
494                 if (sample_overlap(event, array, sizeof(u32)))
495                         return -EFAULT;
496
497                 data->raw_size = u.val32[0];
498                 pdata = (void *) array + sizeof(u32);
499
500                 if (sample_overlap(event, pdata, data->raw_size))
501                         return -EFAULT;
502
503                 data->raw_data = (void *) pdata;
504         }
505
506         return 0;
507 }