转载自:
Linux中的tick模式 - 兰新宇的文章 - 知乎
https://zhuanlan.zhihu.com/p/133211285

基本概念

tick就是周期性的时钟中断,作为OS的心跳,它可以驱动scheduler运转,并且统计相关的运行信息(比如”utime”和”stime”的计算)。

根据硬件频率的不同,tick发生的间隔有所不同,比如x86支持100 Hz, 250 Hz和1000 Hz,则对应的间隔分别是10ms, 4ms和1ms。具体选用的数值可通过grep CONFIG_HZ /boot/config-$(uname -r)命令查看。

从系统开始启动后经过的ticks被记作”jiffies”,每发生一次时钟中断,jiffies的数值就加上1。

dyntick-idle 模式

当CPU进入idle低功耗模式时,其实是不希望被tick打断的。为此,自2007年的2.6.21版本,可通过CONFIG_NO_HZ_IDLE配置选项(曾用名CONFIG_NO_HZ),于idle模式时关闭tick(不需要HZ)。

这种方式有很多种叫法,主流的是”dyntick-idle”,其他还有”nohz”啦,”tickless”啦等等。其带来的收益是功耗的减少,付出的代价则是进入和退出dyntick-idle模式的指令开销,以及需重新填充clock相关的寄存器信息等。

除非workload中idle的次数少、时间短,或者不在乎功耗,又对延迟敏感,否则对于大多数场景来说,dyntick-idle的使用都是利大于弊的,因此是目前内核默认采用的tick模式。

adaptive-ticks 模式

更进一步,如果一个CPU上只有一个runnable的任务,同样也是不需要tick的。这种需求在2013年的3.10版本被支持,称为”adaptive-ticks”模式,对应的配置选项为CONFIG_NO_HZ_FULL,”full”可理解为1个task在一段时间内完全地占有一个CPU。

对于需要开启这项功能的CPU,应在内核启动参数中设置,比如nohz_full=1,6-8,就表明CPU 1, 6, 7, 8是adaptive-ticks的,系统运行后不可再动态更改(想更改只能reboot)。

但要注意的是,即便系统的每个CPU上都只有一个runnable的任务,也不能把全部CPU都设为nohz full模式。这是因为对于处在adaptive-ticks状态的CPU,还是存在任务运行,还是需要使用jiffies或者walltime,因此系统应该至少保留一个CPU来承担timekeeping的工作,被选择作为timekeeper的是负责boot的那个CPU。

一旦CPU上有新的任务加入进来,那么就又需要tick了,只有一个任务运行的限制似乎显得有些理想化。不过,在一些高性能计算和realtime的场景中,将一个CPU单独拿给一个线程用是完全可能的(就连现在的手机不也动辄都是4核8核么)。

此外,一个CPU上虽然有多个runnable的任务,但包含的是一个高优先级的SCHED_FIFO任务和多个低优先级的SCHED_OTHER任务,除非这个SCHED_FIFO的任务block,否则它会一直运行,这种情况其实也可以不使用tick。还有就是任务获得的timeslice比较长,也可以考虑在这段时间内暂时关闭tick。

“dyntick-idle”模式需额外付出的effort对”adaptive-ticks”模式也是存在的,而后者还有一些其他方面的问题。当CPU上唯一runnable的线程从用户态进入内核态执行后,并不会发生task切换,依然满足adaptive-ticks的条件,这就对线程”utime”和”stime”的统计造成了困难。目前,”nohz full”的配置默认是关闭的。


参考资料:

  1. Status of Linux dynticks
  2. (Nearly) full tickless operation in 3.10
  3. Documentation/timers/NO_HZ.txt