Skip to contentSkip to conversation

Infrastructure for software and hardware based TSC rate scaling

PATCH In review Zachary Amsden 1 participant 1 message Jun 21, 2011

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/9 Infrastructure for software and hardware based TSC rate scaling

-------- Original Message --------
Subject: [KVM TSC emulation 1/9] Infrastructure for software and hardware based TSC rate scaling
Date: Mon, 20 Jun 2011 16:59:29 -0700
From: Zachary Amsden <[email protected]>
To: Avi Kivity <[email protected]>, Marcelo Tosatti <[email protected]>, Glauber Costa <[email protected]>, Frank Arnold <[email protected]>, Joerg Roedel <[email protected]>, Jan Kiszka <[email protected]>, [email protected], [email protected], Zachary Amsden <[email protected]>, Avi Kivity <[email protected]>, Marcelo Tosatti <[email protected]>, Glauber Costa <[email protected]>, Frank Arnold <[email protected]>, Joerg Roedel <[email protected]>, Jan Kiszka <[email protected]>, [email protected]
CC: Zachary Amsden <[email protected]>, Zachary Amsden <[email protected]>

This requires some restructuring; rather than use 'virtual_tsc_khz' to indicate whether hardware rate scaling is in effect, we consider each VCPU to always have a virtual TSC rate. Instead, there is new logic above the vendor-specific hardware scaling that decides whether it is even necessary to use and updates all rate variables used by common code. This means we can simply query the virtual rate at any point, which is needed for software rate scaling.

There is also now a threshold added to the TSC rate scaling; minor differences and variations of measured TSC rate can accidentally provoke rate scaling to be used when it is not needed. Instead, we have a tolerance variable called tsc_tolerance_ppm, which is the maximum variation from user requested rate at which scaling will be used. The default is 250ppm, which is the half the threshold for NTP adjustment, allowing for some hardware variation.

In the event that hardware rate scaling is not available, we can kludge a bit by forcing TSC catchup to turn on when a faster than hardware speed has been requested, but there is nothing available yet for the reverse case; this requires a trap and emulate software implementation for RDTSC, which is still forthcoming.

---
 arch/x86/include/asm/kvm_host.h |    9 ++--
 arch/x86/kvm/svm.c              |   20 ++++++----
 arch/x86/kvm/vmx.c              |   16 +++++--
 arch/x86/kvm/x86.c              |   82 ++++++++++++++++++--------------------
 include/linux/kvm.h             |    1 +
 5 files changed, 68 insertions(+), 60 deletions(-)
arch/x86/include/asm/kvm_host.h +5 -4
index da6bbee..184cd38 100644
@@ -393,10 +393,11 @@ struct kvm_vcpu_arch {
 	u64 last_kernel_ns;
 	u64 last_tsc_nsec;
 	u64 last_tsc_write;
-	u32 virtual_tsc_khz;
 	bool tsc_catchup;
-	u32  tsc_catchup_mult;
-	s8   tsc_catchup_shift;
+	bool tsc_always_catchup;
+	s8 virtual_tsc_shift;
+	u32 virtual_tsc_mult;
+	u32 virtual_tsc_khz;
 
 	bool nmi_pending;
 	bool nmi_injected;
@@ -604,7 +605,7 @@ struct kvm_x86_ops {
 
 	bool (*has_wbinvd_exit)(void);
 
-	void (*set_tsc_khz)(struct kvm_vcpu *vcpu, u32 user_tsc_khz);
+	void (*set_tsc_khz)(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale);
 	void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
 
 	u64 (*compute_tsc_offset)(struct kvm_vcpu *vcpu, u64 target_tsc);
arch/x86/kvm/svm.c +12 -8
index 475d1c9..47f557e 100644
@@ -905,20 +905,25 @@ static u64 svm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
 	return _tsc;
 }
 
-static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
+static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
 	u64 ratio;
 	u64 khz;
 
-	/* TSC scaling supported? */
-	if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR))
+	/* Guest TSC same frequency as host TSC? */
+	if (!scale) {
+		svm->tsc_ratio = TSC_RATIO_DEFAULT;
 		return;
+	}
 
-	/* TSC-Scaling disabled or guest TSC same frequency as host TSC? */
-	if (user_tsc_khz == 0) {
-		vcpu->arch.virtual_tsc_khz = 0;
-		svm->tsc_ratio = TSC_RATIO_DEFAULT;
+	/* TSC scaling supported? */
+	if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR)) {
+		if (user_tsc_khz>  tsc_khz) {
+			vcpu->arch.tsc_catchup = 1;
+			vcpu->arch.tsc_always_catchup = 1;
+		} else
+			WARN(1, "user requested TSC rate below hardware speed\n");
 		return;
 	}
 
@@ -933,7 +938,6 @@ static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
 				user_tsc_khz);
 		return;
 	}
-	vcpu->arch.virtual_tsc_khz = user_tsc_khz;
 	svm->tsc_ratio             = ratio;
 }
 
arch/x86/kvm/vmx.c +11 -5
index f5b49c7..bc3ecfd 100644
@@ -1751,13 +1751,19 @@ static u64 guest_read_tsc(void)
 }
 
 /*
- * Empty call-back. Needs to be implemented when VMX enables the SET_TSC_KHZ
- * ioctl. In this case the call-back should update internal vmx state to make
- * the changes effective.
+ * Engage any workarounds for mis-matched TSC rates.  Currently limited to
+ * software catchup for faster rates on slower CPUs.
  */
-static void vmx_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
+static void vmx_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
 {
-	/* Nothing to do here */
+	if (!scale)
+		return;
+
+	if (user_tsc_khz>  tsc_khz) {
+		vcpu->arch.tsc_catchup = 1;
+		vcpu->arch.tsc_always_catchup = 1;
+	} else
+		WARN(1, "user requested TSC rate below hardware speed\n");
 }
 
 /*
arch/x86/kvm/x86.c +39 -43

146 lines not on this page · raw message

include/linux/kvm.h +1 -0
index 9c9ca7c..31adf3d 100644
@@ -544,6 +544,7 @@ struct kvm_ppc_pvinfo {
 #define KVM_CAP_TSC_CONTROL 60
 #define KVM_CAP_GET_TSC_KHZ 61
 #define KVM_CAP_PPC_BOOKE_SREGS 62
+#define KVM_CAP_SET_TSC_KHZ 63
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
Signature · 1 line
1.7.1