快捷搜索:  汽车  科技

linux变量的理解,Linux内核中HZtick和jiffies变量

linux变量的理解,Linux内核中HZtick和jiffies变量对于Linux内核空间而言,尽管通常我们很容易知道HZ宏的值,但是在编写驱动程序时,并不能依赖HZ的具体的值,我们始终使用的是HZ这个宏(也就是说,无论HZ的值为多少,HZ这个宏只代表CPU在1s内其定时器中断产生的次数,所以如果我们需要计算20ms的定时,直接去HZ/50即可),通常而言,我们应该完全信任内核开发者,他们已经选择了最适合当前平台的HZ值,所以一直使用默认值就好。如上两图可知,每一种CPU根据其平台的不同和运行频率的不同,其HZ的取值也不同,例如X86架构和PowerPC架构的CPU基本上都是1000。也就意味着,当__KERNEL__和CONFIG_HZ这两个宏定义后,HZ的默认值为200,即表示此平台定时器中断在1s内会产生200次。如果没有定义宏__KERNEL__,HZ的值默认为100。HZ这个值根据用户在系统移植时,可以自定义修改,比如改为1000。如上图所示,笔

linux变量的理解,Linux内核中HZtick和jiffies变量(1)

一、Linux内核中的HZ

在Linux中,HZ代表1s所产生的定时器中断(timer interrupt)的次数。它被定义在<Linux/param.h>中,其路径为:Linux/include/linux/param.h。或者有些版本的Linux内核由<Linux/param.h>中包含<asm/param.h>,那么HZ就被定义在<asm/param.h>中了,其路径为:linux-3.0.8/arch/arm/include/asm/param.h(笔者使用的Linux内核为3.0.8版本)。

linux变量的理解,Linux内核中HZtick和jiffies变量(2)

如上图所示,当HZ的取值决定于__KERNEL__和CONFIG_HZ这两个宏,当这两个宏已经定义,那么HZ的值就为CONFIG_HZ,其定义如下:

#define CONFIG_HZ 200

也就意味着,当__KERNEL__和CONFIG_HZ这两个宏定义后,HZ的默认值为200,即表示此平台定时器中断在1s内会产生200次。如果没有定义宏__KERNEL__,HZ的值默认为100。HZ这个值根据用户在系统移植时,可以自定义修改,比如改为1000。

如上图所示,笔者所使用板卡所支持的CONFIG_HZ的值为200。当由.config文件配置时,内核源码中的定义将失效。

下图为在Linux内核顶层目录使用命令:grep "CONFIG_HZ" . -r -n 递归搜索Linux-3.0.8版本内核中关于CONFIG_HZ的定义。

linux变量的理解,Linux内核中HZtick和jiffies变量(3)

linux变量的理解,Linux内核中HZtick和jiffies变量(4)

如上两图可知,每一种CPU根据其平台的不同和运行频率的不同,其HZ的取值也不同,例如X86架构和PowerPC架构的CPU基本上都是1000。

对于Linux内核空间而言,尽管通常我们很容易知道HZ宏的值,但是在编写驱动程序时,并不能依赖HZ的具体的值,我们始终使用的是HZ这个宏(也就是说,无论HZ的值为多少,HZ这个宏只代表CPU在1s内其定时器中断产生的次数,所以如果我们需要计算20ms的定时,直接去HZ/50即可),通常而言,我们应该完全信任内核开发者,他们已经选择了最适合当前平台的HZ值,所以一直使用默认值就好。

对于用户空间而言,内核的HZ几乎完全被隐藏了!对于用户程序来说确切的HZ值只能通过 /proc/interrupts 获得:/proc/interrupts 的计数值除以 /proc/uptime 中报告的系统运行时间。如下图为这两个文件的值:

linux变量的理解,Linux内核中HZtick和jiffies变量(5)

二、Linux内核中的tick

tick意为节拍,是指Linux内核定时器连续两次产生中断(timer Interrupt)的时间间隔,它是HZ中断倒数(实际上HZ也成为节拍率),其时间值为1/HZ。

三、Linux内核中的jiffies

在Linux内核中,jiffies主要作为记录自系统启动以来,产生节拍(或者说是内核定时器产生中断(timer Interrupt))的总数。系统启动时,内核将该变量初始化为0,此后,每次时钟中断处理程序都会增加该变量的值。一秒内时钟中断的次数等于Hz,所以jiffies一秒内增加的值也就是Hz。其定义在linux-3.0.8/include/linux/jiffies.h中 ,其原型为:

linux变量的理解,Linux内核中HZtick和jiffies变量(6)

如上图所示,jiffies为unsigned long类型的,其为32位,并且因为其在整个系统运行是,需要一直存在,所以使用volatile进行声明,其不会被编译器优化。当内核定时器产生中断时,jiffies的值自加1。

现在假设HZ=100,那么1个jiffies等于1/100s,而jiffies最大能够表示的时间为:(2^32-1)/100s=42949672.95s 大约是497天。那么也就是在这一天之后jiffies会溢出。这对于常年运行的系统而言,可能会出现一些为他,所以引出了jiffies_64这个变量,jiffies_64作为unsigned long long类型的变量,使用这个变量的话,要溢出也得用好几百万年,这件事就不用往后考虑了(远远超过了机器的寿命)。这个时候jiffies就作为jiffies_64的低32位使用。

有一点必须要声明的是:jiffies_64这个变量无论是在32位的系统还是在64位的系统,它都是64位的变量。另外,对于驱动开发工程师而言jiffies和jiffies_64的属性应该是只读的。

当然,关于jiffies溢出的问题,实际上对于在编写内核驱动时,计算并产生一个时间间隔是没有影响的。比如:要定时在1s后产生一次事件,1s的定时可以使用jiffies HZ得到。

四、Linux中如何放在jiffies溢出造成的逻辑错误

Linux内核通过提供time_after(a b)、time_before(a b)、time_after_eq(a b)和time_before_eq(a b)这四个宏来解决因jiffies溢出而造成程序逻辑的错误。如下图为Linux-3.0.8版本内核的源码,存在于linux-3.0.8/include/linux/jiffies.h文件中。

linux变量的理解,Linux内核中HZtick和jiffies变量(7)

这里有一点值得说明的是,宏time_after的两个参数a和b的数据类型为unsigned long,这样的比较才有实际意义。系统通过采用jiffies来计算时间,但是由于jiffies的溢出可能会使得一些程序(长期依赖于jiffies获取时间的程序)产生逻辑错误,因为在Linux内核的开发中,强烈的建议使用time_after这些宏来比较时间的先后关系

五、内核时钟

Linux内核使用硬件提供不同的时钟来提供依赖于时间的服务/程序,比如busy-waiting(浪费CPU周期)和sleep-waiting(放弃CPU)。

猜您喜欢: