18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * intel-bts.c: Intel Processor Trace support 48c2ecf20Sopenharmony_ci * Copyright (c) 2013-2015, Intel Corporation. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <endian.h> 88c2ecf20Sopenharmony_ci#include <errno.h> 98c2ecf20Sopenharmony_ci#include <byteswap.h> 108c2ecf20Sopenharmony_ci#include <inttypes.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/types.h> 138c2ecf20Sopenharmony_ci#include <linux/bitops.h> 148c2ecf20Sopenharmony_ci#include <linux/log2.h> 158c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "color.h" 188c2ecf20Sopenharmony_ci#include "evsel.h" 198c2ecf20Sopenharmony_ci#include "evlist.h" 208c2ecf20Sopenharmony_ci#include "machine.h" 218c2ecf20Sopenharmony_ci#include "symbol.h" 228c2ecf20Sopenharmony_ci#include "session.h" 238c2ecf20Sopenharmony_ci#include "tool.h" 248c2ecf20Sopenharmony_ci#include "thread.h" 258c2ecf20Sopenharmony_ci#include "thread-stack.h" 268c2ecf20Sopenharmony_ci#include "debug.h" 278c2ecf20Sopenharmony_ci#include "tsc.h" 288c2ecf20Sopenharmony_ci#include "auxtrace.h" 298c2ecf20Sopenharmony_ci#include "intel-pt-decoder/intel-pt-insn-decoder.h" 308c2ecf20Sopenharmony_ci#include "intel-bts.h" 318c2ecf20Sopenharmony_ci#include "util/synthetic-events.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define MAX_TIMESTAMP (~0ULL) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define INTEL_BTS_ERR_NOINSN 5 368c2ecf20Sopenharmony_ci#define INTEL_BTS_ERR_LOST 9 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#if __BYTE_ORDER == __BIG_ENDIAN 398c2ecf20Sopenharmony_ci#define le64_to_cpu bswap_64 408c2ecf20Sopenharmony_ci#else 418c2ecf20Sopenharmony_ci#define le64_to_cpu 428c2ecf20Sopenharmony_ci#endif 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistruct intel_bts { 458c2ecf20Sopenharmony_ci struct auxtrace auxtrace; 468c2ecf20Sopenharmony_ci struct auxtrace_queues queues; 478c2ecf20Sopenharmony_ci struct auxtrace_heap heap; 488c2ecf20Sopenharmony_ci u32 auxtrace_type; 498c2ecf20Sopenharmony_ci struct perf_session *session; 508c2ecf20Sopenharmony_ci struct machine *machine; 518c2ecf20Sopenharmony_ci bool sampling_mode; 528c2ecf20Sopenharmony_ci bool snapshot_mode; 538c2ecf20Sopenharmony_ci bool data_queued; 548c2ecf20Sopenharmony_ci u32 pmu_type; 558c2ecf20Sopenharmony_ci struct perf_tsc_conversion tc; 568c2ecf20Sopenharmony_ci bool cap_user_time_zero; 578c2ecf20Sopenharmony_ci struct itrace_synth_opts synth_opts; 588c2ecf20Sopenharmony_ci bool sample_branches; 598c2ecf20Sopenharmony_ci u32 branches_filter; 608c2ecf20Sopenharmony_ci u64 branches_sample_type; 618c2ecf20Sopenharmony_ci u64 branches_id; 628c2ecf20Sopenharmony_ci size_t branches_event_size; 638c2ecf20Sopenharmony_ci unsigned long num_events; 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistruct intel_bts_queue { 678c2ecf20Sopenharmony_ci struct intel_bts *bts; 688c2ecf20Sopenharmony_ci unsigned int queue_nr; 698c2ecf20Sopenharmony_ci struct auxtrace_buffer *buffer; 708c2ecf20Sopenharmony_ci bool on_heap; 718c2ecf20Sopenharmony_ci bool done; 728c2ecf20Sopenharmony_ci pid_t pid; 738c2ecf20Sopenharmony_ci pid_t tid; 748c2ecf20Sopenharmony_ci int cpu; 758c2ecf20Sopenharmony_ci u64 time; 768c2ecf20Sopenharmony_ci struct intel_pt_insn intel_pt_insn; 778c2ecf20Sopenharmony_ci u32 sample_flags; 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistruct branch { 818c2ecf20Sopenharmony_ci u64 from; 828c2ecf20Sopenharmony_ci u64 to; 838c2ecf20Sopenharmony_ci u64 misc; 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic void intel_bts_dump(struct intel_bts *bts __maybe_unused, 878c2ecf20Sopenharmony_ci unsigned char *buf, size_t len) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct branch *branch; 908c2ecf20Sopenharmony_ci size_t i, pos = 0, br_sz = sizeof(struct branch), sz; 918c2ecf20Sopenharmony_ci const char *color = PERF_COLOR_BLUE; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci color_fprintf(stdout, color, 948c2ecf20Sopenharmony_ci ". ... Intel BTS data: size %zu bytes\n", 958c2ecf20Sopenharmony_ci len); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci while (len) { 988c2ecf20Sopenharmony_ci if (len >= br_sz) 998c2ecf20Sopenharmony_ci sz = br_sz; 1008c2ecf20Sopenharmony_ci else 1018c2ecf20Sopenharmony_ci sz = len; 1028c2ecf20Sopenharmony_ci printf("."); 1038c2ecf20Sopenharmony_ci color_fprintf(stdout, color, " %08x: ", pos); 1048c2ecf20Sopenharmony_ci for (i = 0; i < sz; i++) 1058c2ecf20Sopenharmony_ci color_fprintf(stdout, color, " %02x", buf[i]); 1068c2ecf20Sopenharmony_ci for (; i < br_sz; i++) 1078c2ecf20Sopenharmony_ci color_fprintf(stdout, color, " "); 1088c2ecf20Sopenharmony_ci if (len >= br_sz) { 1098c2ecf20Sopenharmony_ci branch = (struct branch *)buf; 1108c2ecf20Sopenharmony_ci color_fprintf(stdout, color, " %"PRIx64" -> %"PRIx64" %s\n", 1118c2ecf20Sopenharmony_ci le64_to_cpu(branch->from), 1128c2ecf20Sopenharmony_ci le64_to_cpu(branch->to), 1138c2ecf20Sopenharmony_ci le64_to_cpu(branch->misc) & 0x10 ? 1148c2ecf20Sopenharmony_ci "pred" : "miss"); 1158c2ecf20Sopenharmony_ci } else { 1168c2ecf20Sopenharmony_ci color_fprintf(stdout, color, " Bad record!\n"); 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci pos += sz; 1198c2ecf20Sopenharmony_ci buf += sz; 1208c2ecf20Sopenharmony_ci len -= sz; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic void intel_bts_dump_event(struct intel_bts *bts, unsigned char *buf, 1258c2ecf20Sopenharmony_ci size_t len) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci printf(".\n"); 1288c2ecf20Sopenharmony_ci intel_bts_dump(bts, buf, len); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic int intel_bts_lost(struct intel_bts *bts, struct perf_sample *sample) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci union perf_event event; 1348c2ecf20Sopenharmony_ci int err; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE, 1378c2ecf20Sopenharmony_ci INTEL_BTS_ERR_LOST, sample->cpu, sample->pid, 1388c2ecf20Sopenharmony_ci sample->tid, 0, "Lost trace data", sample->time); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci err = perf_session__deliver_synth_event(bts->session, &event, NULL); 1418c2ecf20Sopenharmony_ci if (err) 1428c2ecf20Sopenharmony_ci pr_err("Intel BTS: failed to deliver error event, error %d\n", 1438c2ecf20Sopenharmony_ci err); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return err; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic struct intel_bts_queue *intel_bts_alloc_queue(struct intel_bts *bts, 1498c2ecf20Sopenharmony_ci unsigned int queue_nr) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct intel_bts_queue *btsq; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci btsq = zalloc(sizeof(struct intel_bts_queue)); 1548c2ecf20Sopenharmony_ci if (!btsq) 1558c2ecf20Sopenharmony_ci return NULL; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci btsq->bts = bts; 1588c2ecf20Sopenharmony_ci btsq->queue_nr = queue_nr; 1598c2ecf20Sopenharmony_ci btsq->pid = -1; 1608c2ecf20Sopenharmony_ci btsq->tid = -1; 1618c2ecf20Sopenharmony_ci btsq->cpu = -1; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return btsq; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int intel_bts_setup_queue(struct intel_bts *bts, 1678c2ecf20Sopenharmony_ci struct auxtrace_queue *queue, 1688c2ecf20Sopenharmony_ci unsigned int queue_nr) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct intel_bts_queue *btsq = queue->priv; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (list_empty(&queue->head)) 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (!btsq) { 1768c2ecf20Sopenharmony_ci btsq = intel_bts_alloc_queue(bts, queue_nr); 1778c2ecf20Sopenharmony_ci if (!btsq) 1788c2ecf20Sopenharmony_ci return -ENOMEM; 1798c2ecf20Sopenharmony_ci queue->priv = btsq; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (queue->cpu != -1) 1828c2ecf20Sopenharmony_ci btsq->cpu = queue->cpu; 1838c2ecf20Sopenharmony_ci btsq->tid = queue->tid; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (bts->sampling_mode) 1878c2ecf20Sopenharmony_ci return 0; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (!btsq->on_heap && !btsq->buffer) { 1908c2ecf20Sopenharmony_ci int ret; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci btsq->buffer = auxtrace_buffer__next(queue, NULL); 1938c2ecf20Sopenharmony_ci if (!btsq->buffer) 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci ret = auxtrace_heap__add(&bts->heap, queue_nr, 1978c2ecf20Sopenharmony_ci btsq->buffer->reference); 1988c2ecf20Sopenharmony_ci if (ret) 1998c2ecf20Sopenharmony_ci return ret; 2008c2ecf20Sopenharmony_ci btsq->on_heap = true; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic int intel_bts_setup_queues(struct intel_bts *bts) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci unsigned int i; 2098c2ecf20Sopenharmony_ci int ret; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci for (i = 0; i < bts->queues.nr_queues; i++) { 2128c2ecf20Sopenharmony_ci ret = intel_bts_setup_queue(bts, &bts->queues.queue_array[i], 2138c2ecf20Sopenharmony_ci i); 2148c2ecf20Sopenharmony_ci if (ret) 2158c2ecf20Sopenharmony_ci return ret; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci return 0; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic inline int intel_bts_update_queues(struct intel_bts *bts) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci if (bts->queues.new_data) { 2238c2ecf20Sopenharmony_ci bts->queues.new_data = false; 2248c2ecf20Sopenharmony_ci return intel_bts_setup_queues(bts); 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci return 0; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic unsigned char *intel_bts_find_overlap(unsigned char *buf_a, size_t len_a, 2308c2ecf20Sopenharmony_ci unsigned char *buf_b, size_t len_b) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci size_t offs, len; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (len_a > len_b) 2358c2ecf20Sopenharmony_ci offs = len_a - len_b; 2368c2ecf20Sopenharmony_ci else 2378c2ecf20Sopenharmony_ci offs = 0; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci for (; offs < len_a; offs += sizeof(struct branch)) { 2408c2ecf20Sopenharmony_ci len = len_a - offs; 2418c2ecf20Sopenharmony_ci if (!memcmp(buf_a + offs, buf_b, len)) 2428c2ecf20Sopenharmony_ci return buf_b + len; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci return buf_b; 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic int intel_bts_do_fix_overlap(struct auxtrace_queue *queue, 2498c2ecf20Sopenharmony_ci struct auxtrace_buffer *b) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct auxtrace_buffer *a; 2528c2ecf20Sopenharmony_ci void *start; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (b->list.prev == &queue->head) 2558c2ecf20Sopenharmony_ci return 0; 2568c2ecf20Sopenharmony_ci a = list_entry(b->list.prev, struct auxtrace_buffer, list); 2578c2ecf20Sopenharmony_ci start = intel_bts_find_overlap(a->data, a->size, b->data, b->size); 2588c2ecf20Sopenharmony_ci if (!start) 2598c2ecf20Sopenharmony_ci return -EINVAL; 2608c2ecf20Sopenharmony_ci b->use_size = b->data + b->size - start; 2618c2ecf20Sopenharmony_ci b->use_data = start; 2628c2ecf20Sopenharmony_ci return 0; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic inline u8 intel_bts_cpumode(struct intel_bts *bts, uint64_t ip) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci return machine__kernel_ip(bts->machine, ip) ? 2688c2ecf20Sopenharmony_ci PERF_RECORD_MISC_KERNEL : 2698c2ecf20Sopenharmony_ci PERF_RECORD_MISC_USER; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq, 2738c2ecf20Sopenharmony_ci struct branch *branch) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci int ret; 2768c2ecf20Sopenharmony_ci struct intel_bts *bts = btsq->bts; 2778c2ecf20Sopenharmony_ci union perf_event event; 2788c2ecf20Sopenharmony_ci struct perf_sample sample = { .ip = 0, }; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (bts->synth_opts.initial_skip && 2818c2ecf20Sopenharmony_ci bts->num_events++ <= bts->synth_opts.initial_skip) 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci sample.ip = le64_to_cpu(branch->from); 2858c2ecf20Sopenharmony_ci sample.cpumode = intel_bts_cpumode(bts, sample.ip); 2868c2ecf20Sopenharmony_ci sample.pid = btsq->pid; 2878c2ecf20Sopenharmony_ci sample.tid = btsq->tid; 2888c2ecf20Sopenharmony_ci sample.addr = le64_to_cpu(branch->to); 2898c2ecf20Sopenharmony_ci sample.id = btsq->bts->branches_id; 2908c2ecf20Sopenharmony_ci sample.stream_id = btsq->bts->branches_id; 2918c2ecf20Sopenharmony_ci sample.period = 1; 2928c2ecf20Sopenharmony_ci sample.cpu = btsq->cpu; 2938c2ecf20Sopenharmony_ci sample.flags = btsq->sample_flags; 2948c2ecf20Sopenharmony_ci sample.insn_len = btsq->intel_pt_insn.length; 2958c2ecf20Sopenharmony_ci memcpy(sample.insn, btsq->intel_pt_insn.buf, INTEL_PT_INSN_BUF_SZ); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci event.sample.header.type = PERF_RECORD_SAMPLE; 2988c2ecf20Sopenharmony_ci event.sample.header.misc = sample.cpumode; 2998c2ecf20Sopenharmony_ci event.sample.header.size = sizeof(struct perf_event_header); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (bts->synth_opts.inject) { 3028c2ecf20Sopenharmony_ci event.sample.header.size = bts->branches_event_size; 3038c2ecf20Sopenharmony_ci ret = perf_event__synthesize_sample(&event, 3048c2ecf20Sopenharmony_ci bts->branches_sample_type, 3058c2ecf20Sopenharmony_ci 0, &sample); 3068c2ecf20Sopenharmony_ci if (ret) 3078c2ecf20Sopenharmony_ci return ret; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci ret = perf_session__deliver_synth_event(bts->session, &event, &sample); 3118c2ecf20Sopenharmony_ci if (ret) 3128c2ecf20Sopenharmony_ci pr_err("Intel BTS: failed to deliver branch event, error %d\n", 3138c2ecf20Sopenharmony_ci ret); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return ret; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic int intel_bts_get_next_insn(struct intel_bts_queue *btsq, u64 ip) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct machine *machine = btsq->bts->machine; 3218c2ecf20Sopenharmony_ci struct thread *thread; 3228c2ecf20Sopenharmony_ci unsigned char buf[INTEL_PT_INSN_BUF_SZ]; 3238c2ecf20Sopenharmony_ci ssize_t len; 3248c2ecf20Sopenharmony_ci bool x86_64; 3258c2ecf20Sopenharmony_ci int err = -1; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci thread = machine__find_thread(machine, -1, btsq->tid); 3288c2ecf20Sopenharmony_ci if (!thread) 3298c2ecf20Sopenharmony_ci return -1; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci len = thread__memcpy(thread, machine, buf, ip, INTEL_PT_INSN_BUF_SZ, &x86_64); 3328c2ecf20Sopenharmony_ci if (len <= 0) 3338c2ecf20Sopenharmony_ci goto out_put; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (intel_pt_get_insn(buf, len, x86_64, &btsq->intel_pt_insn)) 3368c2ecf20Sopenharmony_ci goto out_put; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci err = 0; 3398c2ecf20Sopenharmony_ciout_put: 3408c2ecf20Sopenharmony_ci thread__put(thread); 3418c2ecf20Sopenharmony_ci return err; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic int intel_bts_synth_error(struct intel_bts *bts, int cpu, pid_t pid, 3458c2ecf20Sopenharmony_ci pid_t tid, u64 ip) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci union perf_event event; 3488c2ecf20Sopenharmony_ci int err; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE, 3518c2ecf20Sopenharmony_ci INTEL_BTS_ERR_NOINSN, cpu, pid, tid, ip, 3528c2ecf20Sopenharmony_ci "Failed to get instruction", 0); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci err = perf_session__deliver_synth_event(bts->session, &event, NULL); 3558c2ecf20Sopenharmony_ci if (err) 3568c2ecf20Sopenharmony_ci pr_err("Intel BTS: failed to deliver error event, error %d\n", 3578c2ecf20Sopenharmony_ci err); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci return err; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic int intel_bts_get_branch_type(struct intel_bts_queue *btsq, 3638c2ecf20Sopenharmony_ci struct branch *branch) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci int err; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (!branch->from) { 3688c2ecf20Sopenharmony_ci if (branch->to) 3698c2ecf20Sopenharmony_ci btsq->sample_flags = PERF_IP_FLAG_BRANCH | 3708c2ecf20Sopenharmony_ci PERF_IP_FLAG_TRACE_BEGIN; 3718c2ecf20Sopenharmony_ci else 3728c2ecf20Sopenharmony_ci btsq->sample_flags = 0; 3738c2ecf20Sopenharmony_ci btsq->intel_pt_insn.length = 0; 3748c2ecf20Sopenharmony_ci } else if (!branch->to) { 3758c2ecf20Sopenharmony_ci btsq->sample_flags = PERF_IP_FLAG_BRANCH | 3768c2ecf20Sopenharmony_ci PERF_IP_FLAG_TRACE_END; 3778c2ecf20Sopenharmony_ci btsq->intel_pt_insn.length = 0; 3788c2ecf20Sopenharmony_ci } else { 3798c2ecf20Sopenharmony_ci err = intel_bts_get_next_insn(btsq, branch->from); 3808c2ecf20Sopenharmony_ci if (err) { 3818c2ecf20Sopenharmony_ci btsq->sample_flags = 0; 3828c2ecf20Sopenharmony_ci btsq->intel_pt_insn.length = 0; 3838c2ecf20Sopenharmony_ci if (!btsq->bts->synth_opts.errors) 3848c2ecf20Sopenharmony_ci return 0; 3858c2ecf20Sopenharmony_ci err = intel_bts_synth_error(btsq->bts, btsq->cpu, 3868c2ecf20Sopenharmony_ci btsq->pid, btsq->tid, 3878c2ecf20Sopenharmony_ci branch->from); 3888c2ecf20Sopenharmony_ci return err; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci btsq->sample_flags = intel_pt_insn_type(btsq->intel_pt_insn.op); 3918c2ecf20Sopenharmony_ci /* Check for an async branch into the kernel */ 3928c2ecf20Sopenharmony_ci if (!machine__kernel_ip(btsq->bts->machine, branch->from) && 3938c2ecf20Sopenharmony_ci machine__kernel_ip(btsq->bts->machine, branch->to) && 3948c2ecf20Sopenharmony_ci btsq->sample_flags != (PERF_IP_FLAG_BRANCH | 3958c2ecf20Sopenharmony_ci PERF_IP_FLAG_CALL | 3968c2ecf20Sopenharmony_ci PERF_IP_FLAG_SYSCALLRET)) 3978c2ecf20Sopenharmony_ci btsq->sample_flags = PERF_IP_FLAG_BRANCH | 3988c2ecf20Sopenharmony_ci PERF_IP_FLAG_CALL | 3998c2ecf20Sopenharmony_ci PERF_IP_FLAG_ASYNC | 4008c2ecf20Sopenharmony_ci PERF_IP_FLAG_INTERRUPT; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci return 0; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic int intel_bts_process_buffer(struct intel_bts_queue *btsq, 4078c2ecf20Sopenharmony_ci struct auxtrace_buffer *buffer, 4088c2ecf20Sopenharmony_ci struct thread *thread) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct branch *branch; 4118c2ecf20Sopenharmony_ci size_t sz, bsz = sizeof(struct branch); 4128c2ecf20Sopenharmony_ci u32 filter = btsq->bts->branches_filter; 4138c2ecf20Sopenharmony_ci int err = 0; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (buffer->use_data) { 4168c2ecf20Sopenharmony_ci sz = buffer->use_size; 4178c2ecf20Sopenharmony_ci branch = buffer->use_data; 4188c2ecf20Sopenharmony_ci } else { 4198c2ecf20Sopenharmony_ci sz = buffer->size; 4208c2ecf20Sopenharmony_ci branch = buffer->data; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (!btsq->bts->sample_branches) 4248c2ecf20Sopenharmony_ci return 0; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci for (; sz > bsz; branch += 1, sz -= bsz) { 4278c2ecf20Sopenharmony_ci if (!branch->from && !branch->to) 4288c2ecf20Sopenharmony_ci continue; 4298c2ecf20Sopenharmony_ci intel_bts_get_branch_type(btsq, branch); 4308c2ecf20Sopenharmony_ci if (btsq->bts->synth_opts.thread_stack) 4318c2ecf20Sopenharmony_ci thread_stack__event(thread, btsq->cpu, btsq->sample_flags, 4328c2ecf20Sopenharmony_ci le64_to_cpu(branch->from), 4338c2ecf20Sopenharmony_ci le64_to_cpu(branch->to), 4348c2ecf20Sopenharmony_ci btsq->intel_pt_insn.length, 4358c2ecf20Sopenharmony_ci buffer->buffer_nr + 1, true, 0, 0); 4368c2ecf20Sopenharmony_ci if (filter && !(filter & btsq->sample_flags)) 4378c2ecf20Sopenharmony_ci continue; 4388c2ecf20Sopenharmony_ci err = intel_bts_synth_branch_sample(btsq, branch); 4398c2ecf20Sopenharmony_ci if (err) 4408c2ecf20Sopenharmony_ci break; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci return err; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic int intel_bts_process_queue(struct intel_bts_queue *btsq, u64 *timestamp) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct auxtrace_buffer *buffer = btsq->buffer, *old_buffer = buffer; 4488c2ecf20Sopenharmony_ci struct auxtrace_queue *queue; 4498c2ecf20Sopenharmony_ci struct thread *thread; 4508c2ecf20Sopenharmony_ci int err; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (btsq->done) 4538c2ecf20Sopenharmony_ci return 1; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (btsq->pid == -1) { 4568c2ecf20Sopenharmony_ci thread = machine__find_thread(btsq->bts->machine, -1, 4578c2ecf20Sopenharmony_ci btsq->tid); 4588c2ecf20Sopenharmony_ci if (thread) 4598c2ecf20Sopenharmony_ci btsq->pid = thread->pid_; 4608c2ecf20Sopenharmony_ci } else { 4618c2ecf20Sopenharmony_ci thread = machine__findnew_thread(btsq->bts->machine, btsq->pid, 4628c2ecf20Sopenharmony_ci btsq->tid); 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci queue = &btsq->bts->queues.queue_array[btsq->queue_nr]; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if (!buffer) 4688c2ecf20Sopenharmony_ci buffer = auxtrace_buffer__next(queue, NULL); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (!buffer) { 4718c2ecf20Sopenharmony_ci if (!btsq->bts->sampling_mode) 4728c2ecf20Sopenharmony_ci btsq->done = 1; 4738c2ecf20Sopenharmony_ci err = 1; 4748c2ecf20Sopenharmony_ci goto out_put; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* Currently there is no support for split buffers */ 4788c2ecf20Sopenharmony_ci if (buffer->consecutive) { 4798c2ecf20Sopenharmony_ci err = -EINVAL; 4808c2ecf20Sopenharmony_ci goto out_put; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (!buffer->data) { 4848c2ecf20Sopenharmony_ci int fd = perf_data__fd(btsq->bts->session->data); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci buffer->data = auxtrace_buffer__get_data(buffer, fd); 4878c2ecf20Sopenharmony_ci if (!buffer->data) { 4888c2ecf20Sopenharmony_ci err = -ENOMEM; 4898c2ecf20Sopenharmony_ci goto out_put; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (btsq->bts->snapshot_mode && !buffer->consecutive && 4948c2ecf20Sopenharmony_ci intel_bts_do_fix_overlap(queue, buffer)) { 4958c2ecf20Sopenharmony_ci err = -ENOMEM; 4968c2ecf20Sopenharmony_ci goto out_put; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (!btsq->bts->synth_opts.callchain && 5008c2ecf20Sopenharmony_ci !btsq->bts->synth_opts.thread_stack && thread && 5018c2ecf20Sopenharmony_ci (!old_buffer || btsq->bts->sampling_mode || 5028c2ecf20Sopenharmony_ci (btsq->bts->snapshot_mode && !buffer->consecutive))) 5038c2ecf20Sopenharmony_ci thread_stack__set_trace_nr(thread, btsq->cpu, buffer->buffer_nr + 1); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci err = intel_bts_process_buffer(btsq, buffer, thread); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci auxtrace_buffer__drop_data(buffer); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci btsq->buffer = auxtrace_buffer__next(queue, buffer); 5108c2ecf20Sopenharmony_ci if (btsq->buffer) { 5118c2ecf20Sopenharmony_ci if (timestamp) 5128c2ecf20Sopenharmony_ci *timestamp = btsq->buffer->reference; 5138c2ecf20Sopenharmony_ci } else { 5148c2ecf20Sopenharmony_ci if (!btsq->bts->sampling_mode) 5158c2ecf20Sopenharmony_ci btsq->done = 1; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ciout_put: 5188c2ecf20Sopenharmony_ci thread__put(thread); 5198c2ecf20Sopenharmony_ci return err; 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic int intel_bts_flush_queue(struct intel_bts_queue *btsq) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci u64 ts = 0; 5258c2ecf20Sopenharmony_ci int ret; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci while (1) { 5288c2ecf20Sopenharmony_ci ret = intel_bts_process_queue(btsq, &ts); 5298c2ecf20Sopenharmony_ci if (ret < 0) 5308c2ecf20Sopenharmony_ci return ret; 5318c2ecf20Sopenharmony_ci if (ret) 5328c2ecf20Sopenharmony_ci break; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci return 0; 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic int intel_bts_process_tid_exit(struct intel_bts *bts, pid_t tid) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct auxtrace_queues *queues = &bts->queues; 5408c2ecf20Sopenharmony_ci unsigned int i; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci for (i = 0; i < queues->nr_queues; i++) { 5438c2ecf20Sopenharmony_ci struct auxtrace_queue *queue = &bts->queues.queue_array[i]; 5448c2ecf20Sopenharmony_ci struct intel_bts_queue *btsq = queue->priv; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (btsq && btsq->tid == tid) 5478c2ecf20Sopenharmony_ci return intel_bts_flush_queue(btsq); 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci return 0; 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic int intel_bts_process_queues(struct intel_bts *bts, u64 timestamp) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci while (1) { 5558c2ecf20Sopenharmony_ci unsigned int queue_nr; 5568c2ecf20Sopenharmony_ci struct auxtrace_queue *queue; 5578c2ecf20Sopenharmony_ci struct intel_bts_queue *btsq; 5588c2ecf20Sopenharmony_ci u64 ts = 0; 5598c2ecf20Sopenharmony_ci int ret; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (!bts->heap.heap_cnt) 5628c2ecf20Sopenharmony_ci return 0; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (bts->heap.heap_array[0].ordinal > timestamp) 5658c2ecf20Sopenharmony_ci return 0; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci queue_nr = bts->heap.heap_array[0].queue_nr; 5688c2ecf20Sopenharmony_ci queue = &bts->queues.queue_array[queue_nr]; 5698c2ecf20Sopenharmony_ci btsq = queue->priv; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci auxtrace_heap__pop(&bts->heap); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci ret = intel_bts_process_queue(btsq, &ts); 5748c2ecf20Sopenharmony_ci if (ret < 0) { 5758c2ecf20Sopenharmony_ci auxtrace_heap__add(&bts->heap, queue_nr, ts); 5768c2ecf20Sopenharmony_ci return ret; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (!ret) { 5808c2ecf20Sopenharmony_ci ret = auxtrace_heap__add(&bts->heap, queue_nr, ts); 5818c2ecf20Sopenharmony_ci if (ret < 0) 5828c2ecf20Sopenharmony_ci return ret; 5838c2ecf20Sopenharmony_ci } else { 5848c2ecf20Sopenharmony_ci btsq->on_heap = false; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci return 0; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic int intel_bts_process_event(struct perf_session *session, 5928c2ecf20Sopenharmony_ci union perf_event *event, 5938c2ecf20Sopenharmony_ci struct perf_sample *sample, 5948c2ecf20Sopenharmony_ci struct perf_tool *tool) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts, 5978c2ecf20Sopenharmony_ci auxtrace); 5988c2ecf20Sopenharmony_ci u64 timestamp; 5998c2ecf20Sopenharmony_ci int err; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (dump_trace) 6028c2ecf20Sopenharmony_ci return 0; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (!tool->ordered_events) { 6058c2ecf20Sopenharmony_ci pr_err("Intel BTS requires ordered events\n"); 6068c2ecf20Sopenharmony_ci return -EINVAL; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (sample->time && sample->time != (u64)-1) 6108c2ecf20Sopenharmony_ci timestamp = perf_time_to_tsc(sample->time, &bts->tc); 6118c2ecf20Sopenharmony_ci else 6128c2ecf20Sopenharmony_ci timestamp = 0; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci err = intel_bts_update_queues(bts); 6158c2ecf20Sopenharmony_ci if (err) 6168c2ecf20Sopenharmony_ci return err; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci err = intel_bts_process_queues(bts, timestamp); 6198c2ecf20Sopenharmony_ci if (err) 6208c2ecf20Sopenharmony_ci return err; 6218c2ecf20Sopenharmony_ci if (event->header.type == PERF_RECORD_EXIT) { 6228c2ecf20Sopenharmony_ci err = intel_bts_process_tid_exit(bts, event->fork.tid); 6238c2ecf20Sopenharmony_ci if (err) 6248c2ecf20Sopenharmony_ci return err; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (event->header.type == PERF_RECORD_AUX && 6288c2ecf20Sopenharmony_ci (event->aux.flags & PERF_AUX_FLAG_TRUNCATED) && 6298c2ecf20Sopenharmony_ci bts->synth_opts.errors) 6308c2ecf20Sopenharmony_ci err = intel_bts_lost(bts, sample); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci return err; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic int intel_bts_process_auxtrace_event(struct perf_session *session, 6368c2ecf20Sopenharmony_ci union perf_event *event, 6378c2ecf20Sopenharmony_ci struct perf_tool *tool __maybe_unused) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts, 6408c2ecf20Sopenharmony_ci auxtrace); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (bts->sampling_mode) 6438c2ecf20Sopenharmony_ci return 0; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (!bts->data_queued) { 6468c2ecf20Sopenharmony_ci struct auxtrace_buffer *buffer; 6478c2ecf20Sopenharmony_ci off_t data_offset; 6488c2ecf20Sopenharmony_ci int fd = perf_data__fd(session->data); 6498c2ecf20Sopenharmony_ci int err; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if (perf_data__is_pipe(session->data)) { 6528c2ecf20Sopenharmony_ci data_offset = 0; 6538c2ecf20Sopenharmony_ci } else { 6548c2ecf20Sopenharmony_ci data_offset = lseek(fd, 0, SEEK_CUR); 6558c2ecf20Sopenharmony_ci if (data_offset == -1) 6568c2ecf20Sopenharmony_ci return -errno; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci err = auxtrace_queues__add_event(&bts->queues, session, event, 6608c2ecf20Sopenharmony_ci data_offset, &buffer); 6618c2ecf20Sopenharmony_ci if (err) 6628c2ecf20Sopenharmony_ci return err; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* Dump here now we have copied a piped trace out of the pipe */ 6658c2ecf20Sopenharmony_ci if (dump_trace) { 6668c2ecf20Sopenharmony_ci if (auxtrace_buffer__get_data(buffer, fd)) { 6678c2ecf20Sopenharmony_ci intel_bts_dump_event(bts, buffer->data, 6688c2ecf20Sopenharmony_ci buffer->size); 6698c2ecf20Sopenharmony_ci auxtrace_buffer__put_data(buffer); 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci return 0; 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic int intel_bts_flush(struct perf_session *session, 6788c2ecf20Sopenharmony_ci struct perf_tool *tool __maybe_unused) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts, 6818c2ecf20Sopenharmony_ci auxtrace); 6828c2ecf20Sopenharmony_ci int ret; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (dump_trace || bts->sampling_mode) 6858c2ecf20Sopenharmony_ci return 0; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci if (!tool->ordered_events) 6888c2ecf20Sopenharmony_ci return -EINVAL; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci ret = intel_bts_update_queues(bts); 6918c2ecf20Sopenharmony_ci if (ret < 0) 6928c2ecf20Sopenharmony_ci return ret; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci return intel_bts_process_queues(bts, MAX_TIMESTAMP); 6958c2ecf20Sopenharmony_ci} 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_cistatic void intel_bts_free_queue(void *priv) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci struct intel_bts_queue *btsq = priv; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (!btsq) 7028c2ecf20Sopenharmony_ci return; 7038c2ecf20Sopenharmony_ci free(btsq); 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic void intel_bts_free_events(struct perf_session *session) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts, 7098c2ecf20Sopenharmony_ci auxtrace); 7108c2ecf20Sopenharmony_ci struct auxtrace_queues *queues = &bts->queues; 7118c2ecf20Sopenharmony_ci unsigned int i; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci for (i = 0; i < queues->nr_queues; i++) { 7148c2ecf20Sopenharmony_ci intel_bts_free_queue(queues->queue_array[i].priv); 7158c2ecf20Sopenharmony_ci queues->queue_array[i].priv = NULL; 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci auxtrace_queues__free(queues); 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic void intel_bts_free(struct perf_session *session) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts, 7238c2ecf20Sopenharmony_ci auxtrace); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci auxtrace_heap__free(&bts->heap); 7268c2ecf20Sopenharmony_ci intel_bts_free_events(session); 7278c2ecf20Sopenharmony_ci session->auxtrace = NULL; 7288c2ecf20Sopenharmony_ci free(bts); 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistatic bool intel_bts_evsel_is_auxtrace(struct perf_session *session, 7328c2ecf20Sopenharmony_ci struct evsel *evsel) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts, 7358c2ecf20Sopenharmony_ci auxtrace); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci return evsel->core.attr.type == bts->pmu_type; 7388c2ecf20Sopenharmony_ci} 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_cistruct intel_bts_synth { 7418c2ecf20Sopenharmony_ci struct perf_tool dummy_tool; 7428c2ecf20Sopenharmony_ci struct perf_session *session; 7438c2ecf20Sopenharmony_ci}; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic int intel_bts_event_synth(struct perf_tool *tool, 7468c2ecf20Sopenharmony_ci union perf_event *event, 7478c2ecf20Sopenharmony_ci struct perf_sample *sample __maybe_unused, 7488c2ecf20Sopenharmony_ci struct machine *machine __maybe_unused) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci struct intel_bts_synth *intel_bts_synth = 7518c2ecf20Sopenharmony_ci container_of(tool, struct intel_bts_synth, dummy_tool); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci return perf_session__deliver_synth_event(intel_bts_synth->session, 7548c2ecf20Sopenharmony_ci event, NULL); 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic int intel_bts_synth_event(struct perf_session *session, 7588c2ecf20Sopenharmony_ci struct perf_event_attr *attr, u64 id) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct intel_bts_synth intel_bts_synth; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci memset(&intel_bts_synth, 0, sizeof(struct intel_bts_synth)); 7638c2ecf20Sopenharmony_ci intel_bts_synth.session = session; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci return perf_event__synthesize_attr(&intel_bts_synth.dummy_tool, attr, 1, 7668c2ecf20Sopenharmony_ci &id, intel_bts_event_synth); 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic int intel_bts_synth_events(struct intel_bts *bts, 7708c2ecf20Sopenharmony_ci struct perf_session *session) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci struct evlist *evlist = session->evlist; 7738c2ecf20Sopenharmony_ci struct evsel *evsel; 7748c2ecf20Sopenharmony_ci struct perf_event_attr attr; 7758c2ecf20Sopenharmony_ci bool found = false; 7768c2ecf20Sopenharmony_ci u64 id; 7778c2ecf20Sopenharmony_ci int err; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 7808c2ecf20Sopenharmony_ci if (evsel->core.attr.type == bts->pmu_type && evsel->core.ids) { 7818c2ecf20Sopenharmony_ci found = true; 7828c2ecf20Sopenharmony_ci break; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if (!found) { 7878c2ecf20Sopenharmony_ci pr_debug("There are no selected events with Intel BTS data\n"); 7888c2ecf20Sopenharmony_ci return 0; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci memset(&attr, 0, sizeof(struct perf_event_attr)); 7928c2ecf20Sopenharmony_ci attr.size = sizeof(struct perf_event_attr); 7938c2ecf20Sopenharmony_ci attr.type = PERF_TYPE_HARDWARE; 7948c2ecf20Sopenharmony_ci attr.sample_type = evsel->core.attr.sample_type & PERF_SAMPLE_MASK; 7958c2ecf20Sopenharmony_ci attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID | 7968c2ecf20Sopenharmony_ci PERF_SAMPLE_PERIOD; 7978c2ecf20Sopenharmony_ci attr.sample_type &= ~(u64)PERF_SAMPLE_TIME; 7988c2ecf20Sopenharmony_ci attr.sample_type &= ~(u64)PERF_SAMPLE_CPU; 7998c2ecf20Sopenharmony_ci attr.exclude_user = evsel->core.attr.exclude_user; 8008c2ecf20Sopenharmony_ci attr.exclude_kernel = evsel->core.attr.exclude_kernel; 8018c2ecf20Sopenharmony_ci attr.exclude_hv = evsel->core.attr.exclude_hv; 8028c2ecf20Sopenharmony_ci attr.exclude_host = evsel->core.attr.exclude_host; 8038c2ecf20Sopenharmony_ci attr.exclude_guest = evsel->core.attr.exclude_guest; 8048c2ecf20Sopenharmony_ci attr.sample_id_all = evsel->core.attr.sample_id_all; 8058c2ecf20Sopenharmony_ci attr.read_format = evsel->core.attr.read_format; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci id = evsel->core.id[0] + 1000000000; 8088c2ecf20Sopenharmony_ci if (!id) 8098c2ecf20Sopenharmony_ci id = 1; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci if (bts->synth_opts.branches) { 8128c2ecf20Sopenharmony_ci attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; 8138c2ecf20Sopenharmony_ci attr.sample_period = 1; 8148c2ecf20Sopenharmony_ci attr.sample_type |= PERF_SAMPLE_ADDR; 8158c2ecf20Sopenharmony_ci pr_debug("Synthesizing 'branches' event with id %" PRIu64 " sample type %#" PRIx64 "\n", 8168c2ecf20Sopenharmony_ci id, (u64)attr.sample_type); 8178c2ecf20Sopenharmony_ci err = intel_bts_synth_event(session, &attr, id); 8188c2ecf20Sopenharmony_ci if (err) { 8198c2ecf20Sopenharmony_ci pr_err("%s: failed to synthesize 'branches' event type\n", 8208c2ecf20Sopenharmony_ci __func__); 8218c2ecf20Sopenharmony_ci return err; 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci bts->sample_branches = true; 8248c2ecf20Sopenharmony_ci bts->branches_sample_type = attr.sample_type; 8258c2ecf20Sopenharmony_ci bts->branches_id = id; 8268c2ecf20Sopenharmony_ci /* 8278c2ecf20Sopenharmony_ci * We only use sample types from PERF_SAMPLE_MASK so we can use 8288c2ecf20Sopenharmony_ci * __evsel__sample_size() here. 8298c2ecf20Sopenharmony_ci */ 8308c2ecf20Sopenharmony_ci bts->branches_event_size = sizeof(struct perf_record_sample) + 8318c2ecf20Sopenharmony_ci __evsel__sample_size(attr.sample_type); 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci return 0; 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic const char * const intel_bts_info_fmts[] = { 8388c2ecf20Sopenharmony_ci [INTEL_BTS_PMU_TYPE] = " PMU Type %"PRId64"\n", 8398c2ecf20Sopenharmony_ci [INTEL_BTS_TIME_SHIFT] = " Time Shift %"PRIu64"\n", 8408c2ecf20Sopenharmony_ci [INTEL_BTS_TIME_MULT] = " Time Muliplier %"PRIu64"\n", 8418c2ecf20Sopenharmony_ci [INTEL_BTS_TIME_ZERO] = " Time Zero %"PRIu64"\n", 8428c2ecf20Sopenharmony_ci [INTEL_BTS_CAP_USER_TIME_ZERO] = " Cap Time Zero %"PRId64"\n", 8438c2ecf20Sopenharmony_ci [INTEL_BTS_SNAPSHOT_MODE] = " Snapshot mode %"PRId64"\n", 8448c2ecf20Sopenharmony_ci}; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cistatic void intel_bts_print_info(__u64 *arr, int start, int finish) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci int i; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci if (!dump_trace) 8518c2ecf20Sopenharmony_ci return; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci for (i = start; i <= finish; i++) 8548c2ecf20Sopenharmony_ci fprintf(stdout, intel_bts_info_fmts[i], arr[i]); 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ciint intel_bts_process_auxtrace_info(union perf_event *event, 8588c2ecf20Sopenharmony_ci struct perf_session *session) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; 8618c2ecf20Sopenharmony_ci size_t min_sz = sizeof(u64) * INTEL_BTS_SNAPSHOT_MODE; 8628c2ecf20Sopenharmony_ci struct intel_bts *bts; 8638c2ecf20Sopenharmony_ci int err; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) + 8668c2ecf20Sopenharmony_ci min_sz) 8678c2ecf20Sopenharmony_ci return -EINVAL; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci bts = zalloc(sizeof(struct intel_bts)); 8708c2ecf20Sopenharmony_ci if (!bts) 8718c2ecf20Sopenharmony_ci return -ENOMEM; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci err = auxtrace_queues__init(&bts->queues); 8748c2ecf20Sopenharmony_ci if (err) 8758c2ecf20Sopenharmony_ci goto err_free; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci bts->session = session; 8788c2ecf20Sopenharmony_ci bts->machine = &session->machines.host; /* No kvm support */ 8798c2ecf20Sopenharmony_ci bts->auxtrace_type = auxtrace_info->type; 8808c2ecf20Sopenharmony_ci bts->pmu_type = auxtrace_info->priv[INTEL_BTS_PMU_TYPE]; 8818c2ecf20Sopenharmony_ci bts->tc.time_shift = auxtrace_info->priv[INTEL_BTS_TIME_SHIFT]; 8828c2ecf20Sopenharmony_ci bts->tc.time_mult = auxtrace_info->priv[INTEL_BTS_TIME_MULT]; 8838c2ecf20Sopenharmony_ci bts->tc.time_zero = auxtrace_info->priv[INTEL_BTS_TIME_ZERO]; 8848c2ecf20Sopenharmony_ci bts->cap_user_time_zero = 8858c2ecf20Sopenharmony_ci auxtrace_info->priv[INTEL_BTS_CAP_USER_TIME_ZERO]; 8868c2ecf20Sopenharmony_ci bts->snapshot_mode = auxtrace_info->priv[INTEL_BTS_SNAPSHOT_MODE]; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci bts->sampling_mode = false; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci bts->auxtrace.process_event = intel_bts_process_event; 8918c2ecf20Sopenharmony_ci bts->auxtrace.process_auxtrace_event = intel_bts_process_auxtrace_event; 8928c2ecf20Sopenharmony_ci bts->auxtrace.flush_events = intel_bts_flush; 8938c2ecf20Sopenharmony_ci bts->auxtrace.free_events = intel_bts_free_events; 8948c2ecf20Sopenharmony_ci bts->auxtrace.free = intel_bts_free; 8958c2ecf20Sopenharmony_ci bts->auxtrace.evsel_is_auxtrace = intel_bts_evsel_is_auxtrace; 8968c2ecf20Sopenharmony_ci session->auxtrace = &bts->auxtrace; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci intel_bts_print_info(&auxtrace_info->priv[0], INTEL_BTS_PMU_TYPE, 8998c2ecf20Sopenharmony_ci INTEL_BTS_SNAPSHOT_MODE); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci if (dump_trace) 9028c2ecf20Sopenharmony_ci return 0; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci if (session->itrace_synth_opts->set) { 9058c2ecf20Sopenharmony_ci bts->synth_opts = *session->itrace_synth_opts; 9068c2ecf20Sopenharmony_ci } else { 9078c2ecf20Sopenharmony_ci itrace_synth_opts__set_default(&bts->synth_opts, 9088c2ecf20Sopenharmony_ci session->itrace_synth_opts->default_no_sample); 9098c2ecf20Sopenharmony_ci bts->synth_opts.thread_stack = 9108c2ecf20Sopenharmony_ci session->itrace_synth_opts->thread_stack; 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (bts->synth_opts.calls) 9148c2ecf20Sopenharmony_ci bts->branches_filter |= PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC | 9158c2ecf20Sopenharmony_ci PERF_IP_FLAG_TRACE_END; 9168c2ecf20Sopenharmony_ci if (bts->synth_opts.returns) 9178c2ecf20Sopenharmony_ci bts->branches_filter |= PERF_IP_FLAG_RETURN | 9188c2ecf20Sopenharmony_ci PERF_IP_FLAG_TRACE_BEGIN; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci err = intel_bts_synth_events(bts, session); 9218c2ecf20Sopenharmony_ci if (err) 9228c2ecf20Sopenharmony_ci goto err_free_queues; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci err = auxtrace_queues__process_index(&bts->queues, session); 9258c2ecf20Sopenharmony_ci if (err) 9268c2ecf20Sopenharmony_ci goto err_free_queues; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (bts->queues.populated) 9298c2ecf20Sopenharmony_ci bts->data_queued = true; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci return 0; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_cierr_free_queues: 9348c2ecf20Sopenharmony_ci auxtrace_queues__free(&bts->queues); 9358c2ecf20Sopenharmony_ci session->auxtrace = NULL; 9368c2ecf20Sopenharmony_cierr_free: 9378c2ecf20Sopenharmony_ci free(bts); 9388c2ecf20Sopenharmony_ci return err; 9398c2ecf20Sopenharmony_ci} 940