perf/x86/intel: Support the PEBS event mask
BugLink: https://bugs.launchpad.net/bugs/2083656 [ Upstream commit a23eb2fc1d818cdac9b31f032842d55483a6a040 ] The current perf assumes that the counters that support PEBS are contiguous. But it's not guaranteed with the new leaf 0x23 introduced. The counters are enumerated with a counter mask. There may be holes in the counter mask for future platforms or in a virtualization environment. Store the PEBS event mask rather than the maximum number of PEBS counters in the x86 PMU structures. Signed-off-by: Kan Liang <kan.liang@linux.intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Andi Kleen <ak@linux.intel.com> Reviewed-by: Ian Rogers <irogers@google.com> Link: https://lkml.kernel.org/r/20240626143545.480761-2-kan.liang@linux.intel.com Stable-dep-of: f73cefa3b72e ("perf/x86: Fix smp_processor_id()-in-preemptible warnings") Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Koichiro Den <koichiro.den@canonical.com> Signed-off-by: Roxana Nicolescu <roxana.nicolescu@canonical.com>
This commit is contained in:
committed by
Mehmet Basaran
parent
d56dc68ced
commit
178bbb4244
@@ -4727,7 +4727,7 @@ static void intel_pmu_check_hybrid_pmus(struct x86_hybrid_pmu *pmu)
|
||||
{
|
||||
intel_pmu_check_num_counters(&pmu->num_counters, &pmu->num_counters_fixed,
|
||||
&pmu->intel_ctrl, (1ULL << pmu->num_counters_fixed) - 1);
|
||||
pmu->max_pebs_events = min_t(unsigned, MAX_PEBS_EVENTS, pmu->num_counters);
|
||||
pmu->pebs_events_mask = intel_pmu_pebs_mask(GENMASK_ULL(pmu->num_counters - 1, 0));
|
||||
pmu->unconstrained = (struct event_constraint)
|
||||
__EVENT_CONSTRAINT(0, (1ULL << pmu->num_counters) - 1,
|
||||
0, pmu->num_counters, 0, 0);
|
||||
@@ -6076,7 +6076,7 @@ static __always_inline int intel_pmu_init_hybrid(enum hybrid_pmu_type pmus)
|
||||
|
||||
pmu->num_counters = x86_pmu.num_counters;
|
||||
pmu->num_counters_fixed = x86_pmu.num_counters_fixed;
|
||||
pmu->max_pebs_events = min_t(unsigned, MAX_PEBS_EVENTS, pmu->num_counters);
|
||||
pmu->pebs_events_mask = intel_pmu_pebs_mask(GENMASK_ULL(pmu->num_counters - 1, 0));
|
||||
pmu->unconstrained = (struct event_constraint)
|
||||
__EVENT_CONSTRAINT(0, (1ULL << pmu->num_counters) - 1,
|
||||
0, pmu->num_counters, 0, 0);
|
||||
@@ -6199,7 +6199,7 @@ __init int intel_pmu_init(void)
|
||||
x86_pmu.events_maskl = ebx.full;
|
||||
x86_pmu.events_mask_len = eax.split.mask_length;
|
||||
|
||||
x86_pmu.max_pebs_events = min_t(unsigned, MAX_PEBS_EVENTS, x86_pmu.num_counters);
|
||||
x86_pmu.pebs_events_mask = intel_pmu_pebs_mask(GENMASK_ULL(x86_pmu.num_counters - 1, 0));
|
||||
x86_pmu.pebs_capable = PEBS_COUNTER_MASK;
|
||||
|
||||
/*
|
||||
@@ -6832,7 +6832,7 @@ __init int intel_pmu_init(void)
|
||||
pmu->num_counters_fixed = x86_pmu.num_counters_fixed;
|
||||
}
|
||||
|
||||
pmu->max_pebs_events = min_t(unsigned, MAX_PEBS_EVENTS, pmu->num_counters);
|
||||
pmu->pebs_events_mask = intel_pmu_pebs_mask(GENMASK_ULL(pmu->num_counters - 1, 0));
|
||||
pmu->unconstrained = (struct event_constraint)
|
||||
__EVENT_CONSTRAINT(0, (1ULL << pmu->num_counters) - 1,
|
||||
0, pmu->num_counters, 0, 0);
|
||||
|
||||
@@ -1136,7 +1136,7 @@ void intel_pmu_pebs_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sche
|
||||
static inline void pebs_update_threshold(struct cpu_hw_events *cpuc)
|
||||
{
|
||||
struct debug_store *ds = cpuc->ds;
|
||||
int max_pebs_events = hybrid(cpuc->pmu, max_pebs_events);
|
||||
int max_pebs_events = intel_pmu_max_num_pebs(cpuc->pmu);
|
||||
int num_counters_fixed = hybrid(cpuc->pmu, num_counters_fixed);
|
||||
u64 threshold;
|
||||
int reserved;
|
||||
@@ -2160,6 +2160,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs, struct perf_sample_d
|
||||
void *base, *at, *top;
|
||||
short counts[INTEL_PMC_IDX_FIXED + MAX_FIXED_PEBS_EVENTS] = {};
|
||||
short error[INTEL_PMC_IDX_FIXED + MAX_FIXED_PEBS_EVENTS] = {};
|
||||
int max_pebs_events = intel_pmu_max_num_pebs(NULL);
|
||||
int bit, i, size;
|
||||
u64 mask;
|
||||
|
||||
@@ -2171,8 +2172,8 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs, struct perf_sample_d
|
||||
|
||||
ds->pebs_index = ds->pebs_buffer_base;
|
||||
|
||||
mask = (1ULL << x86_pmu.max_pebs_events) - 1;
|
||||
size = x86_pmu.max_pebs_events;
|
||||
mask = x86_pmu.pebs_events_mask;
|
||||
size = max_pebs_events;
|
||||
if (x86_pmu.flags & PMU_FL_PEBS_ALL) {
|
||||
mask |= ((1ULL << x86_pmu.num_counters_fixed) - 1) << INTEL_PMC_IDX_FIXED;
|
||||
size = INTEL_PMC_IDX_FIXED + x86_pmu.num_counters_fixed;
|
||||
@@ -2211,8 +2212,9 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs, struct perf_sample_d
|
||||
pebs_status = p->status = cpuc->pebs_enabled;
|
||||
|
||||
bit = find_first_bit((unsigned long *)&pebs_status,
|
||||
x86_pmu.max_pebs_events);
|
||||
if (bit >= x86_pmu.max_pebs_events)
|
||||
max_pebs_events);
|
||||
|
||||
if (!(x86_pmu.pebs_events_mask & (1 << bit)))
|
||||
continue;
|
||||
|
||||
/*
|
||||
@@ -2270,7 +2272,6 @@ static void intel_pmu_drain_pebs_icl(struct pt_regs *iregs, struct perf_sample_d
|
||||
{
|
||||
short counts[INTEL_PMC_IDX_FIXED + MAX_FIXED_PEBS_EVENTS] = {};
|
||||
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
|
||||
int max_pebs_events = hybrid(cpuc->pmu, max_pebs_events);
|
||||
int num_counters_fixed = hybrid(cpuc->pmu, num_counters_fixed);
|
||||
struct debug_store *ds = cpuc->ds;
|
||||
struct perf_event *event;
|
||||
@@ -2286,7 +2287,7 @@ static void intel_pmu_drain_pebs_icl(struct pt_regs *iregs, struct perf_sample_d
|
||||
|
||||
ds->pebs_index = ds->pebs_buffer_base;
|
||||
|
||||
mask = ((1ULL << max_pebs_events) - 1) |
|
||||
mask = hybrid(cpuc->pmu, pebs_events_mask) |
|
||||
(((1ULL << num_counters_fixed) - 1) << INTEL_PMC_IDX_FIXED);
|
||||
size = INTEL_PMC_IDX_FIXED + num_counters_fixed;
|
||||
|
||||
|
||||
@@ -684,7 +684,7 @@ struct x86_hybrid_pmu {
|
||||
cpumask_t supported_cpus;
|
||||
union perf_capabilities intel_cap;
|
||||
u64 intel_ctrl;
|
||||
int max_pebs_events;
|
||||
u64 pebs_events_mask;
|
||||
int num_counters;
|
||||
int num_counters_fixed;
|
||||
struct event_constraint unconstrained;
|
||||
@@ -852,7 +852,7 @@ struct x86_pmu {
|
||||
pebs_ept :1;
|
||||
int pebs_record_size;
|
||||
int pebs_buffer_size;
|
||||
int max_pebs_events;
|
||||
u64 pebs_events_mask;
|
||||
void (*drain_pebs)(struct pt_regs *regs, struct perf_sample_data *data);
|
||||
struct event_constraint *pebs_constraints;
|
||||
void (*pebs_aliases)(struct perf_event *event);
|
||||
@@ -1648,6 +1648,17 @@ static inline int is_ht_workaround_enabled(void)
|
||||
return !!(x86_pmu.flags & PMU_FL_EXCL_ENABLED);
|
||||
}
|
||||
|
||||
static inline u64 intel_pmu_pebs_mask(u64 cntr_mask)
|
||||
{
|
||||
return MAX_PEBS_EVENTS_MASK & cntr_mask;
|
||||
}
|
||||
|
||||
static inline int intel_pmu_max_num_pebs(struct pmu *pmu)
|
||||
{
|
||||
static_assert(MAX_PEBS_EVENTS == 32);
|
||||
return fls((u32)hybrid(pmu, pebs_events_mask));
|
||||
}
|
||||
|
||||
#else /* CONFIG_CPU_SUP_INTEL */
|
||||
|
||||
static inline void reserve_ds_buffers(void)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
/* The maximal number of PEBS events: */
|
||||
#define MAX_PEBS_EVENTS_FMT4 8
|
||||
#define MAX_PEBS_EVENTS 32
|
||||
#define MAX_PEBS_EVENTS_MASK GENMASK_ULL(MAX_PEBS_EVENTS - 1, 0)
|
||||
#define MAX_FIXED_PEBS_EVENTS 16
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user