sched discussion
[PATCH] sched/fair: Prefer fully idle cores for NOHZ balancing
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;
}
后果有三:
- 即使系统存在完全空闲的物理核,ILB 也可能挑中半忙核上的空闲兄弟。
- 一旦在该兄弟上短促跑 ILB,会打断兄弟线程从 WFI 恢复后的性能资格窗口。
- 在 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;
}
关键实现
is_core_idle(ilb_cpu)遍历 SMT 兄弟判断是否整核空闲;非 SMT 系统被!sched_smt_active()短路,不付任何额外代价。fallback路径保证向后兼容:极端低负载、整核都不空闲时仍能选出一个 ILB CPU,不破坏 NOHZ 平衡的节拍。- 注释解释了为何不直接拒绝所有半忙核——避免让 NOHZ 平衡停止前进。
- 性能基线: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:风险与注意点
- 多次
is_core_idle()扫描:在 SMT-4/SMT-8 上若不主动跳过同一核的兄弟,会反复遍历同一 SMT 核;f8858d96061f 是历史先例,建议像 Andrea 已经在 v2 中那样"扫到本核第一个空闲兄弟就停"。 select_rq_mask重用前提:该变量只在 IRQ 关闭上下文被复用,新代码应加lockdep_assert_irqs_disabled()文档化约束;命名/accessor helper 是独立 cleanup,不应阻塞本 patch 上游。- ILB 延迟与能耗上升:偏好整核空闲可能跨更多 CPU 才选定,导致唤醒延迟或能耗增加;对非 Vera 平台需要重新评估收益是否大于代价——当前没有跨架构评测数据。
- fallback 触发条件不明:补丁正文没有量化"无整核空闲"场景下的吞吐回归,需要确认常见负载分布下 NOHZ 平衡节拍仍能维持。
- SMT 拓扑假设:补丁隐含假设
is_core_idle()的开销小于唤醒半忙兄弟的开销;这条假设在 AMD/IBM 拓扑上是否成立尚无验证,Shrikanth 也提示在他的经验里开销"不太可见",需要更多平台数据。
一句话总结
让 NOHZ ILB 优先挑选整核空闲的 CPU,必要时刻降级到半忙核空闲兄弟,避免反复短促唤醒 Vera Olympus 上代价高昂的 SMT 兄弟线程。