本期重点
1.Peter Zijlstra 发布 "Flatten the pick" v3——CFS cgroup 层级选择的根本性重构,将 pick 操作从 O(depth) 降为单层级,游戏场景 FPS min 从 4.0 飙到 29.0,Peter 计划在 7.2-rc1 后合入。
2.CFS bandwidth throttle 统一到 account_cfs_rq_runtime()——K Prateek Nayak 发 5 补丁系列(含 Peter 原始思路),消除 check_cfs_rq_runtime() 分支,让 throttle 逻辑归一,为 sched/flat(即上述 Flatten the pick 系列,社区简称,git 分支peterz/queue.git sched/flat)铺路。
3.sched_ext 进入 7.1 收尾 + 7.2 特性积累期——Tejun Heo 的 v7.1-rc6 fixes 已被 Linus 拉取,同时 dispatch transaction API v4、cid/cmask 接口完善、arena 地址转换等 7.2 特性密集提交。
4.Qais Yousef 的 schedutil 响应时间系列获 ARM 实测验证——EEVDF 持续演进导致 7.0 在树莓派 5 上性能下降 25%,ttwu + PELT 修复补丁恢复到 6.6 基线的 94%。
5.LPC 2026 sched_ext Microconference 议题征文启动——捷克布拉格 10 月 5-7 日,征集议题包括层级 cgroup sub-scheduler、DL server 集成、proxy execution、BPF arena 可组合调度器等,截稿 7 月 24 日。
一、核心进展
CFS cgroup:Flatten the pick v3 发布
原文[1]
Peter Zijlstra 发布了 "Flatten the pick" 系列的第三版。这个系列的核心思路是把 CFS cgroup 层级的调度选择从一个多层遍历操作变成一个平面单层级操作——cgroup 层级的权重信息通过动态 weight 管理(cgroup_mode knob)表达在同一个 runqueue 上。
v3 的关键变化:新增了cgroup_mode tasks模式,重写了cgroup_mode concur的 changelog,修复了 Vincent Guittot 发现的update_entity_lag()在 dequeue 路径的 bug,以及 Prateek 报告的 throttle vs tick 问题。默认 cgroup_mode 也做了调整。
benchmark 数据很说明问题——在 Intel i7-2600K + AMD RX 580 上跑 Shadows Awakening(通过 Lutris/GE-Proton10/Steam Runtime 3),对比 default 和 slice 模式:
FPS min 从 4 暴涨到 29。Fair scheduler 在 cgroup 深层嵌套场景下的游戏响应问题,可能就此得到解决。
Peter 在邮件中明确表示希望在下个周期(7.2-rc1 之后)尽早合入。改动涉及 fair.c 943 行变更(607 增、488 删),加上 debug.c、sched.h 等文件。
CFS cgroup 调度的一次结构性简化。如果成功合入,层级遍历的开销将消失,cgroup 嵌套深度不再是性能瓶颈。这直接改变了 "容器 + 游戏场景" 的调度成本模型。
CFS Bandwidth:throttle 逻辑统一到 account_cfs_rq_runtime()
原文[2]
K Prateek Nayak 提交了 5 补丁系列,将 CFS bandwidth 的 throttle 触发点从check_cfs_rq_runtime()(在 pick_next_task 路径)迁移到account_cfs_rq_runtime()(在时间统计路径)。这个思路最初由 Peter Zijlstra 在 5 月的邮件中提出。
背景:per-task throttle 引入后,throttle_cfs_rq()的角色变成了一个 "信号传播器"——它只设置 throttle 标记,然后依赖 task work 在任务返回用户态时逐个 dequeue。而旧的check_cfs_rq_runtime()是在 pick 路径里做整层级 dequeue,两者并存是历史遗留。
统一后的逻辑更清晰:account_cfs_rq_runtime()统计时间 → 带宽耗尽 → 调用throttle_cfs_rq()设置标记并挂 task work → 任务自然 dequeue。不再需要check_cfs_rq_runtime()和resched这个间接路径。
同周还出现了这个系列的 v2原文[3],说明作者在积极迭代。Prateek 也提到该系列与 sched/flat 只有一个 trivial conflict。
这不仅是代码清理。统一 throttle 路径是 sched/flat 的前置依赖——扁平化 pick 之后,旧 throttle 路径里的 pick_next_task 钩子将不复存在。先做这个统一,sched/flat(Flatten the pick 系列)合入时就不会踩坑。
cfs_rq 数据局部性优化 v10
原文[4]
Zecheng Li 的cfs_tg_state系列迭代到了 v10。方案是将 per-task_group 的 cfs_rq 和 sched_entity 共同分配在同一块 per-CPU 内存区域(使用 percpu allocator),消除tg->cfs_rq[]和tg->se[]两个指针数组的间接寻址。
数据说服力很强:Google 生产环境 CPU throughput +0.5%、内存 -0.5%;MySQL OLTP(1024 叶 cgroup)TPS +1%、LLC miss -10%;schbench 在 Intel 上 LLC miss -30%、AMD -10%。
这个系列从 v1 到 v10 经历了大量重构,v8 时简化了 free 路径(Prateek 建议),v7 引入了cfs_tg_state把 cfs_rq + sched_entity + sched_statistics 打包在一起(Josh 建议)。代码量反而在减少:93 增、96 删。
这是典型的优化——不改算法,改数据布局就能拿到显著的性能收益。percpu allocator 保证了同一 CPU 上的 cfs_rq 迭代在 cache 里完成,深 cgroup 层级的 hot path 直接受益。
schedutil 响应时间系列获 ARM 实测验证
原文[5]
schedutil 作为内核默认的 DVFS governor,长期存在几个影响系统响应时间的结构性问题:
一是"magic margin" 问题——schedutil 用一个固定的 ~25% margin 来决定何时拉高 CPU 频率,但不同 SoC 的频率阶梯和切换延迟差异巨大,一个固定值无法适配所有硬件。在高阶梯粒度的平台上,margin 过大导致频率迟迟不升;在低延迟平台上又可能过于激进。
二是"black hole" 问题——bursty 任务(间歇性活跃,比如 UI 事件处理)的 PELT util 在不活跃期间衰减到接近 0。当任务被唤醒时,PELT 从近乎 0 开始缓慢爬升,schedutil 在前几轮只能给一个很低的频率,DVFS 响应严重滞后。用户能直接感受到的就是界面卡顿。
三是DVFS ramp-up 太慢——新唤醒的任务需要多轮 PELT 更新(每轮约 1ms,通常需要 10+ 轮)才能让 schedutil 把频率拉到目标水平。对 latency-sensitive 工作负载影响很大。
四是util_est/util_avg 振荡——周期性任务的 util 在 period 边界附近剧烈摆动,导致频率忽高忽低。
Qais Yousef 在 2024 年 8 月首次提交了解决这些问题的 v1 系列。因为个人原因(他在 cover letter 里说 "I had a baby, and now my time that I used to do upstream work late at night was stolen"),这个系列延迟了近两年才提交 v2原文[6]。
13 个补丁按问题拆分:
•Patch 1-3:准备性重构(重命名、引入新辅助函数)•Patch 4-5:解决 magic margin——让 margin 根据硬件实际频率阶梯动态计算•Patch 6-7:解决 black hole——扩展util_est来跟踪 bursty/periodic 任务的历史活跃度•Patch 8-9:引入新的sched_qos接口,支持rampup_multiplier让用户空间控制 DVFS 的加速倍率•Patch 10-11:优化——抵消增加响应性带来的功耗影响•Patch 12-13:修复 util_est 和 util_avg 对周期性任务的振荡,Patch 12 需要 backport 到 stable
本周,Tom Gebhardt 提供了 ARM 平台的实测数据:在树莓派 5(Cortex-A76,4 核)上跑 stress-ng pipe,7.0.0 stock 在 2800 MHz 下对比 6.6 基线差 25.6%,加上 ttwu 补丁恢复到 -22.3%,再加 Qais 的两个 PELT 修复(12/13 和 13/13)后只差 5.9%——94% 的回归被恢复。
Qais 在回复中提出了一个关键观察:树莓派 5 默认用的是 ondemand governor 而非 schedutil,而他的补丁主要影响 schedutil 路径。这意味着性能提升可能来自 util_est 的修复本身(patch 12 修复了update_util_est()调用时机,patch 13 放开了load_avg更新的 period 限制),而非 DVFS 路径的改进。需要 perfetto trace 来确认。
John Stultz 也建议将 12/13 拆分出来单独提交,因为它们是 bug fix,不应该被前面有争议的 sched_qos 接口讨论阻塞。Qais 同意了这个计划。
这个系列瞄准的是 "调度器 → DVFS" 这条链路上长期存在的响应延迟问题。magic margin 和 black hole 问题不是理论推演——它们直接导致手机/桌面 UI 卡顿。ARM 平台的实测数据说明 PELT/util_est 的修复对所有架构都有效,但 DVFS 相关改动(rampup_multiplier、sched_qos 接口)的收益需要更多硬件平台验证。Patch 12/13 拆分后有望快速合入 stable。
cpu_preferred_mask 与 steal-driven vCPU backoff v3
原文[7]
Shrikanth Hegde 在 OSPM26 讨论后发布了第三版。核心思路:在虚拟化环境中,根据 steal time 动态收缩/扩展 preferred CPU mask,让调度器尽量把任务放在 steal time 低的 CPU 上。
v3 引入了独立的CONFIG_PREFERRED_CPU配置项(不再依赖 PARAVIRT),通过 debugfs 的steal_monitor目录控制启停。20 个补丁覆盖了 fair、RT、load balance、wakeup 等路径。
作者在本周发了 ping 邮件原文[8]请求 review。sched_ext 集成仍是 open item。
这是虚拟化场景下调度器感知 steal time 的首次系统性尝试。如果被接受,公有云上的调度器可以主动回避被 overcommit 的 CPU,而不是被动承受 steal 带来的延迟抖动。
pick_next_task() 消除 stale prev 引用 v29
原文[9]
John Stultz 的 proxy-exec 系列的一部分,重构pick_next_task()和prev_balance(),去掉prev参数,改为直接引用rq->donor。背景是 proxy-exec 引入后,rq->donor不再等于rq->curr,且rq->donor可能在 rq lock drop 期间被 return migration 修改,导致缓存的 prev 值失效。
这个改动涉及所有 sched_class 的->pick_next_task()和->balance()签名变更——DL、RT、fair、idle、stop_task 都要改。27 封邮件的讨论量说明这个改动经过了充分的 review。
本周已合入 tip:sched/core原文[10]。
Proxy-exec 是调度器近年来最大的架构性改动之一。消除 stale prev 是让 proxy-exec 在 return migration 场景下稳定工作的必要条件。v29 说明这个系列已经非常成熟。
二、重要 Bug 修复
Lazy preemption 导致 KVM vhost 吞吐暴跌
原文[11]
【问题】IBM 的 Ciunas Bennett 报告,默认 preemption 模式从 full 切换到 lazy 后,uperf TCP 测试(两个 VM 之间,单 vhost queue)吞吐从 ~50 Gb/s 降至 ~13 Gb/s。
【根因】vhost 任务通过schedule_work()把通知挂到system_percpu_wq(per-CPU 绑定)。Lazy preemption 下,如果 RT 父任务持续运行不主动 schedule,per-CPU kworker 要等整个 tick 才能拿到 CPU。kworker 平均延迟从 0.002ms 暴增到 0.721ms。这导致 vhost 无法及时通知 VM 有新数据,VM 端 TCP 出现重传和乱序。
【修复方案】切换到system_dfl_wq(unbound workqueue)后吞吐恢复到 ~50 Gb/s,kworker 延迟降到 0.005ms。Sebastian Andrzej Siewior 提到 Marco 正在重构 workqueue API 来显式区分 per-CPU 和 unbound 需求。
【影响范围】所有使用 lazy preemption + KVM vhost 的环境。不是调度器 bug,而是 lazy preemption 改变了 timing 假设,暴露了 workqueue 绑定策略的缺陷。
timer_slack_ns 在 SCHED_RESET_ON_FORK 下丢失
原文[12]
【问题】RT 任务设置SCHED_RESET_ON_FORK后,子线程继承timer_slack_ns=0(RT 的 slack),但sched_fork()把 policy 重置为SCHED_NORMAL时没有恢复 slack 值。子线程永远以 slack=0 运行。
【根因】两重 bug:init_task从未初始化default_timer_slack_ns(一直为 0);copy_process()用current->timer_slack_ns覆盖default_timer_slack_ns,RT 任务下就是 0。
【修复方案】在init_task中初始化default_timer_slack_ns=50000,在sched_fork()重置 policy 时从default_timer_slack_ns恢复。修复后中断频率从 832K/s 降至 363K/s。
【影响范围】所有 RT 任务使用SCHED_RESET_ON_FORK的场景。Cc: stable 范围需覆盖到 v6.6(ed4fb6d7ef68合入时间)。reviewer Cunlong Li 指出修复方案会影响非 RT 任务的 fork 语义,建议只处理 RT 父任务的情况。
Active load balance 在 CFS 任务 off_rq 时几乎必败
原文[13]
【问题】Active load balance 需要迁移线程中断 src_rq 上的当前任务。即使通过了 cpumask 亲和性检查,如果当前任务是 CFS 任务且on_rq=0(正在被 dequeue 或处于中间状态),active balance 的失败率极高。
【根因】18 CPU 平台上 300 秒测试数据显示,满足curr 是 CFS 且 on_rq=0条件的 active balance 尝试,绝大多数都失败了(比如 CPU 8 上 242 次尝试只成功 16 次)。
【修复方案】在need_active_balance()检查中增加条件:如果 busiest->curr 是 CFS 且!on_rq,直接跳过 active balance。对于非 CFS 任务保留原有亲和性检查(因为这类任务可能在 wake-up 路径有不同行为)。
【影响范围】有 fillback 任务场景的多核平台。减少了无效的 active balance 尝试和对应的 migration IPI 开销。
vruntime underflow:rescale_entity() 中 vlag 放大问题
原文[14]
华为的 Chen Jinghuang 报告了一个rescale_entity()中 vlag 放大的问题:当 cgroup 权重从 209715 急剧降到 614 时,vlag从 3.6G 放大到 1.2T,远超entity_lag()的 limit(724G)。这导致se->vruntime = avruntime - vlag发生下溢。
K Prateek Nayak 回复认为这可能是预期行为——vruntime使用的是 signed delta,下溢后通过zero_vruntime基准比较不会破坏正确性。这个讨论还在进行中,需要 Peter Zijlstra 的判断。
is_blocked 严格化 + proxy/delayed 统一判断
原文[15]
Peter Zijlstra 提交了两个补丁,已合入 tip:sched/core。第一个在try_to_block_task()入口加WARN_ON_ONCE(p->is_blocked),确保is_blocked在 wakeup 路径被正确清零。第二个将 proxy 和 delayed 任务的判断统一到p->is_blocked条件下,简化了ttwu_runnable()的分支逻辑。
三、sched_ext 进展
核心功能演进
Dispatch transaction API v4(Cheng-Yang Chou,3 补丁系列)引入了scx_bpf_dsq_insert_begin()和scx_bpf_dsq_insert_commit()两个 kfunc,解决 BPF 调度器在 pre-dispatch 检查和实际 insert 之间的竞态窗口问题。v4 限制commit()只能在ops.dispatch()中调用且只支持 local DSQ,Tejun Heo 做了大量接口约束设计。原文[16]
cid/cmask 接口为 sub-scheduler 铺路(Tejun Heo,3 补丁系列)重新排列了 cmask helper 参数顺序(与内核test_bit/cpumask_test_cpu保持一致),新增scx_cmask_test()和scx_cmask_for_each_cid(),并将scx_bpf_kick_cid()返回类型从 void 改为 s32。Tejun 在 cover letter 中明确说这是从 in-development 的 sub-scheduler 系列中抽取的。原文[17]
Arena 地址转换封装(Tejun Heo)添加scx_arena_to_kaddr()/scx_kaddr_to_arena()辅助函数,缓存arena_kern_base在scx_sched上。Tejun 说 "更多这样的转换正在路上"——暗示 BPF arena 在 sched_ext 中的使用场景会继续增加。原文[18]
稳定性修复
v7.1-rc6 fixes 已被 Linus 拉取(Tejun Heo):两个低风险修复——去掉 cgroup 迁移时的虚假 WARN,修复 drgn 调试脚本在 per-scheduler struct 重构后的读取问题。原文[19]
exit_cpu 准确性修复 v6(Cheng-Yang Chou):修正 hard lockup 和 softlockup 路径中 exit_cpu 使用错误值的问题,升级 RCU stall 路径以报告 cpumask 而非单个 CPU。Paul McKenney 参与了 RCU 侧的 review。原文[20]
dsq_move_to_local 自测修复(Cheng-Yang Chou):scan_dsq_pool()对scx_bpf_dsq_move_to_local()的返回值判断反了(检查== 0而非直接取 bool 值),导致成功时 double-dispatch、失败时跳过 fallback。原文[21]
生态与工具改进
LPC 2026 sched_ext Microconference 议题征集开始(Andrea Righi):Linux Plumbers Conference(内核开发者年度顶会)2026 年 10 月 5-7 日在捷克布拉格举办,sched_ext Microconference 是其中一个分会场。议题征集建议包括层级 cgroup sub-scheduler、DL server 集成、proxy execution、GPU 调度策略、BPF arena 可组合调度器等原文[22]
scx_flatcg 文档补全(Liang Luo):补充了 cgroup v2 的必要条件说明——scx_flatcg 依赖BPF_MAP_TYPE_CGRP_STORAGE和 cgroup v2 kfuncs,在 cgroup v1 系统上加载会报不明确的错误。原文[23]
sched_ext tools 构建修复(Leo Yan):Makefile 增加EXTRA_CFLAGS支持,方便交叉编译。原文[24]
scx_show_state.py 修复(Zicheng Qu):调试脚本适配 per-scheduler struct 变更。原文[25]
四、工具链与调试
perf sched 大规模修复(Arnaldo Carvalho de Melo)本周集中修复了perf sched子命令的多个 bug:在 event skip 消息中添加 file offset 以便交叉引用 perf report -D原文[26];修复latency_switch_event、timehist_get_thread等函数的 thread reference leak原文[27];清理get_idle_thread()中 init failure 后残留的半初始化 thread原文[28];将多处BUG_ON替换为 graceful skip;释放 idle thread cleanup 中的 callchain 节点。这些修复多数由 sashiko-bot 发现,Claude Opus 4.6 辅助编写。
preempt_offset 清理:__cant_sleep()的未使用preempt_offset参数被移除,简化了 API。原文[29]
五、趋势观察
CFS cgroup 正在经历 "压平" 运动。Flatten the pick、cfs_rq 数据局部性优化、bandwidth throttle 统一——这三个系列指向同一个方向:消除 cgroup 层级带来的遍历和间接开销。Peter Zijlstra 的 sched/flat 是核心,但 Prateek 的 throttle 统一和 Zecheng 的数据布局优化都在为它扫清障碍。如果这些系列在 7.2 周期合入,CFS cgroup 的性能模型将发生根本改变。
sched_ext 正在为 sub-scheduler 做架构准备。cid/cmask 接口完善、arena 地址转换封装、dispatch transaction API——这些看起来像是零散的功能补丁,但 Tejun 在 cover letter 中明确说它们来自 in-development 的 sub-scheduler 系列。BPF arena 作为 sub-scheduler 的共享内存基础设施,正在被一层层构建。LPC 2026 的议题列表也印证了这一点:hierarchical cgroup sub-schedulers 是讨论重点。
Peter Zijlstra 的 proxy-exec 系列接近成熟。pick_next_task() 重构到 v29、is_blocked 严格化已合入 tip——proxy-exec 的基础设施正在一块块落地。这个系列一旦合入,将改变内核处理 mutex holder 优先级反转的方式,对数据库和 JVM 工作负载有深远影响。
六、下周关注点
1.sched/flat 的 review 进度——v3 刚发,Peter 希望尽早合入。Vincent Guittot 和其他 maintainer 的反馈将决定时间线。
2.Lazy preemption 的 workqueue 解决方案——Marco 的 workqueue API 重构是否能在本周期推进,以及是否需要在调度器侧做额外适配。
3.sched_ext dispatch transaction API 的合入状态——v4 经过 Tejun 多轮 review,是否会被拉入 for-7.2。
4.Qais Yousef 的 PELT 修复是否独立提交——John Stultz 建议将 12/13 和 13/13 分离出来先行合入,ARM 的数据已经验证了效果。
5.LPC 2026 sched_ext CFP 响应情况——sub-scheduler、DL server 集成等议题的提案质量将反映社区对 sched_ext 未来方向的真实兴趣。