162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Arm Statistical Profiling Extensions (SPE) support 462306a36Sopenharmony_ci * Copyright (c) 2017-2018, Arm Ltd. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <byteswap.h> 862306a36Sopenharmony_ci#include <endian.h> 962306a36Sopenharmony_ci#include <errno.h> 1062306a36Sopenharmony_ci#include <inttypes.h> 1162306a36Sopenharmony_ci#include <linux/bitops.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/log2.h> 1462306a36Sopenharmony_ci#include <linux/types.h> 1562306a36Sopenharmony_ci#include <linux/zalloc.h> 1662306a36Sopenharmony_ci#include <stdlib.h> 1762306a36Sopenharmony_ci#include <unistd.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "auxtrace.h" 2062306a36Sopenharmony_ci#include "color.h" 2162306a36Sopenharmony_ci#include "debug.h" 2262306a36Sopenharmony_ci#include "evlist.h" 2362306a36Sopenharmony_ci#include "evsel.h" 2462306a36Sopenharmony_ci#include "machine.h" 2562306a36Sopenharmony_ci#include "session.h" 2662306a36Sopenharmony_ci#include "symbol.h" 2762306a36Sopenharmony_ci#include "thread.h" 2862306a36Sopenharmony_ci#include "thread-stack.h" 2962306a36Sopenharmony_ci#include "tsc.h" 3062306a36Sopenharmony_ci#include "tool.h" 3162306a36Sopenharmony_ci#include "util/synthetic-events.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include "arm-spe.h" 3462306a36Sopenharmony_ci#include "arm-spe-decoder/arm-spe-decoder.h" 3562306a36Sopenharmony_ci#include "arm-spe-decoder/arm-spe-pkt-decoder.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include "../../arch/arm64/include/asm/cputype.h" 3862306a36Sopenharmony_ci#define MAX_TIMESTAMP (~0ULL) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistruct arm_spe { 4162306a36Sopenharmony_ci struct auxtrace auxtrace; 4262306a36Sopenharmony_ci struct auxtrace_queues queues; 4362306a36Sopenharmony_ci struct auxtrace_heap heap; 4462306a36Sopenharmony_ci struct itrace_synth_opts synth_opts; 4562306a36Sopenharmony_ci u32 auxtrace_type; 4662306a36Sopenharmony_ci struct perf_session *session; 4762306a36Sopenharmony_ci struct machine *machine; 4862306a36Sopenharmony_ci u32 pmu_type; 4962306a36Sopenharmony_ci u64 midr; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci struct perf_tsc_conversion tc; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci u8 timeless_decoding; 5462306a36Sopenharmony_ci u8 data_queued; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci u64 sample_type; 5762306a36Sopenharmony_ci u8 sample_flc; 5862306a36Sopenharmony_ci u8 sample_llc; 5962306a36Sopenharmony_ci u8 sample_tlb; 6062306a36Sopenharmony_ci u8 sample_branch; 6162306a36Sopenharmony_ci u8 sample_remote_access; 6262306a36Sopenharmony_ci u8 sample_memory; 6362306a36Sopenharmony_ci u8 sample_instructions; 6462306a36Sopenharmony_ci u64 instructions_sample_period; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci u64 l1d_miss_id; 6762306a36Sopenharmony_ci u64 l1d_access_id; 6862306a36Sopenharmony_ci u64 llc_miss_id; 6962306a36Sopenharmony_ci u64 llc_access_id; 7062306a36Sopenharmony_ci u64 tlb_miss_id; 7162306a36Sopenharmony_ci u64 tlb_access_id; 7262306a36Sopenharmony_ci u64 branch_miss_id; 7362306a36Sopenharmony_ci u64 remote_access_id; 7462306a36Sopenharmony_ci u64 memory_id; 7562306a36Sopenharmony_ci u64 instructions_id; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci u64 kernel_start; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci unsigned long num_events; 8062306a36Sopenharmony_ci u8 use_ctx_pkt_for_pid; 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistruct arm_spe_queue { 8462306a36Sopenharmony_ci struct arm_spe *spe; 8562306a36Sopenharmony_ci unsigned int queue_nr; 8662306a36Sopenharmony_ci struct auxtrace_buffer *buffer; 8762306a36Sopenharmony_ci struct auxtrace_buffer *old_buffer; 8862306a36Sopenharmony_ci union perf_event *event_buf; 8962306a36Sopenharmony_ci bool on_heap; 9062306a36Sopenharmony_ci bool done; 9162306a36Sopenharmony_ci pid_t pid; 9262306a36Sopenharmony_ci pid_t tid; 9362306a36Sopenharmony_ci int cpu; 9462306a36Sopenharmony_ci struct arm_spe_decoder *decoder; 9562306a36Sopenharmony_ci u64 time; 9662306a36Sopenharmony_ci u64 timestamp; 9762306a36Sopenharmony_ci struct thread *thread; 9862306a36Sopenharmony_ci u64 period_instructions; 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic void arm_spe_dump(struct arm_spe *spe __maybe_unused, 10262306a36Sopenharmony_ci unsigned char *buf, size_t len) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci struct arm_spe_pkt packet; 10562306a36Sopenharmony_ci size_t pos = 0; 10662306a36Sopenharmony_ci int ret, pkt_len, i; 10762306a36Sopenharmony_ci char desc[ARM_SPE_PKT_DESC_MAX]; 10862306a36Sopenharmony_ci const char *color = PERF_COLOR_BLUE; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci color_fprintf(stdout, color, 11162306a36Sopenharmony_ci ". ... ARM SPE data: size %#zx bytes\n", 11262306a36Sopenharmony_ci len); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci while (len) { 11562306a36Sopenharmony_ci ret = arm_spe_get_packet(buf, len, &packet); 11662306a36Sopenharmony_ci if (ret > 0) 11762306a36Sopenharmony_ci pkt_len = ret; 11862306a36Sopenharmony_ci else 11962306a36Sopenharmony_ci pkt_len = 1; 12062306a36Sopenharmony_ci printf("."); 12162306a36Sopenharmony_ci color_fprintf(stdout, color, " %08x: ", pos); 12262306a36Sopenharmony_ci for (i = 0; i < pkt_len; i++) 12362306a36Sopenharmony_ci color_fprintf(stdout, color, " %02x", buf[i]); 12462306a36Sopenharmony_ci for (; i < 16; i++) 12562306a36Sopenharmony_ci color_fprintf(stdout, color, " "); 12662306a36Sopenharmony_ci if (ret > 0) { 12762306a36Sopenharmony_ci ret = arm_spe_pkt_desc(&packet, desc, 12862306a36Sopenharmony_ci ARM_SPE_PKT_DESC_MAX); 12962306a36Sopenharmony_ci if (!ret) 13062306a36Sopenharmony_ci color_fprintf(stdout, color, " %s\n", desc); 13162306a36Sopenharmony_ci } else { 13262306a36Sopenharmony_ci color_fprintf(stdout, color, " Bad packet!\n"); 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci pos += pkt_len; 13562306a36Sopenharmony_ci buf += pkt_len; 13662306a36Sopenharmony_ci len -= pkt_len; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic void arm_spe_dump_event(struct arm_spe *spe, unsigned char *buf, 14162306a36Sopenharmony_ci size_t len) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci printf(".\n"); 14462306a36Sopenharmony_ci arm_spe_dump(spe, buf, len); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic int arm_spe_get_trace(struct arm_spe_buffer *b, void *data) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct arm_spe_queue *speq = data; 15062306a36Sopenharmony_ci struct auxtrace_buffer *buffer = speq->buffer; 15162306a36Sopenharmony_ci struct auxtrace_buffer *old_buffer = speq->old_buffer; 15262306a36Sopenharmony_ci struct auxtrace_queue *queue; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci queue = &speq->spe->queues.queue_array[speq->queue_nr]; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci buffer = auxtrace_buffer__next(queue, buffer); 15762306a36Sopenharmony_ci /* If no more data, drop the previous auxtrace_buffer and return */ 15862306a36Sopenharmony_ci if (!buffer) { 15962306a36Sopenharmony_ci if (old_buffer) 16062306a36Sopenharmony_ci auxtrace_buffer__drop_data(old_buffer); 16162306a36Sopenharmony_ci b->len = 0; 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci speq->buffer = buffer; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* If the aux_buffer doesn't have data associated, try to load it */ 16862306a36Sopenharmony_ci if (!buffer->data) { 16962306a36Sopenharmony_ci /* get the file desc associated with the perf data file */ 17062306a36Sopenharmony_ci int fd = perf_data__fd(speq->spe->session->data); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci buffer->data = auxtrace_buffer__get_data(buffer, fd); 17362306a36Sopenharmony_ci if (!buffer->data) 17462306a36Sopenharmony_ci return -ENOMEM; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci b->len = buffer->size; 17862306a36Sopenharmony_ci b->buf = buffer->data; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (b->len) { 18162306a36Sopenharmony_ci if (old_buffer) 18262306a36Sopenharmony_ci auxtrace_buffer__drop_data(old_buffer); 18362306a36Sopenharmony_ci speq->old_buffer = buffer; 18462306a36Sopenharmony_ci } else { 18562306a36Sopenharmony_ci auxtrace_buffer__drop_data(buffer); 18662306a36Sopenharmony_ci return arm_spe_get_trace(b, data); 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci return 0; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic struct arm_spe_queue *arm_spe__alloc_queue(struct arm_spe *spe, 19362306a36Sopenharmony_ci unsigned int queue_nr) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct arm_spe_params params = { .get_trace = 0, }; 19662306a36Sopenharmony_ci struct arm_spe_queue *speq; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci speq = zalloc(sizeof(*speq)); 19962306a36Sopenharmony_ci if (!speq) 20062306a36Sopenharmony_ci return NULL; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci speq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE); 20362306a36Sopenharmony_ci if (!speq->event_buf) 20462306a36Sopenharmony_ci goto out_free; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci speq->spe = spe; 20762306a36Sopenharmony_ci speq->queue_nr = queue_nr; 20862306a36Sopenharmony_ci speq->pid = -1; 20962306a36Sopenharmony_ci speq->tid = -1; 21062306a36Sopenharmony_ci speq->cpu = -1; 21162306a36Sopenharmony_ci speq->period_instructions = 0; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* params set */ 21462306a36Sopenharmony_ci params.get_trace = arm_spe_get_trace; 21562306a36Sopenharmony_ci params.data = speq; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci /* create new decoder */ 21862306a36Sopenharmony_ci speq->decoder = arm_spe_decoder_new(¶ms); 21962306a36Sopenharmony_ci if (!speq->decoder) 22062306a36Sopenharmony_ci goto out_free; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci return speq; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ciout_free: 22562306a36Sopenharmony_ci zfree(&speq->event_buf); 22662306a36Sopenharmony_ci free(speq); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci return NULL; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic inline u8 arm_spe_cpumode(struct arm_spe *spe, u64 ip) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci return ip >= spe->kernel_start ? 23462306a36Sopenharmony_ci PERF_RECORD_MISC_KERNEL : 23562306a36Sopenharmony_ci PERF_RECORD_MISC_USER; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic void arm_spe_set_pid_tid_cpu(struct arm_spe *spe, 23962306a36Sopenharmony_ci struct auxtrace_queue *queue) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct arm_spe_queue *speq = queue->priv; 24262306a36Sopenharmony_ci pid_t tid; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci tid = machine__get_current_tid(spe->machine, speq->cpu); 24562306a36Sopenharmony_ci if (tid != -1) { 24662306a36Sopenharmony_ci speq->tid = tid; 24762306a36Sopenharmony_ci thread__zput(speq->thread); 24862306a36Sopenharmony_ci } else 24962306a36Sopenharmony_ci speq->tid = queue->tid; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if ((!speq->thread) && (speq->tid != -1)) { 25262306a36Sopenharmony_ci speq->thread = machine__find_thread(spe->machine, -1, 25362306a36Sopenharmony_ci speq->tid); 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (speq->thread) { 25762306a36Sopenharmony_ci speq->pid = thread__pid(speq->thread); 25862306a36Sopenharmony_ci if (queue->cpu == -1) 25962306a36Sopenharmony_ci speq->cpu = thread__cpu(speq->thread); 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic int arm_spe_set_tid(struct arm_spe_queue *speq, pid_t tid) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct arm_spe *spe = speq->spe; 26662306a36Sopenharmony_ci int err = machine__set_current_tid(spe->machine, speq->cpu, -1, tid); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (err) 26962306a36Sopenharmony_ci return err; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci arm_spe_set_pid_tid_cpu(spe, &spe->queues.queue_array[speq->queue_nr]); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return 0; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic struct simd_flags arm_spe__synth_simd_flags(const struct arm_spe_record *record) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct simd_flags simd_flags = {}; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if ((record->op & ARM_SPE_OP_LDST) && (record->op & ARM_SPE_OP_SVE_LDST)) 28162306a36Sopenharmony_ci simd_flags.arch |= SIMD_OP_FLAGS_ARCH_SVE; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if ((record->op & ARM_SPE_OP_OTHER) && (record->op & ARM_SPE_OP_SVE_OTHER)) 28462306a36Sopenharmony_ci simd_flags.arch |= SIMD_OP_FLAGS_ARCH_SVE; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (record->type & ARM_SPE_SVE_PARTIAL_PRED) 28762306a36Sopenharmony_ci simd_flags.pred |= SIMD_OP_FLAGS_PRED_PARTIAL; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (record->type & ARM_SPE_SVE_EMPTY_PRED) 29062306a36Sopenharmony_ci simd_flags.pred |= SIMD_OP_FLAGS_PRED_EMPTY; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return simd_flags; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic void arm_spe_prep_sample(struct arm_spe *spe, 29662306a36Sopenharmony_ci struct arm_spe_queue *speq, 29762306a36Sopenharmony_ci union perf_event *event, 29862306a36Sopenharmony_ci struct perf_sample *sample) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci struct arm_spe_record *record = &speq->decoder->record; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (!spe->timeless_decoding) 30362306a36Sopenharmony_ci sample->time = tsc_to_perf_time(record->timestamp, &spe->tc); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci sample->ip = record->from_ip; 30662306a36Sopenharmony_ci sample->cpumode = arm_spe_cpumode(spe, sample->ip); 30762306a36Sopenharmony_ci sample->pid = speq->pid; 30862306a36Sopenharmony_ci sample->tid = speq->tid; 30962306a36Sopenharmony_ci sample->period = 1; 31062306a36Sopenharmony_ci sample->cpu = speq->cpu; 31162306a36Sopenharmony_ci sample->simd_flags = arm_spe__synth_simd_flags(record); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci event->sample.header.type = PERF_RECORD_SAMPLE; 31462306a36Sopenharmony_ci event->sample.header.misc = sample->cpumode; 31562306a36Sopenharmony_ci event->sample.header.size = sizeof(struct perf_event_header); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int arm_spe__inject_event(union perf_event *event, struct perf_sample *sample, u64 type) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci event->header.size = perf_event__sample_event_size(sample, type, 0); 32162306a36Sopenharmony_ci return perf_event__synthesize_sample(event, type, 0, sample); 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic inline int 32562306a36Sopenharmony_ciarm_spe_deliver_synth_event(struct arm_spe *spe, 32662306a36Sopenharmony_ci struct arm_spe_queue *speq __maybe_unused, 32762306a36Sopenharmony_ci union perf_event *event, 32862306a36Sopenharmony_ci struct perf_sample *sample) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci int ret; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (spe->synth_opts.inject) { 33362306a36Sopenharmony_ci ret = arm_spe__inject_event(event, sample, spe->sample_type); 33462306a36Sopenharmony_ci if (ret) 33562306a36Sopenharmony_ci return ret; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci ret = perf_session__deliver_synth_event(spe->session, event, sample); 33962306a36Sopenharmony_ci if (ret) 34062306a36Sopenharmony_ci pr_err("ARM SPE: failed to deliver event, error %d\n", ret); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci return ret; 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic int arm_spe__synth_mem_sample(struct arm_spe_queue *speq, 34662306a36Sopenharmony_ci u64 spe_events_id, u64 data_src) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci struct arm_spe *spe = speq->spe; 34962306a36Sopenharmony_ci struct arm_spe_record *record = &speq->decoder->record; 35062306a36Sopenharmony_ci union perf_event *event = speq->event_buf; 35162306a36Sopenharmony_ci struct perf_sample sample = { .ip = 0, }; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci arm_spe_prep_sample(spe, speq, event, &sample); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci sample.id = spe_events_id; 35662306a36Sopenharmony_ci sample.stream_id = spe_events_id; 35762306a36Sopenharmony_ci sample.addr = record->virt_addr; 35862306a36Sopenharmony_ci sample.phys_addr = record->phys_addr; 35962306a36Sopenharmony_ci sample.data_src = data_src; 36062306a36Sopenharmony_ci sample.weight = record->latency; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci return arm_spe_deliver_synth_event(spe, speq, event, &sample); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic int arm_spe__synth_branch_sample(struct arm_spe_queue *speq, 36662306a36Sopenharmony_ci u64 spe_events_id) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct arm_spe *spe = speq->spe; 36962306a36Sopenharmony_ci struct arm_spe_record *record = &speq->decoder->record; 37062306a36Sopenharmony_ci union perf_event *event = speq->event_buf; 37162306a36Sopenharmony_ci struct perf_sample sample = { .ip = 0, }; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci arm_spe_prep_sample(spe, speq, event, &sample); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci sample.id = spe_events_id; 37662306a36Sopenharmony_ci sample.stream_id = spe_events_id; 37762306a36Sopenharmony_ci sample.addr = record->to_ip; 37862306a36Sopenharmony_ci sample.weight = record->latency; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci return arm_spe_deliver_synth_event(spe, speq, event, &sample); 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic int arm_spe__synth_instruction_sample(struct arm_spe_queue *speq, 38462306a36Sopenharmony_ci u64 spe_events_id, u64 data_src) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct arm_spe *spe = speq->spe; 38762306a36Sopenharmony_ci struct arm_spe_record *record = &speq->decoder->record; 38862306a36Sopenharmony_ci union perf_event *event = speq->event_buf; 38962306a36Sopenharmony_ci struct perf_sample sample = { .ip = 0, }; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci /* 39262306a36Sopenharmony_ci * Handles perf instruction sampling period. 39362306a36Sopenharmony_ci */ 39462306a36Sopenharmony_ci speq->period_instructions++; 39562306a36Sopenharmony_ci if (speq->period_instructions < spe->instructions_sample_period) 39662306a36Sopenharmony_ci return 0; 39762306a36Sopenharmony_ci speq->period_instructions = 0; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci arm_spe_prep_sample(spe, speq, event, &sample); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci sample.id = spe_events_id; 40262306a36Sopenharmony_ci sample.stream_id = spe_events_id; 40362306a36Sopenharmony_ci sample.addr = record->virt_addr; 40462306a36Sopenharmony_ci sample.phys_addr = record->phys_addr; 40562306a36Sopenharmony_ci sample.data_src = data_src; 40662306a36Sopenharmony_ci sample.period = spe->instructions_sample_period; 40762306a36Sopenharmony_ci sample.weight = record->latency; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci return arm_spe_deliver_synth_event(spe, speq, event, &sample); 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic const struct midr_range neoverse_spe[] = { 41362306a36Sopenharmony_ci MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1), 41462306a36Sopenharmony_ci MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), 41562306a36Sopenharmony_ci MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V1), 41662306a36Sopenharmony_ci {}, 41762306a36Sopenharmony_ci}; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic void arm_spe__synth_data_source_neoverse(const struct arm_spe_record *record, 42062306a36Sopenharmony_ci union perf_mem_data_src *data_src) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci /* 42362306a36Sopenharmony_ci * Even though four levels of cache hierarchy are possible, no known 42462306a36Sopenharmony_ci * production Neoverse systems currently include more than three levels 42562306a36Sopenharmony_ci * so for the time being we assume three exist. If a production system 42662306a36Sopenharmony_ci * is built with four the this function would have to be changed to 42762306a36Sopenharmony_ci * detect the number of levels for reporting. 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* 43162306a36Sopenharmony_ci * We have no data on the hit level or data source for stores in the 43262306a36Sopenharmony_ci * Neoverse SPE records. 43362306a36Sopenharmony_ci */ 43462306a36Sopenharmony_ci if (record->op & ARM_SPE_OP_ST) { 43562306a36Sopenharmony_ci data_src->mem_lvl = PERF_MEM_LVL_NA; 43662306a36Sopenharmony_ci data_src->mem_lvl_num = PERF_MEM_LVLNUM_NA; 43762306a36Sopenharmony_ci data_src->mem_snoop = PERF_MEM_SNOOP_NA; 43862306a36Sopenharmony_ci return; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci switch (record->source) { 44262306a36Sopenharmony_ci case ARM_SPE_NV_L1D: 44362306a36Sopenharmony_ci data_src->mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT; 44462306a36Sopenharmony_ci data_src->mem_lvl_num = PERF_MEM_LVLNUM_L1; 44562306a36Sopenharmony_ci data_src->mem_snoop = PERF_MEM_SNOOP_NONE; 44662306a36Sopenharmony_ci break; 44762306a36Sopenharmony_ci case ARM_SPE_NV_L2: 44862306a36Sopenharmony_ci data_src->mem_lvl = PERF_MEM_LVL_L2 | PERF_MEM_LVL_HIT; 44962306a36Sopenharmony_ci data_src->mem_lvl_num = PERF_MEM_LVLNUM_L2; 45062306a36Sopenharmony_ci data_src->mem_snoop = PERF_MEM_SNOOP_NONE; 45162306a36Sopenharmony_ci break; 45262306a36Sopenharmony_ci case ARM_SPE_NV_PEER_CORE: 45362306a36Sopenharmony_ci data_src->mem_lvl = PERF_MEM_LVL_L2 | PERF_MEM_LVL_HIT; 45462306a36Sopenharmony_ci data_src->mem_lvl_num = PERF_MEM_LVLNUM_L2; 45562306a36Sopenharmony_ci data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER; 45662306a36Sopenharmony_ci break; 45762306a36Sopenharmony_ci /* 45862306a36Sopenharmony_ci * We don't know if this is L1, L2 but we do know it was a cache-2-cache 45962306a36Sopenharmony_ci * transfer, so set SNOOPX_PEER 46062306a36Sopenharmony_ci */ 46162306a36Sopenharmony_ci case ARM_SPE_NV_LOCAL_CLUSTER: 46262306a36Sopenharmony_ci case ARM_SPE_NV_PEER_CLUSTER: 46362306a36Sopenharmony_ci data_src->mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_HIT; 46462306a36Sopenharmony_ci data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3; 46562306a36Sopenharmony_ci data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER; 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci /* 46862306a36Sopenharmony_ci * System cache is assumed to be L3 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_ci case ARM_SPE_NV_SYS_CACHE: 47162306a36Sopenharmony_ci data_src->mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_HIT; 47262306a36Sopenharmony_ci data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3; 47362306a36Sopenharmony_ci data_src->mem_snoop = PERF_MEM_SNOOP_HIT; 47462306a36Sopenharmony_ci break; 47562306a36Sopenharmony_ci /* 47662306a36Sopenharmony_ci * We don't know what level it hit in, except it came from the other 47762306a36Sopenharmony_ci * socket 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_ci case ARM_SPE_NV_REMOTE: 48062306a36Sopenharmony_ci data_src->mem_lvl = PERF_MEM_LVL_REM_CCE1; 48162306a36Sopenharmony_ci data_src->mem_lvl_num = PERF_MEM_LVLNUM_ANY_CACHE; 48262306a36Sopenharmony_ci data_src->mem_remote = PERF_MEM_REMOTE_REMOTE; 48362306a36Sopenharmony_ci data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER; 48462306a36Sopenharmony_ci break; 48562306a36Sopenharmony_ci case ARM_SPE_NV_DRAM: 48662306a36Sopenharmony_ci data_src->mem_lvl = PERF_MEM_LVL_LOC_RAM | PERF_MEM_LVL_HIT; 48762306a36Sopenharmony_ci data_src->mem_lvl_num = PERF_MEM_LVLNUM_RAM; 48862306a36Sopenharmony_ci data_src->mem_snoop = PERF_MEM_SNOOP_NONE; 48962306a36Sopenharmony_ci break; 49062306a36Sopenharmony_ci default: 49162306a36Sopenharmony_ci break; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic void arm_spe__synth_data_source_generic(const struct arm_spe_record *record, 49662306a36Sopenharmony_ci union perf_mem_data_src *data_src) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci if (record->type & (ARM_SPE_LLC_ACCESS | ARM_SPE_LLC_MISS)) { 49962306a36Sopenharmony_ci data_src->mem_lvl = PERF_MEM_LVL_L3; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (record->type & ARM_SPE_LLC_MISS) 50262306a36Sopenharmony_ci data_src->mem_lvl |= PERF_MEM_LVL_MISS; 50362306a36Sopenharmony_ci else 50462306a36Sopenharmony_ci data_src->mem_lvl |= PERF_MEM_LVL_HIT; 50562306a36Sopenharmony_ci } else if (record->type & (ARM_SPE_L1D_ACCESS | ARM_SPE_L1D_MISS)) { 50662306a36Sopenharmony_ci data_src->mem_lvl = PERF_MEM_LVL_L1; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (record->type & ARM_SPE_L1D_MISS) 50962306a36Sopenharmony_ci data_src->mem_lvl |= PERF_MEM_LVL_MISS; 51062306a36Sopenharmony_ci else 51162306a36Sopenharmony_ci data_src->mem_lvl |= PERF_MEM_LVL_HIT; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (record->type & ARM_SPE_REMOTE_ACCESS) 51562306a36Sopenharmony_ci data_src->mem_lvl |= PERF_MEM_LVL_REM_CCE1; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic u64 arm_spe__synth_data_source(const struct arm_spe_record *record, u64 midr) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci union perf_mem_data_src data_src = { .mem_op = PERF_MEM_OP_NA }; 52162306a36Sopenharmony_ci bool is_neoverse = is_midr_in_range_list(midr, neoverse_spe); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (record->op & ARM_SPE_OP_LD) 52462306a36Sopenharmony_ci data_src.mem_op = PERF_MEM_OP_LOAD; 52562306a36Sopenharmony_ci else if (record->op & ARM_SPE_OP_ST) 52662306a36Sopenharmony_ci data_src.mem_op = PERF_MEM_OP_STORE; 52762306a36Sopenharmony_ci else 52862306a36Sopenharmony_ci return 0; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci if (is_neoverse) 53162306a36Sopenharmony_ci arm_spe__synth_data_source_neoverse(record, &data_src); 53262306a36Sopenharmony_ci else 53362306a36Sopenharmony_ci arm_spe__synth_data_source_generic(record, &data_src); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (record->type & (ARM_SPE_TLB_ACCESS | ARM_SPE_TLB_MISS)) { 53662306a36Sopenharmony_ci data_src.mem_dtlb = PERF_MEM_TLB_WK; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (record->type & ARM_SPE_TLB_MISS) 53962306a36Sopenharmony_ci data_src.mem_dtlb |= PERF_MEM_TLB_MISS; 54062306a36Sopenharmony_ci else 54162306a36Sopenharmony_ci data_src.mem_dtlb |= PERF_MEM_TLB_HIT; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci return data_src.val; 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic int arm_spe_sample(struct arm_spe_queue *speq) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci const struct arm_spe_record *record = &speq->decoder->record; 55062306a36Sopenharmony_ci struct arm_spe *spe = speq->spe; 55162306a36Sopenharmony_ci u64 data_src; 55262306a36Sopenharmony_ci int err; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci data_src = arm_spe__synth_data_source(record, spe->midr); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (spe->sample_flc) { 55762306a36Sopenharmony_ci if (record->type & ARM_SPE_L1D_MISS) { 55862306a36Sopenharmony_ci err = arm_spe__synth_mem_sample(speq, spe->l1d_miss_id, 55962306a36Sopenharmony_ci data_src); 56062306a36Sopenharmony_ci if (err) 56162306a36Sopenharmony_ci return err; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (record->type & ARM_SPE_L1D_ACCESS) { 56562306a36Sopenharmony_ci err = arm_spe__synth_mem_sample(speq, spe->l1d_access_id, 56662306a36Sopenharmony_ci data_src); 56762306a36Sopenharmony_ci if (err) 56862306a36Sopenharmony_ci return err; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (spe->sample_llc) { 57362306a36Sopenharmony_ci if (record->type & ARM_SPE_LLC_MISS) { 57462306a36Sopenharmony_ci err = arm_spe__synth_mem_sample(speq, spe->llc_miss_id, 57562306a36Sopenharmony_ci data_src); 57662306a36Sopenharmony_ci if (err) 57762306a36Sopenharmony_ci return err; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if (record->type & ARM_SPE_LLC_ACCESS) { 58162306a36Sopenharmony_ci err = arm_spe__synth_mem_sample(speq, spe->llc_access_id, 58262306a36Sopenharmony_ci data_src); 58362306a36Sopenharmony_ci if (err) 58462306a36Sopenharmony_ci return err; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (spe->sample_tlb) { 58962306a36Sopenharmony_ci if (record->type & ARM_SPE_TLB_MISS) { 59062306a36Sopenharmony_ci err = arm_spe__synth_mem_sample(speq, spe->tlb_miss_id, 59162306a36Sopenharmony_ci data_src); 59262306a36Sopenharmony_ci if (err) 59362306a36Sopenharmony_ci return err; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (record->type & ARM_SPE_TLB_ACCESS) { 59762306a36Sopenharmony_ci err = arm_spe__synth_mem_sample(speq, spe->tlb_access_id, 59862306a36Sopenharmony_ci data_src); 59962306a36Sopenharmony_ci if (err) 60062306a36Sopenharmony_ci return err; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (spe->sample_branch && (record->type & ARM_SPE_BRANCH_MISS)) { 60562306a36Sopenharmony_ci err = arm_spe__synth_branch_sample(speq, spe->branch_miss_id); 60662306a36Sopenharmony_ci if (err) 60762306a36Sopenharmony_ci return err; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (spe->sample_remote_access && 61162306a36Sopenharmony_ci (record->type & ARM_SPE_REMOTE_ACCESS)) { 61262306a36Sopenharmony_ci err = arm_spe__synth_mem_sample(speq, spe->remote_access_id, 61362306a36Sopenharmony_ci data_src); 61462306a36Sopenharmony_ci if (err) 61562306a36Sopenharmony_ci return err; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* 61962306a36Sopenharmony_ci * When data_src is zero it means the record is not a memory operation, 62062306a36Sopenharmony_ci * skip to synthesize memory sample for this case. 62162306a36Sopenharmony_ci */ 62262306a36Sopenharmony_ci if (spe->sample_memory && data_src) { 62362306a36Sopenharmony_ci err = arm_spe__synth_mem_sample(speq, spe->memory_id, data_src); 62462306a36Sopenharmony_ci if (err) 62562306a36Sopenharmony_ci return err; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (spe->sample_instructions) { 62962306a36Sopenharmony_ci err = arm_spe__synth_instruction_sample(speq, spe->instructions_id, data_src); 63062306a36Sopenharmony_ci if (err) 63162306a36Sopenharmony_ci return err; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci return 0; 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic int arm_spe_run_decoder(struct arm_spe_queue *speq, u64 *timestamp) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci struct arm_spe *spe = speq->spe; 64062306a36Sopenharmony_ci struct arm_spe_record *record; 64162306a36Sopenharmony_ci int ret; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (!spe->kernel_start) 64462306a36Sopenharmony_ci spe->kernel_start = machine__kernel_start(spe->machine); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci while (1) { 64762306a36Sopenharmony_ci /* 64862306a36Sopenharmony_ci * The usual logic is firstly to decode the packets, and then 64962306a36Sopenharmony_ci * based the record to synthesize sample; but here the flow is 65062306a36Sopenharmony_ci * reversed: it calls arm_spe_sample() for synthesizing samples 65162306a36Sopenharmony_ci * prior to arm_spe_decode(). 65262306a36Sopenharmony_ci * 65362306a36Sopenharmony_ci * Two reasons for this code logic: 65462306a36Sopenharmony_ci * 1. Firstly, when setup queue in arm_spe__setup_queue(), it 65562306a36Sopenharmony_ci * has decoded trace data and generated a record, but the record 65662306a36Sopenharmony_ci * is left to generate sample until run to here, so it's correct 65762306a36Sopenharmony_ci * to synthesize sample for the left record. 65862306a36Sopenharmony_ci * 2. After decoding trace data, it needs to compare the record 65962306a36Sopenharmony_ci * timestamp with the coming perf event, if the record timestamp 66062306a36Sopenharmony_ci * is later than the perf event, it needs bail out and pushs the 66162306a36Sopenharmony_ci * record into auxtrace heap, thus the record can be deferred to 66262306a36Sopenharmony_ci * synthesize sample until run to here at the next time; so this 66362306a36Sopenharmony_ci * can correlate samples between Arm SPE trace data and other 66462306a36Sopenharmony_ci * perf events with correct time ordering. 66562306a36Sopenharmony_ci */ 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* 66862306a36Sopenharmony_ci * Update pid/tid info. 66962306a36Sopenharmony_ci */ 67062306a36Sopenharmony_ci record = &speq->decoder->record; 67162306a36Sopenharmony_ci if (!spe->timeless_decoding && record->context_id != (u64)-1) { 67262306a36Sopenharmony_ci ret = arm_spe_set_tid(speq, record->context_id); 67362306a36Sopenharmony_ci if (ret) 67462306a36Sopenharmony_ci return ret; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci spe->use_ctx_pkt_for_pid = true; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci ret = arm_spe_sample(speq); 68062306a36Sopenharmony_ci if (ret) 68162306a36Sopenharmony_ci return ret; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci ret = arm_spe_decode(speq->decoder); 68462306a36Sopenharmony_ci if (!ret) { 68562306a36Sopenharmony_ci pr_debug("No data or all data has been processed.\n"); 68662306a36Sopenharmony_ci return 1; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* 69062306a36Sopenharmony_ci * Error is detected when decode SPE trace data, continue to 69162306a36Sopenharmony_ci * the next trace data and find out more records. 69262306a36Sopenharmony_ci */ 69362306a36Sopenharmony_ci if (ret < 0) 69462306a36Sopenharmony_ci continue; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci record = &speq->decoder->record; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci /* Update timestamp for the last record */ 69962306a36Sopenharmony_ci if (record->timestamp > speq->timestamp) 70062306a36Sopenharmony_ci speq->timestamp = record->timestamp; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci /* 70362306a36Sopenharmony_ci * If the timestamp of the queue is later than timestamp of the 70462306a36Sopenharmony_ci * coming perf event, bail out so can allow the perf event to 70562306a36Sopenharmony_ci * be processed ahead. 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_ci if (!spe->timeless_decoding && speq->timestamp >= *timestamp) { 70862306a36Sopenharmony_ci *timestamp = speq->timestamp; 70962306a36Sopenharmony_ci return 0; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci return 0; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic int arm_spe__setup_queue(struct arm_spe *spe, 71762306a36Sopenharmony_ci struct auxtrace_queue *queue, 71862306a36Sopenharmony_ci unsigned int queue_nr) 71962306a36Sopenharmony_ci{ 72062306a36Sopenharmony_ci struct arm_spe_queue *speq = queue->priv; 72162306a36Sopenharmony_ci struct arm_spe_record *record; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci if (list_empty(&queue->head) || speq) 72462306a36Sopenharmony_ci return 0; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci speq = arm_spe__alloc_queue(spe, queue_nr); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (!speq) 72962306a36Sopenharmony_ci return -ENOMEM; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci queue->priv = speq; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (queue->cpu != -1) 73462306a36Sopenharmony_ci speq->cpu = queue->cpu; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (!speq->on_heap) { 73762306a36Sopenharmony_ci int ret; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (spe->timeless_decoding) 74062306a36Sopenharmony_ci return 0; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ciretry: 74362306a36Sopenharmony_ci ret = arm_spe_decode(speq->decoder); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (!ret) 74662306a36Sopenharmony_ci return 0; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (ret < 0) 74962306a36Sopenharmony_ci goto retry; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci record = &speq->decoder->record; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci speq->timestamp = record->timestamp; 75462306a36Sopenharmony_ci ret = auxtrace_heap__add(&spe->heap, queue_nr, speq->timestamp); 75562306a36Sopenharmony_ci if (ret) 75662306a36Sopenharmony_ci return ret; 75762306a36Sopenharmony_ci speq->on_heap = true; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci return 0; 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cistatic int arm_spe__setup_queues(struct arm_spe *spe) 76462306a36Sopenharmony_ci{ 76562306a36Sopenharmony_ci unsigned int i; 76662306a36Sopenharmony_ci int ret; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci for (i = 0; i < spe->queues.nr_queues; i++) { 76962306a36Sopenharmony_ci ret = arm_spe__setup_queue(spe, &spe->queues.queue_array[i], i); 77062306a36Sopenharmony_ci if (ret) 77162306a36Sopenharmony_ci return ret; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci return 0; 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic int arm_spe__update_queues(struct arm_spe *spe) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci if (spe->queues.new_data) { 78062306a36Sopenharmony_ci spe->queues.new_data = false; 78162306a36Sopenharmony_ci return arm_spe__setup_queues(spe); 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci return 0; 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic bool arm_spe__is_timeless_decoding(struct arm_spe *spe) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci struct evsel *evsel; 79062306a36Sopenharmony_ci struct evlist *evlist = spe->session->evlist; 79162306a36Sopenharmony_ci bool timeless_decoding = true; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci /* 79462306a36Sopenharmony_ci * Circle through the list of event and complain if we find one 79562306a36Sopenharmony_ci * with the time bit set. 79662306a36Sopenharmony_ci */ 79762306a36Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 79862306a36Sopenharmony_ci if ((evsel->core.attr.sample_type & PERF_SAMPLE_TIME)) 79962306a36Sopenharmony_ci timeless_decoding = false; 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci return timeless_decoding; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistatic int arm_spe_process_queues(struct arm_spe *spe, u64 timestamp) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci unsigned int queue_nr; 80862306a36Sopenharmony_ci u64 ts; 80962306a36Sopenharmony_ci int ret; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci while (1) { 81262306a36Sopenharmony_ci struct auxtrace_queue *queue; 81362306a36Sopenharmony_ci struct arm_spe_queue *speq; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci if (!spe->heap.heap_cnt) 81662306a36Sopenharmony_ci return 0; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci if (spe->heap.heap_array[0].ordinal >= timestamp) 81962306a36Sopenharmony_ci return 0; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci queue_nr = spe->heap.heap_array[0].queue_nr; 82262306a36Sopenharmony_ci queue = &spe->queues.queue_array[queue_nr]; 82362306a36Sopenharmony_ci speq = queue->priv; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci auxtrace_heap__pop(&spe->heap); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (spe->heap.heap_cnt) { 82862306a36Sopenharmony_ci ts = spe->heap.heap_array[0].ordinal + 1; 82962306a36Sopenharmony_ci if (ts > timestamp) 83062306a36Sopenharmony_ci ts = timestamp; 83162306a36Sopenharmony_ci } else { 83262306a36Sopenharmony_ci ts = timestamp; 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci /* 83662306a36Sopenharmony_ci * A previous context-switch event has set pid/tid in the machine's context, so 83762306a36Sopenharmony_ci * here we need to update the pid/tid in the thread and SPE queue. 83862306a36Sopenharmony_ci */ 83962306a36Sopenharmony_ci if (!spe->use_ctx_pkt_for_pid) 84062306a36Sopenharmony_ci arm_spe_set_pid_tid_cpu(spe, queue); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci ret = arm_spe_run_decoder(speq, &ts); 84362306a36Sopenharmony_ci if (ret < 0) { 84462306a36Sopenharmony_ci auxtrace_heap__add(&spe->heap, queue_nr, ts); 84562306a36Sopenharmony_ci return ret; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci if (!ret) { 84962306a36Sopenharmony_ci ret = auxtrace_heap__add(&spe->heap, queue_nr, ts); 85062306a36Sopenharmony_ci if (ret < 0) 85162306a36Sopenharmony_ci return ret; 85262306a36Sopenharmony_ci } else { 85362306a36Sopenharmony_ci speq->on_heap = false; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci return 0; 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_cistatic int arm_spe_process_timeless_queues(struct arm_spe *spe, pid_t tid, 86162306a36Sopenharmony_ci u64 time_) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci struct auxtrace_queues *queues = &spe->queues; 86462306a36Sopenharmony_ci unsigned int i; 86562306a36Sopenharmony_ci u64 ts = 0; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci for (i = 0; i < queues->nr_queues; i++) { 86862306a36Sopenharmony_ci struct auxtrace_queue *queue = &spe->queues.queue_array[i]; 86962306a36Sopenharmony_ci struct arm_spe_queue *speq = queue->priv; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci if (speq && (tid == -1 || speq->tid == tid)) { 87262306a36Sopenharmony_ci speq->time = time_; 87362306a36Sopenharmony_ci arm_spe_set_pid_tid_cpu(spe, queue); 87462306a36Sopenharmony_ci arm_spe_run_decoder(speq, &ts); 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci return 0; 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cistatic int arm_spe_context_switch(struct arm_spe *spe, union perf_event *event, 88162306a36Sopenharmony_ci struct perf_sample *sample) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci pid_t pid, tid; 88462306a36Sopenharmony_ci int cpu; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci if (!(event->header.misc & PERF_RECORD_MISC_SWITCH_OUT)) 88762306a36Sopenharmony_ci return 0; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci pid = event->context_switch.next_prev_pid; 89062306a36Sopenharmony_ci tid = event->context_switch.next_prev_tid; 89162306a36Sopenharmony_ci cpu = sample->cpu; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if (tid == -1) 89462306a36Sopenharmony_ci pr_warning("context_switch event has no tid\n"); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci return machine__set_current_tid(spe->machine, cpu, pid, tid); 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_cistatic int arm_spe_process_event(struct perf_session *session, 90062306a36Sopenharmony_ci union perf_event *event, 90162306a36Sopenharmony_ci struct perf_sample *sample, 90262306a36Sopenharmony_ci struct perf_tool *tool) 90362306a36Sopenharmony_ci{ 90462306a36Sopenharmony_ci int err = 0; 90562306a36Sopenharmony_ci u64 timestamp; 90662306a36Sopenharmony_ci struct arm_spe *spe = container_of(session->auxtrace, 90762306a36Sopenharmony_ci struct arm_spe, auxtrace); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci if (dump_trace) 91062306a36Sopenharmony_ci return 0; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci if (!tool->ordered_events) { 91362306a36Sopenharmony_ci pr_err("SPE trace requires ordered events\n"); 91462306a36Sopenharmony_ci return -EINVAL; 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci if (sample->time && (sample->time != (u64) -1)) 91862306a36Sopenharmony_ci timestamp = perf_time_to_tsc(sample->time, &spe->tc); 91962306a36Sopenharmony_ci else 92062306a36Sopenharmony_ci timestamp = 0; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (timestamp || spe->timeless_decoding) { 92362306a36Sopenharmony_ci err = arm_spe__update_queues(spe); 92462306a36Sopenharmony_ci if (err) 92562306a36Sopenharmony_ci return err; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci if (spe->timeless_decoding) { 92962306a36Sopenharmony_ci if (event->header.type == PERF_RECORD_EXIT) { 93062306a36Sopenharmony_ci err = arm_spe_process_timeless_queues(spe, 93162306a36Sopenharmony_ci event->fork.tid, 93262306a36Sopenharmony_ci sample->time); 93362306a36Sopenharmony_ci } 93462306a36Sopenharmony_ci } else if (timestamp) { 93562306a36Sopenharmony_ci err = arm_spe_process_queues(spe, timestamp); 93662306a36Sopenharmony_ci if (err) 93762306a36Sopenharmony_ci return err; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci if (!spe->use_ctx_pkt_for_pid && 94062306a36Sopenharmony_ci (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE || 94162306a36Sopenharmony_ci event->header.type == PERF_RECORD_SWITCH)) 94262306a36Sopenharmony_ci err = arm_spe_context_switch(spe, event, sample); 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci return err; 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_cistatic int arm_spe_process_auxtrace_event(struct perf_session *session, 94962306a36Sopenharmony_ci union perf_event *event, 95062306a36Sopenharmony_ci struct perf_tool *tool __maybe_unused) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe, 95362306a36Sopenharmony_ci auxtrace); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci if (!spe->data_queued) { 95662306a36Sopenharmony_ci struct auxtrace_buffer *buffer; 95762306a36Sopenharmony_ci off_t data_offset; 95862306a36Sopenharmony_ci int fd = perf_data__fd(session->data); 95962306a36Sopenharmony_ci int err; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci if (perf_data__is_pipe(session->data)) { 96262306a36Sopenharmony_ci data_offset = 0; 96362306a36Sopenharmony_ci } else { 96462306a36Sopenharmony_ci data_offset = lseek(fd, 0, SEEK_CUR); 96562306a36Sopenharmony_ci if (data_offset == -1) 96662306a36Sopenharmony_ci return -errno; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci err = auxtrace_queues__add_event(&spe->queues, session, event, 97062306a36Sopenharmony_ci data_offset, &buffer); 97162306a36Sopenharmony_ci if (err) 97262306a36Sopenharmony_ci return err; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci /* Dump here now we have copied a piped trace out of the pipe */ 97562306a36Sopenharmony_ci if (dump_trace) { 97662306a36Sopenharmony_ci if (auxtrace_buffer__get_data(buffer, fd)) { 97762306a36Sopenharmony_ci arm_spe_dump_event(spe, buffer->data, 97862306a36Sopenharmony_ci buffer->size); 97962306a36Sopenharmony_ci auxtrace_buffer__put_data(buffer); 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci return 0; 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_cistatic int arm_spe_flush(struct perf_session *session __maybe_unused, 98862306a36Sopenharmony_ci struct perf_tool *tool __maybe_unused) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe, 99162306a36Sopenharmony_ci auxtrace); 99262306a36Sopenharmony_ci int ret; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci if (dump_trace) 99562306a36Sopenharmony_ci return 0; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci if (!tool->ordered_events) 99862306a36Sopenharmony_ci return -EINVAL; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci ret = arm_spe__update_queues(spe); 100162306a36Sopenharmony_ci if (ret < 0) 100262306a36Sopenharmony_ci return ret; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci if (spe->timeless_decoding) 100562306a36Sopenharmony_ci return arm_spe_process_timeless_queues(spe, -1, 100662306a36Sopenharmony_ci MAX_TIMESTAMP - 1); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci ret = arm_spe_process_queues(spe, MAX_TIMESTAMP); 100962306a36Sopenharmony_ci if (ret) 101062306a36Sopenharmony_ci return ret; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci if (!spe->use_ctx_pkt_for_pid) 101362306a36Sopenharmony_ci ui__warning("Arm SPE CONTEXT packets not found in the traces.\n" 101462306a36Sopenharmony_ci "Matching of TIDs to SPE events could be inaccurate.\n"); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci return 0; 101762306a36Sopenharmony_ci} 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_cistatic void arm_spe_free_queue(void *priv) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci struct arm_spe_queue *speq = priv; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci if (!speq) 102462306a36Sopenharmony_ci return; 102562306a36Sopenharmony_ci thread__zput(speq->thread); 102662306a36Sopenharmony_ci arm_spe_decoder_free(speq->decoder); 102762306a36Sopenharmony_ci zfree(&speq->event_buf); 102862306a36Sopenharmony_ci free(speq); 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistatic void arm_spe_free_events(struct perf_session *session) 103262306a36Sopenharmony_ci{ 103362306a36Sopenharmony_ci struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe, 103462306a36Sopenharmony_ci auxtrace); 103562306a36Sopenharmony_ci struct auxtrace_queues *queues = &spe->queues; 103662306a36Sopenharmony_ci unsigned int i; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci for (i = 0; i < queues->nr_queues; i++) { 103962306a36Sopenharmony_ci arm_spe_free_queue(queues->queue_array[i].priv); 104062306a36Sopenharmony_ci queues->queue_array[i].priv = NULL; 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci auxtrace_queues__free(queues); 104362306a36Sopenharmony_ci} 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_cistatic void arm_spe_free(struct perf_session *session) 104662306a36Sopenharmony_ci{ 104762306a36Sopenharmony_ci struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe, 104862306a36Sopenharmony_ci auxtrace); 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci auxtrace_heap__free(&spe->heap); 105162306a36Sopenharmony_ci arm_spe_free_events(session); 105262306a36Sopenharmony_ci session->auxtrace = NULL; 105362306a36Sopenharmony_ci free(spe); 105462306a36Sopenharmony_ci} 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_cistatic bool arm_spe_evsel_is_auxtrace(struct perf_session *session, 105762306a36Sopenharmony_ci struct evsel *evsel) 105862306a36Sopenharmony_ci{ 105962306a36Sopenharmony_ci struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe, auxtrace); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci return evsel->core.attr.type == spe->pmu_type; 106262306a36Sopenharmony_ci} 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_cistatic const char * const arm_spe_info_fmts[] = { 106562306a36Sopenharmony_ci [ARM_SPE_PMU_TYPE] = " PMU Type %"PRId64"\n", 106662306a36Sopenharmony_ci}; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_cistatic void arm_spe_print_info(__u64 *arr) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci if (!dump_trace) 107162306a36Sopenharmony_ci return; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci fprintf(stdout, arm_spe_info_fmts[ARM_SPE_PMU_TYPE], arr[ARM_SPE_PMU_TYPE]); 107462306a36Sopenharmony_ci} 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_cistruct arm_spe_synth { 107762306a36Sopenharmony_ci struct perf_tool dummy_tool; 107862306a36Sopenharmony_ci struct perf_session *session; 107962306a36Sopenharmony_ci}; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_cistatic int arm_spe_event_synth(struct perf_tool *tool, 108262306a36Sopenharmony_ci union perf_event *event, 108362306a36Sopenharmony_ci struct perf_sample *sample __maybe_unused, 108462306a36Sopenharmony_ci struct machine *machine __maybe_unused) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci struct arm_spe_synth *arm_spe_synth = 108762306a36Sopenharmony_ci container_of(tool, struct arm_spe_synth, dummy_tool); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci return perf_session__deliver_synth_event(arm_spe_synth->session, 109062306a36Sopenharmony_ci event, NULL); 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_cistatic int arm_spe_synth_event(struct perf_session *session, 109462306a36Sopenharmony_ci struct perf_event_attr *attr, u64 id) 109562306a36Sopenharmony_ci{ 109662306a36Sopenharmony_ci struct arm_spe_synth arm_spe_synth; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci memset(&arm_spe_synth, 0, sizeof(struct arm_spe_synth)); 109962306a36Sopenharmony_ci arm_spe_synth.session = session; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci return perf_event__synthesize_attr(&arm_spe_synth.dummy_tool, attr, 1, 110262306a36Sopenharmony_ci &id, arm_spe_event_synth); 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic void arm_spe_set_event_name(struct evlist *evlist, u64 id, 110662306a36Sopenharmony_ci const char *name) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci struct evsel *evsel; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 111162306a36Sopenharmony_ci if (evsel->core.id && evsel->core.id[0] == id) { 111262306a36Sopenharmony_ci if (evsel->name) 111362306a36Sopenharmony_ci zfree(&evsel->name); 111462306a36Sopenharmony_ci evsel->name = strdup(name); 111562306a36Sopenharmony_ci break; 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci} 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cistatic int 112162306a36Sopenharmony_ciarm_spe_synth_events(struct arm_spe *spe, struct perf_session *session) 112262306a36Sopenharmony_ci{ 112362306a36Sopenharmony_ci struct evlist *evlist = session->evlist; 112462306a36Sopenharmony_ci struct evsel *evsel; 112562306a36Sopenharmony_ci struct perf_event_attr attr; 112662306a36Sopenharmony_ci bool found = false; 112762306a36Sopenharmony_ci u64 id; 112862306a36Sopenharmony_ci int err; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 113162306a36Sopenharmony_ci if (evsel->core.attr.type == spe->pmu_type) { 113262306a36Sopenharmony_ci found = true; 113362306a36Sopenharmony_ci break; 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if (!found) { 113862306a36Sopenharmony_ci pr_debug("No selected events with SPE trace data\n"); 113962306a36Sopenharmony_ci return 0; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci memset(&attr, 0, sizeof(struct perf_event_attr)); 114362306a36Sopenharmony_ci attr.size = sizeof(struct perf_event_attr); 114462306a36Sopenharmony_ci attr.type = PERF_TYPE_HARDWARE; 114562306a36Sopenharmony_ci attr.sample_type = evsel->core.attr.sample_type & 114662306a36Sopenharmony_ci (PERF_SAMPLE_MASK | PERF_SAMPLE_PHYS_ADDR); 114762306a36Sopenharmony_ci attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID | 114862306a36Sopenharmony_ci PERF_SAMPLE_PERIOD | PERF_SAMPLE_DATA_SRC | 114962306a36Sopenharmony_ci PERF_SAMPLE_WEIGHT | PERF_SAMPLE_ADDR; 115062306a36Sopenharmony_ci if (spe->timeless_decoding) 115162306a36Sopenharmony_ci attr.sample_type &= ~(u64)PERF_SAMPLE_TIME; 115262306a36Sopenharmony_ci else 115362306a36Sopenharmony_ci attr.sample_type |= PERF_SAMPLE_TIME; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci spe->sample_type = attr.sample_type; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci attr.exclude_user = evsel->core.attr.exclude_user; 115862306a36Sopenharmony_ci attr.exclude_kernel = evsel->core.attr.exclude_kernel; 115962306a36Sopenharmony_ci attr.exclude_hv = evsel->core.attr.exclude_hv; 116062306a36Sopenharmony_ci attr.exclude_host = evsel->core.attr.exclude_host; 116162306a36Sopenharmony_ci attr.exclude_guest = evsel->core.attr.exclude_guest; 116262306a36Sopenharmony_ci attr.sample_id_all = evsel->core.attr.sample_id_all; 116362306a36Sopenharmony_ci attr.read_format = evsel->core.attr.read_format; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci /* create new id val to be a fixed offset from evsel id */ 116662306a36Sopenharmony_ci id = evsel->core.id[0] + 1000000000; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (!id) 116962306a36Sopenharmony_ci id = 1; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci if (spe->synth_opts.flc) { 117262306a36Sopenharmony_ci spe->sample_flc = true; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci /* Level 1 data cache miss */ 117562306a36Sopenharmony_ci err = arm_spe_synth_event(session, &attr, id); 117662306a36Sopenharmony_ci if (err) 117762306a36Sopenharmony_ci return err; 117862306a36Sopenharmony_ci spe->l1d_miss_id = id; 117962306a36Sopenharmony_ci arm_spe_set_event_name(evlist, id, "l1d-miss"); 118062306a36Sopenharmony_ci id += 1; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci /* Level 1 data cache access */ 118362306a36Sopenharmony_ci err = arm_spe_synth_event(session, &attr, id); 118462306a36Sopenharmony_ci if (err) 118562306a36Sopenharmony_ci return err; 118662306a36Sopenharmony_ci spe->l1d_access_id = id; 118762306a36Sopenharmony_ci arm_spe_set_event_name(evlist, id, "l1d-access"); 118862306a36Sopenharmony_ci id += 1; 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci if (spe->synth_opts.llc) { 119262306a36Sopenharmony_ci spe->sample_llc = true; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci /* Last level cache miss */ 119562306a36Sopenharmony_ci err = arm_spe_synth_event(session, &attr, id); 119662306a36Sopenharmony_ci if (err) 119762306a36Sopenharmony_ci return err; 119862306a36Sopenharmony_ci spe->llc_miss_id = id; 119962306a36Sopenharmony_ci arm_spe_set_event_name(evlist, id, "llc-miss"); 120062306a36Sopenharmony_ci id += 1; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci /* Last level cache access */ 120362306a36Sopenharmony_ci err = arm_spe_synth_event(session, &attr, id); 120462306a36Sopenharmony_ci if (err) 120562306a36Sopenharmony_ci return err; 120662306a36Sopenharmony_ci spe->llc_access_id = id; 120762306a36Sopenharmony_ci arm_spe_set_event_name(evlist, id, "llc-access"); 120862306a36Sopenharmony_ci id += 1; 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci if (spe->synth_opts.tlb) { 121262306a36Sopenharmony_ci spe->sample_tlb = true; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci /* TLB miss */ 121562306a36Sopenharmony_ci err = arm_spe_synth_event(session, &attr, id); 121662306a36Sopenharmony_ci if (err) 121762306a36Sopenharmony_ci return err; 121862306a36Sopenharmony_ci spe->tlb_miss_id = id; 121962306a36Sopenharmony_ci arm_spe_set_event_name(evlist, id, "tlb-miss"); 122062306a36Sopenharmony_ci id += 1; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci /* TLB access */ 122362306a36Sopenharmony_ci err = arm_spe_synth_event(session, &attr, id); 122462306a36Sopenharmony_ci if (err) 122562306a36Sopenharmony_ci return err; 122662306a36Sopenharmony_ci spe->tlb_access_id = id; 122762306a36Sopenharmony_ci arm_spe_set_event_name(evlist, id, "tlb-access"); 122862306a36Sopenharmony_ci id += 1; 122962306a36Sopenharmony_ci } 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci if (spe->synth_opts.branches) { 123262306a36Sopenharmony_ci spe->sample_branch = true; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci /* Branch miss */ 123562306a36Sopenharmony_ci err = arm_spe_synth_event(session, &attr, id); 123662306a36Sopenharmony_ci if (err) 123762306a36Sopenharmony_ci return err; 123862306a36Sopenharmony_ci spe->branch_miss_id = id; 123962306a36Sopenharmony_ci arm_spe_set_event_name(evlist, id, "branch-miss"); 124062306a36Sopenharmony_ci id += 1; 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci if (spe->synth_opts.remote_access) { 124462306a36Sopenharmony_ci spe->sample_remote_access = true; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci /* Remote access */ 124762306a36Sopenharmony_ci err = arm_spe_synth_event(session, &attr, id); 124862306a36Sopenharmony_ci if (err) 124962306a36Sopenharmony_ci return err; 125062306a36Sopenharmony_ci spe->remote_access_id = id; 125162306a36Sopenharmony_ci arm_spe_set_event_name(evlist, id, "remote-access"); 125262306a36Sopenharmony_ci id += 1; 125362306a36Sopenharmony_ci } 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci if (spe->synth_opts.mem) { 125662306a36Sopenharmony_ci spe->sample_memory = true; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci err = arm_spe_synth_event(session, &attr, id); 125962306a36Sopenharmony_ci if (err) 126062306a36Sopenharmony_ci return err; 126162306a36Sopenharmony_ci spe->memory_id = id; 126262306a36Sopenharmony_ci arm_spe_set_event_name(evlist, id, "memory"); 126362306a36Sopenharmony_ci id += 1; 126462306a36Sopenharmony_ci } 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci if (spe->synth_opts.instructions) { 126762306a36Sopenharmony_ci if (spe->synth_opts.period_type != PERF_ITRACE_PERIOD_INSTRUCTIONS) { 126862306a36Sopenharmony_ci pr_warning("Only instruction-based sampling period is currently supported by Arm SPE.\n"); 126962306a36Sopenharmony_ci goto synth_instructions_out; 127062306a36Sopenharmony_ci } 127162306a36Sopenharmony_ci if (spe->synth_opts.period > 1) 127262306a36Sopenharmony_ci pr_warning("Arm SPE has a hardware-based sample period.\n" 127362306a36Sopenharmony_ci "Additional instruction events will be discarded by --itrace\n"); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci spe->sample_instructions = true; 127662306a36Sopenharmony_ci attr.config = PERF_COUNT_HW_INSTRUCTIONS; 127762306a36Sopenharmony_ci attr.sample_period = spe->synth_opts.period; 127862306a36Sopenharmony_ci spe->instructions_sample_period = attr.sample_period; 127962306a36Sopenharmony_ci err = arm_spe_synth_event(session, &attr, id); 128062306a36Sopenharmony_ci if (err) 128162306a36Sopenharmony_ci return err; 128262306a36Sopenharmony_ci spe->instructions_id = id; 128362306a36Sopenharmony_ci arm_spe_set_event_name(evlist, id, "instructions"); 128462306a36Sopenharmony_ci } 128562306a36Sopenharmony_cisynth_instructions_out: 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci return 0; 128862306a36Sopenharmony_ci} 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ciint arm_spe_process_auxtrace_info(union perf_event *event, 129162306a36Sopenharmony_ci struct perf_session *session) 129262306a36Sopenharmony_ci{ 129362306a36Sopenharmony_ci struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; 129462306a36Sopenharmony_ci size_t min_sz = sizeof(u64) * ARM_SPE_AUXTRACE_PRIV_MAX; 129562306a36Sopenharmony_ci struct perf_record_time_conv *tc = &session->time_conv; 129662306a36Sopenharmony_ci const char *cpuid = perf_env__cpuid(session->evlist->env); 129762306a36Sopenharmony_ci u64 midr = strtol(cpuid, NULL, 16); 129862306a36Sopenharmony_ci struct arm_spe *spe; 129962306a36Sopenharmony_ci int err; 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) + 130262306a36Sopenharmony_ci min_sz) 130362306a36Sopenharmony_ci return -EINVAL; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci spe = zalloc(sizeof(struct arm_spe)); 130662306a36Sopenharmony_ci if (!spe) 130762306a36Sopenharmony_ci return -ENOMEM; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci err = auxtrace_queues__init(&spe->queues); 131062306a36Sopenharmony_ci if (err) 131162306a36Sopenharmony_ci goto err_free; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci spe->session = session; 131462306a36Sopenharmony_ci spe->machine = &session->machines.host; /* No kvm support */ 131562306a36Sopenharmony_ci spe->auxtrace_type = auxtrace_info->type; 131662306a36Sopenharmony_ci spe->pmu_type = auxtrace_info->priv[ARM_SPE_PMU_TYPE]; 131762306a36Sopenharmony_ci spe->midr = midr; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci spe->timeless_decoding = arm_spe__is_timeless_decoding(spe); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci /* 132262306a36Sopenharmony_ci * The synthesized event PERF_RECORD_TIME_CONV has been handled ahead 132362306a36Sopenharmony_ci * and the parameters for hardware clock are stored in the session 132462306a36Sopenharmony_ci * context. Passes these parameters to the struct perf_tsc_conversion 132562306a36Sopenharmony_ci * in "spe->tc", which is used for later conversion between clock 132662306a36Sopenharmony_ci * counter and timestamp. 132762306a36Sopenharmony_ci * 132862306a36Sopenharmony_ci * For backward compatibility, copies the fields starting from 132962306a36Sopenharmony_ci * "time_cycles" only if they are contained in the event. 133062306a36Sopenharmony_ci */ 133162306a36Sopenharmony_ci spe->tc.time_shift = tc->time_shift; 133262306a36Sopenharmony_ci spe->tc.time_mult = tc->time_mult; 133362306a36Sopenharmony_ci spe->tc.time_zero = tc->time_zero; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci if (event_contains(*tc, time_cycles)) { 133662306a36Sopenharmony_ci spe->tc.time_cycles = tc->time_cycles; 133762306a36Sopenharmony_ci spe->tc.time_mask = tc->time_mask; 133862306a36Sopenharmony_ci spe->tc.cap_user_time_zero = tc->cap_user_time_zero; 133962306a36Sopenharmony_ci spe->tc.cap_user_time_short = tc->cap_user_time_short; 134062306a36Sopenharmony_ci } 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci spe->auxtrace.process_event = arm_spe_process_event; 134362306a36Sopenharmony_ci spe->auxtrace.process_auxtrace_event = arm_spe_process_auxtrace_event; 134462306a36Sopenharmony_ci spe->auxtrace.flush_events = arm_spe_flush; 134562306a36Sopenharmony_ci spe->auxtrace.free_events = arm_spe_free_events; 134662306a36Sopenharmony_ci spe->auxtrace.free = arm_spe_free; 134762306a36Sopenharmony_ci spe->auxtrace.evsel_is_auxtrace = arm_spe_evsel_is_auxtrace; 134862306a36Sopenharmony_ci session->auxtrace = &spe->auxtrace; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci arm_spe_print_info(&auxtrace_info->priv[0]); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci if (dump_trace) 135362306a36Sopenharmony_ci return 0; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci if (session->itrace_synth_opts && session->itrace_synth_opts->set) 135662306a36Sopenharmony_ci spe->synth_opts = *session->itrace_synth_opts; 135762306a36Sopenharmony_ci else 135862306a36Sopenharmony_ci itrace_synth_opts__set_default(&spe->synth_opts, false); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci err = arm_spe_synth_events(spe, session); 136162306a36Sopenharmony_ci if (err) 136262306a36Sopenharmony_ci goto err_free_queues; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci err = auxtrace_queues__process_index(&spe->queues, session); 136562306a36Sopenharmony_ci if (err) 136662306a36Sopenharmony_ci goto err_free_queues; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci if (spe->queues.populated) 136962306a36Sopenharmony_ci spe->data_queued = true; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci return 0; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_cierr_free_queues: 137462306a36Sopenharmony_ci auxtrace_queues__free(&spe->queues); 137562306a36Sopenharmony_ci session->auxtrace = NULL; 137662306a36Sopenharmony_cierr_free: 137762306a36Sopenharmony_ci free(spe); 137862306a36Sopenharmony_ci return err; 137962306a36Sopenharmony_ci} 1380