Skip to content

Commit d4b294b

Browse files
Kan LiangPeter Zijlstra
Kan Liang
authored and
Peter Zijlstra
committed
perf/x86: Hybrid PMU support for counters
The number of GP and fixed counters are different among hybrid PMUs. Each hybrid PMU should use its own counter related information. When handling a certain hybrid PMU, apply the number of counters from the corresponding hybrid PMU. When reserving the counters in the initialization of a new event, reserve all possible counters. The number of counter recored in the global x86_pmu is for the architecture counters which are available for all hybrid PMUs. KVM doesn't support the hybrid PMU yet. Return the number of the architecture counters for now. For the functions only available for the old platforms, e.g., intel_pmu_drain_pebs_nhm(), nothing is changed. Signed-off-by: Kan Liang <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Andi Kleen <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent fc4b8fc commit d4b294b

File tree

4 files changed

+56
-25
lines changed

4 files changed

+56
-25
lines changed

arch/x86/events/core.c

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -185,16 +185,29 @@ static DEFINE_MUTEX(pmc_reserve_mutex);
185185

186186
#ifdef CONFIG_X86_LOCAL_APIC
187187

188+
static inline int get_possible_num_counters(void)
189+
{
190+
int i, num_counters = x86_pmu.num_counters;
191+
192+
if (!is_hybrid())
193+
return num_counters;
194+
195+
for (i = 0; i < x86_pmu.num_hybrid_pmus; i++)
196+
num_counters = max_t(int, num_counters, x86_pmu.hybrid_pmu[i].num_counters);
197+
198+
return num_counters;
199+
}
200+
188201
static bool reserve_pmc_hardware(void)
189202
{
190-
int i;
203+
int i, num_counters = get_possible_num_counters();
191204

192-
for (i = 0; i < x86_pmu.num_counters; i++) {
205+
for (i = 0; i < num_counters; i++) {
193206
if (!reserve_perfctr_nmi(x86_pmu_event_addr(i)))
194207
goto perfctr_fail;
195208
}
196209

197-
for (i = 0; i < x86_pmu.num_counters; i++) {
210+
for (i = 0; i < num_counters; i++) {
198211
if (!reserve_evntsel_nmi(x86_pmu_config_addr(i)))
199212
goto eventsel_fail;
200213
}
@@ -205,7 +218,7 @@ static bool reserve_pmc_hardware(void)
205218
for (i--; i >= 0; i--)
206219
release_evntsel_nmi(x86_pmu_config_addr(i));
207220

208-
i = x86_pmu.num_counters;
221+
i = num_counters;
209222

210223
perfctr_fail:
211224
for (i--; i >= 0; i--)
@@ -216,9 +229,9 @@ static bool reserve_pmc_hardware(void)
216229

217230
static void release_pmc_hardware(void)
218231
{
219-
int i;
232+
int i, num_counters = get_possible_num_counters();
220233

221-
for (i = 0; i < x86_pmu.num_counters; i++) {
234+
for (i = 0; i < num_counters; i++) {
222235
release_perfctr_nmi(x86_pmu_event_addr(i));
223236
release_evntsel_nmi(x86_pmu_config_addr(i));
224237
}
@@ -946,6 +959,7 @@ EXPORT_SYMBOL_GPL(perf_assign_events);
946959

947960
int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
948961
{
962+
int num_counters = hybrid(cpuc->pmu, num_counters);
949963
struct event_constraint *c;
950964
struct perf_event *e;
951965
int n0, i, wmin, wmax, unsched = 0;
@@ -1021,7 +1035,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
10211035

10221036
/* slow path */
10231037
if (i != n) {
1024-
int gpmax = x86_pmu.num_counters;
1038+
int gpmax = num_counters;
10251039

10261040
/*
10271041
* Do not allow scheduling of more than half the available
@@ -1042,7 +1056,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
10421056
* the extra Merge events needed by large increment events.
10431057
*/
10441058
if (x86_pmu.flags & PMU_FL_PAIR) {
1045-
gpmax = x86_pmu.num_counters - cpuc->n_pair;
1059+
gpmax = num_counters - cpuc->n_pair;
10461060
WARN_ON(gpmax <= 0);
10471061
}
10481062

@@ -1129,10 +1143,12 @@ static int collect_event(struct cpu_hw_events *cpuc, struct perf_event *event,
11291143
*/
11301144
static int collect_events(struct cpu_hw_events *cpuc, struct perf_event *leader, bool dogrp)
11311145
{
1146+
int num_counters = hybrid(cpuc->pmu, num_counters);
1147+
int num_counters_fixed = hybrid(cpuc->pmu, num_counters_fixed);
11321148
struct perf_event *event;
11331149
int n, max_count;
11341150

1135-
max_count = x86_pmu.num_counters + x86_pmu.num_counters_fixed;
1151+
max_count = num_counters + num_counters_fixed;
11361152

11371153
/* current number of events already accepted */
11381154
n = cpuc->n_events;
@@ -1499,18 +1515,18 @@ void perf_event_print_debug(void)
14991515
{
15001516
u64 ctrl, status, overflow, pmc_ctrl, pmc_count, prev_left, fixed;
15011517
u64 pebs, debugctl;
1502-
struct cpu_hw_events *cpuc;
1518+
int cpu = smp_processor_id();
1519+
struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
1520+
int num_counters = hybrid(cpuc->pmu, num_counters);
1521+
int num_counters_fixed = hybrid(cpuc->pmu, num_counters_fixed);
15031522
unsigned long flags;
1504-
int cpu, idx;
1523+
int idx;
15051524

1506-
if (!x86_pmu.num_counters)
1525+
if (!num_counters)
15071526
return;
15081527

15091528
local_irq_save(flags);
15101529

1511-
cpu = smp_processor_id();
1512-
cpuc = &per_cpu(cpu_hw_events, cpu);
1513-
15141530
if (x86_pmu.version >= 2) {
15151531
rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl);
15161532
rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status);
@@ -1533,7 +1549,7 @@ void perf_event_print_debug(void)
15331549
}
15341550
pr_info("CPU#%d: active: %016llx\n", cpu, *(u64 *)cpuc->active_mask);
15351551

1536-
for (idx = 0; idx < x86_pmu.num_counters; idx++) {
1552+
for (idx = 0; idx < num_counters; idx++) {
15371553
rdmsrl(x86_pmu_config_addr(idx), pmc_ctrl);
15381554
rdmsrl(x86_pmu_event_addr(idx), pmc_count);
15391555

@@ -1546,7 +1562,7 @@ void perf_event_print_debug(void)
15461562
pr_info("CPU#%d: gen-PMC%d left: %016llx\n",
15471563
cpu, idx, prev_left);
15481564
}
1549-
for (idx = 0; idx < x86_pmu.num_counters_fixed; idx++) {
1565+
for (idx = 0; idx < num_counters_fixed; idx++) {
15501566
if (fixed_counter_disabled(idx, cpuc->pmu))
15511567
continue;
15521568
rdmsrl(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, pmc_count);
@@ -2781,6 +2797,11 @@ unsigned long perf_misc_flags(struct pt_regs *regs)
27812797
void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap)
27822798
{
27832799
cap->version = x86_pmu.version;
2800+
/*
2801+
* KVM doesn't support the hybrid PMU yet.
2802+
* Return the common value in global x86_pmu,
2803+
* which available for all cores.
2804+
*/
27842805
cap->num_counters_gp = x86_pmu.num_counters;
27852806
cap->num_counters_fixed = x86_pmu.num_counters_fixed;
27862807
cap->bit_width_gp = x86_pmu.cntval_bits;

arch/x86/events/intel/core.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2711,21 +2711,23 @@ static void intel_pmu_reset(void)
27112711
{
27122712
struct debug_store *ds = __this_cpu_read(cpu_hw_events.ds);
27132713
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
2714+
int num_counters_fixed = hybrid(cpuc->pmu, num_counters_fixed);
2715+
int num_counters = hybrid(cpuc->pmu, num_counters);
27142716
unsigned long flags;
27152717
int idx;
27162718

2717-
if (!x86_pmu.num_counters)
2719+
if (!num_counters)
27182720
return;
27192721

27202722
local_irq_save(flags);
27212723

27222724
pr_info("clearing PMU state on CPU#%d\n", smp_processor_id());
27232725

2724-
for (idx = 0; idx < x86_pmu.num_counters; idx++) {
2726+
for (idx = 0; idx < num_counters; idx++) {
27252727
wrmsrl_safe(x86_pmu_config_addr(idx), 0ull);
27262728
wrmsrl_safe(x86_pmu_event_addr(idx), 0ull);
27272729
}
2728-
for (idx = 0; idx < x86_pmu.num_counters_fixed; idx++) {
2730+
for (idx = 0; idx < num_counters_fixed; idx++) {
27292731
if (fixed_counter_disabled(idx, cpuc->pmu))
27302732
continue;
27312733
wrmsrl_safe(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, 0ull);

arch/x86/events/intel/ds.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,16 +1007,18 @@ void intel_pmu_pebs_sched_task(struct perf_event_context *ctx, bool sched_in)
10071007
static inline void pebs_update_threshold(struct cpu_hw_events *cpuc)
10081008
{
10091009
struct debug_store *ds = cpuc->ds;
1010+
int max_pebs_events = hybrid(cpuc->pmu, max_pebs_events);
1011+
int num_counters_fixed = hybrid(cpuc->pmu, num_counters_fixed);
10101012
u64 threshold;
10111013
int reserved;
10121014

10131015
if (cpuc->n_pebs_via_pt)
10141016
return;
10151017

10161018
if (x86_pmu.flags & PMU_FL_PEBS_ALL)
1017-
reserved = x86_pmu.max_pebs_events + x86_pmu.num_counters_fixed;
1019+
reserved = max_pebs_events + num_counters_fixed;
10181020
else
1019-
reserved = x86_pmu.max_pebs_events;
1021+
reserved = max_pebs_events;
10201022

10211023
if (cpuc->n_pebs == cpuc->n_large_pebs) {
10221024
threshold = ds->pebs_absolute_maximum -
@@ -2072,6 +2074,8 @@ static void intel_pmu_drain_pebs_icl(struct pt_regs *iregs, struct perf_sample_d
20722074
{
20732075
short counts[INTEL_PMC_IDX_FIXED + MAX_FIXED_PEBS_EVENTS] = {};
20742076
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
2077+
int max_pebs_events = hybrid(cpuc->pmu, max_pebs_events);
2078+
int num_counters_fixed = hybrid(cpuc->pmu, num_counters_fixed);
20752079
struct debug_store *ds = cpuc->ds;
20762080
struct perf_event *event;
20772081
void *base, *at, *top;
@@ -2086,9 +2090,9 @@ static void intel_pmu_drain_pebs_icl(struct pt_regs *iregs, struct perf_sample_d
20862090

20872091
ds->pebs_index = ds->pebs_buffer_base;
20882092

2089-
mask = ((1ULL << x86_pmu.max_pebs_events) - 1) |
2090-
(((1ULL << x86_pmu.num_counters_fixed) - 1) << INTEL_PMC_IDX_FIXED);
2091-
size = INTEL_PMC_IDX_FIXED + x86_pmu.num_counters_fixed;
2093+
mask = ((1ULL << max_pebs_events) - 1) |
2094+
(((1ULL << num_counters_fixed) - 1) << INTEL_PMC_IDX_FIXED);
2095+
size = INTEL_PMC_IDX_FIXED + num_counters_fixed;
20922096

20932097
if (unlikely(base >= top)) {
20942098
intel_pmu_pebs_event_update_no_drain(cpuc, size);

arch/x86/events/perf_event.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,9 @@ struct x86_hybrid_pmu {
635635
struct pmu pmu;
636636
union perf_capabilities intel_cap;
637637
u64 intel_ctrl;
638+
int max_pebs_events;
639+
int num_counters;
640+
int num_counters_fixed;
638641
};
639642

640643
static __always_inline struct x86_hybrid_pmu *hybrid_pmu(struct pmu *pmu)
@@ -850,6 +853,7 @@ struct x86_pmu {
850853
* are available for all PMUs. The hybrid_pmu only includes the
851854
* unique capabilities.
852855
*/
856+
int num_hybrid_pmus;
853857
struct x86_hybrid_pmu *hybrid_pmu;
854858
};
855859

0 commit comments

Comments
 (0)