sched discussion
[PATCH v6 0/5 RESEND] sched/fair: SMT-aware asymmetric CPU capacity
LLM 分析
sched/fair:让非对称 CPU容量调度真正理解 SMT 共享核心
系列概况
- 标题:
[PATCH v6 0/5 RESEND] sched/fair: SMT-aware asymmetric CPU capacity - 作者:Andrea Righi(NVIDIA);K Prateek Nayak(AMD)共同开发 Patch 2、5
- 版本:v6 RESEND;线程中另有 Patch 2 v2、Patch 3 v2独立修订
- 规模:5 个补丁
- 修改文件:
kernel/sched/fair.c、kernel/sched/sched.h、kernel/sched/topology.c - 代码统计:+248 / −55
- Message-ID:
20260509180955.1840064-1-arighi@nvidia.com - 完整性:含封面、全 5 个 patch、评审与修订、tip 合入通知,以及后续 CPU hotplug warning 与
sched_domain_sharedkmemleak;部分邮件正文被截断,末尾三封为空
补丁目的
SD_ASYM_CPUCAPACITY 默认按逻辑 CPU 的静态 capacity_of() 做放置。在 SMT 系统上,逻辑 CPU 空闲且静态容量较高时,若 sibling 正运行,二者争用执行资源,实际可用算力远低于标称值。
系列把“完整空闲 SMT core 优先”这条原则同时应用到唤醒路径和周期负载均衡:
- 唤醒 idle scan 优先完整空闲 core,而非只有一个 thread 空闲的 busy core。
- 拒绝把 misfit task 拉到 busy sibling 所在 core。
- 让
has_idle_coreshint 覆盖 asym-capacity scan 的实际 domain 范围。 - 为
select_idle_capacity()加上SIS_UTIL扫描预算。
Vera Rubin 固件报告约 +/-5% 容量差触发 SD_ASYM_CPUCAPACITY;原策略在 CPU 密集负载下可下降约 2 倍。NVBLAS 从主线 ASYM ~5478 GFLOPS 提升到 ASYM+SMT ~9259 GFLOPS;MediaWiki 全 CPU 测试吞吐变化小但尾延迟改善。Grace(非 SMT)测试未见回归。
旧流程的问题
唤醒路径主要问“逻辑 CPU 空闲 + 静态 capacity 够”,不问“所在物理 core 是否完整空闲”:
Task wakes
|
v
select_idle_capacity()
|
+-- idle logical CPU?
+-- capacity_of(cpu) fits?
|
v
choose CPU, even if SMT sibling is busy
三类问题:
- 容量失真:
capacity_of()不能体现 sibling 忙碌造成的资源争用。 - hint 范围不一致:扫描在
sd_asym_cpucapacity,但has_idle_cores原在sd_llc->shared。 - 错误迁移预期:负载均衡可能把 misfit 拉到 sibling 正忙的目的 CPU,迁移后并未真正升级容量。
新流程
先区分完整空闲 core 与部分空闲 core,再按静态容量适配排序:
Waking task / misfit task
|
v
SMT active?
/ \
no yes
| |
plain destination core fully idle?
scan / \
yes no
| |
highest rank; lower rank;
allow misfit pull reject misfit pull
rank 由好到差:完整空闲 core + 完全 fit(早期返回)→ 完整空闲 core + uclamp miss(−4)→ 完整空闲 core + 容量 miss(−3)→ busy sibling + fit(−2)→ busy sibling + uclamp miss(−1)→ busy sibling + 容量 miss(0)。
关键取舍:静态容量略有 misfit 的完整空闲 core,优先于静态完全 fit 的 busy sibling CPU;SMT 资源争用造成的有效容量损失被认为大于在安静 core 上的小幅 misfit。
Patch 概览
Patch 1:清理 NOHZ 路径冗余 RCU 锁
删除 nohz_balancer_kick()、set_cpu_sd_state_idle/busy 的显式 rcu_read_lock/unlock,改 flags |= 与统一 goto out;依赖 IRQ-off、cpus_write_lock 或 rcu_dereference_all。声称无功能变化,但 Marek Szyprowski 在 linux-next 上跑 CPU hotplug 测试时发现 warning。
Patch 2:把 sched_domain_shared 关联到 sd_asym_cpucapacity
sd_llc_shared 重命名为 sd_balance_shared。对拥有非重叠 SD_ASYM_CPUCAPACITY_FULL 祖先的 CPU,把 sched_domain_shared 关联到该 asym domain,让 has_idle_cores 范围与 select_idle_capacity 扫描一致。对称系统、exclusive cpuset 对称岛和重叠 NUMA domain 仍回退到 LLC。
Patch 3:唤醒时优先完整空闲 SMT core
select_idle_capacity 引入分层 rank,通过 ASYM_IDLE_CORE_BIAS 把完整空闲 core 候选映射到更高优先层。asym_fits_cpu 也加 is_core_idle 条件,使 target/prev/recent_used_cpu 等快速候选不能仅凭“逻辑空闲 + fit”提前胜出。v2 按 Vincent 建议删掉 rank 名里误导的 CORE_ 前缀。
Patch 4:拒绝 misfit 拉到 busy SMT sibling
lb_env 缓存 dst_core_idle;update_sd_pick_busiest 在 SD_ASYM_CPUCAPACITY + misfit 源组 + 目的 core 非完整空闲时拒绝拉取,避免“为了升级容量却搬到共享资源已被占用”的迁移。
Patch 5:为 select_idle_capacity 加 SIS_UTIL
复用 select_idle_cpu 的 nr_idle_scan 预算:SIS_UTIL 启用且 sd->shared 存在时获取扫描上限,预算耗尽返回当前最佳候选;has_idle_core 为真时不提前截断。v6 把特殊 rank guard 去掉,与 select_idle_cpu 对齐。
关键实现
共享对象的 domain 范围
理想结构是数据服务于相同范围:
Asym-capacity scan span
+----------------------------------------+
| sd_asym_cpucapacity |
| select_idle_capacity() |
| has_idle_cores / nr_idle_scan |
+----------------------------------------+
LLC / cache statistics span
+--------------------------------+
| sd_llc |
| cache-aware statistics |
| nr_busy_cpus |
+--------------------------------+
但两个 domain 可能共享同一个 cpumask_first(span)。合并方案引入 alloc_flags union 让每个 sched_domain 各自 claim 一份 shared 对象,若首 CPU 对应对象已被另一 domain 使用就找下一个 CPU。Prateek 又发现若同一 domain 同时具备 SD_SHARE_LLC 与 SD_ASYM_CPUCAPACITY_FULL,二次 init_sched_domain_shared 会覆盖已有 sd->shared,建议在 sd->shared 已存在时直接返回。
hint 只是提示,不是真值
has_idle_cores 可能短暂过时;代码必须允许 hint 说有空闲 core 但扫描未找到、sd->shared 为空时退化为普通 capacity scan、未启用 SMT 时新增逻辑折叠为旧行为。
与其他系列的关联
直接与 cache-aware load balancing / CONFIG_SCHED_CACHE 相交。cache-aware 调度要求保留 LLC 范围共享统计,而本系列又需要 asym 范围 idle-core hint,不能简单“搬走”一份 shared,必须支持多层级分别持有对象。后续还暴露 CPU hotplug warning(Patch 1)与 sched_domain_shared kmemleak(cpuset rebuild + ASYM + SCHED_CACHE),说明 topology 生命周期仍待修。
类比
把每个 SMT core 想成共用一套灶台的厨房,两个逻辑 CPU 是共享灶台的两名厨师。旧调度器只看厨师名牌的“最高出餐能力”,看到第二名厨师空闲便认为整套标称能力都可用;但第一名若正用灶台,第二名实际达不到名牌速度。
新策略先找一间完全空的厨房;即使设备标称稍慢,也常比“名义更快、但灶台已被占用”的厨房更快完成订单。has_idle_cores 像大厅的“有空厨房”指示灯,必须覆盖服务员实际搜索的整层楼。
Highlight:风险与注意点
- 完整空闲 core 的绝对优先级是策略假设:rank 让静态 misfit 的空闲 core 胜过静态 fit 的 busy sibling CPU;需在不同 SMT 架构与 uclamp 场景继续验证。
- 性能数据主要来自 Vera Rubin,不能直接推导所有非对称 SMT 平台同等待遇。
- 高占用率下收益缩小;MediaWiki 数据主要改善在尾延迟。
- hint 与扫描 domain 必须同范围(Patch 2 核心),但把对象从 LLC 挪走会破坏
SCHED_CACHE需求。 - 共享对象不能仅按首 CPU 唯一标识,否则
nr_idle_scan会被不同 domain 别名覆盖。 - 同一 domain 双重 flag 要去重,否则
sd->shared被覆盖造成悬空引用。 - Patch 1 声称无功能变化,但 CPU hotplug 测试报 warning;必须重审完整调用图与 RCU 语义。
- 已观察到 kmemleak:cpuset rebuild + ASYM + SCHED_CACHE 组合下
sched_domain_shared泄漏。 - 输入末尾三封邮件正文为空,不能据此判断 kmemleak 修复已合入。
版本变化
- v1 → v2:重做
select_idle_capacity的 SMT-aware 逻辑;暂删 EAS 与find_new_ilb改动。 - v2 → v3:加 SIS_UTIL;把
sched_domain_shared关联到sd_asym_cpucapacity;引入 fit-state enum;更新has_idle_coreshint。 - v3 → v4:
sd_llc_shared → sd_balance_shared;加 sched-domain RCU guard 清理;SIS_UTIL cap 仅在非偏好完整空闲 core 时应用;缓存目的 CPU core-idle。 - v4 → v5:删除 NOHZ 路径冗余 RCU 保护;保留 CPU capacity asymmetry/SMT warning。
- v5 → v6:简化 SIS_UTIL 提前退出,与
select_idle_cpu对齐;把重命名移入 Patch 2;prefers_idle_core → has_idle_core;完善 rank 表注释;因缺 Subject 而 RESEND。 - 线程内修订:Patch 3 v2 删 rank 名
CORE_前缀;Patch 2 v2 修旧sd_llc->shared->has_idle_cores注释;与sched/cache合并后演化为多 domain claim。
一句话总结
把“逻辑 CPU 标称容量”修正为“物理 SMT core 当前真正可用容量”,在 Vera Rubin 上显著改善任务放置,但后续暴露的 shared 对象别名、CPU hotplug warning 与 kmemleak 说明 topology 生命周期比调度排名本身更容易出错。