]> Pileus Git - ~andy/linux/blob - tools/perf/util/evsel.c
Merge tag 'pm-for-3.6-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[~andy/linux] / 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 #include "target.h"
18 #include "../../../include/linux/hw_breakpoint.h"
19
20 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
21 #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
22
23 static int __perf_evsel__sample_size(u64 sample_type)
24 {
25         u64 mask = sample_type & PERF_SAMPLE_MASK;
26         int size = 0;
27         int i;
28
29         for (i = 0; i < 64; i++) {
30                 if (mask & (1ULL << i))
31                         size++;
32         }
33
34         size *= sizeof(u64);
35
36         return size;
37 }
38
39 void hists__init(struct hists *hists)
40 {
41         memset(hists, 0, sizeof(*hists));
42         hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
43         hists->entries_in = &hists->entries_in_array[0];
44         hists->entries_collapsed = RB_ROOT;
45         hists->entries = RB_ROOT;
46         pthread_mutex_init(&hists->lock, NULL);
47 }
48
49 void perf_evsel__init(struct perf_evsel *evsel,
50                       struct perf_event_attr *attr, int idx)
51 {
52         evsel->idx         = idx;
53         evsel->attr        = *attr;
54         INIT_LIST_HEAD(&evsel->node);
55         hists__init(&evsel->hists);
56         evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
57 }
58
59 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
60 {
61         struct perf_evsel *evsel = zalloc(sizeof(*evsel));
62
63         if (evsel != NULL)
64                 perf_evsel__init(evsel, attr, idx);
65
66         return evsel;
67 }
68
69 static const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = {
70         "cycles",
71         "instructions",
72         "cache-references",
73         "cache-misses",
74         "branches",
75         "branch-misses",
76         "bus-cycles",
77         "stalled-cycles-frontend",
78         "stalled-cycles-backend",
79         "ref-cycles",
80 };
81
82 static const char *__perf_evsel__hw_name(u64 config)
83 {
84         if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config])
85                 return perf_evsel__hw_names[config];
86
87         return "unknown-hardware";
88 }
89
90 static int perf_evsel__add_modifiers(struct perf_evsel *evsel, char *bf, size_t size)
91 {
92         int colon = 0, r = 0;
93         struct perf_event_attr *attr = &evsel->attr;
94         bool exclude_guest_default = false;
95
96 #define MOD_PRINT(context, mod) do {                                    \
97                 if (!attr->exclude_##context) {                         \
98                         if (!colon) colon = ++r;                        \
99                         r += scnprintf(bf + r, size - r, "%c", mod);    \
100                 } } while(0)
101
102         if (attr->exclude_kernel || attr->exclude_user || attr->exclude_hv) {
103                 MOD_PRINT(kernel, 'k');
104                 MOD_PRINT(user, 'u');
105                 MOD_PRINT(hv, 'h');
106                 exclude_guest_default = true;
107         }
108
109         if (attr->precise_ip) {
110                 if (!colon)
111                         colon = ++r;
112                 r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp");
113                 exclude_guest_default = true;
114         }
115
116         if (attr->exclude_host || attr->exclude_guest == exclude_guest_default) {
117                 MOD_PRINT(host, 'H');
118                 MOD_PRINT(guest, 'G');
119         }
120 #undef MOD_PRINT
121         if (colon)
122                 bf[colon - 1] = ':';
123         return r;
124 }
125
126 static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
127 {
128         int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(evsel->attr.config));
129         return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
130 }
131
132 static const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = {
133         "cpu-clock",
134         "task-clock",
135         "page-faults",
136         "context-switches",
137         "CPU-migrations",
138         "minor-faults",
139         "major-faults",
140         "alignment-faults",
141         "emulation-faults",
142 };
143
144 static const char *__perf_evsel__sw_name(u64 config)
145 {
146         if (config < PERF_COUNT_SW_MAX && perf_evsel__sw_names[config])
147                 return perf_evsel__sw_names[config];
148         return "unknown-software";
149 }
150
151 static int perf_evsel__sw_name(struct perf_evsel *evsel, char *bf, size_t size)
152 {
153         int r = scnprintf(bf, size, "%s", __perf_evsel__sw_name(evsel->attr.config));
154         return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
155 }
156
157 static int __perf_evsel__bp_name(char *bf, size_t size, u64 addr, u64 type)
158 {
159         int r;
160
161         r = scnprintf(bf, size, "mem:0x%" PRIx64 ":", addr);
162
163         if (type & HW_BREAKPOINT_R)
164                 r += scnprintf(bf + r, size - r, "r");
165
166         if (type & HW_BREAKPOINT_W)
167                 r += scnprintf(bf + r, size - r, "w");
168
169         if (type & HW_BREAKPOINT_X)
170                 r += scnprintf(bf + r, size - r, "x");
171
172         return r;
173 }
174
175 static int perf_evsel__bp_name(struct perf_evsel *evsel, char *bf, size_t size)
176 {
177         struct perf_event_attr *attr = &evsel->attr;
178         int r = __perf_evsel__bp_name(bf, size, attr->bp_addr, attr->bp_type);
179         return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
180 }
181
182 const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
183                                 [PERF_EVSEL__MAX_ALIASES] = {
184  { "L1-dcache", "l1-d",         "l1d",          "L1-data",              },
185  { "L1-icache", "l1-i",         "l1i",          "L1-instruction",       },
186  { "LLC",       "L2",                                                   },
187  { "dTLB",      "d-tlb",        "Data-TLB",                             },
188  { "iTLB",      "i-tlb",        "Instruction-TLB",                      },
189  { "branch",    "branches",     "bpu",          "btb",          "bpc",  },
190  { "node",                                                              },
191 };
192
193 const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX]
194                                    [PERF_EVSEL__MAX_ALIASES] = {
195  { "load",      "loads",        "read",                                 },
196  { "store",     "stores",       "write",                                },
197  { "prefetch",  "prefetches",   "speculative-read", "speculative-load", },
198 };
199
200 const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
201                                        [PERF_EVSEL__MAX_ALIASES] = {
202  { "refs",      "Reference",    "ops",          "access",               },
203  { "misses",    "miss",                                                 },
204 };
205
206 #define C(x)            PERF_COUNT_HW_CACHE_##x
207 #define CACHE_READ      (1 << C(OP_READ))
208 #define CACHE_WRITE     (1 << C(OP_WRITE))
209 #define CACHE_PREFETCH  (1 << C(OP_PREFETCH))
210 #define COP(x)          (1 << x)
211
212 /*
213  * cache operartion stat
214  * L1I : Read and prefetch only
215  * ITLB and BPU : Read-only
216  */
217 static unsigned long perf_evsel__hw_cache_stat[C(MAX)] = {
218  [C(L1D)]       = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
219  [C(L1I)]       = (CACHE_READ | CACHE_PREFETCH),
220  [C(LL)]        = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
221  [C(DTLB)]      = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
222  [C(ITLB)]      = (CACHE_READ),
223  [C(BPU)]       = (CACHE_READ),
224  [C(NODE)]      = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
225 };
226
227 bool perf_evsel__is_cache_op_valid(u8 type, u8 op)
228 {
229         if (perf_evsel__hw_cache_stat[type] & COP(op))
230                 return true;    /* valid */
231         else
232                 return false;   /* invalid */
233 }
234
235 int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
236                                             char *bf, size_t size)
237 {
238         if (result) {
239                 return scnprintf(bf, size, "%s-%s-%s", perf_evsel__hw_cache[type][0],
240                                  perf_evsel__hw_cache_op[op][0],
241                                  perf_evsel__hw_cache_result[result][0]);
242         }
243
244         return scnprintf(bf, size, "%s-%s", perf_evsel__hw_cache[type][0],
245                          perf_evsel__hw_cache_op[op][1]);
246 }
247
248 static int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size)
249 {
250         u8 op, result, type = (config >>  0) & 0xff;
251         const char *err = "unknown-ext-hardware-cache-type";
252
253         if (type > PERF_COUNT_HW_CACHE_MAX)
254                 goto out_err;
255
256         op = (config >>  8) & 0xff;
257         err = "unknown-ext-hardware-cache-op";
258         if (op > PERF_COUNT_HW_CACHE_OP_MAX)
259                 goto out_err;
260
261         result = (config >> 16) & 0xff;
262         err = "unknown-ext-hardware-cache-result";
263         if (result > PERF_COUNT_HW_CACHE_RESULT_MAX)
264                 goto out_err;
265
266         err = "invalid-cache";
267         if (!perf_evsel__is_cache_op_valid(type, op))
268                 goto out_err;
269
270         return __perf_evsel__hw_cache_type_op_res_name(type, op, result, bf, size);
271 out_err:
272         return scnprintf(bf, size, "%s", err);
273 }
274
275 static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t size)
276 {
277         int ret = __perf_evsel__hw_cache_name(evsel->attr.config, bf, size);
278         return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
279 }
280
281 static int perf_evsel__raw_name(struct perf_evsel *evsel, char *bf, size_t size)
282 {
283         int ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config);
284         return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
285 }
286
287 const char *perf_evsel__name(struct perf_evsel *evsel)
288 {
289         char bf[128];
290
291         if (evsel->name)
292                 return evsel->name;
293
294         switch (evsel->attr.type) {
295         case PERF_TYPE_RAW:
296                 perf_evsel__raw_name(evsel, bf, sizeof(bf));
297                 break;
298
299         case PERF_TYPE_HARDWARE:
300                 perf_evsel__hw_name(evsel, bf, sizeof(bf));
301                 break;
302
303         case PERF_TYPE_HW_CACHE:
304                 perf_evsel__hw_cache_name(evsel, bf, sizeof(bf));
305                 break;
306
307         case PERF_TYPE_SOFTWARE:
308                 perf_evsel__sw_name(evsel, bf, sizeof(bf));
309                 break;
310
311         case PERF_TYPE_TRACEPOINT:
312                 scnprintf(bf, sizeof(bf), "%s", "unknown tracepoint");
313                 break;
314
315         case PERF_TYPE_BREAKPOINT:
316                 perf_evsel__bp_name(evsel, bf, sizeof(bf));
317                 break;
318
319         default:
320                 scnprintf(bf, sizeof(bf), "%s", "unknown attr type");
321                 break;
322         }
323
324         evsel->name = strdup(bf);
325
326         return evsel->name ?: "unknown";
327 }
328
329 void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
330                         struct perf_evsel *first)
331 {
332         struct perf_event_attr *attr = &evsel->attr;
333         int track = !evsel->idx; /* only the first counter needs these */
334
335         attr->disabled = 1;
336         attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
337         attr->inherit       = !opts->no_inherit;
338         attr->read_format   = PERF_FORMAT_TOTAL_TIME_ENABLED |
339                               PERF_FORMAT_TOTAL_TIME_RUNNING |
340                               PERF_FORMAT_ID;
341
342         attr->sample_type  |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
343
344         /*
345          * We default some events to a 1 default interval. But keep
346          * it a weak assumption overridable by the user.
347          */
348         if (!attr->sample_period || (opts->user_freq != UINT_MAX &&
349                                      opts->user_interval != ULLONG_MAX)) {
350                 if (opts->freq) {
351                         attr->sample_type       |= PERF_SAMPLE_PERIOD;
352                         attr->freq              = 1;
353                         attr->sample_freq       = opts->freq;
354                 } else {
355                         attr->sample_period = opts->default_interval;
356                 }
357         }
358
359         if (opts->no_samples)
360                 attr->sample_freq = 0;
361
362         if (opts->inherit_stat)
363                 attr->inherit_stat = 1;
364
365         if (opts->sample_address) {
366                 attr->sample_type       |= PERF_SAMPLE_ADDR;
367                 attr->mmap_data = track;
368         }
369
370         if (opts->call_graph)
371                 attr->sample_type       |= PERF_SAMPLE_CALLCHAIN;
372
373         if (perf_target__has_cpu(&opts->target))
374                 attr->sample_type       |= PERF_SAMPLE_CPU;
375
376         if (opts->period)
377                 attr->sample_type       |= PERF_SAMPLE_PERIOD;
378
379         if (!opts->sample_id_all_missing &&
380             (opts->sample_time || !opts->no_inherit ||
381              perf_target__has_cpu(&opts->target)))
382                 attr->sample_type       |= PERF_SAMPLE_TIME;
383
384         if (opts->raw_samples) {
385                 attr->sample_type       |= PERF_SAMPLE_TIME;
386                 attr->sample_type       |= PERF_SAMPLE_RAW;
387                 attr->sample_type       |= PERF_SAMPLE_CPU;
388         }
389
390         if (opts->no_delay) {
391                 attr->watermark = 0;
392                 attr->wakeup_events = 1;
393         }
394         if (opts->branch_stack) {
395                 attr->sample_type       |= PERF_SAMPLE_BRANCH_STACK;
396                 attr->branch_sample_type = opts->branch_stack;
397         }
398
399         attr->mmap = track;
400         attr->comm = track;
401
402         if (perf_target__none(&opts->target) &&
403             (!opts->group || evsel == first)) {
404                 attr->enable_on_exec = 1;
405         }
406 }
407
408 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
409 {
410         int cpu, thread;
411         evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
412
413         if (evsel->fd) {
414                 for (cpu = 0; cpu < ncpus; cpu++) {
415                         for (thread = 0; thread < nthreads; thread++) {
416                                 FD(evsel, cpu, thread) = -1;
417                         }
418                 }
419         }
420
421         return evsel->fd != NULL ? 0 : -ENOMEM;
422 }
423
424 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
425 {
426         evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
427         if (evsel->sample_id == NULL)
428                 return -ENOMEM;
429
430         evsel->id = zalloc(ncpus * nthreads * sizeof(u64));
431         if (evsel->id == NULL) {
432                 xyarray__delete(evsel->sample_id);
433                 evsel->sample_id = NULL;
434                 return -ENOMEM;
435         }
436
437         return 0;
438 }
439
440 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
441 {
442         evsel->counts = zalloc((sizeof(*evsel->counts) +
443                                 (ncpus * sizeof(struct perf_counts_values))));
444         return evsel->counts != NULL ? 0 : -ENOMEM;
445 }
446
447 void perf_evsel__free_fd(struct perf_evsel *evsel)
448 {
449         xyarray__delete(evsel->fd);
450         evsel->fd = NULL;
451 }
452
453 void perf_evsel__free_id(struct perf_evsel *evsel)
454 {
455         xyarray__delete(evsel->sample_id);
456         evsel->sample_id = NULL;
457         free(evsel->id);
458         evsel->id = NULL;
459 }
460
461 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
462 {
463         int cpu, thread;
464
465         for (cpu = 0; cpu < ncpus; cpu++)
466                 for (thread = 0; thread < nthreads; ++thread) {
467                         close(FD(evsel, cpu, thread));
468                         FD(evsel, cpu, thread) = -1;
469                 }
470 }
471
472 void perf_evsel__exit(struct perf_evsel *evsel)
473 {
474         assert(list_empty(&evsel->node));
475         xyarray__delete(evsel->fd);
476         xyarray__delete(evsel->sample_id);
477         free(evsel->id);
478 }
479
480 void perf_evsel__delete(struct perf_evsel *evsel)
481 {
482         perf_evsel__exit(evsel);
483         close_cgroup(evsel->cgrp);
484         free(evsel->name);
485         free(evsel);
486 }
487
488 int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
489                               int cpu, int thread, bool scale)
490 {
491         struct perf_counts_values count;
492         size_t nv = scale ? 3 : 1;
493
494         if (FD(evsel, cpu, thread) < 0)
495                 return -EINVAL;
496
497         if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
498                 return -ENOMEM;
499
500         if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
501                 return -errno;
502
503         if (scale) {
504                 if (count.run == 0)
505                         count.val = 0;
506                 else if (count.run < count.ena)
507                         count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
508         } else
509                 count.ena = count.run = 0;
510
511         evsel->counts->cpu[cpu] = count;
512         return 0;
513 }
514
515 int __perf_evsel__read(struct perf_evsel *evsel,
516                        int ncpus, int nthreads, bool scale)
517 {
518         size_t nv = scale ? 3 : 1;
519         int cpu, thread;
520         struct perf_counts_values *aggr = &evsel->counts->aggr, count;
521
522         aggr->val = aggr->ena = aggr->run = 0;
523
524         for (cpu = 0; cpu < ncpus; cpu++) {
525                 for (thread = 0; thread < nthreads; thread++) {
526                         if (FD(evsel, cpu, thread) < 0)
527                                 continue;
528
529                         if (readn(FD(evsel, cpu, thread),
530                                   &count, nv * sizeof(u64)) < 0)
531                                 return -errno;
532
533                         aggr->val += count.val;
534                         if (scale) {
535                                 aggr->ena += count.ena;
536                                 aggr->run += count.run;
537                         }
538                 }
539         }
540
541         evsel->counts->scaled = 0;
542         if (scale) {
543                 if (aggr->run == 0) {
544                         evsel->counts->scaled = -1;
545                         aggr->val = 0;
546                         return 0;
547                 }
548
549                 if (aggr->run < aggr->ena) {
550                         evsel->counts->scaled = 1;
551                         aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
552                 }
553         } else
554                 aggr->ena = aggr->run = 0;
555
556         return 0;
557 }
558
559 static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
560                               struct thread_map *threads, bool group,
561                               struct xyarray *group_fds)
562 {
563         int cpu, thread;
564         unsigned long flags = 0;
565         int pid = -1, err;
566
567         if (evsel->fd == NULL &&
568             perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
569                 return -ENOMEM;
570
571         if (evsel->cgrp) {
572                 flags = PERF_FLAG_PID_CGROUP;
573                 pid = evsel->cgrp->fd;
574         }
575
576         for (cpu = 0; cpu < cpus->nr; cpu++) {
577                 int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1;
578
579                 for (thread = 0; thread < threads->nr; thread++) {
580
581                         if (!evsel->cgrp)
582                                 pid = threads->map[thread];
583
584                         FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
585                                                                      pid,
586                                                                      cpus->map[cpu],
587                                                                      group_fd, flags);
588                         if (FD(evsel, cpu, thread) < 0) {
589                                 err = -errno;
590                                 goto out_close;
591                         }
592
593                         if (group && group_fd == -1)
594                                 group_fd = FD(evsel, cpu, thread);
595                 }
596         }
597
598         return 0;
599
600 out_close:
601         do {
602                 while (--thread >= 0) {
603                         close(FD(evsel, cpu, thread));
604                         FD(evsel, cpu, thread) = -1;
605                 }
606                 thread = threads->nr;
607         } while (--cpu >= 0);
608         return err;
609 }
610
611 void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads)
612 {
613         if (evsel->fd == NULL)
614                 return;
615
616         perf_evsel__close_fd(evsel, ncpus, nthreads);
617         perf_evsel__free_fd(evsel);
618         evsel->fd = NULL;
619 }
620
621 static struct {
622         struct cpu_map map;
623         int cpus[1];
624 } empty_cpu_map = {
625         .map.nr = 1,
626         .cpus   = { -1, },
627 };
628
629 static struct {
630         struct thread_map map;
631         int threads[1];
632 } empty_thread_map = {
633         .map.nr  = 1,
634         .threads = { -1, },
635 };
636
637 int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
638                      struct thread_map *threads, bool group,
639                      struct xyarray *group_fd)
640 {
641         if (cpus == NULL) {
642                 /* Work around old compiler warnings about strict aliasing */
643                 cpus = &empty_cpu_map.map;
644         }
645
646         if (threads == NULL)
647                 threads = &empty_thread_map.map;
648
649         return __perf_evsel__open(evsel, cpus, threads, group, group_fd);
650 }
651
652 int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
653                              struct cpu_map *cpus, bool group,
654                              struct xyarray *group_fd)
655 {
656         return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group,
657                                   group_fd);
658 }
659
660 int perf_evsel__open_per_thread(struct perf_evsel *evsel,
661                                 struct thread_map *threads, bool group,
662                                 struct xyarray *group_fd)
663 {
664         return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group,
665                                   group_fd);
666 }
667
668 static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
669                                        struct perf_sample *sample,
670                                        bool swapped)
671 {
672         const u64 *array = event->sample.array;
673         union u64_swap u;
674
675         array += ((event->header.size -
676                    sizeof(event->header)) / sizeof(u64)) - 1;
677
678         if (type & PERF_SAMPLE_CPU) {
679                 u.val64 = *array;
680                 if (swapped) {
681                         /* undo swap of u64, then swap on individual u32s */
682                         u.val64 = bswap_64(u.val64);
683                         u.val32[0] = bswap_32(u.val32[0]);
684                 }
685
686                 sample->cpu = u.val32[0];
687                 array--;
688         }
689
690         if (type & PERF_SAMPLE_STREAM_ID) {
691                 sample->stream_id = *array;
692                 array--;
693         }
694
695         if (type & PERF_SAMPLE_ID) {
696                 sample->id = *array;
697                 array--;
698         }
699
700         if (type & PERF_SAMPLE_TIME) {
701                 sample->time = *array;
702                 array--;
703         }
704
705         if (type & PERF_SAMPLE_TID) {
706                 u.val64 = *array;
707                 if (swapped) {
708                         /* undo swap of u64, then swap on individual u32s */
709                         u.val64 = bswap_64(u.val64);
710                         u.val32[0] = bswap_32(u.val32[0]);
711                         u.val32[1] = bswap_32(u.val32[1]);
712                 }
713
714                 sample->pid = u.val32[0];
715                 sample->tid = u.val32[1];
716         }
717
718         return 0;
719 }
720
721 static bool sample_overlap(const union perf_event *event,
722                            const void *offset, u64 size)
723 {
724         const void *base = event;
725
726         if (offset + size > base + event->header.size)
727                 return true;
728
729         return false;
730 }
731
732 int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
733                              struct perf_sample *data, bool swapped)
734 {
735         u64 type = evsel->attr.sample_type;
736         const u64 *array;
737
738         /*
739          * used for cross-endian analysis. See git commit 65014ab3
740          * for why this goofiness is needed.
741          */
742         union u64_swap u;
743
744         memset(data, 0, sizeof(*data));
745         data->cpu = data->pid = data->tid = -1;
746         data->stream_id = data->id = data->time = -1ULL;
747         data->period = 1;
748
749         if (event->header.type != PERF_RECORD_SAMPLE) {
750                 if (!evsel->attr.sample_id_all)
751                         return 0;
752                 return perf_event__parse_id_sample(event, type, data, swapped);
753         }
754
755         array = event->sample.array;
756
757         if (evsel->sample_size + sizeof(event->header) > event->header.size)
758                 return -EFAULT;
759
760         if (type & PERF_SAMPLE_IP) {
761                 data->ip = event->ip.ip;
762                 array++;
763         }
764
765         if (type & PERF_SAMPLE_TID) {
766                 u.val64 = *array;
767                 if (swapped) {
768                         /* undo swap of u64, then swap on individual u32s */
769                         u.val64 = bswap_64(u.val64);
770                         u.val32[0] = bswap_32(u.val32[0]);
771                         u.val32[1] = bswap_32(u.val32[1]);
772                 }
773
774                 data->pid = u.val32[0];
775                 data->tid = u.val32[1];
776                 array++;
777         }
778
779         if (type & PERF_SAMPLE_TIME) {
780                 data->time = *array;
781                 array++;
782         }
783
784         data->addr = 0;
785         if (type & PERF_SAMPLE_ADDR) {
786                 data->addr = *array;
787                 array++;
788         }
789
790         data->id = -1ULL;
791         if (type & PERF_SAMPLE_ID) {
792                 data->id = *array;
793                 array++;
794         }
795
796         if (type & PERF_SAMPLE_STREAM_ID) {
797                 data->stream_id = *array;
798                 array++;
799         }
800
801         if (type & PERF_SAMPLE_CPU) {
802
803                 u.val64 = *array;
804                 if (swapped) {
805                         /* undo swap of u64, then swap on individual u32s */
806                         u.val64 = bswap_64(u.val64);
807                         u.val32[0] = bswap_32(u.val32[0]);
808                 }
809
810                 data->cpu = u.val32[0];
811                 array++;
812         }
813
814         if (type & PERF_SAMPLE_PERIOD) {
815                 data->period = *array;
816                 array++;
817         }
818
819         if (type & PERF_SAMPLE_READ) {
820                 fprintf(stderr, "PERF_SAMPLE_READ is unsupported for now\n");
821                 return -1;
822         }
823
824         if (type & PERF_SAMPLE_CALLCHAIN) {
825                 if (sample_overlap(event, array, sizeof(data->callchain->nr)))
826                         return -EFAULT;
827
828                 data->callchain = (struct ip_callchain *)array;
829
830                 if (sample_overlap(event, array, data->callchain->nr))
831                         return -EFAULT;
832
833                 array += 1 + data->callchain->nr;
834         }
835
836         if (type & PERF_SAMPLE_RAW) {
837                 const u64 *pdata;
838
839                 u.val64 = *array;
840                 if (WARN_ONCE(swapped,
841                               "Endianness of raw data not corrected!\n")) {
842                         /* undo swap of u64, then swap on individual u32s */
843                         u.val64 = bswap_64(u.val64);
844                         u.val32[0] = bswap_32(u.val32[0]);
845                         u.val32[1] = bswap_32(u.val32[1]);
846                 }
847
848                 if (sample_overlap(event, array, sizeof(u32)))
849                         return -EFAULT;
850
851                 data->raw_size = u.val32[0];
852                 pdata = (void *) array + sizeof(u32);
853
854                 if (sample_overlap(event, pdata, data->raw_size))
855                         return -EFAULT;
856
857                 data->raw_data = (void *) pdata;
858
859                 array = (void *)array + data->raw_size + sizeof(u32);
860         }
861
862         if (type & PERF_SAMPLE_BRANCH_STACK) {
863                 u64 sz;
864
865                 data->branch_stack = (struct branch_stack *)array;
866                 array++; /* nr */
867
868                 sz = data->branch_stack->nr * sizeof(struct branch_entry);
869                 sz /= sizeof(u64);
870                 array += sz;
871         }
872         return 0;
873 }
874
875 int perf_event__synthesize_sample(union perf_event *event, u64 type,
876                                   const struct perf_sample *sample,
877                                   bool swapped)
878 {
879         u64 *array;
880
881         /*
882          * used for cross-endian analysis. See git commit 65014ab3
883          * for why this goofiness is needed.
884          */
885         union u64_swap u;
886
887         array = event->sample.array;
888
889         if (type & PERF_SAMPLE_IP) {
890                 event->ip.ip = sample->ip;
891                 array++;
892         }
893
894         if (type & PERF_SAMPLE_TID) {
895                 u.val32[0] = sample->pid;
896                 u.val32[1] = sample->tid;
897                 if (swapped) {
898                         /*
899                          * Inverse of what is done in perf_evsel__parse_sample
900                          */
901                         u.val32[0] = bswap_32(u.val32[0]);
902                         u.val32[1] = bswap_32(u.val32[1]);
903                         u.val64 = bswap_64(u.val64);
904                 }
905
906                 *array = u.val64;
907                 array++;
908         }
909
910         if (type & PERF_SAMPLE_TIME) {
911                 *array = sample->time;
912                 array++;
913         }
914
915         if (type & PERF_SAMPLE_ADDR) {
916                 *array = sample->addr;
917                 array++;
918         }
919
920         if (type & PERF_SAMPLE_ID) {
921                 *array = sample->id;
922                 array++;
923         }
924
925         if (type & PERF_SAMPLE_STREAM_ID) {
926                 *array = sample->stream_id;
927                 array++;
928         }
929
930         if (type & PERF_SAMPLE_CPU) {
931                 u.val32[0] = sample->cpu;
932                 if (swapped) {
933                         /*
934                          * Inverse of what is done in perf_evsel__parse_sample
935                          */
936                         u.val32[0] = bswap_32(u.val32[0]);
937                         u.val64 = bswap_64(u.val64);
938                 }
939                 *array = u.val64;
940                 array++;
941         }
942
943         if (type & PERF_SAMPLE_PERIOD) {
944                 *array = sample->period;
945                 array++;
946         }
947
948         return 0;
949 }