blob: 905188bd1dfacfde14b45f75aed157ab83dcc944 [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>
Adrian Hunter85ed4722015-04-09 18:53:50 +030027#include <stdio.h>
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +030028#include <string.h>
29#include <errno.h>
30
Adrian Hunter718c6022015-04-09 18:53:42 +030031#include "../perf.h"
32#include "util.h"
33#include "evlist.h"
34#include "cpumap.h"
35#include "thread_map.h"
36#include "asm/bug.h"
37#include "auxtrace.h"
38
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +030039#include "event.h"
Adrian Hunter85ed4722015-04-09 18:53:50 +030040#include "session.h"
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +030041#include "debug.h"
Adrian Hunterf6986c952015-04-09 18:53:49 +030042#include "parse-options.h"
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +030043
Adrian Hunter718c6022015-04-09 18:53:42 +030044int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
45 struct auxtrace_mmap_params *mp,
46 void *userpg, int fd)
47{
48 struct perf_event_mmap_page *pc = userpg;
49
50#if BITS_PER_LONG != 64 && !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)
51 pr_err("Cannot use AUX area tracing mmaps\n");
52 return -1;
53#endif
54
55 WARN_ONCE(mm->base, "Uninitialized auxtrace_mmap\n");
56
57 mm->userpg = userpg;
58 mm->mask = mp->mask;
59 mm->len = mp->len;
60 mm->prev = 0;
61 mm->idx = mp->idx;
62 mm->tid = mp->tid;
63 mm->cpu = mp->cpu;
64
65 if (!mp->len) {
66 mm->base = NULL;
67 return 0;
68 }
69
70 pc->aux_offset = mp->offset;
71 pc->aux_size = mp->len;
72
73 mm->base = mmap(NULL, mp->len, mp->prot, MAP_SHARED, fd, mp->offset);
74 if (mm->base == MAP_FAILED) {
75 pr_debug2("failed to mmap AUX area\n");
76 mm->base = NULL;
77 return -1;
78 }
79
80 return 0;
81}
82
83void auxtrace_mmap__munmap(struct auxtrace_mmap *mm)
84{
85 if (mm->base) {
86 munmap(mm->base, mm->len);
87 mm->base = NULL;
88 }
89}
90
91void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
92 off_t auxtrace_offset,
93 unsigned int auxtrace_pages,
94 bool auxtrace_overwrite)
95{
96 if (auxtrace_pages) {
97 mp->offset = auxtrace_offset;
98 mp->len = auxtrace_pages * (size_t)page_size;
99 mp->mask = is_power_of_2(mp->len) ? mp->len - 1 : 0;
100 mp->prot = PROT_READ | (auxtrace_overwrite ? 0 : PROT_WRITE);
101 pr_debug2("AUX area mmap length %zu\n", mp->len);
102 } else {
103 mp->len = 0;
104 }
105}
106
107void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
108 struct perf_evlist *evlist, int idx,
109 bool per_cpu)
110{
111 mp->idx = idx;
112
113 if (per_cpu) {
114 mp->cpu = evlist->cpus->map[idx];
115 if (evlist->threads)
116 mp->tid = evlist->threads->map[0];
117 else
118 mp->tid = -1;
119 } else {
120 mp->cpu = -1;
121 mp->tid = evlist->threads->map[idx];
122 }
123}
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +0300124
125size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr)
126{
127 if (itr)
128 return itr->info_priv_size(itr);
129 return 0;
130}
131
132static int auxtrace_not_supported(void)
133{
134 pr_err("AUX area tracing is not supported on this architecture\n");
135 return -EINVAL;
136}
137
138int auxtrace_record__info_fill(struct auxtrace_record *itr,
139 struct perf_session *session,
140 struct auxtrace_info_event *auxtrace_info,
141 size_t priv_size)
142{
143 if (itr)
144 return itr->info_fill(itr, session, auxtrace_info, priv_size);
145 return auxtrace_not_supported();
146}
147
148void auxtrace_record__free(struct auxtrace_record *itr)
149{
150 if (itr)
151 itr->free(itr);
152}
153
154int auxtrace_record__options(struct auxtrace_record *itr,
155 struct perf_evlist *evlist,
156 struct record_opts *opts)
157{
158 if (itr)
159 return itr->recording_options(itr, evlist, opts);
160 return 0;
161}
162
163u64 auxtrace_record__reference(struct auxtrace_record *itr)
164{
165 if (itr)
166 return itr->reference(itr);
167 return 0;
168}
169
170struct auxtrace_record *__weak
171auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err)
172{
173 *err = 0;
174 return NULL;
175}
176
Adrian Hunter85ed4722015-04-09 18:53:50 +0300177void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type,
178 int code, int cpu, pid_t pid, pid_t tid, u64 ip,
179 const char *msg)
180{
181 size_t size;
182
183 memset(auxtrace_error, 0, sizeof(struct auxtrace_error_event));
184
185 auxtrace_error->header.type = PERF_RECORD_AUXTRACE_ERROR;
186 auxtrace_error->type = type;
187 auxtrace_error->code = code;
188 auxtrace_error->cpu = cpu;
189 auxtrace_error->pid = pid;
190 auxtrace_error->tid = tid;
191 auxtrace_error->ip = ip;
192 strlcpy(auxtrace_error->msg, msg, MAX_AUXTRACE_ERROR_MSG);
193
194 size = (void *)auxtrace_error->msg - (void *)auxtrace_error +
195 strlen(auxtrace_error->msg) + 1;
196 auxtrace_error->header.size = PERF_ALIGN(size, sizeof(u64));
197}
198
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +0300199int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr,
200 struct perf_tool *tool,
201 struct perf_session *session,
202 perf_event__handler_t process)
203{
204 union perf_event *ev;
205 size_t priv_size;
206 int err;
207
208 pr_debug2("Synthesizing auxtrace information\n");
209 priv_size = auxtrace_record__info_priv_size(itr);
210 ev = zalloc(sizeof(struct auxtrace_info_event) + priv_size);
211 if (!ev)
212 return -ENOMEM;
213
214 ev->auxtrace_info.header.type = PERF_RECORD_AUXTRACE_INFO;
215 ev->auxtrace_info.header.size = sizeof(struct auxtrace_info_event) +
216 priv_size;
217 err = auxtrace_record__info_fill(itr, session, &ev->auxtrace_info,
218 priv_size);
219 if (err)
220 goto out_free;
221
222 err = process(tool, ev, NULL, NULL);
223out_free:
224 free(ev);
225 return err;
226}
227
Adrian Hunterf6986c952015-04-09 18:53:49 +0300228#define PERF_ITRACE_DEFAULT_PERIOD_TYPE PERF_ITRACE_PERIOD_NANOSECS
229#define PERF_ITRACE_DEFAULT_PERIOD 100000
230#define PERF_ITRACE_DEFAULT_CALLCHAIN_SZ 16
231#define PERF_ITRACE_MAX_CALLCHAIN_SZ 1024
232
233void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts)
234{
235 synth_opts->instructions = true;
236 synth_opts->branches = true;
237 synth_opts->errors = true;
238 synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE;
239 synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD;
240 synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ;
241}
242
243/*
244 * Please check tools/perf/Documentation/perf-script.txt for information
245 * about the options parsed here, which is introduced after this cset,
246 * when support in 'perf script' for these options is introduced.
247 */
248int itrace_parse_synth_opts(const struct option *opt, const char *str,
249 int unset)
250{
251 struct itrace_synth_opts *synth_opts = opt->value;
252 const char *p;
253 char *endptr;
254
255 synth_opts->set = true;
256
257 if (unset) {
258 synth_opts->dont_decode = true;
259 return 0;
260 }
261
262 if (!str) {
263 itrace_synth_opts__set_default(synth_opts);
264 return 0;
265 }
266
267 for (p = str; *p;) {
268 switch (*p++) {
269 case 'i':
270 synth_opts->instructions = true;
271 while (*p == ' ' || *p == ',')
272 p += 1;
273 if (isdigit(*p)) {
274 synth_opts->period = strtoull(p, &endptr, 10);
275 p = endptr;
276 while (*p == ' ' || *p == ',')
277 p += 1;
278 switch (*p++) {
279 case 'i':
280 synth_opts->period_type =
281 PERF_ITRACE_PERIOD_INSTRUCTIONS;
282 break;
283 case 't':
284 synth_opts->period_type =
285 PERF_ITRACE_PERIOD_TICKS;
286 break;
287 case 'm':
288 synth_opts->period *= 1000;
289 /* Fall through */
290 case 'u':
291 synth_opts->period *= 1000;
292 /* Fall through */
293 case 'n':
294 if (*p++ != 's')
295 goto out_err;
296 synth_opts->period_type =
297 PERF_ITRACE_PERIOD_NANOSECS;
298 break;
299 case '\0':
300 goto out;
301 default:
302 goto out_err;
303 }
304 }
305 break;
306 case 'b':
307 synth_opts->branches = true;
308 break;
309 case 'e':
310 synth_opts->errors = true;
311 break;
312 case 'd':
313 synth_opts->log = true;
314 break;
315 case 'c':
316 synth_opts->branches = true;
317 synth_opts->calls = true;
318 break;
319 case 'r':
320 synth_opts->branches = true;
321 synth_opts->returns = true;
322 break;
323 case 'g':
324 synth_opts->instructions = true;
325 synth_opts->callchain = true;
326 synth_opts->callchain_sz =
327 PERF_ITRACE_DEFAULT_CALLCHAIN_SZ;
328 while (*p == ' ' || *p == ',')
329 p += 1;
330 if (isdigit(*p)) {
331 unsigned int val;
332
333 val = strtoul(p, &endptr, 10);
334 p = endptr;
335 if (!val || val > PERF_ITRACE_MAX_CALLCHAIN_SZ)
336 goto out_err;
337 synth_opts->callchain_sz = val;
338 }
339 break;
340 case ' ':
341 case ',':
342 break;
343 default:
344 goto out_err;
345 }
346 }
347out:
348 if (synth_opts->instructions) {
349 if (!synth_opts->period_type)
350 synth_opts->period_type =
351 PERF_ITRACE_DEFAULT_PERIOD_TYPE;
352 if (!synth_opts->period)
353 synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD;
354 }
355
356 return 0;
357
358out_err:
359 pr_err("Bad Instruction Tracing options '%s'\n", str);
360 return -EINVAL;
361}
362
Adrian Hunter85ed4722015-04-09 18:53:50 +0300363static const char * const auxtrace_error_type_name[] = {
364 [PERF_AUXTRACE_ERROR_ITRACE] = "instruction trace",
365};
366
367static const char *auxtrace_error_name(int type)
368{
369 const char *error_type_name = NULL;
370
371 if (type < PERF_AUXTRACE_ERROR_MAX)
372 error_type_name = auxtrace_error_type_name[type];
373 if (!error_type_name)
374 error_type_name = "unknown AUX";
375 return error_type_name;
376}
377
378size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp)
379{
380 struct auxtrace_error_event *e = &event->auxtrace_error;
381 int ret;
382
383 ret = fprintf(fp, " %s error type %u",
384 auxtrace_error_name(e->type), e->type);
385 ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRIx64" code %u: %s\n",
386 e->cpu, e->pid, e->tid, e->ip, e->code, e->msg);
387 return ret;
388}
389
390void perf_session__auxtrace_error_inc(struct perf_session *session,
391 union perf_event *event)
392{
393 struct auxtrace_error_event *e = &event->auxtrace_error;
394
395 if (e->type < PERF_AUXTRACE_ERROR_MAX)
396 session->evlist->stats.nr_auxtrace_errors[e->type] += 1;
397}
398
399void events_stats__auxtrace_error_warn(const struct events_stats *stats)
400{
401 int i;
402
403 for (i = 0; i < PERF_AUXTRACE_ERROR_MAX; i++) {
404 if (!stats->nr_auxtrace_errors[i])
405 continue;
406 ui__warning("%u %s errors\n",
407 stats->nr_auxtrace_errors[i],
408 auxtrace_error_name(i));
409 }
410}
411
412int perf_event__process_auxtrace_error(struct perf_tool *tool __maybe_unused,
413 union perf_event *event,
414 struct perf_session *session __maybe_unused)
415{
416 perf_event__fprintf_auxtrace_error(event, stdout);
417 return 0;
418}
419
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +0300420int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
421 struct perf_tool *tool, process_auxtrace_t fn)
422{
423 u64 head = auxtrace_mmap__read_head(mm);
424 u64 old = mm->prev, offset, ref;
425 unsigned char *data = mm->base;
426 size_t size, head_off, old_off, len1, len2, padding;
427 union perf_event ev;
428 void *data1, *data2;
429
430 if (old == head)
431 return 0;
432
433 pr_debug3("auxtrace idx %d old %#"PRIx64" head %#"PRIx64" diff %#"PRIx64"\n",
434 mm->idx, old, head, head - old);
435
436 if (mm->mask) {
437 head_off = head & mm->mask;
438 old_off = old & mm->mask;
439 } else {
440 head_off = head % mm->len;
441 old_off = old % mm->len;
442 }
443
444 if (head_off > old_off)
445 size = head_off - old_off;
446 else
447 size = mm->len - (old_off - head_off);
448
449 ref = auxtrace_record__reference(itr);
450
451 if (head > old || size <= head || mm->mask) {
452 offset = head - size;
453 } else {
454 /*
455 * When the buffer size is not a power of 2, 'head' wraps at the
456 * highest multiple of the buffer size, so we have to subtract
457 * the remainder here.
458 */
459 u64 rem = (0ULL - mm->len) % mm->len;
460
461 offset = head - size - rem;
462 }
463
464 if (size > head_off) {
465 len1 = size - head_off;
466 data1 = &data[mm->len - len1];
467 len2 = head_off;
468 data2 = &data[0];
469 } else {
470 len1 = size;
471 data1 = &data[head_off - len1];
472 len2 = 0;
473 data2 = NULL;
474 }
475
476 /* padding must be written by fn() e.g. record__process_auxtrace() */
477 padding = size & 7;
478 if (padding)
479 padding = 8 - padding;
480
481 memset(&ev, 0, sizeof(ev));
482 ev.auxtrace.header.type = PERF_RECORD_AUXTRACE;
483 ev.auxtrace.header.size = sizeof(ev.auxtrace);
484 ev.auxtrace.size = size + padding;
485 ev.auxtrace.offset = offset;
486 ev.auxtrace.reference = ref;
487 ev.auxtrace.idx = mm->idx;
488 ev.auxtrace.tid = mm->tid;
489 ev.auxtrace.cpu = mm->cpu;
490
491 if (fn(tool, &ev, data1, len1, data2, len2))
492 return -1;
493
494 mm->prev = head;
495
496 auxtrace_mmap__write_tail(mm, head);
497 if (itr->read_finish) {
498 int err;
499
500 err = itr->read_finish(itr, mm->idx);
501 if (err < 0)
502 return err;
503 }
504
505 return 1;
506}