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 <errno.h> 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/types.h> 108c2ecf20Sopenharmony_ci#include <linux/bitops.h> 118c2ecf20Sopenharmony_ci#include <linux/log2.h> 128c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "../../../util/cpumap.h" 158c2ecf20Sopenharmony_ci#include "../../../util/event.h" 168c2ecf20Sopenharmony_ci#include "../../../util/evsel.h" 178c2ecf20Sopenharmony_ci#include "../../../util/evlist.h" 188c2ecf20Sopenharmony_ci#include "../../../util/mmap.h" 198c2ecf20Sopenharmony_ci#include "../../../util/session.h" 208c2ecf20Sopenharmony_ci#include "../../../util/pmu.h" 218c2ecf20Sopenharmony_ci#include "../../../util/debug.h" 228c2ecf20Sopenharmony_ci#include "../../../util/record.h" 238c2ecf20Sopenharmony_ci#include "../../../util/tsc.h" 248c2ecf20Sopenharmony_ci#include "../../../util/auxtrace.h" 258c2ecf20Sopenharmony_ci#include "../../../util/intel-bts.h" 268c2ecf20Sopenharmony_ci#include <internal/lib.h> // page_size 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define KiB(x) ((x) * 1024) 298c2ecf20Sopenharmony_ci#define MiB(x) ((x) * 1024 * 1024) 308c2ecf20Sopenharmony_ci#define KiB_MASK(x) (KiB(x) - 1) 318c2ecf20Sopenharmony_ci#define MiB_MASK(x) (MiB(x) - 1) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistruct intel_bts_snapshot_ref { 348c2ecf20Sopenharmony_ci void *ref_buf; 358c2ecf20Sopenharmony_ci size_t ref_offset; 368c2ecf20Sopenharmony_ci bool wrapped; 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistruct intel_bts_recording { 408c2ecf20Sopenharmony_ci struct auxtrace_record itr; 418c2ecf20Sopenharmony_ci struct perf_pmu *intel_bts_pmu; 428c2ecf20Sopenharmony_ci struct evlist *evlist; 438c2ecf20Sopenharmony_ci bool snapshot_mode; 448c2ecf20Sopenharmony_ci size_t snapshot_size; 458c2ecf20Sopenharmony_ci int snapshot_ref_cnt; 468c2ecf20Sopenharmony_ci struct intel_bts_snapshot_ref *snapshot_refs; 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistruct branch { 508c2ecf20Sopenharmony_ci u64 from; 518c2ecf20Sopenharmony_ci u64 to; 528c2ecf20Sopenharmony_ci u64 misc; 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic size_t 568c2ecf20Sopenharmony_ciintel_bts_info_priv_size(struct auxtrace_record *itr __maybe_unused, 578c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci return INTEL_BTS_AUXTRACE_PRIV_SIZE; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int intel_bts_info_fill(struct auxtrace_record *itr, 638c2ecf20Sopenharmony_ci struct perf_session *session, 648c2ecf20Sopenharmony_ci struct perf_record_auxtrace_info *auxtrace_info, 658c2ecf20Sopenharmony_ci size_t priv_size) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct intel_bts_recording *btsr = 688c2ecf20Sopenharmony_ci container_of(itr, struct intel_bts_recording, itr); 698c2ecf20Sopenharmony_ci struct perf_pmu *intel_bts_pmu = btsr->intel_bts_pmu; 708c2ecf20Sopenharmony_ci struct perf_event_mmap_page *pc; 718c2ecf20Sopenharmony_ci struct perf_tsc_conversion tc = { .time_mult = 0, }; 728c2ecf20Sopenharmony_ci bool cap_user_time_zero = false; 738c2ecf20Sopenharmony_ci int err; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (priv_size != INTEL_BTS_AUXTRACE_PRIV_SIZE) 768c2ecf20Sopenharmony_ci return -EINVAL; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (!session->evlist->core.nr_mmaps) 798c2ecf20Sopenharmony_ci return -EINVAL; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci pc = session->evlist->mmap[0].core.base; 828c2ecf20Sopenharmony_ci if (pc) { 838c2ecf20Sopenharmony_ci err = perf_read_tsc_conversion(pc, &tc); 848c2ecf20Sopenharmony_ci if (err) { 858c2ecf20Sopenharmony_ci if (err != -EOPNOTSUPP) 868c2ecf20Sopenharmony_ci return err; 878c2ecf20Sopenharmony_ci } else { 888c2ecf20Sopenharmony_ci cap_user_time_zero = tc.time_mult != 0; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci if (!cap_user_time_zero) 918c2ecf20Sopenharmony_ci ui__warning("Intel BTS: TSC not available\n"); 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci auxtrace_info->type = PERF_AUXTRACE_INTEL_BTS; 958c2ecf20Sopenharmony_ci auxtrace_info->priv[INTEL_BTS_PMU_TYPE] = intel_bts_pmu->type; 968c2ecf20Sopenharmony_ci auxtrace_info->priv[INTEL_BTS_TIME_SHIFT] = tc.time_shift; 978c2ecf20Sopenharmony_ci auxtrace_info->priv[INTEL_BTS_TIME_MULT] = tc.time_mult; 988c2ecf20Sopenharmony_ci auxtrace_info->priv[INTEL_BTS_TIME_ZERO] = tc.time_zero; 998c2ecf20Sopenharmony_ci auxtrace_info->priv[INTEL_BTS_CAP_USER_TIME_ZERO] = cap_user_time_zero; 1008c2ecf20Sopenharmony_ci auxtrace_info->priv[INTEL_BTS_SNAPSHOT_MODE] = btsr->snapshot_mode; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic int intel_bts_recording_options(struct auxtrace_record *itr, 1068c2ecf20Sopenharmony_ci struct evlist *evlist, 1078c2ecf20Sopenharmony_ci struct record_opts *opts) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct intel_bts_recording *btsr = 1108c2ecf20Sopenharmony_ci container_of(itr, struct intel_bts_recording, itr); 1118c2ecf20Sopenharmony_ci struct perf_pmu *intel_bts_pmu = btsr->intel_bts_pmu; 1128c2ecf20Sopenharmony_ci struct evsel *evsel, *intel_bts_evsel = NULL; 1138c2ecf20Sopenharmony_ci const struct perf_cpu_map *cpus = evlist->core.cpus; 1148c2ecf20Sopenharmony_ci bool privileged = perf_event_paranoid_check(-1); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (opts->auxtrace_sample_mode) { 1178c2ecf20Sopenharmony_ci pr_err("Intel BTS does not support AUX area sampling\n"); 1188c2ecf20Sopenharmony_ci return -EINVAL; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci btsr->evlist = evlist; 1228c2ecf20Sopenharmony_ci btsr->snapshot_mode = opts->auxtrace_snapshot_mode; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 1258c2ecf20Sopenharmony_ci if (evsel->core.attr.type == intel_bts_pmu->type) { 1268c2ecf20Sopenharmony_ci if (intel_bts_evsel) { 1278c2ecf20Sopenharmony_ci pr_err("There may be only one " INTEL_BTS_PMU_NAME " event\n"); 1288c2ecf20Sopenharmony_ci return -EINVAL; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci evsel->core.attr.freq = 0; 1318c2ecf20Sopenharmony_ci evsel->core.attr.sample_period = 1; 1328c2ecf20Sopenharmony_ci intel_bts_evsel = evsel; 1338c2ecf20Sopenharmony_ci opts->full_auxtrace = true; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (opts->auxtrace_snapshot_mode && !opts->full_auxtrace) { 1388c2ecf20Sopenharmony_ci pr_err("Snapshot mode (-S option) requires " INTEL_BTS_PMU_NAME " PMU event (-e " INTEL_BTS_PMU_NAME ")\n"); 1398c2ecf20Sopenharmony_ci return -EINVAL; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (!opts->full_auxtrace) 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (opts->full_auxtrace && !perf_cpu_map__empty(cpus)) { 1468c2ecf20Sopenharmony_ci pr_err(INTEL_BTS_PMU_NAME " does not support per-cpu recording\n"); 1478c2ecf20Sopenharmony_ci return -EINVAL; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* Set default sizes for snapshot mode */ 1518c2ecf20Sopenharmony_ci if (opts->auxtrace_snapshot_mode) { 1528c2ecf20Sopenharmony_ci if (!opts->auxtrace_snapshot_size && !opts->auxtrace_mmap_pages) { 1538c2ecf20Sopenharmony_ci if (privileged) { 1548c2ecf20Sopenharmony_ci opts->auxtrace_mmap_pages = MiB(4) / page_size; 1558c2ecf20Sopenharmony_ci } else { 1568c2ecf20Sopenharmony_ci opts->auxtrace_mmap_pages = KiB(128) / page_size; 1578c2ecf20Sopenharmony_ci if (opts->mmap_pages == UINT_MAX) 1588c2ecf20Sopenharmony_ci opts->mmap_pages = KiB(256) / page_size; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci } else if (!opts->auxtrace_mmap_pages && !privileged && 1618c2ecf20Sopenharmony_ci opts->mmap_pages == UINT_MAX) { 1628c2ecf20Sopenharmony_ci opts->mmap_pages = KiB(256) / page_size; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci if (!opts->auxtrace_snapshot_size) 1658c2ecf20Sopenharmony_ci opts->auxtrace_snapshot_size = 1668c2ecf20Sopenharmony_ci opts->auxtrace_mmap_pages * (size_t)page_size; 1678c2ecf20Sopenharmony_ci if (!opts->auxtrace_mmap_pages) { 1688c2ecf20Sopenharmony_ci size_t sz = opts->auxtrace_snapshot_size; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci sz = round_up(sz, page_size) / page_size; 1718c2ecf20Sopenharmony_ci opts->auxtrace_mmap_pages = roundup_pow_of_two(sz); 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci if (opts->auxtrace_snapshot_size > 1748c2ecf20Sopenharmony_ci opts->auxtrace_mmap_pages * (size_t)page_size) { 1758c2ecf20Sopenharmony_ci pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n", 1768c2ecf20Sopenharmony_ci opts->auxtrace_snapshot_size, 1778c2ecf20Sopenharmony_ci opts->auxtrace_mmap_pages * (size_t)page_size); 1788c2ecf20Sopenharmony_ci return -EINVAL; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci if (!opts->auxtrace_snapshot_size || !opts->auxtrace_mmap_pages) { 1818c2ecf20Sopenharmony_ci pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n"); 1828c2ecf20Sopenharmony_ci return -EINVAL; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci pr_debug2("Intel BTS snapshot size: %zu\n", 1858c2ecf20Sopenharmony_ci opts->auxtrace_snapshot_size); 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* Set default sizes for full trace mode */ 1898c2ecf20Sopenharmony_ci if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) { 1908c2ecf20Sopenharmony_ci if (privileged) { 1918c2ecf20Sopenharmony_ci opts->auxtrace_mmap_pages = MiB(4) / page_size; 1928c2ecf20Sopenharmony_ci } else { 1938c2ecf20Sopenharmony_ci opts->auxtrace_mmap_pages = KiB(128) / page_size; 1948c2ecf20Sopenharmony_ci if (opts->mmap_pages == UINT_MAX) 1958c2ecf20Sopenharmony_ci opts->mmap_pages = KiB(256) / page_size; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* Validate auxtrace_mmap_pages */ 2008c2ecf20Sopenharmony_ci if (opts->auxtrace_mmap_pages) { 2018c2ecf20Sopenharmony_ci size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size; 2028c2ecf20Sopenharmony_ci size_t min_sz; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (opts->auxtrace_snapshot_mode) 2058c2ecf20Sopenharmony_ci min_sz = KiB(4); 2068c2ecf20Sopenharmony_ci else 2078c2ecf20Sopenharmony_ci min_sz = KiB(8); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (sz < min_sz || !is_power_of_2(sz)) { 2108c2ecf20Sopenharmony_ci pr_err("Invalid mmap size for Intel BTS: must be at least %zuKiB and a power of 2\n", 2118c2ecf20Sopenharmony_ci min_sz / 1024); 2128c2ecf20Sopenharmony_ci return -EINVAL; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (intel_bts_evsel) { 2178c2ecf20Sopenharmony_ci /* 2188c2ecf20Sopenharmony_ci * To obtain the auxtrace buffer file descriptor, the auxtrace event 2198c2ecf20Sopenharmony_ci * must come first. 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_ci perf_evlist__to_front(evlist, intel_bts_evsel); 2228c2ecf20Sopenharmony_ci /* 2238c2ecf20Sopenharmony_ci * In the case of per-cpu mmaps, we need the CPU on the 2248c2ecf20Sopenharmony_ci * AUX event. 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_ci if (!perf_cpu_map__empty(cpus)) 2278c2ecf20Sopenharmony_ci evsel__set_sample_bit(intel_bts_evsel, CPU); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* Add dummy event to keep tracking */ 2318c2ecf20Sopenharmony_ci if (opts->full_auxtrace) { 2328c2ecf20Sopenharmony_ci struct evsel *tracking_evsel; 2338c2ecf20Sopenharmony_ci int err; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci err = parse_events(evlist, "dummy:u", NULL); 2368c2ecf20Sopenharmony_ci if (err) 2378c2ecf20Sopenharmony_ci return err; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci tracking_evsel = evlist__last(evlist); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci perf_evlist__set_tracking_event(evlist, tracking_evsel); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci tracking_evsel->core.attr.freq = 0; 2448c2ecf20Sopenharmony_ci tracking_evsel->core.attr.sample_period = 1; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int intel_bts_parse_snapshot_options(struct auxtrace_record *itr, 2518c2ecf20Sopenharmony_ci struct record_opts *opts, 2528c2ecf20Sopenharmony_ci const char *str) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct intel_bts_recording *btsr = 2558c2ecf20Sopenharmony_ci container_of(itr, struct intel_bts_recording, itr); 2568c2ecf20Sopenharmony_ci unsigned long long snapshot_size = 0; 2578c2ecf20Sopenharmony_ci char *endptr; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (str) { 2608c2ecf20Sopenharmony_ci snapshot_size = strtoull(str, &endptr, 0); 2618c2ecf20Sopenharmony_ci if (*endptr || snapshot_size > SIZE_MAX) 2628c2ecf20Sopenharmony_ci return -1; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci opts->auxtrace_snapshot_mode = true; 2668c2ecf20Sopenharmony_ci opts->auxtrace_snapshot_size = snapshot_size; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci btsr->snapshot_size = snapshot_size; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return 0; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic u64 intel_bts_reference(struct auxtrace_record *itr __maybe_unused) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci return rdtsc(); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic int intel_bts_alloc_snapshot_refs(struct intel_bts_recording *btsr, 2798c2ecf20Sopenharmony_ci int idx) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci const size_t sz = sizeof(struct intel_bts_snapshot_ref); 2828c2ecf20Sopenharmony_ci int cnt = btsr->snapshot_ref_cnt, new_cnt = cnt * 2; 2838c2ecf20Sopenharmony_ci struct intel_bts_snapshot_ref *refs; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (!new_cnt) 2868c2ecf20Sopenharmony_ci new_cnt = 16; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci while (new_cnt <= idx) 2898c2ecf20Sopenharmony_ci new_cnt *= 2; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci refs = calloc(new_cnt, sz); 2928c2ecf20Sopenharmony_ci if (!refs) 2938c2ecf20Sopenharmony_ci return -ENOMEM; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci memcpy(refs, btsr->snapshot_refs, cnt * sz); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci btsr->snapshot_refs = refs; 2988c2ecf20Sopenharmony_ci btsr->snapshot_ref_cnt = new_cnt; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci return 0; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic void intel_bts_free_snapshot_refs(struct intel_bts_recording *btsr) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci int i; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci for (i = 0; i < btsr->snapshot_ref_cnt; i++) 3088c2ecf20Sopenharmony_ci zfree(&btsr->snapshot_refs[i].ref_buf); 3098c2ecf20Sopenharmony_ci zfree(&btsr->snapshot_refs); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic void intel_bts_recording_free(struct auxtrace_record *itr) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct intel_bts_recording *btsr = 3158c2ecf20Sopenharmony_ci container_of(itr, struct intel_bts_recording, itr); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci intel_bts_free_snapshot_refs(btsr); 3188c2ecf20Sopenharmony_ci free(btsr); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic int intel_bts_snapshot_start(struct auxtrace_record *itr) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct intel_bts_recording *btsr = 3248c2ecf20Sopenharmony_ci container_of(itr, struct intel_bts_recording, itr); 3258c2ecf20Sopenharmony_ci struct evsel *evsel; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci evlist__for_each_entry(btsr->evlist, evsel) { 3288c2ecf20Sopenharmony_ci if (evsel->core.attr.type == btsr->intel_bts_pmu->type) 3298c2ecf20Sopenharmony_ci return evsel__disable(evsel); 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci return -EINVAL; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic int intel_bts_snapshot_finish(struct auxtrace_record *itr) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci struct intel_bts_recording *btsr = 3378c2ecf20Sopenharmony_ci container_of(itr, struct intel_bts_recording, itr); 3388c2ecf20Sopenharmony_ci struct evsel *evsel; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci evlist__for_each_entry(btsr->evlist, evsel) { 3418c2ecf20Sopenharmony_ci if (evsel->core.attr.type == btsr->intel_bts_pmu->type) 3428c2ecf20Sopenharmony_ci return evsel__enable(evsel); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci return -EINVAL; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic bool intel_bts_first_wrap(u64 *data, size_t buf_size) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci int i, a, b; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci b = buf_size >> 3; 3528c2ecf20Sopenharmony_ci a = b - 512; 3538c2ecf20Sopenharmony_ci if (a < 0) 3548c2ecf20Sopenharmony_ci a = 0; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci for (i = a; i < b; i++) { 3578c2ecf20Sopenharmony_ci if (data[i]) 3588c2ecf20Sopenharmony_ci return true; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci return false; 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic int intel_bts_find_snapshot(struct auxtrace_record *itr, int idx, 3658c2ecf20Sopenharmony_ci struct auxtrace_mmap *mm, unsigned char *data, 3668c2ecf20Sopenharmony_ci u64 *head, u64 *old) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct intel_bts_recording *btsr = 3698c2ecf20Sopenharmony_ci container_of(itr, struct intel_bts_recording, itr); 3708c2ecf20Sopenharmony_ci bool wrapped; 3718c2ecf20Sopenharmony_ci int err; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci pr_debug3("%s: mmap index %d old head %zu new head %zu\n", 3748c2ecf20Sopenharmony_ci __func__, idx, (size_t)*old, (size_t)*head); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (idx >= btsr->snapshot_ref_cnt) { 3778c2ecf20Sopenharmony_ci err = intel_bts_alloc_snapshot_refs(btsr, idx); 3788c2ecf20Sopenharmony_ci if (err) 3798c2ecf20Sopenharmony_ci goto out_err; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci wrapped = btsr->snapshot_refs[idx].wrapped; 3838c2ecf20Sopenharmony_ci if (!wrapped && intel_bts_first_wrap((u64 *)data, mm->len)) { 3848c2ecf20Sopenharmony_ci btsr->snapshot_refs[idx].wrapped = true; 3858c2ecf20Sopenharmony_ci wrapped = true; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* 3898c2ecf20Sopenharmony_ci * In full trace mode 'head' continually increases. However in snapshot 3908c2ecf20Sopenharmony_ci * mode 'head' is an offset within the buffer. Here 'old' and 'head' 3918c2ecf20Sopenharmony_ci * are adjusted to match the full trace case which expects that 'old' is 3928c2ecf20Sopenharmony_ci * always less than 'head'. 3938c2ecf20Sopenharmony_ci */ 3948c2ecf20Sopenharmony_ci if (wrapped) { 3958c2ecf20Sopenharmony_ci *old = *head; 3968c2ecf20Sopenharmony_ci *head += mm->len; 3978c2ecf20Sopenharmony_ci } else { 3988c2ecf20Sopenharmony_ci if (mm->mask) 3998c2ecf20Sopenharmony_ci *old &= mm->mask; 4008c2ecf20Sopenharmony_ci else 4018c2ecf20Sopenharmony_ci *old %= mm->len; 4028c2ecf20Sopenharmony_ci if (*old > *head) 4038c2ecf20Sopenharmony_ci *head += mm->len; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci pr_debug3("%s: wrap-around %sdetected, adjusted old head %zu adjusted new head %zu\n", 4078c2ecf20Sopenharmony_ci __func__, wrapped ? "" : "not ", (size_t)*old, (size_t)*head); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci return 0; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ciout_err: 4128c2ecf20Sopenharmony_ci pr_err("%s: failed, error %d\n", __func__, err); 4138c2ecf20Sopenharmony_ci return err; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistruct auxtrace_record *intel_bts_recording_init(int *err) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct perf_pmu *intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME); 4198c2ecf20Sopenharmony_ci struct intel_bts_recording *btsr; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (!intel_bts_pmu) 4228c2ecf20Sopenharmony_ci return NULL; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (setenv("JITDUMP_USE_ARCH_TIMESTAMP", "1", 1)) { 4258c2ecf20Sopenharmony_ci *err = -errno; 4268c2ecf20Sopenharmony_ci return NULL; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci btsr = zalloc(sizeof(struct intel_bts_recording)); 4308c2ecf20Sopenharmony_ci if (!btsr) { 4318c2ecf20Sopenharmony_ci *err = -ENOMEM; 4328c2ecf20Sopenharmony_ci return NULL; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci btsr->intel_bts_pmu = intel_bts_pmu; 4368c2ecf20Sopenharmony_ci btsr->itr.pmu = intel_bts_pmu; 4378c2ecf20Sopenharmony_ci btsr->itr.recording_options = intel_bts_recording_options; 4388c2ecf20Sopenharmony_ci btsr->itr.info_priv_size = intel_bts_info_priv_size; 4398c2ecf20Sopenharmony_ci btsr->itr.info_fill = intel_bts_info_fill; 4408c2ecf20Sopenharmony_ci btsr->itr.free = intel_bts_recording_free; 4418c2ecf20Sopenharmony_ci btsr->itr.snapshot_start = intel_bts_snapshot_start; 4428c2ecf20Sopenharmony_ci btsr->itr.snapshot_finish = intel_bts_snapshot_finish; 4438c2ecf20Sopenharmony_ci btsr->itr.find_snapshot = intel_bts_find_snapshot; 4448c2ecf20Sopenharmony_ci btsr->itr.parse_snapshot_options = intel_bts_parse_snapshot_options; 4458c2ecf20Sopenharmony_ci btsr->itr.reference = intel_bts_reference; 4468c2ecf20Sopenharmony_ci btsr->itr.read_finish = auxtrace_record__read_finish; 4478c2ecf20Sopenharmony_ci btsr->itr.alignment = sizeof(struct branch); 4488c2ecf20Sopenharmony_ci return &btsr->itr; 4498c2ecf20Sopenharmony_ci} 450