0/3 已展开

LLM 分析

Scheduler 核心:跨排队唤醒保留 wake flags

系列概况

  • 标题: [PATCH] sched/core: Preserve wake flags across queued wakeups
  • 作者: Shubhang Kaushik (Ampere) sh@gentwo.org
  • 版本: v1(单补丁)
  • 规模: 2 个文件,+10/-5 行
  • 修改文件: include/linux/sched.hkernel/sched/core.c
  • 代码统计: 10 insertions(+), 5 deletions(-)
  • Message-ID: 20260710-b4-sched-ttwu-wake-flags-v1-1-23182a4c5367@gentwo.org
  • 完整性: 完整;包含 1 封 PATCH 主帖 + 2 封回复;base-commit d96fcfe1b7f94ac742984ae7986b94a116abff1b

补丁目的

修复 queued wakeup 路径丢失激活相关 wake flags 的问题。当前 __ttwu_queue_wakelist() 只能记下唤醒方是否迁移,把 WF_MIGRATED 以外的所有位(WF_SYNCWF_TTWUWF_RQ_SELECTED)都丢弃;当目标 CPU 通过 sched_ttwu_pending() 排空 wakelist 时,ttwu_do_activate() 收到的标志集与直接唤醒路径不一致,唤醒抢占决策可能产生分歧。

旧流程的问题

直接唤醒路径里,调用者把完整 wake_flags 一路传到 ttwu_do_activate(),下游(如 ttwu_do_wakeup()check_preempt_curr())能完整看到所有位。但走排队路径时:

  • p->sched_remote_wakeup 只占 1 bit,只能写入布尔结果
  • 真正影响激活/抢占的 WF_SYNCWF_TTWUWF_RQ_SELECTED 全部丢失
  • 排空 wakelist 时 sched_ttwu_pending() 只能重建出 WF_MIGRATED 或 0
  • 同一任务可能因走排队或直接路径而在抢占决策上得到不同结果

新流程

  • task_struct 把字段从 sched_remote_wakeup:1 改成 sched_remote_wakeup_flags:8
  • 排队侧写入掩码:WF_TTWU | WF_SYNC | WF_MIGRATED | WF_RQ_SELECTED
  • 排空侧读出 → 清零 → 透传给 ttwu_do_activate()
  • WF_CURRENT_CPU 显式排除(属于 CPU选位提示,而非激活标志)

Patch 概览

/* include/linux/sched.h */
- unsigned sched_remote_wakeup:1;
+ unsigned sched_remote_wakeup_flags:8;

/* kernel/sched/core.c :: sched_ttwu_pending() */
+ int wake_flags;
+ wake_flags = p->sched_remote_wakeup_flags;
+ p->sched_remote_wakeup_flags = 0;
- ttwu_do_activate(rq, p, p->sched_remote_wakeup ? WF_MIGRATED : 0, &rf);
+ ttwu_do_activate(rq, p, wake_flags, &rf);

/* kernel/sched/core.c :: __ttwu_queue_wakelist() */
- p->sched_remote_wakeup = !!(wake_flags & WF_MIGRATED);
+ p->sched_remote_wakeup_flags = wake_flags &
+   (WF_TTWU | WF_SYNC | WF_MIGRATED | WF_RQ_SELECTED);

关键实现

1.字段重定义

sched_remote_wakeup:1 改为 sched_remote_wakeup_flags:8。位宽扩到 8 bit 足够覆盖当前所有 WF_* 位,注释里同步说明新用途。

2. 排队侧:保存关键 wake flags

p->sched_remote_wakeup_flags = wake_flags &
    (WF_TTWU | WF_SYNC | WF_MIGRATED | WF_RQ_SELECTED);

用位与白名单而不是简单布尔。WF_CURRENT_CPU 主动被排除,因为它影响的是 CPU 选择,不会影响激活阶段的抢占判断。

3. 排空侧:读出即清零

wake_flags = p->sched_remote_wakeup_flags;
p->sched_remote_wakeup_flags = 0;
ttwu_do_activate(rq, p, wake_flags, &rf);

清零放在读出后,避免下次入队/排空之间产生标志残留。

类比

把 wakeup 比作快递派送:

  • 直接派送:快递员亲手把包裹连同"易碎/签收/加急/转运"等所有标签一起交到收件人手中。
  • 旧队列派送:快递员只把包裹丢进中转站桶,在包裹上贴一张"曾经转运过"的便签,另一名快递员来取件时只能看到那一张便签,所有特殊处理要求全丢。
  • 新队列派送:快递员把激活相关的所有标签都贴在包裹上,中转站取件员照原样读出并送达。
wake_flags           old: WF_MIGRATED bool -> [1 bit]
                     new: MASK_4_BITS       -> [8 bit]

storage              old: p->sched_remote_wakeup:1
                     new: p->sched_remote_wakeup_flags:8

drain                old: WF_MIGRATED or 0   -> ttwu_do_activate()
                     new: saved flags (post-clear) -> ttwu_do_activate()
  waker
 |
    | direct wakeup: full wake_flags
    v ttwu_do_activate()  ----> preemption / placement ^
 |
  waker --WF_MIGRATED bool--> ttwu_queue_wakelist() --llist-->
 |
                                  v target CPU
 sched_ttwu_pending()
                            read p->sched_remote_wakeup_flags
                            clear field
                            pass to ttwu_do_activate()

Highlight:风险与注意点

  • 位域原子性:1 bit 写入在所有架构上原子,但 8 bit 位域写入依赖编译器布局与目标 ABI,存在被拆成两次字节写入的可能。回复里作者已提到"按字节大小的写入通常原子",reviewer 进一步建议改成显式 u8 字段、紧跟 personality 放置,避免与 rq_lock 串行化字段共享 cache line 时出现踩踏。
  • 白名单维护:当前只覆盖 4 个位,将来 wake_flags 新增位时要同步更新这里的掩码,否则新位会再次悄悄丢失。
  • 重复入队竞争:清零紧贴读出之后执行,需要确认在 ttwu_queue_wakelist() 那一侧的写入同样处在 p->pi_lock/rq->lock 的串行化窗口内,否则理论存在窗口让"清零 → 再入队"的两次写入顺序错乱。
  • 真实收益的工作负载:作者说 perf bench sched messaginghackbench 上结果在运行间噪声范围内;收益更可能出现在强 WF_SYNC 或激进 wakeup-preemption 的负载上,需要更针对性的测试。
  • WF_CURRENT_CPU 的边界:必须明确这是选位 hint 而非激活 flag,提交说明要持续维护这个区分,否则后续 contributor 容易把它也加进白名单。

版本变化

仅有 v1。后续两封回复(K Prateek Nayak 回引 diff;作者引用 Peter Zijlstra 在 2020 年的相关讨论 20201116142005.GE3121392@hirez.programming.kicks-ass.net 并提议改 u8)属 review/cleanup 提议,尚未形成 v2。

一句话总结

sched_remote_wakeup:1 扩展成 sched_remote_wakeup_flags:8,让排队唤醒路径透传 WF_TTWU/WF_SYNC/WF_MIGRATED/WF_RQ_SELECTED,使远端排空时的 ttwu_do_activate() 与直接唤醒行为一致;review 阶段建议改为显式 u8 字段以避免位域原子性歧义。