| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * intel-bts.c: Intel Processor Trace support |
|---|
| 3 | 4 | * Copyright (c) 2013-2015, Intel Corporation. |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 6 | | - * under the terms and conditions of the GNU General Public License, |
|---|
| 7 | | - * version 2, as published by the Free Software Foundation. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
|---|
| 10 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 11 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 12 | | - * more details. |
|---|
| 13 | | - * |
|---|
| 14 | 5 | */ |
|---|
| 15 | 6 | |
|---|
| 16 | 7 | #include <errno.h> |
|---|
| .. | .. |
|---|
| 18 | 9 | #include <linux/types.h> |
|---|
| 19 | 10 | #include <linux/bitops.h> |
|---|
| 20 | 11 | #include <linux/log2.h> |
|---|
| 12 | +#include <linux/zalloc.h> |
|---|
| 21 | 13 | |
|---|
| 22 | | -#include "../../util/cpumap.h" |
|---|
| 23 | | -#include "../../util/evsel.h" |
|---|
| 24 | | -#include "../../util/evlist.h" |
|---|
| 25 | | -#include "../../util/session.h" |
|---|
| 26 | | -#include "../../util/util.h" |
|---|
| 27 | | -#include "../../util/pmu.h" |
|---|
| 28 | | -#include "../../util/debug.h" |
|---|
| 29 | | -#include "../../util/tsc.h" |
|---|
| 30 | | -#include "../../util/auxtrace.h" |
|---|
| 31 | | -#include "../../util/intel-bts.h" |
|---|
| 14 | +#include "../../../util/cpumap.h" |
|---|
| 15 | +#include "../../../util/event.h" |
|---|
| 16 | +#include "../../../util/evsel.h" |
|---|
| 17 | +#include "../../../util/evlist.h" |
|---|
| 18 | +#include "../../../util/mmap.h" |
|---|
| 19 | +#include "../../../util/session.h" |
|---|
| 20 | +#include "../../../util/pmu.h" |
|---|
| 21 | +#include "../../../util/debug.h" |
|---|
| 22 | +#include "../../../util/record.h" |
|---|
| 23 | +#include "../../../util/tsc.h" |
|---|
| 24 | +#include "../../../util/auxtrace.h" |
|---|
| 25 | +#include "../../../util/intel-bts.h" |
|---|
| 26 | +#include <internal/lib.h> // page_size |
|---|
| 32 | 27 | |
|---|
| 33 | 28 | #define KiB(x) ((x) * 1024) |
|---|
| 34 | 29 | #define MiB(x) ((x) * 1024 * 1024) |
|---|
| .. | .. |
|---|
| 44 | 39 | struct intel_bts_recording { |
|---|
| 45 | 40 | struct auxtrace_record itr; |
|---|
| 46 | 41 | struct perf_pmu *intel_bts_pmu; |
|---|
| 47 | | - struct perf_evlist *evlist; |
|---|
| 42 | + struct evlist *evlist; |
|---|
| 48 | 43 | bool snapshot_mode; |
|---|
| 49 | 44 | size_t snapshot_size; |
|---|
| 50 | 45 | int snapshot_ref_cnt; |
|---|
| .. | .. |
|---|
| 59 | 54 | |
|---|
| 60 | 55 | static size_t |
|---|
| 61 | 56 | intel_bts_info_priv_size(struct auxtrace_record *itr __maybe_unused, |
|---|
| 62 | | - struct perf_evlist *evlist __maybe_unused) |
|---|
| 57 | + struct evlist *evlist __maybe_unused) |
|---|
| 63 | 58 | { |
|---|
| 64 | 59 | return INTEL_BTS_AUXTRACE_PRIV_SIZE; |
|---|
| 65 | 60 | } |
|---|
| 66 | 61 | |
|---|
| 67 | 62 | static int intel_bts_info_fill(struct auxtrace_record *itr, |
|---|
| 68 | 63 | struct perf_session *session, |
|---|
| 69 | | - struct auxtrace_info_event *auxtrace_info, |
|---|
| 64 | + struct perf_record_auxtrace_info *auxtrace_info, |
|---|
| 70 | 65 | size_t priv_size) |
|---|
| 71 | 66 | { |
|---|
| 72 | 67 | struct intel_bts_recording *btsr = |
|---|
| .. | .. |
|---|
| 80 | 75 | if (priv_size != INTEL_BTS_AUXTRACE_PRIV_SIZE) |
|---|
| 81 | 76 | return -EINVAL; |
|---|
| 82 | 77 | |
|---|
| 83 | | - if (!session->evlist->nr_mmaps) |
|---|
| 78 | + if (!session->evlist->core.nr_mmaps) |
|---|
| 84 | 79 | return -EINVAL; |
|---|
| 85 | 80 | |
|---|
| 86 | | - pc = session->evlist->mmap[0].base; |
|---|
| 81 | + pc = session->evlist->mmap[0].core.base; |
|---|
| 87 | 82 | if (pc) { |
|---|
| 88 | 83 | err = perf_read_tsc_conversion(pc, &tc); |
|---|
| 89 | 84 | if (err) { |
|---|
| .. | .. |
|---|
| 108 | 103 | } |
|---|
| 109 | 104 | |
|---|
| 110 | 105 | static int intel_bts_recording_options(struct auxtrace_record *itr, |
|---|
| 111 | | - struct perf_evlist *evlist, |
|---|
| 106 | + struct evlist *evlist, |
|---|
| 112 | 107 | struct record_opts *opts) |
|---|
| 113 | 108 | { |
|---|
| 114 | 109 | struct intel_bts_recording *btsr = |
|---|
| 115 | 110 | container_of(itr, struct intel_bts_recording, itr); |
|---|
| 116 | 111 | struct perf_pmu *intel_bts_pmu = btsr->intel_bts_pmu; |
|---|
| 117 | | - struct perf_evsel *evsel, *intel_bts_evsel = NULL; |
|---|
| 118 | | - const struct cpu_map *cpus = evlist->cpus; |
|---|
| 119 | | - bool privileged = geteuid() == 0 || perf_event_paranoid() < 0; |
|---|
| 112 | + struct evsel *evsel, *intel_bts_evsel = NULL; |
|---|
| 113 | + const struct perf_cpu_map *cpus = evlist->core.cpus; |
|---|
| 114 | + bool privileged = perf_event_paranoid_check(-1); |
|---|
| 115 | + |
|---|
| 116 | + if (opts->auxtrace_sample_mode) { |
|---|
| 117 | + pr_err("Intel BTS does not support AUX area sampling\n"); |
|---|
| 118 | + return -EINVAL; |
|---|
| 119 | + } |
|---|
| 120 | 120 | |
|---|
| 121 | 121 | btsr->evlist = evlist; |
|---|
| 122 | 122 | btsr->snapshot_mode = opts->auxtrace_snapshot_mode; |
|---|
| 123 | 123 | |
|---|
| 124 | 124 | evlist__for_each_entry(evlist, evsel) { |
|---|
| 125 | | - if (evsel->attr.type == intel_bts_pmu->type) { |
|---|
| 125 | + if (evsel->core.attr.type == intel_bts_pmu->type) { |
|---|
| 126 | 126 | if (intel_bts_evsel) { |
|---|
| 127 | 127 | pr_err("There may be only one " INTEL_BTS_PMU_NAME " event\n"); |
|---|
| 128 | 128 | return -EINVAL; |
|---|
| 129 | 129 | } |
|---|
| 130 | | - evsel->attr.freq = 0; |
|---|
| 131 | | - evsel->attr.sample_period = 1; |
|---|
| 130 | + evsel->core.attr.freq = 0; |
|---|
| 131 | + evsel->core.attr.sample_period = 1; |
|---|
| 132 | 132 | intel_bts_evsel = evsel; |
|---|
| 133 | 133 | opts->full_auxtrace = true; |
|---|
| 134 | 134 | } |
|---|
| .. | .. |
|---|
| 142 | 142 | if (!opts->full_auxtrace) |
|---|
| 143 | 143 | return 0; |
|---|
| 144 | 144 | |
|---|
| 145 | | - if (opts->full_auxtrace && !cpu_map__empty(cpus)) { |
|---|
| 145 | + if (opts->full_auxtrace && !perf_cpu_map__empty(cpus)) { |
|---|
| 146 | 146 | pr_err(INTEL_BTS_PMU_NAME " does not support per-cpu recording\n"); |
|---|
| 147 | 147 | return -EINVAL; |
|---|
| 148 | 148 | } |
|---|
| .. | .. |
|---|
| 223 | 223 | * In the case of per-cpu mmaps, we need the CPU on the |
|---|
| 224 | 224 | * AUX event. |
|---|
| 225 | 225 | */ |
|---|
| 226 | | - if (!cpu_map__empty(cpus)) |
|---|
| 227 | | - perf_evsel__set_sample_bit(intel_bts_evsel, CPU); |
|---|
| 226 | + if (!perf_cpu_map__empty(cpus)) |
|---|
| 227 | + evsel__set_sample_bit(intel_bts_evsel, CPU); |
|---|
| 228 | 228 | } |
|---|
| 229 | 229 | |
|---|
| 230 | 230 | /* Add dummy event to keep tracking */ |
|---|
| 231 | 231 | if (opts->full_auxtrace) { |
|---|
| 232 | | - struct perf_evsel *tracking_evsel; |
|---|
| 232 | + struct evsel *tracking_evsel; |
|---|
| 233 | 233 | int err; |
|---|
| 234 | 234 | |
|---|
| 235 | 235 | err = parse_events(evlist, "dummy:u", NULL); |
|---|
| 236 | 236 | if (err) |
|---|
| 237 | 237 | return err; |
|---|
| 238 | 238 | |
|---|
| 239 | | - tracking_evsel = perf_evlist__last(evlist); |
|---|
| 239 | + tracking_evsel = evlist__last(evlist); |
|---|
| 240 | 240 | |
|---|
| 241 | 241 | perf_evlist__set_tracking_event(evlist, tracking_evsel); |
|---|
| 242 | 242 | |
|---|
| 243 | | - tracking_evsel->attr.freq = 0; |
|---|
| 244 | | - tracking_evsel->attr.sample_period = 1; |
|---|
| 243 | + tracking_evsel->core.attr.freq = 0; |
|---|
| 244 | + tracking_evsel->core.attr.sample_period = 1; |
|---|
| 245 | 245 | } |
|---|
| 246 | 246 | |
|---|
| 247 | 247 | return 0; |
|---|
| .. | .. |
|---|
| 322 | 322 | { |
|---|
| 323 | 323 | struct intel_bts_recording *btsr = |
|---|
| 324 | 324 | container_of(itr, struct intel_bts_recording, itr); |
|---|
| 325 | | - struct perf_evsel *evsel; |
|---|
| 325 | + struct evsel *evsel; |
|---|
| 326 | 326 | |
|---|
| 327 | 327 | evlist__for_each_entry(btsr->evlist, evsel) { |
|---|
| 328 | | - if (evsel->attr.type == btsr->intel_bts_pmu->type) |
|---|
| 329 | | - return perf_evsel__disable(evsel); |
|---|
| 328 | + if (evsel->core.attr.type == btsr->intel_bts_pmu->type) |
|---|
| 329 | + return evsel__disable(evsel); |
|---|
| 330 | 330 | } |
|---|
| 331 | 331 | return -EINVAL; |
|---|
| 332 | 332 | } |
|---|
| .. | .. |
|---|
| 335 | 335 | { |
|---|
| 336 | 336 | struct intel_bts_recording *btsr = |
|---|
| 337 | 337 | container_of(itr, struct intel_bts_recording, itr); |
|---|
| 338 | | - struct perf_evsel *evsel; |
|---|
| 338 | + struct evsel *evsel; |
|---|
| 339 | 339 | |
|---|
| 340 | 340 | evlist__for_each_entry(btsr->evlist, evsel) { |
|---|
| 341 | | - if (evsel->attr.type == btsr->intel_bts_pmu->type) |
|---|
| 342 | | - return perf_evsel__enable(evsel); |
|---|
| 341 | + if (evsel->core.attr.type == btsr->intel_bts_pmu->type) |
|---|
| 342 | + return evsel__enable(evsel); |
|---|
| 343 | 343 | } |
|---|
| 344 | 344 | return -EINVAL; |
|---|
| 345 | 345 | } |
|---|
| .. | .. |
|---|
| 413 | 413 | return err; |
|---|
| 414 | 414 | } |
|---|
| 415 | 415 | |
|---|
| 416 | | -static int intel_bts_read_finish(struct auxtrace_record *itr, int idx) |
|---|
| 417 | | -{ |
|---|
| 418 | | - struct intel_bts_recording *btsr = |
|---|
| 419 | | - container_of(itr, struct intel_bts_recording, itr); |
|---|
| 420 | | - struct perf_evsel *evsel; |
|---|
| 421 | | - |
|---|
| 422 | | - evlist__for_each_entry(btsr->evlist, evsel) { |
|---|
| 423 | | - if (evsel->attr.type == btsr->intel_bts_pmu->type) |
|---|
| 424 | | - return perf_evlist__enable_event_idx(btsr->evlist, |
|---|
| 425 | | - evsel, idx); |
|---|
| 426 | | - } |
|---|
| 427 | | - return -EINVAL; |
|---|
| 428 | | -} |
|---|
| 429 | | - |
|---|
| 430 | 416 | struct auxtrace_record *intel_bts_recording_init(int *err) |
|---|
| 431 | 417 | { |
|---|
| 432 | 418 | struct perf_pmu *intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME); |
|---|
| .. | .. |
|---|
| 447 | 433 | } |
|---|
| 448 | 434 | |
|---|
| 449 | 435 | btsr->intel_bts_pmu = intel_bts_pmu; |
|---|
| 436 | + btsr->itr.pmu = intel_bts_pmu; |
|---|
| 450 | 437 | btsr->itr.recording_options = intel_bts_recording_options; |
|---|
| 451 | 438 | btsr->itr.info_priv_size = intel_bts_info_priv_size; |
|---|
| 452 | 439 | btsr->itr.info_fill = intel_bts_info_fill; |
|---|
| .. | .. |
|---|
| 456 | 443 | btsr->itr.find_snapshot = intel_bts_find_snapshot; |
|---|
| 457 | 444 | btsr->itr.parse_snapshot_options = intel_bts_parse_snapshot_options; |
|---|
| 458 | 445 | btsr->itr.reference = intel_bts_reference; |
|---|
| 459 | | - btsr->itr.read_finish = intel_bts_read_finish; |
|---|
| 446 | + btsr->itr.read_finish = auxtrace_record__read_finish; |
|---|
| 460 | 447 | btsr->itr.alignment = sizeof(struct branch); |
|---|
| 461 | 448 | return &btsr->itr; |
|---|
| 462 | 449 | } |
|---|