sched discussion
[PATCH v3 1/2] sched/numa: Drive NUMA task tick from execution context
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_numa由static改为外部可见、在sched.h暴露;core.c加sched_tick_exec_ctx();fair.c的task_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=yx {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 干活时被漏掉。