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调度周期中的核心地位:
1.3 时钟中断在调度中的作用
时钟中断(Timer Tick)是Linux内核调度系统的心跳。在CFS中,时钟中断承担以下关键职责:
- 周期性触发调度器入口:每次时钟中断返回前,内核检查当前进程是否需要被抢占。
- 更新进程时间统计:调用
update_curr()函数,累加当前进程的物理运行时间,并更新其vruntime。 - 触发调度点(schedule()):如果当前进程的vruntime超过红黑树最左节点,设置
TIF_NEED_RESCHED标志,在中断返回时触发进程切换。 - 维护系统时间基准:提供纳秒级精度的时间戳,用于计算delta_exec。
调度延迟关键点:时钟中断的频率(HZ值)直接影响调度延迟的上限。HZ=1000时,时钟中断间隔为1ms,调度延迟理论上限为1ms;HZ=100时,间隔为10ms,调度延迟可能达到10ms。CFS通过高精度定时器(hrtimer)在部分场景下突破了这一限制。
下图展示了时钟中断与CFS调度器的交互架构:
1.4 调度延迟的定义与度量
调度延迟(Scheduling Latency)是指从进程变为可运行状态到进程实际获得CPU开始执行之间的时间间隔。在CFS中,调度延迟主要由以下因素决定:
| 延迟来源 | 典型耗时 | 影响因素 |
|---|---|---|
| 时钟中断等待 | 0 ~ 1/HZ 秒 | HZ配置、高精度定时器 |
| 中断处理开销 | 1 ~ 10 μs | 硬件平台、中断嵌套 |
| 调度器决策 | 0.1 ~ 5 μs | 就绪队列大小、红黑树深度 |
| 上下文切换 | 1 ~ 20 μs | TLB刷新、缓存污染 |
课程核心问题:vruntime的更新精度和时钟中断的触发时机,共同决定了CFS调度延迟的下限。本课程将深入分析这一关键路径上的每一处细节。