0/3 已展开

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.cis_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 或后续邮件补完。
  • 待跟进
    1. v2 是否改为纯 rename(如 core_has_no_busy_siblings),把行为改动彻底分离;
    2. 若坚持改行为,需要在 powerpc / x86 hybrid / arm64 big.LITTLE 上做 newidle 微基准;
    3. dst_core_idle 是否另开 patch 并提供实测数据。

一句话总结

一个声称"修语义"的清理 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