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