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

你可能感兴趣的:(kvm时钟)