[PATCH 1/2] KVM: x86: Add CPUID cache for frequent X86_FEATURE_* guest lookups

From: Sean Christopherson
Date: Tue Jul 26 2022 - 12:20:37 EST


Implement a small "cache" for expediting guest_cpuid_has() lookups of
frequently used features. Guest CPUID lookups are slow, especially if
the associated leaf has no entry, as KVM uses a linear walk of all CPUID
entries to find the associated leaf, e.g. adding a guest_cpuid_has()
lookup in the VM-Enter path is slow enough that it shows up on perf
traces.

Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx>
---
arch/x86/include/asm/kvm_host.h | 1 +
arch/x86/kvm/cpuid.c | 9 +++++++++
arch/x86/kvm/cpuid.h | 28 ++++++++++++++++++++++++++--
3 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index e8281d64a431..8cdb5c46815d 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -759,6 +759,7 @@ struct kvm_vcpu_arch {
int cpuid_nent;
struct kvm_cpuid_entry2 *cpuid_entries;
u32 kvm_cpuid_base;
+ u32 kvm_cpuid_x86_feature_cache;

u64 reserved_gpa_bits;
int maxphyaddr;
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 75dcf7a72605..27b25fdb4335 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -377,6 +377,12 @@ u64 kvm_vcpu_reserved_gpa_bits_raw(struct kvm_vcpu *vcpu)
return rsvd_bits(cpuid_maxphyaddr(vcpu), 63);
}

+#define kvm_cpuid_cache_update(__vcpu, x86_feature) \
+do { \
+ if (__guest_cpuid_has(__vcpu, x86_feature)) \
+ (__vcpu)->arch.kvm_cpuid_x86_feature_cache |= BIT(KVM_CACHED_ ## x86_feature); \
+} while (0)
+
static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
int nent)
{
@@ -412,6 +418,9 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
vcpu->arch.cpuid_entries = e2;
vcpu->arch.cpuid_nent = nent;

+ /* Update the cache before doing anything else. */
+ vcpu->arch.kvm_cpuid_x86_feature_cache = 0;
+
kvm_update_kvm_cpuid_base(vcpu);
kvm_vcpu_after_set_cpuid(vcpu);

diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index b1658c0de847..49009d16022a 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -85,8 +85,21 @@ static __always_inline u32 *guest_cpuid_get_register(struct kvm_vcpu *vcpu,
return __cpuid_entry_get_reg(entry, cpuid.reg);
}

-static __always_inline bool guest_cpuid_has(struct kvm_vcpu *vcpu,
- unsigned int x86_feature)
+enum kvm_cpuid_cached_feature {
+ NR_KVM_CACHED_X86_FEATURES,
+};
+
+static __always_inline int guest_cpuid_get_cache_bit(unsigned int x86_feature)
+{
+ int cache_bytes = sizeof((struct kvm_vcpu_arch *)0)->kvm_cpuid_x86_feature_cache;
+
+ BUILD_BUG_ON(NR_KVM_CACHED_X86_FEATURES > cache_bytes * BITS_PER_BYTE);
+
+ return NR_KVM_CACHED_X86_FEATURES;
+}
+
+static __always_inline bool __guest_cpuid_has(struct kvm_vcpu *vcpu,
+ unsigned int x86_feature)
{
u32 *reg;

@@ -97,6 +110,17 @@ static __always_inline bool guest_cpuid_has(struct kvm_vcpu *vcpu,
return *reg & __feature_bit(x86_feature);
}

+static __always_inline bool guest_cpuid_has(struct kvm_vcpu *vcpu,
+ unsigned int x86_feature)
+{
+ int cache_bit = guest_cpuid_get_cache_bit(x86_feature);
+
+ if (cache_bit != NR_KVM_CACHED_X86_FEATURES)
+ return vcpu->arch.kvm_cpuid_x86_feature_cache & BIT(cache_bit);
+
+ return __guest_cpuid_has(vcpu, x86_feature);
+}
+
static __always_inline void guest_cpuid_clear(struct kvm_vcpu *vcpu,
unsigned int x86_feature)
{

base-commit: 1a4d88a361af4f2e91861d632c6a1fe87a9665c2
--
2.37.1.455.g008518b4e5-goog


--dx/GFEplJzZRgpXz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="0002-KVM-x86-Cache-guest-CPUID-s-PDMC-for-fast-lookup.patch"