Prhub

#20845 Fix prefill batch iter logging under overlap

原始 PR 作者 weireweire 合并时间 2026-05-07 17:10 文件变更 6 提交数 9 评论 12 代码增减 +19 / -2

执行摘要

修复 overlap 调度下 prefill batch 日志迭代器号错误

Under overlap scheduling, the scheduler can launch the current batch before processing the previous batch result and increase forward_ct. The old prefill logging used the current global forward_ct when emitting Prefill batch lines, so completed batches could be mislabeled as a later iter. 当下一批次无任务且不增加 forward_ct 时,前后连续完成的 batches 甚至会打印相同的 iter id。

值得精读,特别是其设计抉择:在 run_batch 冻结快照而非 process_batch_result。理解此区别有助于掌握 overlap 调度下全局状态与局部状态的交互。

讨论亮点
  • gemini-code-assist[bot] 指出 report_decode_stats 同样应使用 batch-specific forward_iter,以避免 overlap 下 decode 日志错标;该建议被采纳,最终实现覆盖了 decode 分支。
  • ShangmingCai 询问 prefill 日志中应使用 self.forward_ct 还是 self.forward_ct+1;作者未直接回应,但最终代码采用 batch.forward_iter(值等于 run_batch 时的 forward_ct),即修正了原来 prefill 日志 +1 的 off-by-one 问题。
  • sufeng-buaa 质疑为什么不在 process_batch_result 中赋值 forward_iter;作者解释:在 process_batch_result 赋值相当于读取处理时的全局计数器,不能排除后续 run_batch 的影响;在 run_batch 赋值确保快照是启动时的值。sufeng-buaa 回复 'ok' 表示理解。

实现拆解

  1. 在 ScheduleBatch 类中新增 forward_iter: Optional[int] 属性,并在 copy() 方法中同步复制该属性,确保快照沿 batch 生命周期传递。
  2. 在 scheduler.py 的 run_batch() 中,递增 self.forward_ct 后立即将新值赋给 batch.forward_iter,冻结该批次的迭代身份标识。
  3. 在 scheduler_metrics_mixin.py 的 report_prefill_stats() 和 report_decode_stats() 中,优先读取 batch.forward_iter(仅当其为非 None 时使用),否则回退到 self.forward_ct。
  4. 在三个调用点(dllm mixin、scheduler_output_processor_mixin、disaggregation prefill)向 report_prefill_stats 新增 batch 参数,使可观测性函数能够访问到 batch 对象。
文件 模块 状态 重要度
python/sglang/srt/observability/scheduler_metrics_mixin.py 可观测性 modified 6.54
python/sglang/srt/managers/scheduler.py 调度器 modified 5.36
python/sglang/srt/managers/schedule_batch.py 调度批次 modified 4.89
python/sglang/srt/managers/scheduler_output_processor_mixin.py 调度器输出 modified 4.96
python/sglang/srt/dllm/mixin/scheduler.py DLLM 调度器 modified 4.96
python/sglang/srt/disaggregation/prefill.py 分离式 prefill modified 4.35

关键符号

report_prefill_stats report_decode_stats run_batch ScheduleBatch.copy

关键源码片段

python/sglang/srt/observability/scheduler_metrics_mixin.py core-logic

修改了日志迭代器生成逻辑,是修复的核心文件。

# scheduler_metrics_mixin.py — 使用 batch 级 forward_iter 替代全局 forward_ctdef report_prefill_stats(
    self: Scheduler,
    batch: Optional[ScheduleBatch], # 新增 batch 参数
    prefill_stats: PrefillStats,
    can_run_cuda_graph: bool,
    dp_cooperation_info: Optional[DPCooperationInfo] = None,
):
    ...
    # 优先使用 batch 自带的 forward_iter,否则回退到全局 forward_ct
    batch_iter = (
        batch.forward_iter
        if batch is not None and batch.forward_iter is not None
        else self.forward_ct
    )
    iter_msg = f" [{batch_iter}]" if LOG_FORWARD_ITERS else ""
    ...
python/sglang/srt/managers/scheduler.py core-logic

在 run_batch 方法中赋值 forward_iter,决定了快照时机。

# scheduler.py·run_batch — 冻结 batch 的迭代号def run_batch(
    self,
    batch: ScheduleBatch,
    pp_proxy_tensors: Optional[PPProxyTensors] = None,
) -> Union[GenerationBatchResult, EmbeddingBatchResult]:
    self.forward_ct += 1
    batch.forward_iter = self.forward_ct # 快照当前 forward_ct
    ...
python/sglang/srt/managers/schedule_batch.py data-contract

定义 forward_iter 属性并在 copy 方法中复制它,确保快照随 batch 传递。

# schedule_batch.py — ScheduleBatch 数据属性扩展class ScheduleBatch(ScheduleBatchDisaggregationDecodeMixin):
    ...
    forward_iter: Optional[int] = None # 新增,用于稳定日志迭代号
    ...
    def copy(self) -> "ScheduleBatch":
        return ScheduleBatch(
            ...
            forward_iter=self.forward_iter, # 复制快照
            ...
        )

评论区精华

decode 日志也应使用 batch.forward_iter 正确性

gemini-code-assist[bot] 评论指出 report_decode_stats 应类似 prefill 使用 batch-specific forward_iter,避免 overlap 下 decode 日志错标。

结论:被采纳,最终实现中 report_decode_stats 同样使用 batch_iter 逻辑。 · 已解决

prefill 日志应使用 forward_ct 还是 forward_ct+1 question

ShangmingCai 询问是否应为 self.forward_ct 或 self.forward_ct + 1。

结论:最终代码采用 batch.forward_iter(等于 run_batch 时的 forward_ct),修正了原 prefill 日志 +1 的 off-by-one 问题。 · 已解决

forward_iter 赋值时机:run_batch vs process_batch_result 设计

sufeng-buaa 质疑为何不在 process_batch_result 中赋值,作者解释:在 process_batch_result 赋值相当于读处理时的全局计数器,不能排除后续 run_batch 的影响;在 run_batch 赋值确保快照是启动时的值。

结论:作者解释后,sufeng-buaa 回复 'ok' 确认理解。 · 已解决

风险与影响

  1. 向后兼容:当 batch 为 None 或 forward_iter 为 None 时,日志回退到 self.forward_ct,对于 prefill 日志的迭代号会比旧版少 1(原使用 forward_ct+1),但所有现有调用路径均传入非空 batch,且旧 off-by-one 应视为 bug 而非特性,风险可控。
  2. 测试覆盖:本次改动未包含对应测试,若未来重构 batch 生命周期可能遗漏 forward_iter 复制,建议增加单元测试覆盖。
  3. 性能:仅新增一个整型属性赋值与读取,无性能影响。

影响范围:仅当开启 overlap 调度(enable_overlap=True)且 LOG_FORWARD_ITERS 为 True 时日志行为改变。非 overlap 模式下,若 batch 传入非 None,prefill 日志迭代号从原 forward_ct+1 变为 forward_ct(修正 off-by-one);decode 日志迭代号不变。整体改善了调度可观测性数据的准确性,便于调试和性能分析。

缺少测试覆盖 快照时机依赖性

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论