sched-ext discussion
[PATCH] sched_ext: don't deliver duplicate ops.cgroup_set_idle() for same value
LLM 分析
sched_ext:避免对相同 idle 值重复派发 cgroup_set_idle 回调
系列概况
- 标题:[PATCH] sched_ext: don't deliver duplicate ops.cgroup_set_idle() for same value
- 作者:Tao Cui cuitao@kylinos.cn
- 版本:v1(单封 patch,邮件标题无 [vN] 前缀)
- 规模:1 个文件,+2/-1 行
- 修改文件:kernel/sched/ext/ext.c
- 代码统计:1 file changed, 2 insertions(+), 1 deletion(-)
- Message-ID:20260901031101.731943-1-cui.tao@linux.dev
- 完整性:commit message + diff + Fixes tag + Signed-off-by 完整;Link: 标签为空(被 Andrea Righi 在 review 中指出)
补丁目的
ops.cgroup_set_idle() 在文档里被定义成"cgroup 在 idle 与非 idle 之间发生跃迁时"才触发;但 scx_group_set_idle() 当前是无条件派发——只要用户再次写入与当前相同的 cpu.idle 值,BPF 调度器都会收到一次伪"跃迁"。对基于切换计数或累计的 BPF 调度器而言,重复写入会被错算成多次状态切换。
本补丁在派发条件里追加 tg->scx.sched_idle != idle,让"无变化"的写入短路掉,与 scx_group_set_weight() 已有的 value-preserving 跳过路径对齐。
旧流程的问题
每次写入 cpu.idle 都直接通过 SCX_CALL_OP 触发 BPF 侧的回调:
if (scx_cgroup_enabled && sch && SCX_HAS_OP(sch, cgroup_set_idle))
SCX_CALL_OP(sch, cgroup_set_idle, NULL, tg_cgrp(tg), idle);
等值写入会让 BPF 调度器误以为发生了一次 idle ↔ non-idle 跃迁:做 toggle 的调度器多翻一次开关,做累计的调度器多计一次 idle 周期,依赖"只在边界触发"语义的实现会失真。
新流程
if (scx_cgroup_enabled && sch && SCX_HAS_OP(sch, cgroup_set_idle) &&
tg->scx.sched_idle != idle)
SCX_CALL_OP(sch, cgroup_set_idle, NULL, tg_cgrp(tg), idle);
只有当目标 idle 值与上次记录的 sched_idle 不一致时才真正调用 BPF 回调,与 scx_group_set_weight() 的 guard 模式对称。
+-----------+ old flow (unconditional) +-----------+
| write | -- always --> SCX_CALL_OP(...) --> | BPF sched |
| cpu.idle | +-----------+
+-----------+
+-----------+ new flow (guarded) +-----------+
| write | -- guard sched_idle != idle ? -----> | BPF sched |
| cpu.idle | \ +-----------+
| | \--> skip if same value (no callback)
+-----------+
Patch 概览
- 修改点:kernel/sched/ext/ext.c 的
scx_group_set_idle()。 - 修改前后对比:
- if (scx_cgroup_enabled && sch && SCX_HAS_OP(sch, cgroup_set_idle))
+ if (scx_cgroup_enabled && sch && SCX_HAS_OP(sch, cgroup_set_idle) &&
+ tg->scx.sched_idle != idle)
SCX_CALL_OP(sch, cgroup_set_idle, NULL, tg_cgrp(tg), idle);
- 对称做法:与
scx_group_set_weight()跳过等值写入的模式对齐。 - 修复目标 commit:
347ed2d566da ("sched/ext: Implement cgroup_set_idle() callback")。
关键实现
void scx_group_set_idle(struct task_group *tg, bool idle)
{
percpu_down_read(&scx_cgroup_ops_rwsem);
sch = scx_tg_knob_sched(tg);
if (scx_cgroup_enabled && sch && SCX_HAS_OP(sch, cgroup_set_idle) &&
tg->scx.sched_idle != idle) /* new guard */
SCX_CALL_OP(sch, cgroup_set_idle, NULL, tg_cgrp(tg), idle);
/* Update the task group's idle state */
}
守卫条件 tg->scx.sched_idle != idle 借助 task_group 的 scx 子结构里记录的"上次派发值"做比较,避免重复跃迁事件。
类比
把它想成宿舍楼里"住户在家 / 外出"的门牌翻牌器:
- 旧流程:管理员每次路过都随手翻一次门牌,哪怕住户其实没变。结果楼栋统计系统以为又发生了一次出入,电梯流量计费也跟着虚增。
- 新流程:管理员翻牌前先瞄一眼当前牌面,住户真变了才翻——楼栋统计、电梯计费都只反映真实事件,BPF 调度器也就只收到"真跃迁"。
Highlight:风险与注意点
tg->scx.sched_idle字段不一定存在:sashiko-bot 静态扫描以 Low 严重度报警,指出tg->scx中可能没有sched_idle成员,理论上会导致编译失败。Andrea Righi 仍给出 Reviewed-by,意味着该字段在他基于的内核树里存在,或者由另一个配套 patch 引入;合入前应核对上游是否同步具备成员定义,必要时把字段定义也带上。- patch 没有展示对
sched_idle的赋值更新。原函数SCX_CALL_OP之后还有/* Update the task group's idle state */注释——对称地看本 patch 可能缺少"回调之后写回 sched_idle"那一行,否则 guard 会一直读到同一个旧值,重复写入仍可能继续派发。建议 v2 同步补齐赋值。 Link:标签为空:Andrea Righi 在 review 里明确指出 "this link seems broken",需要在重新提交时补上一个真实可访问的归档 / 上游链接(例如 lore.kernel.org 自己的 URL)。- 测试口径只有"打印回调次数"的探针:足以证明回调不再重复,但未覆盖 BPF 侧 toggle / 累计统计是否仍正确;后续 v2 可补一份对照实验,把"两次相同 idle 写入"前后 BPF 内部计数器的快照记录下来。
- 命名一致性:把
tg->scx.sched_idle和idle命名风格放在一起略显不一致(一个是"sched idle"语义字段,一个是 bool 形参),维护者可能在 v2 中建议改成tg->scx.idle或类似形式以减少认知负担。
一句话总结
在 scx_group_set_idle() 的派发条件里追加"新旧值不同才回调"的守卫,避免相同 idle 值被反复误算成跃迁事件,与 scx_group_set_weight() 的现有做法保持对称。