0/2 已展开

LLM 分析

sched/numa:修复候选节点距离计算使用陈旧 dst_nid 的 bug

系列概况

  • 标题: [PATCH] sched/numa: fix stale dst_nid used in distance calculation for candidate nodes
  • 作者: Li RongQing lirongqing@baidu.com
  • 版本: v1(单 patch,邮件未带版本号)
  • 规模: 1 file changed, 1 insertion(+), 1 deletion(-)
  • 修改文件: kernel/sched/fair.c(函数 task_numa_migrate)
  • 代码统计: +1/-1
  • Message-ID: 20260714092110.1722-1-lirongqing@baidu.com
  • 完整性: thread 含 1 个 patch + 1 个作者自我 ping 回复,没有 maintainer 公开 review

补丁目的

修正 task_numa_migrate() 在遍历候选 NUMA 节点时,dist 没有用当前候选节点 nid 重新计算,而是复用了上一次迭代留下的 env.dst_nid。结果下游 task_weight() 评分建立在陈旧距离上,NUMA balancing 决策可能把 task 留在次优节点。

旧流程的问题

旧代码:

dist = node_distance(env.src_nid, env.dst_nid);

env.dst_nid 在循环开头是 preferred nid(或上一次迭代选出的最优 nid),被错当成"输入距离参数"使用。每个候选 nid 都被同一个距离打分,违反"为每个候选单独评分"的语义。

新流程

dist = node_distance(env.src_nid, nid);

每轮循环都用当前候选节点 nid 取真实距离,下游 task_weight()if (dist != env.dist) 的比较都基于正确数值。

Patch 概览

  • 文件:kernel/sched/fair.c,函数 task_numa_migrate()
  • 单 hunk 单行修改:
-       dist = node_distance(env.src_nid, env.dst_nid);
+       dist = node_distance(env.src_nid, nid);

关键实现

上下文(行 3319 附近):

for_each candidate nid {
    if (nid == env.src_nid || nid == p->numa_preferred_nid)
        continue;

    dist = node_distance(env.src_nid, nid);   /* 修复点 */

    if (sched_numa_topology_type == NUMA_BACKPLANE &&
        dist != env.dist) {
        taskweight = task_weight(p, env.src_nid, dist);
        ...
    }
    /* 循环末尾把最优 nid 写回 env.dst_nid(仅作输出) */
}

env.dst_nid 在下游被赋值为本次迭代的最优 nid,本应只承担"输出"职责;旧实现却把它当作输入距离参数复用,混用导致 bug。

变量身份示意:

            +----------------------+
  loop in -->| candidate nid (var) |---+
            +----------------------+   |
                                       v
   env.dst_nid  <-----  writes best nid (output slot)
        ^
        |
        +-- old code wrongly reads it as input distance
        +-- new code no longer uses env.dst_nid for distance

控制流:

task_numa_migrate(p)
  |
  +-- init env (src_nid, dst_nid=preferred, ...)
  |
  +-- for each candidate nid:
  |     |
  |     +-- nid == src/preferred ? --> skip
  |     |
  |     +-- dist = node_distance(src_nid, nid)   <-- fix
  |     |     (old: src_nid, env.dst_nid)
  |     |
  |     +-- BACKPLANE && dist != env.dist ?
  |     |     taskweight = task_weight(p, src_nid, dist)
  |     |
  |     +-- pick best nid -> env.dst_nid (may stay stale)
  |
  +-- choose final dst and migrate

类比

  • 像外卖调度员在几家候选餐厅中选一家下单:旧逻辑下,每看一家新店,他都还在念叨"上一家店离我 5 km",结果所有候选都按 5 km 评分,越选越离谱。新逻辑每看一家都用"这家店离我 X km"打分,决策才靠谱。
  • 或者像超市比价,每拿起一件商品都该看自己的价签,而不是抄第一件商品的价格当所有商品的价格。

Highlight:风险与注意点

  1. env.dst_nid 同时承担"输入距离参数"与"本次最优 nid 输出槽"两重角色,是经典的"可变变量被复用"陷阱;下游若有代码再读 env.dst_nid 做距离相关比较,需要复查是否再次踩坑。
  2. 触发条件:NUMA_BACKPLANE 拓扑或任何依赖 disttask_weight() 路径;影响 NUMA 自动平衡的迁移方向,长期可能让 task 停在次优节点。
  3. patch 没有附带回归测试或 perf 数据,修复收益难以量化;maintainer 通常会要求补充 before/after 指标或 workload 数据。
  4. 第二封只是作者自我 ping,无 reviewer 反馈,thread 当前处于无人评审状态,需要持续跟进 v2 或新回复。

版本变化

仅一版(v1),无后续版本演进。

一句话总结

一行修复让 task_numa_migrate() 用当前候选 nid 而不是陈旧的 env.dst_nid 计算距离,把 NUMA balancing 评分拉回正确轨道。