Skip to contentSkip to conversation

fix VMX TSC synchronicity

RFC In review Marcelo Tosatti 6 participants 21 messages Jan 11, 2008 – May 6, 2008 11 messages not in the archive

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

RFC 1/1 fix VMX TSC synchronicity

The boot TSC sync check is failing on recent Linux SMP guests on TSC stable hosts.

Following patch attempts to address the problems, which are:

1) APIC_DM_STARTUP, which is only called for vcpu's other than vcpu0, will trigger ->vcpu_reset(), setting the TSC to 0. Fix that by moving the guest_write_tsc(0) to vcpu_load.

2) vcpu's are initialized at different times by QEMU (vcpu0 init happens way earlier than the rest). Fix that by initializing the TSC of vcpu's > 0 with reference to vcpu0 init tsc value. This way TSC synchronization is kept (apparently Xen does something similar).

3) The code which adjusts the TSC of a VCPU on physical CPU switch is meant to guarantee that the guest sees a monotonically increasing value. However there is a large gap, in terms of clocks, between the time which the source CPU TSC is read and the time the destination CPU TSC is read. So move those two reads to happen at vcpu_clear.

I believe that 3) is the reason for the -no-kvm-irqchip problems reported by Avi on RHEL5, with kernels < 2.6.21 (where vcpu->cpu pinning would fix the problem). Unfortunately I could reproduce that problem.

4-way guest with constant tick at 250Hz now reliably sees the TSC's synchronized, and idle guest CPU consumption is reduced by 50% (3-4% instead of 8%, the latter with acpi_pm_good boot parameter).

arch/x86/kvm/vmx.c +24 -9
index 4741806..e1c8cf4 100644
@@ -47,6 +47,8 @@ struct vcpu_vmx {
 	struct kvm_vcpu       vcpu;
 	int                   launched;
 	u8                    fail;
+	u64		      first_tsc;
+	u64		      tsc_this;
 	u32                   idt_vectoring_info;
 	struct kvm_msr_entry *guest_msrs;
 	struct kvm_msr_entry *host_msrs;
@@ -254,6 +256,7 @@ static void vcpu_clear(struct vcpu_vmx *vmx)
 	if (vmx->vcpu.cpu == -1)
 		return;
 	smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, vmx, 0, 1);
+	rdtscll(vmx->tsc_this);
 	vmx->launched = 0;
 }
 
@@ -480,6 +483,8 @@ static void vmx_load_host_state(struct vcpu_vmx *vmx)
 	reload_host_efer(vmx);
 }
 
+static void guest_write_tsc(u64 host_tsc, u64 guest_tsc);
+
 /*
  * Switches to specified vcpu, until a matching vcpu_put(), but assumes
  * vcpu mutex is already taken.
@@ -488,7 +493,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	u64 phys_addr = __pa(vmx->vmcs);
-	u64 tsc_this, delta;
+	u64 delta;
 
 	if (vcpu->cpu != cpu) {
 		vcpu_clear(vmx);
@@ -511,6 +516,19 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 		struct descriptor_table dt;
 		unsigned long sysenter_esp;
 
+		if (unlikely(vcpu->cpu == -1)) {
+			rdtscll(vcpu->arch.host_tsc);
+			vmx->tsc_this = vcpu->arch.host_tsc;
+			if (vcpu->vcpu_id == 0) {
+				guest_write_tsc(vcpu->arch.host_tsc, 0);
+				vmx->first_tsc = vcpu->arch.host_tsc;
+			} else {
+				struct vcpu_vmx *cpu0;
+				cpu0 = to_vmx(vcpu->kvm->vcpus[0]);
+				guest_write_tsc(cpu0->first_tsc, 0);
+			}
+		}
+
 		vcpu->cpu = cpu;
 		/*
 		 * Linux uses per-cpu TSS and GDT, so set these when switching
@@ -526,8 +544,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 		/*
 		 * Make sure the time stamp counter is monotonous.
 		 */
-		rdtscll(tsc_this);
-		delta = vcpu->arch.host_tsc - tsc_this;
+		delta = vcpu->arch.host_tsc - vmx->tsc_this;
 		vmcs_write64(TSC_OFFSET, vmcs_read64(TSC_OFFSET) + delta);
 	}
 }
@@ -690,11 +707,8 @@ static u64 guest_read_tsc(void)
  * writes 'guest_tsc' into guest's timestamp counter "register"
  * guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc
  */
-static void guest_write_tsc(u64 guest_tsc)
+static void guest_write_tsc(u64 host_tsc, u64 guest_tsc)
 {
-	u64 host_tsc;
-
-	rdtscll(host_tsc);
 	vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc);
 }
 
@@ -758,6 +772,7 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	struct kvm_msr_entry *msr;
+	u64 host_tsc;
 	int ret = 0;
 
 	switch (msr_index) {
@@ -786,7 +801,8 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
 		vmcs_writel(GUEST_SYSENTER_ESP, data);
 		break;
 	case MSR_IA32_TIME_STAMP_COUNTER:
-		guest_write_tsc(data);
+		rdtscll(host_tsc);
+		guest_write_tsc(host_tsc, data);
 		break;
 	default:
 		msr = find_msr_entry(vmx, msr_index);
@@ -1684,7 +1700,6 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
 	vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0);
 	vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0);
 
-	guest_write_tsc(0);
 
 	/* Special registers */
 	vmcs_write64(GUEST_IA32_DEBUGCTL, 0);

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace

#1 lore raw
Quoted 4 lines · Marcelo Tosatti

The boot TSC sync check is failing on recent Linux SMP guests on TSC stable hosts.

What about tsc unstable hosts? If your patch convinces the guest its tsc is table, while the host tsc is not, then it may cause confusion later on.

Quoted 66 lines

Following patch attempts to address the problems, which are:

1) APIC_DM_STARTUP, which is only called for vcpu's other than vcpu0, will trigger ->vcpu_reset(), setting the TSC to 0. Fix that by moving the guest_write_tsc(0) to vcpu_load.

2) vcpu's are initialized at different times by QEMU (vcpu0 init happens way earlier than the rest). Fix that by initializing the TSC of vcpu's > 0 with reference to vcpu0 init tsc value. This way TSC synchronization is kept (apparently Xen does something similar).

3) The code which adjusts the TSC of a VCPU on physical CPU switch is meant to guarantee that the guest sees a monotonically increasing value. However there is a large gap, in terms of clocks, between the time which the source CPU TSC is read and the time the destination CPU TSC is read. So move those two reads to happen at vcpu_clear.

I believe that 3) is the reason for the -no-kvm-irqchip problems reported by Avi on RHEL5, with kernels < 2.6.21 (where vcpu->cpu pinning would fix the problem). Unfortunately I could reproduce that problem.

4-way guest with constant tick at 250Hz now reliably sees the TSC's synchronized, and idle guest CPU consumption is reduced by 50% (3-4% instead of 8%, the latter with acpi_pm_good boot parameter).

arch/x86/kvm/vmx.c +6 -1
index 4741806..e1c8cf4 100644
@@ -47,6 +47,8 @@ struct vcpu_vmx {
 	struct kvm_vcpu       vcpu;
 	int                   launched;
 	u8                    fail;
+	u64		      first_tsc;
+	u64		      tsc_this;
 	u32                   idt_vectoring_info;
 	struct kvm_msr_entry *guest_msrs;
 	struct kvm_msr_entry *host_msrs;
@@ -254,6 +256,7 @@ static void vcpu_clear(struct vcpu_vmx *vmx)
 	if (vmx->vcpu.cpu == -1)
 		return;
 	smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, vmx, 0, 1);
+	rdtscll(vmx->tsc_this);
 	vmx->launched = 0;
 }
 
@@ -480,6 +483,8 @@ static void vmx_load_host_state(struct vcpu_vmx *vmx)
 	reload_host_efer(vmx);
 }
 
+static void guest_write_tsc(u64 host_tsc, u64 guest_tsc);
+
 /*
  * Switches to specified vcpu, until a matching vcpu_put(), but assumes
  * vcpu mutex is already taken.
@@ -488,7 +493,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	u64 phys_addr = __pa(vmx->vmcs);
-	u64 tsc_this, delta;
+	u64 delta;
 
 	if (vcpu->cpu != cpu) {
 		vcpu_clear(vmx);

arch/x86/kvm/vmx.c static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) · line 520

Quoted 5 lines
arch/x86/kvm/vmx.c +1 -0
@@ -511,6 +516,19 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 		struct descriptor_table dt;
 		unsigned long sysenter_esp;
 
+		if (unlikely(vcpu->cpu == -1)) {
 

This can happen after migration, I believe.

arch/x86/kvm/vmx.c static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)

Quoted 13 lines
arch/x86/kvm/vmx.c +12 -0
+			rdtscll(vcpu->arch.host_tsc);
+			vmx->tsc_this = vcpu->arch.host_tsc;
+			if (vcpu->vcpu_id == 0) {
+				guest_write_tsc(vcpu->arch.host_tsc, 0);
+				vmx->first_tsc = vcpu->arch.host_tsc;
+			} else {
+				struct vcpu_vmx *cpu0;
+				cpu0 = to_vmx(vcpu->kvm->vcpus[0]);
+				guest_write_tsc(cpu0->first_tsc, 0);
+			}
+		}
+
 

Depending on vcpu_id == 0 can cause problems (for example, if vcpu 0 is somehow not the first to run).

We might initialize the tsc base on vm creation, and if the host tsc is synced, then the guest tsc should also be.

arch/x86/kvm/vmx.c static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) · line 549

Quoted 12 lines
arch/x86/kvm/vmx.c +0 -0
 		vcpu->cpu = cpu;
arch/x86/kvm/vmx.c +1 -2
 		/*
 		 * Linux uses per-cpu TSS and GDT, so set these when switching
@@ -526,8 +544,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 		/*
 		 * Make sure the time stamp counter is monotonous.
 		 */
-		rdtscll(tsc_this);
-		delta = vcpu->arch.host_tsc - tsc_this;
+		delta = vcpu->arch.host_tsc - vmx->tsc_this;
 		vmcs_write64(TSC_OFFSET, vmcs_read64(TSC_OFFSET) + delta);
 

This is a little roundabout, how about moving the delta calculation immediately after the call to vcpu_clear()?

I don't think this is the cause of the problem, it can't account for more than a few hundred cycles, compared to the much greater vmentry cost.

Anyway it should be in a separate patch.

Signature · 8 lines
error compiling committee.c: too many arguments to function


-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace

A message that is not in the archive (sent off-list or not yet received): 478A01D1.7000402-atKUWr5tajBWk0Htik3J/[email protected]

#3 lore raw

Hi Avi,

Quoted 9 lines · Avi Kivity
Quoted 4 lines · Marcelo Tosatti

The boot TSC sync check is failing on recent Linux SMP guests on TSC stable hosts.

What about tsc unstable hosts? If your patch convinces the guest its tsc is table, while the host tsc is not, then it may cause confusion later on.

The adjustment to zero won't fool the guest because it assumes that the TSC's are synchronized. It will simply set the guest TSC to zero on all VCPUs based on the time VCPU0 was initialized.

That is, setting -(vcpu[0].first_tsc) on all VCPU's will not correct any synchronization problem.

Quoted 71 lines
Quoted 71 lines

Following patch attempts to address the problems, which are:

1) APIC_DM_STARTUP, which is only called for vcpu's other than vcpu0, will trigger ->vcpu_reset(), setting the TSC to 0. Fix that by moving the guest_write_tsc(0) to vcpu_load.

2) vcpu's are initialized at different times by QEMU (vcpu0 init happens way earlier than the rest). Fix that by initializing the TSC of vcpu's > 0 with reference to vcpu0 init tsc value. This way TSC synchronization is kept (apparently Xen does something similar).

3) The code which adjusts the TSC of a VCPU on physical CPU switch is meant to guarantee that the guest sees a monotonically increasing value. However there is a large gap, in terms of clocks, between the time which the source CPU TSC is read and the time the destination CPU TSC is read. So move those two reads to happen at vcpu_clear.

I believe that 3) is the reason for the -no-kvm-irqchip problems reported by Avi on RHEL5, with kernels < 2.6.21 (where vcpu->cpu pinning would fix the problem). Unfortunately I could reproduce that problem.

4-way guest with constant tick at 250Hz now reliably sees the TSC's synchronized, and idle guest CPU consumption is reduced by 50% (3-4% instead of 8%, the latter with acpi_pm_good boot parameter).

arch/x86/kvm/vmx.c +6 -1
index 4741806..e1c8cf4 100644
@@ -47,6 +47,8 @@ struct vcpu_vmx {
 	struct kvm_vcpu       vcpu;
 	int                   launched;
 	u8                    fail;
+	u64		      first_tsc;
+	u64		      tsc_this;
 	u32                   idt_vectoring_info;
 	struct kvm_msr_entry *guest_msrs;
 	struct kvm_msr_entry *host_msrs;
@@ -254,6 +256,7 @@ static void vcpu_clear(struct vcpu_vmx *vmx)
 	if (vmx->vcpu.cpu == -1)
 		return;
 	smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, vmx, 0, 1);
+	rdtscll(vmx->tsc_this);
 	vmx->launched = 0;
 }
 
@@ -480,6 +483,8 @@ static void vmx_load_host_state(struct vcpu_vmx *vmx)
 	reload_host_efer(vmx);
 }
 
+static void guest_write_tsc(u64 host_tsc, u64 guest_tsc);
+
 /*
 * Switches to specified vcpu, until a matching vcpu_put(), but assumes
 * vcpu mutex is already taken.
@@ -488,7 +493,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int 
 cpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	u64 phys_addr = __pa(vmx->vmcs);
-	u64 tsc_this, delta;
+	u64 delta;
 
 	if (vcpu->cpu != cpu) {
		vcpu_clear(vmx);
arch/x86/kvm/vmx.c +0 -0
@@ -511,6 +516,19 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int 
 cpu)
 		struct descriptor_table dt;
 		unsigned long sysenter_esp;
 
Quoted 4 lines

arch/x86/kvm/vmx.c static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int · line 521

Quoted 2 lines
arch/x86/kvm/vmx.c +1 -0
+		if (unlikely(vcpu->cpu == -1)) {
 

This can happen after migration, I believe.

Right now the destination host will do ->vcpu_reset() on all VCPU's on startup... so its already broken. This patch is not introducing any issues, just changing where it happens :)

Perhaps fixing migration should be the subject of a separate patch?

Quoted 8 lines
Quoted 8 lines
arch/x86/kvm/vmx.c +8 -0
+			rdtscll(vcpu->arch.host_tsc);
+			vmx->tsc_this = vcpu->arch.host_tsc;
+			if (vcpu->vcpu_id == 0) {
+				guest_write_tsc(vcpu->arch.host_tsc, 0);
+				vmx->first_tsc = vcpu->arch.host_tsc;
+			} else {
+				struct vcpu_vmx *cpu0;
+				cpu0 = to_vmx(vcpu->kvm->vcpus[0]);
Quoted 8 lines

arch/x86/kvm/vmx.c static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int · line 534

Quoted 5 lines
arch/x86/kvm/vmx.c +4 -0
+				guest_write_tsc(cpu0->first_tsc, 0);
+			}
+		}
+
 

Depending on vcpu_id == 0 can cause problems (for example, if vcpu 0 is somehow not the first to run).

But QEMU will always run kvm_create() first (which does kvm_create_vcpu(0)), then start the other threads later. So I don't see how that can happen.

Quoted 21 lines

We might initialize the tsc base on vm creation, and if the host tsc is synced, then the guest tsc should also be.

Quoted 5 lines
		vcpu->cpu = cpu;
		/*
		 * Linux uses per-cpu TSS and GDT, so set these when 
		 switching

arch/x86/kvm/vmx.c static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int · line 550

Quoted 9 lines
arch/x86/kvm/vmx.c +1 -2
@@ -526,8 +544,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int 
 cpu)
 		/*
 		 * Make sure the time stamp counter is monotonous.
 		 */
-		rdtscll(tsc_this);
-		delta = vcpu->arch.host_tsc - tsc_this;
+		delta = vcpu->arch.host_tsc - vmx->tsc_this;
 		vmcs_write64(TSC_OFFSET, vmcs_read64(TSC_OFFSET) + delta);
 

This is a little roundabout, how about moving the delta calculation immediately after the call to vcpu_clear()?

Quoted 2 lines

I don't think this is the cause of the problem, it can't account for more than a few hundred cycles, compared to the much greater vmentry cost.

Actually it accounts for several thousand cycles warp by the time the kernel checks the TSC synchronization between CPU's, which happens very early on boot.

You saw the hang on userspace init, by then there could be many VCPU->CPU switchs.

Quoted 2 lines

Anyway it should be in a separate patch.

How does the following look (minus proper changelog):

arch/x86/kvm/vmx.c +18 -7
Index: kvm.quilt/arch/x86/kvm/vmx.c
===================================================================
@@ -47,6 +47,7 @@ struct vcpu_vmx {
 	struct kvm_vcpu       vcpu;
 	int                   launched;
 	u8                    fail;
+	u64		      first_tsc;
 	u32                   idt_vectoring_info;
 	struct kvm_msr_entry *guest_msrs;
 	struct kvm_msr_entry *host_msrs;
@@ -480,6 +481,7 @@ static void vmx_load_host_state(struct v
 	reload_host_efer(vmx);
 }
 
+static void guest_write_tsc(u64 host_tsc, u64 guest_tsc);
 /*
  * Switches to specified vcpu, until a matching vcpu_put(), but assumes
  * vcpu mutex is already taken.
@@ -511,6 +513,18 @@ static void vmx_vcpu_load(struct kvm_vcp
 		struct descriptor_table dt;
 		unsigned long sysenter_esp;
 
+		if (unlikely(vcpu->cpu == -1)) {
+			rdtscll(vcpu->arch.host_tsc);
+			if (vcpu->vcpu_id == 0) {
+				guest_write_tsc(vcpu->arch.host_tsc, 0);
+				vmx->first_tsc = vcpu->arch.host_tsc;
+			} else {
+				struct vcpu_vmx *cpu0;
+				cpu0 = to_vmx(vcpu->kvm->vcpus[0]);
+				guest_write_tsc(cpu0->first_tsc, 0);
+			}
+		}
+
 		vcpu->cpu = cpu;
 		/*
 		 * Linux uses per-cpu TSS and GDT, so set these when switching
@@ -690,11 +704,8 @@ static u64 guest_read_tsc(void)
  * writes 'guest_tsc' into guest's timestamp counter "register"
  * guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc
  */
-static void guest_write_tsc(u64 guest_tsc)
+static void guest_write_tsc(u64 host_tsc, u64 guest_tsc)
 {
-	u64 host_tsc;
-
-	rdtscll(host_tsc);
 	vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc);
 }
 
@@ -758,6 +769,7 @@ static int vmx_set_msr(struct kvm_vcpu *
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	struct kvm_msr_entry *msr;
+	u64 host_tsc;
 	int ret = 0;
 
 	switch (msr_index) {
@@ -786,7 +798,8 @@ static int vmx_set_msr(struct kvm_vcpu *
 		vmcs_writel(GUEST_SYSENTER_ESP, data);
 		break;
 	case MSR_IA32_TIME_STAMP_COUNTER:
-		guest_write_tsc(data);
+		rdtscll(host_tsc);
+		guest_write_tsc(host_tsc, data);
 		break;
 	default:
 		msr = find_msr_entry(vmx, msr_index);
@@ -1684,8 +1697,6 @@ static int vmx_vcpu_reset(struct kvm_vcp
 	vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0);
 	vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0);
 
-	guest_write_tsc(0);
-
 	/* Special registers */
 	vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
 
arch/x86/kvm/vmx.c +28 -28

80 lines not on this page · raw message

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace

#4 lore raw
Quoted 151 lines · Marcelo Tosatti

Hi Avi,

Quoted 9 lines · Avi Kivity
Quoted 4 lines · Marcelo Tosatti

The boot TSC sync check is failing on recent Linux SMP guests on TSC stable hosts.

What about tsc unstable hosts? If your patch convinces the guest its tsc is table, while the host tsc is not, then it may cause confusion later on.

The adjustment to zero won't fool the guest because it assumes that the TSC's are synchronized. It will simply set the guest TSC to zero on all VCPUs based on the time VCPU0 was initialized.

That is, setting -(vcpu[0].first_tsc) on all VCPU's will not correct any synchronization problem.

Quoted 71 lines
Quoted 71 lines

Following patch attempts to address the problems, which are:

1) APIC_DM_STARTUP, which is only called for vcpu's other than vcpu0, will trigger ->vcpu_reset(), setting the TSC to 0. Fix that by moving the guest_write_tsc(0) to vcpu_load.

2) vcpu's are initialized at different times by QEMU (vcpu0 init happens way earlier than the rest). Fix that by initializing the TSC of vcpu's > 0 with reference to vcpu0 init tsc value. This way TSC synchronization is kept (apparently Xen does something similar).

3) The code which adjusts the TSC of a VCPU on physical CPU switch is meant to guarantee that the guest sees a monotonically increasing value. However there is a large gap, in terms of clocks, between the time which the source CPU TSC is read and the time the destination CPU TSC is read. So move those two reads to happen at vcpu_clear.

I believe that 3) is the reason for the -no-kvm-irqchip problems reported by Avi on RHEL5, with kernels < 2.6.21 (where vcpu->cpu pinning would fix the problem). Unfortunately I could reproduce that problem.

4-way guest with constant tick at 250Hz now reliably sees the TSC's synchronized, and idle guest CPU consumption is reduced by 50% (3-4% instead of 8%, the latter with acpi_pm_good boot parameter).

arch/x86/kvm/vmx.c +6 -1
index 4741806..e1c8cf4 100644
@@ -47,6 +47,8 @@ struct vcpu_vmx {
 	struct kvm_vcpu       vcpu;
 	int                   launched;
 	u8                    fail;
+	u64		      first_tsc;
+	u64		      tsc_this;
 	u32                   idt_vectoring_info;
 	struct kvm_msr_entry *guest_msrs;
 	struct kvm_msr_entry *host_msrs;
@@ -254,6 +256,7 @@ static void vcpu_clear(struct vcpu_vmx *vmx)
 	if (vmx->vcpu.cpu == -1)
 		return;
 	smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, vmx, 0, 1);
+	rdtscll(vmx->tsc_this);
 	vmx->launched = 0;
 }
 
@@ -480,6 +483,8 @@ static void vmx_load_host_state(struct vcpu_vmx *vmx)
 	reload_host_efer(vmx);
 }
 
+static void guest_write_tsc(u64 host_tsc, u64 guest_tsc);
+
 /*
 * Switches to specified vcpu, until a matching vcpu_put(), but assumes
 * vcpu mutex is already taken.
@@ -488,7 +493,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int 
 cpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	u64 phys_addr = __pa(vmx->vmcs);
-	u64 tsc_this, delta;
+	u64 delta;
 
 	if (vcpu->cpu != cpu) {
		vcpu_clear(vmx);
arch/x86/kvm/vmx.c +0 -0
@@ -511,6 +516,19 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int 
 cpu)
 		struct descriptor_table dt;
 		unsigned long sysenter_esp;
 
Quoted 4 lines

arch/x86/kvm/vmx.c static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int · line 521

Quoted 2 lines
arch/x86/kvm/vmx.c +1 -0
+		if (unlikely(vcpu->cpu == -1)) {
 

This can happen after migration, I believe.

Right now the destination host will do ->vcpu_reset() on all VCPU's on startup... so its already broken. This patch is not introducing any issues, just changing where it happens :)

Perhaps fixing migration should be the subject of a separate patch?

Quoted 8 lines
Quoted 8 lines
arch/x86/kvm/vmx.c +8 -0
+			rdtscll(vcpu->arch.host_tsc);
+			vmx->tsc_this = vcpu->arch.host_tsc;
+			if (vcpu->vcpu_id == 0) {
+				guest_write_tsc(vcpu->arch.host_tsc, 0);
+				vmx->first_tsc = vcpu->arch.host_tsc;
+			} else {
+				struct vcpu_vmx *cpu0;
+				cpu0 = to_vmx(vcpu->kvm->vcpus[0]);
Quoted 8 lines

arch/x86/kvm/vmx.c static void vmx_vcpu_load(struct kvm_vcp

Quoted 5 lines
arch/x86/kvm/vmx.c +4 -0
+				guest_write_tsc(cpu0->first_tsc, 0);
+			}
+		}
+
 

Depending on vcpu_id == 0 can cause problems (for example, if vcpu 0 is somehow not the first to run).

But QEMU will always run kvm_create() first (which does kvm_create_vcpu(0)), then start the other threads later. So I don't see how that can happen.

Quoted 21 lines

We might initialize the tsc base on vm creation, and if the host tsc is synced, then the guest tsc should also be.

Quoted 5 lines
		vcpu->cpu = cpu;
		/*
		 * Linux uses per-cpu TSS and GDT, so set these when 
		 switching

arch/x86/kvm/vmx.c static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int · line 550

Quoted 9 lines
arch/x86/kvm/vmx.c +1 -2
@@ -526,8 +544,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int 
 cpu)
 		/*
 		 * Make sure the time stamp counter is monotonous.
 		 */
-		rdtscll(tsc_this);
-		delta = vcpu->arch.host_tsc - tsc_this;
+		delta = vcpu->arch.host_tsc - vmx->tsc_this;
 		vmcs_write64(TSC_OFFSET, vmcs_read64(TSC_OFFSET) + delta);
 

This is a little roundabout, how about moving the delta calculation immediately after the call to vcpu_clear()?

Quoted 2 lines

I don't think this is the cause of the problem, it can't account for more than a few hundred cycles, compared to the much greater vmentry cost.

Actually it accounts for several thousand cycles warp by the time the kernel checks the TSC synchronization between CPU's, which happens very early on boot.

Quoted 7 lines

You saw the hang on userspace init, by then there could be many VCPU->CPU switchs.

Quoted 2 lines

Anyway it should be in a separate patch.

How does the following look (minus proper changelog):

Actually setting the TSC_OFFSET at vcpu_clear() seems a bit early:

vmwrite error: reg 2010 value 82470677 (err -2109274505)
Pid: 5590, comm: qemu-system-x86 Not tainted 2.6.24-rc6-ge7706133 #26

Call Trace:
 [<ffffffff880a5983>] :kvm_intel:vmwrite_error+0x22/0x28
 [<ffffffff880a5a99>] :kvm_intel:vcpu_clear+0x54/0x60
 [<ffffffff880a5ad0>] :kvm_intel:vmx_vcpu_load+0x29/0x12b
 [<ffffffff8024d803>] get_futex_value_locked+0x1d/0x38
 [<ffffffff8808fcf1>] :kvm:kvm_arch_vcpu_ioctl_run+0x13/0x4b9
 [<ffffffff8808c3df>] :kvm:kvm_vcpu_ioctl+0xda/0x2dd

So the first patch seemed alright (taking into account the comments from my previous email, that migration should probably be fixed in a separate patch since its broken already and that its guaranteed that vcpu0 is the first to hit vcpu_load).

Avi?

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace

#5 lore raw
Quoted 5 lines · Marcelo Tosatti

So the first patch seemed alright (taking into account the comments from my previous email, that migration should probably be fixed in a separate patch since its broken already and that its guaranteed that vcpu0 is the first to hit vcpu_load).

I really would like not to have this dependency. It's easy to write userspace that doesn't do this and there's no reason not to.

Signature · 7 lines
error compiling committee.c: too many arguments to function


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
#6 lore raw
In reply to Marcelo Tosatti
Quoted 16 lines · Marcelo Tosatti

Hi Avi,

Quoted 11 lines · Avi Kivity
Quoted 5 lines · Marcelo Tosatti

The boot TSC sync check is failing on recent Linux SMP guests on TSC stable hosts.

What about tsc unstable hosts? If your patch convinces the guest its tsc is table, while the host tsc is not, then it may cause confusion later on.

Quoted 8 lines

The adjustment to zero won't fool the guest because it assumes that the TSC's are synchronized. It will simply set the guest TSC to zero on all VCPUs based on the time VCPU0 was initialized.

That is, setting -(vcpu[0].first_tsc) on all VCPU's will not correct any synchronization problem.

What I mean is, right now we present really broken tscs to the guest. After your patch, we present less-broken tscs (at boot, they will closely resemble stable tscs). But after the machine idles a bit and cpufreq takes over, the tscs won't be stable any more.

Quoted 26 lines
Quoted 20 lines
Quoted 20 lines
(quoted diff) +2 -0
+static void guest_write_tsc(u64 host_tsc, u64 guest_tsc);
+

/*
* Switches to specified vcpu, until a matching vcpu_put(), but assumes
* vcpu mutex is already taken.

arch/x86/kvm/vmx.c +1 -1
@@ -488,7 +493,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int 
 cpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	u64 phys_addr = __pa(vmx->vmcs);
-	u64 tsc_this, delta;
+	u64 delta;
 
 	if (vcpu->cpu != cpu) {
		vcpu_clear(vmx);
arch/x86/kvm/vmx.c +0 -0
@@ -511,6 +516,19 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int 
 cpu)
 		struct descriptor_table dt;
 		unsigned long sysenter_esp;
 
Quoted 5 lines

Review static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int · line 522

Quoted 3 lines
(quoted diff) +1 -0
+		if (unlikely(vcpu->cpu == -1)) {
 
 

This can happen after migration, I believe.

Quoted 4 lines

Right now the destination host will do ->vcpu_reset() on all VCPU's on startup... so its already broken. This patch is not introducing any issues, just changing where it happens :)

No, after the reset qemu will set the guest msrs including the tsc msr, overriding the reset value.

However, by that time vcpu->cpu will no longer be -1, so there's no issue there.

On the other hand, it may happen during cpu hotunplug (see decache_vcpus_on_vcpu).

Quoted 20 lines
Quoted 19 lines
Quoted 6 lines
arch/x86/kvm/vmx.c +2 -0
+			rdtscll(vcpu->arch.host_tsc);
+			vmx->tsc_this = vcpu->arch.host_tsc;

arch/x86/kvm/vmx.c static void vmx_vcpu_load(struct kvm_vcp · line 527

Quoted 10 lines
arch/x86/kvm/vmx.c +10 -0
+			if (vcpu->vcpu_id == 0) {
+				guest_write_tsc(vcpu->arch.host_tsc, 0);
+				vmx->first_tsc = vcpu->arch.host_tsc;
+			} else {
+				struct vcpu_vmx *cpu0;
+				cpu0 = to_vmx(vcpu->kvm->vcpus[0]);
+				guest_write_tsc(cpu0->first_tsc, 0);
+			}
+		}
+

Depending on vcpu_id == 0 can cause problems (for example, if vcpu 0 is somehow not the first to run).

Quoted 5 lines

But QEMU will always run kvm_create() first (which does kvm_create_vcpu(0)), then start the other threads later. So I don't see how that can happen.

We're not developing purely for qemu (there's xenner, for example) and I don't want to embed hidden assumptions into the API.

Quoted 22 lines
Quoted 18 lines
Quoted 6 lines
		vcpu->cpu = cpu;
		/*
		 * Linux uses per-cpu TSS and GDT, so set these when 
		 switching

Review static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int · line 550

Quoted 9 lines
(quoted diff) +1 -2
@@ -526,8 +544,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int 
 cpu)
 		/*
 		 * Make sure the time stamp counter is monotonous.
 		 */
-		rdtscll(tsc_this);
-		delta = vcpu->arch.host_tsc - tsc_this;
+		delta = vcpu->arch.host_tsc - vmx->tsc_this;
 		vmcs_write64(TSC_OFFSET, vmcs_read64(TSC_OFFSET) + delta);
 

This is a little roundabout, how about moving the delta calculation immediately after the call to vcpu_clear()?

Quoted 3 lines

I don't think this is the cause of the problem, it can't account for more than a few hundred cycles, compared to the much greater vmentry cost.

Quoted 8 lines

Actually it accounts for several thousand cycles warp by the time the kernel checks the TSC synchronization between CPU's, which happens very early on boot.

You saw the hang on userspace init, by then there could be many VCPU->CPU switchs.

Okay.

Quoted 34 lines
Quoted 2 lines

Anyway it should be in a separate patch.

How does the following look (minus proper changelog):

Index: kvm.quilt/arch/x86/kvm/vmx.c
===================================================================

arch/x86/kvm/vmx.c +5 -0
@@ -47,6 +47,7 @@ struct vcpu_vmx {
 	struct kvm_vcpu       vcpu;
 	int                   launched;
 	u8                    fail;
+	u64		      first_tsc;
 	u32                   idt_vectoring_info;
 	struct kvm_msr_entry *guest_msrs;
 	struct kvm_msr_entry *host_msrs;
@@ -480,6 +481,7 @@ static void vmx_load_host_state(struct v
 	reload_host_efer(vmx);
 }
 
+static void guest_write_tsc(u64 host_tsc, u64 guest_tsc);
 /*
  * Switches to specified vcpu, until a matching vcpu_put(), but assumes
  * vcpu mutex is already taken.
@@ -511,6 +513,18 @@ static void vmx_vcpu_load(struct kvm_vcp
 		struct descriptor_table dt;
 		unsigned long sysenter_esp;
 
+		if (unlikely(vcpu->cpu == -1)) {
 
+			rdtscll(vcpu->arch.host_tsc);
+			if (vcpu->vcpu_id == 0) {

arch/x86/kvm/vmx.c static void vmx_vcpu_load(struct kvm_vcp · line 529

Quoted 10 lines
arch/x86/kvm/vmx.c +9 -0
+				guest_write_tsc(vcpu->arch.host_tsc, 0);
+				vmx->first_tsc = vcpu->arch.host_tsc;
+			} else {
+				struct vcpu_vmx *cpu0;
+				cpu0 = to_vmx(vcpu->kvm->vcpus[0]);
+				guest_write_tsc(cpu0->first_tsc, 0);
+			}
+		}
+
 

I don't like the dependency on vcpu 0. Also see comments above.

Quoted 19 lines
arch/x86/kvm/vmx.c +17 -0
+static void __vcpu_clear(void *arg)
+{
+	struct vcpu_vmx *vmx = arg;
+	int cpu = raw_smp_processor_id();
+
+	if (vmx->vcpu.cpu == cpu)
+		vmcs_clear(vmx->vmcs);
+	if (per_cpu(current_vmcs, cpu) == vmx->vmcs)
+		per_cpu(current_vmcs, cpu) = NULL;
+	rdtscll(vmx->vcpu.arch.host_tsc);
+}
+
+static void vcpu_clear(struct vcpu_vmx *vmx)
+{
+	u64 tsc_this, delta;
+
+	if (vmx->vcpu.cpu == -1)

arch/x86/kvm/vmx.c static void update_exception_bitmap(stru · line 357

Quoted 10 lines
arch/x86/kvm/vmx.c +10 -0
+		return;
+	smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, vmx, 0, 1);
+	/*
+	 * Make sure the time stamp counter is monotonous.
+	 */
+	rdtscll(tsc_this);
+	delta = vmx->vcpu.arch.host_tsc - tsc_this;
+	vmcs_write64(TSC_OFFSET, vmcs_read64(TSC_OFFSET) + delta);
+	vmx->launched = 0;
+}

This part is fine.

Signature · 7 lines
error compiling committee.c: too many arguments to function


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): 478CC448.1030901-atKUWr5tajBWk0Htik3J/[email protected]

#8 lore raw
Quoted 31 lines · Avi Kivity
Quoted 19 lines · Marcelo Tosatti

Hi Avi,

Quoted 9 lines · Avi Kivity
Quoted 6 lines · Marcelo Tosatti

The boot TSC sync check is failing on recent Linux SMP guests on TSC stable hosts.

Quoted 5 lines

What about tsc unstable hosts? If your patch convinces the guest its tsc is table, while the host tsc is not, then it may cause confusion later on.

Quoted 9 lines

The adjustment to zero won't fool the guest because it assumes that the TSC's are synchronized. It will simply set the guest TSC to zero on all VCPUs based on the time VCPU0 was initialized.

That is, setting -(vcpu[0].first_tsc) on all VCPU's will not correct any synchronization problem.

Quoted 6 lines

What I mean is, right now we present really broken tscs to the guest. After your patch, we present less-broken tscs (at boot, they will closely resemble stable tscs). But after the machine idles a bit and cpufreq takes over, the tscs won't be stable any more.

Why would the TSC break due to cpufreq? This patchset was against VMX, which is only available on current Intel CPUs. All of those guarantee a constant TSC increase at the maximum frequency.

Also see the Intel Documentation:

Vol. 3 18-37

For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]); for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]); for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]): the time-stamp counter increments at a constant rate. That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by the maximum resolved frequency at which the processor is booted. The maximum resolved frequency may differ from the maximum qualified frequency of the processor, see Section 18.17.5 for more detail.
The specific processor configuration determines the behavior. Constant TSC behavior ensures that the duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if the processor core changes frequency.
This is the architectural behavior moving forward.

Alex

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): [email protected]

#10 lore raw
Quoted 19 lines · Alexander Graf
Quoted 10 lines
Quoted 3 lines

What I mean is, right now we present really broken tscs to the guest. After your patch, we present less-broken tscs (at boot, they will closely resemble stable tscs). But after the machine idles a bit and cpufreq takes over, the tscs won't be stable any more.

Why would the TSC break due to cpufreq? This patchset was against VMX, which is only available on current Intel CPUs. All of those guarantee a constant TSC increase at the maximum frequency.

Also see the Intel Documentation:

Vol. 3 18-37

Quoted 15 lines

For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]); for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]); for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]): the time-stamp counter increments at a constant rate. That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by the maximum resolved frequency at which the processor is booted. The maximum resolved frequency may differ from the maximum qualified frequency of the processor, see Section 18.17.5 for more detail.
The specific processor configuration determines the behavior. Constant TSC behavior ensures that the duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if the processor core changes frequency.
This is the architectural behavior moving forward.

Thanks; that's reassuring to know that it will work (at least on Intel).

Signature · 7 lines
error compiling committee.c: too many arguments to function


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): 478CCCA9.2080300-atKUWr5tajBWk0Htik3J/[email protected]

#12 lore raw
Quoted 39 lines · Avi Kivity
Quoted 20 lines · Alexander Graf
Quoted 4 lines
Quoted 4 lines
Quoted 8 lines

What I mean is, right now we present really broken tscs to the guest. After your patch, we present less-broken tscs (at boot, they will closely resemble stable tscs). But after the machine idles a bit and cpufreq takes over, the tscs won't be stable any more.

Why would the TSC break due to cpufreq? This patchset was against VMX, which is only available on current Intel CPUs. All of those guarantee a constant TSC increase at the maximum frequency.

Also see the Intel Documentation:

Vol. 3 18-37

Quoted 16 lines

For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]); for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]); for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]): the time-stamp counter increments at a constant rate. That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by the maximum resolved frequency at which the processor is booted. The maximum resolved frequency may differ from the maximum qualified frequency of the processor, see Section 18.17.5 for more detail.
The specific processor configuration determines the behavior. Constant TSC behavior ensures that the duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if the processor core changes frequency.
This is the architectural behavior moving forward.

Quoted 3 lines

Thanks; that's reassuring to know that it will work (at least on Intel).

If I remember correctly, there was a statement on LKML by AMD which said that the TSC is completely broken on AMD systems, so you should not use it there anyway.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): [email protected]

#14 lore raw
Quoted 4 lines · Alexander Graf

If I remember correctly, there was a statement on LKML by AMD which said that the TSC is completely broken on AMD systems, so you should not use it there anyway.

Well, that's up to the guest to decide. Looks like older Linux guests make the wrong decision.

Signature · 7 lines
error compiling committee.c: too many arguments to function


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): 478CF186.5030304-atKUWr5tajBWk0Htik3J/[email protected]

#16 lore raw
Quoted 7 lines · On Tuesday 15 January 2008 23:16:46 Avi Kivity wrote:
Quoted 3 lines · Alexander Graf

If I remember correctly, there was a statement on LKML by AMD which said that the TSC is completely broken on AMD systems, so you should not use it there anyway.

Well, that's up to the guest to decide. Looks like older Linux guests make the wrong decision.

http://lkml.org/lkml/2005/11/4/173

That talks about AMD's TSC plans (dated 2005), but it's possible to find out whether it's a monotonically-increasing source. Basically some revisions of AMD family F onwards should support this feature:

Future TSC Directions and Solutions
===================================
Future AMD processors will provide a TSC that is P-state and C-State invariant and unaffected by STPCLK-throttling. This

will make  the TSC immune  to drift.  Because using  the TSC
for  fast  timer APIs  is  a  desirable  feature that  helps

performance, AMD has defined a CPUID feature bit that
software can test to determine if the TSC is
invariant. Issuing a CPUID instruction with an %eax register value of 0x8000_0007, on a processor whose base family is 0xF, returns "Advanced Power Management Information" in the %eax, %ebx, %ecx, and %edx registers. Bit 8 of the return %edx is the "TscInvariant" feature flag which is set when TSC is P-state, C-state, and STPCLK-throttling invariant; it is clear otherwise.

The  rate of the  invariant TSC  is implementation-dependent
and  will likely  *not* be  the frequency  of  the processor

core; however, its period should be short enough such that it is not possible for two back-to-back rdtsc instructions to return the same value. Software which is trying to measure actual processor frequency or cycle-performance should use Performance Event 76h, CPU Clocks not Halted, rather than the TSC to count CPU cycles.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

#17 lore raw
In reply to a message not in the archive
Quoted 1 line · Avi Kivity

Thanks; that's reassuring to know that it will work (at least on Intel).

Actually there are modern Intel systems which still have instable TSCs; e.g. IBM Summit multi node systems and some others. So you should still handle that case.

-Andi

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): [email protected]

#19 lore raw

[fixing gmane emails, urgfhsz]

Quoted 10 lines · Andi Kleen
Quoted 2 lines · Avi Kivity

Thanks; that's reassuring to know that it will work (at least on Intel).

Actually there are modern Intel systems which still have instable TSCs; e.g. IBM Summit multi node systems and some others. So you should still handle that case.

I really don't see any way we could. If the guest assumes tscs are synchronous, and they really are not, there's nothing we can do.

[well, we could trap and emulate rdtsc, but performance would tank]

You might taskset guests into a single node on such systems, which is a good idea anyway.

Signature · 7 lines
error compiling committee.c: too many arguments to function


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): 478DC453.1000404-atKUWr5tajBWk0Htik3J/[email protected]

#21 lore raw
Quoted 9 lines · Avi Kivity

[fixing gmane emails, urgfhsz]

Quoted 6 lines · Andi Kleen
Quoted 2 lines · Avi Kivity

Thanks; that's reassuring to know that it will work (at least on Intel).

Quoted 7 lines
Quoted 4 lines

Actually there are modern Intel systems which still have instable TSCs; e.g. IBM Summit multi node systems and some others. So you should still handle that case.

I really don't see any way we could. If the guest assumes tscs are synchronous, and they really are not, there's nothing we can do.

Linux checks a couple of things: e.g. if there are no deep C states and if there are no clustered nodes in the APIC etc.

It might be reasonable to check the clock source of the kernel and if it's not TSC force one of these in the emulated firmware environment

Quoted 2 lines

You might taskset guests into a single node on such systems, which is a good idea anyway.

Ah pushing the problem to the user. An easy, but typically wrong, solution.

-Andi

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): 478E08E5.2030507-atKUWr5tajBWk0Htik3J/[email protected]

#24 lore raw
Quoted 4 lines · Avi Kivity
Quoted 3 lines · Andi Kleen

Linux checks a couple of things: e.g. if there are no deep C states and if there are no clustered nodes in the APIC etc.

Quoted 8 lines
Quoted 5 lines

It might be reasonable to check the clock source of the kernel and if it's not TSC force one of these in the emulated firmware environment

The problems are with older guests which assume the tsc is okay. Newer guests check the tsc and conclude that it isn't usable.

If the guest would get it wrong running natively on the host I guess it would be reasonable to require an option that forces TSC off. Disabling the TSC bit unfortunately won't work for 64bit guests, but for probably most 32bit guests.

But for non broken guests they can only do that if the guest has the same visibility into the firmware state as the host. For the easy cases Linux will check it anyways becaused on standard the TSC synchronicity check, but there are cases where the TSCs only drift apart slowly over a longer time

[I finally fixed the clocksource watchdog now to catch this case, but it will be only in .25]

I think it would be better to fake at least some of the usual firmware cues for bad TSC if the host does not use it.

Quoted 10 lines
Quoted 7 lines
Quoted 4 lines

You might taskset guests into a single node on such systems, which is a good idea anyway.

Ah pushing the problem to the user. An easy, but typically wrong, solution.

If you have other suggestions I'll be happy to hear them. I don't like this either.

Check if host is using TSC source and if not force a clustered APIC mode (only works for 64bit unfortunately) or fake a C3 state in ACPI and on AMD clear the synchronous TSC bit.

-Andi

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): 20080116135415.GA14664-qrUzlfsMFqo/[email protected]

#26 lore raw
Quoted 4 lines · Andi Kleen

Check if host is using TSC source and if not force a clustered APIC mode (only works for 64bit unfortunately) or fake a C3 state in ACPI and on AMD clear the synchronous TSC bit.

Yes, I got similar suggestions from Thomas. But it looks like older guests will need a boot option.

Signature · 7 lines
error compiling committee.c: too many arguments to function


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
#27 lore raw
In reply to a message not in the archive
Quoted 38 lines · Andi Kleen
Quoted 4 lines · Avi Kivity
Quoted 3 lines · Andi Kleen

Linux checks a couple of things: e.g. if there are no deep C states and if there are no clustered nodes in the APIC etc.

Quoted 8 lines
Quoted 5 lines

It might be reasonable to check the clock source of the kernel and if it's not TSC force one of these in the emulated firmware environment

The problems are with older guests which assume the tsc is okay. Newer guests check the tsc and conclude that it isn't usable.

If the guest would get it wrong running natively on the host I guess it would be reasonable to require an option that forces TSC off. Disabling the TSC bit unfortunately won't work for 64bit guests, but for probably most 32bit guests.

But for non broken guests they can only do that if the guest has the same visibility into the firmware state as the host. For the easy cases Linux will check it anyways becaused on standard the TSC synchronicity check, but there are cases where the TSCs only drift apart slowly over a longer time

[I finally fixed the clocksource watchdog now to catch this case, but it will be only in .25]

I think it would be better to fake at least some of the usual firmware cues for bad TSC if the host does not use it.

Quoted 8 lines
Quoted 7 lines
Quoted 4 lines

You might taskset guests into a single node on such systems, which is a good idea anyway.

Ah pushing the problem to the user. An easy, but typically wrong, solution.

Quoted 6 lines
Quoted 2 lines

If you have other suggestions I'll be happy to hear them. I don't like this either.

Check if host is using TSC source and if not force a clustered APIC mode (only works for 64bit unfortunately) or fake a C3 state in ACPI and on AMD clear the synchronous TSC bit.

Forcing clustered APIC mode works only on SMP, and there were high CPU consumption on Windows SMP guests due to C3 state being reported (fixed in kvm-30 something).

So perhaps:
- Faking clustered APIC on SMP
- Faking C3 on UP

And turning of the TSC bit (for 32-bit guests).

Is the way to go?

Avi, do you understand why C3 was causing the Windows SMP problems ?

/* Common C-state entry for C2, C3, .. */
static void acpi_cstate_enter(struct acpi_processor_cx *cstate)

{
        if (cstate->space_id == ACPI_CSTATE_FFH) {
                /* Call into architectural FFH based C-state */
                acpi_processor_ffh_cstate_enter(cstate);
        } else {
                int unused;
                /* IO port based C-state */
                inb(cstate->address);
                /* Dummy wait op - must do something useless after P_LVL2 read
                   because chipsets cannot guarantee that STPCLK# signal
                   gets asserted in time to freeze execution properly. */
                unused = inl(acpi_gbl_FADT.xpm_timer_block.address);
        }
}

Clearly that inb() won't actually idle under QEMU. So the question is, if C3 stated is reported, that port read should be emulated... But how?

http://www.mail-archive.com/[email protected]/msg05360.html

Quoted 5 lines · Yunfeng
Quoted 4 lines

I ran the same image under qemu 0.9.0, uniprocessor, and got the same
results: high host cpu usage while the guest is idle. Most likely the BIOS ACPI tables are misconfigured and the Windows idle loop is

confused.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

#28 lore raw
Quoted 1 line

And turning of the TSC bit (for 32-bit guests).

Turning off the TSC bit will break 64bit Linux (it checks if the cpuid bits have minimum supported features) and you don't know in advantage if a guest is 32bit or not.

Ok there is a special BIOS call that the kernel issues to tell the BIOS that it is 64bit -- in theory you could intercept that one and then disable the TSC bit, but it doesn't sound very clean.

Also that call wasn't in the very first 64bit kernels.

-Andi

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

#29 lore raw
In reply to Marcelo Tosatti
Quoted 3 lines · Marcelo Tosatti

Avi, do you understand why C3 was causing the Windows SMP problems ?

It may be that the latency was advertised as so low that Windows switched into C3 and back too often.

Also, the problem possibly wasn't SMP related but rather TPR related -- when the idle loop called acpi to do the mode switches, that caused many tpr hits. Perhaps with a FlexPriority enabled processor it would work better.

Signature · 7 lines
error compiling committee.c: too many arguments to function


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
#30 lore raw
In reply to Marcelo Tosatti

[Resurrecting post from the dead]

Quoted 8 lines · Marcelo Tosatti

Forcing clustered APIC mode works only on SMP, and there were high CPU consumption on Windows SMP guests due to C3 state being reported (fixed in kvm-30 something).

So perhaps:
- Faking clustered APIC on SMP
- Faking C3 on UP

Quoted 7 lines

And turning of the TSC bit (for 32-bit guests).

Is the way to go?

Avi, do you understand why C3 was causing the Windows SMP problems ?

It's probably inb()ing on the port in a loop. It's not SMP causing the problems, but the ACPI HAL. I'll check this.

Quoted 17 lines

/* Common C-state entry for C2, C3, .. */
static void acpi_cstate_enter(struct acpi_processor_cx *cstate)

{
        if (cstate->space_id == ACPI_CSTATE_FFH) {
                /* Call into architectural FFH based C-state */
                acpi_processor_ffh_cstate_enter(cstate);
        } else {
                int unused;
                /* IO port based C-state */
                inb(cstate->address);
                /* Dummy wait op - must do something useless after P_LVL2 read
                   because chipsets cannot guarantee that STPCLK# signal
                   gets asserted in time to freeze execution properly. */
                unused = inl(acpi_gbl_FADT.xpm_timer_block.address);
        }
}
Quoted 3 lines

Clearly that inb() won't actually idle under QEMU. So the question is, if C3 stated is reported, that port read should be emulated... But how?

We can add now use the KVM_SET_MPSTATE ioctl to halt the vcpu if we see the port read. Since not all hosts support setting mpstate, the bios should only report C3 if the host supports it.

Signature · 8 lines
error compiling committee.c: too many arguments to function


-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
#31 lore raw
Quoted 13 lines · Avi Kivity

[Resurrecting post from the dead]

Quoted 9 lines · Marcelo Tosatti

Forcing clustered APIC mode works only on SMP, and there were high CPU consumption on Windows SMP guests due to C3 state being reported (fixed in kvm-30 something).

So perhaps:
- Faking clustered APIC on SMP - Faking C3 on UP

And turning of the TSC bit (for 32-bit guests).

Quoted 8 lines
Quoted 4 lines

Is the way to go?
Avi, do you understand why C3 was causing the Windows SMP problems ?

It's probably inb()ing on the port in a loop. It's not SMP causing the problems, but the ACPI HAL. I'll check this.

Yes, it's reading 0xb010 and 0xb014, which ought to place the cpu in sleep mode, but don't.

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


-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone