From: Colton Lewis <coltonlewis@google.com>
To: kvm@vger.kernel.org
Cc: Mingwei Zhang <mizhang@google.com>,
Jinrong Liang <ljr.kernel@gmail.com>,
Jim Mattson <jmattson@google.com>,
Aaron Lewis <aaronlewis@google.com>,
Sean Christopherson <seanjc@google.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Shuah Khan <shuah@kernel.org>,
linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org,
Colton Lewis <coltonlewis@google.com>
Subject: [PATCH 5/6] KVM: x86: selftests: Test core events
Date: Tue, 13 Aug 2024 16:42:43 +0000 [thread overview]
Message-ID: <20240813164244.751597-6-coltonlewis@google.com> (raw)
In-Reply-To: <20240813164244.751597-1-coltonlewis@google.com>
Test events on core counters by iterating through every combination of
events in amd_pmu_zen_events with every core counter.
For each combination, calculate the appropriate register addresses for
the event selection/control register and the counter register. The
base addresses and layout schemes change depending on whether we have
the CoreExt feature.
To do the testing, reuse GUEST_TEST_EVENT to run a standard known
workload. Decouple it from guest_assert_event_count (now
guest_assert_intel_event_count) to generalize to AMD.
Then assert the most specific detail that can be reasonably known
about the counter result. Exact count is defined and known for some
events and for other events merely asserted to be nonzero.
Note on exact counts: AMD counts one more branch than Intel for the
same workload. Though I can't confirm a reason, the only thing it
could be is the boundary of the loop instruction being counted
differently. Presumably, when the counter reaches 0 and execution
continues to the next instruction, AMD counts this as a branch and
Intel doesn't.
Signed-off-by: Colton Lewis <coltonlewis@google.com>
---
.../selftests/kvm/x86_64/pmu_counters_test.c | 87 ++++++++++++++++---
1 file changed, 77 insertions(+), 10 deletions(-)
diff --git a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c
index 9620fc33d26e..fae078b444b3 100644
--- a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c
+++ b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c
@@ -29,6 +29,9 @@
/* Total number of instructions retired within the measured section. */
#define NUM_INSNS_RETIRED (NUM_LOOPS * NUM_INSNS_PER_LOOP + NUM_EXTRA_INSNS)
+/* AMD counting one extra branch. Probably at loop boundary condition. */
+#define NUM_BRANCH_INSNS_RETIRED_AMD (NUM_LOOPS+1)
+#define NUM_INSNS_RETIRED_AMD (NUM_INSNS_RETIRED+1)
static uint8_t kvm_pmu_version;
static bool kvm_has_perf_caps;
@@ -98,7 +101,7 @@ static uint8_t guest_get_pmu_version(void)
* Sanity check that in all cases, the event doesn't count when it's disabled,
* and that KVM correctly emulates the write of an arbitrary value.
*/
-static void guest_assert_event_count(uint8_t idx,
+static void guest_assert_intel_event_count(uint8_t idx,
struct kvm_x86_pmu_feature event,
uint32_t pmc, uint32_t pmc_msr)
{
@@ -140,6 +143,33 @@ static void guest_assert_event_count(uint8_t idx,
GUEST_ASSERT_EQ(_rdpmc(pmc), 0xdead);
}
+static void guest_assert_amd_event_count(uint8_t evt_idx, uint8_t cnt_idx, uint32_t pmc_msr)
+{
+ uint64_t count;
+ uint64_t count_pmc;
+
+ count = rdmsr(pmc_msr);
+ count_pmc = _rdpmc(cnt_idx);
+ GUEST_ASSERT_EQ(count, count_pmc);
+
+ switch (evt_idx) {
+ case AMD_ZEN_CORE_CYCLES_INDEX:
+ GUEST_ASSERT_NE(count, 0);
+ break;
+ case AMD_ZEN_INSTRUCTIONS_INDEX:
+ GUEST_ASSERT_EQ(count, NUM_INSNS_RETIRED_AMD);
+ break;
+ case AMD_ZEN_BRANCHES_INDEX:
+ GUEST_ASSERT_EQ(count, NUM_BRANCH_INSNS_RETIRED_AMD);
+ break;
+ case AMD_ZEN_BRANCH_MISSES_INDEX:
+ GUEST_ASSERT_NE(count, 0);
+ break;
+ default:
+ break;
+ }
+
+}
/*
* Enable and disable the PMC in a monolithic asm blob to ensure that the
* compiler can't insert _any_ code into the measured sequence. Note, ECX
@@ -172,28 +202,29 @@ do { \
); \
} while (0)
-#define GUEST_TEST_EVENT(_idx, _event, _pmc, _pmc_msr, _ctrl_msr, _value, FEP) \
+#define GUEST_TEST_EVENT(_pmc_msr, _ctrl_msr, _ctrl_value, FEP) \
do { \
wrmsr(_pmc_msr, 0); \
\
if (this_cpu_has(X86_FEATURE_CLFLUSHOPT)) \
- GUEST_MEASURE_EVENT(_ctrl_msr, _value, "clflushopt .", FEP); \
+ GUEST_MEASURE_EVENT(_ctrl_msr, _ctrl_value, "clflushopt .", FEP); \
else if (this_cpu_has(X86_FEATURE_CLFLUSH)) \
- GUEST_MEASURE_EVENT(_ctrl_msr, _value, "clflush .", FEP); \
+ GUEST_MEASURE_EVENT(_ctrl_msr, _ctrl_value, "clflush .", FEP); \
else \
- GUEST_MEASURE_EVENT(_ctrl_msr, _value, "nop", FEP); \
- \
- guest_assert_event_count(_idx, _event, _pmc, _pmc_msr); \
+ GUEST_MEASURE_EVENT(_ctrl_msr, _ctrl_value, "nop", FEP); \
} while (0)
static void __guest_test_arch_event(uint8_t idx, struct kvm_x86_pmu_feature event,
uint32_t pmc, uint32_t pmc_msr,
uint32_t ctrl_msr, uint64_t ctrl_msr_value)
{
- GUEST_TEST_EVENT(idx, event, pmc, pmc_msr, ctrl_msr, ctrl_msr_value, "");
+ GUEST_TEST_EVENT(pmc_msr, ctrl_msr, ctrl_msr_value, "");
+ guest_assert_intel_event_count(idx, event, pmc, pmc_msr);
- if (is_forced_emulation_enabled)
- GUEST_TEST_EVENT(idx, event, pmc, pmc_msr, ctrl_msr, ctrl_msr_value, KVM_FEP);
+ if (is_forced_emulation_enabled) {
+ GUEST_TEST_EVENT(pmc_msr, ctrl_msr, ctrl_msr_value, KVM_FEP);
+ guest_assert_intel_event_count(idx, event, pmc, pmc_msr);
+ }
}
#define X86_PMU_FEATURE_NULL \
@@ -684,9 +715,45 @@ static void guest_test_rdwr_core_counters(void)
}
}
+static void __guest_test_core_event(uint8_t event_idx, uint8_t counter_idx)
+{
+ /* One fortunate area of actual compatibility! This register
+ * layout is the same for both AMD and Intel.
+ */
+ uint64_t eventsel = ARCH_PERFMON_EVENTSEL_OS |
+ ARCH_PERFMON_EVENTSEL_ENABLE |
+ amd_pmu_zen_events[event_idx];
+ bool core_ext = this_cpu_has(X86_FEATURE_PERF_CTR_EXT_CORE);
+ uint64_t esel_msr_base = core_ext ? MSR_F15H_PERF_CTL : MSR_K7_EVNTSEL0;
+ uint64_t cnt_msr_base = core_ext ? MSR_F15H_PERF_CTR : MSR_K7_PERFCTR0;
+ uint64_t msr_step = core_ext ? 2 : 1;
+ uint64_t esel_msr = esel_msr_base + msr_step * counter_idx;
+ uint64_t cnt_msr = cnt_msr_base + msr_step * counter_idx;
+
+ GUEST_TEST_EVENT(cnt_msr, esel_msr, eventsel, "");
+ guest_assert_amd_event_count(event_idx, counter_idx, cnt_msr);
+
+ if (is_forced_emulation_enabled) {
+ GUEST_TEST_EVENT(cnt_msr, esel_msr, eventsel, KVM_FEP);
+ guest_assert_amd_event_count(event_idx, counter_idx, cnt_msr);
+ }
+
+}
+
+static void guest_test_core_events(void)
+{
+ uint8_t nr_counters = this_cpu_property(X86_PROPERTY_NUM_PERF_CTR_CORE);
+
+ for (uint8_t i = 0; i < NR_AMD_ZEN_EVENTS; i++) {
+ for (uint8_t j = 0; j < nr_counters; j++)
+ __guest_test_core_event(i, j);
+ }
+}
+
static void guest_test_core_counters(void)
{
guest_test_rdwr_core_counters();
+ guest_test_core_events();
GUEST_DONE();
}
--
2.46.0.76.ge559c4bf1a-goog
next prev parent reply other threads:[~2024-08-13 16:43 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-13 16:42 [PATCH 0/6] Extend pmu_counters_test to AMD CPUs Colton Lewis
2024-08-13 16:42 ` [PATCH 1/6] KVM: x86: selftests: Fix typos in macro variable use Colton Lewis
2024-08-21 18:21 ` Mingwei Zhang
2024-08-28 21:24 ` Colton Lewis
2024-08-13 16:42 ` [PATCH 2/6] KVM: x86: selftests: Define AMD PMU CPUID leaves Colton Lewis
2024-08-26 22:27 ` Mingwei Zhang
2024-08-28 22:24 ` Colton Lewis
2024-08-29 20:25 ` Sean Christopherson
2024-08-13 16:42 ` [PATCH 3/6] KVM: x86: selftests: Set up AMD VM in pmu_counters_test Colton Lewis
2024-08-26 22:43 ` Mingwei Zhang
2024-08-28 22:39 ` Colton Lewis
2024-08-28 23:18 ` Mingwei Zhang
2024-08-29 20:45 ` Sean Christopherson
2024-09-02 18:37 ` Colton Lewis
2024-08-13 16:42 ` [PATCH 4/6] KVM: x86: selftests: Test read/write core counters Colton Lewis
2024-08-13 16:42 ` Colton Lewis [this message]
2024-08-13 16:42 ` [PATCH 6/6] KVM: x86: selftests: Test PerfMonV2 Colton Lewis
2024-08-13 17:36 ` [PATCH 0/6] Extend pmu_counters_test to AMD CPUs Sean Christopherson
2024-08-13 20:09 ` Colton Lewis
2024-08-14 1:03 ` Sean Christopherson
2024-08-14 16:58 ` Colton Lewis
-- strict thread matches above, loose matches on Subject: below --
2024-08-02 18:22 [PATCH 0/7] " Colton Lewis
2024-08-02 18:22 ` [PATCH 5/6] KVM: x86: selftests: Test core events Colton Lewis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240813164244.751597-6-coltonlewis@google.com \
--to=coltonlewis@google.com \
--cc=aaronlewis@google.com \
--cc=jmattson@google.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=ljr.kernel@gmail.com \
--cc=mizhang@google.com \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
--cc=shuah@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox