0/1 已展开

LLM 分析

sched: 在重排队 delayed entity 前更新当前时间

系列概况

  • 标题[tip: sched/core] sched: Update time before requeueing delayed entities
  • 作者:Vincent Guittot <vincent.guittot@linaro.org>
  • 提交者:Peter Zijlstra (Intel) <peterz@infradead.org>
  • 版本:tip-bot2 自动通告的已合并 commit,无独立版本号(单 patch)
  • 规模:1 个文件,+2 行(1 file changed, 2 insertions(+)
  • 修改文件kernel/sched/fair.c,仅改动 requeue_delayed_entity() 函数
  • 代码统计kernel/sched/fair.c | 2 ++
  • Message-ID178673615898.442315.12755541915005920303.tip-bot2@tip-bot2
  • 完整性:tip-bot2 merge notice,正文含 GitWeb commit 链接、commit message 全文与 hunk 上下文,可独立理解;唯一一封邮件,无系列回复

补丁目的

CFS 调度器在 requeue_delayed_entity() 中把"被延迟出队"的任务(标记 sched_delayed 的 SLEEPING 任务)重新挂回 runqueue 时,需要先计算它累积的 lag(应运行时间减去实际运行时间),再据此补偿 vruntime。

update_entity_lag() 内部依赖 rq 上的"当前时间"(cfs_rq->clock_task 等)来计算两次统计窗口之间的差值。如果不先 update_curr(cfs_rq) 把时间推到 now,runqueue 的 clock_task 可能仍是上次记账时的旧值,差值被压缩,lag 偏小,delayed 任务被少补偿。

这是一个隐性公平性 bug:delayed entity 在 wake-up 重排队时被少算了等待补偿。

旧流程的问题

requeue_delayed_entity(se)
   |
   +-> update_entity_lag(cfs_rq, se)
   |
   +-> dequeue / requeue decision

clock_task 若仍是陈旧值,差值被压缩,lag 偏小,delayed 任务拿不到足额 vruntime 补偿,调度公平性下降。

新流程

requeue_delayed_entity(se)
   |
   +-> update_curr(cfs_rq)               [NEW line]
   |
   +-> update_entity_lag(cfs_rq, se)
   |
   +-> dequeue / requeue decision

只多一行 update_curr(cfs_rq),但保证 lag 计算使用的是 now 而非陈旧快照。

关键实现

补丁只动了 kernel/sched/fair.crequeue_delayed_entity()

requeue_delayed_entity(struct sched_entity *se)
{
       struct cfs_rq *cfs_rq = cfs_rq_of(se);
       struct sched_entity *curr = cfs_rq->curr;

       update_curr(cfs_rq);              /* NEW line */

       WARN_ON_ONCE(!se->sched_delayed);
       WARN_ON_ONCE(!se->on_rq);
       if (update_entity_lag(cfs_rq, se)) {
               cfs_rq->nr_queued--;
               if (se != cfs_rq->curr)
                       ...
       }
}

update_curr() 刷新 cfs_rq->clock_taskcfs_rq->clockcurr->exec_start 等基于 now 的统计点;后续 update_entity_lag() 读到的是真实当前时间。

类比

把 delayed entity 想象成自习课中途离开教室 10 分钟的学生。学生回到座位(requeue)时,老师要补录他落下多少分钟笔记(lag)。

如果老师不抬头看墙上的钟,凭印象写"大概只落下 3 分钟",那他实际落下的 10 分钟就丢了。update_curr(cfs_rq) 就是老师先看一眼钟、把"现在几点"校准,再算学生落下多少。

也可以从会计角度:CFS 的 clock_task 是 runqueue 的"会计时钟",任务执行 / 睡眠 / 被延迟出队期间它都可能没被推进;跨时段 lag 结算前必须先把会计时钟对齐到 wall clock now,否则就是用上周的报表算这个月的工资。

Highlight:风险与注意点

  • 影响范围:所有使用 delayed dequeue 机制的 CFS 任务(典型为短 sleep 后被 wake-up 的 event-driven worker、kernel thread),都会从此补丁获益。
  • 回归风险update_curr() 会顺带刷新 curr->exec_start 等统计;如果有别的路径依赖"requeue_delayed_entity 调用前 clock_task 仍是旧值",行为可能出现细微差异,需要 scheduler latency / fairness 基准回归。
  • 可观察点:在未打补丁内核上,可用 perf trace update_entity_lag 返回值,观察 delayed 任务 wake-up 时 lag 是否显著偏小。
  • 后续观察:Vincent Guittot 持续重构 CFS dequeue / requeue 与 delayed entity 路径,未来可能还有更多"先 update_curr 再算 lag"的同类清理。

一句话总结

CFS 在重排 delayed entity 前先 update_curr(),确保 update_entity_lag() 读到当前时间,修正 delayed 任务因 lag 偏小而被少补偿的公平性 bug。