Skip to content

Commit 61e76d5

Browse files
Kan LiangPeter Zijlstra
authored andcommitted
perf/x86: Track pmu in per-CPU cpu_hw_events
Some platforms, e.g. Alder Lake, have hybrid architecture. In the same package, there may be more than one type of CPU. The PMU capabilities are different among different types of CPU. Perf will register a dedicated PMU for each type of CPU. Add a 'pmu' variable in the struct cpu_hw_events to track the dedicated PMU of the current CPU. Current x86_get_pmu() use the global 'pmu', which will be broken on a hybrid platform. Modify it to apply the 'pmu' of the specific CPU. Initialize the per-CPU 'pmu' variable with the global 'pmu'. There is nothing changed for the non-hybrid platforms. The is_x86_event() will be updated in the later patch ("perf/x86: Register hybrid PMUs") for hybrid platforms. For the non-hybrid platforms, nothing is changed here. Suggested-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Kan Liang <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 250b3c0 commit 61e76d5

File tree

5 files changed

+24
-12
lines changed

5 files changed

+24
-12
lines changed

arch/x86/events/core.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,11 @@
4545
#include "perf_event.h"
4646

4747
struct x86_pmu x86_pmu __read_mostly;
48+
static struct pmu pmu;
4849

4950
DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
5051
.enabled = 1,
52+
.pmu = &pmu,
5153
};
5254

5355
DEFINE_STATIC_KEY_FALSE(rdpmc_never_available_key);
@@ -724,16 +726,23 @@ void x86_pmu_enable_all(int added)
724726
}
725727
}
726728

727-
static struct pmu pmu;
728-
729729
static inline int is_x86_event(struct perf_event *event)
730730
{
731731
return event->pmu == &pmu;
732732
}
733733

734-
struct pmu *x86_get_pmu(void)
734+
struct pmu *x86_get_pmu(unsigned int cpu)
735735
{
736-
return &pmu;
736+
struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
737+
738+
/*
739+
* All CPUs of the hybrid type have been offline.
740+
* The x86_get_pmu() should not be invoked.
741+
*/
742+
if (WARN_ON_ONCE(!cpuc->pmu))
743+
return &pmu;
744+
745+
return cpuc->pmu;
737746
}
738747
/*
739748
* Event scheduler state:

arch/x86/events/intel/core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4876,7 +4876,7 @@ static void update_tfa_sched(void *ignored)
48764876
* and if so force schedule out for all event types all contexts
48774877
*/
48784878
if (test_bit(3, cpuc->active_mask))
4879-
perf_pmu_resched(x86_get_pmu());
4879+
perf_pmu_resched(x86_get_pmu(smp_processor_id()));
48804880
}
48814881

48824882
static ssize_t show_sysctl_tfa(struct device *cdev,

arch/x86/events/intel/ds.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2192,7 +2192,7 @@ void __init intel_ds_init(void)
21922192
PERF_SAMPLE_TIME;
21932193
x86_pmu.flags |= PMU_FL_PEBS_ALL;
21942194
pebs_qual = "-baseline";
2195-
x86_get_pmu()->capabilities |= PERF_PMU_CAP_EXTENDED_REGS;
2195+
x86_get_pmu(smp_processor_id())->capabilities |= PERF_PMU_CAP_EXTENDED_REGS;
21962196
} else {
21972197
/* Only basic record supported */
21982198
x86_pmu.large_pebs_flags &=
@@ -2207,7 +2207,7 @@ void __init intel_ds_init(void)
22072207

22082208
if (x86_pmu.intel_cap.pebs_output_pt_available) {
22092209
pr_cont("PEBS-via-PT, ");
2210-
x86_get_pmu()->capabilities |= PERF_PMU_CAP_AUX_OUTPUT;
2210+
x86_get_pmu(smp_processor_id())->capabilities |= PERF_PMU_CAP_AUX_OUTPUT;
22112211
}
22122212

22132213
break;

arch/x86/events/intel/lbr.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ void intel_pmu_lbr_add(struct perf_event *event)
705705

706706
void release_lbr_buffers(void)
707707
{
708-
struct kmem_cache *kmem_cache = x86_get_pmu()->task_ctx_cache;
708+
struct kmem_cache *kmem_cache;
709709
struct cpu_hw_events *cpuc;
710710
int cpu;
711711

@@ -714,6 +714,7 @@ void release_lbr_buffers(void)
714714

715715
for_each_possible_cpu(cpu) {
716716
cpuc = per_cpu_ptr(&cpu_hw_events, cpu);
717+
kmem_cache = x86_get_pmu(cpu)->task_ctx_cache;
717718
if (kmem_cache && cpuc->lbr_xsave) {
718719
kmem_cache_free(kmem_cache, cpuc->lbr_xsave);
719720
cpuc->lbr_xsave = NULL;
@@ -1609,7 +1610,7 @@ void intel_pmu_lbr_init_hsw(void)
16091610
x86_pmu.lbr_sel_mask = LBR_SEL_MASK;
16101611
x86_pmu.lbr_sel_map = hsw_lbr_sel_map;
16111612

1612-
x86_get_pmu()->task_ctx_cache = create_lbr_kmem_cache(size, 0);
1613+
x86_get_pmu(smp_processor_id())->task_ctx_cache = create_lbr_kmem_cache(size, 0);
16131614

16141615
if (lbr_from_signext_quirk_needed())
16151616
static_branch_enable(&lbr_from_quirk_key);
@@ -1629,7 +1630,7 @@ __init void intel_pmu_lbr_init_skl(void)
16291630
x86_pmu.lbr_sel_mask = LBR_SEL_MASK;
16301631
x86_pmu.lbr_sel_map = hsw_lbr_sel_map;
16311632

1632-
x86_get_pmu()->task_ctx_cache = create_lbr_kmem_cache(size, 0);
1633+
x86_get_pmu(smp_processor_id())->task_ctx_cache = create_lbr_kmem_cache(size, 0);
16331634

16341635
/*
16351636
* SW branch filter usage:
@@ -1726,7 +1727,7 @@ static bool is_arch_lbr_xsave_available(void)
17261727

17271728
void __init intel_pmu_arch_lbr_init(void)
17281729
{
1729-
struct pmu *pmu = x86_get_pmu();
1730+
struct pmu *pmu = x86_get_pmu(smp_processor_id());
17301731
union cpuid28_eax eax;
17311732
union cpuid28_ebx ebx;
17321733
union cpuid28_ecx ecx;

arch/x86/events/perf_event.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,8 @@ struct cpu_hw_events {
326326
int n_pair; /* Large increment events */
327327

328328
void *kfree_on_online[X86_PERF_KFREE_MAX];
329+
330+
struct pmu *pmu;
329331
};
330332

331333
#define __EVENT_CONSTRAINT_RANGE(c, e, n, m, w, o, f) { \
@@ -904,7 +906,7 @@ static struct perf_pmu_events_ht_attr event_attr_##v = { \
904906
.event_str_ht = ht, \
905907
}
906908

907-
struct pmu *x86_get_pmu(void);
909+
struct pmu *x86_get_pmu(unsigned int cpu);
908910
extern struct x86_pmu x86_pmu __read_mostly;
909911

910912
static __always_inline struct x86_perf_task_context_opt *task_context_opt(void *ctx)

0 commit comments

Comments
 (0)