Linux CFS 调度器深度实战:从 vruntime 红黑树到 NUMA 感知的多核负载均衡

一、调度器演进与设计哲学

Linux 内核的进程调度器经历了从简单的 O(n) 调度器到 O(1) 调度器,再到 Completely Fair Scheduler (CFS) 的演进。CFS 自 2.6.23 版本引入内核主线以来,彻底改变了 Linux 对 CPU 时间分配的基本假设——它不维护传统的 runqueue 和时间片概念,而是基于"虚拟运行时间"(virtual runtime, vruntime)实现"完全公平"的调度理念。

CFS 由 Ingo Molnár 提出,其核心思想简洁而深刻:如果一个调度器能在一台拥有 N 个 CPU 核心的机器上,让每个可运行任务获得 1/N 的 CPU 时间,那么这个调度器是"完全公平"的。为了逼近这个理想模型,CFS 引入了以下关键抽象:

  • virtual runtime (vruntime):每个调度实体维护一个单调递增的虚拟时间戳,记录它在虚拟时钟下的累计运行时间
  • 红黑树 (rbtree):所有可运行任务按 vruntime 排序在红黑树上,最左侧节点即 vruntime 最小的任务,也就是"最亏欠" CPU 的任务
  • min_vruntime:每个 cgroup 和 CPU runqueue 维护一个最小 vruntime 基准,用于新任务的初始化和负载均衡时的偏移校正

二、调度实体与 vruntime 计算

CFS 的核心数据结构是 sched_entity,它是 task_struct 的内嵌字段。每个调度实体包含以下关键字段:

struct sched_entity {
    struct load_weight  load;       // 调度权重
    struct rb_node      run_node;   // 红黑树节点
    u64                 exec_start; // 本次开始执行时间
    u64                 sum_exec_runtime;  // 累计实际运行时间
    u64                 vruntime;   // 虚拟运行时间
    u64                 prev_sum_exec_runtime; // 上次切换时累计时间
    // ...
};

vruntime 的计算公式直接体现了"公平"的权重分配思想:

delta_exec = now - entity->exec_start;        // 实际执行时间段
delta_exec_weighted = delta_exec * (NICE_0_LOAD / entity->load.weight);
entity->vruntime  = delta_exec_weighted;

其中关键因子 NICE_0_LOAD / entity-

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部