162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * intel-bts.c: Intel Processor Trace support 462306a36Sopenharmony_ci * Copyright (c) 2013-2015, Intel Corporation. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <endian.h> 862306a36Sopenharmony_ci#include <errno.h> 962306a36Sopenharmony_ci#include <byteswap.h> 1062306a36Sopenharmony_ci#include <inttypes.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/types.h> 1362306a36Sopenharmony_ci#include <linux/bitops.h> 1462306a36Sopenharmony_ci#include <linux/log2.h> 1562306a36Sopenharmony_ci#include <linux/zalloc.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "color.h" 1862306a36Sopenharmony_ci#include "evsel.h" 1962306a36Sopenharmony_ci#include "evlist.h" 2062306a36Sopenharmony_ci#include "machine.h" 2162306a36Sopenharmony_ci#include "symbol.h" 2262306a36Sopenharmony_ci#include "session.h" 2362306a36Sopenharmony_ci#include "tool.h" 2462306a36Sopenharmony_ci#include "thread.h" 2562306a36Sopenharmony_ci#include "thread-stack.h" 2662306a36Sopenharmony_ci#include "debug.h" 2762306a36Sopenharmony_ci#include "tsc.h" 2862306a36Sopenharmony_ci#include "auxtrace.h" 2962306a36Sopenharmony_ci#include "intel-pt-decoder/intel-pt-insn-decoder.h" 3062306a36Sopenharmony_ci#include "intel-bts.h" 3162306a36Sopenharmony_ci#include "util/synthetic-events.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define MAX_TIMESTAMP (~0ULL) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define INTEL_BTS_ERR_NOINSN 5 3662306a36Sopenharmony_ci#define INTEL_BTS_ERR_LOST 9 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 3962306a36Sopenharmony_ci#define le64_to_cpu bswap_64 4062306a36Sopenharmony_ci#else 4162306a36Sopenharmony_ci#define le64_to_cpu 4262306a36Sopenharmony_ci#endif 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistruct intel_bts { 4562306a36Sopenharmony_ci struct auxtrace auxtrace; 4662306a36Sopenharmony_ci struct auxtrace_queues queues; 4762306a36Sopenharmony_ci struct auxtrace_heap heap; 4862306a36Sopenharmony_ci u32 auxtrace_type; 4962306a36Sopenharmony_ci struct perf_session *session; 5062306a36Sopenharmony_ci struct machine *machine; 5162306a36Sopenharmony_ci bool sampling_mode; 5262306a36Sopenharmony_ci bool snapshot_mode; 5362306a36Sopenharmony_ci bool data_queued; 5462306a36Sopenharmony_ci u32 pmu_type; 5562306a36Sopenharmony_ci struct perf_tsc_conversion tc; 5662306a36Sopenharmony_ci bool cap_user_time_zero; 5762306a36Sopenharmony_ci struct itrace_synth_opts synth_opts; 5862306a36Sopenharmony_ci bool sample_branches; 5962306a36Sopenharmony_ci u32 branches_filter; 6062306a36Sopenharmony_ci u64 branches_sample_type; 6162306a36Sopenharmony_ci u64 branches_id; 6262306a36Sopenharmony_ci size_t branches_event_size; 6362306a36Sopenharmony_ci unsigned long num_events; 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistruct intel_bts_queue { 6762306a36Sopenharmony_ci struct intel_bts *bts; 6862306a36Sopenharmony_ci unsigned int queue_nr; 6962306a36Sopenharmony_ci struct auxtrace_buffer *buffer; 7062306a36Sopenharmony_ci bool on_heap; 7162306a36Sopenharmony_ci bool done; 7262306a36Sopenharmony_ci pid_t pid; 7362306a36Sopenharmony_ci pid_t tid; 7462306a36Sopenharmony_ci int cpu; 7562306a36Sopenharmony_ci u64 time; 7662306a36Sopenharmony_ci struct intel_pt_insn intel_pt_insn; 7762306a36Sopenharmony_ci u32 sample_flags; 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistruct branch { 8162306a36Sopenharmony_ci u64 from; 8262306a36Sopenharmony_ci u64 to; 8362306a36Sopenharmony_ci u64 misc; 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic void intel_bts_dump(struct intel_bts *bts __maybe_unused, 8762306a36Sopenharmony_ci unsigned char *buf, size_t len) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct branch *branch; 9062306a36Sopenharmony_ci size_t i, pos = 0, br_sz = sizeof(struct branch), sz; 9162306a36Sopenharmony_ci const char *color = PERF_COLOR_BLUE; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci color_fprintf(stdout, color, 9462306a36Sopenharmony_ci ". ... Intel BTS data: size %zu bytes\n", 9562306a36Sopenharmony_ci len); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci while (len) { 9862306a36Sopenharmony_ci if (len >= br_sz) 9962306a36Sopenharmony_ci sz = br_sz; 10062306a36Sopenharmony_ci else 10162306a36Sopenharmony_ci sz = len; 10262306a36Sopenharmony_ci printf("."); 10362306a36Sopenharmony_ci color_fprintf(stdout, color, " %08x: ", pos); 10462306a36Sopenharmony_ci for (i = 0; i < sz; i++) 10562306a36Sopenharmony_ci color_fprintf(stdout, color, " %02x", buf[i]); 10662306a36Sopenharmony_ci for (; i < br_sz; i++) 10762306a36Sopenharmony_ci color_fprintf(stdout, color, " "); 10862306a36Sopenharmony_ci if (len >= br_sz) { 10962306a36Sopenharmony_ci branch = (struct branch *)buf; 11062306a36Sopenharmony_ci color_fprintf(stdout, color, " %"PRIx64" -> %"PRIx64" %s\n", 11162306a36Sopenharmony_ci le64_to_cpu(branch->from), 11262306a36Sopenharmony_ci le64_to_cpu(branch->to), 11362306a36Sopenharmony_ci le64_to_cpu(branch->misc) & 0x10 ? 11462306a36Sopenharmony_ci "pred" : "miss"); 11562306a36Sopenharmony_ci } else { 11662306a36Sopenharmony_ci color_fprintf(stdout, color, " Bad record!\n"); 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci pos += sz; 11962306a36Sopenharmony_ci buf += sz; 12062306a36Sopenharmony_ci len -= sz; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void intel_bts_dump_event(struct intel_bts *bts, unsigned char *buf, 12562306a36Sopenharmony_ci size_t len) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci printf(".\n"); 12862306a36Sopenharmony_ci intel_bts_dump(bts, buf, len); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic int intel_bts_lost(struct intel_bts *bts, struct perf_sample *sample) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci union perf_event event; 13462306a36Sopenharmony_ci int err; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE, 13762306a36Sopenharmony_ci INTEL_BTS_ERR_LOST, sample->cpu, sample->pid, 13862306a36Sopenharmony_ci sample->tid, 0, "Lost trace data", sample->time); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci err = perf_session__deliver_synth_event(bts->session, &event, NULL); 14162306a36Sopenharmony_ci if (err) 14262306a36Sopenharmony_ci pr_err("Intel BTS: failed to deliver error event, error %d\n", 14362306a36Sopenharmony_ci err); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return err; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic struct intel_bts_queue *intel_bts_alloc_queue(struct intel_bts *bts, 14962306a36Sopenharmony_ci unsigned int queue_nr) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct intel_bts_queue *btsq; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci btsq = zalloc(sizeof(struct intel_bts_queue)); 15462306a36Sopenharmony_ci if (!btsq) 15562306a36Sopenharmony_ci return NULL; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci btsq->bts = bts; 15862306a36Sopenharmony_ci btsq->queue_nr = queue_nr; 15962306a36Sopenharmony_ci btsq->pid = -1; 16062306a36Sopenharmony_ci btsq->tid = -1; 16162306a36Sopenharmony_ci btsq->cpu = -1; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci return btsq; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int intel_bts_setup_queue(struct intel_bts *bts, 16762306a36Sopenharmony_ci struct auxtrace_queue *queue, 16862306a36Sopenharmony_ci unsigned int queue_nr) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct intel_bts_queue *btsq = queue->priv; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (list_empty(&queue->head)) 17362306a36Sopenharmony_ci return 0; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (!btsq) { 17662306a36Sopenharmony_ci btsq = intel_bts_alloc_queue(bts, queue_nr); 17762306a36Sopenharmony_ci if (!btsq) 17862306a36Sopenharmony_ci return -ENOMEM; 17962306a36Sopenharmony_ci queue->priv = btsq; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (queue->cpu != -1) 18262306a36Sopenharmony_ci btsq->cpu = queue->cpu; 18362306a36Sopenharmony_ci btsq->tid = queue->tid; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (bts->sampling_mode) 18762306a36Sopenharmony_ci return 0; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (!btsq->on_heap && !btsq->buffer) { 19062306a36Sopenharmony_ci int ret; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci btsq->buffer = auxtrace_buffer__next(queue, NULL); 19362306a36Sopenharmony_ci if (!btsq->buffer) 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci ret = auxtrace_heap__add(&bts->heap, queue_nr, 19762306a36Sopenharmony_ci btsq->buffer->reference); 19862306a36Sopenharmony_ci if (ret) 19962306a36Sopenharmony_ci return ret; 20062306a36Sopenharmony_ci btsq->on_heap = true; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic int intel_bts_setup_queues(struct intel_bts *bts) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci unsigned int i; 20962306a36Sopenharmony_ci int ret; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci for (i = 0; i < bts->queues.nr_queues; i++) { 21262306a36Sopenharmony_ci ret = intel_bts_setup_queue(bts, &bts->queues.queue_array[i], 21362306a36Sopenharmony_ci i); 21462306a36Sopenharmony_ci if (ret) 21562306a36Sopenharmony_ci return ret; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci return 0; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic inline int intel_bts_update_queues(struct intel_bts *bts) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci if (bts->queues.new_data) { 22362306a36Sopenharmony_ci bts->queues.new_data = false; 22462306a36Sopenharmony_ci return intel_bts_setup_queues(bts); 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci return 0; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic unsigned char *intel_bts_find_overlap(unsigned char *buf_a, size_t len_a, 23062306a36Sopenharmony_ci unsigned char *buf_b, size_t len_b) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci size_t offs, len; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (len_a > len_b) 23562306a36Sopenharmony_ci offs = len_a - len_b; 23662306a36Sopenharmony_ci else 23762306a36Sopenharmony_ci offs = 0; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci for (; offs < len_a; offs += sizeof(struct branch)) { 24062306a36Sopenharmony_ci len = len_a - offs; 24162306a36Sopenharmony_ci if (!memcmp(buf_a + offs, buf_b, len)) 24262306a36Sopenharmony_ci return buf_b + len; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci return buf_b; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int intel_bts_do_fix_overlap(struct auxtrace_queue *queue, 24962306a36Sopenharmony_ci struct auxtrace_buffer *b) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct auxtrace_buffer *a; 25262306a36Sopenharmony_ci void *start; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (b->list.prev == &queue->head) 25562306a36Sopenharmony_ci return 0; 25662306a36Sopenharmony_ci a = list_entry(b->list.prev, struct auxtrace_buffer, list); 25762306a36Sopenharmony_ci start = intel_bts_find_overlap(a->data, a->size, b->data, b->size); 25862306a36Sopenharmony_ci if (!start) 25962306a36Sopenharmony_ci return -EINVAL; 26062306a36Sopenharmony_ci b->use_size = b->data + b->size - start; 26162306a36Sopenharmony_ci b->use_data = start; 26262306a36Sopenharmony_ci return 0; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic inline u8 intel_bts_cpumode(struct intel_bts *bts, uint64_t ip) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci return machine__kernel_ip(bts->machine, ip) ? 26862306a36Sopenharmony_ci PERF_RECORD_MISC_KERNEL : 26962306a36Sopenharmony_ci PERF_RECORD_MISC_USER; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq, 27362306a36Sopenharmony_ci struct branch *branch) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci int ret; 27662306a36Sopenharmony_ci struct intel_bts *bts = btsq->bts; 27762306a36Sopenharmony_ci union perf_event event; 27862306a36Sopenharmony_ci struct perf_sample sample = { .ip = 0, }; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (bts->synth_opts.initial_skip && 28162306a36Sopenharmony_ci bts->num_events++ <= bts->synth_opts.initial_skip) 28262306a36Sopenharmony_ci return 0; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci sample.ip = le64_to_cpu(branch->from); 28562306a36Sopenharmony_ci sample.cpumode = intel_bts_cpumode(bts, sample.ip); 28662306a36Sopenharmony_ci sample.pid = btsq->pid; 28762306a36Sopenharmony_ci sample.tid = btsq->tid; 28862306a36Sopenharmony_ci sample.addr = le64_to_cpu(branch->to); 28962306a36Sopenharmony_ci sample.id = btsq->bts->branches_id; 29062306a36Sopenharmony_ci sample.stream_id = btsq->bts->branches_id; 29162306a36Sopenharmony_ci sample.period = 1; 29262306a36Sopenharmony_ci sample.cpu = btsq->cpu; 29362306a36Sopenharmony_ci sample.flags = btsq->sample_flags; 29462306a36Sopenharmony_ci sample.insn_len = btsq->intel_pt_insn.length; 29562306a36Sopenharmony_ci memcpy(sample.insn, btsq->intel_pt_insn.buf, INTEL_PT_INSN_BUF_SZ); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci event.sample.header.type = PERF_RECORD_SAMPLE; 29862306a36Sopenharmony_ci event.sample.header.misc = sample.cpumode; 29962306a36Sopenharmony_ci event.sample.header.size = sizeof(struct perf_event_header); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (bts->synth_opts.inject) { 30262306a36Sopenharmony_ci event.sample.header.size = bts->branches_event_size; 30362306a36Sopenharmony_ci ret = perf_event__synthesize_sample(&event, 30462306a36Sopenharmony_ci bts->branches_sample_type, 30562306a36Sopenharmony_ci 0, &sample); 30662306a36Sopenharmony_ci if (ret) 30762306a36Sopenharmony_ci return ret; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci ret = perf_session__deliver_synth_event(bts->session, &event, &sample); 31162306a36Sopenharmony_ci if (ret) 31262306a36Sopenharmony_ci pr_err("Intel BTS: failed to deliver branch event, error %d\n", 31362306a36Sopenharmony_ci ret); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci return ret; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int intel_bts_get_next_insn(struct intel_bts_queue *btsq, u64 ip) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci struct machine *machine = btsq->bts->machine; 32162306a36Sopenharmony_ci struct thread *thread; 32262306a36Sopenharmony_ci unsigned char buf[INTEL_PT_INSN_BUF_SZ]; 32362306a36Sopenharmony_ci ssize_t len; 32462306a36Sopenharmony_ci bool x86_64; 32562306a36Sopenharmony_ci int err = -1; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci thread = machine__find_thread(machine, -1, btsq->tid); 32862306a36Sopenharmony_ci if (!thread) 32962306a36Sopenharmony_ci return -1; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci len = thread__memcpy(thread, machine, buf, ip, INTEL_PT_INSN_BUF_SZ, &x86_64); 33262306a36Sopenharmony_ci if (len <= 0) 33362306a36Sopenharmony_ci goto out_put; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (intel_pt_get_insn(buf, len, x86_64, &btsq->intel_pt_insn)) 33662306a36Sopenharmony_ci goto out_put; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci err = 0; 33962306a36Sopenharmony_ciout_put: 34062306a36Sopenharmony_ci thread__put(thread); 34162306a36Sopenharmony_ci return err; 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic int intel_bts_synth_error(struct intel_bts *bts, int cpu, pid_t pid, 34562306a36Sopenharmony_ci pid_t tid, u64 ip) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci union perf_event event; 34862306a36Sopenharmony_ci int err; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE, 35162306a36Sopenharmony_ci INTEL_BTS_ERR_NOINSN, cpu, pid, tid, ip, 35262306a36Sopenharmony_ci "Failed to get instruction", 0); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci err = perf_session__deliver_synth_event(bts->session, &event, NULL); 35562306a36Sopenharmony_ci if (err) 35662306a36Sopenharmony_ci pr_err("Intel BTS: failed to deliver error event, error %d\n", 35762306a36Sopenharmony_ci err); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return err; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic int intel_bts_get_branch_type(struct intel_bts_queue *btsq, 36362306a36Sopenharmony_ci struct branch *branch) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci int err; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (!branch->from) { 36862306a36Sopenharmony_ci if (branch->to) 36962306a36Sopenharmony_ci btsq->sample_flags = PERF_IP_FLAG_BRANCH | 37062306a36Sopenharmony_ci PERF_IP_FLAG_TRACE_BEGIN; 37162306a36Sopenharmony_ci else 37262306a36Sopenharmony_ci btsq->sample_flags = 0; 37362306a36Sopenharmony_ci btsq->intel_pt_insn.length = 0; 37462306a36Sopenharmony_ci } else if (!branch->to) { 37562306a36Sopenharmony_ci btsq->sample_flags = PERF_IP_FLAG_BRANCH | 37662306a36Sopenharmony_ci PERF_IP_FLAG_TRACE_END; 37762306a36Sopenharmony_ci btsq->intel_pt_insn.length = 0; 37862306a36Sopenharmony_ci } else { 37962306a36Sopenharmony_ci err = intel_bts_get_next_insn(btsq, branch->from); 38062306a36Sopenharmony_ci if (err) { 38162306a36Sopenharmony_ci btsq->sample_flags = 0; 38262306a36Sopenharmony_ci btsq->intel_pt_insn.length = 0; 38362306a36Sopenharmony_ci if (!btsq->bts->synth_opts.errors) 38462306a36Sopenharmony_ci return 0; 38562306a36Sopenharmony_ci err = intel_bts_synth_error(btsq->bts, btsq->cpu, 38662306a36Sopenharmony_ci btsq->pid, btsq->tid, 38762306a36Sopenharmony_ci branch->from); 38862306a36Sopenharmony_ci return err; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci btsq->sample_flags = intel_pt_insn_type(btsq->intel_pt_insn.op); 39162306a36Sopenharmony_ci /* Check for an async branch into the kernel */ 39262306a36Sopenharmony_ci if (!machine__kernel_ip(btsq->bts->machine, branch->from) && 39362306a36Sopenharmony_ci machine__kernel_ip(btsq->bts->machine, branch->to) && 39462306a36Sopenharmony_ci btsq->sample_flags != (PERF_IP_FLAG_BRANCH | 39562306a36Sopenharmony_ci PERF_IP_FLAG_CALL | 39662306a36Sopenharmony_ci PERF_IP_FLAG_SYSCALLRET)) 39762306a36Sopenharmony_ci btsq->sample_flags = PERF_IP_FLAG_BRANCH | 39862306a36Sopenharmony_ci PERF_IP_FLAG_CALL | 39962306a36Sopenharmony_ci PERF_IP_FLAG_ASYNC | 40062306a36Sopenharmony_ci PERF_IP_FLAG_INTERRUPT; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic int intel_bts_process_buffer(struct intel_bts_queue *btsq, 40762306a36Sopenharmony_ci struct auxtrace_buffer *buffer, 40862306a36Sopenharmony_ci struct thread *thread) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct branch *branch; 41162306a36Sopenharmony_ci size_t sz, bsz = sizeof(struct branch); 41262306a36Sopenharmony_ci u32 filter = btsq->bts->branches_filter; 41362306a36Sopenharmony_ci int err = 0; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (buffer->use_data) { 41662306a36Sopenharmony_ci sz = buffer->use_size; 41762306a36Sopenharmony_ci branch = buffer->use_data; 41862306a36Sopenharmony_ci } else { 41962306a36Sopenharmony_ci sz = buffer->size; 42062306a36Sopenharmony_ci branch = buffer->data; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (!btsq->bts->sample_branches) 42462306a36Sopenharmony_ci return 0; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci for (; sz > bsz; branch += 1, sz -= bsz) { 42762306a36Sopenharmony_ci if (!branch->from && !branch->to) 42862306a36Sopenharmony_ci continue; 42962306a36Sopenharmony_ci intel_bts_get_branch_type(btsq, branch); 43062306a36Sopenharmony_ci if (btsq->bts->synth_opts.thread_stack) 43162306a36Sopenharmony_ci thread_stack__event(thread, btsq->cpu, btsq->sample_flags, 43262306a36Sopenharmony_ci le64_to_cpu(branch->from), 43362306a36Sopenharmony_ci le64_to_cpu(branch->to), 43462306a36Sopenharmony_ci btsq->intel_pt_insn.length, 43562306a36Sopenharmony_ci buffer->buffer_nr + 1, true, 0, 0); 43662306a36Sopenharmony_ci if (filter && !(filter & btsq->sample_flags)) 43762306a36Sopenharmony_ci continue; 43862306a36Sopenharmony_ci err = intel_bts_synth_branch_sample(btsq, branch); 43962306a36Sopenharmony_ci if (err) 44062306a36Sopenharmony_ci break; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci return err; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic int intel_bts_process_queue(struct intel_bts_queue *btsq, u64 *timestamp) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci struct auxtrace_buffer *buffer = btsq->buffer, *old_buffer = buffer; 44862306a36Sopenharmony_ci struct auxtrace_queue *queue; 44962306a36Sopenharmony_ci struct thread *thread; 45062306a36Sopenharmony_ci int err; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (btsq->done) 45362306a36Sopenharmony_ci return 1; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (btsq->pid == -1) { 45662306a36Sopenharmony_ci thread = machine__find_thread(btsq->bts->machine, -1, 45762306a36Sopenharmony_ci btsq->tid); 45862306a36Sopenharmony_ci if (thread) 45962306a36Sopenharmony_ci btsq->pid = thread__pid(thread); 46062306a36Sopenharmony_ci } else { 46162306a36Sopenharmony_ci thread = machine__findnew_thread(btsq->bts->machine, btsq->pid, 46262306a36Sopenharmony_ci btsq->tid); 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci queue = &btsq->bts->queues.queue_array[btsq->queue_nr]; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (!buffer) 46862306a36Sopenharmony_ci buffer = auxtrace_buffer__next(queue, NULL); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (!buffer) { 47162306a36Sopenharmony_ci if (!btsq->bts->sampling_mode) 47262306a36Sopenharmony_ci btsq->done = 1; 47362306a36Sopenharmony_ci err = 1; 47462306a36Sopenharmony_ci goto out_put; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* Currently there is no support for split buffers */ 47862306a36Sopenharmony_ci if (buffer->consecutive) { 47962306a36Sopenharmony_ci err = -EINVAL; 48062306a36Sopenharmony_ci goto out_put; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (!buffer->data) { 48462306a36Sopenharmony_ci int fd = perf_data__fd(btsq->bts->session->data); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci buffer->data = auxtrace_buffer__get_data(buffer, fd); 48762306a36Sopenharmony_ci if (!buffer->data) { 48862306a36Sopenharmony_ci err = -ENOMEM; 48962306a36Sopenharmony_ci goto out_put; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (btsq->bts->snapshot_mode && !buffer->consecutive && 49462306a36Sopenharmony_ci intel_bts_do_fix_overlap(queue, buffer)) { 49562306a36Sopenharmony_ci err = -ENOMEM; 49662306a36Sopenharmony_ci goto out_put; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (!btsq->bts->synth_opts.callchain && 50062306a36Sopenharmony_ci !btsq->bts->synth_opts.thread_stack && thread && 50162306a36Sopenharmony_ci (!old_buffer || btsq->bts->sampling_mode || 50262306a36Sopenharmony_ci (btsq->bts->snapshot_mode && !buffer->consecutive))) 50362306a36Sopenharmony_ci thread_stack__set_trace_nr(thread, btsq->cpu, buffer->buffer_nr + 1); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci err = intel_bts_process_buffer(btsq, buffer, thread); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci auxtrace_buffer__drop_data(buffer); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci btsq->buffer = auxtrace_buffer__next(queue, buffer); 51062306a36Sopenharmony_ci if (btsq->buffer) { 51162306a36Sopenharmony_ci if (timestamp) 51262306a36Sopenharmony_ci *timestamp = btsq->buffer->reference; 51362306a36Sopenharmony_ci } else { 51462306a36Sopenharmony_ci if (!btsq->bts->sampling_mode) 51562306a36Sopenharmony_ci btsq->done = 1; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ciout_put: 51862306a36Sopenharmony_ci thread__put(thread); 51962306a36Sopenharmony_ci return err; 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic int intel_bts_flush_queue(struct intel_bts_queue *btsq) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci u64 ts = 0; 52562306a36Sopenharmony_ci int ret; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci while (1) { 52862306a36Sopenharmony_ci ret = intel_bts_process_queue(btsq, &ts); 52962306a36Sopenharmony_ci if (ret < 0) 53062306a36Sopenharmony_ci return ret; 53162306a36Sopenharmony_ci if (ret) 53262306a36Sopenharmony_ci break; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci return 0; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic int intel_bts_process_tid_exit(struct intel_bts *bts, pid_t tid) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci struct auxtrace_queues *queues = &bts->queues; 54062306a36Sopenharmony_ci unsigned int i; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci for (i = 0; i < queues->nr_queues; i++) { 54362306a36Sopenharmony_ci struct auxtrace_queue *queue = &bts->queues.queue_array[i]; 54462306a36Sopenharmony_ci struct intel_bts_queue *btsq = queue->priv; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (btsq && btsq->tid == tid) 54762306a36Sopenharmony_ci return intel_bts_flush_queue(btsq); 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci return 0; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic int intel_bts_process_queues(struct intel_bts *bts, u64 timestamp) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci while (1) { 55562306a36Sopenharmony_ci unsigned int queue_nr; 55662306a36Sopenharmony_ci struct auxtrace_queue *queue; 55762306a36Sopenharmony_ci struct intel_bts_queue *btsq; 55862306a36Sopenharmony_ci u64 ts = 0; 55962306a36Sopenharmony_ci int ret; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (!bts->heap.heap_cnt) 56262306a36Sopenharmony_ci return 0; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (bts->heap.heap_array[0].ordinal > timestamp) 56562306a36Sopenharmony_ci return 0; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci queue_nr = bts->heap.heap_array[0].queue_nr; 56862306a36Sopenharmony_ci queue = &bts->queues.queue_array[queue_nr]; 56962306a36Sopenharmony_ci btsq = queue->priv; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci auxtrace_heap__pop(&bts->heap); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci ret = intel_bts_process_queue(btsq, &ts); 57462306a36Sopenharmony_ci if (ret < 0) { 57562306a36Sopenharmony_ci auxtrace_heap__add(&bts->heap, queue_nr, ts); 57662306a36Sopenharmony_ci return ret; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (!ret) { 58062306a36Sopenharmony_ci ret = auxtrace_heap__add(&bts->heap, queue_nr, ts); 58162306a36Sopenharmony_ci if (ret < 0) 58262306a36Sopenharmony_ci return ret; 58362306a36Sopenharmony_ci } else { 58462306a36Sopenharmony_ci btsq->on_heap = false; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return 0; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic int intel_bts_process_event(struct perf_session *session, 59262306a36Sopenharmony_ci union perf_event *event, 59362306a36Sopenharmony_ci struct perf_sample *sample, 59462306a36Sopenharmony_ci struct perf_tool *tool) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts, 59762306a36Sopenharmony_ci auxtrace); 59862306a36Sopenharmony_ci u64 timestamp; 59962306a36Sopenharmony_ci int err; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (dump_trace) 60262306a36Sopenharmony_ci return 0; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (!tool->ordered_events) { 60562306a36Sopenharmony_ci pr_err("Intel BTS requires ordered events\n"); 60662306a36Sopenharmony_ci return -EINVAL; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci if (sample->time && sample->time != (u64)-1) 61062306a36Sopenharmony_ci timestamp = perf_time_to_tsc(sample->time, &bts->tc); 61162306a36Sopenharmony_ci else 61262306a36Sopenharmony_ci timestamp = 0; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci err = intel_bts_update_queues(bts); 61562306a36Sopenharmony_ci if (err) 61662306a36Sopenharmony_ci return err; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci err = intel_bts_process_queues(bts, timestamp); 61962306a36Sopenharmony_ci if (err) 62062306a36Sopenharmony_ci return err; 62162306a36Sopenharmony_ci if (event->header.type == PERF_RECORD_EXIT) { 62262306a36Sopenharmony_ci err = intel_bts_process_tid_exit(bts, event->fork.tid); 62362306a36Sopenharmony_ci if (err) 62462306a36Sopenharmony_ci return err; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (event->header.type == PERF_RECORD_AUX && 62862306a36Sopenharmony_ci (event->aux.flags & PERF_AUX_FLAG_TRUNCATED) && 62962306a36Sopenharmony_ci bts->synth_opts.errors) 63062306a36Sopenharmony_ci err = intel_bts_lost(bts, sample); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci return err; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic int intel_bts_process_auxtrace_event(struct perf_session *session, 63662306a36Sopenharmony_ci union perf_event *event, 63762306a36Sopenharmony_ci struct perf_tool *tool __maybe_unused) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts, 64062306a36Sopenharmony_ci auxtrace); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (bts->sampling_mode) 64362306a36Sopenharmony_ci return 0; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci if (!bts->data_queued) { 64662306a36Sopenharmony_ci struct auxtrace_buffer *buffer; 64762306a36Sopenharmony_ci off_t data_offset; 64862306a36Sopenharmony_ci int fd = perf_data__fd(session->data); 64962306a36Sopenharmony_ci int err; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci if (perf_data__is_pipe(session->data)) { 65262306a36Sopenharmony_ci data_offset = 0; 65362306a36Sopenharmony_ci } else { 65462306a36Sopenharmony_ci data_offset = lseek(fd, 0, SEEK_CUR); 65562306a36Sopenharmony_ci if (data_offset == -1) 65662306a36Sopenharmony_ci return -errno; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci err = auxtrace_queues__add_event(&bts->queues, session, event, 66062306a36Sopenharmony_ci data_offset, &buffer); 66162306a36Sopenharmony_ci if (err) 66262306a36Sopenharmony_ci return err; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* Dump here now we have copied a piped trace out of the pipe */ 66562306a36Sopenharmony_ci if (dump_trace) { 66662306a36Sopenharmony_ci if (auxtrace_buffer__get_data(buffer, fd)) { 66762306a36Sopenharmony_ci intel_bts_dump_event(bts, buffer->data, 66862306a36Sopenharmony_ci buffer->size); 66962306a36Sopenharmony_ci auxtrace_buffer__put_data(buffer); 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci return 0; 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic int intel_bts_flush(struct perf_session *session, 67862306a36Sopenharmony_ci struct perf_tool *tool __maybe_unused) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts, 68162306a36Sopenharmony_ci auxtrace); 68262306a36Sopenharmony_ci int ret; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (dump_trace || bts->sampling_mode) 68562306a36Sopenharmony_ci return 0; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (!tool->ordered_events) 68862306a36Sopenharmony_ci return -EINVAL; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci ret = intel_bts_update_queues(bts); 69162306a36Sopenharmony_ci if (ret < 0) 69262306a36Sopenharmony_ci return ret; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci return intel_bts_process_queues(bts, MAX_TIMESTAMP); 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_cistatic void intel_bts_free_queue(void *priv) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci struct intel_bts_queue *btsq = priv; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if (!btsq) 70262306a36Sopenharmony_ci return; 70362306a36Sopenharmony_ci free(btsq); 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic void intel_bts_free_events(struct perf_session *session) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts, 70962306a36Sopenharmony_ci auxtrace); 71062306a36Sopenharmony_ci struct auxtrace_queues *queues = &bts->queues; 71162306a36Sopenharmony_ci unsigned int i; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci for (i = 0; i < queues->nr_queues; i++) { 71462306a36Sopenharmony_ci intel_bts_free_queue(queues->queue_array[i].priv); 71562306a36Sopenharmony_ci queues->queue_array[i].priv = NULL; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci auxtrace_queues__free(queues); 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic void intel_bts_free(struct perf_session *session) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts, 72362306a36Sopenharmony_ci auxtrace); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci auxtrace_heap__free(&bts->heap); 72662306a36Sopenharmony_ci intel_bts_free_events(session); 72762306a36Sopenharmony_ci session->auxtrace = NULL; 72862306a36Sopenharmony_ci free(bts); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic bool intel_bts_evsel_is_auxtrace(struct perf_session *session, 73262306a36Sopenharmony_ci struct evsel *evsel) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts, 73562306a36Sopenharmony_ci auxtrace); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci return evsel->core.attr.type == bts->pmu_type; 73862306a36Sopenharmony_ci} 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistruct intel_bts_synth { 74162306a36Sopenharmony_ci struct perf_tool dummy_tool; 74262306a36Sopenharmony_ci struct perf_session *session; 74362306a36Sopenharmony_ci}; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic int intel_bts_event_synth(struct perf_tool *tool, 74662306a36Sopenharmony_ci union perf_event *event, 74762306a36Sopenharmony_ci struct perf_sample *sample __maybe_unused, 74862306a36Sopenharmony_ci struct machine *machine __maybe_unused) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci struct intel_bts_synth *intel_bts_synth = 75162306a36Sopenharmony_ci container_of(tool, struct intel_bts_synth, dummy_tool); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci return perf_session__deliver_synth_event(intel_bts_synth->session, 75462306a36Sopenharmony_ci event, NULL); 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cistatic int intel_bts_synth_event(struct perf_session *session, 75862306a36Sopenharmony_ci struct perf_event_attr *attr, u64 id) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci struct intel_bts_synth intel_bts_synth; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci memset(&intel_bts_synth, 0, sizeof(struct intel_bts_synth)); 76362306a36Sopenharmony_ci intel_bts_synth.session = session; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci return perf_event__synthesize_attr(&intel_bts_synth.dummy_tool, attr, 1, 76662306a36Sopenharmony_ci &id, intel_bts_event_synth); 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_cistatic int intel_bts_synth_events(struct intel_bts *bts, 77062306a36Sopenharmony_ci struct perf_session *session) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct evlist *evlist = session->evlist; 77362306a36Sopenharmony_ci struct evsel *evsel; 77462306a36Sopenharmony_ci struct perf_event_attr attr; 77562306a36Sopenharmony_ci bool found = false; 77662306a36Sopenharmony_ci u64 id; 77762306a36Sopenharmony_ci int err; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 78062306a36Sopenharmony_ci if (evsel->core.attr.type == bts->pmu_type && evsel->core.ids) { 78162306a36Sopenharmony_ci found = true; 78262306a36Sopenharmony_ci break; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci if (!found) { 78762306a36Sopenharmony_ci pr_debug("There are no selected events with Intel BTS data\n"); 78862306a36Sopenharmony_ci return 0; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci memset(&attr, 0, sizeof(struct perf_event_attr)); 79262306a36Sopenharmony_ci attr.size = sizeof(struct perf_event_attr); 79362306a36Sopenharmony_ci attr.type = PERF_TYPE_HARDWARE; 79462306a36Sopenharmony_ci attr.sample_type = evsel->core.attr.sample_type & PERF_SAMPLE_MASK; 79562306a36Sopenharmony_ci attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID | 79662306a36Sopenharmony_ci PERF_SAMPLE_PERIOD; 79762306a36Sopenharmony_ci attr.sample_type &= ~(u64)PERF_SAMPLE_TIME; 79862306a36Sopenharmony_ci attr.sample_type &= ~(u64)PERF_SAMPLE_CPU; 79962306a36Sopenharmony_ci attr.exclude_user = evsel->core.attr.exclude_user; 80062306a36Sopenharmony_ci attr.exclude_kernel = evsel->core.attr.exclude_kernel; 80162306a36Sopenharmony_ci attr.exclude_hv = evsel->core.attr.exclude_hv; 80262306a36Sopenharmony_ci attr.exclude_host = evsel->core.attr.exclude_host; 80362306a36Sopenharmony_ci attr.exclude_guest = evsel->core.attr.exclude_guest; 80462306a36Sopenharmony_ci attr.sample_id_all = evsel->core.attr.sample_id_all; 80562306a36Sopenharmony_ci attr.read_format = evsel->core.attr.read_format; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci id = evsel->core.id[0] + 1000000000; 80862306a36Sopenharmony_ci if (!id) 80962306a36Sopenharmony_ci id = 1; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci if (bts->synth_opts.branches) { 81262306a36Sopenharmony_ci attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; 81362306a36Sopenharmony_ci attr.sample_period = 1; 81462306a36Sopenharmony_ci attr.sample_type |= PERF_SAMPLE_ADDR; 81562306a36Sopenharmony_ci pr_debug("Synthesizing 'branches' event with id %" PRIu64 " sample type %#" PRIx64 "\n", 81662306a36Sopenharmony_ci id, (u64)attr.sample_type); 81762306a36Sopenharmony_ci err = intel_bts_synth_event(session, &attr, id); 81862306a36Sopenharmony_ci if (err) { 81962306a36Sopenharmony_ci pr_err("%s: failed to synthesize 'branches' event type\n", 82062306a36Sopenharmony_ci __func__); 82162306a36Sopenharmony_ci return err; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci bts->sample_branches = true; 82462306a36Sopenharmony_ci bts->branches_sample_type = attr.sample_type; 82562306a36Sopenharmony_ci bts->branches_id = id; 82662306a36Sopenharmony_ci /* 82762306a36Sopenharmony_ci * We only use sample types from PERF_SAMPLE_MASK so we can use 82862306a36Sopenharmony_ci * __evsel__sample_size() here. 82962306a36Sopenharmony_ci */ 83062306a36Sopenharmony_ci bts->branches_event_size = sizeof(struct perf_record_sample) + 83162306a36Sopenharmony_ci __evsel__sample_size(attr.sample_type); 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci return 0; 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_cistatic const char * const intel_bts_info_fmts[] = { 83862306a36Sopenharmony_ci [INTEL_BTS_PMU_TYPE] = " PMU Type %"PRId64"\n", 83962306a36Sopenharmony_ci [INTEL_BTS_TIME_SHIFT] = " Time Shift %"PRIu64"\n", 84062306a36Sopenharmony_ci [INTEL_BTS_TIME_MULT] = " Time Muliplier %"PRIu64"\n", 84162306a36Sopenharmony_ci [INTEL_BTS_TIME_ZERO] = " Time Zero %"PRIu64"\n", 84262306a36Sopenharmony_ci [INTEL_BTS_CAP_USER_TIME_ZERO] = " Cap Time Zero %"PRId64"\n", 84362306a36Sopenharmony_ci [INTEL_BTS_SNAPSHOT_MODE] = " Snapshot mode %"PRId64"\n", 84462306a36Sopenharmony_ci}; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic void intel_bts_print_info(__u64 *arr, int start, int finish) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci int i; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if (!dump_trace) 85162306a36Sopenharmony_ci return; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci for (i = start; i <= finish; i++) 85462306a36Sopenharmony_ci fprintf(stdout, intel_bts_info_fmts[i], arr[i]); 85562306a36Sopenharmony_ci} 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ciint intel_bts_process_auxtrace_info(union perf_event *event, 85862306a36Sopenharmony_ci struct perf_session *session) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; 86162306a36Sopenharmony_ci size_t min_sz = sizeof(u64) * INTEL_BTS_SNAPSHOT_MODE; 86262306a36Sopenharmony_ci struct intel_bts *bts; 86362306a36Sopenharmony_ci int err; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) + 86662306a36Sopenharmony_ci min_sz) 86762306a36Sopenharmony_ci return -EINVAL; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci bts = zalloc(sizeof(struct intel_bts)); 87062306a36Sopenharmony_ci if (!bts) 87162306a36Sopenharmony_ci return -ENOMEM; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci err = auxtrace_queues__init(&bts->queues); 87462306a36Sopenharmony_ci if (err) 87562306a36Sopenharmony_ci goto err_free; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci bts->session = session; 87862306a36Sopenharmony_ci bts->machine = &session->machines.host; /* No kvm support */ 87962306a36Sopenharmony_ci bts->auxtrace_type = auxtrace_info->type; 88062306a36Sopenharmony_ci bts->pmu_type = auxtrace_info->priv[INTEL_BTS_PMU_TYPE]; 88162306a36Sopenharmony_ci bts->tc.time_shift = auxtrace_info->priv[INTEL_BTS_TIME_SHIFT]; 88262306a36Sopenharmony_ci bts->tc.time_mult = auxtrace_info->priv[INTEL_BTS_TIME_MULT]; 88362306a36Sopenharmony_ci bts->tc.time_zero = auxtrace_info->priv[INTEL_BTS_TIME_ZERO]; 88462306a36Sopenharmony_ci bts->cap_user_time_zero = 88562306a36Sopenharmony_ci auxtrace_info->priv[INTEL_BTS_CAP_USER_TIME_ZERO]; 88662306a36Sopenharmony_ci bts->snapshot_mode = auxtrace_info->priv[INTEL_BTS_SNAPSHOT_MODE]; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci bts->sampling_mode = false; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci bts->auxtrace.process_event = intel_bts_process_event; 89162306a36Sopenharmony_ci bts->auxtrace.process_auxtrace_event = intel_bts_process_auxtrace_event; 89262306a36Sopenharmony_ci bts->auxtrace.flush_events = intel_bts_flush; 89362306a36Sopenharmony_ci bts->auxtrace.free_events = intel_bts_free_events; 89462306a36Sopenharmony_ci bts->auxtrace.free = intel_bts_free; 89562306a36Sopenharmony_ci bts->auxtrace.evsel_is_auxtrace = intel_bts_evsel_is_auxtrace; 89662306a36Sopenharmony_ci session->auxtrace = &bts->auxtrace; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci intel_bts_print_info(&auxtrace_info->priv[0], INTEL_BTS_PMU_TYPE, 89962306a36Sopenharmony_ci INTEL_BTS_SNAPSHOT_MODE); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (dump_trace) 90262306a36Sopenharmony_ci return 0; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (session->itrace_synth_opts->set) { 90562306a36Sopenharmony_ci bts->synth_opts = *session->itrace_synth_opts; 90662306a36Sopenharmony_ci } else { 90762306a36Sopenharmony_ci itrace_synth_opts__set_default(&bts->synth_opts, 90862306a36Sopenharmony_ci session->itrace_synth_opts->default_no_sample); 90962306a36Sopenharmony_ci bts->synth_opts.thread_stack = 91062306a36Sopenharmony_ci session->itrace_synth_opts->thread_stack; 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci if (bts->synth_opts.calls) 91462306a36Sopenharmony_ci bts->branches_filter |= PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC | 91562306a36Sopenharmony_ci PERF_IP_FLAG_TRACE_END; 91662306a36Sopenharmony_ci if (bts->synth_opts.returns) 91762306a36Sopenharmony_ci bts->branches_filter |= PERF_IP_FLAG_RETURN | 91862306a36Sopenharmony_ci PERF_IP_FLAG_TRACE_BEGIN; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci err = intel_bts_synth_events(bts, session); 92162306a36Sopenharmony_ci if (err) 92262306a36Sopenharmony_ci goto err_free_queues; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci err = auxtrace_queues__process_index(&bts->queues, session); 92562306a36Sopenharmony_ci if (err) 92662306a36Sopenharmony_ci goto err_free_queues; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci if (bts->queues.populated) 92962306a36Sopenharmony_ci bts->data_queued = true; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci return 0; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_cierr_free_queues: 93462306a36Sopenharmony_ci auxtrace_queues__free(&bts->queues); 93562306a36Sopenharmony_ci session->auxtrace = NULL; 93662306a36Sopenharmony_cierr_free: 93762306a36Sopenharmony_ci free(bts); 93862306a36Sopenharmony_ci return err; 93962306a36Sopenharmony_ci} 940