设为首页 收藏本站
查看: 2588|回复: 0

[经验分享] Qemu-KVM TSC研究总结

[复制链接]
累计签到:13 天
连续签到:1 天
发表于 2015-12-24 15:26:40 | 显示全部楼层 |阅读模式
响应延时的实时测试需要读TSC,但是这两天做实验发现一个很奇怪的问题,用VxWorks作为guest时,对于类似“tsc1=rdtsc;nanosleep(100);tsc2=rdtsc;” 的程序,tsc2却总是比tsc1要小了。而用Linux作为guest时,对于类似的程序,是没有问题的。那么,是否是kvm中对于TSC的处理有问题呢?带着这个问题,我把kvm-kmod-2.6.33.1中的TSC处理机制研究了一下。
首先要提到影响guest rdtsc指令结果的因素。在vmcs中有两个很重要的字段:RDTSC_EXITING和TSC_OFFSETTING两个控制位决定了guest RDTSC将发生什么事:
1. 当EXITING为1时,guest rdtsc将导致VM-Exit;
2. 当EXITING为0时,OFFSETTING为0时,直接guest rdtsc直接将物理TSC导入EDX:EAX;
3. 当EXITING为0时,OFFSETTING为1时,guest rdtsc读出物理TSC再加上tsc_offset再导入EDX:EAX。
在"VMCS研究总结"一文中提到过,kvm采用第3种模式,我的疑问是为什么要tsc_offset特性,为什么不采用第二种最直接的方式。还有,读取TSC的方式其实不止RDTSC一种,还有RDMSR也可以,参数指定MSR_IA32_TSC就可以了,RDMSR就会造成VM-Exit,随后在在handle_rdmsr中处理,进而调用guest_read_tsc,其中就可以发送它也是返回host_tsc+tsc_offset。
我个人认为,这个tsc_offset可能是用于支持live migration:VM在A机器中跑,TSC读取的是A机器CPU的,如果live migrate到机器B,机器B的TSC肯定与A不同,这时用tsc_offset就可以实现guest TSC同步,主要是避免了guest TSC在live migration后发生变小的情况,保证TSC总是单调递增的。
先抛开上述的问题,现在假定有这个tsc_offset,下一个研究问题就是,kvm在哪里及如何设置这个tsc_offset呢?

kvm中只有三个地方会写vmcs中的TSC_OFFSET字段:vmx_vcpu_load、vxm_vcpu_setup及vxm_set_msr。其中后面两个都是通过调用guest_write_tsc来完成的。vmx_vcpu_load和vmx_vcpu_setup都是在vmx_create_vcpu中调用的,其中vmx_vcpu_load在前。注意:vmx_vcpu_setup只会在vmx_create_vcpu调用,有几个vcpu被创建就调用几次;但是vmx_vcpu_load好像是在每次进入guest前都要调用的,是通过kvm_x86_ops->vcpu_load调用。
那么首先就来看vmx_vcpu_load中关于tsc的以下代码:首先读当前tsc,如果tsc_this小于arch.host_tsc,那么TSC_OFFSET将加上两者之间的差。这个arch.host_tsc在第一次vmx_create_vcpu里面应该是为0的,所以第一次vcpu刚创建时if代码应该不会执行。我想它应该是用于后面第二次调用vmx_vcpu_load时同步host_tsc和guest_tsc的。写入arch.host_tsc是在__vcpu_clear中,现在还不太清楚这个函数的作用是什么,不过我猜想是每次退出guest模式时调用__vcpu_clear,下次重新进入guest模式前调用vmx_vcpu_load,一般情况下肯定是tsc_this大于arch.host_tsc,但是当有live migration情况下,就不一定了,这个地方应该就是为了live migration而加的吧!
rdtscll(tsc_this);
if (tsc_this <
vcpu->arch.host_tsc) {
delta = vcpu->arch.host_tsc - tsc_this;
new_offset = vmcs_read64(TSC_OFFSET) + delta;
vmcs_write64(TSC_OFFSET, new_offset);

}
再来vmx_vcpu_setup,它紧跟着vmx_vcpu_load被调用,其中关于tsc的代码如下:首先要搞清楚arch.vm_init_tsc是指什么?它是在kvm_arch_create_vm(x86.c)中调用rdtscll读入的,也就是说它指的是vm创建时的tsc。vcpu创建必然是在vm创建之后,所以一般情况下这里的tsc_this都要比arch.vm_init_tsc大,我想只有当live migration时才会出现比其小的情况。所以一般情况下,以下if语句不会执行。再看看guest_write_tsc调用,它将第一个参数减去第二个参数的结果写入TSC_OFFSET。因此,这里的调用会将-tsc_base写入,意味着什么呢?由于guest_tsc=host_tsc + tsc_offset = host_tsc - tsc_base = host_tsc - arch.vm_init_tsc,也就是说kvm配置是让virtual tsc从vm创建的时刻,即写入arch.vm_init_tsc时开始从0计数。

tsc_base = vmx->vcpu.kvm->arch.vm_init_tsc;
rdtscll(tsc_this);
if (tsc_this < vmx->vcpu.kvm->arch.vm_init_tsc)
tsc_base = tsc_this;
guest_write_tsc(0, tsc_base);
最后来看vmx_set_msr,关于tsc代码如下:vmx_set_msr用于处理guest对msr(Machine-Specific Register)写操作,这里guest意思是将guest TSC设置成data值。那么相当于现在开始guest TSC从data开始计数,所以设置TSC_OFFSET为(data - host_tsc),也就是说实际的guest_tsc= host_tsc + TSC_OFFSET = data。
case MSR_IA32_TSC:
rdtscll(host_tsc);
guest_write_tsc(data,host_tsc)




ne

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-155834-1-1.html 上篇帖子: 内核虚拟化KVM——overview 下篇帖子: 确定虚拟机是Xen还是KVM
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表