linux time和kvm time虚拟化综述

2021-06-25 10:11:23 浏览数 (1)

linux time

linux对时间有两种需求:

第一就是获取当前时间,就像人想知道时间时看墙上挂的时钟一样,简称clock,如time()/ftime()/gettimeofday()/data()等这些系统调用,都是软件主动获取时间。

第二就是定时器,就像闹钟一样,有点特殊的闹钟,这个闹钟不是说几点到了响铃通知我,而是说半个小时后响铃,或者我想睡觉8小时,8小时后就响铃,如timerfd_create()/sleep()/delay()这些函数。

clock软件是无法实现的,只能是硬件实现,硬件增加一个counter寄存器,周期性增加,软件想获取当前时间,读一下这个寄存器就行,linux把这个counter称为clocksource,比如这台服务器就有三个clocksource,选择用一个就行。

代码语言:javascript复制
[root@test] /home/huiwei$ cat /sys/devices/system/clocksource/clocksource0/available_clocksource
tsc hpet acpi_pm
[root@test] /home/huiwei$ cat /sys/devices/system/clocksource/clocksource0/current_clocksource
tsc

timer分为硬件定时器和软件定时器,硬件定时器数量有限,软件定时器随便增加,软件定时器是由硬件定时器驱动起来的,CPU一直忙着干活,根据就不知道软件定时器是否超时了,只能靠硬件定时器周期性中断打断CPU,CPU再检查哪些软件定时器超时了,linux把硬件定时器称为clockevent。

代码语言:javascript复制
[root@test] /home/huiwei$ cat /sys/devices/system/clockevents/broadcast/current_device
hpet
[root@test] /home/huiwei$ cat /sys/devices/system/clockevents/clockevent0/current_device
lapic-deadline

clock和timer是概念,clocksource和clockevent是linux对这两个概念的抽象,体系结构无关的,hpet/tsc/pit/rtc/acpi_pm/lapic-deadline是硬件设备,是x86体系结构下的硬件设备,也许arm/ppc/mips下就是其它名称的硬件,硬件有的只提供clock功能,有的clock和timer功能都提供,clock和timer有全局的,也有局部的,如tsc就是一个cpu一个,hpet就是全局的,所有cpu都可以读。

看x86代码,linux初始化这些硬件设备,注册中断,中断处理中都调用到event_handler,简单理解为tick模块注册的函数,调用到tick的这个函数,它负责处理软件定时器,进行进程时间片计算等,当然tick觉得timer中断太多就可以把超时时间修改长一点,这样cpu不会被频繁打扰。

代码语言:javascript复制
static void local_apic_timer_interrupt(void)
{
	struct clock_event_device *evt = this_cpu_ptr(&lapic_events);
	evt->event_handler(evt);
}

/*
 * Local APIC timer interrupt. This is the most natural way for doing
 * local interrupts, but local timer interrupts can be emulated by
 * broadcast interrupts too. [in case the hw doesn't support APIC timers]
 *
 * [ if a single-CPU system runs an SMP kernel then we call the local
 *   interrupt as well. Thus we cannot inline the local irq ... ]
 */
DEFINE_IDTENTRY_SYSVEC(sysvec_apic_timer_interrupt)
{
	local_apic_timer_interrupt();
}



/*
 * Default timer interrupt handler for PIT/HPET
 */
static irqreturn_t timer_interrupt(int irq, void *dev_id)
{
	global_clock_event->event_handler(global_clock_event);
	return IRQ_HANDLED;
}

static void __init setup_default_timer_irq(void)
{

	if (request_irq(0, timer_interrupt, flags, "timer", NULL))
		pr_info("Failed to register legacy timer interruptn");
}

kvm time

虚拟机中看到的关于时间的硬件都是假的,rtc/pit/hpet/tsc/lapic local timer都是假的,那么guest读clock当前时间就会导致exit出来,exit出来后kvm计算出一个值返回给guest。guest写timer的超时时间就会导致exit出来,exit出来后kvm给一个软件定时器设置超时时间,等这个软件定时器超后,kvm生成一个时间虚拟中断,把这个中断注入给虚拟机。

看这台虚拟机,模拟rtc和pit,没有hpet。

代码语言:javascript复制
<clock offset='utc'>
    <timer name='pit' tickpolicy='delay'/>
    <timer name='rtc' tickpolicy='catchup'/>
    <timer name='hpet' present='no'/>
</clock>
-rtc base=utc,driftfix=slew -global kvm-pit.lost_tick_policy=delay -no-hpet

内核多了一个pit线程

代码语言:javascript复制
[kvm-pit/759886]

虚拟机里看clocksource和clockevent,clocksource用的是kvm-clock那就是因为kernel检测到自己运行在kvm上,并且kvm提供了kvmclock特性。

代码语言:javascript复制
[root@syh2021v ~]# cat /sys/devices/system/clocksource/clocksource0/available_clocksource
kvm-clock tsc acpi_pm
[root@syh2021v ~]# cat /sys/devices/system/clocksource/clocksource0/current_clocksource
kvm-clock
[root@syh2021v ~]# cat /sys/devices/system/clockevents/broadcast/current_device
pit
[root@syh2021v ~]# cat /sys/devices/system/clockevents/clockevent0/current_device
lapic-deadline

虚拟机中时间存在很多问题,如时间跳跃,时间倒退,而且虚拟机要热迁移,两台host情况不一样,会报错。

代码语言:javascript复制
2020-09-14T02:58:56.537854Z qemu-kvm: warning: TSC frequency mismatch between VM (2094951 kHz) and host (2593749 kHz), and TSC scaling unavailable

读counter exit出来,模拟出一个值,那怎么个模拟法,这个模拟过程用了多久时间,重新enter又要用多久,最后在虚拟机中看到的counter就是不准,而且exit出来影响性能,所以就有kvmclock这样的pv方案,读counter不exit出来,或者pasthrough方案,如虚拟机中rdtsc直接读cpu内部counter,或者硬件辅助一下的方案。物理cpu exit出来后再重新enter执行guest,那谁来让软件定时器超时?软件定时器是不准的,kvm软件定时器模拟硬件定时器肯定不准,而且时间虚拟中断不一定能及时注入虚拟机中。

再考虑一些问题,有全局hpet和局部local apic timer,cpu会用哪个呢?hpet中断哪个cpu处理?其它cpu收不到这个中断怎么tick呢?软件定时器是全局的还是局部的?

总结

虚拟化中时间问题太复杂,有些问题还没想明白,后面再对tsc虚拟化pv timer一一分解,这个算是综述,全当抛砖引玉。

0 人点赞