blob: 252417ac28e248dfc8ae0bef8bb092cba5cd417e [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>
Adrian Huntere5027892015-04-21 12:21:51 +030025#include <linux/string.h>
Adrian Hunter718c6022015-04-09 18:53:42 +030026
Adrian Huntere5027892015-04-21 12:21:51 +030027#include <sys/param.h>
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +030028#include <stdlib.h>
Adrian Hunter85ed4722015-04-09 18:53:50 +030029#include <stdio.h>
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +030030#include <string.h>
Adrian Huntere5027892015-04-21 12:21:51 +030031#include <limits.h>
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +030032#include <errno.h>
Adrian Huntere5027892015-04-21 12:21:51 +030033#include <linux/list.h>
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +030034
Adrian Hunter718c6022015-04-09 18:53:42 +030035#include "../perf.h"
36#include "util.h"
37#include "evlist.h"
38#include "cpumap.h"
39#include "thread_map.h"
40#include "asm/bug.h"
41#include "auxtrace.h"
42
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +030043#include "event.h"
Adrian Hunter85ed4722015-04-09 18:53:50 +030044#include "session.h"
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +030045#include "debug.h"
Adrian Hunterf6986c952015-04-09 18:53:49 +030046#include "parse-options.h"
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +030047
Adrian Hunter718c6022015-04-09 18:53:42 +030048int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
49 struct auxtrace_mmap_params *mp,
50 void *userpg, int fd)
51{
52 struct perf_event_mmap_page *pc = userpg;
53
54#if BITS_PER_LONG != 64 && !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)
55 pr_err("Cannot use AUX area tracing mmaps\n");
56 return -1;
57#endif
58
59 WARN_ONCE(mm->base, "Uninitialized auxtrace_mmap\n");
60
61 mm->userpg = userpg;
62 mm->mask = mp->mask;
63 mm->len = mp->len;
64 mm->prev = 0;
65 mm->idx = mp->idx;
66 mm->tid = mp->tid;
67 mm->cpu = mp->cpu;
68
69 if (!mp->len) {
70 mm->base = NULL;
71 return 0;
72 }
73
74 pc->aux_offset = mp->offset;
75 pc->aux_size = mp->len;
76
77 mm->base = mmap(NULL, mp->len, mp->prot, MAP_SHARED, fd, mp->offset);
78 if (mm->base == MAP_FAILED) {
79 pr_debug2("failed to mmap AUX area\n");
80 mm->base = NULL;
81 return -1;
82 }
83
84 return 0;
85}
86
87void auxtrace_mmap__munmap(struct auxtrace_mmap *mm)
88{
89 if (mm->base) {
90 munmap(mm->base, mm->len);
91 mm->base = NULL;
92 }
93}
94
95void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
96 off_t auxtrace_offset,
97 unsigned int auxtrace_pages,
98 bool auxtrace_overwrite)
99{
100 if (auxtrace_pages) {
101 mp->offset = auxtrace_offset;
102 mp->len = auxtrace_pages * (size_t)page_size;
103 mp->mask = is_power_of_2(mp->len) ? mp->len - 1 : 0;
104 mp->prot = PROT_READ | (auxtrace_overwrite ? 0 : PROT_WRITE);
105 pr_debug2("AUX area mmap length %zu\n", mp->len);
106 } else {
107 mp->len = 0;
108 }
109}
110
111void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
112 struct perf_evlist *evlist, int idx,
113 bool per_cpu)
114{
115 mp->idx = idx;
116
117 if (per_cpu) {
118 mp->cpu = evlist->cpus->map[idx];
119 if (evlist->threads)
120 mp->tid = evlist->threads->map[0];
121 else
122 mp->tid = -1;
123 } else {
124 mp->cpu = -1;
125 mp->tid = evlist->threads->map[idx];
126 }
127}
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +0300128
Adrian Huntere5027892015-04-21 12:21:51 +0300129#define AUXTRACE_INIT_NR_QUEUES 32
130
131static struct auxtrace_queue *auxtrace_alloc_queue_array(unsigned int nr_queues)
132{
133 struct auxtrace_queue *queue_array;
134 unsigned int max_nr_queues, i;
135
136 max_nr_queues = UINT_MAX / sizeof(struct auxtrace_queue);
137 if (nr_queues > max_nr_queues)
138 return NULL;
139
140 queue_array = calloc(nr_queues, sizeof(struct auxtrace_queue));
141 if (!queue_array)
142 return NULL;
143
144 for (i = 0; i < nr_queues; i++) {
145 INIT_LIST_HEAD(&queue_array[i].head);
146 queue_array[i].priv = NULL;
147 }
148
149 return queue_array;
150}
151
152int auxtrace_queues__init(struct auxtrace_queues *queues)
153{
154 queues->nr_queues = AUXTRACE_INIT_NR_QUEUES;
155 queues->queue_array = auxtrace_alloc_queue_array(queues->nr_queues);
156 if (!queues->queue_array)
157 return -ENOMEM;
158 return 0;
159}
160
161static int auxtrace_queues__grow(struct auxtrace_queues *queues,
162 unsigned int new_nr_queues)
163{
164 unsigned int nr_queues = queues->nr_queues;
165 struct auxtrace_queue *queue_array;
166 unsigned int i;
167
168 if (!nr_queues)
169 nr_queues = AUXTRACE_INIT_NR_QUEUES;
170
171 while (nr_queues && nr_queues < new_nr_queues)
172 nr_queues <<= 1;
173
174 if (nr_queues < queues->nr_queues || nr_queues < new_nr_queues)
175 return -EINVAL;
176
177 queue_array = auxtrace_alloc_queue_array(nr_queues);
178 if (!queue_array)
179 return -ENOMEM;
180
181 for (i = 0; i < queues->nr_queues; i++) {
182 list_splice_tail(&queues->queue_array[i].head,
183 &queue_array[i].head);
184 queue_array[i].priv = queues->queue_array[i].priv;
185 }
186
187 queues->nr_queues = nr_queues;
188 queues->queue_array = queue_array;
189
190 return 0;
191}
192
193static void *auxtrace_copy_data(u64 size, struct perf_session *session)
194{
195 int fd = perf_data_file__fd(session->file);
196 void *p;
197 ssize_t ret;
198
199 if (size > SSIZE_MAX)
200 return NULL;
201
202 p = malloc(size);
203 if (!p)
204 return NULL;
205
206 ret = readn(fd, p, size);
207 if (ret != (ssize_t)size) {
208 free(p);
209 return NULL;
210 }
211
212 return p;
213}
214
215static int auxtrace_queues__add_buffer(struct auxtrace_queues *queues,
216 unsigned int idx,
217 struct auxtrace_buffer *buffer)
218{
219 struct auxtrace_queue *queue;
220 int err;
221
222 if (idx >= queues->nr_queues) {
223 err = auxtrace_queues__grow(queues, idx + 1);
224 if (err)
225 return err;
226 }
227
228 queue = &queues->queue_array[idx];
229
230 if (!queue->set) {
231 queue->set = true;
232 queue->tid = buffer->tid;
233 queue->cpu = buffer->cpu;
234 } else if (buffer->cpu != queue->cpu || buffer->tid != queue->tid) {
235 pr_err("auxtrace queue conflict: cpu %d, tid %d vs cpu %d, tid %d\n",
236 queue->cpu, queue->tid, buffer->cpu, buffer->tid);
237 return -EINVAL;
238 }
239
240 buffer->buffer_nr = queues->next_buffer_nr++;
241
242 list_add_tail(&buffer->list, &queue->head);
243
244 queues->new_data = true;
245 queues->populated = true;
246
247 return 0;
248}
249
250/* Limit buffers to 32MiB on 32-bit */
251#define BUFFER_LIMIT_FOR_32_BIT (32 * 1024 * 1024)
252
253static int auxtrace_queues__split_buffer(struct auxtrace_queues *queues,
254 unsigned int idx,
255 struct auxtrace_buffer *buffer)
256{
257 u64 sz = buffer->size;
258 bool consecutive = false;
259 struct auxtrace_buffer *b;
260 int err;
261
262 while (sz > BUFFER_LIMIT_FOR_32_BIT) {
263 b = memdup(buffer, sizeof(struct auxtrace_buffer));
264 if (!b)
265 return -ENOMEM;
266 b->size = BUFFER_LIMIT_FOR_32_BIT;
267 b->consecutive = consecutive;
268 err = auxtrace_queues__add_buffer(queues, idx, b);
269 if (err) {
270 auxtrace_buffer__free(b);
271 return err;
272 }
273 buffer->data_offset += BUFFER_LIMIT_FOR_32_BIT;
274 sz -= BUFFER_LIMIT_FOR_32_BIT;
275 consecutive = true;
276 }
277
278 buffer->size = sz;
279 buffer->consecutive = consecutive;
280
281 return 0;
282}
283
284static int auxtrace_queues__add_event_buffer(struct auxtrace_queues *queues,
285 struct perf_session *session,
286 unsigned int idx,
287 struct auxtrace_buffer *buffer)
288{
289 if (session->one_mmap) {
290 buffer->data = buffer->data_offset - session->one_mmap_offset +
291 session->one_mmap_addr;
292 } else if (perf_data_file__is_pipe(session->file)) {
293 buffer->data = auxtrace_copy_data(buffer->size, session);
294 if (!buffer->data)
295 return -ENOMEM;
296 buffer->data_needs_freeing = true;
297 } else if (BITS_PER_LONG == 32 &&
298 buffer->size > BUFFER_LIMIT_FOR_32_BIT) {
299 int err;
300
301 err = auxtrace_queues__split_buffer(queues, idx, buffer);
302 if (err)
303 return err;
304 }
305
306 return auxtrace_queues__add_buffer(queues, idx, buffer);
307}
308
309int auxtrace_queues__add_event(struct auxtrace_queues *queues,
310 struct perf_session *session,
311 union perf_event *event, off_t data_offset,
312 struct auxtrace_buffer **buffer_ptr)
313{
314 struct auxtrace_buffer *buffer;
315 unsigned int idx;
316 int err;
317
318 buffer = zalloc(sizeof(struct auxtrace_buffer));
319 if (!buffer)
320 return -ENOMEM;
321
322 buffer->pid = -1;
323 buffer->tid = event->auxtrace.tid;
324 buffer->cpu = event->auxtrace.cpu;
325 buffer->data_offset = data_offset;
326 buffer->offset = event->auxtrace.offset;
327 buffer->reference = event->auxtrace.reference;
328 buffer->size = event->auxtrace.size;
329 idx = event->auxtrace.idx;
330
331 err = auxtrace_queues__add_event_buffer(queues, session, idx, buffer);
332 if (err)
333 goto out_err;
334
335 if (buffer_ptr)
336 *buffer_ptr = buffer;
337
338 return 0;
339
340out_err:
341 auxtrace_buffer__free(buffer);
342 return err;
343}
344
345void auxtrace_queues__free(struct auxtrace_queues *queues)
346{
347 unsigned int i;
348
349 for (i = 0; i < queues->nr_queues; i++) {
350 while (!list_empty(&queues->queue_array[i].head)) {
351 struct auxtrace_buffer *buffer;
352
353 buffer = list_entry(queues->queue_array[i].head.next,
354 struct auxtrace_buffer, list);
355 list_del(&buffer->list);
356 auxtrace_buffer__free(buffer);
357 }
358 }
359
360 zfree(&queues->queue_array);
361 queues->nr_queues = 0;
362}
363
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +0300364size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr)
365{
366 if (itr)
367 return itr->info_priv_size(itr);
368 return 0;
369}
370
371static int auxtrace_not_supported(void)
372{
373 pr_err("AUX area tracing is not supported on this architecture\n");
374 return -EINVAL;
375}
376
377int auxtrace_record__info_fill(struct auxtrace_record *itr,
378 struct perf_session *session,
379 struct auxtrace_info_event *auxtrace_info,
380 size_t priv_size)
381{
382 if (itr)
383 return itr->info_fill(itr, session, auxtrace_info, priv_size);
384 return auxtrace_not_supported();
385}
386
387void auxtrace_record__free(struct auxtrace_record *itr)
388{
389 if (itr)
390 itr->free(itr);
391}
392
393int auxtrace_record__options(struct auxtrace_record *itr,
394 struct perf_evlist *evlist,
395 struct record_opts *opts)
396{
397 if (itr)
398 return itr->recording_options(itr, evlist, opts);
399 return 0;
400}
401
402u64 auxtrace_record__reference(struct auxtrace_record *itr)
403{
404 if (itr)
405 return itr->reference(itr);
406 return 0;
407}
408
409struct auxtrace_record *__weak
410auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err)
411{
412 *err = 0;
413 return NULL;
414}
415
Adrian Huntere5027892015-04-21 12:21:51 +0300416struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue,
417 struct auxtrace_buffer *buffer)
418{
419 if (buffer) {
420 if (list_is_last(&buffer->list, &queue->head))
421 return NULL;
422 return list_entry(buffer->list.next, struct auxtrace_buffer,
423 list);
424 } else {
425 if (list_empty(&queue->head))
426 return NULL;
427 return list_entry(queue->head.next, struct auxtrace_buffer,
428 list);
429 }
430}
431
432void *auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd)
433{
434 size_t adj = buffer->data_offset & (page_size - 1);
435 size_t size = buffer->size + adj;
436 off_t file_offset = buffer->data_offset - adj;
437 void *addr;
438
439 if (buffer->data)
440 return buffer->data;
441
442 addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, file_offset);
443 if (addr == MAP_FAILED)
444 return NULL;
445
446 buffer->mmap_addr = addr;
447 buffer->mmap_size = size;
448
449 buffer->data = addr + adj;
450
451 return buffer->data;
452}
453
454void auxtrace_buffer__put_data(struct auxtrace_buffer *buffer)
455{
456 if (!buffer->data || !buffer->mmap_addr)
457 return;
458 munmap(buffer->mmap_addr, buffer->mmap_size);
459 buffer->mmap_addr = NULL;
460 buffer->mmap_size = 0;
461 buffer->data = NULL;
462 buffer->use_data = NULL;
463}
464
465void auxtrace_buffer__drop_data(struct auxtrace_buffer *buffer)
466{
467 auxtrace_buffer__put_data(buffer);
468 if (buffer->data_needs_freeing) {
469 buffer->data_needs_freeing = false;
470 zfree(&buffer->data);
471 buffer->use_data = NULL;
472 buffer->size = 0;
473 }
474}
475
476void auxtrace_buffer__free(struct auxtrace_buffer *buffer)
477{
478 auxtrace_buffer__drop_data(buffer);
479 free(buffer);
480}
481
Adrian Hunter85ed4722015-04-09 18:53:50 +0300482void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type,
483 int code, int cpu, pid_t pid, pid_t tid, u64 ip,
484 const char *msg)
485{
486 size_t size;
487
488 memset(auxtrace_error, 0, sizeof(struct auxtrace_error_event));
489
490 auxtrace_error->header.type = PERF_RECORD_AUXTRACE_ERROR;
491 auxtrace_error->type = type;
492 auxtrace_error->code = code;
493 auxtrace_error->cpu = cpu;
494 auxtrace_error->pid = pid;
495 auxtrace_error->tid = tid;
496 auxtrace_error->ip = ip;
497 strlcpy(auxtrace_error->msg, msg, MAX_AUXTRACE_ERROR_MSG);
498
499 size = (void *)auxtrace_error->msg - (void *)auxtrace_error +
500 strlen(auxtrace_error->msg) + 1;
501 auxtrace_error->header.size = PERF_ALIGN(size, sizeof(u64));
502}
503
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +0300504int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr,
505 struct perf_tool *tool,
506 struct perf_session *session,
507 perf_event__handler_t process)
508{
509 union perf_event *ev;
510 size_t priv_size;
511 int err;
512
513 pr_debug2("Synthesizing auxtrace information\n");
514 priv_size = auxtrace_record__info_priv_size(itr);
515 ev = zalloc(sizeof(struct auxtrace_info_event) + priv_size);
516 if (!ev)
517 return -ENOMEM;
518
519 ev->auxtrace_info.header.type = PERF_RECORD_AUXTRACE_INFO;
520 ev->auxtrace_info.header.size = sizeof(struct auxtrace_info_event) +
521 priv_size;
522 err = auxtrace_record__info_fill(itr, session, &ev->auxtrace_info,
523 priv_size);
524 if (err)
525 goto out_free;
526
527 err = process(tool, ev, NULL, NULL);
528out_free:
529 free(ev);
530 return err;
531}
532
Adrian Hunterf6986c952015-04-09 18:53:49 +0300533#define PERF_ITRACE_DEFAULT_PERIOD_TYPE PERF_ITRACE_PERIOD_NANOSECS
534#define PERF_ITRACE_DEFAULT_PERIOD 100000
535#define PERF_ITRACE_DEFAULT_CALLCHAIN_SZ 16
536#define PERF_ITRACE_MAX_CALLCHAIN_SZ 1024
537
538void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts)
539{
540 synth_opts->instructions = true;
541 synth_opts->branches = true;
542 synth_opts->errors = true;
543 synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE;
544 synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD;
545 synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ;
546}
547
548/*
549 * Please check tools/perf/Documentation/perf-script.txt for information
550 * about the options parsed here, which is introduced after this cset,
551 * when support in 'perf script' for these options is introduced.
552 */
553int itrace_parse_synth_opts(const struct option *opt, const char *str,
554 int unset)
555{
556 struct itrace_synth_opts *synth_opts = opt->value;
557 const char *p;
558 char *endptr;
559
560 synth_opts->set = true;
561
562 if (unset) {
563 synth_opts->dont_decode = true;
564 return 0;
565 }
566
567 if (!str) {
568 itrace_synth_opts__set_default(synth_opts);
569 return 0;
570 }
571
572 for (p = str; *p;) {
573 switch (*p++) {
574 case 'i':
575 synth_opts->instructions = true;
576 while (*p == ' ' || *p == ',')
577 p += 1;
578 if (isdigit(*p)) {
579 synth_opts->period = strtoull(p, &endptr, 10);
580 p = endptr;
581 while (*p == ' ' || *p == ',')
582 p += 1;
583 switch (*p++) {
584 case 'i':
585 synth_opts->period_type =
586 PERF_ITRACE_PERIOD_INSTRUCTIONS;
587 break;
588 case 't':
589 synth_opts->period_type =
590 PERF_ITRACE_PERIOD_TICKS;
591 break;
592 case 'm':
593 synth_opts->period *= 1000;
594 /* Fall through */
595 case 'u':
596 synth_opts->period *= 1000;
597 /* Fall through */
598 case 'n':
599 if (*p++ != 's')
600 goto out_err;
601 synth_opts->period_type =
602 PERF_ITRACE_PERIOD_NANOSECS;
603 break;
604 case '\0':
605 goto out;
606 default:
607 goto out_err;
608 }
609 }
610 break;
611 case 'b':
612 synth_opts->branches = true;
613 break;
614 case 'e':
615 synth_opts->errors = true;
616 break;
617 case 'd':
618 synth_opts->log = true;
619 break;
620 case 'c':
621 synth_opts->branches = true;
622 synth_opts->calls = true;
623 break;
624 case 'r':
625 synth_opts->branches = true;
626 synth_opts->returns = true;
627 break;
628 case 'g':
629 synth_opts->instructions = true;
630 synth_opts->callchain = true;
631 synth_opts->callchain_sz =
632 PERF_ITRACE_DEFAULT_CALLCHAIN_SZ;
633 while (*p == ' ' || *p == ',')
634 p += 1;
635 if (isdigit(*p)) {
636 unsigned int val;
637
638 val = strtoul(p, &endptr, 10);
639 p = endptr;
640 if (!val || val > PERF_ITRACE_MAX_CALLCHAIN_SZ)
641 goto out_err;
642 synth_opts->callchain_sz = val;
643 }
644 break;
645 case ' ':
646 case ',':
647 break;
648 default:
649 goto out_err;
650 }
651 }
652out:
653 if (synth_opts->instructions) {
654 if (!synth_opts->period_type)
655 synth_opts->period_type =
656 PERF_ITRACE_DEFAULT_PERIOD_TYPE;
657 if (!synth_opts->period)
658 synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD;
659 }
660
661 return 0;
662
663out_err:
664 pr_err("Bad Instruction Tracing options '%s'\n", str);
665 return -EINVAL;
666}
667
Adrian Hunter85ed4722015-04-09 18:53:50 +0300668static const char * const auxtrace_error_type_name[] = {
669 [PERF_AUXTRACE_ERROR_ITRACE] = "instruction trace",
670};
671
672static const char *auxtrace_error_name(int type)
673{
674 const char *error_type_name = NULL;
675
676 if (type < PERF_AUXTRACE_ERROR_MAX)
677 error_type_name = auxtrace_error_type_name[type];
678 if (!error_type_name)
679 error_type_name = "unknown AUX";
680 return error_type_name;
681}
682
683size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp)
684{
685 struct auxtrace_error_event *e = &event->auxtrace_error;
686 int ret;
687
688 ret = fprintf(fp, " %s error type %u",
689 auxtrace_error_name(e->type), e->type);
690 ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRIx64" code %u: %s\n",
691 e->cpu, e->pid, e->tid, e->ip, e->code, e->msg);
692 return ret;
693}
694
695void perf_session__auxtrace_error_inc(struct perf_session *session,
696 union perf_event *event)
697{
698 struct auxtrace_error_event *e = &event->auxtrace_error;
699
700 if (e->type < PERF_AUXTRACE_ERROR_MAX)
701 session->evlist->stats.nr_auxtrace_errors[e->type] += 1;
702}
703
704void events_stats__auxtrace_error_warn(const struct events_stats *stats)
705{
706 int i;
707
708 for (i = 0; i < PERF_AUXTRACE_ERROR_MAX; i++) {
709 if (!stats->nr_auxtrace_errors[i])
710 continue;
711 ui__warning("%u %s errors\n",
712 stats->nr_auxtrace_errors[i],
713 auxtrace_error_name(i));
714 }
715}
716
717int perf_event__process_auxtrace_error(struct perf_tool *tool __maybe_unused,
718 union perf_event *event,
719 struct perf_session *session __maybe_unused)
720{
721 perf_event__fprintf_auxtrace_error(event, stdout);
722 return 0;
723}
724
Adrian Hunter9e0cc4f2015-04-09 18:53:44 +0300725int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
726 struct perf_tool *tool, process_auxtrace_t fn)
727{
728 u64 head = auxtrace_mmap__read_head(mm);
729 u64 old = mm->prev, offset, ref;
730 unsigned char *data = mm->base;
731 size_t size, head_off, old_off, len1, len2, padding;
732 union perf_event ev;
733 void *data1, *data2;
734
735 if (old == head)
736 return 0;
737
738 pr_debug3("auxtrace idx %d old %#"PRIx64" head %#"PRIx64" diff %#"PRIx64"\n",
739 mm->idx, old, head, head - old);
740
741 if (mm->mask) {
742 head_off = head & mm->mask;
743 old_off = old & mm->mask;
744 } else {
745 head_off = head % mm->len;
746 old_off = old % mm->len;
747 }
748
749 if (head_off > old_off)
750 size = head_off - old_off;
751 else
752 size = mm->len - (old_off - head_off);
753
754 ref = auxtrace_record__reference(itr);
755
756 if (head > old || size <= head || mm->mask) {
757 offset = head - size;
758 } else {
759 /*
760 * When the buffer size is not a power of 2, 'head' wraps at the
761 * highest multiple of the buffer size, so we have to subtract
762 * the remainder here.
763 */
764 u64 rem = (0ULL - mm->len) % mm->len;
765
766 offset = head - size - rem;
767 }
768
769 if (size > head_off) {
770 len1 = size - head_off;
771 data1 = &data[mm->len - len1];
772 len2 = head_off;
773 data2 = &data[0];
774 } else {
775 len1 = size;
776 data1 = &data[head_off - len1];
777 len2 = 0;
778 data2 = NULL;
779 }
780
781 /* padding must be written by fn() e.g. record__process_auxtrace() */
782 padding = size & 7;
783 if (padding)
784 padding = 8 - padding;
785
786 memset(&ev, 0, sizeof(ev));
787 ev.auxtrace.header.type = PERF_RECORD_AUXTRACE;
788 ev.auxtrace.header.size = sizeof(ev.auxtrace);
789 ev.auxtrace.size = size + padding;
790 ev.auxtrace.offset = offset;
791 ev.auxtrace.reference = ref;
792 ev.auxtrace.idx = mm->idx;
793 ev.auxtrace.tid = mm->tid;
794 ev.auxtrace.cpu = mm->cpu;
795
796 if (fn(tool, &ev, data1, len1, data2, len2))
797 return -1;
798
799 mm->prev = head;
800
801 auxtrace_mmap__write_tail(mm, head);
802 if (itr->read_finish) {
803 int err;
804
805 err = itr->read_finish(itr, mm->idx);
806 if (err < 0)
807 return err;
808 }
809
810 return 1;
811}