2. BFS调度器核心思想:O(1)调度、全局运行队列、虚拟截止时间、公平性分析

BFS(Brain Fuck Scheduler)是Con Kolivas为桌面交互场景设计的调度器,其设计哲学与主流CFS完全相反:追求极低调度延迟与交互响应确定性,放弃多核负载均衡的复杂性。本章深入剖析BFS的四大核心支柱。

2.1 O(1)调度:无红黑树的就绪队列

BFS摒弃了CFS的红黑树(O(log n)),采用双链表 + 优先级位图实现O(1)调度。每个优先级(0~139)对应一个链表头,调度时通过位图扫描找到最高优先级非空链表,取出队首任务。

关键指标: BFS的调度器入口 schedule() 时间复杂度恒为O(1),与系统中任务总数n无关。在桌面负载(n < 1000)下,链表遍历开销远小于红黑树旋转。
BFS O(1) 就绪队列结构 优先级位图 (140 bit) — 通过 __ffs() 找到最高优先级 双链表数组:prio_queue[0] ~ prio_queue[139] prio=0 prio=0 prio=0 prio=139 prio=139 schedule() 取队首 → 切换

2.2 全局运行队列:单队列模型

BFS使用单一全局运行队列(rq),所有CPU核心共享同一个就绪链表集合。这与CFS每个CPU独立运行队列的设计截然不同。

特性 BFS 全局队列 CFS 每CPU队列
队列数量 1个(全局) N个(N=CPU数)
负载均衡 天然均衡(任务从全局取) 需要主动迁移(load_balance)
锁竞争 高(单锁保护全局队列) 低(每CPU本地锁)
缓存亲和性 弱(任务可能在不同CPU间漂移) 强(任务尽量留在同一CPU)
设计取舍: 全局队列在桌面场景(2~8核)下锁竞争可接受,且省去了复杂的负载均衡算法。但在服务器场景(32核以上)下,全局锁会成为严重瓶颈。

2.3 虚拟截止时间(Virtual Deadline)

BFS不使用CFS的虚拟运行时间(vruntime),而是引入虚拟截止时间(Virtual Deadline, VD)作为调度决策依据。每个任务被赋予一个VD值,调度器总是选择VD最小的任务执行。

VD计算规则

/* BFS虚拟截止时间计算(简化伪代码) */
void update_deadline(struct task_struct *p) {
    if (p->policy == SCHED_NORMAL || p->policy == SCHED_BATCH) {
        /* 交互任务:vd = 当前时间 + 短时间片 */
        if (p->interactive)
            p->deadline = now + (p->prio_ratio * 6);
        else
            p->deadline = now + (p->prio_ratio * 20);
    }
}

/* 调度决策:选vd最小的任务 */
struct task_struct *pick_next_task(void) {
    struct task_struct *best = NULL;
    u64 min_deadline = ULLONG_MAX;
    
    for_each_task_in_global_queue(p) {
        if (p->deadline < min_deadline) {
            min_deadline = p->deadline;
            best = p;
        }
    }
    return best;
}
虚拟截止时间调度示例 时间轴 → 任务A VD=100 任务B VD=80 任务C VD=120 ← 选中VD最小的任务B

2.4 公平性分析:交互优先 vs 时间公平

BFS的公平性定义与CFS完全不同:BFS追求的是“交互公平”而非“时间公平”。即:交互型任务(如GUI应用、音频播放)获得不成比例的CPU时间,以确保用户感知的流畅性。

公平性对比表

维度 BFS CFS
公平基准 交互响应延迟 CPU时间比例(权重)
交互任务优待 显著(VD更短,频繁被调度) 轻微(通过睡眠补偿)
CPU密集型任务 被压制(VD增长快,调度间隔长) 按权重公平分配
饥饿风险 低优先级CPU任务可能长时间得不到CPU 低(vruntime保证最终运行)
适用场景 桌面、音频工作站 服务器、通用
实验观察: 在BFS下运行 make -j4 编译任务的同时拖动窗口,窗口响应几乎无延迟;而同等负载下CFS会出现明显的窗口拖拽卡顿。代价是编译完成时间比CFS长15%~30%。

2.5 核心思想总结

  1. O(1)调度: 双链表+位图,调度延迟与任务数无关,适合桌面负载规模。
  2. 全局运行队列: 消除负载均衡开销,但引入全局锁竞争。
  3. 虚拟截止时间: 以VD最小为选择依据,交互任务VD增长慢,获得更多CPU机会。
  4. 交互优先公平: 牺牲CPU密集型任务的吞吐量,换取交互响应确定性。
BFS核心思想架构图 BFS调度器 O(1) 调度 位图+链表 全局运行队列 单队列共享 虚拟截止时间 VD最小优先 交互优先公平 延迟优先于吞吐
移植要点: 在将BFS移植到新内核版本时,需要重点关注:
① 全局运行队列的锁机制(原始BFS使用自旋锁,需适配新内核的排队自旋锁);
② 虚拟截止时间的计算与优先级映射关系;
③ 与内核调度类接口(sched_class)的对接点。