0/5 已展开

LLM 分析

sched/numa & sched/cache:把 task tick 从调度上下文搬到执行上下文

系列概况

  • 标题:[PATCH v3 0/2] sched: Fix execution-context tick handling under proxy execution
  • 作者:Hui Su sh_def@163.com
  • 版本:v3(cover letter 标注 v1 -> v2 -> v3 演进)
  • 规模:2 个 patch,3 个文件,+26/-9(cover letter 统计)
  • 修改文件:kernel/sched/core.c、kernel/sched/fair.c、kernel/sched/sched.h
  • 代码统计:26 insertions(+), 9 deletions(-)
  • Message-ID(cover):20260904085244.799276-1-sh_def@163.com
  • 完整性:thread 共 5 封邮件(1 封 cover + 2 个 patch 体 + 2 封回复),patch diff 可见,回复齐全

补丁目的

修复 proxy execution 引入的回归:当 fair 任务实际替 SCHED_FIFO/DEADLINE 的 donor 执行时,原本属于 fair 的 NUMA/cache tick 钩子被漏掉,导致 cache scan epoch 过期、preferred LLC 被误失效,NUMA 周期扫描也不再推进。

旧流程的问题

  • proxy execution 把 rq->donor(调度上下文)和 rq->curr(执行上下文)拆开。
  • sched_tick() 走的是 donor->sched_class->task_tick(rq, donor, 0),所以 task_tick_numa()task_tick_cache() 被困在 task_tick_fair() 内部。
  • 当 fair 任务替 RT/deadline donor 跑时,donor 不是 fair,task_tick_fair() 不会被触发,NUMA 与 cache 扫描都不前进。
  • account_mm_sched() 是按 rq->curr 累加运行时间的,runtime 在走、scan epoch 不走,cache 的 preferred LLC 因此过期被作废。
  • sched_tick_remote()(full-dynticks 远端 tick)按 curr 的调度类派发,本就不进入 fair 的 task_tick,行为同样缺失。

新流程

  • 新增 sched_tick_exec_ctx(rq) helper:只看 rq->curr,仅当 curr 是 fair 任务时执行 task_tick_numa()task_tick_cache()
  • sched_tick() 调完 donor->sched_class->task_tick() 之后再调一次 helper。
  • sched_tick_remote() 也调一次,保证远端 tick 路径行为一致。
  • task_tick_fair() 里保留 misfit、overutilized、core scheduling 等"调度上下文"记账,把执行上下文的 NUMA/cache 钩子拆出去。

Patch 概览

  • 1/2 sched/numa:把 task_tick_numastatic 改为外部可见、在 sched.h 暴露;core.csched_tick_exec_ctx()fair.ctask_tick_fair 不再直接调用 task_tick_numa
  • 2/2 sched/cache:同理处理 task_tick_cache,并在 fair.c 加注释说明 misfit/overutilized/core 仍归属调度上下文。

关键实现

static void sched_tick_exec_ctx(struct rq *rq)
{
    struct task_struct *curr = rq->curr;

    if (curr->sched_class != &fair_sched_class)
        return;

    if (static_branch_unlikely(&sched_numa_balancing))
        task_tick_numa(rq, curr);

    task_tick_cache(rq, curr);
}
  • 两个 patch 都把 fair.c 的两个 static 改成外部可见、声明加进 sched.h,由 core.c 统一调用。
  • sched_tick()sched_tick_remote() 都增加 sched_tick_exec_ctx(rq) 调用点,路径对称。
  • 不动 task_tick_core() 的消费时间片记账,作者明确留给另一条线索单独处理。

类比

把 CPU 想成一家公司:CEO(donor)把项目交给项目经理(curr)去执行。HR 做季度考核(NUMA tick)和项目复盘(cache tick)时,应该看的是"真正干活的项目经理",而不是发号施令的 CEO。旧流程只在 CEO 本身是 fair 出身时才考核,于是把代理执行漏掉了;新流程不管 CEO 是谁,只要干活的人是 fair 出身就考核。

+-------------------+   sched_tick()    +------------------------+
| HZ timer          | --donor->sched--> | task_tick_fair()       |
| (or remote tick)  |   class->task_tick| - misfit / overutilized|
|                   |   (rq, donor, 0)  | - core scheduling      |
+-------------------+                   +------------------------+
                                                |
                                                v
                                   +----------------------------+
                                   | sched_tick_exec_ctx(rq)    |
                                   |   if curr is fair:         |
                                   |     task_tick_numa(curr)   |
                                   |     task_tick_cache(curr)  |
                                   +----------------------------+

When rq->curr == rq->donor, both paths see the same task; when a
fair task executes on behalf of an RT/deadline donor, the helper
still fires for the fair curr, and the scheduling-class path keeps
handling the donor's bookkeeping.

Highlight:风险与注意点

  • task_tick_cache#ifdef CONFIG_NUMA_BALANCING 内外两条声明都要从 static 改出去,CONFIG 不开 NUMA 时容易漏改。
  • sched_tick()sched_tick_remote() 必须先按调度类派发、再调 helper;顺序错位会让公平记账错乱。
  • task_tick_core() 的 consumed-slice 在代理执行下仍有缺陷,作者已声明不在本次处理。
  • 验证矩阵要覆盖 SCHED_PROXY_EXEC=y x {NUMA, cache, both, none} 四种组合,并跑 CONFIG_NO_HZ_FULL=y 与全 dynticks,否则远端 tick 路径回归会漏掉。

版本变化

  • v2 -> v3:把 NUMA/cache 的执行上下文 tick 进一步抽到统一的 sched_tick_exec_ctx(),让 sched_tick()sched_tick_remote() 共用同一路径;NUMA 理由改写为"执行上下文状态 + mm/任务",sum_exec_runtime 退为辅助论据;新增注释解释 misfit/overutilized/core 仍归属调度上下文;task_tick_core() 消费时间片问题保持分离。
  • v1 -> v2:把执行上下文 tick 从 task_tick_fair() 挪到 sched_tick(),按 rq->curr 是否为 fair 调用,并补上 sched_tick_remote() 调用点。

一句话总结

把 NUMA/cache 的 task tick 从 task_tick_fair() 拆出,统一放进 sched_tick_exec_ctx(),让它们跟着真正执行的 fair 任务走,避免 fair 任务替 RT/DL donor 干活时被漏掉。