sched discussion
[PATCH] sched/fair: Fix the util_avg_cap formula in a comment
LLM 分析
sched/fair:修复注释中 util_avg_cap 公式
系列概况
- 标题:
[PATCH] sched/fair: Fix the util_avg_cap formula in a comment - 作者:Zhan Xusheng zhanxusheng@xiaomi.com
- 版本:单封 v1(无版本号)
- 规模:1 个 patch,单文件改动
- 修改文件:
kernel/sched/fair.c - 代码统计:4 insertions(+), 2 deletions(-)
- Message-ID:
20260717092530.1495648-1-zhanxusheng@xiaomi.com - 完整性:完整 patch,包含 diff、commit message 主体、Fixes 标签、Sign-off
补丁目的
init_entity_runnable_average() 上方解释新任务 util_avg 上限的注释里写的是
(cpu_scale - cfs_rq->avg.util_avg) / 2^n,而真实代码实现的是除以 2。
注释本身给的工作示例(1024 容量、512 已用、第 2 个任务得到 256)和代码也是
一致的——只是文字公式少抄了"反复对剩余预算除以 2 才会得到 2^n 序列"这一层
逻辑。本补丁把注释公式改成与代码一致,并补一句说明 2^n 序列来自"每新建一个
任务就把剩余预算再砍一半",而不是每次新建任务都按 2^n 缩放。
旧流程的问题
注释里 (cpu_scale - cfs_rq->avg.util_avg) / 2^n 的写法有两个问题:
- 公式与代码不一致:代码做的是
(cpu_scale - cfs_rq->avg.util_avg) / 2,
不是/ 2^n。读者按注释公式去对照代码会一头雾水。 - 公式与注释自身的例子不一致:用第 2 个任务、
util_avg = 512、
cpu_scale = 1024代入,注释公式得到(1024 - 512) / 2^2 = 128,
而注释表格里给出的值是 256,代码算出来也是 256。
这是个纯注释 bug,但阅读 fair.c 的开发者会拿到一个错误的"心智模型",
从而误以为单次上限的衰减系数随任务序号指数增长——这对后续调试或在该处
增加新逻辑(例如更细粒度的 cap)非常危险。
新流程
保留代码逻辑不动,只把注释公式改为
util_avg_cap = (cpu_scale - cfs_rq->avg.util_avg) / 2,
并加一句解释:因为 cfs_rq->avg.util_avg 会累加之前已建任务的结果,
每次"对剩余预算再砍一半"叠加起来,对第 n 个任务来说最终上限才是
cpu_scale / 2^n。代码语义零变化,只修正文档。
Patch 概览
| 文件 | 位置 | 改动 |
|---|---|---|
kernel/sched/fair.c | init_entity_runnable_average 上方注释块 | 公式 /2^n → /2;新增 2 行解释 2^n 序列的来源 |
关键实现
被改动的核心是注释,不是 C 代码。改动前后的 hunk 含义如下:
/*
- * util_avg_cap = (cpu_scale - cfs_rq->avg.util_avg) / 2^n
- * where n denotes the nth task and cpu_scale the CPU capacity.
+ * util_avg_cap = (cpu_scale - cfs_rq->avg.util_avg) / 2
+ * where cpu_scale is the CPU capacity. Since cfs_rq->avg.util_avg
+ * accumulates the previously created tasks, applying this cap to each new
+ * task gives the nth task a util_avg_cap of cpu_scale / 2^n.
*
* For example, for a CPU with 1024 of capacity, a simplest series from
* the beginning would be like:
* ...
*/
Fixes: 2b8c41daba32 ("sched/fair: Fix initial util_avg calculation") 指明
这条坏注释最初是被 commit 2b8c41daba32 引入的,对应的 stable 标记逻辑
会让这个修复回溯到所有包含该 commit 的 stable 分支。
下面用一张图把"注释里误导性的公式 / 实际代码 / 真实累加结果"三条线索并排
放在一起,方便对比:
task# cfs_rq util_avg comment says /2^n code does /2 actual cap
----- --------------- ------------------ ------------- ----------
1 0 1024 / 2^1 = 512 1024 / 2 =512 512
2 512 (1024-512)/2^2=128 (1024-512)/2=256 256
3 768 (1024-768)/2^3=32 (1024-768)/2=128 128
4 896 (1024-896)/2^4=8 (1024-896)/2=64 64
-> comment "column 3" never matches code "column 4"
-> series in "column 4" is 512,256,128,64... which equals cpu_scale/2^n
only because cfs_rq->avg.util_avg keeps accumulating the previous caps.
代码 init_entity_runnable_average() 中真正发生的事是简单的"对剩余预算
除以 2",2^n 序列是累加的副产物:
init_entity_runnable_average(se)
|
v
util_avg = 0
|
v
remaining = cpu_scale - cfs_rq->avg.util_avg
|
v
cap = remaining / 2 <-- 注释里错写成 "/ 2^n"
|
v
util_avg = min(util_avg, cap)
|
v
cfs_rq->avg.util_avg += util_avg <-- 累加到 rq 总量,下次任务用
类比
把 cpu_scale 想成一个固定大小的蛋糕(容量 1024),每个新任务进入 cfs_rq
时只能分走剩余蛋糕的一半——第一个任务分走 512,剩下 512;
第二个任务分走 256,剩下 256;以此类推。
并不是每个任务一次性就把蛋糕切成 1/2、1/4、1/8……而是"分一次、剩一次、
下次再分剩下的"。注释里直接写"第 n 个任务拿到 1/2^n"是结果对、过程错——
就像直接告诉别人"第 n 个月存 1/2^n 元"听起来像是每个月按指数缩减,
但其实是把每月剩余金额再砍一半、累加起来才得到这个序列。
Highlight:风险与注意点
- 公式误导而非行为 bug:代码本身没有问题,只是注释错误;不影响调度行为,
但维护者在该区域附近做新特性(例如动态 cap、per-CPU 上限调整)时可能被
错误的/2^n公式带偏。修注释比修代码更便宜,但是个非常合理的提交。 Fixes标签会触发 stable 回溯:因为指向了被多个 stable 系列吸收的
commit,maintainer 通常会要求带上Cc: stable@vger.kernel.org显式抄送,
并确认subject前缀使用sched/fair:而非手写编号。- 可能的扩展讨论点:是否同时把那段示例表也补全(标注第 1、2、3…… 个
任务的实际数值),或者把"/2^n"作为注释里唯一出现的位置统一替换;
这只是 polish,不是必须。
一句话总结
这是一条仅修注释的 patch:把 fair.c 中 util_avg_cap 公式从错误的
/2^n 改成与代码一致的 /2,并补一句说明 2^n 序列来自逐次对剩余预算
减半的累积行为。