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 单位为秒