2023-05-30 14:22:03

by Jinrong Liang

[permalink] [raw]
Subject: [PATCH v2 0/8] KVM: selftests: Test the consistency of the PMU's CPUID and its features

Hi,

The KVM selftests show advantages over KUT in terms of finding defects through
flexible and varied guest settings from the KVM user space.

This patchset tests whether the Intel vPMU works properly with different Intel
CPUID.0xA configurations. It also provides test scaffolding and a sufficient
number of PMU test cases to subsequently offer adequate code coverage of AMD
vPMU or Intel complex features, such as LBR or PEBS, in selftests.

Please feel free to add more tests or share valuable comments.

Thanks

v2:
- Rebased to 5c291b93e5d6(tag: kvm-x86-next-2023.04.26)
- Added a new patch to add macros to processor.h to obtain the number of fixed
counters and fixed counters bit mask. (Sean)
- Added a new patch to introduce a new pmu.h header file to better organize the
PMU performance event constants and common masks. (Sean)
- Changed the file name to pmu_basic_functionality_test. (Sean)
- Replaced new_vcpu() with the new function pmu_vm_create_with_one_vcpu() and
replaced free_vcpu() wrapper with kvm_vm_free(). (Sean)
- Modified the run_vcpu() wrapper to return the first ucall param. (Sean)
- Defined KVM_X86_CPU_PROPERTY macros where possible to avoid opening code in
multiple places. (Sean)
- Optimized the comment. (Sean, Jim)
- Modified the guest logic to have the guest return the counter value and
perform the assert in kvm user space. (Sean)
- Used goto instead of the ternary operator in intel_guest_run_arch_event(). (Sean)
- Added a test to check that KVM drops writes to MSR_P6_PERFCTR[0|1]. (Sean)
- Used rdmsr_safe() and/or wrmsr_safe() instead of installing a dedicated handler. (Sean)
- Optimized variables that do not need to be initialized. (Sean)
- Removed patch KVM: selftests: Test Intel counters' bit width emulation.

Previous:
https://lore.kernel.org/kvm/[email protected]/T/#u

Jinrong Liang (5):
KVM: selftests: Add macros for fixed counters in processor.h
KVM: selftests: Add pmu.h for PMU events and common masks
KVM: selftests: Test Intel PMU architectural events on fixed counters
KVM: selftests: Test consistency of CPUID with num of fixed counters
KVM: selftests: Test consistency of PMU MSRs with Intel PMU version

Like Xu (3):
KVM: selftests: Test Intel PMU architectural events on gp counters
KVM: selftests: Test consistency of CPUID with num of gp counters
KVM: selftests: Test Intel supported fixed counters bit mask

tools/testing/selftests/kvm/Makefile | 1 +
.../selftests/kvm/include/x86_64/pmu.h | 56 +++
.../selftests/kvm/include/x86_64/processor.h | 2 +
.../kvm/x86_64/pmu_basic_functionality_test.c | 455 ++++++++++++++++++
4 files changed, 514 insertions(+)
create mode 100644 tools/testing/selftests/kvm/include/x86_64/pmu.h
create mode 100644 tools/testing/selftests/kvm/x86_64/pmu_basic_functionality_test.c


base-commit: 5c291b93e5d665380dbecc6944973583f9565ee5
--
2.31.1



2023-05-30 14:23:55

by Jinrong Liang

[permalink] [raw]
Subject: [PATCH v2 4/8] KVM: selftests: Test Intel PMU architectural events on fixed counters

From: Jinrong Liang <[email protected]>

Update test to cover Intel PMU architectural events on fixed counters.
Per Intel SDM, PMU users can also count architecture performance events
on fixed counters (specifically, FIXED_CTR0 for the retired instructions
and FIXED_CTR1 for cpu core cycles event). Therefore, if guest's CPUID
indicates that an architecture event is not available, the corresponding
fixed counter will also not count that event.

Co-developed-by: Like Xu <[email protected]>
Signed-off-by: Like Xu <[email protected]>
Signed-off-by: Jinrong Liang <[email protected]>
---
.../kvm/x86_64/pmu_basic_functionality_test.c | 28 +++++++++++++++++--
1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/kvm/x86_64/pmu_basic_functionality_test.c b/tools/testing/selftests/kvm/x86_64/pmu_basic_functionality_test.c
index 1f100fd94d67..81029d05367a 100644
--- a/tools/testing/selftests/kvm/x86_64/pmu_basic_functionality_test.c
+++ b/tools/testing/selftests/kvm/x86_64/pmu_basic_functionality_test.c
@@ -47,7 +47,8 @@ static uint64_t run_vcpu(struct kvm_vcpu *vcpu, uint64_t *ucall_arg)
}

static void intel_guest_run_arch_event(uint8_t version, uint8_t max_gp_num,
- uint32_t ctr_base_msr, uint64_t evt_code)
+ uint32_t ctr_base_msr, uint64_t evt_code,
+ uint8_t max_fixed_num)
{
uint32_t global_msr = MSR_CORE_PERF_GLOBAL_CTRL;
unsigned int i;
@@ -66,6 +67,27 @@ static void intel_guest_run_arch_event(uint8_t version, uint8_t max_gp_num,
GUEST_SYNC(_rdpmc(i));
}

+ /* No need to test independent arch events on fixed counters. */
+ if (version <= 1 || max_fixed_num <= 1)
+ goto done;
+
+ if (evt_code == evt_code_for_fixed_ctr(0))
+ i = 0;
+ else if (evt_code == evt_code_for_fixed_ctr(1))
+ i = 1;
+ else
+ goto done;
+
+ wrmsr(MSR_CORE_PERF_FIXED_CTR0 + i, 0);
+ wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, BIT_ULL(4 * i));
+ wrmsr(global_msr, BIT_ULL(INTEL_PMC_IDX_FIXED + i));
+
+ __asm__ __volatile__("loop ." : "+c"((int){NUM_BRANCHES}));
+
+ wrmsr(global_msr, 0);
+ GUEST_SYNC(_rdpmc(RDPMC_FIXED_BASE | i));
+
+done:
GUEST_DONE();
}

@@ -90,8 +112,8 @@ static void test_arch_events_cpuid(struct kvm_vcpu *vcpu, uint8_t evt_vector,
is_supported = !(entry->ebx & BIT_ULL(idx)) &&
(((entry->eax & EVT_LEN_MASK) >> EVT_LEN_OFS_BIT) > idx);

- vcpu_args_set(vcpu, 4, X86_INTEL_PMU_VERSION, X86_INTEL_MAX_GP_CTR_NUM,
- ctr_msr, arch_events[idx]);
+ vcpu_args_set(vcpu, 5, X86_INTEL_PMU_VERSION, X86_INTEL_MAX_GP_CTR_NUM,
+ ctr_msr, arch_events[idx], X86_INTEL_MAX_FIXED_CTR_NUM);

while (run_vcpu(vcpu, &counter_val) != UCALL_DONE)
TEST_ASSERT(is_supported == !!counter_val,
--
2.31.1


2023-05-30 14:24:36

by Jinrong Liang

[permalink] [raw]
Subject: [PATCH v2 6/8] KVM: selftests: Test consistency of CPUID with num of fixed counters

From: Jinrong Liang <[email protected]>

Add test to check if non-existent counters can be accessed in guest after
determining the number of Intel generic performance counters by CPUID.
Per SDM, fixed-function performance counter 'i' is supported if ECX[i] ||
(EDX[4:0] > i). KVM doesn't emulate more counters than it can support.

Co-developed-by: Like Xu <[email protected]>
Signed-off-by: Like Xu <[email protected]>
Signed-off-by: Jinrong Liang <[email protected]>
---
.../kvm/x86_64/pmu_basic_functionality_test.c | 42 +++++++++++++++++++
1 file changed, 42 insertions(+)

diff --git a/tools/testing/selftests/kvm/x86_64/pmu_basic_functionality_test.c b/tools/testing/selftests/kvm/x86_64/pmu_basic_functionality_test.c
index 116437ac2095..e19f8c2774c5 100644
--- a/tools/testing/selftests/kvm/x86_64/pmu_basic_functionality_test.c
+++ b/tools/testing/selftests/kvm/x86_64/pmu_basic_functionality_test.c
@@ -228,10 +228,46 @@ static void test_oob_gp_counter(uint8_t eax_gp_num, uint8_t offset,
kvm_vm_free(vm);
}

+static void intel_test_oob_fixed_ctr(uint8_t edx_fix_num,
+ uint32_t fixed_bitmask, uint64_t expected)
+{
+ struct kvm_vm *vm;
+ struct kvm_vcpu *vcpu;
+ struct kvm_cpuid_entry2 *entry;
+ uint8_t idx = edx_fix_num;
+ bool visible;
+ uint64_t msr_val;
+
+ vm = pmu_vm_create_with_one_vcpu(&vcpu, guest_wr_and_rd_msrs);
+
+ entry = vcpu_get_cpuid_entry(vcpu, 0xa);
+ entry->ecx = fixed_bitmask;
+ entry->edx = (entry->edx & ~FIXED_CTR_NUM_MASK) | edx_fix_num;
+ vcpu_set_cpuid(vcpu);
+
+ /* Per Intel SDM, FxCtr[i]_is_supported := ECX[i] || (EDX[4:0] > i). */
+ visible = (entry->ecx & BIT_ULL(idx) ||
+ ((entry->edx & FIXED_CTR_NUM_MASK) > idx));
+
+ /* KVM doesn't emulate more fixed counters than it can support. */
+ if (idx >= X86_INTEL_MAX_FIXED_CTR_NUM)
+ visible = false;
+
+ vcpu_args_set(vcpu, 4, MSR_CORE_PERF_FIXED_CTR0, 0xffff, idx, 1);
+ if (!visible)
+ while (run_vcpu(vcpu, &msr_val) != UCALL_DONE)
+ TEST_ASSERT(msr_val == expected,
+ "Unexpected when testing fixed counter num.");
+
+ kvm_vm_free(vm);
+}
+
static void intel_test_counters_num(void)
{
unsigned int i;
+ uint32_t ecx;
uint8_t kvm_gp_num = X86_INTEL_MAX_GP_CTR_NUM;
+ uint8_t kvm_fixed_num = X86_INTEL_MAX_FIXED_CTR_NUM;

TEST_REQUIRE(kvm_gp_num > 2);

@@ -254,6 +290,12 @@ static void intel_test_counters_num(void)
if (perf_caps[i] == 0)
test_oob_gp_counter(0, 2, perf_caps[i], 0);
}
+
+ for (ecx = 0; ecx <= X86_INTEL_FIXED_CTRS_BITMASK + 1; ecx++) {
+ intel_test_oob_fixed_ctr(0, ecx, GP_VECTOR);
+ intel_test_oob_fixed_ctr(kvm_fixed_num, ecx, GP_VECTOR);
+ intel_test_oob_fixed_ctr(kvm_fixed_num + 1, ecx, GP_VECTOR);
+ }
}

static void intel_test_pmu_cpuid(void)
--
2.31.1


2023-06-28 21:10:28

by Sean Christopherson

[permalink] [raw]
Subject: Re: [PATCH v2 6/8] KVM: selftests: Test consistency of CPUID with num of fixed counters

On Tue, May 30, 2023, Jinrong Liang wrote:
> From: Jinrong Liang <[email protected]>
>
> Add test to check if non-existent counters can be accessed in guest after
> determining the number of Intel generic performance counters by CPUID.
> Per SDM, fixed-function performance counter 'i' is supported if ECX[i] ||
> (EDX[4:0] > i). KVM doesn't emulate more counters than it can support.
>
> Co-developed-by: Like Xu <[email protected]>
> Signed-off-by: Like Xu <[email protected]>
> Signed-off-by: Jinrong Liang <[email protected]>
> ---
> .../kvm/x86_64/pmu_basic_functionality_test.c | 42 +++++++++++++++++++
> 1 file changed, 42 insertions(+)
>
> diff --git a/tools/testing/selftests/kvm/x86_64/pmu_basic_functionality_test.c b/tools/testing/selftests/kvm/x86_64/pmu_basic_functionality_test.c
> index 116437ac2095..e19f8c2774c5 100644
> --- a/tools/testing/selftests/kvm/x86_64/pmu_basic_functionality_test.c
> +++ b/tools/testing/selftests/kvm/x86_64/pmu_basic_functionality_test.c
> @@ -228,10 +228,46 @@ static void test_oob_gp_counter(uint8_t eax_gp_num, uint8_t offset,
> kvm_vm_free(vm);
> }
>
> +static void intel_test_oob_fixed_ctr(uint8_t edx_fix_num,
> + uint32_t fixed_bitmask, uint64_t expected)
> +{
> + struct kvm_vm *vm;
> + struct kvm_vcpu *vcpu;
> + struct kvm_cpuid_entry2 *entry;
> + uint8_t idx = edx_fix_num;
> + bool visible;
> + uint64_t msr_val;
> +
> + vm = pmu_vm_create_with_one_vcpu(&vcpu, guest_wr_and_rd_msrs);
> +
> + entry = vcpu_get_cpuid_entry(vcpu, 0xa);
> + entry->ecx = fixed_bitmask;
> + entry->edx = (entry->edx & ~FIXED_CTR_NUM_MASK) | edx_fix_num;
> + vcpu_set_cpuid(vcpu);
> +
> + /* Per Intel SDM, FxCtr[i]_is_supported := ECX[i] || (EDX[4:0] > i). */
> + visible = (entry->ecx & BIT_ULL(idx) ||
> + ((entry->edx & FIXED_CTR_NUM_MASK) > idx));

Add a helper (in pmu.h) for this one too.

> + /* KVM doesn't emulate more fixed counters than it can support. */
> + if (idx >= X86_INTEL_MAX_FIXED_CTR_NUM)
> + visible = false;
> +
> + vcpu_args_set(vcpu, 4, MSR_CORE_PERF_FIXED_CTR0, 0xffff, idx, 1);
> + if (!visible)

Curly braces need around a multi-line statement.

> + while (run_vcpu(vcpu, &msr_val) != UCALL_DONE)
> + TEST_ASSERT(msr_val == expected,
> + "Unexpected when testing fixed counter num.");

ASSERT_EQ() will print the expected versus actually for you.