xref: /linux/tools/perf/util/auxtrace.c (revision a7fde09a78a8ae40b81cfb5096c3cefef6c078c9)
1718c602dSAdrian Hunter /*
2718c602dSAdrian Hunter  * auxtrace.c: AUX area trace support
3718c602dSAdrian Hunter  * Copyright (c) 2013-2015, Intel Corporation.
4718c602dSAdrian Hunter  *
5718c602dSAdrian Hunter  * This program is free software; you can redistribute it and/or modify it
6718c602dSAdrian Hunter  * under the terms and conditions of the GNU General Public License,
7718c602dSAdrian Hunter  * version 2, as published by the Free Software Foundation.
8718c602dSAdrian Hunter  *
9718c602dSAdrian Hunter  * This program is distributed in the hope it will be useful, but WITHOUT
10718c602dSAdrian Hunter  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11718c602dSAdrian Hunter  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12718c602dSAdrian Hunter  * more details.
13718c602dSAdrian Hunter  *
14718c602dSAdrian Hunter  */
15718c602dSAdrian Hunter 
16718c602dSAdrian Hunter #include <sys/types.h>
17718c602dSAdrian Hunter #include <sys/mman.h>
18718c602dSAdrian Hunter #include <stdbool.h>
19718c602dSAdrian Hunter 
20718c602dSAdrian Hunter #include <linux/kernel.h>
21718c602dSAdrian Hunter #include <linux/perf_event.h>
22718c602dSAdrian Hunter #include <linux/types.h>
23718c602dSAdrian Hunter #include <linux/bitops.h>
24718c602dSAdrian Hunter #include <linux/log2.h>
25e5027893SAdrian Hunter #include <linux/string.h>
26718c602dSAdrian Hunter 
27e5027893SAdrian Hunter #include <sys/param.h>
289e0cc4feSAdrian Hunter #include <stdlib.h>
2985ed4729SAdrian Hunter #include <stdio.h>
309e0cc4feSAdrian Hunter #include <string.h>
31e5027893SAdrian Hunter #include <limits.h>
329e0cc4feSAdrian Hunter #include <errno.h>
33e5027893SAdrian Hunter #include <linux/list.h>
349e0cc4feSAdrian Hunter 
35718c602dSAdrian Hunter #include "../perf.h"
36718c602dSAdrian Hunter #include "util.h"
37718c602dSAdrian Hunter #include "evlist.h"
38718c602dSAdrian Hunter #include "cpumap.h"
39718c602dSAdrian Hunter #include "thread_map.h"
40718c602dSAdrian Hunter #include "asm/bug.h"
41718c602dSAdrian Hunter #include "auxtrace.h"
42718c602dSAdrian Hunter 
43c3278f02SAdrian Hunter #include <linux/hash.h>
44c3278f02SAdrian Hunter 
459e0cc4feSAdrian Hunter #include "event.h"
4685ed4729SAdrian Hunter #include "session.h"
479e0cc4feSAdrian Hunter #include "debug.h"
48f6986c95SAdrian Hunter #include "parse-options.h"
499e0cc4feSAdrian Hunter 
50718c602dSAdrian Hunter int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
51718c602dSAdrian Hunter 			struct auxtrace_mmap_params *mp,
52718c602dSAdrian Hunter 			void *userpg, int fd)
53718c602dSAdrian Hunter {
54718c602dSAdrian Hunter 	struct perf_event_mmap_page *pc = userpg;
55718c602dSAdrian Hunter 
56718c602dSAdrian Hunter 	WARN_ONCE(mm->base, "Uninitialized auxtrace_mmap\n");
57718c602dSAdrian Hunter 
58718c602dSAdrian Hunter 	mm->userpg = userpg;
59718c602dSAdrian Hunter 	mm->mask = mp->mask;
60718c602dSAdrian Hunter 	mm->len = mp->len;
61718c602dSAdrian Hunter 	mm->prev = 0;
62718c602dSAdrian Hunter 	mm->idx = mp->idx;
63718c602dSAdrian Hunter 	mm->tid = mp->tid;
64718c602dSAdrian Hunter 	mm->cpu = mp->cpu;
65718c602dSAdrian Hunter 
66718c602dSAdrian Hunter 	if (!mp->len) {
67718c602dSAdrian Hunter 		mm->base = NULL;
68718c602dSAdrian Hunter 		return 0;
69718c602dSAdrian Hunter 	}
70718c602dSAdrian Hunter 
71*a7fde09aSAdrian Hunter #if BITS_PER_LONG != 64 && !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)
72*a7fde09aSAdrian Hunter 	pr_err("Cannot use AUX area tracing mmaps\n");
73*a7fde09aSAdrian Hunter 	return -1;
74*a7fde09aSAdrian Hunter #endif
75*a7fde09aSAdrian Hunter 
76718c602dSAdrian Hunter 	pc->aux_offset = mp->offset;
77718c602dSAdrian Hunter 	pc->aux_size = mp->len;
78718c602dSAdrian Hunter 
79718c602dSAdrian Hunter 	mm->base = mmap(NULL, mp->len, mp->prot, MAP_SHARED, fd, mp->offset);
80718c602dSAdrian Hunter 	if (mm->base == MAP_FAILED) {
81718c602dSAdrian Hunter 		pr_debug2("failed to mmap AUX area\n");
82718c602dSAdrian Hunter 		mm->base = NULL;
83718c602dSAdrian Hunter 		return -1;
84718c602dSAdrian Hunter 	}
85718c602dSAdrian Hunter 
86718c602dSAdrian Hunter 	return 0;
87718c602dSAdrian Hunter }
88718c602dSAdrian Hunter 
89718c602dSAdrian Hunter void auxtrace_mmap__munmap(struct auxtrace_mmap *mm)
90718c602dSAdrian Hunter {
91718c602dSAdrian Hunter 	if (mm->base) {
92718c602dSAdrian Hunter 		munmap(mm->base, mm->len);
93718c602dSAdrian Hunter 		mm->base = NULL;
94718c602dSAdrian Hunter 	}
95718c602dSAdrian Hunter }
96718c602dSAdrian Hunter 
97718c602dSAdrian Hunter void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
98718c602dSAdrian Hunter 				off_t auxtrace_offset,
99718c602dSAdrian Hunter 				unsigned int auxtrace_pages,
100718c602dSAdrian Hunter 				bool auxtrace_overwrite)
101718c602dSAdrian Hunter {
102718c602dSAdrian Hunter 	if (auxtrace_pages) {
103718c602dSAdrian Hunter 		mp->offset = auxtrace_offset;
104718c602dSAdrian Hunter 		mp->len = auxtrace_pages * (size_t)page_size;
105718c602dSAdrian Hunter 		mp->mask = is_power_of_2(mp->len) ? mp->len - 1 : 0;
106718c602dSAdrian Hunter 		mp->prot = PROT_READ | (auxtrace_overwrite ? 0 : PROT_WRITE);
107718c602dSAdrian Hunter 		pr_debug2("AUX area mmap length %zu\n", mp->len);
108718c602dSAdrian Hunter 	} else {
109718c602dSAdrian Hunter 		mp->len = 0;
110718c602dSAdrian Hunter 	}
111718c602dSAdrian Hunter }
112718c602dSAdrian Hunter 
113718c602dSAdrian Hunter void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
114718c602dSAdrian Hunter 				   struct perf_evlist *evlist, int idx,
115718c602dSAdrian Hunter 				   bool per_cpu)
116718c602dSAdrian Hunter {
117718c602dSAdrian Hunter 	mp->idx = idx;
118718c602dSAdrian Hunter 
119718c602dSAdrian Hunter 	if (per_cpu) {
120718c602dSAdrian Hunter 		mp->cpu = evlist->cpus->map[idx];
121718c602dSAdrian Hunter 		if (evlist->threads)
122e13798c7SJiri Olsa 			mp->tid = thread_map__pid(evlist->threads, 0);
123718c602dSAdrian Hunter 		else
124718c602dSAdrian Hunter 			mp->tid = -1;
125718c602dSAdrian Hunter 	} else {
126718c602dSAdrian Hunter 		mp->cpu = -1;
127e13798c7SJiri Olsa 		mp->tid = thread_map__pid(evlist->threads, idx);
128718c602dSAdrian Hunter 	}
129718c602dSAdrian Hunter }
1309e0cc4feSAdrian Hunter 
131e5027893SAdrian Hunter #define AUXTRACE_INIT_NR_QUEUES	32
132e5027893SAdrian Hunter 
133e5027893SAdrian Hunter static struct auxtrace_queue *auxtrace_alloc_queue_array(unsigned int nr_queues)
134e5027893SAdrian Hunter {
135e5027893SAdrian Hunter 	struct auxtrace_queue *queue_array;
136e5027893SAdrian Hunter 	unsigned int max_nr_queues, i;
137e5027893SAdrian Hunter 
138e5027893SAdrian Hunter 	max_nr_queues = UINT_MAX / sizeof(struct auxtrace_queue);
139e5027893SAdrian Hunter 	if (nr_queues > max_nr_queues)
140e5027893SAdrian Hunter 		return NULL;
141e5027893SAdrian Hunter 
142e5027893SAdrian Hunter 	queue_array = calloc(nr_queues, sizeof(struct auxtrace_queue));
143e5027893SAdrian Hunter 	if (!queue_array)
144e5027893SAdrian Hunter 		return NULL;
145e5027893SAdrian Hunter 
146e5027893SAdrian Hunter 	for (i = 0; i < nr_queues; i++) {
147e5027893SAdrian Hunter 		INIT_LIST_HEAD(&queue_array[i].head);
148e5027893SAdrian Hunter 		queue_array[i].priv = NULL;
149e5027893SAdrian Hunter 	}
150e5027893SAdrian Hunter 
151e5027893SAdrian Hunter 	return queue_array;
152e5027893SAdrian Hunter }
153e5027893SAdrian Hunter 
154e5027893SAdrian Hunter int auxtrace_queues__init(struct auxtrace_queues *queues)
155e5027893SAdrian Hunter {
156e5027893SAdrian Hunter 	queues->nr_queues = AUXTRACE_INIT_NR_QUEUES;
157e5027893SAdrian Hunter 	queues->queue_array = auxtrace_alloc_queue_array(queues->nr_queues);
158e5027893SAdrian Hunter 	if (!queues->queue_array)
159e5027893SAdrian Hunter 		return -ENOMEM;
160e5027893SAdrian Hunter 	return 0;
161e5027893SAdrian Hunter }
162e5027893SAdrian Hunter 
163e5027893SAdrian Hunter static int auxtrace_queues__grow(struct auxtrace_queues *queues,
164e5027893SAdrian Hunter 				 unsigned int new_nr_queues)
165e5027893SAdrian Hunter {
166e5027893SAdrian Hunter 	unsigned int nr_queues = queues->nr_queues;
167e5027893SAdrian Hunter 	struct auxtrace_queue *queue_array;
168e5027893SAdrian Hunter 	unsigned int i;
169e5027893SAdrian Hunter 
170e5027893SAdrian Hunter 	if (!nr_queues)
171e5027893SAdrian Hunter 		nr_queues = AUXTRACE_INIT_NR_QUEUES;
172e5027893SAdrian Hunter 
173e5027893SAdrian Hunter 	while (nr_queues && nr_queues < new_nr_queues)
174e5027893SAdrian Hunter 		nr_queues <<= 1;
175e5027893SAdrian Hunter 
176e5027893SAdrian Hunter 	if (nr_queues < queues->nr_queues || nr_queues < new_nr_queues)
177e5027893SAdrian Hunter 		return -EINVAL;
178e5027893SAdrian Hunter 
179e5027893SAdrian Hunter 	queue_array = auxtrace_alloc_queue_array(nr_queues);
180e5027893SAdrian Hunter 	if (!queue_array)
181e5027893SAdrian Hunter 		return -ENOMEM;
182e5027893SAdrian Hunter 
183e5027893SAdrian Hunter 	for (i = 0; i < queues->nr_queues; i++) {
184e5027893SAdrian Hunter 		list_splice_tail(&queues->queue_array[i].head,
185e5027893SAdrian Hunter 				 &queue_array[i].head);
186e5027893SAdrian Hunter 		queue_array[i].priv = queues->queue_array[i].priv;
187e5027893SAdrian Hunter 	}
188e5027893SAdrian Hunter 
189e5027893SAdrian Hunter 	queues->nr_queues = nr_queues;
190e5027893SAdrian Hunter 	queues->queue_array = queue_array;
191e5027893SAdrian Hunter 
192e5027893SAdrian Hunter 	return 0;
193e5027893SAdrian Hunter }
194e5027893SAdrian Hunter 
195e5027893SAdrian Hunter static void *auxtrace_copy_data(u64 size, struct perf_session *session)
196e5027893SAdrian Hunter {
197e5027893SAdrian Hunter 	int fd = perf_data_file__fd(session->file);
198e5027893SAdrian Hunter 	void *p;
199e5027893SAdrian Hunter 	ssize_t ret;
200e5027893SAdrian Hunter 
201e5027893SAdrian Hunter 	if (size > SSIZE_MAX)
202e5027893SAdrian Hunter 		return NULL;
203e5027893SAdrian Hunter 
204e5027893SAdrian Hunter 	p = malloc(size);
205e5027893SAdrian Hunter 	if (!p)
206e5027893SAdrian Hunter 		return NULL;
207e5027893SAdrian Hunter 
208e5027893SAdrian Hunter 	ret = readn(fd, p, size);
209e5027893SAdrian Hunter 	if (ret != (ssize_t)size) {
210e5027893SAdrian Hunter 		free(p);
211e5027893SAdrian Hunter 		return NULL;
212e5027893SAdrian Hunter 	}
213e5027893SAdrian Hunter 
214e5027893SAdrian Hunter 	return p;
215e5027893SAdrian Hunter }
216e5027893SAdrian Hunter 
217e5027893SAdrian Hunter static int auxtrace_queues__add_buffer(struct auxtrace_queues *queues,
218e5027893SAdrian Hunter 				       unsigned int idx,
219e5027893SAdrian Hunter 				       struct auxtrace_buffer *buffer)
220e5027893SAdrian Hunter {
221e5027893SAdrian Hunter 	struct auxtrace_queue *queue;
222e5027893SAdrian Hunter 	int err;
223e5027893SAdrian Hunter 
224e5027893SAdrian Hunter 	if (idx >= queues->nr_queues) {
225e5027893SAdrian Hunter 		err = auxtrace_queues__grow(queues, idx + 1);
226e5027893SAdrian Hunter 		if (err)
227e5027893SAdrian Hunter 			return err;
228e5027893SAdrian Hunter 	}
229e5027893SAdrian Hunter 
230e5027893SAdrian Hunter 	queue = &queues->queue_array[idx];
231e5027893SAdrian Hunter 
232e5027893SAdrian Hunter 	if (!queue->set) {
233e5027893SAdrian Hunter 		queue->set = true;
234e5027893SAdrian Hunter 		queue->tid = buffer->tid;
235e5027893SAdrian Hunter 		queue->cpu = buffer->cpu;
236e5027893SAdrian Hunter 	} else if (buffer->cpu != queue->cpu || buffer->tid != queue->tid) {
237e5027893SAdrian Hunter 		pr_err("auxtrace queue conflict: cpu %d, tid %d vs cpu %d, tid %d\n",
238e5027893SAdrian Hunter 		       queue->cpu, queue->tid, buffer->cpu, buffer->tid);
239e5027893SAdrian Hunter 		return -EINVAL;
240e5027893SAdrian Hunter 	}
241e5027893SAdrian Hunter 
242e5027893SAdrian Hunter 	buffer->buffer_nr = queues->next_buffer_nr++;
243e5027893SAdrian Hunter 
244e5027893SAdrian Hunter 	list_add_tail(&buffer->list, &queue->head);
245e5027893SAdrian Hunter 
246e5027893SAdrian Hunter 	queues->new_data = true;
247e5027893SAdrian Hunter 	queues->populated = true;
248e5027893SAdrian Hunter 
249e5027893SAdrian Hunter 	return 0;
250e5027893SAdrian Hunter }
251e5027893SAdrian Hunter 
252e5027893SAdrian Hunter /* Limit buffers to 32MiB on 32-bit */
253e5027893SAdrian Hunter #define BUFFER_LIMIT_FOR_32_BIT (32 * 1024 * 1024)
254e5027893SAdrian Hunter 
255e5027893SAdrian Hunter static int auxtrace_queues__split_buffer(struct auxtrace_queues *queues,
256e5027893SAdrian Hunter 					 unsigned int idx,
257e5027893SAdrian Hunter 					 struct auxtrace_buffer *buffer)
258e5027893SAdrian Hunter {
259e5027893SAdrian Hunter 	u64 sz = buffer->size;
260e5027893SAdrian Hunter 	bool consecutive = false;
261e5027893SAdrian Hunter 	struct auxtrace_buffer *b;
262e5027893SAdrian Hunter 	int err;
263e5027893SAdrian Hunter 
264e5027893SAdrian Hunter 	while (sz > BUFFER_LIMIT_FOR_32_BIT) {
265e5027893SAdrian Hunter 		b = memdup(buffer, sizeof(struct auxtrace_buffer));
266e5027893SAdrian Hunter 		if (!b)
267e5027893SAdrian Hunter 			return -ENOMEM;
268e5027893SAdrian Hunter 		b->size = BUFFER_LIMIT_FOR_32_BIT;
269e5027893SAdrian Hunter 		b->consecutive = consecutive;
270e5027893SAdrian Hunter 		err = auxtrace_queues__add_buffer(queues, idx, b);
271e5027893SAdrian Hunter 		if (err) {
272e5027893SAdrian Hunter 			auxtrace_buffer__free(b);
273e5027893SAdrian Hunter 			return err;
274e5027893SAdrian Hunter 		}
275e5027893SAdrian Hunter 		buffer->data_offset += BUFFER_LIMIT_FOR_32_BIT;
276e5027893SAdrian Hunter 		sz -= BUFFER_LIMIT_FOR_32_BIT;
277e5027893SAdrian Hunter 		consecutive = true;
278e5027893SAdrian Hunter 	}
279e5027893SAdrian Hunter 
280e5027893SAdrian Hunter 	buffer->size = sz;
281e5027893SAdrian Hunter 	buffer->consecutive = consecutive;
282e5027893SAdrian Hunter 
283e5027893SAdrian Hunter 	return 0;
284e5027893SAdrian Hunter }
285e5027893SAdrian Hunter 
286e5027893SAdrian Hunter static int auxtrace_queues__add_event_buffer(struct auxtrace_queues *queues,
287e5027893SAdrian Hunter 					     struct perf_session *session,
288e5027893SAdrian Hunter 					     unsigned int idx,
289e5027893SAdrian Hunter 					     struct auxtrace_buffer *buffer)
290e5027893SAdrian Hunter {
291e5027893SAdrian Hunter 	if (session->one_mmap) {
292e5027893SAdrian Hunter 		buffer->data = buffer->data_offset - session->one_mmap_offset +
293e5027893SAdrian Hunter 			       session->one_mmap_addr;
294e5027893SAdrian Hunter 	} else if (perf_data_file__is_pipe(session->file)) {
295e5027893SAdrian Hunter 		buffer->data = auxtrace_copy_data(buffer->size, session);
296e5027893SAdrian Hunter 		if (!buffer->data)
297e5027893SAdrian Hunter 			return -ENOMEM;
298e5027893SAdrian Hunter 		buffer->data_needs_freeing = true;
299e5027893SAdrian Hunter 	} else if (BITS_PER_LONG == 32 &&
300e5027893SAdrian Hunter 		   buffer->size > BUFFER_LIMIT_FOR_32_BIT) {
301e5027893SAdrian Hunter 		int err;
302e5027893SAdrian Hunter 
303e5027893SAdrian Hunter 		err = auxtrace_queues__split_buffer(queues, idx, buffer);
304e5027893SAdrian Hunter 		if (err)
305e5027893SAdrian Hunter 			return err;
306e5027893SAdrian Hunter 	}
307e5027893SAdrian Hunter 
308e5027893SAdrian Hunter 	return auxtrace_queues__add_buffer(queues, idx, buffer);
309e5027893SAdrian Hunter }
310e5027893SAdrian Hunter 
311e5027893SAdrian Hunter int auxtrace_queues__add_event(struct auxtrace_queues *queues,
312e5027893SAdrian Hunter 			       struct perf_session *session,
313e5027893SAdrian Hunter 			       union perf_event *event, off_t data_offset,
314e5027893SAdrian Hunter 			       struct auxtrace_buffer **buffer_ptr)
315e5027893SAdrian Hunter {
316e5027893SAdrian Hunter 	struct auxtrace_buffer *buffer;
317e5027893SAdrian Hunter 	unsigned int idx;
318e5027893SAdrian Hunter 	int err;
319e5027893SAdrian Hunter 
320e5027893SAdrian Hunter 	buffer = zalloc(sizeof(struct auxtrace_buffer));
321e5027893SAdrian Hunter 	if (!buffer)
322e5027893SAdrian Hunter 		return -ENOMEM;
323e5027893SAdrian Hunter 
324e5027893SAdrian Hunter 	buffer->pid = -1;
325e5027893SAdrian Hunter 	buffer->tid = event->auxtrace.tid;
326e5027893SAdrian Hunter 	buffer->cpu = event->auxtrace.cpu;
327e5027893SAdrian Hunter 	buffer->data_offset = data_offset;
328e5027893SAdrian Hunter 	buffer->offset = event->auxtrace.offset;
329e5027893SAdrian Hunter 	buffer->reference = event->auxtrace.reference;
330e5027893SAdrian Hunter 	buffer->size = event->auxtrace.size;
331e5027893SAdrian Hunter 	idx = event->auxtrace.idx;
332e5027893SAdrian Hunter 
333e5027893SAdrian Hunter 	err = auxtrace_queues__add_event_buffer(queues, session, idx, buffer);
334e5027893SAdrian Hunter 	if (err)
335e5027893SAdrian Hunter 		goto out_err;
336e5027893SAdrian Hunter 
337e5027893SAdrian Hunter 	if (buffer_ptr)
338e5027893SAdrian Hunter 		*buffer_ptr = buffer;
339e5027893SAdrian Hunter 
340e5027893SAdrian Hunter 	return 0;
341e5027893SAdrian Hunter 
342e5027893SAdrian Hunter out_err:
343e5027893SAdrian Hunter 	auxtrace_buffer__free(buffer);
344e5027893SAdrian Hunter 	return err;
345e5027893SAdrian Hunter }
346e5027893SAdrian Hunter 
34799fa2984SAdrian Hunter static int auxtrace_queues__add_indexed_event(struct auxtrace_queues *queues,
34899fa2984SAdrian Hunter 					      struct perf_session *session,
34999fa2984SAdrian Hunter 					      off_t file_offset, size_t sz)
35099fa2984SAdrian Hunter {
35199fa2984SAdrian Hunter 	union perf_event *event;
35299fa2984SAdrian Hunter 	int err;
35399fa2984SAdrian Hunter 	char buf[PERF_SAMPLE_MAX_SIZE];
35499fa2984SAdrian Hunter 
35599fa2984SAdrian Hunter 	err = perf_session__peek_event(session, file_offset, buf,
35699fa2984SAdrian Hunter 				       PERF_SAMPLE_MAX_SIZE, &event, NULL);
35799fa2984SAdrian Hunter 	if (err)
35899fa2984SAdrian Hunter 		return err;
35999fa2984SAdrian Hunter 
36099fa2984SAdrian Hunter 	if (event->header.type == PERF_RECORD_AUXTRACE) {
36199fa2984SAdrian Hunter 		if (event->header.size < sizeof(struct auxtrace_event) ||
36299fa2984SAdrian Hunter 		    event->header.size != sz) {
36399fa2984SAdrian Hunter 			err = -EINVAL;
36499fa2984SAdrian Hunter 			goto out;
36599fa2984SAdrian Hunter 		}
36699fa2984SAdrian Hunter 		file_offset += event->header.size;
36799fa2984SAdrian Hunter 		err = auxtrace_queues__add_event(queues, session, event,
36899fa2984SAdrian Hunter 						 file_offset, NULL);
36999fa2984SAdrian Hunter 	}
37099fa2984SAdrian Hunter out:
37199fa2984SAdrian Hunter 	return err;
37299fa2984SAdrian Hunter }
37399fa2984SAdrian Hunter 
374e5027893SAdrian Hunter void auxtrace_queues__free(struct auxtrace_queues *queues)
375e5027893SAdrian Hunter {
376e5027893SAdrian Hunter 	unsigned int i;
377e5027893SAdrian Hunter 
378e5027893SAdrian Hunter 	for (i = 0; i < queues->nr_queues; i++) {
379e5027893SAdrian Hunter 		while (!list_empty(&queues->queue_array[i].head)) {
380e5027893SAdrian Hunter 			struct auxtrace_buffer *buffer;
381e5027893SAdrian Hunter 
382e5027893SAdrian Hunter 			buffer = list_entry(queues->queue_array[i].head.next,
383e5027893SAdrian Hunter 					    struct auxtrace_buffer, list);
384e5027893SAdrian Hunter 			list_del(&buffer->list);
385e5027893SAdrian Hunter 			auxtrace_buffer__free(buffer);
386e5027893SAdrian Hunter 		}
387e5027893SAdrian Hunter 	}
388e5027893SAdrian Hunter 
389e5027893SAdrian Hunter 	zfree(&queues->queue_array);
390e5027893SAdrian Hunter 	queues->nr_queues = 0;
391e5027893SAdrian Hunter }
392e5027893SAdrian Hunter 
393f9397155SAdrian Hunter static void auxtrace_heapify(struct auxtrace_heap_item *heap_array,
394f9397155SAdrian Hunter 			     unsigned int pos, unsigned int queue_nr,
395f9397155SAdrian Hunter 			     u64 ordinal)
396f9397155SAdrian Hunter {
397f9397155SAdrian Hunter 	unsigned int parent;
398f9397155SAdrian Hunter 
399f9397155SAdrian Hunter 	while (pos) {
400f9397155SAdrian Hunter 		parent = (pos - 1) >> 1;
401f9397155SAdrian Hunter 		if (heap_array[parent].ordinal <= ordinal)
402f9397155SAdrian Hunter 			break;
403f9397155SAdrian Hunter 		heap_array[pos] = heap_array[parent];
404f9397155SAdrian Hunter 		pos = parent;
405f9397155SAdrian Hunter 	}
406f9397155SAdrian Hunter 	heap_array[pos].queue_nr = queue_nr;
407f9397155SAdrian Hunter 	heap_array[pos].ordinal = ordinal;
408f9397155SAdrian Hunter }
409f9397155SAdrian Hunter 
410f9397155SAdrian Hunter int auxtrace_heap__add(struct auxtrace_heap *heap, unsigned int queue_nr,
411f9397155SAdrian Hunter 		       u64 ordinal)
412f9397155SAdrian Hunter {
413f9397155SAdrian Hunter 	struct auxtrace_heap_item *heap_array;
414f9397155SAdrian Hunter 
415f9397155SAdrian Hunter 	if (queue_nr >= heap->heap_sz) {
416f9397155SAdrian Hunter 		unsigned int heap_sz = AUXTRACE_INIT_NR_QUEUES;
417f9397155SAdrian Hunter 
418f9397155SAdrian Hunter 		while (heap_sz <= queue_nr)
419f9397155SAdrian Hunter 			heap_sz <<= 1;
420f9397155SAdrian Hunter 		heap_array = realloc(heap->heap_array,
421f9397155SAdrian Hunter 				     heap_sz * sizeof(struct auxtrace_heap_item));
422f9397155SAdrian Hunter 		if (!heap_array)
423f9397155SAdrian Hunter 			return -ENOMEM;
424f9397155SAdrian Hunter 		heap->heap_array = heap_array;
425f9397155SAdrian Hunter 		heap->heap_sz = heap_sz;
426f9397155SAdrian Hunter 	}
427f9397155SAdrian Hunter 
428f9397155SAdrian Hunter 	auxtrace_heapify(heap->heap_array, heap->heap_cnt++, queue_nr, ordinal);
429f9397155SAdrian Hunter 
430f9397155SAdrian Hunter 	return 0;
431f9397155SAdrian Hunter }
432f9397155SAdrian Hunter 
433f9397155SAdrian Hunter void auxtrace_heap__free(struct auxtrace_heap *heap)
434f9397155SAdrian Hunter {
435f9397155SAdrian Hunter 	zfree(&heap->heap_array);
436f9397155SAdrian Hunter 	heap->heap_cnt = 0;
437f9397155SAdrian Hunter 	heap->heap_sz = 0;
438f9397155SAdrian Hunter }
439f9397155SAdrian Hunter 
440f9397155SAdrian Hunter void auxtrace_heap__pop(struct auxtrace_heap *heap)
441f9397155SAdrian Hunter {
442f9397155SAdrian Hunter 	unsigned int pos, last, heap_cnt = heap->heap_cnt;
443f9397155SAdrian Hunter 	struct auxtrace_heap_item *heap_array;
444f9397155SAdrian Hunter 
445f9397155SAdrian Hunter 	if (!heap_cnt)
446f9397155SAdrian Hunter 		return;
447f9397155SAdrian Hunter 
448f9397155SAdrian Hunter 	heap->heap_cnt -= 1;
449f9397155SAdrian Hunter 
450f9397155SAdrian Hunter 	heap_array = heap->heap_array;
451f9397155SAdrian Hunter 
452f9397155SAdrian Hunter 	pos = 0;
453f9397155SAdrian Hunter 	while (1) {
454f9397155SAdrian Hunter 		unsigned int left, right;
455f9397155SAdrian Hunter 
456f9397155SAdrian Hunter 		left = (pos << 1) + 1;
457f9397155SAdrian Hunter 		if (left >= heap_cnt)
458f9397155SAdrian Hunter 			break;
459f9397155SAdrian Hunter 		right = left + 1;
460f9397155SAdrian Hunter 		if (right >= heap_cnt) {
461f9397155SAdrian Hunter 			heap_array[pos] = heap_array[left];
462f9397155SAdrian Hunter 			return;
463f9397155SAdrian Hunter 		}
464f9397155SAdrian Hunter 		if (heap_array[left].ordinal < heap_array[right].ordinal) {
465f9397155SAdrian Hunter 			heap_array[pos] = heap_array[left];
466f9397155SAdrian Hunter 			pos = left;
467f9397155SAdrian Hunter 		} else {
468f9397155SAdrian Hunter 			heap_array[pos] = heap_array[right];
469f9397155SAdrian Hunter 			pos = right;
470f9397155SAdrian Hunter 		}
471f9397155SAdrian Hunter 	}
472f9397155SAdrian Hunter 
473f9397155SAdrian Hunter 	last = heap_cnt - 1;
474f9397155SAdrian Hunter 	auxtrace_heapify(heap_array, pos, heap_array[last].queue_nr,
475f9397155SAdrian Hunter 			 heap_array[last].ordinal);
476f9397155SAdrian Hunter }
477f9397155SAdrian Hunter 
4789e0cc4feSAdrian Hunter size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr)
4799e0cc4feSAdrian Hunter {
4809e0cc4feSAdrian Hunter 	if (itr)
4819e0cc4feSAdrian Hunter 		return itr->info_priv_size(itr);
4829e0cc4feSAdrian Hunter 	return 0;
4839e0cc4feSAdrian Hunter }
4849e0cc4feSAdrian Hunter 
4859e0cc4feSAdrian Hunter static int auxtrace_not_supported(void)
4869e0cc4feSAdrian Hunter {
4879e0cc4feSAdrian Hunter 	pr_err("AUX area tracing is not supported on this architecture\n");
4889e0cc4feSAdrian Hunter 	return -EINVAL;
4899e0cc4feSAdrian Hunter }
4909e0cc4feSAdrian Hunter 
4919e0cc4feSAdrian Hunter int auxtrace_record__info_fill(struct auxtrace_record *itr,
4929e0cc4feSAdrian Hunter 			       struct perf_session *session,
4939e0cc4feSAdrian Hunter 			       struct auxtrace_info_event *auxtrace_info,
4949e0cc4feSAdrian Hunter 			       size_t priv_size)
4959e0cc4feSAdrian Hunter {
4969e0cc4feSAdrian Hunter 	if (itr)
4979e0cc4feSAdrian Hunter 		return itr->info_fill(itr, session, auxtrace_info, priv_size);
4989e0cc4feSAdrian Hunter 	return auxtrace_not_supported();
4999e0cc4feSAdrian Hunter }
5009e0cc4feSAdrian Hunter 
5019e0cc4feSAdrian Hunter void auxtrace_record__free(struct auxtrace_record *itr)
5029e0cc4feSAdrian Hunter {
5039e0cc4feSAdrian Hunter 	if (itr)
5049e0cc4feSAdrian Hunter 		itr->free(itr);
5059e0cc4feSAdrian Hunter }
5069e0cc4feSAdrian Hunter 
507d20031bbSAdrian Hunter int auxtrace_record__snapshot_start(struct auxtrace_record *itr)
508d20031bbSAdrian Hunter {
509d20031bbSAdrian Hunter 	if (itr && itr->snapshot_start)
510d20031bbSAdrian Hunter 		return itr->snapshot_start(itr);
511d20031bbSAdrian Hunter 	return 0;
512d20031bbSAdrian Hunter }
513d20031bbSAdrian Hunter 
514d20031bbSAdrian Hunter int auxtrace_record__snapshot_finish(struct auxtrace_record *itr)
515d20031bbSAdrian Hunter {
516d20031bbSAdrian Hunter 	if (itr && itr->snapshot_finish)
517d20031bbSAdrian Hunter 		return itr->snapshot_finish(itr);
518d20031bbSAdrian Hunter 	return 0;
519d20031bbSAdrian Hunter }
520d20031bbSAdrian Hunter 
521d20031bbSAdrian Hunter int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx,
522d20031bbSAdrian Hunter 				   struct auxtrace_mmap *mm,
523d20031bbSAdrian Hunter 				   unsigned char *data, u64 *head, u64 *old)
524d20031bbSAdrian Hunter {
525d20031bbSAdrian Hunter 	if (itr && itr->find_snapshot)
526d20031bbSAdrian Hunter 		return itr->find_snapshot(itr, idx, mm, data, head, old);
527d20031bbSAdrian Hunter 	return 0;
528d20031bbSAdrian Hunter }
529d20031bbSAdrian Hunter 
5309e0cc4feSAdrian Hunter int auxtrace_record__options(struct auxtrace_record *itr,
5319e0cc4feSAdrian Hunter 			     struct perf_evlist *evlist,
5329e0cc4feSAdrian Hunter 			     struct record_opts *opts)
5339e0cc4feSAdrian Hunter {
5349e0cc4feSAdrian Hunter 	if (itr)
5359e0cc4feSAdrian Hunter 		return itr->recording_options(itr, evlist, opts);
5369e0cc4feSAdrian Hunter 	return 0;
5379e0cc4feSAdrian Hunter }
5389e0cc4feSAdrian Hunter 
5399e0cc4feSAdrian Hunter u64 auxtrace_record__reference(struct auxtrace_record *itr)
5409e0cc4feSAdrian Hunter {
5419e0cc4feSAdrian Hunter 	if (itr)
5429e0cc4feSAdrian Hunter 		return itr->reference(itr);
5439e0cc4feSAdrian Hunter 	return 0;
5449e0cc4feSAdrian Hunter }
5459e0cc4feSAdrian Hunter 
546d20031bbSAdrian Hunter int auxtrace_parse_snapshot_options(struct auxtrace_record *itr,
547d20031bbSAdrian Hunter 				    struct record_opts *opts, const char *str)
548d20031bbSAdrian Hunter {
549d20031bbSAdrian Hunter 	if (!str)
550d20031bbSAdrian Hunter 		return 0;
551d20031bbSAdrian Hunter 
552d20031bbSAdrian Hunter 	if (itr)
553d20031bbSAdrian Hunter 		return itr->parse_snapshot_options(itr, opts, str);
554d20031bbSAdrian Hunter 
555d20031bbSAdrian Hunter 	pr_err("No AUX area tracing to snapshot\n");
556d20031bbSAdrian Hunter 	return -EINVAL;
557d20031bbSAdrian Hunter }
558d20031bbSAdrian Hunter 
5599e0cc4feSAdrian Hunter struct auxtrace_record *__weak
5609e0cc4feSAdrian Hunter auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err)
5619e0cc4feSAdrian Hunter {
5629e0cc4feSAdrian Hunter 	*err = 0;
5639e0cc4feSAdrian Hunter 	return NULL;
5649e0cc4feSAdrian Hunter }
5659e0cc4feSAdrian Hunter 
56699fa2984SAdrian Hunter static int auxtrace_index__alloc(struct list_head *head)
56799fa2984SAdrian Hunter {
56899fa2984SAdrian Hunter 	struct auxtrace_index *auxtrace_index;
56999fa2984SAdrian Hunter 
57099fa2984SAdrian Hunter 	auxtrace_index = malloc(sizeof(struct auxtrace_index));
57199fa2984SAdrian Hunter 	if (!auxtrace_index)
57299fa2984SAdrian Hunter 		return -ENOMEM;
57399fa2984SAdrian Hunter 
57499fa2984SAdrian Hunter 	auxtrace_index->nr = 0;
57599fa2984SAdrian Hunter 	INIT_LIST_HEAD(&auxtrace_index->list);
57699fa2984SAdrian Hunter 
57799fa2984SAdrian Hunter 	list_add_tail(&auxtrace_index->list, head);
57899fa2984SAdrian Hunter 
57999fa2984SAdrian Hunter 	return 0;
58099fa2984SAdrian Hunter }
58199fa2984SAdrian Hunter 
58299fa2984SAdrian Hunter void auxtrace_index__free(struct list_head *head)
58399fa2984SAdrian Hunter {
58499fa2984SAdrian Hunter 	struct auxtrace_index *auxtrace_index, *n;
58599fa2984SAdrian Hunter 
58699fa2984SAdrian Hunter 	list_for_each_entry_safe(auxtrace_index, n, head, list) {
58799fa2984SAdrian Hunter 		list_del(&auxtrace_index->list);
58899fa2984SAdrian Hunter 		free(auxtrace_index);
58999fa2984SAdrian Hunter 	}
59099fa2984SAdrian Hunter }
59199fa2984SAdrian Hunter 
59299fa2984SAdrian Hunter static struct auxtrace_index *auxtrace_index__last(struct list_head *head)
59399fa2984SAdrian Hunter {
59499fa2984SAdrian Hunter 	struct auxtrace_index *auxtrace_index;
59599fa2984SAdrian Hunter 	int err;
59699fa2984SAdrian Hunter 
59799fa2984SAdrian Hunter 	if (list_empty(head)) {
59899fa2984SAdrian Hunter 		err = auxtrace_index__alloc(head);
59999fa2984SAdrian Hunter 		if (err)
60099fa2984SAdrian Hunter 			return NULL;
60199fa2984SAdrian Hunter 	}
60299fa2984SAdrian Hunter 
60399fa2984SAdrian Hunter 	auxtrace_index = list_entry(head->prev, struct auxtrace_index, list);
60499fa2984SAdrian Hunter 
60599fa2984SAdrian Hunter 	if (auxtrace_index->nr >= PERF_AUXTRACE_INDEX_ENTRY_COUNT) {
60699fa2984SAdrian Hunter 		err = auxtrace_index__alloc(head);
60799fa2984SAdrian Hunter 		if (err)
60899fa2984SAdrian Hunter 			return NULL;
60999fa2984SAdrian Hunter 		auxtrace_index = list_entry(head->prev, struct auxtrace_index,
61099fa2984SAdrian Hunter 					    list);
61199fa2984SAdrian Hunter 	}
61299fa2984SAdrian Hunter 
61399fa2984SAdrian Hunter 	return auxtrace_index;
61499fa2984SAdrian Hunter }
61599fa2984SAdrian Hunter 
61699fa2984SAdrian Hunter int auxtrace_index__auxtrace_event(struct list_head *head,
61799fa2984SAdrian Hunter 				   union perf_event *event, off_t file_offset)
61899fa2984SAdrian Hunter {
61999fa2984SAdrian Hunter 	struct auxtrace_index *auxtrace_index;
62099fa2984SAdrian Hunter 	size_t nr;
62199fa2984SAdrian Hunter 
62299fa2984SAdrian Hunter 	auxtrace_index = auxtrace_index__last(head);
62399fa2984SAdrian Hunter 	if (!auxtrace_index)
62499fa2984SAdrian Hunter 		return -ENOMEM;
62599fa2984SAdrian Hunter 
62699fa2984SAdrian Hunter 	nr = auxtrace_index->nr;
62799fa2984SAdrian Hunter 	auxtrace_index->entries[nr].file_offset = file_offset;
62899fa2984SAdrian Hunter 	auxtrace_index->entries[nr].sz = event->header.size;
62999fa2984SAdrian Hunter 	auxtrace_index->nr += 1;
63099fa2984SAdrian Hunter 
63199fa2984SAdrian Hunter 	return 0;
63299fa2984SAdrian Hunter }
63399fa2984SAdrian Hunter 
63499fa2984SAdrian Hunter static int auxtrace_index__do_write(int fd,
63599fa2984SAdrian Hunter 				    struct auxtrace_index *auxtrace_index)
63699fa2984SAdrian Hunter {
63799fa2984SAdrian Hunter 	struct auxtrace_index_entry ent;
63899fa2984SAdrian Hunter 	size_t i;
63999fa2984SAdrian Hunter 
64099fa2984SAdrian Hunter 	for (i = 0; i < auxtrace_index->nr; i++) {
64199fa2984SAdrian Hunter 		ent.file_offset = auxtrace_index->entries[i].file_offset;
64299fa2984SAdrian Hunter 		ent.sz = auxtrace_index->entries[i].sz;
64399fa2984SAdrian Hunter 		if (writen(fd, &ent, sizeof(ent)) != sizeof(ent))
64499fa2984SAdrian Hunter 			return -errno;
64599fa2984SAdrian Hunter 	}
64699fa2984SAdrian Hunter 	return 0;
64799fa2984SAdrian Hunter }
64899fa2984SAdrian Hunter 
64999fa2984SAdrian Hunter int auxtrace_index__write(int fd, struct list_head *head)
65099fa2984SAdrian Hunter {
65199fa2984SAdrian Hunter 	struct auxtrace_index *auxtrace_index;
65299fa2984SAdrian Hunter 	u64 total = 0;
65399fa2984SAdrian Hunter 	int err;
65499fa2984SAdrian Hunter 
65599fa2984SAdrian Hunter 	list_for_each_entry(auxtrace_index, head, list)
65699fa2984SAdrian Hunter 		total += auxtrace_index->nr;
65799fa2984SAdrian Hunter 
65899fa2984SAdrian Hunter 	if (writen(fd, &total, sizeof(total)) != sizeof(total))
65999fa2984SAdrian Hunter 		return -errno;
66099fa2984SAdrian Hunter 
66199fa2984SAdrian Hunter 	list_for_each_entry(auxtrace_index, head, list) {
66299fa2984SAdrian Hunter 		err = auxtrace_index__do_write(fd, auxtrace_index);
66399fa2984SAdrian Hunter 		if (err)
66499fa2984SAdrian Hunter 			return err;
66599fa2984SAdrian Hunter 	}
66699fa2984SAdrian Hunter 
66799fa2984SAdrian Hunter 	return 0;
66899fa2984SAdrian Hunter }
66999fa2984SAdrian Hunter 
67099fa2984SAdrian Hunter static int auxtrace_index__process_entry(int fd, struct list_head *head,
67199fa2984SAdrian Hunter 					 bool needs_swap)
67299fa2984SAdrian Hunter {
67399fa2984SAdrian Hunter 	struct auxtrace_index *auxtrace_index;
67499fa2984SAdrian Hunter 	struct auxtrace_index_entry ent;
67599fa2984SAdrian Hunter 	size_t nr;
67699fa2984SAdrian Hunter 
67799fa2984SAdrian Hunter 	if (readn(fd, &ent, sizeof(ent)) != sizeof(ent))
67899fa2984SAdrian Hunter 		return -1;
67999fa2984SAdrian Hunter 
68099fa2984SAdrian Hunter 	auxtrace_index = auxtrace_index__last(head);
68199fa2984SAdrian Hunter 	if (!auxtrace_index)
68299fa2984SAdrian Hunter 		return -1;
68399fa2984SAdrian Hunter 
68499fa2984SAdrian Hunter 	nr = auxtrace_index->nr;
68599fa2984SAdrian Hunter 	if (needs_swap) {
68699fa2984SAdrian Hunter 		auxtrace_index->entries[nr].file_offset =
68799fa2984SAdrian Hunter 						bswap_64(ent.file_offset);
68899fa2984SAdrian Hunter 		auxtrace_index->entries[nr].sz = bswap_64(ent.sz);
68999fa2984SAdrian Hunter 	} else {
69099fa2984SAdrian Hunter 		auxtrace_index->entries[nr].file_offset = ent.file_offset;
69199fa2984SAdrian Hunter 		auxtrace_index->entries[nr].sz = ent.sz;
69299fa2984SAdrian Hunter 	}
69399fa2984SAdrian Hunter 
69499fa2984SAdrian Hunter 	auxtrace_index->nr = nr + 1;
69599fa2984SAdrian Hunter 
69699fa2984SAdrian Hunter 	return 0;
69799fa2984SAdrian Hunter }
69899fa2984SAdrian Hunter 
69999fa2984SAdrian Hunter int auxtrace_index__process(int fd, u64 size, struct perf_session *session,
70099fa2984SAdrian Hunter 			    bool needs_swap)
70199fa2984SAdrian Hunter {
70299fa2984SAdrian Hunter 	struct list_head *head = &session->auxtrace_index;
70399fa2984SAdrian Hunter 	u64 nr;
70499fa2984SAdrian Hunter 
70599fa2984SAdrian Hunter 	if (readn(fd, &nr, sizeof(u64)) != sizeof(u64))
70699fa2984SAdrian Hunter 		return -1;
70799fa2984SAdrian Hunter 
70899fa2984SAdrian Hunter 	if (needs_swap)
70999fa2984SAdrian Hunter 		nr = bswap_64(nr);
71099fa2984SAdrian Hunter 
71199fa2984SAdrian Hunter 	if (sizeof(u64) + nr * sizeof(struct auxtrace_index_entry) > size)
71299fa2984SAdrian Hunter 		return -1;
71399fa2984SAdrian Hunter 
71499fa2984SAdrian Hunter 	while (nr--) {
71599fa2984SAdrian Hunter 		int err;
71699fa2984SAdrian Hunter 
71799fa2984SAdrian Hunter 		err = auxtrace_index__process_entry(fd, head, needs_swap);
71899fa2984SAdrian Hunter 		if (err)
71999fa2984SAdrian Hunter 			return -1;
72099fa2984SAdrian Hunter 	}
72199fa2984SAdrian Hunter 
72299fa2984SAdrian Hunter 	return 0;
72399fa2984SAdrian Hunter }
72499fa2984SAdrian Hunter 
72599fa2984SAdrian Hunter static int auxtrace_queues__process_index_entry(struct auxtrace_queues *queues,
72699fa2984SAdrian Hunter 						struct perf_session *session,
72799fa2984SAdrian Hunter 						struct auxtrace_index_entry *ent)
72899fa2984SAdrian Hunter {
72999fa2984SAdrian Hunter 	return auxtrace_queues__add_indexed_event(queues, session,
73099fa2984SAdrian Hunter 						  ent->file_offset, ent->sz);
73199fa2984SAdrian Hunter }
73299fa2984SAdrian Hunter 
73399fa2984SAdrian Hunter int auxtrace_queues__process_index(struct auxtrace_queues *queues,
73499fa2984SAdrian Hunter 				   struct perf_session *session)
73599fa2984SAdrian Hunter {
73699fa2984SAdrian Hunter 	struct auxtrace_index *auxtrace_index;
73799fa2984SAdrian Hunter 	struct auxtrace_index_entry *ent;
73899fa2984SAdrian Hunter 	size_t i;
73999fa2984SAdrian Hunter 	int err;
74099fa2984SAdrian Hunter 
74199fa2984SAdrian Hunter 	list_for_each_entry(auxtrace_index, &session->auxtrace_index, list) {
74299fa2984SAdrian Hunter 		for (i = 0; i < auxtrace_index->nr; i++) {
74399fa2984SAdrian Hunter 			ent = &auxtrace_index->entries[i];
74499fa2984SAdrian Hunter 			err = auxtrace_queues__process_index_entry(queues,
74599fa2984SAdrian Hunter 								   session,
74699fa2984SAdrian Hunter 								   ent);
74799fa2984SAdrian Hunter 			if (err)
74899fa2984SAdrian Hunter 				return err;
74999fa2984SAdrian Hunter 		}
75099fa2984SAdrian Hunter 	}
75199fa2984SAdrian Hunter 	return 0;
75299fa2984SAdrian Hunter }
75399fa2984SAdrian Hunter 
754e5027893SAdrian Hunter struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue,
755e5027893SAdrian Hunter 					      struct auxtrace_buffer *buffer)
756e5027893SAdrian Hunter {
757e5027893SAdrian Hunter 	if (buffer) {
758e5027893SAdrian Hunter 		if (list_is_last(&buffer->list, &queue->head))
759e5027893SAdrian Hunter 			return NULL;
760e5027893SAdrian Hunter 		return list_entry(buffer->list.next, struct auxtrace_buffer,
761e5027893SAdrian Hunter 				  list);
762e5027893SAdrian Hunter 	} else {
763e5027893SAdrian Hunter 		if (list_empty(&queue->head))
764e5027893SAdrian Hunter 			return NULL;
765e5027893SAdrian Hunter 		return list_entry(queue->head.next, struct auxtrace_buffer,
766e5027893SAdrian Hunter 				  list);
767e5027893SAdrian Hunter 	}
768e5027893SAdrian Hunter }
769e5027893SAdrian Hunter 
770e5027893SAdrian Hunter void *auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd)
771e5027893SAdrian Hunter {
772e5027893SAdrian Hunter 	size_t adj = buffer->data_offset & (page_size - 1);
773e5027893SAdrian Hunter 	size_t size = buffer->size + adj;
774e5027893SAdrian Hunter 	off_t file_offset = buffer->data_offset - adj;
775e5027893SAdrian Hunter 	void *addr;
776e5027893SAdrian Hunter 
777e5027893SAdrian Hunter 	if (buffer->data)
778e5027893SAdrian Hunter 		return buffer->data;
779e5027893SAdrian Hunter 
780e5027893SAdrian Hunter 	addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, file_offset);
781e5027893SAdrian Hunter 	if (addr == MAP_FAILED)
782e5027893SAdrian Hunter 		return NULL;
783e5027893SAdrian Hunter 
784e5027893SAdrian Hunter 	buffer->mmap_addr = addr;
785e5027893SAdrian Hunter 	buffer->mmap_size = size;
786e5027893SAdrian Hunter 
787e5027893SAdrian Hunter 	buffer->data = addr + adj;
788e5027893SAdrian Hunter 
789e5027893SAdrian Hunter 	return buffer->data;
790e5027893SAdrian Hunter }
791e5027893SAdrian Hunter 
792e5027893SAdrian Hunter void auxtrace_buffer__put_data(struct auxtrace_buffer *buffer)
793e5027893SAdrian Hunter {
794e5027893SAdrian Hunter 	if (!buffer->data || !buffer->mmap_addr)
795e5027893SAdrian Hunter 		return;
796e5027893SAdrian Hunter 	munmap(buffer->mmap_addr, buffer->mmap_size);
797e5027893SAdrian Hunter 	buffer->mmap_addr = NULL;
798e5027893SAdrian Hunter 	buffer->mmap_size = 0;
799e5027893SAdrian Hunter 	buffer->data = NULL;
800e5027893SAdrian Hunter 	buffer->use_data = NULL;
801e5027893SAdrian Hunter }
802e5027893SAdrian Hunter 
803e5027893SAdrian Hunter void auxtrace_buffer__drop_data(struct auxtrace_buffer *buffer)
804e5027893SAdrian Hunter {
805e5027893SAdrian Hunter 	auxtrace_buffer__put_data(buffer);
806e5027893SAdrian Hunter 	if (buffer->data_needs_freeing) {
807e5027893SAdrian Hunter 		buffer->data_needs_freeing = false;
808e5027893SAdrian Hunter 		zfree(&buffer->data);
809e5027893SAdrian Hunter 		buffer->use_data = NULL;
810e5027893SAdrian Hunter 		buffer->size = 0;
811e5027893SAdrian Hunter 	}
812e5027893SAdrian Hunter }
813e5027893SAdrian Hunter 
814e5027893SAdrian Hunter void auxtrace_buffer__free(struct auxtrace_buffer *buffer)
815e5027893SAdrian Hunter {
816e5027893SAdrian Hunter 	auxtrace_buffer__drop_data(buffer);
817e5027893SAdrian Hunter 	free(buffer);
818e5027893SAdrian Hunter }
819e5027893SAdrian Hunter 
82085ed4729SAdrian Hunter void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type,
82185ed4729SAdrian Hunter 			  int code, int cpu, pid_t pid, pid_t tid, u64 ip,
82285ed4729SAdrian Hunter 			  const char *msg)
82385ed4729SAdrian Hunter {
82485ed4729SAdrian Hunter 	size_t size;
82585ed4729SAdrian Hunter 
82685ed4729SAdrian Hunter 	memset(auxtrace_error, 0, sizeof(struct auxtrace_error_event));
82785ed4729SAdrian Hunter 
82885ed4729SAdrian Hunter 	auxtrace_error->header.type = PERF_RECORD_AUXTRACE_ERROR;
82985ed4729SAdrian Hunter 	auxtrace_error->type = type;
83085ed4729SAdrian Hunter 	auxtrace_error->code = code;
83185ed4729SAdrian Hunter 	auxtrace_error->cpu = cpu;
83285ed4729SAdrian Hunter 	auxtrace_error->pid = pid;
83385ed4729SAdrian Hunter 	auxtrace_error->tid = tid;
83485ed4729SAdrian Hunter 	auxtrace_error->ip = ip;
83585ed4729SAdrian Hunter 	strlcpy(auxtrace_error->msg, msg, MAX_AUXTRACE_ERROR_MSG);
83685ed4729SAdrian Hunter 
83785ed4729SAdrian Hunter 	size = (void *)auxtrace_error->msg - (void *)auxtrace_error +
83885ed4729SAdrian Hunter 	       strlen(auxtrace_error->msg) + 1;
83985ed4729SAdrian Hunter 	auxtrace_error->header.size = PERF_ALIGN(size, sizeof(u64));
84085ed4729SAdrian Hunter }
84185ed4729SAdrian Hunter 
8429e0cc4feSAdrian Hunter int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr,
8439e0cc4feSAdrian Hunter 					 struct perf_tool *tool,
8449e0cc4feSAdrian Hunter 					 struct perf_session *session,
8459e0cc4feSAdrian Hunter 					 perf_event__handler_t process)
8469e0cc4feSAdrian Hunter {
8479e0cc4feSAdrian Hunter 	union perf_event *ev;
8489e0cc4feSAdrian Hunter 	size_t priv_size;
8499e0cc4feSAdrian Hunter 	int err;
8509e0cc4feSAdrian Hunter 
8519e0cc4feSAdrian Hunter 	pr_debug2("Synthesizing auxtrace information\n");
8529e0cc4feSAdrian Hunter 	priv_size = auxtrace_record__info_priv_size(itr);
8539e0cc4feSAdrian Hunter 	ev = zalloc(sizeof(struct auxtrace_info_event) + priv_size);
8549e0cc4feSAdrian Hunter 	if (!ev)
8559e0cc4feSAdrian Hunter 		return -ENOMEM;
8569e0cc4feSAdrian Hunter 
8579e0cc4feSAdrian Hunter 	ev->auxtrace_info.header.type = PERF_RECORD_AUXTRACE_INFO;
8589e0cc4feSAdrian Hunter 	ev->auxtrace_info.header.size = sizeof(struct auxtrace_info_event) +
8599e0cc4feSAdrian Hunter 					priv_size;
8609e0cc4feSAdrian Hunter 	err = auxtrace_record__info_fill(itr, session, &ev->auxtrace_info,
8619e0cc4feSAdrian Hunter 					 priv_size);
8629e0cc4feSAdrian Hunter 	if (err)
8639e0cc4feSAdrian Hunter 		goto out_free;
8649e0cc4feSAdrian Hunter 
8659e0cc4feSAdrian Hunter 	err = process(tool, ev, NULL, NULL);
8669e0cc4feSAdrian Hunter out_free:
8679e0cc4feSAdrian Hunter 	free(ev);
8689e0cc4feSAdrian Hunter 	return err;
8699e0cc4feSAdrian Hunter }
8709e0cc4feSAdrian Hunter 
87173f75fb1SAdrian Hunter static bool auxtrace__dont_decode(struct perf_session *session)
87273f75fb1SAdrian Hunter {
87373f75fb1SAdrian Hunter 	return !session->itrace_synth_opts ||
87473f75fb1SAdrian Hunter 	       session->itrace_synth_opts->dont_decode;
87573f75fb1SAdrian Hunter }
87673f75fb1SAdrian Hunter 
87773f75fb1SAdrian Hunter int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused,
87873f75fb1SAdrian Hunter 				      union perf_event *event,
87973f75fb1SAdrian Hunter 				      struct perf_session *session __maybe_unused)
88073f75fb1SAdrian Hunter {
88173f75fb1SAdrian Hunter 	enum auxtrace_type type = event->auxtrace_info.type;
88273f75fb1SAdrian Hunter 
88373f75fb1SAdrian Hunter 	if (dump_trace)
88473f75fb1SAdrian Hunter 		fprintf(stdout, " type: %u\n", type);
88573f75fb1SAdrian Hunter 
88673f75fb1SAdrian Hunter 	switch (type) {
88773f75fb1SAdrian Hunter 	case PERF_AUXTRACE_UNKNOWN:
88873f75fb1SAdrian Hunter 	default:
88973f75fb1SAdrian Hunter 		return -EINVAL;
89073f75fb1SAdrian Hunter 	}
89173f75fb1SAdrian Hunter }
89273f75fb1SAdrian Hunter 
89373f75fb1SAdrian Hunter s64 perf_event__process_auxtrace(struct perf_tool *tool,
89473f75fb1SAdrian Hunter 				 union perf_event *event,
89573f75fb1SAdrian Hunter 				 struct perf_session *session)
89673f75fb1SAdrian Hunter {
89773f75fb1SAdrian Hunter 	s64 err;
89873f75fb1SAdrian Hunter 
89973f75fb1SAdrian Hunter 	if (dump_trace)
90073f75fb1SAdrian Hunter 		fprintf(stdout, " size: %#"PRIx64"  offset: %#"PRIx64"  ref: %#"PRIx64"  idx: %u  tid: %d  cpu: %d\n",
90173f75fb1SAdrian Hunter 			event->auxtrace.size, event->auxtrace.offset,
90273f75fb1SAdrian Hunter 			event->auxtrace.reference, event->auxtrace.idx,
90373f75fb1SAdrian Hunter 			event->auxtrace.tid, event->auxtrace.cpu);
90473f75fb1SAdrian Hunter 
90573f75fb1SAdrian Hunter 	if (auxtrace__dont_decode(session))
90673f75fb1SAdrian Hunter 		return event->auxtrace.size;
90773f75fb1SAdrian Hunter 
90873f75fb1SAdrian Hunter 	if (!session->auxtrace || event->header.type != PERF_RECORD_AUXTRACE)
90973f75fb1SAdrian Hunter 		return -EINVAL;
91073f75fb1SAdrian Hunter 
91173f75fb1SAdrian Hunter 	err = session->auxtrace->process_auxtrace_event(session, event, tool);
91273f75fb1SAdrian Hunter 	if (err < 0)
91373f75fb1SAdrian Hunter 		return err;
91473f75fb1SAdrian Hunter 
91573f75fb1SAdrian Hunter 	return event->auxtrace.size;
91673f75fb1SAdrian Hunter }
91773f75fb1SAdrian Hunter 
918f6986c95SAdrian Hunter #define PERF_ITRACE_DEFAULT_PERIOD_TYPE		PERF_ITRACE_PERIOD_NANOSECS
919f6986c95SAdrian Hunter #define PERF_ITRACE_DEFAULT_PERIOD		100000
920f6986c95SAdrian Hunter #define PERF_ITRACE_DEFAULT_CALLCHAIN_SZ	16
921f6986c95SAdrian Hunter #define PERF_ITRACE_MAX_CALLCHAIN_SZ		1024
922f6986c95SAdrian Hunter 
923f6986c95SAdrian Hunter void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts)
924f6986c95SAdrian Hunter {
925f6986c95SAdrian Hunter 	synth_opts->instructions = true;
926f6986c95SAdrian Hunter 	synth_opts->branches = true;
92753c76b0eSAdrian Hunter 	synth_opts->transactions = true;
928f6986c95SAdrian Hunter 	synth_opts->errors = true;
929f6986c95SAdrian Hunter 	synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE;
930f6986c95SAdrian Hunter 	synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD;
931f6986c95SAdrian Hunter 	synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ;
932f6986c95SAdrian Hunter }
933f6986c95SAdrian Hunter 
934f6986c95SAdrian Hunter /*
935f6986c95SAdrian Hunter  * Please check tools/perf/Documentation/perf-script.txt for information
936f6986c95SAdrian Hunter  * about the options parsed here, which is introduced after this cset,
937f6986c95SAdrian Hunter  * when support in 'perf script' for these options is introduced.
938f6986c95SAdrian Hunter  */
939f6986c95SAdrian Hunter int itrace_parse_synth_opts(const struct option *opt, const char *str,
940f6986c95SAdrian Hunter 			    int unset)
941f6986c95SAdrian Hunter {
942f6986c95SAdrian Hunter 	struct itrace_synth_opts *synth_opts = opt->value;
943f6986c95SAdrian Hunter 	const char *p;
944f6986c95SAdrian Hunter 	char *endptr;
945f6986c95SAdrian Hunter 
946f6986c95SAdrian Hunter 	synth_opts->set = true;
947f6986c95SAdrian Hunter 
948f6986c95SAdrian Hunter 	if (unset) {
949f6986c95SAdrian Hunter 		synth_opts->dont_decode = true;
950f6986c95SAdrian Hunter 		return 0;
951f6986c95SAdrian Hunter 	}
952f6986c95SAdrian Hunter 
953f6986c95SAdrian Hunter 	if (!str) {
954f6986c95SAdrian Hunter 		itrace_synth_opts__set_default(synth_opts);
955f6986c95SAdrian Hunter 		return 0;
956f6986c95SAdrian Hunter 	}
957f6986c95SAdrian Hunter 
958f6986c95SAdrian Hunter 	for (p = str; *p;) {
959f6986c95SAdrian Hunter 		switch (*p++) {
960f6986c95SAdrian Hunter 		case 'i':
961f6986c95SAdrian Hunter 			synth_opts->instructions = true;
962f6986c95SAdrian Hunter 			while (*p == ' ' || *p == ',')
963f6986c95SAdrian Hunter 				p += 1;
964f6986c95SAdrian Hunter 			if (isdigit(*p)) {
965f6986c95SAdrian Hunter 				synth_opts->period = strtoull(p, &endptr, 10);
966f6986c95SAdrian Hunter 				p = endptr;
967f6986c95SAdrian Hunter 				while (*p == ' ' || *p == ',')
968f6986c95SAdrian Hunter 					p += 1;
969f6986c95SAdrian Hunter 				switch (*p++) {
970f6986c95SAdrian Hunter 				case 'i':
971f6986c95SAdrian Hunter 					synth_opts->period_type =
972f6986c95SAdrian Hunter 						PERF_ITRACE_PERIOD_INSTRUCTIONS;
973f6986c95SAdrian Hunter 					break;
974f6986c95SAdrian Hunter 				case 't':
975f6986c95SAdrian Hunter 					synth_opts->period_type =
976f6986c95SAdrian Hunter 						PERF_ITRACE_PERIOD_TICKS;
977f6986c95SAdrian Hunter 					break;
978f6986c95SAdrian Hunter 				case 'm':
979f6986c95SAdrian Hunter 					synth_opts->period *= 1000;
980f6986c95SAdrian Hunter 					/* Fall through */
981f6986c95SAdrian Hunter 				case 'u':
982f6986c95SAdrian Hunter 					synth_opts->period *= 1000;
983f6986c95SAdrian Hunter 					/* Fall through */
984f6986c95SAdrian Hunter 				case 'n':
985f6986c95SAdrian Hunter 					if (*p++ != 's')
986f6986c95SAdrian Hunter 						goto out_err;
987f6986c95SAdrian Hunter 					synth_opts->period_type =
988f6986c95SAdrian Hunter 						PERF_ITRACE_PERIOD_NANOSECS;
989f6986c95SAdrian Hunter 					break;
990f6986c95SAdrian Hunter 				case '\0':
991f6986c95SAdrian Hunter 					goto out;
992f6986c95SAdrian Hunter 				default:
993f6986c95SAdrian Hunter 					goto out_err;
994f6986c95SAdrian Hunter 				}
995f6986c95SAdrian Hunter 			}
996f6986c95SAdrian Hunter 			break;
997f6986c95SAdrian Hunter 		case 'b':
998f6986c95SAdrian Hunter 			synth_opts->branches = true;
999f6986c95SAdrian Hunter 			break;
100053c76b0eSAdrian Hunter 		case 'x':
100153c76b0eSAdrian Hunter 			synth_opts->transactions = true;
100253c76b0eSAdrian Hunter 			break;
1003f6986c95SAdrian Hunter 		case 'e':
1004f6986c95SAdrian Hunter 			synth_opts->errors = true;
1005f6986c95SAdrian Hunter 			break;
1006f6986c95SAdrian Hunter 		case 'd':
1007f6986c95SAdrian Hunter 			synth_opts->log = true;
1008f6986c95SAdrian Hunter 			break;
1009f6986c95SAdrian Hunter 		case 'c':
1010f6986c95SAdrian Hunter 			synth_opts->branches = true;
1011f6986c95SAdrian Hunter 			synth_opts->calls = true;
1012f6986c95SAdrian Hunter 			break;
1013f6986c95SAdrian Hunter 		case 'r':
1014f6986c95SAdrian Hunter 			synth_opts->branches = true;
1015f6986c95SAdrian Hunter 			synth_opts->returns = true;
1016f6986c95SAdrian Hunter 			break;
1017f6986c95SAdrian Hunter 		case 'g':
1018f6986c95SAdrian Hunter 			synth_opts->callchain = true;
1019f6986c95SAdrian Hunter 			synth_opts->callchain_sz =
1020f6986c95SAdrian Hunter 					PERF_ITRACE_DEFAULT_CALLCHAIN_SZ;
1021f6986c95SAdrian Hunter 			while (*p == ' ' || *p == ',')
1022f6986c95SAdrian Hunter 				p += 1;
1023f6986c95SAdrian Hunter 			if (isdigit(*p)) {
1024f6986c95SAdrian Hunter 				unsigned int val;
1025f6986c95SAdrian Hunter 
1026f6986c95SAdrian Hunter 				val = strtoul(p, &endptr, 10);
1027f6986c95SAdrian Hunter 				p = endptr;
1028f6986c95SAdrian Hunter 				if (!val || val > PERF_ITRACE_MAX_CALLCHAIN_SZ)
1029f6986c95SAdrian Hunter 					goto out_err;
1030f6986c95SAdrian Hunter 				synth_opts->callchain_sz = val;
1031f6986c95SAdrian Hunter 			}
1032f6986c95SAdrian Hunter 			break;
1033f6986c95SAdrian Hunter 		case ' ':
1034f6986c95SAdrian Hunter 		case ',':
1035f6986c95SAdrian Hunter 			break;
1036f6986c95SAdrian Hunter 		default:
1037f6986c95SAdrian Hunter 			goto out_err;
1038f6986c95SAdrian Hunter 		}
1039f6986c95SAdrian Hunter 	}
1040f6986c95SAdrian Hunter out:
1041f6986c95SAdrian Hunter 	if (synth_opts->instructions) {
1042f6986c95SAdrian Hunter 		if (!synth_opts->period_type)
1043f6986c95SAdrian Hunter 			synth_opts->period_type =
1044f6986c95SAdrian Hunter 					PERF_ITRACE_DEFAULT_PERIOD_TYPE;
1045f6986c95SAdrian Hunter 		if (!synth_opts->period)
1046f6986c95SAdrian Hunter 			synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD;
1047f6986c95SAdrian Hunter 	}
1048f6986c95SAdrian Hunter 
1049f6986c95SAdrian Hunter 	return 0;
1050f6986c95SAdrian Hunter 
1051f6986c95SAdrian Hunter out_err:
1052f6986c95SAdrian Hunter 	pr_err("Bad Instruction Tracing options '%s'\n", str);
1053f6986c95SAdrian Hunter 	return -EINVAL;
1054f6986c95SAdrian Hunter }
1055f6986c95SAdrian Hunter 
105685ed4729SAdrian Hunter static const char * const auxtrace_error_type_name[] = {
105785ed4729SAdrian Hunter 	[PERF_AUXTRACE_ERROR_ITRACE] = "instruction trace",
105885ed4729SAdrian Hunter };
105985ed4729SAdrian Hunter 
106085ed4729SAdrian Hunter static const char *auxtrace_error_name(int type)
106185ed4729SAdrian Hunter {
106285ed4729SAdrian Hunter 	const char *error_type_name = NULL;
106385ed4729SAdrian Hunter 
106485ed4729SAdrian Hunter 	if (type < PERF_AUXTRACE_ERROR_MAX)
106585ed4729SAdrian Hunter 		error_type_name = auxtrace_error_type_name[type];
106685ed4729SAdrian Hunter 	if (!error_type_name)
106785ed4729SAdrian Hunter 		error_type_name = "unknown AUX";
106885ed4729SAdrian Hunter 	return error_type_name;
106985ed4729SAdrian Hunter }
107085ed4729SAdrian Hunter 
107185ed4729SAdrian Hunter size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp)
107285ed4729SAdrian Hunter {
107385ed4729SAdrian Hunter 	struct auxtrace_error_event *e = &event->auxtrace_error;
107485ed4729SAdrian Hunter 	int ret;
107585ed4729SAdrian Hunter 
107685ed4729SAdrian Hunter 	ret = fprintf(fp, " %s error type %u",
107785ed4729SAdrian Hunter 		      auxtrace_error_name(e->type), e->type);
107885ed4729SAdrian Hunter 	ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRIx64" code %u: %s\n",
107985ed4729SAdrian Hunter 		       e->cpu, e->pid, e->tid, e->ip, e->code, e->msg);
108085ed4729SAdrian Hunter 	return ret;
108185ed4729SAdrian Hunter }
108285ed4729SAdrian Hunter 
108385ed4729SAdrian Hunter void perf_session__auxtrace_error_inc(struct perf_session *session,
108485ed4729SAdrian Hunter 				      union perf_event *event)
108585ed4729SAdrian Hunter {
108685ed4729SAdrian Hunter 	struct auxtrace_error_event *e = &event->auxtrace_error;
108785ed4729SAdrian Hunter 
108885ed4729SAdrian Hunter 	if (e->type < PERF_AUXTRACE_ERROR_MAX)
108985ed4729SAdrian Hunter 		session->evlist->stats.nr_auxtrace_errors[e->type] += 1;
109085ed4729SAdrian Hunter }
109185ed4729SAdrian Hunter 
109285ed4729SAdrian Hunter void events_stats__auxtrace_error_warn(const struct events_stats *stats)
109385ed4729SAdrian Hunter {
109485ed4729SAdrian Hunter 	int i;
109585ed4729SAdrian Hunter 
109685ed4729SAdrian Hunter 	for (i = 0; i < PERF_AUXTRACE_ERROR_MAX; i++) {
109785ed4729SAdrian Hunter 		if (!stats->nr_auxtrace_errors[i])
109885ed4729SAdrian Hunter 			continue;
109985ed4729SAdrian Hunter 		ui__warning("%u %s errors\n",
110085ed4729SAdrian Hunter 			    stats->nr_auxtrace_errors[i],
110185ed4729SAdrian Hunter 			    auxtrace_error_name(i));
110285ed4729SAdrian Hunter 	}
110385ed4729SAdrian Hunter }
110485ed4729SAdrian Hunter 
110585ed4729SAdrian Hunter int perf_event__process_auxtrace_error(struct perf_tool *tool __maybe_unused,
110685ed4729SAdrian Hunter 				       union perf_event *event,
110773f75fb1SAdrian Hunter 				       struct perf_session *session)
110885ed4729SAdrian Hunter {
110973f75fb1SAdrian Hunter 	if (auxtrace__dont_decode(session))
111073f75fb1SAdrian Hunter 		return 0;
111173f75fb1SAdrian Hunter 
111285ed4729SAdrian Hunter 	perf_event__fprintf_auxtrace_error(event, stdout);
111385ed4729SAdrian Hunter 	return 0;
111485ed4729SAdrian Hunter }
111585ed4729SAdrian Hunter 
1116d20031bbSAdrian Hunter static int __auxtrace_mmap__read(struct auxtrace_mmap *mm,
1117d20031bbSAdrian Hunter 				 struct auxtrace_record *itr,
1118d20031bbSAdrian Hunter 				 struct perf_tool *tool, process_auxtrace_t fn,
1119d20031bbSAdrian Hunter 				 bool snapshot, size_t snapshot_size)
11209e0cc4feSAdrian Hunter {
1121d20031bbSAdrian Hunter 	u64 head, old = mm->prev, offset, ref;
11229e0cc4feSAdrian Hunter 	unsigned char *data = mm->base;
11239e0cc4feSAdrian Hunter 	size_t size, head_off, old_off, len1, len2, padding;
11249e0cc4feSAdrian Hunter 	union perf_event ev;
11259e0cc4feSAdrian Hunter 	void *data1, *data2;
11269e0cc4feSAdrian Hunter 
1127d20031bbSAdrian Hunter 	if (snapshot) {
1128d20031bbSAdrian Hunter 		head = auxtrace_mmap__read_snapshot_head(mm);
1129d20031bbSAdrian Hunter 		if (auxtrace_record__find_snapshot(itr, mm->idx, mm, data,
1130d20031bbSAdrian Hunter 						   &head, &old))
1131d20031bbSAdrian Hunter 			return -1;
1132d20031bbSAdrian Hunter 	} else {
1133d20031bbSAdrian Hunter 		head = auxtrace_mmap__read_head(mm);
1134d20031bbSAdrian Hunter 	}
1135d20031bbSAdrian Hunter 
11369e0cc4feSAdrian Hunter 	if (old == head)
11379e0cc4feSAdrian Hunter 		return 0;
11389e0cc4feSAdrian Hunter 
11399e0cc4feSAdrian Hunter 	pr_debug3("auxtrace idx %d old %#"PRIx64" head %#"PRIx64" diff %#"PRIx64"\n",
11409e0cc4feSAdrian Hunter 		  mm->idx, old, head, head - old);
11419e0cc4feSAdrian Hunter 
11429e0cc4feSAdrian Hunter 	if (mm->mask) {
11439e0cc4feSAdrian Hunter 		head_off = head & mm->mask;
11449e0cc4feSAdrian Hunter 		old_off = old & mm->mask;
11459e0cc4feSAdrian Hunter 	} else {
11469e0cc4feSAdrian Hunter 		head_off = head % mm->len;
11479e0cc4feSAdrian Hunter 		old_off = old % mm->len;
11489e0cc4feSAdrian Hunter 	}
11499e0cc4feSAdrian Hunter 
11509e0cc4feSAdrian Hunter 	if (head_off > old_off)
11519e0cc4feSAdrian Hunter 		size = head_off - old_off;
11529e0cc4feSAdrian Hunter 	else
11539e0cc4feSAdrian Hunter 		size = mm->len - (old_off - head_off);
11549e0cc4feSAdrian Hunter 
1155d20031bbSAdrian Hunter 	if (snapshot && size > snapshot_size)
1156d20031bbSAdrian Hunter 		size = snapshot_size;
1157d20031bbSAdrian Hunter 
11589e0cc4feSAdrian Hunter 	ref = auxtrace_record__reference(itr);
11599e0cc4feSAdrian Hunter 
11609e0cc4feSAdrian Hunter 	if (head > old || size <= head || mm->mask) {
11619e0cc4feSAdrian Hunter 		offset = head - size;
11629e0cc4feSAdrian Hunter 	} else {
11639e0cc4feSAdrian Hunter 		/*
11649e0cc4feSAdrian Hunter 		 * When the buffer size is not a power of 2, 'head' wraps at the
11659e0cc4feSAdrian Hunter 		 * highest multiple of the buffer size, so we have to subtract
11669e0cc4feSAdrian Hunter 		 * the remainder here.
11679e0cc4feSAdrian Hunter 		 */
11689e0cc4feSAdrian Hunter 		u64 rem = (0ULL - mm->len) % mm->len;
11699e0cc4feSAdrian Hunter 
11709e0cc4feSAdrian Hunter 		offset = head - size - rem;
11719e0cc4feSAdrian Hunter 	}
11729e0cc4feSAdrian Hunter 
11739e0cc4feSAdrian Hunter 	if (size > head_off) {
11749e0cc4feSAdrian Hunter 		len1 = size - head_off;
11759e0cc4feSAdrian Hunter 		data1 = &data[mm->len - len1];
11769e0cc4feSAdrian Hunter 		len2 = head_off;
11779e0cc4feSAdrian Hunter 		data2 = &data[0];
11789e0cc4feSAdrian Hunter 	} else {
11799e0cc4feSAdrian Hunter 		len1 = size;
11809e0cc4feSAdrian Hunter 		data1 = &data[head_off - len1];
11819e0cc4feSAdrian Hunter 		len2 = 0;
11829e0cc4feSAdrian Hunter 		data2 = NULL;
11839e0cc4feSAdrian Hunter 	}
11849e0cc4feSAdrian Hunter 
118583b2ea25SAdrian Hunter 	if (itr->alignment) {
118683b2ea25SAdrian Hunter 		unsigned int unwanted = len1 % itr->alignment;
118783b2ea25SAdrian Hunter 
118883b2ea25SAdrian Hunter 		len1 -= unwanted;
118983b2ea25SAdrian Hunter 		size -= unwanted;
119083b2ea25SAdrian Hunter 	}
119183b2ea25SAdrian Hunter 
11929e0cc4feSAdrian Hunter 	/* padding must be written by fn() e.g. record__process_auxtrace() */
11939e0cc4feSAdrian Hunter 	padding = size & 7;
11949e0cc4feSAdrian Hunter 	if (padding)
11959e0cc4feSAdrian Hunter 		padding = 8 - padding;
11969e0cc4feSAdrian Hunter 
11979e0cc4feSAdrian Hunter 	memset(&ev, 0, sizeof(ev));
11989e0cc4feSAdrian Hunter 	ev.auxtrace.header.type = PERF_RECORD_AUXTRACE;
11999e0cc4feSAdrian Hunter 	ev.auxtrace.header.size = sizeof(ev.auxtrace);
12009e0cc4feSAdrian Hunter 	ev.auxtrace.size = size + padding;
12019e0cc4feSAdrian Hunter 	ev.auxtrace.offset = offset;
12029e0cc4feSAdrian Hunter 	ev.auxtrace.reference = ref;
12039e0cc4feSAdrian Hunter 	ev.auxtrace.idx = mm->idx;
12049e0cc4feSAdrian Hunter 	ev.auxtrace.tid = mm->tid;
12059e0cc4feSAdrian Hunter 	ev.auxtrace.cpu = mm->cpu;
12069e0cc4feSAdrian Hunter 
12079e0cc4feSAdrian Hunter 	if (fn(tool, &ev, data1, len1, data2, len2))
12089e0cc4feSAdrian Hunter 		return -1;
12099e0cc4feSAdrian Hunter 
12109e0cc4feSAdrian Hunter 	mm->prev = head;
12119e0cc4feSAdrian Hunter 
1212d20031bbSAdrian Hunter 	if (!snapshot) {
12139e0cc4feSAdrian Hunter 		auxtrace_mmap__write_tail(mm, head);
12149e0cc4feSAdrian Hunter 		if (itr->read_finish) {
12159e0cc4feSAdrian Hunter 			int err;
12169e0cc4feSAdrian Hunter 
12179e0cc4feSAdrian Hunter 			err = itr->read_finish(itr, mm->idx);
12189e0cc4feSAdrian Hunter 			if (err < 0)
12199e0cc4feSAdrian Hunter 				return err;
12209e0cc4feSAdrian Hunter 		}
1221d20031bbSAdrian Hunter 	}
12229e0cc4feSAdrian Hunter 
12239e0cc4feSAdrian Hunter 	return 1;
12249e0cc4feSAdrian Hunter }
1225c3278f02SAdrian Hunter 
1226d20031bbSAdrian Hunter int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
1227d20031bbSAdrian Hunter 			struct perf_tool *tool, process_auxtrace_t fn)
1228d20031bbSAdrian Hunter {
1229d20031bbSAdrian Hunter 	return __auxtrace_mmap__read(mm, itr, tool, fn, false, 0);
1230d20031bbSAdrian Hunter }
1231d20031bbSAdrian Hunter 
1232d20031bbSAdrian Hunter int auxtrace_mmap__read_snapshot(struct auxtrace_mmap *mm,
1233d20031bbSAdrian Hunter 				 struct auxtrace_record *itr,
1234d20031bbSAdrian Hunter 				 struct perf_tool *tool, process_auxtrace_t fn,
1235d20031bbSAdrian Hunter 				 size_t snapshot_size)
1236d20031bbSAdrian Hunter {
1237d20031bbSAdrian Hunter 	return __auxtrace_mmap__read(mm, itr, tool, fn, true, snapshot_size);
1238d20031bbSAdrian Hunter }
1239d20031bbSAdrian Hunter 
1240c3278f02SAdrian Hunter /**
1241c3278f02SAdrian Hunter  * struct auxtrace_cache - hash table to implement a cache
1242c3278f02SAdrian Hunter  * @hashtable: the hashtable
1243c3278f02SAdrian Hunter  * @sz: hashtable size (number of hlists)
1244c3278f02SAdrian Hunter  * @entry_size: size of an entry
1245c3278f02SAdrian Hunter  * @limit: limit the number of entries to this maximum, when reached the cache
1246c3278f02SAdrian Hunter  *         is dropped and caching begins again with an empty cache
1247c3278f02SAdrian Hunter  * @cnt: current number of entries
1248c3278f02SAdrian Hunter  * @bits: hashtable size (@sz = 2^@bits)
1249c3278f02SAdrian Hunter  */
1250c3278f02SAdrian Hunter struct auxtrace_cache {
1251c3278f02SAdrian Hunter 	struct hlist_head *hashtable;
1252c3278f02SAdrian Hunter 	size_t sz;
1253c3278f02SAdrian Hunter 	size_t entry_size;
1254c3278f02SAdrian Hunter 	size_t limit;
1255c3278f02SAdrian Hunter 	size_t cnt;
1256c3278f02SAdrian Hunter 	unsigned int bits;
1257c3278f02SAdrian Hunter };
1258c3278f02SAdrian Hunter 
1259c3278f02SAdrian Hunter struct auxtrace_cache *auxtrace_cache__new(unsigned int bits, size_t entry_size,
1260c3278f02SAdrian Hunter 					   unsigned int limit_percent)
1261c3278f02SAdrian Hunter {
1262c3278f02SAdrian Hunter 	struct auxtrace_cache *c;
1263c3278f02SAdrian Hunter 	struct hlist_head *ht;
1264c3278f02SAdrian Hunter 	size_t sz, i;
1265c3278f02SAdrian Hunter 
1266c3278f02SAdrian Hunter 	c = zalloc(sizeof(struct auxtrace_cache));
1267c3278f02SAdrian Hunter 	if (!c)
1268c3278f02SAdrian Hunter 		return NULL;
1269c3278f02SAdrian Hunter 
1270c3278f02SAdrian Hunter 	sz = 1UL << bits;
1271c3278f02SAdrian Hunter 
1272c3278f02SAdrian Hunter 	ht = calloc(sz, sizeof(struct hlist_head));
1273c3278f02SAdrian Hunter 	if (!ht)
1274c3278f02SAdrian Hunter 		goto out_free;
1275c3278f02SAdrian Hunter 
1276c3278f02SAdrian Hunter 	for (i = 0; i < sz; i++)
1277c3278f02SAdrian Hunter 		INIT_HLIST_HEAD(&ht[i]);
1278c3278f02SAdrian Hunter 
1279c3278f02SAdrian Hunter 	c->hashtable = ht;
1280c3278f02SAdrian Hunter 	c->sz = sz;
1281c3278f02SAdrian Hunter 	c->entry_size = entry_size;
1282c3278f02SAdrian Hunter 	c->limit = (c->sz * limit_percent) / 100;
1283c3278f02SAdrian Hunter 	c->bits = bits;
1284c3278f02SAdrian Hunter 
1285c3278f02SAdrian Hunter 	return c;
1286c3278f02SAdrian Hunter 
1287c3278f02SAdrian Hunter out_free:
1288c3278f02SAdrian Hunter 	free(c);
1289c3278f02SAdrian Hunter 	return NULL;
1290c3278f02SAdrian Hunter }
1291c3278f02SAdrian Hunter 
1292c3278f02SAdrian Hunter static void auxtrace_cache__drop(struct auxtrace_cache *c)
1293c3278f02SAdrian Hunter {
1294c3278f02SAdrian Hunter 	struct auxtrace_cache_entry *entry;
1295c3278f02SAdrian Hunter 	struct hlist_node *tmp;
1296c3278f02SAdrian Hunter 	size_t i;
1297c3278f02SAdrian Hunter 
1298c3278f02SAdrian Hunter 	if (!c)
1299c3278f02SAdrian Hunter 		return;
1300c3278f02SAdrian Hunter 
1301c3278f02SAdrian Hunter 	for (i = 0; i < c->sz; i++) {
1302c3278f02SAdrian Hunter 		hlist_for_each_entry_safe(entry, tmp, &c->hashtable[i], hash) {
1303c3278f02SAdrian Hunter 			hlist_del(&entry->hash);
1304c3278f02SAdrian Hunter 			auxtrace_cache__free_entry(c, entry);
1305c3278f02SAdrian Hunter 		}
1306c3278f02SAdrian Hunter 	}
1307c3278f02SAdrian Hunter 
1308c3278f02SAdrian Hunter 	c->cnt = 0;
1309c3278f02SAdrian Hunter }
1310c3278f02SAdrian Hunter 
1311c3278f02SAdrian Hunter void auxtrace_cache__free(struct auxtrace_cache *c)
1312c3278f02SAdrian Hunter {
1313c3278f02SAdrian Hunter 	if (!c)
1314c3278f02SAdrian Hunter 		return;
1315c3278f02SAdrian Hunter 
1316c3278f02SAdrian Hunter 	auxtrace_cache__drop(c);
1317c3278f02SAdrian Hunter 	free(c->hashtable);
1318c3278f02SAdrian Hunter 	free(c);
1319c3278f02SAdrian Hunter }
1320c3278f02SAdrian Hunter 
1321c3278f02SAdrian Hunter void *auxtrace_cache__alloc_entry(struct auxtrace_cache *c)
1322c3278f02SAdrian Hunter {
1323c3278f02SAdrian Hunter 	return malloc(c->entry_size);
1324c3278f02SAdrian Hunter }
1325c3278f02SAdrian Hunter 
1326c3278f02SAdrian Hunter void auxtrace_cache__free_entry(struct auxtrace_cache *c __maybe_unused,
1327c3278f02SAdrian Hunter 				void *entry)
1328c3278f02SAdrian Hunter {
1329c3278f02SAdrian Hunter 	free(entry);
1330c3278f02SAdrian Hunter }
1331c3278f02SAdrian Hunter 
1332c3278f02SAdrian Hunter int auxtrace_cache__add(struct auxtrace_cache *c, u32 key,
1333c3278f02SAdrian Hunter 			struct auxtrace_cache_entry *entry)
1334c3278f02SAdrian Hunter {
1335c3278f02SAdrian Hunter 	if (c->limit && ++c->cnt > c->limit)
1336c3278f02SAdrian Hunter 		auxtrace_cache__drop(c);
1337c3278f02SAdrian Hunter 
1338c3278f02SAdrian Hunter 	entry->key = key;
1339c3278f02SAdrian Hunter 	hlist_add_head(&entry->hash, &c->hashtable[hash_32(key, c->bits)]);
1340c3278f02SAdrian Hunter 
1341c3278f02SAdrian Hunter 	return 0;
1342c3278f02SAdrian Hunter }
1343c3278f02SAdrian Hunter 
1344c3278f02SAdrian Hunter void *auxtrace_cache__lookup(struct auxtrace_cache *c, u32 key)
1345c3278f02SAdrian Hunter {
1346c3278f02SAdrian Hunter 	struct auxtrace_cache_entry *entry;
1347c3278f02SAdrian Hunter 	struct hlist_head *hlist;
1348c3278f02SAdrian Hunter 
1349c3278f02SAdrian Hunter 	if (!c)
1350c3278f02SAdrian Hunter 		return NULL;
1351c3278f02SAdrian Hunter 
1352c3278f02SAdrian Hunter 	hlist = &c->hashtable[hash_32(key, c->bits)];
1353c3278f02SAdrian Hunter 	hlist_for_each_entry(entry, hlist, hash) {
1354c3278f02SAdrian Hunter 		if (entry->key == key)
1355c3278f02SAdrian Hunter 			return entry;
1356c3278f02SAdrian Hunter 	}
1357c3278f02SAdrian Hunter 
1358c3278f02SAdrian Hunter 	return NULL;
1359c3278f02SAdrian Hunter }
1360