执行摘要
- 一句话:改为 launch 间隔统计 prefill/decode 忙时,统一负载指标
- 推荐动作:值得精读,虽然改动量不大,但它是调度器负载统计口径的一次重要统一设计。可以重点关注
_record_step_counters 中样本过滤条件的组合,以及 after_idle_gap 标记在重叠事件循环中的传递路径。建议后续补充针对边界条件的单元测试,以保护该统计逻辑的稳定性。
功能与动机
PR body 明确指出:Prefill busy time currently spans from batch launch until result processing. Under scheduler overlap, that includes unrelated CPU scheduling work and makes prefill accounting inconsistent with the existing launch-to-launch decode metric. 因此需要将 prefill 统计改为与 decode 相同的 launch 间隔口径,保证 autoscale 等负载判断一致性。
实现拆解
- 数据模型扩展:在
ScheduleBatch 类中新增 after_idle_gap: bool = False 字段,并在 copy() 方法中透传该字段,用于标记当前批次是否为调度器空闲后的首个批次。
- 调度器状态追踪:在
Scheduler 中,将原有的 _prev_decode_launch_ts 替换为 _prev_step: Optional[Tuple[int, float, bool]],保存上一次的前向迭代号、launch 时间戳和 prefill 标志;同时在 init_load_inquirer 中新增 _sched_idled = False 状态,并在 event_loop_normal 与 event_loop_overlap 中,当批次为空时(batch is None)置位 _sched_idled = True。
- launch 入口标记:
run_batch 中在记录 launch_ts 后,将 _sched_idled 写入 batch.after_idle_gap,然后立即复位 _sched_idled = False,从而让后续的统计逻辑感知到 idle 空档。
- 统计逻辑重写:
_record_step_counters 改为基于 _prev_step 与当前批次的 launch 时间戳计算间隔 step_us,并依次丢弃四类无效样本:无前置记录、after_idle_gap 为真、前后迭代号不连续、prefill/decode 模式切换;在合法区间 0 < step_us < STEP_MAX_US 内,prefill 累加 total_prefill_busy_us,decode 调用 _accumulate_decode_moment。
- 常量和测试配套:将
DECODE_STEP_MAX_US 重命名为 STEP_MAX_US 以覆盖两种统计;第二个提交删除了原来针对 step counter 的单元测试,因此该改动目前没有新增自动化测试覆盖。
关键文件:
python/sglang/srt/managers/scheduler.py(模块 调度器;类别 source;类型 core-logic;符号 _record_step_counters, _prev_step, _sched_idled, run_batch): 核心统计逻辑所在文件,包含 _record_step_counters 重写、_prev_step 状态引入、_sched_idled 标记以及常量重命名。
python/sglang/srt/managers/schedule_batch.py(模块 调度器;类别 source;类型 core-logic;符号 ScheduleBatch.after_idle_gap, ScheduleBatch.copy): 为 ScheduleBatch 新增 after_idle_gap 字段并在 copy() 中透传,是统计逻辑传递 idle 状态的关键数据通路。
关键符号:_record_step_counters, run_batch, init_load_inquirer, ScheduleBatch.copy
关键源码片段
python/sglang/srt/managers/scheduler.py
核心统计逻辑所在文件,包含 _record_step_counters 重写、_prev_step 状态引入、_sched_idled 标记以及常量重命名。
# _record_step_counters 核心统计逻辑(重新整理)
def _record_step_counters(self, batch, result):
# 健康检查请求不参与负载统计,直接返回
if all(is_health_check_generate_req(req) for req in batch.reqs):
return
# 根据 forward_mode 判断当前批次是否为 prefill
is_prefill = batch.forward_mode.is_prefill()
prev = self._prev_step
# 先记录当前步,之后再用旧值计算间隔
self._prev_step = (batch.forward_iter, batch.launch_ts, is_prefill)
# 丢弃无前置记录、idle 空档后的首个批次
if prev is None or batch.after_idle_gap:
return
prev_iter, prev_ts, prev_is_prefill = prev
# 丢弃 forward 迭代不连续(如插入其他 batch 或跳步)以及模式切换的样本
if prev_iter + 1 != batch.forward_iter or prev_is_prefill != is_prefill:
return
# 相邻两次 launch 的时间间隔(微秒),这里才是真正的忙时口径
step_us = int((batch.launch_ts - prev_ts) * 1e6)
# 丢弃非法时长,避免时钟异常或过大间隔污染统计
if not 0 < step_us < STEP_MAX_US:
return
if is_prefill:
self.total_prefill_busy_us += step_us
self.total_prefill_uncached_tokens += batch.extend_num_tokens
else:
# decode 沿用原有动量累积,但间隔也改为 launch-to-launch
_accumulate_decode_moment(
self.decode_moment_totals,
len(batch.reqs),
step_us,
len(batch.reqs) + result.num_correct_drafts,
)
python/sglang/srt/managers/schedule_batch.py
为 ScheduleBatch 新增 after_idle_gap 字段并在 copy() 中透传,是统计逻辑传递 idle 状态的关键数据通路。
# ScheduleBatch 中新增的字段定义(节选)
class ScheduleBatch(...):
# ... 其他字段 ...
# Metrics
dp_cooperation_info: Optional[DPCooperationInfo] = None
prefill_stats: Optional[PrefillStats] = None
forward_iter: Optional[int] = None
launch_ts: Optional[float] = None
# 标记当前批次是否紧跟在调度器空闲之后,用于统计时丢弃跨 idle 的样本
after_idle_gap: bool = False
def copy(self):
# ... 其他参数 ...
return ScheduleBatch(
# ... 其余构造参数 ...
forward_iter=self.forward_iter,
launch_ts=self.launch_ts,
after_idle_gap=self.after_idle_gap,
extend_num_tokens=self.extend_num_tokens,
)
评论区精华
该 PR 没有公开的 review 评论或讨论线程,仅有两次 /tag-and-rerun-ci 触发 CI 的指令。作者在 PR body 中说明此变更只影响调度器指标记账,不影响模型输出,因此未提供测试和性能数据。
风险与影响
-
风险:风险主要在于统计口径变更可能影响 autoscale 等依赖负载指标的功能:
_prev_step 只在连续同模式批次间累积,若长期 idle 或频繁模式切换,样本量可能减少,导致忙时估算偏低;
after_idle_gap 标记依赖 run_batch 入口,prebuilt batch 等提前返回路径是否同样设置尚未验证;
- 该 PR 明确没有单元测试覆盖,
_record_step_counters 的边界条件(如 forward_iter 不连续、时长阈值)缺少回归保护。
但这些风险仅影响指标统计精度,不直接影响模型推理正确性。
-
影响:影响范围集中在调度器内部的负载统计模块,涉及 scheduler.py 和 schedule_batch.py 两个文件。用户可见行为无变化,但 autoscale 和负载监控相关的下游逻辑可能观察到不同的 prefill busy 时间数值。对团队而言,后续在 overlap 调度下需要重新校准基于该指标设置的阈值。
- 风险标记:核心调度指标变更, 缺少单元测试覆盖
关联脉络
- PR #33403 [Scheduler] Honor explicit min-free-slots thresholds: 同为调度器负载控制相关改动,修改了 min-free-slots 延迟器的阈值逻辑,与本次 load metrics 统计口径调整共同影响调度器的负载判断和 autoscale 行为。
参与讨论