0/47 已展开

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.ckernel/sched/sched.hkernel/sched/topology.c
  • 代码统计:+248 / −55
  • Message-ID20260509180955.1840064-1-arighi@nvidia.com
  • 完整性:含封面、全 5 个 patch、评审与修订、tip 合入通知,以及后续 CPU hotplug warning 与 sched_domain_shared kmemleak;部分邮件正文被截断,末尾三封为空

补丁目的

SD_ASYM_CPUCAPACITY 默认按逻辑 CPU 的静态 capacity_of() 做放置。在 SMT 系统上,逻辑 CPU 空闲且静态容量较高时,若 sibling 正运行,二者争用执行资源,实际可用算力远低于标称值。

系列把“完整空闲 SMT core 优先”这条原则同时应用到唤醒路径和周期负载均衡:

  1. 唤醒 idle scan 优先完整空闲 core,而非只有一个 thread 空闲的 busy core。
  2. 拒绝把 misfit task 拉到 busy sibling 所在 core。
  3. has_idle_cores hint 覆盖 asym-capacity scan 的实际 domain 范围。
  4. 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_idleupdate_sd_pick_busiestSD_ASYM_CPUCAPACITY + misfit 源组 + 目的 core 非完整空闲时拒绝拉取,避免“为了升级容量却搬到共享资源已被占用”的迁移。

Patch 5:为 select_idle_capacity 加 SIS_UTIL

复用 select_idle_cpunr_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_LLCSD_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_cores hint。
  • 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 生命周期比调度排名本身更容易出错。