@[toc]
Linux 内核 jiffies
更新机制解析:周期性Tick模型和动态时钟/无Tick模型的实现与行为
1. jiffies
更新的双重模型框架
Linux内核对jiffies
全局计数器的更新并非采用单一策略,而是根据中央处理器(CPU)的运行状态和系统配置,在两种截然不同的模型间进行切换。
1.1 周期性Tick模型 (Periodic Tick Model)
- 适用条件:此模型在CPU持续执行非空闲任务,或内核未完全开启
CONFIG_NO_HZ_FULL
等动态时钟配置时被激活。 - 工作机制:内核中存在一个周期性的时钟中断事件。该中断以一个由内核编译时配置的
HZ
值所决定的固定频率(例如250Hz)规律性地发生。在现代内核中,此中断通常由高精度定时器(hrtimer)模拟的tick_sched_timer
来驱动。 jiffies
更新行为:在每一次时钟中断的服务例程中,tick_periodic()
函数都将被调用,其核心任务之一就是将全局变量jiffies_64
的值原子性地增加1。在此模型下,jiffies
的增长是线性的、可预测的。
其更新流程如下图所示:
1 | graph TD |
流程图一:周期性Tick模型下的jiffies
更新流程
1.2 动态时钟/无Tick模型 (NOHZ / Tickless Model)
- 适用条件:当一个CPU通过执行
do_idle
进入idle
状态,或被配置为用于特定任务的“full NOHZ”模式时,此模型生效。 - 工作机制:为了降低功耗,内核会停止该CPU上的周期性时钟中断。这意味着CPU可以进入更深度的睡眠状态,不再有周期性的中断事件来唤醒它。
jiffies
更新策略:由于周期性中断已停止,jiffies
的更新被推迟。内核采用了一种**“按需更新”或“追赶式更新”(Catch-up Update)**的策略。更新操作被延迟到下一次该CPU上发生任何硬件中断的时刻。当中断发生时,内核会根据底层时钟源计算出从上次更新到当前时刻所经过的精确时间,并换算为错过的节拍总数,然后一次性地将jiffies
的值加上这个差值。
2. NOHZ 模型在运行时的调用路径分析
在NOHZ模型下,jiffies
的更新与CPU的idle
状态转换和中断唤醒过程紧密耦合。
2.1 从 idle
状态被中断唤醒
此为NOHZ“追赶式更新”最典型的路径。当一个处于idle
状态的CPU被外部硬件中断时,其执行流程如下。
其“追赶式更新”流程如下图所示:
1 | graph TD |
流程图二:NOHZ模型下从idle
唤醒时的jiffies
追赶式更新流程
2.2 进入与退出 idle
状态的边界处理
- 进入Idle (
tick_nohz_idle_enter
): 在CPU即将通过do_idle
进入睡眠之前,tick_nohz_idle_enter
会被调用。它会调用tick_nohz_stop_sched_tick
来停止周期性tick,并在停止前执行最后一次jiffies
更新,以确保进入睡眠前jiffies
值的精确性。 - 退出Idle前的检查 (
tick_check_idle
): 此路径与从idle
被唤醒类似,是在退出idle
状态过程中的一个检查点,同样会确保jiffies
的追赶式更新被触发。 - 中断处理退出 (
tick_nohz_irq_exit
): 在中断处理即将结束,且内核判断CPU将重新返回idle
状态时,tick_nohz_irq_exit
会被调用,以检查是否需要重新停止tick,并可能在此过程中更新jiffies
。
3. 结论:jiffies
的动态更新特性
jiffies
的更新频率是动态的,而非固定不变的。其行为由CPU的实时状态决定:
- 对于一个持续繁忙的CPU:
jiffies
的更新由一个周期性的时钟中断驱动,其更新频率严格等于内核配置的HZ
值。 - 对于一个进入了
idle
状态的CPU:其周期性tick被停止。jiffies
的更新被推迟至下一次中断发生时。在中断处理路径上,内核会计算出自上次更新以来经过的全部时间,并一次性地、追赶式地将jiffies
更新到正确的新值。
因此,jiffies
这个全局变量的值,是系统中所有CPU共同作用的结果。一个繁忙的CPU会以固定的节奏周期性地推进其增长,而一个空闲的CPU则会在被唤醒时,一次性地将其值增加一个较大的量。这两种机制协同工作,共同保证了jiffies
作为内核的传统时间基准,其值始终能与真实时间的流逝保持一致,实现了系统性能、传统API兼容性与现代功耗管理之间的平衡。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 wdfk-prog的个人博客!
评论