参考链接:http://blog.csdn.net/DroidPhone/article/category/1263459
关键字:定时器 高精度定时器 HZ usleep
一、低精度定时器
利用定时器,我们可以设定在未来的某一时刻,触发一个特定的事件。所谓低分辨率定时器,是指这种定时器的计时单位基于jiffies值的计数,系统在在每个jiffie的tick事件中断中进行查询和处理定时器,这也是造成其精度只有1/HZ的原因;
假如你的内核配置的HZ是1000,那意味着系统中的低分辨率定时器的精度就是1ms。我们有时候把这种基于HZ的定时器机制成为时间轮:time wheel。
1.1 修改系统HZ的数值
较低版本的Linux系统不支持高精度定时器方案,或者平台硬件不支持高精度的定时器。基于此,我们可以通过修改HZ的值去改变定时器的精度。
在文件arch/arm/Kconfig 文件中
config HZ int default 200 if ARCH_EBSA110 || ARCH_S3C2410 || ARCH_S5P64X0 || \ ARCH_S5PV210 || ARCH_EXYNOS4 default OMAP_32K_TIMER_HZ if ARCH_OMAP && OMAP_32K_TIMER default AT91_TIMER_HZ if ARCH_AT91 default SHMOBILE_TIMER_HZ if ARCH_SHMOBILE default 100
修改上述默认数值100,即可改变系统HZ的值。
1.2 修改HZ的负面影响
HZ越小,进程切换的频率就越低,进程响应的速度就会下降。HZ越大,进程切换的频率就越大,相应的进程相应的速度也会越快,但是频繁的进程切换会耗费过多的时间,系统效率会降低。
依赖于系统HZ的定时器受CPU的负载情况影响,精度只会更低。
修改HZ,整个系统的节奏会改变,这样可能会带来其他意外的后果,所以不建议这么做。
二、高精度定时器
早期的内核版本中,进程的调度基于一个称之为tick的时钟滴答,通常使用时钟中断来定时地产生tick信号,每次tick定时中断都会进行进程的统计和调度,并对tick进行计数,记录在一个jiffies变量中,定时器的设计也是基于jiffies。这时候的内核代码中,几乎所有关于时钟的操作都是在machine级的代码中实现,很多公共的代码要在每个平台上重复实现。随后,随着通用时钟框架的引入,内核需要支持高精度的定时器,为此,通用时间框架为定时器硬件定义了一个标准的接口:clock_event_device,machine级的代码只要按这个标准接口实现相应的硬件控制功能,剩下的与平台无关的特性则统一由通用时间框架层来实现。
2.1 通用时间框架
时钟源设备:clocksource,时钟事件设备:clock_event_device。
clocksource不能被编程,没有产生事件的能力,它主要被用于timekeeper来实现对真实时间进行精确的统计,而clock_event_device则是可编程的,它可以工作在周期触发或单次触发模式,系统可以对它进行编程,以确定下一次事件触发的时间,clock_event_device主要用于实现普通定时器和高精度定时器,同时也用于产生tick事件,供给进程调度子系统使用。时钟事件设备与通用时间框架中的其他模块的关系如下图所示:
2.2 Hrtimer
内核用一个hrtimer结构来表示一个高精度定时器。hrtimer系统需要通过timekeeper获取当前的时间,计算与到期时间的差值,并根据该差值,设定该cpu的tick_device(clock_event_device)的下一次的到期时间,时间一到,在clock_event_device的事件回调函数中处理到期的hrtimer。
2.4 内核配置高精度定时器
对于硬件支持高精度定时器的平台,我们可以打开内核的配置选项,使用高精度的定时器提高usleep的精度。
选择 Kernel feature àHigh Resolution Timer Support 选项。
三、usleep最小睡眠时间单元
Linux程序中经常需要把进程延时一段时间,使用usleep是个很好的方法。
usleep功能把进程挂起一段时间,单位是微秒。usleep使用简单,但并不是一个精准的定时函数。
3.1 不开启高精度定时器
未开启高精度定时器,usleep的最小睡眠时间取决于HZ,当HZ=100,usleep的最小睡眠时间是10ms,HZ=1000,usleep最小睡眠时间单元是1ms。且受系统负载影响很大。
3.2 开启高精度定时器
最小睡眠时间取决于硬件定时器精度和Linux 时间框架clock_event_device的粒度影响,实测最小睡眠时间单位可达70uS。