Skip to content

Commit e6faa04

Browse files
Jinrong Liangsean-jc
authored andcommitted
KVM: selftests: Add pmu.h and lib/pmu.c for common PMU assets
Add a PMU library for x86 selftests to help eliminate open-coded event encodings, and to reduce the amount of copy+paste between PMU selftests. Use the new common macro definitions in the existing PMU event filter test. Cc: Aaron Lewis <[email protected]> Suggested-by: Sean Christopherson <[email protected]> Signed-off-by: Jinrong Liang <[email protected]> Co-developed-by: Sean Christopherson <[email protected]> Tested-by: Dapeng Mi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sean Christopherson <[email protected]>
1 parent 370d536 commit e6faa04

File tree

4 files changed

+173
-97
lines changed

4 files changed

+173
-97
lines changed

tools/testing/selftests/kvm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ LIBKVM_x86_64 += lib/x86_64/apic.c
3636
LIBKVM_x86_64 += lib/x86_64/handlers.S
3737
LIBKVM_x86_64 += lib/x86_64/hyperv.c
3838
LIBKVM_x86_64 += lib/x86_64/memstress.c
39+
LIBKVM_x86_64 += lib/x86_64/pmu.c
3940
LIBKVM_x86_64 += lib/x86_64/processor.c
4041
LIBKVM_x86_64 += lib/x86_64/svm.c
4142
LIBKVM_x86_64 += lib/x86_64/ucall.c
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (C) 2023, Tencent, Inc.
4+
*/
5+
#ifndef SELFTEST_KVM_PMU_H
6+
#define SELFTEST_KVM_PMU_H
7+
8+
#include <stdint.h>
9+
10+
#define KVM_PMU_EVENT_FILTER_MAX_EVENTS 300
11+
12+
/*
13+
* Encode an eventsel+umask pair into event-select MSR format. Note, this is
14+
* technically AMD's format, as Intel's format only supports 8 bits for the
15+
* event selector, i.e. doesn't use bits 24:16 for the selector. But, OR-ing
16+
* in '0' is a nop and won't clobber the CMASK.
17+
*/
18+
#define RAW_EVENT(eventsel, umask) (((eventsel & 0xf00UL) << 24) | \
19+
((eventsel) & 0xff) | \
20+
((umask) & 0xff) << 8)
21+
22+
/*
23+
* These are technically Intel's definitions, but except for CMASK (see above),
24+
* AMD's layout is compatible with Intel's.
25+
*/
26+
#define ARCH_PERFMON_EVENTSEL_EVENT GENMASK_ULL(7, 0)
27+
#define ARCH_PERFMON_EVENTSEL_UMASK GENMASK_ULL(15, 8)
28+
#define ARCH_PERFMON_EVENTSEL_USR BIT_ULL(16)
29+
#define ARCH_PERFMON_EVENTSEL_OS BIT_ULL(17)
30+
#define ARCH_PERFMON_EVENTSEL_EDGE BIT_ULL(18)
31+
#define ARCH_PERFMON_EVENTSEL_PIN_CONTROL BIT_ULL(19)
32+
#define ARCH_PERFMON_EVENTSEL_INT BIT_ULL(20)
33+
#define ARCH_PERFMON_EVENTSEL_ANY BIT_ULL(21)
34+
#define ARCH_PERFMON_EVENTSEL_ENABLE BIT_ULL(22)
35+
#define ARCH_PERFMON_EVENTSEL_INV BIT_ULL(23)
36+
#define ARCH_PERFMON_EVENTSEL_CMASK GENMASK_ULL(31, 24)
37+
38+
/* RDPMC control flags, Intel only. */
39+
#define INTEL_RDPMC_METRICS BIT_ULL(29)
40+
#define INTEL_RDPMC_FIXED BIT_ULL(30)
41+
#define INTEL_RDPMC_FAST BIT_ULL(31)
42+
43+
/* Fixed PMC controls, Intel only. */
44+
#define FIXED_PMC_GLOBAL_CTRL_ENABLE(_idx) BIT_ULL((32 + (_idx)))
45+
46+
#define FIXED_PMC_KERNEL BIT_ULL(0)
47+
#define FIXED_PMC_USER BIT_ULL(1)
48+
#define FIXED_PMC_ANYTHREAD BIT_ULL(2)
49+
#define FIXED_PMC_ENABLE_PMI BIT_ULL(3)
50+
#define FIXED_PMC_NR_BITS 4
51+
#define FIXED_PMC_CTRL(_idx, _val) ((_val) << ((_idx) * FIXED_PMC_NR_BITS))
52+
53+
#define PMU_CAP_FW_WRITES BIT_ULL(13)
54+
#define PMU_CAP_LBR_FMT 0x3f
55+
56+
#define INTEL_ARCH_CPU_CYCLES RAW_EVENT(0x3c, 0x00)
57+
#define INTEL_ARCH_INSTRUCTIONS_RETIRED RAW_EVENT(0xc0, 0x00)
58+
#define INTEL_ARCH_REFERENCE_CYCLES RAW_EVENT(0x3c, 0x01)
59+
#define INTEL_ARCH_LLC_REFERENCES RAW_EVENT(0x2e, 0x4f)
60+
#define INTEL_ARCH_LLC_MISSES RAW_EVENT(0x2e, 0x41)
61+
#define INTEL_ARCH_BRANCHES_RETIRED RAW_EVENT(0xc4, 0x00)
62+
#define INTEL_ARCH_BRANCHES_MISPREDICTED RAW_EVENT(0xc5, 0x00)
63+
#define INTEL_ARCH_TOPDOWN_SLOTS RAW_EVENT(0xa4, 0x01)
64+
65+
#define AMD_ZEN_CORE_CYCLES RAW_EVENT(0x76, 0x00)
66+
#define AMD_ZEN_INSTRUCTIONS_RETIRED RAW_EVENT(0xc0, 0x00)
67+
#define AMD_ZEN_BRANCHES_RETIRED RAW_EVENT(0xc2, 0x00)
68+
#define AMD_ZEN_BRANCHES_MISPREDICTED RAW_EVENT(0xc3, 0x00)
69+
70+
/*
71+
* Note! The order and thus the index of the architectural events matters as
72+
* support for each event is enumerated via CPUID using the index of the event.
73+
*/
74+
enum intel_pmu_architectural_events {
75+
INTEL_ARCH_CPU_CYCLES_INDEX,
76+
INTEL_ARCH_INSTRUCTIONS_RETIRED_INDEX,
77+
INTEL_ARCH_REFERENCE_CYCLES_INDEX,
78+
INTEL_ARCH_LLC_REFERENCES_INDEX,
79+
INTEL_ARCH_LLC_MISSES_INDEX,
80+
INTEL_ARCH_BRANCHES_RETIRED_INDEX,
81+
INTEL_ARCH_BRANCHES_MISPREDICTED_INDEX,
82+
INTEL_ARCH_TOPDOWN_SLOTS_INDEX,
83+
NR_INTEL_ARCH_EVENTS,
84+
};
85+
86+
enum amd_pmu_zen_events {
87+
AMD_ZEN_CORE_CYCLES_INDEX,
88+
AMD_ZEN_INSTRUCTIONS_INDEX,
89+
AMD_ZEN_BRANCHES_INDEX,
90+
AMD_ZEN_BRANCH_MISSES_INDEX,
91+
NR_AMD_ZEN_EVENTS,
92+
};
93+
94+
extern const uint64_t intel_pmu_arch_events[];
95+
extern const uint64_t amd_pmu_zen_events[];
96+
97+
#endif /* SELFTEST_KVM_PMU_H */
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (C) 2023, Tencent, Inc.
4+
*/
5+
6+
#include <stdint.h>
7+
8+
#include <linux/kernel.h>
9+
10+
#include "kvm_util.h"
11+
#include "pmu.h"
12+
13+
const uint64_t intel_pmu_arch_events[] = {
14+
INTEL_ARCH_CPU_CYCLES,
15+
INTEL_ARCH_INSTRUCTIONS_RETIRED,
16+
INTEL_ARCH_REFERENCE_CYCLES,
17+
INTEL_ARCH_LLC_REFERENCES,
18+
INTEL_ARCH_LLC_MISSES,
19+
INTEL_ARCH_BRANCHES_RETIRED,
20+
INTEL_ARCH_BRANCHES_MISPREDICTED,
21+
INTEL_ARCH_TOPDOWN_SLOTS,
22+
};
23+
kvm_static_assert(ARRAY_SIZE(intel_pmu_arch_events) == NR_INTEL_ARCH_EVENTS);
24+
25+
const uint64_t amd_pmu_zen_events[] = {
26+
AMD_ZEN_CORE_CYCLES,
27+
AMD_ZEN_INSTRUCTIONS_RETIRED,
28+
AMD_ZEN_BRANCHES_RETIRED,
29+
AMD_ZEN_BRANCHES_MISPREDICTED,
30+
};
31+
kvm_static_assert(ARRAY_SIZE(amd_pmu_zen_events) == NR_AMD_ZEN_EVENTS);

tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c

Lines changed: 44 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -11,99 +11,47 @@
1111
*/
1212

1313
#define _GNU_SOURCE /* for program_invocation_short_name */
14-
#include "test_util.h"
14+
1515
#include "kvm_util.h"
16+
#include "pmu.h"
1617
#include "processor.h"
17-
18-
/*
19-
* In lieu of copying perf_event.h into tools...
20-
*/
21-
#define ARCH_PERFMON_EVENTSEL_OS (1ULL << 17)
22-
#define ARCH_PERFMON_EVENTSEL_ENABLE (1ULL << 22)
23-
24-
/* End of stuff taken from perf_event.h. */
25-
26-
/* Oddly, this isn't in perf_event.h. */
27-
#define ARCH_PERFMON_BRANCHES_RETIRED 5
18+
#include "test_util.h"
2819

2920
#define NUM_BRANCHES 42
30-
#define INTEL_PMC_IDX_FIXED 32
31-
32-
/* Matches KVM_PMU_EVENT_FILTER_MAX_EVENTS in pmu.c */
33-
#define MAX_FILTER_EVENTS 300
3421
#define MAX_TEST_EVENTS 10
3522

3623
#define PMU_EVENT_FILTER_INVALID_ACTION (KVM_PMU_EVENT_DENY + 1)
3724
#define PMU_EVENT_FILTER_INVALID_FLAGS (KVM_PMU_EVENT_FLAGS_VALID_MASK << 1)
38-
#define PMU_EVENT_FILTER_INVALID_NEVENTS (MAX_FILTER_EVENTS + 1)
39-
40-
/*
41-
* This is how the event selector and unit mask are stored in an AMD
42-
* core performance event-select register. Intel's format is similar,
43-
* but the event selector is only 8 bits.
44-
*/
45-
#define EVENT(select, umask) ((select & 0xf00UL) << 24 | (select & 0xff) | \
46-
(umask & 0xff) << 8)
47-
48-
/*
49-
* "Branch instructions retired", from the Intel SDM, volume 3,
50-
* "Pre-defined Architectural Performance Events."
51-
*/
52-
53-
#define INTEL_BR_RETIRED EVENT(0xc4, 0)
54-
55-
/*
56-
* "Retired branch instructions", from Processor Programming Reference
57-
* (PPR) for AMD Family 17h Model 01h, Revision B1 Processors,
58-
* Preliminary Processor Programming Reference (PPR) for AMD Family
59-
* 17h Model 31h, Revision B0 Processors, and Preliminary Processor
60-
* Programming Reference (PPR) for AMD Family 19h Model 01h, Revision
61-
* B1 Processors Volume 1 of 2.
62-
*/
63-
64-
#define AMD_ZEN_BR_RETIRED EVENT(0xc2, 0)
65-
66-
67-
/*
68-
* "Retired instructions", from Processor Programming Reference
69-
* (PPR) for AMD Family 17h Model 01h, Revision B1 Processors,
70-
* Preliminary Processor Programming Reference (PPR) for AMD Family
71-
* 17h Model 31h, Revision B0 Processors, and Preliminary Processor
72-
* Programming Reference (PPR) for AMD Family 19h Model 01h, Revision
73-
* B1 Processors Volume 1 of 2.
74-
* --- and ---
75-
* "Instructions retired", from the Intel SDM, volume 3,
76-
* "Pre-defined Architectural Performance Events."
77-
*/
78-
79-
#define INST_RETIRED EVENT(0xc0, 0)
25+
#define PMU_EVENT_FILTER_INVALID_NEVENTS (KVM_PMU_EVENT_FILTER_MAX_EVENTS + 1)
8026

8127
struct __kvm_pmu_event_filter {
8228
__u32 action;
8329
__u32 nevents;
8430
__u32 fixed_counter_bitmap;
8531
__u32 flags;
8632
__u32 pad[4];
87-
__u64 events[MAX_FILTER_EVENTS];
33+
__u64 events[KVM_PMU_EVENT_FILTER_MAX_EVENTS];
8834
};
8935

9036
/*
91-
* This event list comprises Intel's eight architectural events plus
92-
* AMD's "retired branch instructions" for Zen[123] (and possibly
93-
* other AMD CPUs).
37+
* This event list comprises Intel's known architectural events, plus AMD's
38+
* "retired branch instructions" for Zen1-Zen3 (and* possibly other AMD CPUs).
39+
* Note, AMD and Intel use the same encoding for instructions retired.
9440
*/
41+
kvm_static_assert(INTEL_ARCH_INSTRUCTIONS_RETIRED == AMD_ZEN_INSTRUCTIONS_RETIRED);
42+
9543
static const struct __kvm_pmu_event_filter base_event_filter = {
9644
.nevents = ARRAY_SIZE(base_event_filter.events),
9745
.events = {
98-
EVENT(0x3c, 0),
99-
INST_RETIRED,
100-
EVENT(0x3c, 1),
101-
EVENT(0x2e, 0x4f),
102-
EVENT(0x2e, 0x41),
103-
EVENT(0xc4, 0),
104-
EVENT(0xc5, 0),
105-
EVENT(0xa4, 1),
106-
AMD_ZEN_BR_RETIRED,
46+
INTEL_ARCH_CPU_CYCLES,
47+
INTEL_ARCH_INSTRUCTIONS_RETIRED,
48+
INTEL_ARCH_REFERENCE_CYCLES,
49+
INTEL_ARCH_LLC_REFERENCES,
50+
INTEL_ARCH_LLC_MISSES,
51+
INTEL_ARCH_BRANCHES_RETIRED,
52+
INTEL_ARCH_BRANCHES_MISPREDICTED,
53+
INTEL_ARCH_TOPDOWN_SLOTS,
54+
AMD_ZEN_BRANCHES_RETIRED,
10755
},
10856
};
10957

@@ -165,9 +113,9 @@ static void intel_guest_code(void)
165113
for (;;) {
166114
wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0);
167115
wrmsr(MSR_P6_EVNTSEL0, ARCH_PERFMON_EVENTSEL_ENABLE |
168-
ARCH_PERFMON_EVENTSEL_OS | INTEL_BR_RETIRED);
116+
ARCH_PERFMON_EVENTSEL_OS | INTEL_ARCH_BRANCHES_RETIRED);
169117
wrmsr(MSR_P6_EVNTSEL1, ARCH_PERFMON_EVENTSEL_ENABLE |
170-
ARCH_PERFMON_EVENTSEL_OS | INST_RETIRED);
118+
ARCH_PERFMON_EVENTSEL_OS | INTEL_ARCH_INSTRUCTIONS_RETIRED);
171119
wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0x3);
172120

173121
run_and_measure_loop(MSR_IA32_PMC0);
@@ -189,9 +137,9 @@ static void amd_guest_code(void)
189137
for (;;) {
190138
wrmsr(MSR_K7_EVNTSEL0, 0);
191139
wrmsr(MSR_K7_EVNTSEL0, ARCH_PERFMON_EVENTSEL_ENABLE |
192-
ARCH_PERFMON_EVENTSEL_OS | AMD_ZEN_BR_RETIRED);
140+
ARCH_PERFMON_EVENTSEL_OS | AMD_ZEN_BRANCHES_RETIRED);
193141
wrmsr(MSR_K7_EVNTSEL1, ARCH_PERFMON_EVENTSEL_ENABLE |
194-
ARCH_PERFMON_EVENTSEL_OS | INST_RETIRED);
142+
ARCH_PERFMON_EVENTSEL_OS | AMD_ZEN_INSTRUCTIONS_RETIRED);
195143

196144
run_and_measure_loop(MSR_K7_PERFCTR0);
197145
GUEST_SYNC(0);
@@ -312,7 +260,7 @@ static void test_amd_deny_list(struct kvm_vcpu *vcpu)
312260
.action = KVM_PMU_EVENT_DENY,
313261
.nevents = 1,
314262
.events = {
315-
EVENT(0x1C2, 0),
263+
RAW_EVENT(0x1C2, 0),
316264
},
317265
};
318266

@@ -347,9 +295,9 @@ static void test_not_member_deny_list(struct kvm_vcpu *vcpu)
347295

348296
f.action = KVM_PMU_EVENT_DENY;
349297

350-
remove_event(&f, INST_RETIRED);
351-
remove_event(&f, INTEL_BR_RETIRED);
352-
remove_event(&f, AMD_ZEN_BR_RETIRED);
298+
remove_event(&f, INTEL_ARCH_INSTRUCTIONS_RETIRED);
299+
remove_event(&f, INTEL_ARCH_BRANCHES_RETIRED);
300+
remove_event(&f, AMD_ZEN_BRANCHES_RETIRED);
353301
test_with_filter(vcpu, &f);
354302

355303
ASSERT_PMC_COUNTING_INSTRUCTIONS();
@@ -361,9 +309,9 @@ static void test_not_member_allow_list(struct kvm_vcpu *vcpu)
361309

362310
f.action = KVM_PMU_EVENT_ALLOW;
363311

364-
remove_event(&f, INST_RETIRED);
365-
remove_event(&f, INTEL_BR_RETIRED);
366-
remove_event(&f, AMD_ZEN_BR_RETIRED);
312+
remove_event(&f, INTEL_ARCH_INSTRUCTIONS_RETIRED);
313+
remove_event(&f, INTEL_ARCH_BRANCHES_RETIRED);
314+
remove_event(&f, AMD_ZEN_BRANCHES_RETIRED);
367315
test_with_filter(vcpu, &f);
368316

369317
ASSERT_PMC_NOT_COUNTING_INSTRUCTIONS();
@@ -452,9 +400,9 @@ static bool use_amd_pmu(void)
452400
* - Sapphire Rapids, Ice Lake, Cascade Lake, Skylake.
453401
*/
454402
#define MEM_INST_RETIRED 0xD0
455-
#define MEM_INST_RETIRED_LOAD EVENT(MEM_INST_RETIRED, 0x81)
456-
#define MEM_INST_RETIRED_STORE EVENT(MEM_INST_RETIRED, 0x82)
457-
#define MEM_INST_RETIRED_LOAD_STORE EVENT(MEM_INST_RETIRED, 0x83)
403+
#define MEM_INST_RETIRED_LOAD RAW_EVENT(MEM_INST_RETIRED, 0x81)
404+
#define MEM_INST_RETIRED_STORE RAW_EVENT(MEM_INST_RETIRED, 0x82)
405+
#define MEM_INST_RETIRED_LOAD_STORE RAW_EVENT(MEM_INST_RETIRED, 0x83)
458406

459407
static bool supports_event_mem_inst_retired(void)
460408
{
@@ -486,9 +434,9 @@ static bool supports_event_mem_inst_retired(void)
486434
* B1 Processors Volume 1 of 2.
487435
*/
488436
#define LS_DISPATCH 0x29
489-
#define LS_DISPATCH_LOAD EVENT(LS_DISPATCH, BIT(0))
490-
#define LS_DISPATCH_STORE EVENT(LS_DISPATCH, BIT(1))
491-
#define LS_DISPATCH_LOAD_STORE EVENT(LS_DISPATCH, BIT(2))
437+
#define LS_DISPATCH_LOAD RAW_EVENT(LS_DISPATCH, BIT(0))
438+
#define LS_DISPATCH_STORE RAW_EVENT(LS_DISPATCH, BIT(1))
439+
#define LS_DISPATCH_LOAD_STORE RAW_EVENT(LS_DISPATCH, BIT(2))
492440

493441
#define INCLUDE_MASKED_ENTRY(event_select, mask, match) \
494442
KVM_PMU_ENCODE_MASKED_ENTRY(event_select, mask, match, false)
@@ -729,14 +677,14 @@ static void add_dummy_events(uint64_t *events, int nevents)
729677

730678
static void test_masked_events(struct kvm_vcpu *vcpu)
731679
{
732-
int nevents = MAX_FILTER_EVENTS - MAX_TEST_EVENTS;
733-
uint64_t events[MAX_FILTER_EVENTS];
680+
int nevents = KVM_PMU_EVENT_FILTER_MAX_EVENTS - MAX_TEST_EVENTS;
681+
uint64_t events[KVM_PMU_EVENT_FILTER_MAX_EVENTS];
734682

735683
/* Run the test cases against a sparse PMU event filter. */
736684
run_masked_events_tests(vcpu, events, 0);
737685

738686
/* Run the test cases against a dense PMU event filter. */
739-
add_dummy_events(events, MAX_FILTER_EVENTS);
687+
add_dummy_events(events, KVM_PMU_EVENT_FILTER_MAX_EVENTS);
740688
run_masked_events_tests(vcpu, events, nevents);
741689
}
742690

@@ -809,20 +757,19 @@ static void test_filter_ioctl(struct kvm_vcpu *vcpu)
809757
TEST_ASSERT(!r, "Masking non-existent fixed counters should be allowed");
810758
}
811759

812-
static void intel_run_fixed_counter_guest_code(uint8_t fixed_ctr_idx)
760+
static void intel_run_fixed_counter_guest_code(uint8_t idx)
813761
{
814762
for (;;) {
815763
wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0);
816-
wrmsr(MSR_CORE_PERF_FIXED_CTR0 + fixed_ctr_idx, 0);
764+
wrmsr(MSR_CORE_PERF_FIXED_CTR0 + idx, 0);
817765

818766
/* Only OS_EN bit is enabled for fixed counter[idx]. */
819-
wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, BIT_ULL(4 * fixed_ctr_idx));
820-
wrmsr(MSR_CORE_PERF_GLOBAL_CTRL,
821-
BIT_ULL(INTEL_PMC_IDX_FIXED + fixed_ctr_idx));
767+
wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, FIXED_PMC_CTRL(idx, FIXED_PMC_KERNEL));
768+
wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, FIXED_PMC_GLOBAL_CTRL_ENABLE(idx));
822769
__asm__ __volatile__("loop ." : "+c"((int){NUM_BRANCHES}));
823770
wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0);
824771

825-
GUEST_SYNC(rdmsr(MSR_CORE_PERF_FIXED_CTR0 + fixed_ctr_idx));
772+
GUEST_SYNC(rdmsr(MSR_CORE_PERF_FIXED_CTR0 + idx));
826773
}
827774
}
828775

0 commit comments

Comments
 (0)