perf evsel: Introduce config attr method
[platform/adaptation/renesas_rcar/renesas_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 void perf_evsel__init(struct perf_evsel *evsel,
38                       struct perf_event_attr *attr, int idx)
39 {
40         evsel->idx         = idx;
41         evsel->attr        = *attr;
42         INIT_LIST_HEAD(&evsel->node);
43         hists__init(&evsel->hists);
44 }
45
46 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
47 {
48         struct perf_evsel *evsel = zalloc(sizeof(*evsel));
49
50         if (evsel != NULL)
51                 perf_evsel__init(evsel, attr, idx);
52
53         return evsel;
54 }
55
56 void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts)
57 {
58         struct perf_event_attr *attr = &evsel->attr;
59         int track = !evsel->idx; /* only the first counter needs these */
60
61         attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
62         attr->inherit       = !opts->no_inherit;
63         attr->read_format   = PERF_FORMAT_TOTAL_TIME_ENABLED |
64                               PERF_FORMAT_TOTAL_TIME_RUNNING |
65                               PERF_FORMAT_ID;
66
67         attr->sample_type  |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
68
69         /*
70          * We default some events to a 1 default interval. But keep
71          * it a weak assumption overridable by the user.
72          */
73         if (!attr->sample_period || (opts->user_freq != UINT_MAX &&
74                                      opts->user_interval != ULLONG_MAX)) {
75                 if (opts->freq) {
76                         attr->sample_type       |= PERF_SAMPLE_PERIOD;
77                         attr->freq              = 1;
78                         attr->sample_freq       = opts->freq;
79                 } else {
80                         attr->sample_period = opts->default_interval;
81                 }
82         }
83
84         if (opts->no_samples)
85                 attr->sample_freq = 0;
86
87         if (opts->inherit_stat)
88                 attr->inherit_stat = 1;
89
90         if (opts->sample_address) {
91                 attr->sample_type       |= PERF_SAMPLE_ADDR;
92                 attr->mmap_data = track;
93         }
94
95         if (opts->call_graph)
96                 attr->sample_type       |= PERF_SAMPLE_CALLCHAIN;
97
98         if (opts->system_wide)
99                 attr->sample_type       |= PERF_SAMPLE_CPU;
100
101         if (opts->sample_id_all_avail &&
102             (opts->sample_time || opts->system_wide ||
103              !opts->no_inherit || opts->cpu_list))
104                 attr->sample_type       |= PERF_SAMPLE_TIME;
105
106         if (opts->raw_samples) {
107                 attr->sample_type       |= PERF_SAMPLE_TIME;
108                 attr->sample_type       |= PERF_SAMPLE_RAW;
109                 attr->sample_type       |= PERF_SAMPLE_CPU;
110         }
111
112         if (opts->no_delay) {
113                 attr->watermark = 0;
114                 attr->wakeup_events = 1;
115         }
116
117         attr->mmap = track;
118         attr->comm = track;
119
120         if (opts->target_pid == -1 && opts->target_tid == -1 && !opts->system_wide) {
121                 attr->disabled = 1;
122                 attr->enable_on_exec = 1;
123         }
124 }
125
126 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
127 {
128         int cpu, thread;
129         evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
130
131         if (evsel->fd) {
132                 for (cpu = 0; cpu < ncpus; cpu++) {
133                         for (thread = 0; thread < nthreads; thread++) {
134                                 FD(evsel, cpu, thread) = -1;
135                         }
136                 }
137         }
138
139         return evsel->fd != NULL ? 0 : -ENOMEM;
140 }
141
142 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
143 {
144         evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
145         if (evsel->sample_id == NULL)
146                 return -ENOMEM;
147
148         evsel->id = zalloc(ncpus * nthreads * sizeof(u64));
149         if (evsel->id == NULL) {
150                 xyarray__delete(evsel->sample_id);
151                 evsel->sample_id = NULL;
152                 return -ENOMEM;
153         }
154
155         return 0;
156 }
157
158 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
159 {
160         evsel->counts = zalloc((sizeof(*evsel->counts) +
161                                 (ncpus * sizeof(struct perf_counts_values))));
162         return evsel->counts != NULL ? 0 : -ENOMEM;
163 }
164
165 void perf_evsel__free_fd(struct perf_evsel *evsel)
166 {
167         xyarray__delete(evsel->fd);
168         evsel->fd = NULL;
169 }
170
171 void perf_evsel__free_id(struct perf_evsel *evsel)
172 {
173         xyarray__delete(evsel->sample_id);
174         evsel->sample_id = NULL;
175         free(evsel->id);
176         evsel->id = NULL;
177 }
178
179 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
180 {
181         int cpu, thread;
182
183         for (cpu = 0; cpu < ncpus; cpu++)
184                 for (thread = 0; thread < nthreads; ++thread) {
185                         close(FD(evsel, cpu, thread));
186                         FD(evsel, cpu, thread) = -1;
187                 }
188 }
189
190 void perf_evsel__exit(struct perf_evsel *evsel)
191 {
192         assert(list_empty(&evsel->node));
193         xyarray__delete(evsel->fd);
194         xyarray__delete(evsel->sample_id);
195         free(evsel->id);
196 }
197
198 void perf_evsel__delete(struct perf_evsel *evsel)
199 {
200         perf_evsel__exit(evsel);
201         close_cgroup(evsel->cgrp);
202         free(evsel->name);
203         free(evsel);
204 }
205
206 int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
207                               int cpu, int thread, bool scale)
208 {
209         struct perf_counts_values count;
210         size_t nv = scale ? 3 : 1;
211
212         if (FD(evsel, cpu, thread) < 0)
213                 return -EINVAL;
214
215         if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
216                 return -ENOMEM;
217
218         if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
219                 return -errno;
220
221         if (scale) {
222                 if (count.run == 0)
223                         count.val = 0;
224                 else if (count.run < count.ena)
225                         count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
226         } else
227                 count.ena = count.run = 0;
228
229         evsel->counts->cpu[cpu] = count;
230         return 0;
231 }
232
233 int __perf_evsel__read(struct perf_evsel *evsel,
234                        int ncpus, int nthreads, bool scale)
235 {
236         size_t nv = scale ? 3 : 1;
237         int cpu, thread;
238         struct perf_counts_values *aggr = &evsel->counts->aggr, count;
239
240         aggr->val = aggr->ena = aggr->run = 0;
241
242         for (cpu = 0; cpu < ncpus; cpu++) {
243                 for (thread = 0; thread < nthreads; thread++) {
244                         if (FD(evsel, cpu, thread) < 0)
245                                 continue;
246
247                         if (readn(FD(evsel, cpu, thread),
248                                   &count, nv * sizeof(u64)) < 0)
249                                 return -errno;
250
251                         aggr->val += count.val;
252                         if (scale) {
253                                 aggr->ena += count.ena;
254                                 aggr->run += count.run;
255                         }
256                 }
257         }
258
259         evsel->counts->scaled = 0;
260         if (scale) {
261                 if (aggr->run == 0) {
262                         evsel->counts->scaled = -1;
263                         aggr->val = 0;
264                         return 0;
265                 }
266
267                 if (aggr->run < aggr->ena) {
268                         evsel->counts->scaled = 1;
269                         aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
270                 }
271         } else
272                 aggr->ena = aggr->run = 0;
273
274         return 0;
275 }
276
277 static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
278                               struct thread_map *threads, bool group,
279                               struct xyarray *group_fds)
280 {
281         int cpu, thread;
282         unsigned long flags = 0;
283         int pid = -1, err;
284
285         if (evsel->fd == NULL &&
286             perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
287                 return -ENOMEM;
288
289         if (evsel->cgrp) {
290                 flags = PERF_FLAG_PID_CGROUP;
291                 pid = evsel->cgrp->fd;
292         }
293
294         for (cpu = 0; cpu < cpus->nr; cpu++) {
295                 int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1;
296
297                 for (thread = 0; thread < threads->nr; thread++) {
298
299                         if (!evsel->cgrp)
300                                 pid = threads->map[thread];
301
302                         FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
303                                                                      pid,
304                                                                      cpus->map[cpu],
305                                                                      group_fd, flags);
306                         if (FD(evsel, cpu, thread) < 0) {
307                                 err = -errno;
308                                 goto out_close;
309                         }
310
311                         if (group && group_fd == -1)
312                                 group_fd = FD(evsel, cpu, thread);
313                 }
314         }
315
316         return 0;
317
318 out_close:
319         do {
320                 while (--thread >= 0) {
321                         close(FD(evsel, cpu, thread));
322                         FD(evsel, cpu, thread) = -1;
323                 }
324                 thread = threads->nr;
325         } while (--cpu >= 0);
326         return err;
327 }
328
329 void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads)
330 {
331         if (evsel->fd == NULL)
332                 return;
333
334         perf_evsel__close_fd(evsel, ncpus, nthreads);
335         perf_evsel__free_fd(evsel);
336         evsel->fd = NULL;
337 }
338
339 static struct {
340         struct cpu_map map;
341         int cpus[1];
342 } empty_cpu_map = {
343         .map.nr = 1,
344         .cpus   = { -1, },
345 };
346
347 static struct {
348         struct thread_map map;
349         int threads[1];
350 } empty_thread_map = {
351         .map.nr  = 1,
352         .threads = { -1, },
353 };
354
355 int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
356                      struct thread_map *threads, bool group,
357                      struct xyarray *group_fd)
358 {
359         if (cpus == NULL) {
360                 /* Work around old compiler warnings about strict aliasing */
361                 cpus = &empty_cpu_map.map;
362         }
363
364         if (threads == NULL)
365                 threads = &empty_thread_map.map;
366
367         return __perf_evsel__open(evsel, cpus, threads, group, group_fd);
368 }
369
370 int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
371                              struct cpu_map *cpus, bool group,
372                              struct xyarray *group_fd)
373 {
374         return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group,
375                                   group_fd);
376 }
377
378 int perf_evsel__open_per_thread(struct perf_evsel *evsel,
379                                 struct thread_map *threads, bool group,
380                                 struct xyarray *group_fd)
381 {
382         return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group,
383                                   group_fd);
384 }
385
386 static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
387                                        struct perf_sample *sample)
388 {
389         const u64 *array = event->sample.array;
390
391         array += ((event->header.size -
392                    sizeof(event->header)) / sizeof(u64)) - 1;
393
394         if (type & PERF_SAMPLE_CPU) {
395                 u32 *p = (u32 *)array;
396                 sample->cpu = *p;
397                 array--;
398         }
399
400         if (type & PERF_SAMPLE_STREAM_ID) {
401                 sample->stream_id = *array;
402                 array--;
403         }
404
405         if (type & PERF_SAMPLE_ID) {
406                 sample->id = *array;
407                 array--;
408         }
409
410         if (type & PERF_SAMPLE_TIME) {
411                 sample->time = *array;
412                 array--;
413         }
414
415         if (type & PERF_SAMPLE_TID) {
416                 u32 *p = (u32 *)array;
417                 sample->pid = p[0];
418                 sample->tid = p[1];
419         }
420
421         return 0;
422 }
423
424 static bool sample_overlap(const union perf_event *event,
425                            const void *offset, u64 size)
426 {
427         const void *base = event;
428
429         if (offset + size > base + event->header.size)
430                 return true;
431
432         return false;
433 }
434
435 int perf_event__parse_sample(const union perf_event *event, u64 type,
436                              int sample_size, bool sample_id_all,
437                              struct perf_sample *data, bool swapped)
438 {
439         const u64 *array;
440
441         /*
442          * used for cross-endian analysis. See git commit 65014ab3
443          * for why this goofiness is needed.
444          */
445         union {
446                 u64 val64;
447                 u32 val32[2];
448         } u;
449
450
451         data->cpu = data->pid = data->tid = -1;
452         data->stream_id = data->id = data->time = -1ULL;
453
454         if (event->header.type != PERF_RECORD_SAMPLE) {
455                 if (!sample_id_all)
456                         return 0;
457                 return perf_event__parse_id_sample(event, type, data);
458         }
459
460         array = event->sample.array;
461
462         if (sample_size + sizeof(event->header) > event->header.size)
463                 return -EFAULT;
464
465         if (type & PERF_SAMPLE_IP) {
466                 data->ip = event->ip.ip;
467                 array++;
468         }
469
470         if (type & PERF_SAMPLE_TID) {
471                 u.val64 = *array;
472                 if (swapped) {
473                         /* undo swap of u64, then swap on individual u32s */
474                         u.val64 = bswap_64(u.val64);
475                         u.val32[0] = bswap_32(u.val32[0]);
476                         u.val32[1] = bswap_32(u.val32[1]);
477                 }
478
479                 data->pid = u.val32[0];
480                 data->tid = u.val32[1];
481                 array++;
482         }
483
484         if (type & PERF_SAMPLE_TIME) {
485                 data->time = *array;
486                 array++;
487         }
488
489         data->addr = 0;
490         if (type & PERF_SAMPLE_ADDR) {
491                 data->addr = *array;
492                 array++;
493         }
494
495         data->id = -1ULL;
496         if (type & PERF_SAMPLE_ID) {
497                 data->id = *array;
498                 array++;
499         }
500
501         if (type & PERF_SAMPLE_STREAM_ID) {
502                 data->stream_id = *array;
503                 array++;
504         }
505
506         if (type & PERF_SAMPLE_CPU) {
507
508                 u.val64 = *array;
509                 if (swapped) {
510                         /* undo swap of u64, then swap on individual u32s */
511                         u.val64 = bswap_64(u.val64);
512                         u.val32[0] = bswap_32(u.val32[0]);
513                 }
514
515                 data->cpu = u.val32[0];
516                 array++;
517         }
518
519         if (type & PERF_SAMPLE_PERIOD) {
520                 data->period = *array;
521                 array++;
522         }
523
524         if (type & PERF_SAMPLE_READ) {
525                 fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n");
526                 return -1;
527         }
528
529         if (type & PERF_SAMPLE_CALLCHAIN) {
530                 if (sample_overlap(event, array, sizeof(data->callchain->nr)))
531                         return -EFAULT;
532
533                 data->callchain = (struct ip_callchain *)array;
534
535                 if (sample_overlap(event, array, data->callchain->nr))
536                         return -EFAULT;
537
538                 array += 1 + data->callchain->nr;
539         }
540
541         if (type & PERF_SAMPLE_RAW) {
542                 const u64 *pdata;
543
544                 u.val64 = *array;
545                 if (WARN_ONCE(swapped,
546                               "Endianness of raw data not corrected!\n")) {
547                         /* undo swap of u64, then swap on individual u32s */
548                         u.val64 = bswap_64(u.val64);
549                         u.val32[0] = bswap_32(u.val32[0]);
550                         u.val32[1] = bswap_32(u.val32[1]);
551                 }
552
553                 if (sample_overlap(event, array, sizeof(u32)))
554                         return -EFAULT;
555
556                 data->raw_size = u.val32[0];
557                 pdata = (void *) array + sizeof(u32);
558
559                 if (sample_overlap(event, pdata, data->raw_size))
560                         return -EFAULT;
561
562                 data->raw_data = (void *) pdata;
563         }
564
565         return 0;
566 }