插件窝 干货文章 Linux进程调度策略:CFS是如何实现的

Linux进程调度策略:CFS是如何实现的

进程 vruntime 调度 时间 457    来源:    2025-05-07

Linux CFS (Completely Fair Scheduler) 实现解析

CFS (完全公平调度器) 是 Linux 内核默认的进程调度器,自2.6.23版本引入,取代了之前的O(1)调度器。以下是CFS的核心实现机制:

核心设计理念

  1. 完全公平性:试图给所有可运行进程公平的CPU时间份额
  2. 基于虚拟时间:使用虚拟运行时间(vruntime)而非实际时间作为调度依据
  3. 红黑树结构:高效管理可运行进程

关键数据结构

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. 调度流程

  1. 时钟中断处理:更新当前进程的vruntime
  2. 检查抢占:如果当前进程vruntime不再是最小,设置抢占标志
  3. 调度点触发:主动或被动调用schedule()
  4. 选择下一个进程:从红黑树选取最左侧节点
  5. 上下文切换:切换到新进程执行

4. 权重与优先级

  • 每个进程有静态优先级(static priority, 即nice值)
  • nice值映射到权重表(prio_to_weight[])
  • nice值每变化1,CPU时间份额变化约10%

5. 时间片计算

CFS没有固定时间片概念,而是:

  • 计算目标延迟(target latency):保证所有可运行进程至少运行一次的时间
  • 最小粒度(minimum granularity):防止过多上下文切换

特殊处理机制

  1. 新进程处理:初始vruntime设置为当前队列min_vruntime,避免老进程饥饿
  2. 唤醒进程:适当补偿vruntime,防止频繁睡眠进程处于劣势
  3. 多处理器负载均衡:定期在各CPU间迁移任务保持平衡
  4. 组调度:支持控制组(CGroups)的CPU资源分配

性能优化

  1. 快速路径调度:当没有更高优先级进程时快速返回当前进程
  2. 缓存热点:维护最左侧节点的缓存指针
  3. 延迟计算:部分统计信息延迟更新减少开销

CFS通过这种设计实现了良好的公平性、可扩展性和交互性能,能够适应从嵌入式系统到大型服务器的各种场景。