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 <errno.h> 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/types.h> 1062306a36Sopenharmony_ci#include <linux/bitops.h> 1162306a36Sopenharmony_ci#include <linux/log2.h> 1262306a36Sopenharmony_ci#include <linux/zalloc.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "../../../util/cpumap.h" 1562306a36Sopenharmony_ci#include "../../../util/event.h" 1662306a36Sopenharmony_ci#include "../../../util/evsel.h" 1762306a36Sopenharmony_ci#include "../../../util/evlist.h" 1862306a36Sopenharmony_ci#include "../../../util/mmap.h" 1962306a36Sopenharmony_ci#include "../../../util/session.h" 2062306a36Sopenharmony_ci#include "../../../util/pmus.h" 2162306a36Sopenharmony_ci#include "../../../util/debug.h" 2262306a36Sopenharmony_ci#include "../../../util/record.h" 2362306a36Sopenharmony_ci#include "../../../util/tsc.h" 2462306a36Sopenharmony_ci#include "../../../util/auxtrace.h" 2562306a36Sopenharmony_ci#include "../../../util/intel-bts.h" 2662306a36Sopenharmony_ci#include <internal/lib.h> // page_size 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define KiB(x) ((x) * 1024) 2962306a36Sopenharmony_ci#define MiB(x) ((x) * 1024 * 1024) 3062306a36Sopenharmony_ci#define KiB_MASK(x) (KiB(x) - 1) 3162306a36Sopenharmony_ci#define MiB_MASK(x) (MiB(x) - 1) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistruct intel_bts_snapshot_ref { 3462306a36Sopenharmony_ci void *ref_buf; 3562306a36Sopenharmony_ci size_t ref_offset; 3662306a36Sopenharmony_ci bool wrapped; 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistruct intel_bts_recording { 4062306a36Sopenharmony_ci struct auxtrace_record itr; 4162306a36Sopenharmony_ci struct perf_pmu *intel_bts_pmu; 4262306a36Sopenharmony_ci struct evlist *evlist; 4362306a36Sopenharmony_ci bool snapshot_mode; 4462306a36Sopenharmony_ci size_t snapshot_size; 4562306a36Sopenharmony_ci int snapshot_ref_cnt; 4662306a36Sopenharmony_ci struct intel_bts_snapshot_ref *snapshot_refs; 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistruct branch { 5062306a36Sopenharmony_ci u64 from; 5162306a36Sopenharmony_ci u64 to; 5262306a36Sopenharmony_ci u64 misc; 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic size_t 5662306a36Sopenharmony_ciintel_bts_info_priv_size(struct auxtrace_record *itr __maybe_unused, 5762306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci return INTEL_BTS_AUXTRACE_PRIV_SIZE; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic int intel_bts_info_fill(struct auxtrace_record *itr, 6362306a36Sopenharmony_ci struct perf_session *session, 6462306a36Sopenharmony_ci struct perf_record_auxtrace_info *auxtrace_info, 6562306a36Sopenharmony_ci size_t priv_size) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci struct intel_bts_recording *btsr = 6862306a36Sopenharmony_ci container_of(itr, struct intel_bts_recording, itr); 6962306a36Sopenharmony_ci struct perf_pmu *intel_bts_pmu = btsr->intel_bts_pmu; 7062306a36Sopenharmony_ci struct perf_event_mmap_page *pc; 7162306a36Sopenharmony_ci struct perf_tsc_conversion tc = { .time_mult = 0, }; 7262306a36Sopenharmony_ci bool cap_user_time_zero = false; 7362306a36Sopenharmony_ci int err; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (priv_size != INTEL_BTS_AUXTRACE_PRIV_SIZE) 7662306a36Sopenharmony_ci return -EINVAL; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (!session->evlist->core.nr_mmaps) 7962306a36Sopenharmony_ci return -EINVAL; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci pc = session->evlist->mmap[0].core.base; 8262306a36Sopenharmony_ci if (pc) { 8362306a36Sopenharmony_ci err = perf_read_tsc_conversion(pc, &tc); 8462306a36Sopenharmony_ci if (err) { 8562306a36Sopenharmony_ci if (err != -EOPNOTSUPP) 8662306a36Sopenharmony_ci return err; 8762306a36Sopenharmony_ci } else { 8862306a36Sopenharmony_ci cap_user_time_zero = tc.time_mult != 0; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci if (!cap_user_time_zero) 9162306a36Sopenharmony_ci ui__warning("Intel BTS: TSC not available\n"); 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci auxtrace_info->type = PERF_AUXTRACE_INTEL_BTS; 9562306a36Sopenharmony_ci auxtrace_info->priv[INTEL_BTS_PMU_TYPE] = intel_bts_pmu->type; 9662306a36Sopenharmony_ci auxtrace_info->priv[INTEL_BTS_TIME_SHIFT] = tc.time_shift; 9762306a36Sopenharmony_ci auxtrace_info->priv[INTEL_BTS_TIME_MULT] = tc.time_mult; 9862306a36Sopenharmony_ci auxtrace_info->priv[INTEL_BTS_TIME_ZERO] = tc.time_zero; 9962306a36Sopenharmony_ci auxtrace_info->priv[INTEL_BTS_CAP_USER_TIME_ZERO] = cap_user_time_zero; 10062306a36Sopenharmony_ci auxtrace_info->priv[INTEL_BTS_SNAPSHOT_MODE] = btsr->snapshot_mode; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci return 0; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic int intel_bts_recording_options(struct auxtrace_record *itr, 10662306a36Sopenharmony_ci struct evlist *evlist, 10762306a36Sopenharmony_ci struct record_opts *opts) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct intel_bts_recording *btsr = 11062306a36Sopenharmony_ci container_of(itr, struct intel_bts_recording, itr); 11162306a36Sopenharmony_ci struct perf_pmu *intel_bts_pmu = btsr->intel_bts_pmu; 11262306a36Sopenharmony_ci struct evsel *evsel, *intel_bts_evsel = NULL; 11362306a36Sopenharmony_ci const struct perf_cpu_map *cpus = evlist->core.user_requested_cpus; 11462306a36Sopenharmony_ci bool privileged = perf_event_paranoid_check(-1); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (opts->auxtrace_sample_mode) { 11762306a36Sopenharmony_ci pr_err("Intel BTS does not support AUX area sampling\n"); 11862306a36Sopenharmony_ci return -EINVAL; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci btsr->evlist = evlist; 12262306a36Sopenharmony_ci btsr->snapshot_mode = opts->auxtrace_snapshot_mode; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 12562306a36Sopenharmony_ci if (evsel->core.attr.type == intel_bts_pmu->type) { 12662306a36Sopenharmony_ci if (intel_bts_evsel) { 12762306a36Sopenharmony_ci pr_err("There may be only one " INTEL_BTS_PMU_NAME " event\n"); 12862306a36Sopenharmony_ci return -EINVAL; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci evsel->core.attr.freq = 0; 13162306a36Sopenharmony_ci evsel->core.attr.sample_period = 1; 13262306a36Sopenharmony_ci evsel->needs_auxtrace_mmap = true; 13362306a36Sopenharmony_ci intel_bts_evsel = evsel; 13462306a36Sopenharmony_ci opts->full_auxtrace = true; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (opts->auxtrace_snapshot_mode && !opts->full_auxtrace) { 13962306a36Sopenharmony_ci pr_err("Snapshot mode (-S option) requires " INTEL_BTS_PMU_NAME " PMU event (-e " INTEL_BTS_PMU_NAME ")\n"); 14062306a36Sopenharmony_ci return -EINVAL; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (!opts->full_auxtrace) 14462306a36Sopenharmony_ci return 0; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (opts->full_auxtrace && !perf_cpu_map__empty(cpus)) { 14762306a36Sopenharmony_ci pr_err(INTEL_BTS_PMU_NAME " does not support per-cpu recording\n"); 14862306a36Sopenharmony_ci return -EINVAL; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Set default sizes for snapshot mode */ 15262306a36Sopenharmony_ci if (opts->auxtrace_snapshot_mode) { 15362306a36Sopenharmony_ci if (!opts->auxtrace_snapshot_size && !opts->auxtrace_mmap_pages) { 15462306a36Sopenharmony_ci if (privileged) { 15562306a36Sopenharmony_ci opts->auxtrace_mmap_pages = MiB(4) / page_size; 15662306a36Sopenharmony_ci } else { 15762306a36Sopenharmony_ci opts->auxtrace_mmap_pages = KiB(128) / page_size; 15862306a36Sopenharmony_ci if (opts->mmap_pages == UINT_MAX) 15962306a36Sopenharmony_ci opts->mmap_pages = KiB(256) / page_size; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci } else if (!opts->auxtrace_mmap_pages && !privileged && 16262306a36Sopenharmony_ci opts->mmap_pages == UINT_MAX) { 16362306a36Sopenharmony_ci opts->mmap_pages = KiB(256) / page_size; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci if (!opts->auxtrace_snapshot_size) 16662306a36Sopenharmony_ci opts->auxtrace_snapshot_size = 16762306a36Sopenharmony_ci opts->auxtrace_mmap_pages * (size_t)page_size; 16862306a36Sopenharmony_ci if (!opts->auxtrace_mmap_pages) { 16962306a36Sopenharmony_ci size_t sz = opts->auxtrace_snapshot_size; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci sz = round_up(sz, page_size) / page_size; 17262306a36Sopenharmony_ci opts->auxtrace_mmap_pages = roundup_pow_of_two(sz); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci if (opts->auxtrace_snapshot_size > 17562306a36Sopenharmony_ci opts->auxtrace_mmap_pages * (size_t)page_size) { 17662306a36Sopenharmony_ci pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n", 17762306a36Sopenharmony_ci opts->auxtrace_snapshot_size, 17862306a36Sopenharmony_ci opts->auxtrace_mmap_pages * (size_t)page_size); 17962306a36Sopenharmony_ci return -EINVAL; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci if (!opts->auxtrace_snapshot_size || !opts->auxtrace_mmap_pages) { 18262306a36Sopenharmony_ci pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n"); 18362306a36Sopenharmony_ci return -EINVAL; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci pr_debug2("Intel BTS snapshot size: %zu\n", 18662306a36Sopenharmony_ci opts->auxtrace_snapshot_size); 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* Set default sizes for full trace mode */ 19062306a36Sopenharmony_ci if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) { 19162306a36Sopenharmony_ci if (privileged) { 19262306a36Sopenharmony_ci opts->auxtrace_mmap_pages = MiB(4) / page_size; 19362306a36Sopenharmony_ci } else { 19462306a36Sopenharmony_ci opts->auxtrace_mmap_pages = KiB(128) / page_size; 19562306a36Sopenharmony_ci if (opts->mmap_pages == UINT_MAX) 19662306a36Sopenharmony_ci opts->mmap_pages = KiB(256) / page_size; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* Validate auxtrace_mmap_pages */ 20162306a36Sopenharmony_ci if (opts->auxtrace_mmap_pages) { 20262306a36Sopenharmony_ci size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size; 20362306a36Sopenharmony_ci size_t min_sz; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (opts->auxtrace_snapshot_mode) 20662306a36Sopenharmony_ci min_sz = KiB(4); 20762306a36Sopenharmony_ci else 20862306a36Sopenharmony_ci min_sz = KiB(8); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (sz < min_sz || !is_power_of_2(sz)) { 21162306a36Sopenharmony_ci pr_err("Invalid mmap size for Intel BTS: must be at least %zuKiB and a power of 2\n", 21262306a36Sopenharmony_ci min_sz / 1024); 21362306a36Sopenharmony_ci return -EINVAL; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (intel_bts_evsel) { 21862306a36Sopenharmony_ci /* 21962306a36Sopenharmony_ci * To obtain the auxtrace buffer file descriptor, the auxtrace event 22062306a36Sopenharmony_ci * must come first. 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ci evlist__to_front(evlist, intel_bts_evsel); 22362306a36Sopenharmony_ci /* 22462306a36Sopenharmony_ci * In the case of per-cpu mmaps, we need the CPU on the 22562306a36Sopenharmony_ci * AUX event. 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_ci if (!perf_cpu_map__empty(cpus)) 22862306a36Sopenharmony_ci evsel__set_sample_bit(intel_bts_evsel, CPU); 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci /* Add dummy event to keep tracking */ 23262306a36Sopenharmony_ci if (opts->full_auxtrace) { 23362306a36Sopenharmony_ci struct evsel *tracking_evsel; 23462306a36Sopenharmony_ci int err; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci err = parse_event(evlist, "dummy:u"); 23762306a36Sopenharmony_ci if (err) 23862306a36Sopenharmony_ci return err; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci tracking_evsel = evlist__last(evlist); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci evlist__set_tracking_event(evlist, tracking_evsel); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci tracking_evsel->core.attr.freq = 0; 24562306a36Sopenharmony_ci tracking_evsel->core.attr.sample_period = 1; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic int intel_bts_parse_snapshot_options(struct auxtrace_record *itr, 25262306a36Sopenharmony_ci struct record_opts *opts, 25362306a36Sopenharmony_ci const char *str) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct intel_bts_recording *btsr = 25662306a36Sopenharmony_ci container_of(itr, struct intel_bts_recording, itr); 25762306a36Sopenharmony_ci unsigned long long snapshot_size = 0; 25862306a36Sopenharmony_ci char *endptr; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (str) { 26162306a36Sopenharmony_ci snapshot_size = strtoull(str, &endptr, 0); 26262306a36Sopenharmony_ci if (*endptr || snapshot_size > SIZE_MAX) 26362306a36Sopenharmony_ci return -1; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci opts->auxtrace_snapshot_mode = true; 26762306a36Sopenharmony_ci opts->auxtrace_snapshot_size = snapshot_size; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci btsr->snapshot_size = snapshot_size; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci return 0; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic u64 intel_bts_reference(struct auxtrace_record *itr __maybe_unused) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci return rdtsc(); 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic int intel_bts_alloc_snapshot_refs(struct intel_bts_recording *btsr, 28062306a36Sopenharmony_ci int idx) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci const size_t sz = sizeof(struct intel_bts_snapshot_ref); 28362306a36Sopenharmony_ci int cnt = btsr->snapshot_ref_cnt, new_cnt = cnt * 2; 28462306a36Sopenharmony_ci struct intel_bts_snapshot_ref *refs; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (!new_cnt) 28762306a36Sopenharmony_ci new_cnt = 16; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci while (new_cnt <= idx) 29062306a36Sopenharmony_ci new_cnt *= 2; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci refs = calloc(new_cnt, sz); 29362306a36Sopenharmony_ci if (!refs) 29462306a36Sopenharmony_ci return -ENOMEM; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci memcpy(refs, btsr->snapshot_refs, cnt * sz); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci btsr->snapshot_refs = refs; 29962306a36Sopenharmony_ci btsr->snapshot_ref_cnt = new_cnt; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci return 0; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic void intel_bts_free_snapshot_refs(struct intel_bts_recording *btsr) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci int i; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci for (i = 0; i < btsr->snapshot_ref_cnt; i++) 30962306a36Sopenharmony_ci zfree(&btsr->snapshot_refs[i].ref_buf); 31062306a36Sopenharmony_ci zfree(&btsr->snapshot_refs); 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic void intel_bts_recording_free(struct auxtrace_record *itr) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci struct intel_bts_recording *btsr = 31662306a36Sopenharmony_ci container_of(itr, struct intel_bts_recording, itr); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci intel_bts_free_snapshot_refs(btsr); 31962306a36Sopenharmony_ci free(btsr); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic int intel_bts_snapshot_start(struct auxtrace_record *itr) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct intel_bts_recording *btsr = 32562306a36Sopenharmony_ci container_of(itr, struct intel_bts_recording, itr); 32662306a36Sopenharmony_ci struct evsel *evsel; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci evlist__for_each_entry(btsr->evlist, evsel) { 32962306a36Sopenharmony_ci if (evsel->core.attr.type == btsr->intel_bts_pmu->type) 33062306a36Sopenharmony_ci return evsel__disable(evsel); 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci return -EINVAL; 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int intel_bts_snapshot_finish(struct auxtrace_record *itr) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci struct intel_bts_recording *btsr = 33862306a36Sopenharmony_ci container_of(itr, struct intel_bts_recording, itr); 33962306a36Sopenharmony_ci struct evsel *evsel; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci evlist__for_each_entry(btsr->evlist, evsel) { 34262306a36Sopenharmony_ci if (evsel->core.attr.type == btsr->intel_bts_pmu->type) 34362306a36Sopenharmony_ci return evsel__enable(evsel); 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci return -EINVAL; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic bool intel_bts_first_wrap(u64 *data, size_t buf_size) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci int i, a, b; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci b = buf_size >> 3; 35362306a36Sopenharmony_ci a = b - 512; 35462306a36Sopenharmony_ci if (a < 0) 35562306a36Sopenharmony_ci a = 0; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci for (i = a; i < b; i++) { 35862306a36Sopenharmony_ci if (data[i]) 35962306a36Sopenharmony_ci return true; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci return false; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic int intel_bts_find_snapshot(struct auxtrace_record *itr, int idx, 36662306a36Sopenharmony_ci struct auxtrace_mmap *mm, unsigned char *data, 36762306a36Sopenharmony_ci u64 *head, u64 *old) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci struct intel_bts_recording *btsr = 37062306a36Sopenharmony_ci container_of(itr, struct intel_bts_recording, itr); 37162306a36Sopenharmony_ci bool wrapped; 37262306a36Sopenharmony_ci int err; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci pr_debug3("%s: mmap index %d old head %zu new head %zu\n", 37562306a36Sopenharmony_ci __func__, idx, (size_t)*old, (size_t)*head); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (idx >= btsr->snapshot_ref_cnt) { 37862306a36Sopenharmony_ci err = intel_bts_alloc_snapshot_refs(btsr, idx); 37962306a36Sopenharmony_ci if (err) 38062306a36Sopenharmony_ci goto out_err; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci wrapped = btsr->snapshot_refs[idx].wrapped; 38462306a36Sopenharmony_ci if (!wrapped && intel_bts_first_wrap((u64 *)data, mm->len)) { 38562306a36Sopenharmony_ci btsr->snapshot_refs[idx].wrapped = true; 38662306a36Sopenharmony_ci wrapped = true; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* 39062306a36Sopenharmony_ci * In full trace mode 'head' continually increases. However in snapshot 39162306a36Sopenharmony_ci * mode 'head' is an offset within the buffer. Here 'old' and 'head' 39262306a36Sopenharmony_ci * are adjusted to match the full trace case which expects that 'old' is 39362306a36Sopenharmony_ci * always less than 'head'. 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_ci if (wrapped) { 39662306a36Sopenharmony_ci *old = *head; 39762306a36Sopenharmony_ci *head += mm->len; 39862306a36Sopenharmony_ci } else { 39962306a36Sopenharmony_ci if (mm->mask) 40062306a36Sopenharmony_ci *old &= mm->mask; 40162306a36Sopenharmony_ci else 40262306a36Sopenharmony_ci *old %= mm->len; 40362306a36Sopenharmony_ci if (*old > *head) 40462306a36Sopenharmony_ci *head += mm->len; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci pr_debug3("%s: wrap-around %sdetected, adjusted old head %zu adjusted new head %zu\n", 40862306a36Sopenharmony_ci __func__, wrapped ? "" : "not ", (size_t)*old, (size_t)*head); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci return 0; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ciout_err: 41362306a36Sopenharmony_ci pr_err("%s: failed, error %d\n", __func__, err); 41462306a36Sopenharmony_ci return err; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistruct auxtrace_record *intel_bts_recording_init(int *err) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci struct perf_pmu *intel_bts_pmu = perf_pmus__find(INTEL_BTS_PMU_NAME); 42062306a36Sopenharmony_ci struct intel_bts_recording *btsr; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (!intel_bts_pmu) 42362306a36Sopenharmony_ci return NULL; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (setenv("JITDUMP_USE_ARCH_TIMESTAMP", "1", 1)) { 42662306a36Sopenharmony_ci *err = -errno; 42762306a36Sopenharmony_ci return NULL; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci btsr = zalloc(sizeof(struct intel_bts_recording)); 43162306a36Sopenharmony_ci if (!btsr) { 43262306a36Sopenharmony_ci *err = -ENOMEM; 43362306a36Sopenharmony_ci return NULL; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci btsr->intel_bts_pmu = intel_bts_pmu; 43762306a36Sopenharmony_ci btsr->itr.pmu = intel_bts_pmu; 43862306a36Sopenharmony_ci btsr->itr.recording_options = intel_bts_recording_options; 43962306a36Sopenharmony_ci btsr->itr.info_priv_size = intel_bts_info_priv_size; 44062306a36Sopenharmony_ci btsr->itr.info_fill = intel_bts_info_fill; 44162306a36Sopenharmony_ci btsr->itr.free = intel_bts_recording_free; 44262306a36Sopenharmony_ci btsr->itr.snapshot_start = intel_bts_snapshot_start; 44362306a36Sopenharmony_ci btsr->itr.snapshot_finish = intel_bts_snapshot_finish; 44462306a36Sopenharmony_ci btsr->itr.find_snapshot = intel_bts_find_snapshot; 44562306a36Sopenharmony_ci btsr->itr.parse_snapshot_options = intel_bts_parse_snapshot_options; 44662306a36Sopenharmony_ci btsr->itr.reference = intel_bts_reference; 44762306a36Sopenharmony_ci btsr->itr.read_finish = auxtrace_record__read_finish; 44862306a36Sopenharmony_ci btsr->itr.alignment = sizeof(struct branch); 44962306a36Sopenharmony_ci return &btsr->itr; 45062306a36Sopenharmony_ci} 451