sched discussion
[PATCH] sched/fair: Make is_core_idle() check all cpus in a core
LLM 分析
sched/fair: is_core_idle() 是否应该按"整核"语义
系列概况
- 标题: [PATCH] sched/fair: Make is_core_idle() check all cpus in a core
- 作者: Mete Durlu meted@linux.ibm.com
- 版本: v1(单 patch,无 series)
- 规模: 1 file, +0/-3
- 修改文件:
kernel/sched/fair.c - 代码统计: 删除 3 行
- Message-ID:
20260806-fix_is_core_idle-v1-1-605119e55b25@linux.ibm.com - 完整性: 完整,含 commit message、diff、Signed-off-by、base-commit (
8ba098e6b6ff...)、change-id
补丁目的
is_core_idle() 名字与行为不一致:函数名暗示"整核是否空闲",但实现里有一段
if (cpu == sibling) continue;,让循环跳过传入 CPU 自身,只看兄弟线程。
作者想通过删除这个 skip,把函数语义统一成"包括传入 CPU 在内的整核都 idle 才返回 true"。
旧流程的问题
旧实现:
int sibling;
for_each_cpu(sibling, cpu_smt_mask(cpu)) {
if (cpu == sibling)
continue;
if (!idle_cpu(sibling))
return false;
}
问题点:
- 函数名承诺"core idle",实际只回答"other siblings are idle"。
- 最初由
ff7db0bf24db("sched/numa: Prefer using an idle CPU as a migration target") 引入时,调用方先idle_cpu(cpu),skip 是合理优化。 - 后续
8b36d07f1d63("sched/fair: Move is_core_idle() out of CONFIG_NUMA") 把它移出 NUMA,新调用者不一定先做idle_cpu(),于是"看着像整核、其实是兄弟"成为隐患。
新流程
直接去掉 skip:
int sibling;
for_each_cpu(sibling, cpu_smt_mask(cpu)) {
if (!idle_cpu(sibling))
return false;
}
关键实现
改动集中在 kernel/sched/fair.c 的 is_core_idle() 函数体(约 2162 行),纯减法 3 行。
其他逻辑未动,所有调用点保持不变,行为差异完全由 idle_cpu(this_cpu) 这一新增的真假决定。
类比
把 is_core_idle() 想象成酒店"整层是否可入住"的查询。旧实现相当于前台只问"5 楼以外的房间空不空",却把结果标成"整层可住"。Zhan 的反驳相当于指出:有时候来问的人正是 5 楼那个正在退房的客人,他当下当然还没正式走人(idle_cpu(this_cpu)==false),但 5 楼很快就会空;把他挡掉会让 5 楼永远显示为"已占"。
Highlight:风险与注意点
- 真正的回归路径:
sched_balance_newidle()->sched_balance_rq(this_cpu, this_rq, sd, CPU_NEWLY_IDLE, ...),env->dst_cpu == this_cpu,且当前还卡在__schedule()里,rq->curr是 outgoing task。idle_cpu(this_cpu)必然 false。 - 下游两个副作用:
env->dst_core_idle被算成 false,update_sd_pick_busiest()的 misfit 闸门不再拉任务;sched_use_asym_prio()因此返回 false,整套 asym packing 失效。
- s390 看不出来:
SD_ASYM_PACKING只在 powerpc / x86 ITMT 启用,SD_ASYM_CPUCAPACITY只在 arm64 big.LITTLE 与 x86 hybrid 启用。回归只能在这两类架构的 newidle 路径上复现,s390 跑 stress-ng / hackbench 几乎打不到这条路径。 - 冗余但无害的调用方:
numa_idle_core()、select_idle_capacity()、asym_fits_cpu()、should_we_balance()都先做idle_cpu(cpu),patch 在它们身上只是多了一次idle_cpu()(wakeup 路径上每个候选多两次)。 - 争议焦点:Zhan 主张"既然问题是名字,那只重命名就好"。
asym_fits_cpu()内部已经描述成 "core has no busy siblings";sched_use_asym_prio()的 kernel-doc 本来就把@cpu的 idleness 当作 caller precondition。改名风险远低于改行为。 - 作者回复被截断:第三封邮件正文在
numbers from处截断,似乎要承认dst_core_idle整核语义可作独立 patch,但需等待 v2 或后续邮件补完。 - 待跟进:
- v2 是否改为纯 rename(如
core_has_no_busy_siblings),把行为改动彻底分离; - 若坚持改行为,需要在 powerpc / x86 hybrid / arm64 big.LITTLE 上做 newidle 微基准;
dst_core_idle是否另开 patch 并提供实测数据。
- v2 是否改为纯 rename(如
一句话总结
一个声称"修语义"的清理 patch 被 review 指出会让 sched_balance_newidle() 在 powerpc / x86 / arm64 hybrid 上丢掉 asym packing 与 misfit 拉任务,争论落点是"改名字"还是"改行为"——前者更稳。
+-----------------+ +-----------------------+
| caller | ---> | is_core_idle(cpu) |
+-----------------+ +-----------------------+
|
| before patch:
| skip when sibling == cpu
| => "others idle" only
|
| after patch:
| no skip
| => idle_cpu(cpu) included
v
+--------------+
| return value |
+--------------+
|
+---------------------+---------------------+
| | |
v v v
sched_balance_newidle asym_fits_cpu numa_idle_core
this_cpu itself idle_cpu(cpu) first idle_cpu(cpu) first
=> false (NEW) => redundant check => redundant check
=> misfit gate off wakeup path: +2 benign
=> asym packing off
ASYM topology flags:
SD_ASYM_PACKING -> powerpc, x86 ITMT
SD_ASYM_CPUCAPACITY -> arm64 big.LITTLE, x86 hybrid
s390: none of these -> benchmark cannot show the regression