sched discussion
[PATCH v2] sched/core: Preserve wake flags across queued wakeups
LLM 分析
sched/core:在 queued wakeup 路径上保留 wake flags
系列概况
- 标题:
[PATCH v2] sched/core: Preserve wake flags across queued wakeups - 作者: Shubhang Kaushik (Ampere) sh@gentwo.org
- 版本: v2;base-commit =
d96fcfe1b7f9(mainline origin/master) - 规模: 单 patch;3 个文件,+7/-18
- 修改文件:
include/linux/sched.h、kernel/sched/core.c、kernel/sched/sched.h - 代码统计: +7/-18
- Message-ID:
20260713-b4-sched-ttwu-wake-flags-v2-1-76e23a8cc313@gentwo.org - 完整性: 完整(含 commit message、Signed-off-by、base-commit、change-id、v1 链接、perf bench/hackbench 测试结论)
补丁目的
让 queued remote wakeup 在被 sched_ttwu_pending() drain 时,传入 ttwu_do_activate() 的 wake flags 与直接 try_to_wake_up() 路径保持一致,避免两条路径在目标 CPU 非空闲时给出不同的抢占决策。
旧流程的问题
旧实现只在 task_struct 中保留 sched_remote_wakeup:1 一个布尔位,仅记录 "wakee 是否被迁移过"。其余 WF_TTWU / WF_SYNC / WF_RQ_SELECTED 等激活阶段需要的 flag 全部被丢弃。
当 wakeup 跨 CPU 被排入 wakelist,等到目标 CPU自行 drain 时只能传回 WF_MIGRATED 或 0,这与 direct wakeup 把完整 wake_flags 传给 ttwu_do_activate() 的做法不一致,从而在目标 CPU 非空闲场景下产生不同抢占结果。
新流程
把 sched_remote_wakeup:1 替换为独立的 u8 sched_remote_wakeup_flags,使用新的 WF_TTWU_QUEUE_MASK 在 __ttwu_queue_wakelist() 阶段截取并保存真正影响激活路径的位;drain 时再原样回传给 ttwu_do_activate()。
WF_CURRENT_CPU 故意不放进 mask——它只是 CPU 选择阶段的放置提示,进入激活流程已无意义。
direct try_to_wake_up() queued remote wakeup
--------------------- ----------------------
wake_flags (full set) p->sched_remote_wakeup_flags
| = wake_flags & WF_TTWU_QUEUE_MASK
v |
ttwu_do_activate(rq,p,wake_flags,..) v
sched_ttwu_pending() (target CPU)
|
v
ttwu_do_activate(rq,p,
stored_flags,..)
|
v
consistent preemption
decision w/ direct path
mask membership:
WF_TTWU | YES | -- activation matters
WF_SYNC | YES | -- activation matters
WF_MIGRATED | YES | -- was already kept
WF_RQ_SELECTED | YES | -- activation matters
WF_CURRENT_CPU | NO | -- placement hint only
关键实现
kernel/sched/sched.h 新增掩码:
#define WF_TTWU_QUEUE_MASK (WF_TTWU | WF_SYNC | WF_MIGRATED | WF_RQ_SELECTED)
kernel/sched/core.c 写入端(__ttwu_queue_wakelist):
p->sched_remote_wakeup_flags = wake_flags & WF_TTWU_QUEUE_MASK;
读取端(sched_ttwu_pending):
int wake_flags;
wake_flags = p->sched_remote_wakeup_flags;
ttwu_do_activate(rq, p, wake_flags, &rf);
include/linux/sched.h 把字段从 unsigned sched_remote_wakeup:1 改为独立的 u8 sched_remote_wakeup_flags,并删除与之配套的、关于 p->on_cpu 不再序列化 wakelist 的长篇注释;v2 把字段挪出 scheduler word,避免再与该 bitfield 的串行化约束挂钩。
类比
把 wake flags 想成快递面单上的处理标签。直送路径就像快递员看到 "加急 / 同步 / 已选路线 / 已转运" 全部标签后决定何时投递;旧 queued 路径相当于把面单撕掉只剩 "是否转运",目的分拣站只看到这个标签来处理。
新版本相当于给转运件保留了一份精简过的面单副本(WF_TTWU_QUEUE_MASK),让分拣站能和直送件做出一致的优先级判断。而 WF_CURRENT_CPU 不进副本,是因为它只是 "去哪个分拣中心" 的提示;一旦进了分拣流程,再保留这个地址已经没有意义。
Highlight:风险与注意点
- 行为变化面:queued wakeup 的 preemption 决策会更接近 direct wakeup,可能让以往依赖旧默认行为的 workload 见到细微的延迟 /吞吐差异,需要重点 review 抢占敏感场景。
- 字段体积与 bitfield 语义:从 1 bit 变
u8有task_struct体积开销;v2 已把它挪出 scheduler word,原先关于 "被 on_cpu 序列化" 的长注释被删除,需要确认 reviewer 理解字段位置变更。 - 覆盖完整性:
WF_TTWU_QUEUE_MASK当前含 4 个 flag;将来若给ttwu_do_activate()新增激活语义 flag,必须同步加入 mask,否则又会出现遗漏。 - 测试覆盖:作者仅在 Ampere Altra 80 CPU ARM 服务器上跑
perf bench sched messaging与hackbench,吞吐处于噪声范围;建议在 x86 NUMA 拓扑或抢占更敏感的内核构建下复测。 - 可观测性:tracepoint / perf 等若记录 wake flags,需确认它们读到的是 drain 后的完整 mask,而不是被丢掉的其它位。
版本变化(v1 → v2)
- 把
sched_remote_wakeup_flags移出 scheduler bitfields,作为独立u8。 - 去掉
sched_ttwu_pending()里不再需要的 reset。 - 新增
WF_TTWU_QUEUE_MASK,明确跨 wakelist 保留哪些 wake flags。 - 收紧 changelog,聚焦 direct 与 queued wakeup 之间的一致性。
一句话总结
把 queued wakeup 上保存的 wake flags 从 "是否迁移" 一位布尔扩展到 WF_TTWU_QUEUE_MASK,让 sched_ttwu_pending() drain 时传给 ttwu_do_activate() 的 flag 与 direct wakeup 路径保持一致,从而统一两条 wakeup 路径的抢占决策。