sched discussion
[PATCH v2] sched: Account cgroup CPU time to the execution context
LLM 分析
sched:cgroup CPU 时间归到执行上下文(v2)
系列概况
- 标题:[PATCH v2] sched: Account cgroup CPU time to the execution context
- 作者:Hui Su sh_def@163.com
- 版本:v2(共一封 patch,无系列号)
- 规模:1 file changed, 1 insertion(+), 3 deletions(-)
- 修改文件:
kernel/sched/fair.c(update_se()函数) - 代码统计:-3 +1
- Message-ID:20260904034707.268416-1-sh_def@163.com
- 完整性:完整 diff + commit message + Fixes tag + Suggested-by + Signed-off-by + Changes since v1 + Testing 矩阵
补丁目的
修复 proxy execution 场景下 cgroup CPU 时间被错误归到 donor cgroup 的回归。当 donor(提供调度上下文的 task)和真正执行代码的 task 处于不同 cgroup 时,旧代码会把执行 task 的 CPU 时间算到 donor 的 cgroup,破坏 cgroup 资源隔离的语义。补丁让 cgroup CPU usage 跟随真正在跑的那个 task(rq->curr),与已有的 per-task / thread-group runtime 归属规则保持一致。
旧流程的问题
Commit aa4f74dfd42b("sched: Fix runtime accounting w/ split exec & sched contexts")引入了「split exec & sched contexts」:per-task 和 thread-group 的 runtime 改为跟随真正执行的 task,但 cgroup CPU usage 仍记到 donor。结果在跨 cgroup 的 proxy execution 中,同一段执行时间在 per-task 维度归自己、在 cgroup 维度归别人——两个视角不一致。
donor (cgroup A) executor (cgroup B)
| |
| proxy_exec sets donor | actually runs code
v v
+-----------+ +-----------+
| sched ctx | ----------------> | exec ctx |
+-----------+ +-----------+
| |
per-task / tg runtime ----follows executor----+
cgroup CPU usage -------charged to donor A----+ <-- WRONG
新流程
update_se() 中把 cgroup_account_cputime 的入参从 donor 改为 running(即 rq->curr,当前 rq 实际执行者)。scheduling 状态仍归 donor,cgroup user/system time 也仍由 task 维度提供——三方都遵循「执行上下文优先」这一原则。
donor (cgroup A) executor (cgroup B)
| |
| proxy_exec sets donor | actually runs code
v v
+-----------+ +-----------+
| sched ctx | ----------------> | exec ctx |
+-----------+ +-----------+
| |
per-task / tg runtime ----follows executor----+
cgroup CPU usage -------follows executor B---+ <-- FIXED
(sched state still on donor A)
Patch 概览
只改 kernel/sched/fair.c 的 update_se(),三行删一行增:
@@ -1404,7 +1404,6 @@ static s64 update_se(struct rq *rq, struct sched_entity *se)
se->exec_start = now;
if (entity_is_task(se)) {
- struct task_struct *donor = task_of(se);
struct task_struct *running = rq->curr;
- /* cgroup time is always accounted against the donor */
- cgroup_account_cputime(donor, delta_exec);
+ cgroup_account_cputime(running, delta_exec);
account_group_exec_runtime(running, delta_exec);
account_mm_sched(rq, running, delta_exec);
} else {
核心改动:去掉 donor 局部变量与注释,把 cgroup 归属对象换成 running。
关键实现
- 函数:
update_se(),每次 task 离开 running 状态时被调用,是把"刚刚跑了多久"分摊到各账本的入口。 - 分支:
entity_is_task(se)表示当前 sched_entity 直接挂在一个 task_struct 上;否则是 group_entity,时间记到se->sum_exec_runtime。 - 设计选择:v1 曾引入 per-rq cputime owner、deferred boundary handling、donor lifetime tracking 等机制试图追踪跨 cgroup 边界,被 Tejun Heo 指出过度设计。v2 直接复用
rq->curr——它就是当前 rq 上真正在跑的 task,归属于它天然不歧义。 - cgroup user/system time:原本就以 task 为单位统计,不需要再切;这次只需要纠正 cgroup CPU usage 这一条漏网之鱼。
类比
把 cgroup 想象成「公司各部门的成本中心」。Proxy execution 就像 A 部门(donor)的主管被派到 B 部门顶岗干活:旧规则下这位主管在 B 部门打卡上班,但工资成本仍走 A 部门的账——B 部门的「本部门人工成本」凭空少了一截,A 部门则被多算。新规则下成本归实际干活的部门,B 部门的成本中心终于能反映真实工作负荷。
Highlight:风险与注意点
- 回归来源清晰:
Fixes: aa4f74dfd42b直接指向引入 split 的 commit,是 stable 回溯候选;任何启用了CONFIG_SCHED_PROXY_EXEC且跨 cgroup 部署的 workload 都会受影响。 - 测试覆盖够广:作者给了 cgroup v2 proxy reproducer、RT donor reproducer、cgroup v1 cpuacct legacy、
sched_proxy_exec=off对照组、CONFIG_SCHED_PROXY_EXEC / CONFIG_CGROUPS / CONFIG_CGROUP_CPUACCT构建矩阵、W=1与checkpatch --strict。 - 后续观察点:跨 cgroup 边界处若 cpu.stat 仍依赖 donor 视角的旧接口,下游监控/计费可能仍读错;需要关注 cgroup v2 cpu.stat 各字段在 proxy exec 下的语义说明是否同步更新。
- 未触达边界:CPU hotplug、cgroup throttled 边界、NMI/IRQ 时间不经过
update_se,不在本 patch 范围;不要误以为全 cgroup 计量都已被对齐。 - Tejun Heo 的回复仅引用了 patch 上下文,文本上未给进一步的 LGTM / Reviewed-by 字样,落地状态以后续 maintainer 邮件为准。
版本变化
- v1:引入 per-rq cputime owner、deferred boundary handling、donor lifetime tracking,并尝试把 cgroup user/system accounting 也搬到 scheduling context 上。结构复杂,被 Tejun 指出过度工程。
- v2:放弃上述机制,最小改动——
cgroup_account_cputime(running, delta_exec)跟随执行上下文,scheduling state 仍归 donor。代码量从「多机制叠加」压缩到-3 +1,机制简单也更对。
与其他相关 patch 系列的关联
- aa4f74dfd42b("sched: Fix runtime accounting w/ split exec & sched contexts"):本 patch 直接修复的回归引入点,所有 split exec & sched contexts 概念都源于它。
CONFIG_SCHED_PROXY_EXEC:proxy execution 子系统本身的开关注入点;任何围绕「donor vs executor」归属的 patch 都要回答「算到谁头上」这个问题,本 patch 是「cgroup 维度跟随 executor」的最小范例。
一句话总结
把 cgroup CPU 时间从 donor 改归真正的执行 task,纠正 proxy execution 引入的 cgroup 归属回归。