sched discussion
[PATCH v4] sched/fair: Preserve wake-affine CPU for non-SMT reciprocal sync wakeups
LLM 分析
sched/fair:保留非 SMT 互反同步唤醒的 wake-affine CPU(v4)
系列概况
- 标题:[PATCH v4] sched/fair: Preserve wake-affine CPU for non-SMT reciprocal sync wakeups
- 作者:Shubhang Kaushik (Ampere) sh@gentwo.org
- 版本:v4(迭代自 v1/v2/v3)
- 规模:单 patch
- 修改文件:
kernel/sched/fair.c - 代码统计:1 file changed, 26 insertions(+)
- Message-ID:20260803-b4-sched-sync-wakeup-v4-1-52333b0cfb79@gentwo.org
- 完整性:包含完整 commit message、diff、性能测试数据、版本演进说明;基线 commit 5186ef36909c(tip:sched/core);thread 包含 6 封邮件(1 patch + 5 reply),讨论覆盖 SMT 路径、WF_SYNC 语义、基准覆盖面
补丁目的
CFS wakeup 路径里 wake_affine() 可能选中 waker CPU 作为目标,但接下来 select_idle_sibling() 又会去搜索空闲 CPU。pipe ping-pong 这种 A 与 B 互相唤醒对方的窄互反场景,把 wakee 挪走反而比贴住 waker CPU 更贵(cache miss、IPI、跨核搬运)。本 patch 限定非 SMT 系统上当 waker rq 上没有其他 fair 任务时,让 select_task_rq_fair() 在 idle-sibling 之前直接返回 waker CPU。
旧流程的问题
对 WF_SYNC 唤醒:
wake_affine()选中 waker CPU(亲和路径已经算出 wake_affine_idle)。- 控制流继续进入
select_idle_sibling(),把目标换成搜索到的 idle CPU。 - A <-> B 互反唤醒里 wakee 本来就贴 waker 跑,被挪走导致 cache 失效、runqueue 重新 attach、IPI 等待。
新流程
WF_SYNC wakeup
|
v
wake_affine() picks waker CPU
|
v
select_task_rq_fair()
|
|-- sync && !SMT && new_cpu == cpu
| && p->last_wakee == current
| && prefer_sync_pair_cpu(p, cpu) ---> return cpu
|
+-- otherwise continue select_idle_sibling()
判定条件:
sync(WF_SYNC)!sched_smt_active()(非 SMT 系统)p->last_wakee == current(A <-> B 互反)prefer_sync_pair_cpu()真:- waker rq 上
(nr_running - cfs_h_nr_delayed) == 1(无其他 fair 任务) - 若
sched_asym_cpucap_active(),还需task_fits_cpu(p, cpu)
- waker rq 上
Patch 概览
新增 helper prefer_sync_pair_cpu() 并在 select_task_rq_fair() 早返回 waker CPU;不动 wake_affine()、不动 SMT 路径、不动通用 WF_SYNC 路径。
关键实现
static bool prefer_sync_pair_cpu(struct task_struct *p, int cpu)
{
struct rq *rq = cpu_rq(cpu);
if ((rq->nr_running - cfs_h_nr_delayed(rq)) != 1)
return false;
if (sched_asym_cpucap_active()) {
sync_entity_load_avg(&p->se);
if (!task_fits_cpu(p, cpu))
return false;
}
return true;
}
调用点(位于 select_task_rq_fair() 中 wake_affine 已选/保留 waker CPU 之后):
if (sync && !sched_smt_active() &&
new_cpu == cpu &&
p->last_wakee == current &&
prefer_sync_pair_cpu(p, cpu))
return cpu;
性能数据(80 核非 SMT Ampere Altra,tip:sched/core 5186ef36909c 基线,perf bench sched pipe -l 1000000,20 轮):
- default:均值 3.985 -> 3.187 usec/op(约 20% 提升),中位数 4.026 -> 3.181(约 21%)
- taskset -c 78,79:均值约 18.4%、中位数约 17.4% 提升
- taskset -c 79:均值慢约 1.9%、中位数慢约 2.1%(单 CPU,噪声范围)
- hackbench 1/2/4/8 组 process/thread pipe 在 -1.8% 至 +3.7% 噪声内;schbench 8/40/80/240 normal 与 1/2/4/8 pipe 无显著退化
类比
把 CPU 想象成办公桌,pipe ping-pong 是 A 与 B 不断来回传纸条:
- 旧流程:办公室主任(
wake_affine)说"给离 B 最近的桌子",紧接着前台(select_idle_sibling)看到有更空的桌子,又把 B 挪过去。每次换桌都要重摆文具、重认路、cache 冷启动。 - 新流程:前台先确认"这张桌子确实只剩 A 在用"且没有 SMT 双胞胎时,才把 B 固定在 A 桌边。SMT 系统相当于同桌两人,原规则继续由前台找空位处理。
另一个类比:WF_SYNC 像接力赛传棒,下一棒的人贴着接棒人起跑比跑到下一条空闲赛道更快。新 patch 只在确认是一对一的接力(A <-> B)且非 SMT 时才强制贴棒。
Highlight:风险与注意点
- WF_SYNC 语义模糊:Prateek 指出
anon_pipe_read()用wake_up_interruptible_sync_poll()唤醒写者,但读者拿到数据后未必立刻阻塞;networking 代码也各处乱用,导致依赖 waker/wakee 是否同节点、wake_wide()结果产生不一致延迟/吞吐。 - 文档化优先于局部 fix:Shrikanth 主张先在
Documentation/scheduler/把 WF_SYNC 语义写清楚(hint-only vs waker-only-task 强制),否则"一个 benchmark 受益、一个受损"的循环不会停。 - SMT 路径被刻意跳过:v3/v4 把优化限制在
!sched_smt_active()。Shrikanth 质疑 SMT 是否真有本质差异——若 SMT 上也跑 pipe ping-pong,问题应同样存在。 - 版本节奏过快:Shrikanth 批评 v3 回复未到即发 v4,且 v4 没有解决 v3 的核心问题(语义文档化、SMT 路径、基准覆盖面)。
- 单 CPU 略退化:
taskset -c 79出现约 2% 退化,虽属噪声,但提示 patch 在某些场景下并非单调更优。 - 基准覆盖面窄:只跑 pipe/hackbench/schbench,未覆盖 messaging。Prateek 提议跑
perf bench sched messaging(threads + pipes)以验证 SMT 与多 LLC 场景。 - 维护者态度:Peter、Ingo、Vincent、Mel 等被点名叫来表态——本 thread 的关键瓶颈不是 patch 本身,而是上层 WF_SYNC 语义未定。
版本变化
- v4 -> v3
- 仅在 wake-affine 路径已选/保留 waker CPU 时才偏好 waker CPU
- 明确 WF_SYNC 仍是 hint,不是通用 placement 规则
- SMT 系统保留走
select_idle_sibling() - 基于 tip:sched/core 重测
- v3 -> v2
- 把"非 SMT 偏好 waker CPU"限制在
!sched_smt_active() - 去掉冗余 affinity 检查(
want_affine已检查) - 用普通
p->last_wakee读取代READ_ONCE() - 在 v7.2-rc5 基础上 rebase
- 把"非 SMT 偏好 waker CPU"限制在
- v2 -> v1
- 把互反 handoff 偏好移到现有
SD_WAKE_AFFINE域检查下 - 从 changelog 动机里去掉 futex
- rebase 后刷新 pipe 性能数据
- 把互反 handoff 偏好移到现有
一句话总结
v4 在非 SMT 系统的窄互反 WF_SYNC 唤醒中保留 waker CPU、绕过 idle-sibling 搜索;维护者更关心的是 WF_SYNC 整体语义未定,应先在 Documentation/scheduler/ 文档化再谈局部优化。