0/7 已展开

LLM 分析

sched/fair:NOHZ 平衡优先选择完全空闲的核心

系列概况

  • 标题: [PATCH] sched/fair: Prefer fully idle cores for NOHZ balancing
  • 作者: Andrea Righi (NVIDIA)
  • 版本: v1(单 patch)
  • 规模: 1 file changed, 18 insertions(+), 5 deletions(-)
  • 修改文件: kernel/sched/fair.c
  • 代码统计: 净增约 13 行;修改集中在 find_new_ilb()
  • Message-ID: 20260728214442.1648483-1-arighi@nvidia.com
  • 完整性: 邮件 body 内嵌完整 diff(含 commit message),可直接解析

补丁目的

让 NOHZ idle load balancer (ILB) 在挑选运行 CPU 时,优先选中"整核空闲"的 SMT 兄弟,而不是先把正在忙的 SMT 核心上那个空闲兄弟唤醒。在 NVIDIA Vera 的 Olympus SMT 核心上,反复短促地唤醒已经 WFI 的兄弟线程会让"单线程性能恢复"延后到资格窗口结束(实测约 10 Ki cycles)才完成,导致持续干扰并显著拉低 CPU 密集型负载吞吐。补丁正文给出基线:在 ad-hoc GEMM benchmark 上每 SMT 核一个 CPU 密集任务时,性能从约 6.2 TFLOP/s 提升到 9.4 TFLOP/s。

旧流程的问题

find_new_ilb() 只在 housekeeping mask 上找"第一个 idle CPU",完全没考虑该 CPU 所在 SMT core 的兄弟是否也在跑:

for_each_cpu_and(ilb_cpu, nohz.idle_cpus_mask, hk_mask) {
    if (idle_cpu(ilb_cpu))
        return ilb_cpu;
}

后果有三:

  1. 即使系统存在完全空闲的物理核,ILB 也可能挑中半忙核上的空闲兄弟。
  2. 一旦在该兄弟上短促跑 ILB,会打断兄弟线程从 WFI 恢复后的性能资格窗口。
  3. 在 SMT-4/SMT-8 拓扑上,重复短促唤醒会让兄弟长期处于降频状态。

新流程

引入 fallback 机制:第一次扫到"整核空闲"的 ILB 候选就直接返回;否则记下第一个"半忙核空闲 CPU"做 fallback,确保没有完全空闲核时仍能让 NOHZ 平衡前进。

   +------------------------------------------------------+
   | find_new_ilb()                                       |
   |   fallback = -1                                      |
   |   for ilb_cpu in (nohz.idle_cpus_mask & hk_mask):    |
   |     if (ilb_cpu == this_cpu)  --> continue           |
   |     if (!idle_cpu(ilb_cpu))   --> continue           |
   |     if (!SMT || is_core_idle(ilb_cpu))              |
   |         --> return ilb_cpu                           |
   |     if (fallback < 0)                                |
   |         --> fallback = ilb_cpu                       |
   |   return fallback                                    |
   +------------------------------------------------------+

   Decision flow per candidate:
   +-------------+   +----------------+   +-----------------+
   | ilb_cpu ==  |   | idle_cpu() ==  |   | is_core_idle()  |
   | this_cpu?   |--> | false ?        |--> | true  ?         |
   +-------------+   +----------------+   +-----------------+
        | skip            | skip              | yes | no
        v                 v                   v     v
     continue          continue         return     set fallback
                                          ilb_cpu

非 SMT 系统的行为完全不变:!sched_smt_active() 为真时直接选中第一个 idle CPU,与旧版本等价。

Patch 概览

仅修改 kernel/sched/fair.c::find_new_ilb()

static inline int find_new_ilb(void)
{
    int this_cpu = smp_processor_id();
    const struct cpumask *hk_mask;
    int ilb_cpu, fallback = -1;

    hk_mask = housekeeping_cpumask(HK_TYPE_KERNEL_NOISE);

    for_each_cpu_and(ilb_cpu, nohz.idle_cpus_mask, hk_mask) {
        if (ilb_cpu == this_cpu)
            continue;

        if (!idle_cpu(ilb_cpu))
            continue;

        /*
         * Running the idle load balancer on an idle sibling of a busy
         * SMT core can reduce the capacity available to its sibling. Prefer
         * a CPU whose entire core is idle, but retain the first idle CPU as
         * a fallback so idle balancing can still make progress when no fully
         * idle core exists.
         */
        if (!sched_smt_active() || is_core_idle(ilb_cpu))
            return ilb_cpu;

        if (fallback < 0)
            fallback = ilb_cpu;
    }

    return fallback;
}

关键实现

  1. is_core_idle(ilb_cpu) 遍历 SMT 兄弟判断是否整核空闲;非 SMT 系统被 !sched_smt_active() 短路,不付任何额外代价。
  2. fallback 路径保证向后兼容:极端低负载、整核都不空闲时仍能选出一个 ILB CPU,不破坏 NOHZ 平衡的节拍。
  3. 注释解释了为何不直接拒绝所有半忙核——避免让 NOHZ 平衡停止前进。
  4. 性能基线:Vera + Olympus 上 GEMM 由 6.2 TFLOP/s 提升到 9.4 TFLOP/s。

评审迭代中的实现细节

Prateek 指出两个会真正影响 v2 实现的点:

  • 避免重复 is_core_idle():当前 patch 在 SMT-4/SMT-8 上会对同一 SMT 核的多个兄弟分别调用 is_core_idle(),重复扫描开销在历史补丁 f8858d96061f 中已经处理过,建议仿照它"扫到半忙核的第一个空闲兄弟后立即停止本核扫描"。
  • mask 交集一次性算完:用 this_cpu_cpumask_var_ptr(select_rq_mask) 预先做 cpumask_and,避免循环里每次重复算 nohz.idle_cpus_mask & hk_mask;同时新增 lockdep_assert_irqs_disabled() 文档化"select_rq_mask 只能在 IRQ 关闭上下文使用"的前提。
  • select_rq_mask 改名/accessor:是否把它改成通用 IRQ-off 临时 mask 名或加 helper 是个独立的 scheduler cleanup,Peter Zijlstra 倾向"独立提交,不作为本 patch 的前置"。

Andrea 已在 v2 中接受 Prateek 的"短路兄弟扫描 + select_rq_mask 复用"思路,并在自己 Vera 平台验证性能不退化。

类比

把 SMT 核想成一间双人间宿舍,NOHZ ILB 是楼道里巡逻的保洁阿姨:

  • 旧逻辑:阿姨一推门就进最近那间"有一个人空着床位"的宿舍,把这位睡着的同学拍醒扫地。
  • 新逻辑:阿姨先扫一眼整间宿舍,两个床位都空就直接进这间;只有两个床位都有动静时,才记下"实在没人住"的房间做备案。
  • 关键比喻:Olympus 这种"被叫醒就要 10 Ki cycles 才回到峰值"的房间里,反复叫醒会让那位同学长期处于迷糊状态,所以一定要优先选完全空着的房间。

Highlight:风险与注意点

  1. 多次 is_core_idle() 扫描:在 SMT-4/SMT-8 上若不主动跳过同一核的兄弟,会反复遍历同一 SMT 核;f8858d96061f 是历史先例,建议像 Andrea 已经在 v2 中那样"扫到本核第一个空闲兄弟就停"。
  2. select_rq_mask 重用前提:该变量只在 IRQ 关闭上下文被复用,新代码应加 lockdep_assert_irqs_disabled() 文档化约束;命名/accessor helper 是独立 cleanup,不应阻塞本 patch 上游。
  3. ILB 延迟与能耗上升:偏好整核空闲可能跨更多 CPU 才选定,导致唤醒延迟或能耗增加;对非 Vera 平台需要重新评估收益是否大于代价——当前没有跨架构评测数据。
  4. fallback 触发条件不明:补丁正文没有量化"无整核空闲"场景下的吞吐回归,需要确认常见负载分布下 NOHZ 平衡节拍仍能维持。
  5. SMT 拓扑假设:补丁隐含假设 is_core_idle() 的开销小于唤醒半忙兄弟的开销;这条假设在 AMD/IBM 拓扑上是否成立尚无验证,Shrikanth 也提示在他的经验里开销"不太可见",需要更多平台数据。

一句话总结

让 NOHZ ILB 优先挑选整核空闲的 CPU,必要时刻降级到半忙核空闲兄弟,避免反复短促唤醒 Vera Olympus 上代价高昂的 SMT 兄弟线程。