0/3 已展开

LLM 分析

sched/ext:有限时间片任务必须保持 scheduler tick

系列基线信息

  • 标题[PATCH sched_ext] sched/ext: Keep tick enabled for finite-slice tasks
  • 作者:Zhimin Feng(冯志敏)
  • 共同开发者:Chengming Zhou
  • 版本:未标注版本,可视为首版
  • 系列规模:单补丁
  • 改动规模:2 个文件,新增 29 行、删除 3 行
  • 涉及文件
    • kernel/sched/ext/ext.c
    • kernel/sched/sched.h
  • 首封 Message-ID20260716023746.3289089-1-fengzhimin@bytedance.com
  • 来源频道sched-ext
  • 讨论规模:3 封邮件
  • 关联链接:回复中指向 20260708074812.1041434-1-arighi@nvidia.com

明确目的

这个补丁修复 sched_extnohz_full CPU 上运行有限时间片任务时,scheduler tick 可能被错误关闭的问题。

有限时间片 SCX 任务依赖周期性 tick 扣减和检查 p->scx.slice。时间片耗尽后,调度器才能及时触发重新调度。如果 tick 停止,任务的时间片可能无法正常到期,从而破坏时间片轮转和调度前进性。

问题出现在 set_next_task_scx() 选择了下一个 SCX 任务、但 rq->curr 尚未切换到该任务的窗口:

  1. 下一个任务 p 使用有限时间片。
  2. set_next_task_scx() 调用旧的 sched_update_tick_dependency()
  3. 后者通过 sched_can_stop_tick() 检查 rq->curr
  4. 此时 rq->curr 仍可能是 idle、RT、CFS 或另一个允许停 tick 的旧任务。
  5. 调度器据此错误地保持或清除了 TICK_DEP_BIT_SCHED
  6. 新 SCX 任务开始运行后,CPU 可能仍然处于无 scheduler tick 状态。

补丁的核心原则是:是否需要 tick 应根据即将运行的任务 p 判断,而不能依赖尚未更新的 rq->curr

遍历代码

1. 计算下一个 SCX 任务能否停 tick

set_next_task_scx() 根据时间片是否无限来计算状态:

can_stop_tick = p->scx.slice == SCX_SLICE_INF;
tick_state_changed = can_stop_tick !=
        (bool)(rq->scx.flags & SCX_RQ_CAN_STOP_TICK);

语义如下:

  • p->scx.slice == SCX_SLICE_INF:任务没有有限时间片到期需求,可以允许停 tick。
  • p->scx.slice != SCX_SLICE_INF:任务必须依靠 tick 推进时间片,不能停 tick。
  • tick_state_changed:记录新任务的需求是否与 runqueue 当前缓存状态不同。

2. 更新 runqueue 的 SCX tick 状态

当状态发生变化时,补丁继续维护 SCX_RQ_CAN_STOP_TICK

if (tick_state_changed) {
        if (can_stop_tick)
                rq->scx.flags |= SCX_RQ_CAN_STOP_TICK;
        else
                rq->scx.flags &= ~SCX_RQ_CAN_STOP_TICK;
}

这个标志描述 SCX 当前选中任务是否允许关闭 scheduler tick。

补丁将“更新状态标志”和“设置实际 tick dependency”拆开,使后者可以明确根据下一个任务执行。

3. 有限时间片任务直接设置 tick dependency

对于有限时间片任务,新的逻辑不再通过 rq->curr 间接判断:

if (!can_stop_tick)
        sched_set_tick_dependency(rq);

这一步直接设置对应 CPU 的 TICK_DEP_BIT_SCHED,保证 scheduler tick 保持运行。

这里即使 SCX 标志没有发生变化,也会再次设置 dependency。这样可以避免实际 tick dependency 与 SCX 缓存状态因其他路径而不同步。

4. 无限时间片任务仍可恢复 tickless

当下一个任务使用 SCX_SLICE_INF,且状态确实发生变化时,代码才通过现有更新路径重新评估能否停 tick:

else if (tick_state_changed)
        sched_update_tick_dependency(rq);

因此补丁没有禁止 SCX 使用 tickless 模式:

  • 有限时间片:强制保留 tick。
  • 无限时间片:仍按系统整体条件决定是否可以停止 tick。

5. 在 scheduler 公共头文件增加直接设置 helper

sched.h 新增:

static inline void sched_set_tick_dependency(struct rq *rq)
{
        int cpu = cpu_of(rq);

        if (!tick_nohz_full_cpu(cpu))
                return;

        tick_nohz_dep_set_cpu(cpu, TICK_DEP_BIT_SCHED);
}

该 helper:

  1. 从 runqueue 得到 CPU。
  2. 只对 nohz_full CPU 执行操作。
  3. 直接设置 scheduler 的 tick dependency。
  4. 不调用 sched_can_stop_tick(),因此不读取可能仍指向旧任务的 rq->curr

在未启用 CONFIG_NO_HZ_FULL 时,提供空实现,不影响其他配置。

6. 与 CFS 现有处理对齐

提交说明指出,CFS 对需要 bandwidth accounting 的任务已有基于“下一个任务”的检查:sched_fair_update_stop_tick() 会明确设置 TICK_DEP_BIT_SCHED

这个补丁为 SCX 有限时间片建立了对应保障,但没有把 CFS 的完整逻辑直接复制到 SCX。

ASCII 流程图

                  set_next_task_scx(rq, p)
                            |
                            v
              +-----------------------------+
              | Is p->scx.slice infinite?   |
              +-----------------------------+
                    | yes             | no
                    v                 v
          can_stop_tick=true   can_stop_tick=false
                    |                 |
                    |                 v
                    |      sched_set_tick_dependency(rq)
                    |                 |
                    |      set TICK_DEP_BIT_SCHED
                    |                 |
                    v                 v
          tickless may resume    scheduler tick stays on
          after reevaluation     slice expiration progresses

旧路径中的竞态窗口:

Old task              set_next_task_scx()              New SCX task
rq->curr = old  --->  p = finite-slice SCX  ------->  rq->curr = p
                           |
                           v
                 sched_can_stop_tick(rq)
                           |
                           v
                 examines rq->curr = old
                           |
                           v
                 may incorrectly allow tick stop

修复后的判断来源:

Before: rq->curr(old) -> sched_can_stop_tick() -> possibly stop tick
After : p(new) finite -> direct dependency     -> keep tick enabled

概念类比

可以把 scheduler tick 看成厨房里的定时提醒器,有限时间片任务则是只能使用灶台十分钟的厨师。

旧逻辑在新厨师接手灶台时,仍询问上一位厨师是否需要定时器。上一位厨师可能已经做完,回答“不需要”,于是定时器被关掉。新厨师虽然只有十分钟配额,却再也收不到到时提醒,可能一直占用灶台。

补丁改为直接查看即将接手的厨师:

  • 新厨师有明确时限,就立即打开定时器。
  • 新厨师没有时限,才允许根据厨房的其他工作重新判断是否关闭定时器。

SCX_RQ_CAN_STOP_TICK 类似登记簿上的状态,而 TICK_DEP_BIT_SCHED 才是定时器的实际开关。补丁同时关注登记状态和真实开关,避免只改了登记簿却没有打开定时器。

Highlight 突出问题

  1. 关键问题不是普通的数据竞争,而是调度切换阶段的观察对象错误。
    set_next_task_scx() 已经知道下一个任务是 p,但旧 helper 仍通过 rq->curr 判断,而 rq->curr 此时尚未完成切换。

  2. 影响集中在 nohz_full CPU。
    普通周期 tick 一直运行的 CPU 不容易表现出该问题;隔离 CPU、低干扰 workload 和 full dynticks 场景更需要重点验证。

  3. 有限时间片任务可能失去时间片到期前进性。
    风险不只是统计误差,还可能表现为任务超出配置时间片、轮转延迟或其他 runnable 任务迟迟得不到调度。

  4. 设置 dependency 与清除 dependency 不对称是有意设计。
    有限时间片任务可以无条件设置 dependency;恢复 tickless 则必须重新检查系统的其他 tick 需求,不能仅因 SCX 使用无限时间片就直接清除全局 scheduler dependency。

  5. 需要验证不同前驱调度类的切换。
    建议覆盖 idle、CFS、RT、无限时间片 SCX 到有限时间片 SCX 的切换,并确认时间片到期后能及时发生重新调度。

  6. 需要验证实际 dependency 与 SCX_RQ_CAN_STOP_TICK 的一致性。
    尤其应覆盖 dependency 被其他 scheduler 路径修改、但 SCX 标志没有变化的情况。补丁对有限时间片任务每次直接设位,正是在防御这种不同步。

  7. 邮件正文存在截断。
    输入中的 Andrea Righi 回复只保留了引用内容,未显示其实际评论;冯志敏的回复也在引用原提交时被截断。因此无法从当前材料确认评审结论、是否要求修改,或关联系列是否已经解决同一问题。

版本演进

当前线程只提供一个未标注版本的单补丁,没有可确认的 v1 -> v2 演进记录。

若后续发布新版本,值得关注的变化包括:

  • helper 的命名和放置位置是否调整;
  • 是否补充 Fixes: 标签;
  • 是否增加 nohz_full 与有限时间片切换测试;
  • 是否与 Andrea Righi 的关联补丁合并或重构;
  • 是否进一步统一 CFS 与 SCX 的 next-task tick dependency 处理。

与其他相关 patch 系列的关联

冯志敏的回复给出了以下链接:

https://lore.kernel.org/all/20260708074812.1041434-1-arighi@nvidia.com/

从回复结构看,这是在提示 Andrea Righi 于 2026 年 7 月 8 日提交的相关工作。它很可能与 scheduler tick dependency 或本补丁触及的路径存在重叠。

不过,当前输入没有包含该关联邮件的标题和正文,而且两封回复都被截断,因此只能确认“评审者指出了一个相关系列”,不能可靠断言:

  • 两个补丁是否完全重复;
  • 哪一个覆盖范围更广;
  • 当前补丁是否应撤回;
  • 是否需要基于关联系列重写;
  • maintainer 最终倾向采用哪套方案。

这是本线程最需要后续核实的评审信息。

分类说明

该线程应归类为 Bugfix

虽然补丁标题使用的是“Keep tick enabled”,但提交说明明确描述了一个调度正确性缺陷:有限时间片 SCX 任务可能因为错误检查旧 rq->curr 而没有 scheduler tick,导致时间片无法正常到期。它不是单纯 feature、cleanup 或性能优化。

is_important 标记为 true,因为问题涉及调度前进性、时间片语义和 nohz_full CPU 上的任务公平运行,错误行为可能直接影响生产环境中的 CPU 隔离 workload。

一句话总结

该补丁让 sched_ext 根据即将运行的有限时间片任务直接打开 scheduler tick,避免因误看旧 rq->curr 而使时间片永不到期。