0/32 已展开

LLM 分析

sched_ext:让 Proxy Execution 与 sched_ext 共存

系列概况

  • 标题[PATCHSET v10 sched_ext/for-7.3] sched: Make proxy execution compatible with sched_ext
  • 作者:Andrea Righi(NVIDIA)
  • 版本:v10,序列 15/15
  • 规模:15 个 patch + 1 封 cover letter;前置工作来自 John Stultz
  • 修改文件kernel/sched/core.cfair.csyscalls.csched.hkernel/sched/ext/ext.csub.cext.hinternal.hinclude/linux/sched/ext.hinit/Kconfigtools/sched_ext/scx_qmap.{bpf.c,c,h};新文件 tools/testing/selftests/sched_ext/enq_blocked.{c,bpf.c};新增 TEST 模块 test_modules/scx_enq_blocked_test.ko
  • 代码统计:删多增多,主要 diff 集中在 sched_ext;最大 patch 是 P11(约 50 行净增)
  • Message-ID20260728154425.1549660-1-arighi@nvidia.com
  • 完整性:完整,含 cover、15 patches、3 个 sashiko-bot 评审、8 个 Tejun Heo 评审、5 个作者回复

补丁目的

CONFIG_SCHED_PROXY_EXEC=yCONFIG_SCHED_CLASS_EXT=y 由编译期互斥改成可同时开启。

Proxy 执行让等锁任务(donor)把自己的调度上下文“借给”持锁 owner,让 owner 在保持 donor runnable 的情况下推进临界区。sched_ext 走自己的 DSQ/回调,跟 core 的 rq->curr 视图天然不一致。本系列引入 SCX_OPS_ENQ_BLOCKED capability,让 BPF scheduler 显式接收被阻塞的 donor,按需调度,core 把调度上下文迁到 owner 的 rq 后再执行 owner。

旧流程的问题

  • 在前 v10 之前,SCHED_PROXY_EXEC 直接 depends on !SCHED_CLASS_EXT,发行版无法同时选择两者。
  • 即便勉强启用,sched_ext 的 rq->curr/current 视图会跟 proxy 后的执行上下文不一致:BPF helper 看到的 running 任务与 core 实际跑的任务不对齐,DSQ/vtime 状态错乱。
  • proxy 把 donor 调度上下文搬到 owner rq 后,set_task_cpu() 会误报 migration-disabled warning。
  • NOHZ tick 停止检查只看 rq->curr + nr_running==1,FAIR donor 受带宽限但 owner 是另一个 class,tick 会错误停止。

新流程

  • BPF 调度器可选地置 SCX_OPS_ENQ_BLOCKED,op 必须实现 enqueue()
  • proxy 阻塞 donor 被 scx_allow_proxy_exec() 放行,进入运行队列等 BPF 调度;
  • BPF 通过 enqueue() 收下后,core 沿 mutex-owner 链迁移 donor 调度上下文到 owner rq;
  • rq->donor 持真正消耗 slice 的任务,rq->curr 持正在执行 owner;
  • kfunc (scx_bpf_task_running/cpu_curr/cid_curr) 一律回报 donor;
  • ops.running/stopping 会话边界不再与物理 switch 严格对齐,由 SCX_TASK_RUN_TRACKED 管控;
  • remote DSQ 传输在 src_rq 上重检查 proxy 状态,必要时丢进 reject DSQ 待 proxy settle 后再 reenq;
  • 最后打开 SCHED_PROXY_EXECSCHED_CLASS_EXT 同开的 Kconfig 闸门。
         donor blocks on mutex
                |
                v
    +-----------------------+   enqueue(SCX_ENQ_BLOCKED)
    |   core: retain donor  | <--------------------------+
    |   on rq as blocked    |                            |
    +-----------------------+                            |
                |  SCX_OPS_ENQ_BLOCKED ?                 |
                |  no -> normal block                   |
                v                                       |
    +-----------------------+    find_proxy_task()       |
    |   BPF enqueue()       | -> walks owner chain       |
    |   (re-)dispatch donor |                            |
    +-----------------------+                            |
                |                                       |
                v                                       |
   donor rq -> owner rq (migration-disabled path)       |
                |                                       |
                v                                       |
    rq->donor = donor      rq->curr = mutex owner       |
    slice consumed by donor; owner executes critical    |
                |                                       |
                v                                       |
    owner releases -> donor wakes -> enqueue clean ----+

Patch 概览

#标题主要改动
01sched/core: Avoid false migration warning for proxy donors把 blocked+proxy 排除掉 migration-disabled WARN
02sched: Make NOHZ CFS bandwidth checks follow proxy donorCFS bandwidth tick check 改为看 rq->donorcfs.h_nr_queued
03sched: Add helper to block retained proxy donors新增 sched_proxy_block_task()
04sched: Skip class callbacks with SCHED_FLAG_KEEP_PARAMSKEEP_PARAMS 不再触发 DEQUEUE_CLASS
05sched: Add prepare_switch() class callbacksched_change_begin() 接收 next_class 并回调
06sched: Add sched_ext hooks for proxy execution引入三个 scx_ 钩子(空实现)
07sched_ext: Block proxy donors across scheduler transitions默认拒绝;实现 prepare_switch_scx
08sched_ext: Fix ops.running/stopping() pairing for proxy-exec引入 SCX_TASK_RUN_TRACKED
09sched_ext: Generalize the reject DSQ reenqueue pathreject_dsq 解耦 sub-cap,reason 通过 reject_reason 传递
10sched_ext: Handle proxy-exec races in remote DSQ transfers新增 task_move_reject_reason + scx_reject_task
11sched_ext: Split currdonor references properly
12sched_ext: Delegate proxy donor admission to BPF schedulers引入 SCX_OPS_ENQ_BLOCKED 主功能
13sched_ext: Add selftest for blocked donor admission新增 enq_blocked selftest + 内核模块
14sched_ext: scx_qmap: Add proxy execution support-B 选项 + 被拒 donor 转发 SHARED_DSQ
15sched: Allow enabling proxy exec with sched_ext删除 depends on !SCHED_CLASS_EXT

关键实现

  • SCX_OPS_ENQ_BLOCKED:新 ops flag,要求 BPF 实现 enqueue();交出 blocked donor 的入队决策权。
  • SCX_ENQ_BLOCKED:传给 enqueue() 的 flag,提示这是持锁等待任务。
  • SCX_TASK_REENQ_* 家族:cap=4、新增 MIGRATION_DISABLED=5、PROXY=6,描述 reenqueue 原因。
  • SCX_RQ_PROXY_REENQscx_rq_flags 上标志,标记本 rq 有 proxy-pending 任务待 drain。
  • scx_prepare_task_sched_change():在 sched_change_begin() 前清理不兼容 scheduler 的 proxy 残留。
  • task_move_reject_reason():在持有 src_rq 后重检查 on_cpu/migration-disabled/current-donor 三个状态。
  • NOHZ tick__need_bw_check() 只看 donor,不再要求 nr_running==1;新条件 cfs.h_nr_queued != 1
  • qmap -B:blocked donor 走 SCX_DSQ_LOCAL_ON|cid,slice 刷新并 SCX_ENQ_PREEMPT;被 local DSQ 再次拒绝时切到 SHARED_DSQkick_cid

类比

把调度器想象成餐厅调度员:

  • Proxy = 让 VIP 把座位借给正要去端菜的厨师:VIP 仍然排着“该轮到我了”,但允许调度员临时让厨师用 VIP 的优先级切菜。
  • rq->donor vs rq->curr:VIP 是“付款的顾客”,厨师是“真正端盘子的手”,调度员核账看 VIP。
  • Reject DSQ:是 VIP 因临时状况(路线冲突、厨房不让用)退回“候补队列”,等障碍解除再重新排队。
  • SCX_OPS_ENQ_BLOCKED capability:餐厅声明“我接受帮别人送菜的 VIP”,否则一律按普通顾客排队。

Highlight:风险与注意点

  • scalar flag 含义重载p->scx.flags 现在既要表达 queued、tracked、reject-reason,又要表达 wakeup——Sashiko 已经标记 medium 严重度的文档与实现不一致(patch 11)。
  • PREEMPT_RT 仍然互斥!PREEMPT_RT 仍未解开;RT 与 proxy-exec 的耦合在 patch 7 的回复被 Andrea 显式承认。
  • PI/deboost 跨类切换:Andrea 给出 FAIR→RT PI 例子证明需要保留 proxy;Tejun 倾向 class-level capability。
  • DSQ 锁次序scx_reject_tasksrc_rq 上记录 reason 又要 dst_rq 退出,锁转换出错会丢 reason(Sashiko 标记为 high)。
  • 测试覆盖:enq_blocked selftest 引入新内核模块依赖,需保证 CI 加载/清理顺序。

版本变化

  • 本系列为 v10;cover letter 列出 v1–v9 全部 lore 链接;本次相对可见差异:reject_dsq 全局化、SCX_TASK_RUN_TRACKED 精细化、文档同步更新。
  • Andrea 在 v9→v10 把 sub-cap reject 路径抽到 core,新增 reject_reason 字段。

一句话总结

通过 SCX_OPS_ENQ_BLOCKED capability 与 rq->donor / rq->curr 视角分离,让 BPF 调度器显式接管被阻塞的 proxy donor,从而解除 SCHED_PROXY_EXECSCHED_CLASS_EXT 的编译期互斥。