专栏首页皮振伟的专栏[virt][qemu]clocksource的管理和虚拟化

[virt][qemu]clocksource的管理和虚拟化

前言: kvm-clock,tsc,hpet,acpi_pm,pit,rtc。。。这些词看着都晕了@@ 虚拟化场景下,容作者在这里一一道来。 分析: 1,Linux clocksource

以Linux为例,查看操作系统的clocksource: 在/sys/devices/system/clocksource/clocksource0目录下; available_clocksource是当前所有可用的clocksource; current_clocksource是当前正在使用的clocksource。 所以,先不管这些名词是什么东西,怎么实现的,起码kvm-clock、tsc、hpet、acpi_pm是同一类的东西;并且,在Linux上,统一管理它们,并叫“clocksource”。它们提供了timer的能力,给操作系统使用。举例来说,kernel中的调度,就需要使用timer来支持。 因为windows不开源,也不知道它的源代码,最多就是根据外部的一些现象来猜测它的逻辑。具体的代码分析都基于Linux。 2,clocksource management 主要逻辑代码在linux-4.0.4/kernel/time/clocksource.c中实现:

clocksource实现了一个基本框架,提供了clocksource_register给具体的driver使用。 其中关键函数clocksource_enqueue:

可见,所有的clocksource是根据rating参数大小被组织到了一个list中。 linux默认使用rating最高的clocksource,或者用户修改过clocksource,通过clocksource_select函数生效。 在linux-4.0.4/arch/x86/kernel/kvmclock.c:

声明了kvm-clock的rating是400; 同理,在linux-4.0.4/arch/x86/kernel/tsc.c中,可以看到tsc的rating是300; linux-4.0.4/arch/x86/kernel/hpet.c中,hpet的rating是250; linux-4.0.4/drivers/clocksource/acpi_pm.c中,acpi_pm的rating是200; linux-4.0.4/drivers/clocksource/i8253.c中,pit的rating是110。 综上,Linux大致实现了clocksource的管理框架,各个timer实现自己的drvier,并注册到clocksource中。根据rating来看timer的性能:kvmclock>tsc>hpet>acpi_pm>pit。 3,kvmclock kvmclock比较特殊,是在kvm虚拟化的时候使用的,物理机上并没有---这也是和其他的timer很大的一个差别。 在linux-4.0.4/arch/x86/kernel/kvmclock.c中,kvmclock实现的关键函数:

计算出来pvit的物理地址(这个“物理地址”,其实是Guest Physical Address,即GPA),写MSR寄存器,通过msr_kvm_system_time(MSR_KVM_SYSTEM_TIME),告诉Host它的pvit地址。 在Host中: linux-4.0.4/arch/x86/kvm/x86.c文件中kvm_set_msr_common函数:

这里说一下,Guest中使用了wrmsr指令,Host会感知,然后进入到kvm_set_msr_common中处理。可见,通过kvm_gfn_to_hva_cache_init函数,会把传过来的地址参数data记录到pv_time中。这样子就可以通过pv_time来直接修改Guest中的pvit。 因为Host和Guest,使用的是相同的tsc,这里还需要说明一个问题: 参考linux-4.0.4/arch/x86/kvm/x86.c文件中kvm_guest_time_update函数: 关于Guest中的时间的计算,pv time中有两个重要参数:tsc_timestamp和system_time Guest Sytem Time = Guest Sytem Time + offset; 为什么要这么麻烦的计算? 因为热迁移。两台Host的TSC不一样,如果Dst Host的TSC比Src Host的TSC小,那么可能会让Windows蓝屏或者linux panic。 如果Dst Host的TSC比Src Host的TSC大,那么在Guest中看到tsc瞬间跳变。所以需要计算offset来调整。 另外,在Guest中,还需要做一次计算delta: 在linux-4.0.4/arch/x86/include/asm/pvclock.h文件中的__pvclock_read_cycles函数中: 计算Host中读取到Tsc和Guest中读取到的Tsc的差值,再计算出来delta,最后再计算出来Guest中的“kvmclock”。这里把Host和Guest中前后两次的Tsc微小差值都计算进去了,可见精度确实很高。 kvmclock是kvm虚拟化中rating最高的timer;当然,它的计算也真的很麻烦。 4,tsc 如果Guest中使用rdtsc指令,则会被Host拦截,Host中处理后返回给Guest: linux-4.0.4/arch/x86/kvm/emulate.c中:

继续调用,会到linux-4.0.4/arch/x86/kvm/vmx.c中:

先读取出来Host的Tsc,在加上offset。offset的原理也是为了防止热迁移tsc变小。 这里再说一下tsc的timer。因为tsc只是一个单调递增的寄存器,本身不能产生timer的irq。设置了tsc之后,apic会产生timer的irq。 5, hpet hpet是纯粹的qemu在用户态模拟出来的。 代码qemu-2.8.0-rc4/hw/timer/hpet.c

qemu的设备虚拟化逻辑。注意,是为hpet设备注册了callback函数hpet_timer: 前面是计算下次超时的时间,最后一行很关键,向Guest里inject irq了。 所以,hpet的逻辑就很清晰了:qemu模拟了hpet device,并在用户态周期性的inject irq,在Guest中就觉得是一个timer了。 6, pit 代码实现在:linux-4.0.4/arch/x86/kvm/i8254.c中:

关键代码分析,Host为Guest的pit创建了一个内核线程,名称就是“kvm-pit/PID”。所以,启动一个qemu虚拟机之后,ps找到qemu的pid,然后就能看到一个对应的内核线程。稍微说一下,这个线程稍微特殊一点,不是一个常规定义的routine函数,是基于kernel worker机制。

继续分析,当Guest中激活了PIT之后,Host中调用create_pit_timer函数创建一个hr timer。hr timer会在interval后调用callback函数---pit_timer_fn。 pit_timer_fn就是把一个work加入到worker queue中,刚刚创建的kvm-pit线程就可以执行了。kvm-pit真正执行的,就是pit_do_work函数。

好吧,又向Guest中inject irq了。 这里多说一句哈,在Guest Linux上,虽然创建了kvm-pit线程,但是却没有跑;在Guest windows上,kvm-pit线程周期性的执行work。

后记:

总结上述timer的逻辑,或使用不同的硬件,或使用软件,或在内核态,或在用户态,都是周期性地向Guest中inject irq。

KVM虚拟化CPU和管理内存,qemu虚拟化设备,加上上述的timer,还有就是apic,那么龙珠就集齐了,可以召唤神龙了~

本文分享自微信公众号 - AlwaysGeek(gh_d0972b1eeb60),作者:AlwaysGeek

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-02-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • [kvm][virt]PIO技术分析

    前言: 基于KVM的设备虚拟化,就从这里开始吧。 分析: 1,PIO Port IO,所谓端口IO,x86上使用in、out指令进行访问。和内存的地址空间完...

    皮振伟
  • [virt][clock]steal time技术分析

    前言: 在《clocksource的管理和虚拟化》中,大概分析了kvm clock,tsc,hpet等clock source。其中尤其是kvm clock计算...

    皮振伟
  • ​[linux][memory]cgroup回收内存对虚拟机的影响分析

    前言: 在虚拟化场景下,libvirt会为每个qemu进程,也就是一台虚拟机,创建对应的cgroup,用来限制这台虚拟机的资源使用。这章讨论一下cgroup对内...

    皮振伟
  • Ubuntu 常用技巧

    程序手艺人
  • 聊聊nacos-sdk-go的NamingClient

    nacos-sdk-go-v0.3.2/clients/naming_client/naming_client.go

    codecraft
  • 聊聊nacos-sdk-go的NamingClient

    nacos-sdk-go-v0.3.2/clients/naming_client/naming_client.go

    codecraft
  • 日志帮助类

     1.代码 using System; using System.Collections.Generic; using System.Linq; using S...

    用户1055830
  • CLI简介与linux命令初步

    作为开篇,我们对命令行接口和linux命令做一下简介。之后的几篇我们会进入到linux常用基础命令的讲解中。let's begin!

    用户5030870
  • 腾讯超越IBM 解读2015年全球创新企业

    波士顿顾问集团(Boston Consulting Group)2日发布一份面向1500家企业创新能力的评估报告,今年的榜首和榜眼仍是苹果及谷歌,依序分别为特斯...

    人称T客
  • 牛X!纽约餐厅用数据说话,应对差评

    大数据文摘

扫码关注云+社区

领取腾讯云代金券