Prhub

#19545 feat(observability): add OpenTelemetry tracing for speculative decoding

sgl-project/sglang · 作者 RichardoMrMu · 合并时间 2026-04-17 14:01

分析状态 已生成
文件变更 3提交数 2 · 评论 9
代码增减 +99 / -1
feature observability speculative-decoding run-ci

执行摘要

为推测解码管道添加 OpenTelemetry 追踪,覆盖 EAGLE 和 NGRAM 工作器的 draft、verify 和 accept 阶段。

根据PR body和关联Issue #13511,推测解码的各个阶段目前没有instrumentation,使得诊断性能瓶颈变得困难。这是追踪路线图(#13511)的一部分,旨在填补这一空白,提升系统的可观测性。

建议技术管理者和工程师精读此PR,特别是req_time_stats.py中新增的追踪方法设计和set_time_batch的使用模式,这些展示了如何将OpenTelemetry集成到高性能推理管道中,同时保持低开销。关注设计决策如trace_only参数和事件放置时机,对于构建可观测性功能有借鉴价值。

讨论亮点

review中,sufeng-buaa提出关键建议:

  • 设计统一化:建议使用现有的set_time_batch模式来统一时间设置,并添加trace_only参数以优化性能("You can add a default bool parameter trace_only to set_time_batch")。
  • 事件放置正确性:指出事件应放在trace结束前,否则可能丢失("The event should be placed before the trace end")。
  • 代码质量:提醒移除废弃代码行以通过lint检查("Sorry, this deprecated line needs to be removed")。
    作者接受了所有建议,在后续提交中应用补丁并重构代码,最终获得批准。

实现拆解

  1. 扩展追踪配置:在python/sglang/srt/observability/req_time_stats.py中,新增RequestStage枚举值SPEC_DRAFT(level 2)、SPEC_VERIFY(level 2)和SPEC_DRAFT_EXTEND(level 3),并添加对应的追踪方法(如set_spec_draft_start_time),这些方法使用time.perf_counter()记录时间戳并调用trace_slice生成追踪片段。
  2. 集成到EAGLE工作器:在python/sglang/srt/speculative/eagle_worker.py中导入set_time_batchget_global_tracing_enabled,在forward_batch_generation方法的draft、verify和draft_extend阶段调用set_time_batch(例如set_time_batch(batch.reqs, "set_spec_draft_start_time", trace_only=True)),并通过循环为每个请求设置accepted_tokens事件。
  3. 集成到NGRAM工作器:在python/sglang/srt/speculative/ngram_worker.py中类似地导入并集成追踪逻辑,在forward_batch_generation方法的关键点添加set_time_batch调用和事件处理。
  4. 确保零开销设计:所有追踪逻辑都通过get_global_tracing_enabled()检查,并在set_time_batch中新增trace_only参数,当追踪禁用时快速返回,避免对核心路径的性能影响。
  5. 无测试或配置配套改动:本次变更专注于源码级集成,没有修改测试文件或部署配置,但需确保与现有追踪系统兼容。
文件 模块 状态 重要度
python/sglang/srt/observability/req_time_stats.py 可观测性 modified 7.87
python/sglang/srt/speculative/eagle_worker.py 推测解码 modified 6.32
python/sglang/srt/speculative/ngram_worker.py 推测解码 modified 6.29
python/sglang/srt/observability/req_time_stats.py core-logic

核心追踪逻辑变更,新增 speculative decode 的配置和追踪方法,是 PR 的基石。

# 在RequestStage枚举中新增speculative decode的追踪配置
SPEC_DRAFT = RequestStageConfig(
    "spec_draft",
    level=2, # 追踪级别2,用于细粒度性能分析
)SPEC_VERIFY = RequestStageConfig(
    "spec_verify",
    level=2,
)SPEC_DRAFT_EXTEND = RequestStageConfig(
    "spec_draft_extend",
    level=3, # 级别3,提供更详细的追踪信息
)# 新增的追踪方法:记录draft阶段开始时间
class SchedulerReqTimeStats(ReqTimeStatsBase):
    # 添加字段存储时间戳
    spec_draft_start_time: float = 0.0
    spec_verify_start_time: float = 0.0
    spec_draft_extend_start_time: float = 0.0
​
    def set_spec_draft_start_time(self, ts=None):
        if ts is None:
            ts = time.perf_counter() # 使用高精度计时器获取当前时间
        self.spec_draft_start_time = ts # 存储开始时间戳
​
    def set_spec_draft_end_time(self, ts=None):
        if ts is None:
            ts = time.perf_counter()
        stage = RequestStage.SPEC_DRAFT
        # 调用trace_slice生成追踪片段,记录从开始到结束的时间区间
        self.trace_slice(stage, self.spec_draft_start_time, ts)
​
    def set_spec_verify_end_time(self, ts=None, accepted_tokens: int = 0):
        if ts is None:
            ts = time.perf_counter()
        stage = RequestStage.SPEC_VERIFY
        # 在追踪片段中添加accepted_tokens属性,记录验证阶段接受的令牌数
        self.trace_slice(stage, self.spec_verify_start_time, ts, {"accepted_tokens": accepted_tokens})# 扩展set_time_batch函数以支持trace_only参数
# 当trace_only为True且全局追踪禁用时,快速返回以避免开销
def set_time_batch(reqs: List[Any], set_func: str, trace_only: bool = False):
    if reqs is None or len(reqs) == 0:
        return
    if trace_only and not get_global_tracing_enabled():
        return # 仅用于追踪时,检查全局开关
    ts = time.perf_counter()
    for req in reqs:
        method = getattr(req.time_stats, set_func) # 动态调用对应的set_*_time方法
        method(ts)

关键符号

set_spec_draft_start_time set_spec_draft_end_time set_spec_verify_start_time set_spec_verify_end_time set_spec_draft_extend_start_time set_spec_draft_extend_end_time set_time_batch

评论区精华

使用 set_time_batch 模式统一时间设置 设计

sufeng-buaa 建议在 eagle_worker.py 中使用现有的 set_time_batch 模式,并添加 trace_only 参数,以避免手动时间戳处理并优化性能。

结论:作者采纳建议,在后续提交中重构代码,使用 set_time_batch 并添加 trace_only 参数。 · 已解决

事件放置时机以避免数据丢失 正确性

sufeng-buaa 指出事件应放在 trace 结束前,否则可能丢失或附加到下一个 span。

结论:作者调整代码,确保事件在 trace 结束前记录。 · 已解决

移除废弃代码以通过 lint 检查 style

sufeng-buaa 在 req_time_stats.py 中发现废弃代码行,建议移除以避免 lint 失败。

结论:作者移除废弃行,保持代码整洁。 · 已解决

风险与影响

性能风险:追踪逻辑可能增加CPU开销,但通过get_global_tracing_enabled()门控和trace_only参数在禁用时避免额外成本,最小化影响。
正确性风险:新增的set_spec_*_time方法在req_time_stats.py中需确保时间戳处理正确,特别是trace_slice调用可能因参数传递错误导致追踪数据不准确。
兼容性风险:与现有追踪模式(如TraceReqContext)集成需一致,但基于现有设计降低了风险。
测试覆盖不足:没有直接对应的测试变更,可能隐藏回归bug,需依赖现有测试套件验证。

用户影响:启用OpenTelemetry追踪后,用户可以获得推测解码阶段的详细时间线,帮助诊断性能瓶颈,提升调试效率。
系统影响:在追踪启用时增加少量CPU开销(主要来自时间戳记录和span管理),但设计上避免了主要推理路径的负担;追踪数据可通过现有渠道导出,增强系统可观测性。
团队影响:工程师能更轻松地分析推测解码性能,支持优化工作,同时展示了如何在高性能系统中优雅集成追踪功能。

性能开销门控 核心路径变更 缺少测试覆盖

关联 Issue

#13511 [Roadmap] roadmap of request tracing (2025 Q4 and 2026 Q1)

完整报告

执行摘要

  • 一句话:为推测解码管道添加OpenTelemetry追踪,覆盖EAGLE和NGRAM工作器的draft、verify和accept阶段。
  • 推荐动作:建议技术管理者和工程师精读此PR,特别是req_time_stats.py中新增的追踪方法设计和set_time_batch的使用模式,这些展示了如何将OpenTelemetry集成到高性能推理管道中,同时保持低开销。关注设计决策如trace_only参数和事件放置时机,对于构建可观测性功能有借鉴价值。

功能与动机

根据PR body和关联Issue #13511,推测解码的各个阶段目前没有instrumentation,使得诊断性能瓶颈变得困难。这是追踪路线图(#13511)的一部分,旨在填补这一空白,提升系统的可观测性。

实现拆解

  1. 扩展追踪配置:在python/sglang/srt/observability/req_time_stats.py中,新增RequestStage枚举值SPEC_DRAFT(level 2)、SPEC_VERIFY(level 2)和SPEC_DRAFT_EXTEND(level 3),并添加对应的追踪方法(如set_spec_draft_start_time),这些方法使用time.perf_counter()记录时间戳并调用trace_slice生成追踪片段。
  2. 集成到EAGLE工作器:在python/sglang/srt/speculative/eagle_worker.py中导入set_time_batchget_global_tracing_enabled,在forward_batch_generation方法的draft、verify和draft_extend阶段调用set_time_batch(例如set_time_batch(batch.reqs, "set_spec_draft_start_time", trace_only=True)),并通过循环为每个请求设置accepted_tokens事件。
  3. 集成到NGRAM工作器:在python/sglang/srt/speculative/ngram_worker.py中类似地导入并集成追踪逻辑,在forward_batch_generation方法的关键点添加set_time_batch调用和事件处理。
  4. 确保零开销设计:所有追踪逻辑都通过get_global_tracing_enabled()检查,并在set_time_batch中新增trace_only参数,当追踪禁用时快速返回,避免对核心路径的性能影响。
  5. 无测试或配置配套改动:本次变更专注于源码级集成,没有修改测试文件或部署配置,但需确保与现有追踪系统兼容。

关键文件:

  • python/sglang/srt/observability/req_time_stats.py(模块 可观测性;类别 source;类型 core-logic;符号 set_spec_draft_start_time, set_spec_draft_end_time, set_spec_verify_start_time, set_spec_verify_end_time): 核心追踪逻辑变更,新增speculative decode的配置和追踪方法,是PR的基石。
  • python/sglang/srt/speculative/eagle_worker.py(模块 推测解码;类别 source;类型 dependency-wiring): EAGLE工作器集成追踪,在draft、verify和draft_extend阶段添加span,是功能的关键集成点。
  • python/sglang/srt/speculative/ngram_worker.py(模块 推测解码;类别 source;类型 dependency-wiring): NGRAM工作器集成追踪,类似EAGLE工作器,确保两种推测解码算法都有完整的追踪支持。

关键符号:set_spec_draft_start_time, set_spec_draft_end_time, set_spec_verify_start_time, set_spec_verify_end_time, set_spec_draft_extend_start_time, set_spec_draft_extend_end_time, set_time_batch

关键源码片段

python/sglang/srt/observability/req_time_stats.py

核心追踪逻辑变更,新增speculative decode的配置和追踪方法,是PR的基石。

# 在RequestStage枚举中新增speculative decode的追踪配置
SPEC_DRAFT = RequestStageConfig(
    "spec_draft",
    level=2, # 追踪级别2,用于细粒度性能分析
)SPEC_VERIFY = RequestStageConfig(
    "spec_verify",
    level=2,
)SPEC_DRAFT_EXTEND = RequestStageConfig(
    "spec_draft_extend",
    level=3, # 级别3,提供更详细的追踪信息
)# 新增的追踪方法:记录draft阶段开始时间
class SchedulerReqTimeStats(ReqTimeStatsBase):
    # 添加字段存储时间戳
    spec_draft_start_time: float = 0.0
    spec_verify_start_time: float = 0.0
    spec_draft_extend_start_time: float = 0.0
​
    def set_spec_draft_start_time(self, ts=None):
        if ts is None:
            ts = time.perf_counter() # 使用高精度计时器获取当前时间
        self.spec_draft_start_time = ts # 存储开始时间戳
​
    def set_spec_draft_end_time(self, ts=None):
        if ts is None:
            ts = time.perf_counter()
        stage = RequestStage.SPEC_DRAFT
        # 调用trace_slice生成追踪片段,记录从开始到结束的时间区间
        self.trace_slice(stage, self.spec_draft_start_time, ts)
​
    def set_spec_verify_end_time(self, ts=None, accepted_tokens: int = 0):
        if ts is None:
            ts = time.perf_counter()
        stage = RequestStage.SPEC_VERIFY
        # 在追踪片段中添加accepted_tokens属性,记录验证阶段接受的令牌数
        self.trace_slice(stage, self.spec_verify_start_time, ts, {"accepted_tokens": accepted_tokens})# 扩展set_time_batch函数以支持trace_only参数
# 当trace_only为True且全局追踪禁用时,快速返回以避免开销
def set_time_batch(reqs: List[Any], set_func: str, trace_only: bool = False):
    if reqs is None or len(reqs) == 0:
        return
    if trace_only and not get_global_tracing_enabled():
        return # 仅用于追踪时,检查全局开关
    ts = time.perf_counter()
    for req in reqs:
        method = getattr(req.time_stats, set_func) # 动态调用对应的set_*_time方法
        method(ts)

评论区精华

review中,sufeng-buaa提出关键建议:

  • 设计统一化:建议使用现有的set_time_batch模式来统一时间设置,并添加trace_only参数以优化性能("You can add a default bool parameter trace_only to set_time_batch")。
  • 事件放置正确性:指出事件应放在trace结束前,否则可能丢失("The event should be placed before the trace end")。
  • 代码质量:提醒移除废弃代码行以通过lint检查("Sorry, this deprecated line needs to be removed")。
    作者接受了所有建议,在后续提交中应用补丁并重构代码,最终获得批准。

  • 使用set_time_batch模式统一时间设置 (design): 作者采纳建议,在后续提交中重构代码,使用set_time_batch并添加trace_only参数。

  • 事件放置时机以避免数据丢失 (correctness): 作者调整代码,确保事件在trace结束前记录。
  • 移除废弃代码以通过lint检查 (style): 作者移除废弃行,保持代码整洁。

风险与影响

  • 风险:性能风险:追踪逻辑可能增加CPU开销,但通过get_global_tracing_enabled()门控和trace_only参数在禁用时避免额外成本,最小化影响。
    正确性风险:新增的set_spec_*_time方法在req_time_stats.py中需确保时间戳处理正确,特别是trace_slice调用可能因参数传递错误导致追踪数据不准确。
    兼容性风险:与现有追踪模式(如TraceReqContext)集成需一致,但基于现有设计降低了风险。
    测试覆盖不足:没有直接对应的测试变更,可能隐藏回归bug,需依赖现有测试套件验证。

  • 影响:用户影响:启用OpenTelemetry追踪后,用户可以获得推测解码阶段的详细时间线,帮助诊断性能瓶颈,提升调试效率。
    系统影响:在追踪启用时增加少量CPU开销(主要来自时间戳记录和span管理),但设计上避免了主要推理路径的负担;追踪数据可通过现有渠道导出,增强系统可观测性。
    团队影响:工程师能更轻松地分析推测解码性能,支持优化工作,同时展示了如何在高性能系统中优雅集成追踪功能。

  • 风险标记:性能开销门控, 核心路径变更, 缺少测试覆盖

关联脉络

  • 暂无明显关联 PR

参与讨论