Linux进程调度策略:CFS是如何实现的
Linux CFS (Completely Fair Scheduler) 实现解析
CFS (完全公平调度器) 是 Linux 内核默认的进程调度器,自2.6.23版本引入,取代了之前的O(1)调度器。以下是CFS的核心实现机制:
核心设计理念
- 完全公平性:试图给所有可运行进程公平的CPU时间份额
- 基于虚拟时间:使用虚拟运行时间(vruntime)而非实际时间作为调度依据
- 红黑树结构:高效管理可运行进程
关键数据结构
struct sched_entity {
struct load_weight load; // 进程权重
struct rb_node run_node; // 红黑树节点
u64 vruntime; // 虚拟运行时间
// ...
};
struct cfs_rq {
struct rb_root_cached tasks_timeline; // 红黑树根节点
struct sched_entity *curr; // 当前运行进程
u64 min_vruntime; // 最小vruntime
// ...
};
主要实现机制
1. 虚拟运行时间(vruntime)计算
vruntime是CFS调度的核心概念,计算公式为:
vruntime += delta_exec × (NICE_0_LOAD / weight)
其中:
- delta_exec
:实际执行时间
- weight
:进程权重(由nice值决定)
- NICE_0_LOAD
:nice=0的默认权重
2. 红黑树管理可运行进程
- 所有可运行进程按vruntime排序存储在红黑树中
- 最左侧节点(最小vruntime)是下一个要调度的进程
- 插入/删除操作时间复杂度为O(log n)
3. 调度流程
- 时钟中断处理:更新当前进程的vruntime
- 检查抢占:如果当前进程vruntime不再是最小,设置抢占标志
- 调度点触发:主动或被动调用schedule()
- 选择下一个进程:从红黑树选取最左侧节点
- 上下文切换:切换到新进程执行
4. 权重与优先级
- 每个进程有静态优先级(static priority, 即nice值)
- nice值映射到权重表(prio_to_weight[])
- nice值每变化1,CPU时间份额变化约10%
5. 时间片计算
CFS没有固定时间片概念,而是:
- 计算目标延迟(target latency):保证所有可运行进程至少运行一次的时间
- 最小粒度(minimum granularity):防止过多上下文切换
特殊处理机制
- 新进程处理:初始vruntime设置为当前队列min_vruntime,避免老进程饥饿
- 唤醒进程:适当补偿vruntime,防止频繁睡眠进程处于劣势
- 多处理器负载均衡:定期在各CPU间迁移任务保持平衡
- 组调度:支持控制组(CGroups)的CPU资源分配
性能优化
- 快速路径调度:当没有更高优先级进程时快速返回当前进程
- 缓存热点:维护最左侧节点的缓存指针
- 延迟计算:部分统计信息延迟更新减少开销
CFS通过这种设计实现了良好的公平性、可扩展性和交互性能,能够适应从嵌入式系统到大型服务器的各种场景。