乐趣区

关于kvm:KVM时钟漂移

KVM 中 Windows Guest 工夫漂移

起因

测试发现当虚拟机运行前期初工夫和宿主机保持一致,而应用一段时间后两者之间就产生了显著的差异,具体表现为虚拟机的工夫会比宿主机的慢,另体现为应用频率高时会比低时偏移的体现更加显著。

起因

经翻阅材料才搞明确这是一个 kvm 时钟至今存在的一个无奈防止的问题就是所谓的虚拟机工夫漂移

传统时钟

咱们晓得传统时钟有 RTC/HPET/PIT/ACPI PM TIMER/TSC 等, 这些时钟按原理可分成两类:提供中断的周期性时钟, 如 RTC/PIT/HPET 等;另一种是提供 COUNTER 计数器的单步递增性时钟,如 TSC。

虚拟化下的时钟

  1. TSC
    Guest 中应用 rdtsc 指令读取 TSC 时,会因为 EXIT_REASON_RDTSC 导致 VM Exit。VMM 读取 Host 的 TSC 和 VMCS 中的 TSC_OFFSET,而后把 host_tst+tsc_offset 返回给 Guest。
    要做出 OFFSET 的起因是思考到 vcpu 热插拔和 Guest 会在不同的 Host 间迁徙。
  2. qemu 软件模仿的时钟:
    qemu 中有对 RTC 和 hpet 都模拟出了相应的设施,例如 RTC 的典型芯片 mc146818。
    这种软件模仿时钟中断存在的问题:因为 qemu 也是应用程序,收到 cpu 调度的影响,软件时钟中断不能及时产生,并且软件时钟中断注入则是每次产生 VM Exit/Vm Entry 的时刻。所以软件模仿时钟就无奈精准的登程并注入到 Guest,存在提早较大的问题。
  3. kvm-clock:
    kvm-clock 是 KVM 下 Linux Guest 默认的半虚拟化时钟源。在 Guest 上实现一个 kvmclock 驱动,Guest 通过该驱动向 VMM 查问工夫。临时在 windows 内没有,具体原理临时未知。
    其工作流程也比较简单:Guest 调配一个内存页,将该内存地址通过写入 MSR 通知 VMM,VMM 把 Host 零碎工夫写入这个内存页,而后 Guest 去读取这个工夫来更新。
    这里应用到的两个 MSR 是:MSR_KVM_WALL_CLOCK_NEW 和 MSR_KVM_SYSTEM_TIME_NEW(这是新的,应用 cpuid 0x40000001 来标记应用新的还是旧的)别离对应 pvclock_wall_clock 和 pvclock_vcpu_time_info(具体构造体中的内容在内核代码中可查看)。
    Linux Guest 中查看以后时钟源是否为 kvm-clock:
$ cat /sys/devices/system/clocksource/clocksource0/current_clocksource

$ kvm-clock

解决办法

以下摘自 qemu 代码中 qemu-options.hx 的原文:
(-rtc base=utc|localtime|date[,driftfix=none|slew])
Enable @option{driftfix} (i386 targets only) if you experience time drift problems, specifically with Windows’ ACPI HAL. This option will try to figure out how many timer interrupts were not processed by the Windows guest and will re-inject them.
大抵意思就是:如果有工夫漂移问题能够尝试计算出(零碎中没有解决的计数器终端数量),并从新注入。

说白了就是,写个脚本依照一个特定的工夫去从新同步时钟。

解决思路

  1. 能够在 windows 现有的虚拟化 agent 上增加工夫同步的代码。能够通过串口和宿主机通信进行时钟同步,另外这样做的益处宿主能够自定义时钟同步的工夫,不便解决。
  2. 另外能够批改 windows 内工夫同步的距离,例如改为 3 分钟:在注册表内“HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\W32Time\TimeProviders\NtpClient”下的 SpecialPollInterval 单位为秒
退出移动版