mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: cpu: Re-sync vCPU TSC offsets after restore
Restoring a snapshot (snapshot restore or live-migration receive) sets each vCPU's TSC by writing MSR_IA32_TSC as the vCPU is created. However because CpuManager creates and restores vCPUs one at a time, the host TSC advances between the per-vCPU writes and KVM derives a slightly different TSC offset for each vCPU. KVM only engages its masterclock when every offset matches. This has a side effect of breaking the HyperV TSC reference clock page resulting in significantly reduced performance on Windows. After restore synchronise all vCPU's TSC offset to the boot vCPU's via the KVM_VCPU_TSC_CTRL device attribute group (Linux 5.16+) this allows the KVM TSC masterclock to engage and mitigates performance issues with the KVM HyperV emulation. See: #8383 Signed-off-by: Rob Bradford <rbradford@meta.com> Assisted-by: Claude <claude-opus-4-8>
This commit is contained in:
@@ -1120,9 +1120,36 @@ impl CpuManager {
|
||||
)?);
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
if snapshot.is_some() {
|
||||
Self::synchronize_tsc_offsets(&vcpus);
|
||||
}
|
||||
|
||||
Ok(vcpus)
|
||||
}
|
||||
|
||||
// Synchronize TSC offsets (mitigates each vCPU being restored at a slightly different time)
|
||||
// and allows the TSC masterclock to engage.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn synchronize_tsc_offsets(vcpus: &[Arc<Mutex<Vcpu>>]) {
|
||||
let Some(reference) = vcpus.first() else {
|
||||
return;
|
||||
};
|
||||
let offset = match reference.lock().unwrap().vcpu.tsc_offset() {
|
||||
Ok(Some(offset)) => offset,
|
||||
Ok(None) => return,
|
||||
Err(e) => {
|
||||
warn!("Could not read vCPU TSC offset for resync: {e}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
for vcpu in vcpus {
|
||||
if let Err(e) = vcpu.lock().unwrap().vcpu.set_tsc_offset(offset) {
|
||||
warn!("Could not synchronize vCPU TSC offset: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub fn init_pmu(&self, irq: u32) -> Result<bool> {
|
||||
for cpu in self.vcpus.iter() {
|
||||
|
||||
Reference in New Issue
Block a user