blob: db40d6c6c01069bbf201fe0209c2c6f98c918992 [file] [log] [blame]
Adrian Hunter718c6022015-04-09 18:53:42 +03001/*
2 * auxtrace.c: AUX area trace support
3 * Copyright (c) 2013-2015, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16#include <sys/types.h>
17#include <sys/mman.h>
18#include <stdbool.h>
19
20#include <linux/kernel.h>
21#include <linux/perf_event.h>
22#include <linux/types.h>
23#include <linux/bitops.h>
24#include <linux/log2.h>
25
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +030026#include <stdlib.h>
27#include <string.h>
28#include <errno.h>
29
Adrian Hunter718c6022015-04-09 18:53:42 +030030#include "../perf.h"
31#include "util.h"
32#include "evlist.h"
33#include "cpumap.h"
34#include "thread_map.h"
35#include "asm/bug.h"
36#include "auxtrace.h"
37
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +030038#include "event.h"
39#include "debug.h"
Adrian Hunterf6986c952015-04-09 18:53:49 +030040#include "parse-options.h"
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +030041
Adrian Hunter718c6022015-04-09 18:53:42 +030042int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
43 struct auxtrace_mmap_params *mp,
44 void *userpg, int fd)
45{
46 struct perf_event_mmap_page *pc = userpg;
47
48#if BITS_PER_LONG != 64 && !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)
49 pr_err("Cannot use AUX area tracing mmaps\n");
50 return -1;
51#endif
52
53 WARN_ONCE(mm->base, "Uninitialized auxtrace_mmap\n");
54
55 mm->userpg = userpg;
56 mm->mask = mp->mask;
57 mm->len = mp->len;
58 mm->prev = 0;
59 mm->idx = mp->idx;
60 mm->tid = mp->tid;
61 mm->cpu = mp->cpu;
62
63 if (!mp->len) {
64 mm->base = NULL;
65 return 0;
66 }
67
68 pc->aux_offset = mp->offset;
69 pc->aux_size = mp->len;
70
71 mm->base = mmap(NULL, mp->len, mp->prot, MAP_SHARED, fd, mp->offset);
72 if (mm->base == MAP_FAILED) {
73 pr_debug2("failed to mmap AUX area\n");
74 mm->base = NULL;
75 return -1;
76 }
77
78 return 0;
79}
80
81void auxtrace_mmap__munmap(struct auxtrace_mmap *mm)
82{
83 if (mm->base) {
84 munmap(mm->base, mm->len);
85 mm->base = NULL;
86 }
87}
88
89void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
90 off_t auxtrace_offset,
91 unsigned int auxtrace_pages,
92 bool auxtrace_overwrite)
93{
94 if (auxtrace_pages) {
95 mp->offset = auxtrace_offset;
96 mp->len = auxtrace_pages * (size_t)page_size;
97 mp->mask = is_power_of_2(mp->len) ? mp->len - 1 : 0;
98 mp->prot = PROT_READ | (auxtrace_overwrite ? 0 : PROT_WRITE);
99 pr_debug2("AUX area mmap length %zu\n", mp->len);
100 } else {
101 mp->len = 0;
102 }
103}
104
105void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
106 struct perf_evlist *evlist, int idx,
107 bool per_cpu)
108{
109 mp->idx = idx;
110
111 if (per_cpu) {
112 mp->cpu = evlist->cpus->map[idx];
113 if (evlist->threads)
114 mp->tid = evlist->threads->map[0];
115 else
116 mp->tid = -1;
117 } else {
118 mp->cpu = -1;
119 mp->tid = evlist->threads->map[idx];
120 }
121}
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +0300122
123size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr)
124{
125 if (itr)
126 return itr->info_priv_size(itr);
127 return 0;
128}
129
130static int auxtrace_not_supported(void)
131{
132 pr_err("AUX area tracing is not supported on this architecture\n");
133 return -EINVAL;
134}
135
136int auxtrace_record__info_fill(struct auxtrace_record *itr,
137 struct perf_session *session,
138 struct auxtrace_info_event *auxtrace_info,
139 size_t priv_size)
140{
141 if (itr)
142 return itr->info_fill(itr, session, auxtrace_info, priv_size);
143 return auxtrace_not_supported();
144}
145
146void auxtrace_record__free(struct auxtrace_record *itr)
147{
148 if (itr)
149 itr->free(itr);
150}
151
152int auxtrace_record__options(struct auxtrace_record *itr,
153 struct perf_evlist *evlist,
154 struct record_opts *opts)
155{
156 if (itr)
157 return itr->recording_options(itr, evlist, opts);
158 return 0;
159}
160
161u64 auxtrace_record__reference(struct auxtrace_record *itr)
162{
163 if (itr)
164 return itr->reference(itr);
165 return 0;
166}
167
168struct auxtrace_record *__weak
169auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err)
170{
171 *err = 0;
172 return NULL;
173}
174
175int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr,
176 struct perf_tool *tool,
177 struct perf_session *session,
178 perf_event__handler_t process)
179{
180 union perf_event *ev;
181 size_t priv_size;
182 int err;
183
184 pr_debug2("Synthesizing auxtrace information\n");
185 priv_size = auxtrace_record__info_priv_size(itr);
186 ev = zalloc(sizeof(struct auxtrace_info_event) + priv_size);
187 if (!ev)
188 return -ENOMEM;
189
190 ev->auxtrace_info.header.type = PERF_RECORD_AUXTRACE_INFO;
191 ev->auxtrace_info.header.size = sizeof(struct auxtrace_info_event) +
192 priv_size;
193 err = auxtrace_record__info_fill(itr, session, &ev->auxtrace_info,
194 priv_size);
195 if (err)
196 goto out_free;
197
198 err = process(tool, ev, NULL, NULL);
199out_free:
200 free(ev);
201 return err;
202}
203
Adrian Hunterf6986c952015-04-09 18:53:49 +0300204#define PERF_ITRACE_DEFAULT_PERIOD_TYPE PERF_ITRACE_PERIOD_NANOSECS
205#define PERF_ITRACE_DEFAULT_PERIOD 100000
206#define PERF_ITRACE_DEFAULT_CALLCHAIN_SZ 16
207#define PERF_ITRACE_MAX_CALLCHAIN_SZ 1024
208
209void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts)
210{
211 synth_opts->instructions = true;
212 synth_opts->branches = true;
213 synth_opts->errors = true;
214 synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE;
215 synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD;
216 synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ;
217}
218
219/*
220 * Please check tools/perf/Documentation/perf-script.txt for information
221 * about the options parsed here, which is introduced after this cset,
222 * when support in 'perf script' for these options is introduced.
223 */
224int itrace_parse_synth_opts(const struct option *opt, const char *str,
225 int unset)
226{
227 struct itrace_synth_opts *synth_opts = opt->value;
228 const char *p;
229 char *endptr;
230
231 synth_opts->set = true;
232
233 if (unset) {
234 synth_opts->dont_decode = true;
235 return 0;
236 }
237
238 if (!str) {
239 itrace_synth_opts__set_default(synth_opts);
240 return 0;
241 }
242
243 for (p = str; *p;) {
244 switch (*p++) {
245 case 'i':
246 synth_opts->instructions = true;
247 while (*p == ' ' || *p == ',')
248 p += 1;
249 if (isdigit(*p)) {
250 synth_opts->period = strtoull(p, &endptr, 10);
251 p = endptr;
252 while (*p == ' ' || *p == ',')
253 p += 1;
254 switch (*p++) {
255 case 'i':
256 synth_opts->period_type =
257 PERF_ITRACE_PERIOD_INSTRUCTIONS;
258 break;
259 case 't':
260 synth_opts->period_type =
261 PERF_ITRACE_PERIOD_TICKS;
262 break;
263 case 'm':
264 synth_opts->period *= 1000;
265 /* Fall through */
266 case 'u':
267 synth_opts->period *= 1000;
268 /* Fall through */
269 case 'n':
270 if (*p++ != 's')
271 goto out_err;
272 synth_opts->period_type =
273 PERF_ITRACE_PERIOD_NANOSECS;
274 break;
275 case '\0':
276 goto out;
277 default:
278 goto out_err;
279 }
280 }
281 break;
282 case 'b':
283 synth_opts->branches = true;
284 break;
285 case 'e':
286 synth_opts->errors = true;
287 break;
288 case 'd':
289 synth_opts->log = true;
290 break;
291 case 'c':
292 synth_opts->branches = true;
293 synth_opts->calls = true;
294 break;
295 case 'r':
296 synth_opts->branches = true;
297 synth_opts->returns = true;
298 break;
299 case 'g':
300 synth_opts->instructions = true;
301 synth_opts->callchain = true;
302 synth_opts->callchain_sz =
303 PERF_ITRACE_DEFAULT_CALLCHAIN_SZ;
304 while (*p == ' ' || *p == ',')
305 p += 1;
306 if (isdigit(*p)) {
307 unsigned int val;
308
309 val = strtoul(p, &endptr, 10);
310 p = endptr;
311 if (!val || val > PERF_ITRACE_MAX_CALLCHAIN_SZ)
312 goto out_err;
313 synth_opts->callchain_sz = val;
314 }
315 break;
316 case ' ':
317 case ',':
318 break;
319 default:
320 goto out_err;
321 }
322 }
323out:
324 if (synth_opts->instructions) {
325 if (!synth_opts->period_type)
326 synth_opts->period_type =
327 PERF_ITRACE_DEFAULT_PERIOD_TYPE;
328 if (!synth_opts->period)
329 synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD;
330 }
331
332 return 0;
333
334out_err:
335 pr_err("Bad Instruction Tracing options '%s'\n", str);
336 return -EINVAL;
337}
338
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +0300339int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
340 struct perf_tool *tool, process_auxtrace_t fn)
341{
342 u64 head = auxtrace_mmap__read_head(mm);
343 u64 old = mm->prev, offset, ref;
344 unsigned char *data = mm->base;
345 size_t size, head_off, old_off, len1, len2, padding;
346 union perf_event ev;
347 void *data1, *data2;
348
349 if (old == head)
350 return 0;
351
352 pr_debug3("auxtrace idx %d old %#"PRIx64" head %#"PRIx64" diff %#"PRIx64"\n",
353 mm->idx, old, head, head - old);
354
355 if (mm->mask) {
356 head_off = head & mm->mask;
357 old_off = old & mm->mask;
358 } else {
359 head_off = head % mm->len;
360 old_off = old % mm->len;
361 }
362
363 if (head_off > old_off)
364 size = head_off - old_off;
365 else
366 size = mm->len - (old_off - head_off);
367
368 ref = auxtrace_record__reference(itr);
369
370 if (head > old || size <= head || mm->mask) {
371 offset = head - size;
372 } else {
373 /*
374 * When the buffer size is not a power of 2, 'head' wraps at the
375 * highest multiple of the buffer size, so we have to subtract
376 * the remainder here.
377 */
378 u64 rem = (0ULL - mm->len) % mm->len;
379
380 offset = head - size - rem;
381 }
382
383 if (size > head_off) {
384 len1 = size - head_off;
385 data1 = &data[mm->len - len1];
386 len2 = head_off;
387 data2 = &data[0];
388 } else {
389 len1 = size;
390 data1 = &data[head_off - len1];
391 len2 = 0;
392 data2 = NULL;
393 }
394
395 /* padding must be written by fn() e.g. record__process_auxtrace() */
396 padding = size & 7;
397 if (padding)
398 padding = 8 - padding;
399
400 memset(&ev, 0, sizeof(ev));
401 ev.auxtrace.header.type = PERF_RECORD_AUXTRACE;
402 ev.auxtrace.header.size = sizeof(ev.auxtrace);
403 ev.auxtrace.size = size + padding;
404 ev.auxtrace.offset = offset;
405 ev.auxtrace.reference = ref;
406 ev.auxtrace.idx = mm->idx;
407 ev.auxtrace.tid = mm->tid;
408 ev.auxtrace.cpu = mm->cpu;
409
410 if (fn(tool, &ev, data1, len1, data2, len2))
411 return -1;
412
413 mm->prev = head;
414
415 auxtrace_mmap__write_tail(mm, head);
416 if (itr->read_finish) {
417 int err;
418
419 err = itr->read_finish(itr, mm->idx);
420 if (err < 0)
421 return err;
422 }
423
424 return 1;
425}