首页 理论教育深入剖析Linux内核及设备驱动:时间管理框架介绍

深入剖析Linux内核及设备驱动:时间管理框架介绍

【摘要】:1老版本内核时间管理框架在Linux 2.6.16之前,内核一直使用一种称为timer wheel的机制来管理时钟。这就是熟知的基于Hz的timer机制。2新的时间管理框架为了解决timer wheel低精度以及与内核其他模块的高耦合性的缺点,Linux内核引入了hrtimer。它是建立在per-cpu时钟事件设备基础上的。图4-48Linux内核时间管理框架⑤dynamic tick。它能在系统空闲时通过停止tick的运行以达到降低处理器功耗的目的。dynamic tick是为彻底替换掉周期性的tick机制而产生的。这是因为hrtimer在高精度模式时必须使

1ᤫ老版本内核时间管理框架

在Linux 2.6.16之前,内核一直使用一种称为timer wheel的机制来管理时钟。这就是熟知的基于Hz的timer机制。timer wheel有占用的内存少等优点,但timer wheel的实现机制仍然存在弊端。一方面timer wheel是为timeout类型的定时器优化的,并不适合精准定时timer;另一方面,由于timer wheel是建立在Hz的基础上的,因此其计时精度无法进一步提高。毕竟一味的通过提高Hz值来提高计时精度并无意义,结果只能是产生大量的定时中断,增加额外的系统开销。因此,有必要将高精度的timer与低精度的timer分开,这样既可以确保低精度的timeout类型的定时器应用,也便于高精度的timer类型定时器的应用。另外timer wheel的实现与jiffies的耦合性太强,非常不便于扩展。

2ᤫ新的时间管理框架

为了解决timer wheel低精度以及与内核其他模块的高耦合性的缺点,Linux内核引入了hrtimer。另外为了能在电源管理方面进行优化,有必要去除以频率(Hz)触发的定时时钟中断,改为动态时钟机制(dynamic tick)或者说NO_HZ机制。新的时间管理框架如图4-48所示。

下面介绍其中的各个模块。

①时钟源设备(clock-source device)。它是系统中可以提供一定精度的计时设备。不同的时钟源提供的时钟精度是不一样的。此外,时钟源的计时都是单调递增的(monotoni-cally)。时钟源作为系统时钟的提供者,在可靠并且可用的前提下精度越高越好。在Linux中不同的时钟源有不同的频率,具有更高频率的时钟源会优先被系统使用。

②时钟事件设备(clock-event device)。它是系统中可以触发one-shot(单次)或者周期性中断的设备。某些设备既可以做时钟源设备也可以做时钟事件设备。时钟事件设备的类型分为全局和per-cpu两种类型。全局的时钟事件设备完成的是系统相关的工作,例如完成系统的tick更新;per-cpu的时钟事件设备主要完成本地CPU上的一些功能,例如对在当前CPU上运行进程的时间统计,profile,设置本地CPU上的下一次事件中断等。和时钟源设备的实现类似,时钟事件设备也通过频率来区分优先级关系。(www.chuimin.cn)

③tick device。它是用来处理周期性的tick event。tickdevice其实是对时钟事件设备的整合,因此tick device也有one-shot和周期性这两种中断触发模式。每注册一个时钟事件设备,这个设备会自动被注册为一个tick device。全局的tickdevice用来更新诸如jiffies这样的全局信息,per-cpu的tick device则用来更新每个CPU相关的特定信息。

④hrtimer。它是建立在per-cpu时钟事件设备基础上的。对于一个SMP系统,如果只有全局的时钟事件设备,hrtimer无法工作。ktime_t是hrtimer主要使用的时间结构。无论使用哪种体系结构,ktime_t始终保持64bit的精度,并且考虑了大小端的影响。hrtimer有两种工作模式:低精度模式(low-resolution mode)与高精度模式(high-resolution mode)。虽然hrtimer子系统是为高精度的timer准备的,但是系统可能在运行过程中动态切换到不同精度的时钟源设备,因此hrtimer需要能够在低精度模式与高精度模式下自由切换。低精度模式是建立在高精度模式基础之上的,在低精度模式下,hrtimer的核心处理函数是hrtimer_run_queues,每一次tick中断都要执行一次。hrtimer_bases是实现hrtimer的核心数据结构,通过hrtimer_bases,hrtimer可以管理挂在每一个CPU上的所有timer。在update_process_times中,除了处理处于低精度模式的hrtimer外,还要唤醒时间中断的softirq(TIMER_SOFTIRQ)以便执行timer wheel的代码。由于hrtimer子系统的加入,在时间中断的softirq中还需要通过hrtimer_run_pending检查是否可以将hrtimer切换到高精度模式,如果可以将hrtimer切换到高精度模式,则调用hrtimer_switch_to_hres函数进行切换。

978-7-111-49426-3-Chapter04-266.jpg

图4-48 Linux内核时间管理框架

⑤dynamic tick。它能在系统空闲时通过停止tick的运行以达到降低处理器功耗的目的。使用dynamic tick的系统,只有在实际工作时才会产生tick,否则tick处于停止状态。dynamic tick是为彻底替换掉周期性的tick机制而产生的。它对周期性运行的tick机制所完成的(如进程时间片的计算、更新profile、协助CPU进行负载均衡等)诸多工作都提供了相应的模拟机制。hrtimer从低精度模式切换到高精度模式的切换点,也是低精度模式下从周期性tick到dynamic tick的切换点,会将tick切换到one-shot模式下,另外通过tick_nohz_handler模拟周期性tick device完成的工作:如果当前CPU负责全局tick device的工作,则更新jiffies,同时完成对本地CPU的进程时间统计等工作;如果当前tick device在此之前已经处于停止状态,为了防止tick停止时间过长造成watchdog超时,从而引发soft-lockdep的错误,需要通过调用touch_softlockup_watchdog软件复位看门狗防止其溢出;设置了下一次的超时事件,但是由于系统空闲时会停止tick,因此下一次的超时事件可能发生,也可能不发生。在高精度模式下tick_sched_timer用来模拟周期性tick device的功能。dynamic tick的实现也使用了这个函数。这是因为hrtimer在高精度模式时必须使用one-shot模式的tick device,这也同时符合dynamic tick的要求。虽然使用同样的函数,表面上都会触发周期性的tick中断,但是使用dynamic tick的系统在空闲时会停止tick工作,因此tick中断不会是周期产生的。对于tick的开关在cpuidle中通过tick_nohz_stop_sched_tick和tick_nohz_restart_sched_tick来实现,其中通过tick_do_update_jiffies64来更新时间,保证模拟的正确性。