1. 课程导论:CFS调度器概述、vruntime核心概念、时钟中断在调度中的作用

1.1 CFS调度器设计哲学

完全公平调度器(Completely Fair Scheduler, CFS)是Linux内核自2.6.23版本引入的默认调度类,用于普通进程(SCHED_NORMAL/SCHED_OTHER)。其核心思想是:在理想的多任务处理器上,每个进程应获得等比例的CPU时间。CFS摒弃了传统基于时间片轮转的固定分配模型,转而采用基于虚拟运行时间(vruntime)的动态优先级模型。

核心设计目标:最小化调度延迟,确保交互式进程的响应性,同时维持全局吞吐量。

CFS通过红黑树(Red-Black Tree)组织就绪队列,以vruntime为键值。每次调度时,选择vruntime最小的进程运行——即“最饥饿”的进程。这种设计天然实现了公平性:运行时间越少的进程,其vruntime增长越慢,越容易被选中。

1.2 vruntime核心概念

vruntime是CFS调度器的核心度量指标,它表示一个进程在理想多处理器系统上应当获得的虚拟CPU时间。实际运行时间通过权重(weight)转换为vruntime增量,转换公式如下:

vruntime += delta_exec * (NICE_0_LOAD / se->load.weight)

其中:

  • delta_exec:进程实际运行的物理时间(纳秒级)。
  • NICE_0_LOAD:nice值为0时的基准权重(1024)。
  • se->load.weight:当前进程的调度实体权重,由nice值映射得到。

权重映射关系如下表所示:

nice值 权重(weight) 相对CPU占比(vs nice=0)
-20 88761 86.7x
-10 11051 10.8x
0 1024 1.0x
10 304 0.30x
19 15 0.015x
关键理解:高优先级(低nice值)进程的权重更大,因此相同物理运行时间下,vruntime增长更慢,从而获得更多CPU时间。低优先级进程则相反。

下图展示了vruntime在CFS调度周期中的核心地位:

CFS调度核心流程:vruntime驱动 进程运行 delta_exec 物理时间 vruntime更新 delta_exec / weight 红黑树插入 键值 = vruntime 调度决策 选择最左节点 时钟中断触发 周期性检查 & 更新

1.3 时钟中断在调度中的作用

时钟中断(Timer Tick)是Linux内核调度系统的心跳。在CFS中,时钟中断承担以下关键职责:

  1. 周期性触发调度器入口:每次时钟中断返回前,内核检查当前进程是否需要被抢占。
  2. 更新进程时间统计:调用 update_curr() 函数,累加当前进程的物理运行时间,并更新其vruntime。
  3. 触发调度点(schedule()):如果当前进程的vruntime超过红黑树最左节点,设置 TIF_NEED_RESCHED 标志,在中断返回时触发进程切换。
  4. 维护系统时间基准:提供纳秒级精度的时间戳,用于计算delta_exec。
调度延迟关键点:时钟中断的频率(HZ值)直接影响调度延迟的上限。HZ=1000时,时钟中断间隔为1ms,调度延迟理论上限为1ms;HZ=100时,间隔为10ms,调度延迟可能达到10ms。CFS通过高精度定时器(hrtimer)在部分场景下突破了这一限制。

下图展示了时钟中断与CFS调度器的交互架构:

时钟中断与CFS调度器交互架构 硬件时钟 PIT / APIC定时器 时钟中断处理 tick_periodic() CFS调度器 update_curr() 进程时间统计 vruntime更新 调度决策 schedule() 调度延迟产生点 中断处理 → 调度入口 → 切换

1.4 调度延迟的定义与度量

调度延迟(Scheduling Latency)是指从进程变为可运行状态到进程实际获得CPU开始执行之间的时间间隔。在CFS中,调度延迟主要由以下因素决定:

延迟来源 典型耗时 影响因素
时钟中断等待 0 ~ 1/HZ 秒 HZ配置、高精度定时器
中断处理开销 1 ~ 10 μs 硬件平台、中断嵌套
调度器决策 0.1 ~ 5 μs 就绪队列大小、红黑树深度
上下文切换 1 ~ 20 μs TLB刷新、缓存污染
课程核心问题:vruntime的更新精度和时钟中断的触发时机,共同决定了CFS调度延迟的下限。本课程将深入分析这一关键路径上的每一处细节。