@[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
2
3
4
5
6
7
8
9
10
11
12
13
14
graph TD
A["高精度定时器 (tick_sched_timer) 到期"] --> B["执行其回调函数 tick_sched_timer()"];
B --> C["调用 tick_periodic()"];
C --> D["jiffies_64++<br/>(原子性增加1)"];
B --> E["重新编程定时器以在下一个节拍到期<br/>(hrtimer_forward)"];
E --> A;

subgraph "周期性Tick循环"
A
B
C
D
E
end

流程图一:周期性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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
graph TD
A["外部硬件中断发生<br/>(如网卡、磁盘IO)"] --> B["CPU 从 do_idle() 睡眠状态中被唤醒"];
B --> C["中断入口调用 irq_enter_rcu()"];
C --> D{"检测到当前任务是<br/>idle 任务?"};
D -- 是 --> E["调用 tick_irq_enter()"];
E --> F["调用 tick_nohz_irq_enter()"];
F --> G["计算错过的节拍数<br/>(missed ticks)"];
G --> H["调用 tick_nohz_update_jiffies()"];
H --> I["jiffies_64 += missed_ticks<br/>(一次性补偿)"];
I --> J["继续处理该硬件中断的<br/>后续特定事务"];

subgraph "NOHZ 追赶式更新路径"
A
B
C
D
E
F
G
H
I
J
end

流程图二: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的实时状态决定:

  • 对于一个持续繁忙的CPUjiffies的更新由一个周期性的时钟中断驱动,其更新频率严格等于内核配置的HZ值。
  • 对于一个进入了idle状态的CPU:其周期性tick被停止。jiffies的更新被推迟至下一次中断发生时。在中断处理路径上,内核会计算出自上次更新以来经过的全部时间,并一次性地、追赶式地将jiffies更新到正确的新值。

因此,jiffies这个全局变量的值,是系统中所有CPU共同作用的结果。一个繁忙的CPU会以固定的节奏周期性地推进其增长,而一个空闲的CPU则会在被唤醒时,一次性地将其值增加一个较大的量。这两种机制协同工作,共同保证了jiffies作为内核的传统时间基准,其值始终能与真实时间的流逝保持一致,实现了系统性能、传统API兼容性与现代功耗管理之间的平衡。