From: Like Xu <likexu@xxxxxxxxxxx> Continuing the theme of code reuse, tests shouldn't need to manually compute gp_counter_base and gp_event_select_base. They can be accessed directly after initialization and changed via setters when they need to be changed in some cases, e.g. full writes. Suggested-by: Sean Christopherson <seanjc@xxxxxxxxxx> Signed-off-by: Like Xu <likexu@xxxxxxxxxxx> --- lib/x86/pmu.c | 2 ++ lib/x86/pmu.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++ x86/pmu.c | 50 ++++++++++++++++++++++++-------------------------- 3 files changed, 73 insertions(+), 26 deletions(-) diff --git a/lib/x86/pmu.c b/lib/x86/pmu.c index 35b7efb..c0d100d 100644 --- a/lib/x86/pmu.c +++ b/lib/x86/pmu.c @@ -8,4 +8,6 @@ void pmu_init(void) cpuid_10 = cpuid(10); if (this_cpu_has(X86_FEATURE_PDCM)) pmu.perf_cap = rdmsr(MSR_IA32_PERF_CAPABILITIES); + pmu.msr_gp_counter_base = MSR_IA32_PERFCTR0; + pmu.msr_gp_event_select_base = MSR_P6_EVNTSEL0; } \ No newline at end of file diff --git a/lib/x86/pmu.h b/lib/x86/pmu.h index 95b17da..7487a30 100644 --- a/lib/x86/pmu.h +++ b/lib/x86/pmu.h @@ -35,6 +35,8 @@ struct pmu_caps { u64 perf_cap; + u32 msr_gp_counter_base; + u32 msr_gp_event_select_base; }; extern struct cpuid cpuid_10; @@ -42,6 +44,46 @@ extern struct pmu_caps pmu; void pmu_init(void); +static inline u32 gp_counter_base(void) +{ + return pmu.msr_gp_counter_base; +} + +static inline void set_gp_counter_base(u32 new_base) +{ + pmu.msr_gp_counter_base = new_base; +} + +static inline u32 gp_event_select_base(void) +{ + return pmu.msr_gp_event_select_base; +} + +static inline void set_gp_event_select_base(u32 new_base) +{ + pmu.msr_gp_event_select_base = new_base; +} + +static inline u32 gp_counter_msr(unsigned int i) +{ + return gp_counter_base() + i; +} + +static inline u32 gp_event_select_msr(unsigned int i) +{ + return gp_event_select_base() + i; +} + +static inline void write_gp_counter_value(unsigned int i, u64 value) +{ + wrmsr(gp_counter_msr(i), value); +} + +static inline void write_gp_event_select(unsigned int i, u64 value) +{ + wrmsr(gp_event_select_msr(i), value); +} + static inline u8 pmu_version(void) { return cpuid_10.a & 0xff; @@ -109,4 +151,9 @@ static inline bool pmu_has_full_writes(void) return this_cpu_perf_capabilities() & PMU_CAP_FW_WRITES; } +static inline bool pmu_use_full_writes(void) +{ + return gp_counter_base() == MSR_IA32_PMC0; +} + #endif /* _X86_PMU_H_ */ diff --git a/x86/pmu.c b/x86/pmu.c index a6329cd..589c7cb 100644 --- a/x86/pmu.c +++ b/x86/pmu.c @@ -44,8 +44,6 @@ struct pmu_event { {"fixed 3", MSR_CORE_PERF_FIXED_CTR0 + 2, 0.1*N, 30*N} }; -static u64 gp_counter_base = MSR_IA32_PERFCTR0; - char *buf; static inline void loop(void) @@ -84,7 +82,7 @@ static bool is_gp(pmu_counter_t *evt) static int event_to_global_idx(pmu_counter_t *cnt) { - return cnt->ctr - (is_gp(cnt) ? gp_counter_base : + return cnt->ctr - (is_gp(cnt) ? gp_counter_base() : (MSR_CORE_PERF_FIXED_CTR0 - FIXED_CNT_INDEX)); } @@ -121,8 +119,7 @@ static void __start_event(pmu_counter_t *evt, uint64_t count) evt->count = count; wrmsr(evt->ctr, evt->count); if (is_gp(evt)) - wrmsr(MSR_P6_EVNTSEL0 + event_to_global_idx(evt), - evt->config | EVNTSEL_EN); + write_gp_event_select(event_to_global_idx(evt), evt->config | EVNTSEL_EN); else { uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL); int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4; @@ -150,8 +147,7 @@ static void stop_event(pmu_counter_t *evt) { global_disable(evt); if (is_gp(evt)) - wrmsr(MSR_P6_EVNTSEL0 + event_to_global_idx(evt), - evt->config & ~EVNTSEL_EN); + write_gp_event_select(event_to_global_idx(evt), evt->config & ~EVNTSEL_EN); else { uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL); int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4; @@ -198,12 +194,12 @@ static void check_gp_counter(struct pmu_event *evt) { int nr_gp_counters = pmu_nr_gp_counters(); pmu_counter_t cnt = { - .ctr = gp_counter_base, .config = EVNTSEL_OS | EVNTSEL_USR | evt->unit_sel, }; int i; - for (i = 0; i < nr_gp_counters; i++, cnt.ctr++) { + for (i = 0; i < nr_gp_counters; i++) { + cnt.ctr = gp_counter_msr(i); measure_one(&cnt); report(verify_event(cnt.count, evt), "%s-%d", evt->name, i); } @@ -247,7 +243,7 @@ static void check_counters_many(void) if (!pmu_gp_counter_is_available(i)) continue; - cnt[n].ctr = gp_counter_base + n; + cnt[n].ctr = gp_counter_msr(n); cnt[n].config = EVNTSEL_OS | EVNTSEL_USR | gp_events[i % ARRAY_SIZE(gp_events)].unit_sel; n++; @@ -287,7 +283,7 @@ static void check_counter_overflow(void) uint64_t overflow_preset; int i; pmu_counter_t cnt = { - .ctr = gp_counter_base, + .ctr = gp_counter_msr(0), .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[1].unit_sel /* instructions */, }; overflow_preset = measure_for_overflow(&cnt); @@ -297,18 +293,20 @@ static void check_counter_overflow(void) report_prefix_push("overflow"); - for (i = 0; i < nr_gp_counters + 1; i++, cnt.ctr++) { + for (i = 0; i < nr_gp_counters + 1; i++) { uint64_t status; int idx; cnt.count = overflow_preset; - if (gp_counter_base == MSR_IA32_PMC0) + if (pmu_use_full_writes()) cnt.count &= (1ull << pmu_gp_counter_width()) - 1; if (i == nr_gp_counters) { cnt.ctr = fixed_events[0].unit_sel; cnt.count = measure_for_overflow(&cnt); cnt.count &= (1ull << pmu_fixed_counter_width()) - 1; + } else { + cnt.ctr = gp_counter_msr(i); } if (i % 2) @@ -332,7 +330,7 @@ static void check_counter_overflow(void) static void check_gp_counter_cmask(void) { pmu_counter_t cnt = { - .ctr = gp_counter_base, + .ctr = gp_counter_msr(0), .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[1].unit_sel /* instructions */, }; cnt.config |= (0x2 << EVNTSEL_CMASK_SHIFT); @@ -367,7 +365,7 @@ static void check_rdpmc(void) for (i = 0; i < nr_gp_counters; i++) { uint64_t x; pmu_counter_t cnt = { - .ctr = gp_counter_base + i, + .ctr = gp_counter_msr(i), .idx = i }; @@ -375,7 +373,7 @@ static void check_rdpmc(void) * Without full-width writes, only the low 32 bits are writable, * and the value is sign-extended. */ - if (gp_counter_base == MSR_IA32_PERFCTR0) + if (gp_counter_base() == MSR_IA32_PERFCTR0) x = (uint64_t)(int64_t)(int32_t)val; else x = (uint64_t)(int64_t)val; @@ -383,7 +381,7 @@ static void check_rdpmc(void) /* Mask according to the number of supported bits */ x &= (1ull << gp_counter_width) - 1; - wrmsr(gp_counter_base + i, val); + write_gp_counter_value(i, val); report(rdpmc(i) == x, "cntr-%d", i); exc = test_for_exception(GP_VECTOR, do_rdpmc_fast, &cnt); @@ -417,7 +415,7 @@ static void check_running_counter_wrmsr(void) uint64_t status; uint64_t count; pmu_counter_t evt = { - .ctr = gp_counter_base, + .ctr = gp_counter_msr(0), .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[1].unit_sel, }; @@ -425,7 +423,7 @@ static void check_running_counter_wrmsr(void) start_event(&evt); loop(); - wrmsr(gp_counter_base, 0); + write_gp_counter_value(0, 0); stop_event(&evt); report(evt.count < gp_events[1].min, "cntr"); @@ -436,10 +434,10 @@ static void check_running_counter_wrmsr(void) start_event(&evt); count = -1; - if (gp_counter_base == MSR_IA32_PMC0) + if (pmu_use_full_writes()) count &= (1ull << pmu_gp_counter_width()) - 1; - wrmsr(gp_counter_base, count); + write_gp_counter_value(0, count); loop(); stop_event(&evt); @@ -453,12 +451,12 @@ static void check_emulated_instr(void) { uint64_t status, instr_start, brnch_start; pmu_counter_t brnch_cnt = { - .ctr = MSR_IA32_PERFCTR0, + .ctr = gp_counter_msr(0), /* branch instructions */ .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[5].unit_sel, }; pmu_counter_t instr_cnt = { - .ctr = MSR_IA32_PERFCTR0 + 1, + .ctr = gp_counter_msr(1), /* instructions */ .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[1].unit_sel, }; @@ -472,8 +470,8 @@ static void check_emulated_instr(void) brnch_start = -EXPECTED_BRNCH; instr_start = -EXPECTED_INSTR; - wrmsr(MSR_IA32_PERFCTR0, brnch_start); - wrmsr(MSR_IA32_PERFCTR0 + 1, instr_start); + write_gp_counter_value(0, brnch_start); + write_gp_counter_value(1, instr_start); // KVM_FEP is a magic prefix that forces emulation so // 'KVM_FEP "jne label\n"' just counts as a single instruction. asm volatile( @@ -670,7 +668,7 @@ int main(int ac, char **av) check_counters(); if (pmu_has_full_writes()) { - gp_counter_base = MSR_IA32_PMC0; + set_gp_counter_base(MSR_IA32_PMC0); report_prefix_push("full-width writes"); check_counters(); check_gp_counters_write_width(); -- 2.38.1