Skip to contentSkip to conversation

Sync TSC for guest when vcpu has been migrated to another cpu

PATCH In review Leonard Norrgard 4 participants 8 messages Mar 2, 2007 – Mar 3, 2007 4 messages not in the archive KVM

lore
Share & tools
lore
#0 lore raw

cover Sync TSC for guest when vcpu has been migrated to another cpu

When a vcpu is migrated to another cpu, an unexpected difference in current and previous cpu TSC values can cause a guest to wait indefinitely. A known workaround has been to run kvm with taskset, locking it to a single cpu. This patch series modifies the guest TSC offset as needed to guarantee that the guest sees a monotonically increasing TSC, adds a statistic for vcpu_migrated and updates kvm_stat so the first column isn't truncated.

[1/3] Sync guest viewable TSC when vcpu migrated
[2/3] Add a vcpu_migrated statistic
[3/3] Widen key column in kvm_stat

-- Leonard

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

A message that is not in the archive (sent off-list or not yet received): 45E853A0.3080207-g2GXA8XeJSExHbG02/[email protected]

#2 lore raw

PATCH 1/3 Sync guest viewable TSC when vcpu migrated

When a vcpu is migrated to another cpu, an unexpected difference in current and previous cpu TSC values can cause a guest to wait indefinitely. A known workaround has been to run kvm with taskset, locking it to a single cpu. This patch modifies the guest viewable TSC so that the TSC is guaranteed to be monotonically increasing.

Thanks to Avi Kivity for help in pinpointing this issue and advice for fixing it.

drivers/kvm/svm.c +37 -1
Index: linux-2.6/drivers/kvm/svm.c
===================================================================
@@ -598,9 +598,45 @@
 	kfree(vcpu->svm);
 }
 
+#ifdef CONFIG_SMP
+static void ipi_rdtscll(void *arg)
+{
+	u64 *tsc = arg;
+	rdtscll(*tsc);
+}
+#endif
+
+/*
+ * Switches to specified vcpu, until a matching vcpu_put(), but assumes
+ * vcpu mutex is already taken.
+ */
 static struct kvm_vcpu *svm_vcpu_load(struct kvm_vcpu *vcpu)
 {
-	get_cpu();
+	int cpu;
+
+	cpu = get_cpu();
+
+#ifdef CONFIG_SMP
+	if (vcpu->cpu != cpu) {
+		if (vcpu->cpu != -1) {
+			u64 tsc_this, tsc_previous;
+
+			/* Get TSC value for this and the previous cpu. */
+			rdtscll(tsc_this);
+			smp_call_function_single(vcpu->cpu, ipi_rdtscll,
+						 &tsc_previous, 0, 1);
+
+			/*
+			 * Make sure that the guest sees a monotonically
+			 * increasing TSC.
+			 */
+			vcpu->svm->vmcb->control.tsc_offset +=
+						tsc_previous - tsc_this;
+		}
+	}
+#endif
+
+	vcpu->cpu = cpu;
 	return vcpu;
 }
 
drivers/kvm/vmx.c +27 -0
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -200,6 +200,14 @@
 #endif
 }
 
+#ifdef CONFIG_SMP
+static void ipi_rdtscll(void *arg)
+{
+	u64 *tsc = arg;
+	rdtscll(*tsc);
+}
+#endif
+
 /*
  * Switches to specified vcpu, until a matching vcpu_put(), but assumes
  * vcpu mutex is already taken.
@@ -230,6 +238,25 @@
 		struct descriptor_table dt;
 		unsigned long sysenter_esp;
 
+#ifdef CONFIG_SMP
+		if (vcpu->cpu != -1) {
+			u64 tsc_this, tsc_previous, guest_tsc_offset;
+
+			/* Get TSC value for this and the previous cpu. */
+			rdtscll(tsc_this);
+			smp_call_function_single(vcpu->cpu, ipi_rdtscll,
+						 &tsc_previous, 0, 1);
+
+			/*
+			 * Make sure that the guest sees a monotonically
+			 * increasing TSC.
+			 */
+			guest_tsc_offset = vmcs_read64(TSC_OFFSET);
+			vmcs_write64(TSC_OFFSET, guest_tsc_offset +
+				     		tsc_previous - tsc_this);
+		}
+#endif
+
 		vcpu->cpu = cpu;
 		/*
 		 * Linux uses per-cpu TSS and GDT, so set these when switching

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

_______________________________________________
kvm-devel mailing list [email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel

A message that is not in the archive (sent off-list or not yet received): 45E85566.3010706-g2GXA8XeJSExHbG02/[email protected]

#4 lore raw

Re: [PATCH 1/3] Sync guest viewable TSC when vcpu migrated

Quoted 11 lines · Leonard Norrgard

When a vcpu is migrated to another cpu, an unexpected difference in current and previous cpu TSC values can cause a guest to wait indefinitely. A known workaround has been to run kvm with taskset, locking it to a single cpu. This patch modifies the guest viewable TSC so that the TSC is guaranteed to be monotonically increasing.

Thanks to Avi Kivity for help in pinpointing this issue and advice for fixing it.

Hi Leonard,

Why not factor the common code into kvm_main.c and add a set_tsc_offset member to the kvm ops function table?

Regards,

Anthony Liguori

Quoted 108 lines

------------------------------------------------------------------------

Index: linux-2.6/drivers/kvm/svm.c
===================================================================

drivers/kvm/svm.c +37 -1
@@ -598,9 +598,45 @@
 	kfree(vcpu->svm);
 }
 
+#ifdef CONFIG_SMP
+static void ipi_rdtscll(void *arg)
+{
+	u64 *tsc = arg;
+	rdtscll(*tsc);
+}
+#endif
+
+/*
+ * Switches to specified vcpu, until a matching vcpu_put(), but assumes
+ * vcpu mutex is already taken.
+ */
 static struct kvm_vcpu *svm_vcpu_load(struct kvm_vcpu *vcpu)
 {
-	get_cpu();
+	int cpu;
+
+	cpu = get_cpu();
+
+#ifdef CONFIG_SMP
+	if (vcpu->cpu != cpu) {
+		if (vcpu->cpu != -1) {
+			u64 tsc_this, tsc_previous;
+
+			/* Get TSC value for this and the previous cpu. */
+			rdtscll(tsc_this);
+			smp_call_function_single(vcpu->cpu, ipi_rdtscll,
+						 &tsc_previous, 0, 1);
+
+			/*
+			 * Make sure that the guest sees a monotonically
+			 * increasing TSC.
+			 */
+			vcpu->svm->vmcb->control.tsc_offset +=
+						tsc_previous - tsc_this;
+		}
+	}
+#endif
+
+	vcpu->cpu = cpu;
 	return vcpu;
 }
 

Index: linux-2.6/drivers/kvm/vmx.c
===================================================================

drivers/kvm/vmx.c +27 -2
@@ -200,6 +200,14 @@
 #endif
 }
 
+#ifdef CONFIG_SMP
+static void ipi_rdtscll(void *arg)
+{
+	u64 *tsc = arg;
+	rdtscll(*tsc);
+}
+#endif
+
 /*
  * Switches to specified vcpu, until a matching vcpu_put(), but assumes
  * vcpu mutex is already taken.
@@ -230,6 +238,25 @@
 		struct descriptor_table dt;
 		unsigned long sysenter_esp;
 
+#ifdef CONFIG_SMP
+		if (vcpu->cpu != -1) {
+			u64 tsc_this, tsc_previous, guest_tsc_offset;
+
+			/* Get TSC value for this and the previous cpu. */
+			rdtscll(tsc_this);
+			smp_call_function_single(vcpu->cpu, ipi_rdtscll,
+						 &tsc_previous, 0, 1);
+
+			/*
+			 * Make sure that the guest sees a monotonically
+			 * increasing TSC.
+			 */
+			guest_tsc_offset = vmcs_read64(TSC_OFFSET);
+			vmcs_write64(TSC_OFFSET, guest_tsc_offset +
+				     		tsc_previous - tsc_this);
+		}
+#endif
+
 		vcpu->cpu = cpu;
 		/*
 		 * Linux uses per-cpu TSS and GDT, so set these when switching
 
------------------------------------------------------------------------
 
-------------------------------------------------------------------------

Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
------------------------------------------------------------------------

Quoted 5 lines

_______________________________________________
kvm-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
kvm-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel

A message that is not in the archive (sent off-list or not yet received): 45E85717.6030906-r/[email protected]

#6 lore raw

Re: [PATCH 1/3] Sync guest viewable TSC when vcpu migrated

Quoted 4 lines

Hi Leonard,

Why not factor the common code into kvm_main.c and add a set_tsc_offset member to the kvm ops function table?

Good idea, I put it on the todo list.

Quoted 3 lines

Regards,

Anthony Liguori

Thanks,

-- Leonard

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

#7 lore raw

Re: [PATCH 1/3] Sync guest viewable TSC when vcpu migrated

In reply to a message not in the archive

Thanks for picking this up! Some comments below.

Quoted 19 lines · Leonard Norrgard

Index: linux-2.6/drivers/kvm/svm.c
===================================================================

drivers/kvm/svm.c +11 -0
@@ -598,9 +598,45 @@
 	kfree(vcpu->svm);
 }
 
+#ifdef CONFIG_SMP
+static void ipi_rdtscll(void *arg)
+{
+	u64 *tsc = arg;
+	rdtscll(*tsc);
+}
+#endif
+
+/*
+ * Switches to specified vcpu, until a matching vcpu_put(), but assumes
+ * vcpu mutex is already taken.

drivers/kvm/svm.c line 620

Quoted 10 lines
drivers/kvm/svm.c +6 -1
+ */
 static struct kvm_vcpu *svm_vcpu_load(struct kvm_vcpu *vcpu)
 {
-	get_cpu();
+	int cpu;
+
+	cpu = get_cpu();
+
+#ifdef CONFIG_SMP
 

Please avoid such #ifdefs. Non-SMP virtualization capable processors are rare, and smp_call_function_single() is defined for the !CONFIG_SMP case.

Quoted 51 lines
drivers/kvm/svm.c +15 -0
+	if (vcpu->cpu != cpu) {
+		if (vcpu->cpu != -1) {
+			u64 tsc_this, tsc_previous;
+
+			/* Get TSC value for this and the previous cpu. */
+			rdtscll(tsc_this);
+			smp_call_function_single(vcpu->cpu, ipi_rdtscll,
+						 &tsc_previous, 0, 1);
+
+			/*
+			 * Make sure that the guest sees a monotonically
+			 * increasing TSC.
+			 */
+			vcpu->svm->vmcb->control.tsc_offset +=
+						tsc_previous - tsc_this;
 
 

Index: linux-2.6/drivers/kvm/vmx.c
===================================================================

drivers/kvm/vmx.c +18 -0
@@ -200,6 +200,14 @@
 #endif
 }
 
+#ifdef CONFIG_SMP
+static void ipi_rdtscll(void *arg)
+{
+	u64 *tsc = arg;
+	rdtscll(*tsc);
+}
+#endif
+
 /*
  * Switches to specified vcpu, until a matching vcpu_put(), but assumes
  * vcpu mutex is already taken.
@@ -230,6 +238,25 @@
 		struct descriptor_table dt;
 		unsigned long sysenter_esp;
 
+#ifdef CONFIG_SMP
+		if (vcpu->cpu != -1) {
+			u64 tsc_this, tsc_previous, guest_tsc_offset;
+
+			/* Get TSC value for this and the previous cpu. */
+			rdtscll(tsc_this);
+			smp_call_function_single(vcpu->cpu, ipi_rdtscll,
+						 &tsc_previous, 0, 1);
+
+			/*

drivers/kvm/vmx.c line 260

Quoted 10 lines
drivers/kvm/vmx.c +9 -0
+			 * Make sure that the guest sees a monotonically
+			 * increasing TSC.
+			 */
+			guest_tsc_offset = vmcs_read64(TSC_OFFSET);
+			vmcs_write64(TSC_OFFSET, guest_tsc_offset +
+				     		tsc_previous - tsc_this);
+		}
+#endif
+
 

The vmx code already has an IPI (in vcpu_clear), so the two should be merged. IPIs are very expensive.

Perhaps call a vmx_vcpu_migrate IPI, which calls __vcpu_clear() and loads the tsc. You can add a tsc_previous to struct kvm_vcpu so you have somewhere to store it.

Signature · 8 lines
Do not meddle in the internals of kernels, for they are subtle and quick to panic.


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
#8 lore raw

PATCH 2/3 Add a vcpu_migrated statistic

In reply to a message not in the archive

The previous patch introduces an IPI on every vcpu migration on SMP machines to find out the TSC value on the previous cpu. We might be able to avoid this IPI on systems that have a synchronized TSC by checking for it in svm/vmx_vcpu_load:

+ /* If this isn't the first vcpu_load and if the TSC
+ doesn't run at a constant rate, we must handle TSC
+ offsets. */
+ if (vcpu->cpu != -1
+ && !boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {

Wether this is actually reliable and working in the intended way is not know yet. In the meantime, introduce a statistic for vcpu migration, so we get some decision support for the needs for such an optimization.

drivers/kvm/kvm_main.c +1 -0
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -67,6 +67,7 @@
 	{ "halt_exits", &kvm_stat.halt_exits },
 	{ "request_irq", &kvm_stat.request_irq_exits },
 	{ "irq_exits", &kvm_stat.irq_exits },
+	{ "vcpu_migrated", &kvm_stat.vcpu_migrated },
 	{ NULL, NULL }
 };
 
drivers/kvm/svm.c +2 -0
Index: linux-2.6/drivers/kvm/svm.c
===================================================================
@@ -621,6 +621,8 @@
 		if (vcpu->cpu != -1) {
 			u64 tsc_this, tsc_previous;
 
+			++kvm_stat.vcpu_migrated;
+
 			/* Get TSC value for this and the previous cpu. */
 			rdtscll(tsc_this);
 			smp_call_function_single(vcpu->cpu, ipi_rdtscll,
drivers/kvm/vmx.c +2 -0
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -242,6 +242,8 @@
 		if (vcpu->cpu != -1) {
 			u64 tsc_this, tsc_previous, guest_tsc_offset;
 
+			++kvm_stat.vcpu_migrated;
+
 			/* Get TSC value for this and the previous cpu. */
 			rdtscll(tsc_this);
 			smp_call_function_single(vcpu->cpu, ipi_rdtscll,

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

_______________________________________________
kvm-devel mailing list [email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel

A message that is not in the archive (sent off-list or not yet received): 45E8567C.6080704-g2GXA8XeJSExHbG02/[email protected]

#10 lore raw

Re: [PATCH 2/3] Add a vcpu_migrated statistic

Quoted 11 lines · Leonard Norrgard

The previous patch introduces an IPI on every vcpu migration on SMP machines to find out the TSC value on the previous cpu. We might be able to avoid this IPI on systems that have a synchronized TSC by checking for it in svm/vmx_vcpu_load:

(quoted diff) +5 -0
+               /* If this isn't the first vcpu_load and if the TSC
+                  doesn't run at a constant rate, we must handle TSC
+                  offsets. */
+               if (vcpu->cpu != -1
+                   && !boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {
Quoted 2 lines

Wether this is actually reliable and working in the intended way is not know yet.

Reading the documentation for X86_FEATURE_CONSTANT_TSC, I'm not sure either.

Quoted 5 lines

In the meantime, introduce a statistic for vcpu migration, so we get some decision support for the needs for such an optimization.

The statistic is great (vcpu migrations are very expensive, we should know when they happen), but why two unrelated changes in a patch? I think you can drop the constant tsc optimization for now, given we aren't certain it works as we expect.

Signature · 8 lines
Do not meddle in the internals of kernels, for they are subtle and quick to panic.


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
#11 lore raw

PATCH 3/3 Widen key column in kvm_stat

In reply to a message not in the archive

Make the key column wider, so the keys are fully shown.

=== kvm_stat
==================================================================

kvm_stat +2 -2
@@ -39,9 +39,9 @@
         for key in sorted(s.keys()):
             values = s[key]
             screen.addstr(row, 1, key)
-            screen.addstr(row, 12, '%10d' % (values[0],))
+            screen.addstr(row, 14, '%10d' % (values[0],))
             if values[1] is not None:
-                screen.addstr(row, 22, '%8d' % (values[1],))
+                screen.addstr(row, 24, '%8d' % (values[1],))
             row += 1
         screen.refresh()
 

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

_______________________________________________
kvm-devel mailing list [email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel