tsc_deadline和tsc_adjust虚拟化场景影响
1. tsc_deadline及其影响
Linux上tsc_deadline机制说明
tsc_deadline是tsc机制的一种,通过cat /proc/cpuinfo可以获取当前cpu是否支持tsc特性。对于local APIC timer机制,有3中timer机制,分别是:
- one-shot模式,这种模式下,通过编程赋初始值到当前计数寄存器,该寄存器接下来会随着时间推移自减,当到达0的时候,会产生一个时钟中断,直到下次重新编程,该值一直处于0。即单次触发。
- periodic模式,同ones-shot模式类似,也是基于计数器自减,但不同的是,当时钟中断产生后,会重新开始计数器自减,即周期性产生时钟中断。
- tsc_deadline模式,tsc-deadline模式下,当本地cpu的tsc大于等于其IA32_TSC_DEADLINE MSR的值时触发lapic timer中断。
对于操作系统,其初始启动时都使用的PERIODIC模式,当可用作HRES的时钟源注册后,更优的时钟源被选择会触发tick_device的工作模式切换,即从PERIODIC模式切换为ONESHOT模式。对于lapic tick device,其初始化的setup_APIC_timer()函数中,会判定CPU是否支持tsc_deadline,若支持,则会将其set_next_event函数指针赋值为lapic_next_deadline,即通过tsc_deadline机制产生时钟中断。
1 | static int lapic_next_deadline(unsigned long delta, |
2. QEMU-KVM虚拟化场景下tsc_deadline及VMX_PREEMPTION_TIMER的原理分析
由上述可知,对于QEMU-KVM虚拟化场景,oneshot模式的lapic timer设定机制有2种:
- TSC_DEADLINE:即guest os的lapic驱动在设置下一时钟中断,通过wrmsr(MSR_IA32_TSC_DEADLINE,),触发CPU从guest模式退出到VMM,kvm模块截获EXIT REASON后,通过kvm_set_lapic_tscdeadline_msr()函数设置下次lapic时钟中断。
- 无TSC_DEADLINE特性,此时guest kernel通过apic_write(APIC_TMICT, delata)写入下次触发间隔,触发VM_EXIT,kvm模块调用kvm_set_msr_common()–> kvm_x2apic_msr_write()–>kvm_lapic_set_reg()-> set_target_expiration()+restart_apic_timer(apic)设置下次时钟中断。
####关于VMX_PREEMPTION_TIMER机制
VMX_PREEMPTION_TIMER机制主要影响lapic timer触发机制:当使能VMX_PREEPTION_TIMER机制时,当timer时刻点到达时,CPU会直接从guest模式EXIT,其EXIT REASON为EXIT_REASON_PREEMPTION_TIMER,如此,通过handle_preemption_timer()对vcpu->arch.apic.laic_timer.pending加1,后续可通过该pending值大于0判定此时需要注入lapic timer中断,通过kvm_inject_pending_timer_irqs()进行注入。
当不使能VMX_PREEPTION_TIMER机制时,host上基于hrtimer机制设置guest vcpu lapic timer,即当hrtimer到达后,触发器callback apic_timer_fn,调用apic_timer_expired(apic) pend lapic中断。但为vcpu 注入中断机制一致。不同的是,此时host需进入中断处理流程。
3. 影响
从上述可知,使用tsc_deadline和不使用tsc_deadline机制是类似的,guest设置apic timer时都需EXIT到VMM进行处理,理论上对虚拟机性能影响差异不大。若使用VMX_PREEMPTION_TIMER机制,会导致EXIT_REASON_PREEMPTION_TIMER,但应会减小host上apic timer中断,即最终应减小guest上的irq_exit,而host apic timer需host内核进入中断处理,因此整体开销应会大于使用VMX_PREEMPTION_TIMER机制的情况。
2. tsc_adjust原理分析及影响
1. tsc_adjust机制
通过cat /proc/cpuinfo可获取cpu是否支持tsc_adjust特性,tsc_adjust主要用于CPU tsc软件同步。软件可以通过WRMSR指令写入IA32_TIME_STAMP_COUNTER_MSR修改TSC值。由于这个写操作只会应用到逻辑CPU,软件寻求在多个逻辑处理器上同步TSC值必须在每个逻辑处理器中执行这一操作。对软件来说这相比于让所有TSC在给定时间有相同值更难。通过使用64位的IA32_TSC_ADJUST MSR简化TSC修正同步。类似IA32_TIME_STAMP_COUNTER_MSR, 每个逻辑处理器都各自维护IA32_TSC_ADJUST。其工作机制如下:
- RESET后IA32_TSC_ADJUST为0
- 如果WRMSR 从TSC加(减)值X,逻辑处理器也会从IA32_TSC_ADJUST MSR中加或减X
- 若WRMSR从IA32_TSC_ADJUST MSR加(减)值X, 处理器中TSC也会加(减)相应值
2. Linux内核的使用
对于tsc_adjust机制,Linux内核的使用主要体现在两方面: - CPU初始化时同步tsc
- cpu_enter_idle()时恢复MSR_IA32_TSC_ADJUST 值,因为某些场景下该值可能丢失
3. qemu-kvm虚拟化场景下的影响分析
对于虚拟化场景,由于其tsc本身就是基于host cpu获取的,因此可以理解tsc_adjust在虚拟化场景下意义不大。而开启tsc_adjust特性后,cpu_enter_idle()时的rdmsr(MSR_IA32_TSC_ADJUST)会导致CPU退出到guest模式,引起VM_EXIT。因此最好是disable这一特性。