sched discussion
[PATCH] sched/fair: Drop min_vruntime() call from set_protect_slice()
LLM 分析
CFS 调度器:set_protect_slice() 简化被退回
系列概况
- 标题: [PATCH] sched/fair: Drop min_vruntime() call from set_protect_slice()
- 作者: Kayra Cizmeci kayracizmeci@gmail.com
- 版本: v1(单 patch,无后续版本;作者在 thread 内主动撤回)
- 规模: 1 file changed, 6 insertions(+), 1 deletion(-)
- 修改文件:
kernel/sched/fair.c - 代码统计:
set_protect_slice()函数体内1 处删除、4 行注释新增- Message-ID(首封):20260810115422.38390-1-kayracizmeci@gmail.com - 完整性: 完整 3 封——patch / reviewer 反驳 / 作者主动 drop
补丁目的
set_protect_slice()用来设置 se->vprot,它是 RUN_TO_PARITY 调度特性在 pick 实体时防止该实体被过度抢占的"保护水位"。
作者的原意是:进入该分支时 slice 已经是 min(slice, se->slice),所以 slice < se->slice,se->vruntime + calc_delta_fair(slice, se) 这条算出的路径必然是 min_vruntime() 的两个候选里更小的那一个。于是可以直接把 min_vruntime() 包装剥掉,省一次比较。
旧流程的问题
作者在 commit message 里隐含的假设是"se->vruntime + calc_delta_fair(slice, se) 一定在 se->deadline 之前"。Zhan Xusheng 在 review 里把这个假设拆穿了:
place_entity()在PLACE_DEADLINE_INITIAL(默认开)+ENQUEUE_INITIAL时会把vslice /= 2,新实体的se->deadline只领先 半个 slice。- 进入运行后,
update_deadline()在vruntime还没过 deadline 时直接返回、不刷新;put_prev_entity()把被抢占的实体重新入队时也不会续期 deadline。下一次 pick 时se->deadline - se->vruntime只是剩下那点 slice 余量。 - 因此只要
cfs_rq_min_slice(cfs_rq)大于(se->deadline - se->vruntime),直接算出的结果就 越过se->deadline。此时只有min_vruntime()把vprot拉回到 deadline 之前。 - 一旦
vprot > deadline,protect_slice()只比较se->vruntime与se->vprot,RUN_TO_PARITY 会把实体保护到其本应停止的时间之后,破坏 CFS 公平性。
换句话说,原作者看到的是"两个候选里算出来的更小",但他没看到"算出来的可能已经晚于 deadline"——min_vruntime 真正兜底的是这一层语义,而不是简单的"取小"。
新流程
作者在第 3 封邮件中明确请求 drop,patch 没有被合并。set_protect_slice() 维持原状:
slice = cfs_rq_min_slice(cfs_rq);
slice = min(slice, se->slice);
if (slice != se->slice) {
vprot = min_vruntime(vprot, se->vruntime + calc_delta_fair(slice, se));
se->vprot = vprot;
}
Patch 概览
只动 kernel/sched/fair.c 的 set_protect_slice():
- vprot = min_vruntime(vprot, se->vruntime + calc_delta_fair(slice, se));
+ vprot = se->vruntime + calc_delta_fair(slice, se);
并在函数体内追加 4 行注释,断言"算出来的值始终在 se->deadline 之前,因此不需要比较"。
关键实现
- 删除
min_vruntime()包装,直接把算式赋给vprot。 - 注释里写的"
< se->slice⇒ 计算值必在 min_vruntime 之前"这一步假定了se->deadline等于完整 slice,但这个前提并不总成立。 - 测试只覆盖 Zen3 x86 的启动路径,没跑 RUN_TO_PARITY + 自定义 slice 的功能场景。
类比
把 se->deadline 想成电影票上的"入场截止时间",se->vprot 是"持票人受保护的最后时刻":
- 简化 patch 的潜台词是"我提前到,肯定赶得上"。
- 但这张票其实是"首映优惠票"——
PLACE_DEADLINE_INITIAL把时间砍到一半(half slice);而且放映已经开始了一段时间(实体已运行),截止时间比票面上看到的更靠前。 - 真正稳妥的
min_vruntime就是"在'你算出的时间'和'票面上的截止时间'之间取 更早 的那个",避免在票失效之后还把观众留在大厅里享受保护。
new entity enqueue (PLACE_DEADLINE_INITIAL = on, ENQUEUE_INITIAL = set)
|
v deadline = vruntime + 0.5 * slice <-- half-slice deadline!
|
v entity runs a while |
v update_deadline() returns early (vruntime < deadline)
|
v preempted -> put_prev_entity() re-enqueues WITHOUT renewing deadline
|
v by next pick: (deadline - vruntime) = small remainder < 0.5 * slice
|
v cfs_rq_min_slice(cfs_rq) < se->slice --> branch fires
|
v computed = vruntime + calc_delta_fair(slice, se)
|
+--- WITHOUT min_vruntime : vprot = computed (PAST deadline) BUG
|
+--- WITH min_vruntime : vprot = min(computed, deadline)
keeps vprot at/before deadline
reviewer call path (Zhan Xusheng)
|
v
place_entity() halves vslice under PLACE_DEADLINE_INITIAL
|
v
update_deadline() no-op while vruntime < deadline
|
v
put_prev_entity() re-enqueues without deadline renewal
|
v
next pick sees (deadline - vruntime) << se->slice
|
v
set_protect_slice() branch fires with cfs_rq_min_slice(cfs_rq) > remainder
|
v
computed > deadline ==> min_vruntime() is the safety net, not redundancy
Highlight:风险与注意点
PLACE_DEADLINE_INITIAL默认开启:所有 ENQUEUE_INITIAL 路径上 deadline 都只领先半 slice,作者没有覆盖这一分支。put_prev_entity()不续期 deadline:被抢占再入队后,剩余时间窗比表面看上去要小得多。- 这是语义错而不是性能回退:单纯做 boot test 抓不到;需要 trace 或功能测试覆盖 RUN_TO_PARITY + 自定义 slice 场景。
- simplification 类 patch 必须双向读:只看
set_protect_slice()单点、忽略place_entity()/update_deadline(),极易得出错误的不变量。 - 若作者未来再提 v2:必须先证明
se->vruntime + calc_delta_fair(slice, se) <= se->deadline在所有路径上恒成立,否则应保留min_vruntime()作为兜底。 - review 价值点:Zhan 通过读
place_entity()反推出 half-slice deadline,再结合put_prev_entity()的非续期行为,才把原作者"两个候选里取较小"这种纯局部论证驳倒——这是函数级别优化 review 中典型的"跨函数求证"思路。
版本变化
仅 v1,thread 内由作者主动撤回;不存在 v2 或后续 spin。
一句话总结
Kayra 想省掉 set_protect_slice() 里的 min_vruntime(),Zhan 指出 PLACE_DEADLINE_INITIAL + 运行消耗会让 deadline 不等于完整 slice,算出的 vprot 可能越过 deadline、破坏 RUN_TO_PARITY,作者当场认错并请求 drop patch。