SGLang 性能分析:Torch Profiler 重叠启发式(Overlap Heuristics)判读指南
【免费下载链接】sglangSGLang is a high-performance serving framework for large language models and multimodal models.项目地址: https://gitcode.com/GitHub_Trending/sg/sglang
导读
本文面向使用 SGLang 进行 torch.profiler 分析、需要判断 GPU 内核(kernel)之间是否真的存在重叠(overlap)机会的开发者。它系统讲解分析器所采用的重叠启发式规则:mapping/formal 双 trace 的分工、内核"隐藏"(hidden)的判定标准、内核分类方法、重叠机会表(overlap-opportunity table)的读取方式、依赖信号的生成逻辑及其边界限制。读完本文,你将能够正确解读 SGLang profiler 分析报告中的headroom、low-roi-hidden、依赖风险标签与try overlap / try fusion / check deps等建议,并将其与仓库中的重叠目录(catalog)和源码实现相互印证,避免把已知优化误判为"新机会"。
本文对应的分析器说明文档位于 .claude/skills/llm-torch-profiler-analysis/references/heuristics.md,统一入口脚本为 .claude/skills/llm-torch-profiler-analysis/scripts/analyze_llm_torch_profile.py,重叠计算与依赖信号的核心实现位于 .claude/skills/llm-torch-profiler-analysis/scripts/triage_overlap_helpers.py。
一个前提:分析器是"刻意保守"的
文档开篇就点明了整套启发式的设计基调:"This analyzer is intentionally conservative"(本分析器刻意保持保守)。这意味着:
- 它不会因为两个内核出现在不同 CUDA 流上就断言它们"应该"重叠;
- 它不会把 Python 作用域(scope)映射当作数据依赖的证明;
- 它在给出"值得优化"的结论之前,会先排除明显的串行链(serial chain)风险。
保守的目的是避免产生误导性的性能优化建议——尤其是避免把通信内核(如 all-reduce)误报为"干净的 overlap 候选"。下面所有规则都可以在这个前提下理解。
mapping trace 与 formal trace:两个 trace 各司其职
重叠分析支持两种 trace 输入,它们的定位截然不同(对应 SKILL.md 中的--mapping-input/--formal-input双 trace triage 流程):
| Trace 类型 | 生成方式 | 用于计算什么 | 定位 |
|---|---|---|---|
| mapping trace | graph 关闭或低融合配置下采集,保证可读性 | kernel -> cpu_op -> python scope的调用链映射、启动点(launch-site)调用链 | 更易读,但不是最终服务调度形态 |
| formal trace | 真实服务优化全部开启时采集 | hidden ratio(隐藏比)、exclusive ratio(独占比)、overlap headroom(重叠余量)、ASCII 时间线 | 反映真实 serving 形态 |
两条 trace 的分工原则是:mapping trace 负责"这个内核从哪段 Python 代码启动",formal trace 负责"这个内核在真实调度下到底被藏住了多少"。因此文档明确建议,不要把 mapping trace 叫做"快速 profile"——它存在的唯一目的是恢复kernel -> cpu_op -> python scope这条调用链(源码实现见 triage_overlap_helpers.py 中的build_kernel_source_map,它通过External id -> CPU op -> 活跃 Python scope的时间线重建来给内核打上源位置标记)。
对应的两条命令(出自 SKILL.md):
# 双 trace 已有存量 trace python3 scripts/analyze_llm_torch_profile.py \ --mapping-input /path/to/graph_off_profile_dir \ --formal-input /path/to/graph_on_profile_dir # 双 trace 从运行中的 SGLang 服务实时采集 python3 scripts/analyze_llm_torch_profile.py \ --framework sglang \ --mapping-url http://127.0.0.1:31025 \ --formal-url http://127.0.0.1:31026 \ --num-steps 5 \ --profile-by-stage"隐藏"(hidden)的判定标准
一个内核在某段时间片段(segment)内被判定为hidden,需要同时满足两个条件:
- 该内核在该片段内处于活跃状态(即其
ts到ts+dur覆盖该片段); - 至少有一个位于不同流上的其他内核也在该片段内活跃。
如果与之重叠的内核是 compute 类内核,分析器还会单独记录一条"在 compute 之下被隐藏"(hidden under compute)的统计,用于区分"被计算掩盖"与"被通信掩盖"两种情况。
这段逻辑在源码中有精确对应。见 triage_overlap_helpers.py 的analyze_overlap:它对所有内核的ts / end做扫描线(sweep line)处理,维护活跃事件集合active;当某一片段内活跃内核涉及的不同流数量 >= 2时,该片段被计入total_overlap,同时每个内核累积hidden_us;若重叠对象中存在category == "compute"的内核,则额外累积hidden_by_compute_us;没有重叠对象的片段则累积为exclusive_us(独占时间)。最终聚合出两个核心指标(见AggregateStats的属性定义,triage_overlap_helpers.py):
hidden_ratio = hidden_us / total_us:该内核总时间中被其他流掩盖的比例;exclusive_ratio = exclusive_us / total_us:该内核总时间中"独占 GPU、无其他流并发"的比例。
内核分类启发式:按名字归类,仅用于优先级排序
分析器按内核名称做五类划分(文档原文,与源码关键词表一一对应):
| 类别 | 覆盖范围(文档) | 源码关键词证据(triage_overlap_helpers.py) |
|---|---|---|
compute | GEMM、attention、cutlass、cublas、类 matmul 的 Triton 内核 | cublas、cudnn、cutlass、triton、gemm、matmul、grouped_mm、flash、attention、marlin、fused_moe、mma、wgmma、bmm等 |
communication | NCCL、all-reduce、reduce-scatter、all-gather、DeepEP dispatch/combine | 强关键词allreduce、all_reduce、reduce_scatter、allgather、nccl、deepep、a2a、alltoall、mooncake;弱关键词broadcast、dispatch、combine |
elementwise | sigmoid、top-k、gate、rmsnorm、layernorm、rope、类型转换 | sigmoid、silu、gelu、softmax、layernorm、rmsnorm、rotary、rope、topk、gate、_cast、gather、scatter等 |
memory | memcpy、memset、fill、copy | 强关键词memcpy、memset、dma、prefetch;弱关键词fill、copy |
other | 其余一切 | 兜底返回 |
分类优先级固定且确定(classify_kernel中先判 memory/communication 强关键词,再判 compute/elementwise,最后兜底other),并配有一个类别优先级表CATEGORY_PRIORITY = {compute: 4, communication: 3, memory: 2, elementwise: 1, other: 0},用于决定"谁是主导重叠对象"(见dominant_overlap_name)。
需要特别强调:这些类别只服务于优先级排序(prioritization),本身不代表任何性能结论。比如一个elementwise内核被标记为"被隐藏",并不意味着它不重要——它可能只是当前调度下恰好被掩盖了。
如何阅读重叠机会表(Action Table)
重叠机会表故意不是完整的内核转储("intentionally not a full kernel dump")。它只保留已经带有动作导向标签(action-oriented label)的行,标签只有两种:
headroom:该内核在 formal trace 中仍有可观的暴露时间;low-roi-hidden:该内核已经被其他流大部分掩盖。
裁剪规则与 1% 门槛
排完优先级后,表会裁剪非常小的headroom行:
- 如果某
headroom行因低于默认的1% GPU 时间占比(share bar)而被判为P5,则从表中删除; low-roi-hidden行即使很小也保留,因为它们是"别先追这个"(do not chase this first)的重要信号。
1% 门槛在统一入口脚本中有直接对应:MIN_RENDER_SHARE_PCT = 1.0(analyze_llm_torch_profile.py),内核表、重叠表、融合表默认都只渲染 GPU 时间占比 >= 1.0% 的行。
headroom行的解读
- 该内核在 formal trace 中仍花费了有意义的暴露时间(exclusive 占比高);
- 映射到的 Python scope 是检查调度或融合机会的好位置;
- 在把它当作严肃的重叠候选之前,仍应先检查依赖信号。
low-roi-hidden行的解读
- 该内核已经被其他流大部分隐藏;
- 单独优化它,不太可能推动端到端延迟;
- 应把注意力转向融合(fusion)、减少 launch 次数,或周边调度,而不是单独调这个内核。
这两个标签的建议文本在源码中由build_headroom_suggestion/build_hidden_suggestion生成,例如 hidden 行会给出"Mostly hidden under {重叠对象} (X us). Revisit only if schedule or fusion changes."这类提示(triage_overlap_helpers.py)。
依赖信号(Dependency Signal):相邻性启发式,而非数据流证明
表中还包含一个来自 formal trace 的面向依赖的相邻性信号。它的构建输入是:
- 同一流上最近的前一个与后一个内核;
- mapping trace 的源归属(source attribution)。
为什么通信内核被"更保守"对待
文档强调通信内核的处理比以前更保守:
- 如果紧邻的内核看起来像可能的生产者或消费者(producer/consumer),即使它们的 Python scope 名称不同,表也会提高依赖风险;
- 这避免了仅因为 all-reduce 类内核的邻居映射到不同函数,就过度宣称它是干净的 overlap 候选。
源码中对应的判定函数是classify_dependency_signal(triage_overlap_helpers.py),核心规则:
- 紧邻判定:
tight_gap_threshold = max(2.0, min(20.0, current.dur * 0.15)),即间隙不超过该阈值视为"紧邻"; - 风险判定三要素:邻居与当前内核属于同一 scope 家族(
same_scope_family)、CPU 启动操作相同、或满足类别依赖关系(如communication内核的邻居是compute/elementwise/memory类,见is_neighbor_dependency_like); - 当紧邻但源归属太弱、无法做出更强断言时,标记为
adjacency unclear。
典型标签
文档列出的完整标签集合:
| 标签 | 含义 |
|---|---|
serial risk low | 相邻内核不像同代码路径上的紧密串行链 |
prev-side serial risk | 前一个相邻内核看起来与当前内核紧密绑定在同一代码路径 |
next-side serial risk | 后一个相邻内核看起来与当前内核紧密绑定在同一代码路径 |
both-side serial risk | 两侧都像是紧密串行链 |
adjacency unclear | 时序很紧,但源归属太弱,不足以支撑更强断言 |
可读表格会把这些压缩为更短的标签(dependency_risk_label映射,triage_overlap_helpers.py):
low(serial risk low)high(prev/next/both-side serial risk)unclear(adjacency unclear)
文档特别提醒:把它当作强启发式,而不是数据流的证明("a strong heuristic, not proof of dataflow")。
建议标签(Recommendation Labels)
重叠机会表的推荐标签刻意保持简短:
try overlap:依赖风险低、类别权重高,值得尝试与其他流重叠;try fusion:适合先做融合而非跨流重叠;check deps:依赖信号不明确,先核实依赖再动手;skip overlap:不值得追(如low-roi-hidden或 share 低于 1% 的 P5 行);manual check:需要人工核查;observe later:暂缓观察。
这些推荐连同 P1–P5 优先级由build_priority_and_recommendation统一生成(triage_overlap_helpers.py):例如headroom+ 依赖low+communication类别 →P1 / try overlap;headroom+ 依赖low+ 非通信 →P1 / try fusion;headroom+ 依赖非 low →P2 / check deps;share < 1% →P5 / skip。
实战:拿到重叠机会表后如何与仓库证据对照
这是整套技能最关键的一步(见 SKILL.md 的 Workflow):在宣称任何"新"优化之前,先把表中最顶部的行与仓库中的两个目录对照:
- references/overlap-catalog.md:只收录在 profiler 中可见为 GPU 内核/集合通信内核/流式内核家族的 overlap 模式;
- references/fuse-overlap-catalog.md:源背书的融合与重叠模式查找表。
对照结论应优先落在四种表述上:
- 已存在、但在此 trace 中缺失/被禁用/回归/后端不支持的路径;
- 已存在、但未应用到当前模型形态的路径;
- 上游其他框架已有、本地缺失的模式;
- 只有当目录中没有任何一行能对上时,才允许称为"真正的新机会"。
例如,如果重叠表里出现 MoE combine 内核与 down-gemm 相邻暴露,目录会引导你先对照 SGLang 的 Single-batch Overlap(SBO)家族(python/sglang/srt/batch_overlap/single_batch_overlap.py,开关enable_single_batch_overlap位于 python/sglang/srt/server_args.py);如果出现 Q/K norm 分流的 trace,则先对照apply_qk_norm的alt_stream家族(python/sglang/srt/models/utils.py);出现 allreduce + RMSNorm 分离时,先核对 FlashInferallreduce_fusion路径(python/sglang/srt/layers/layernorm.py 中的forward_with_allreduce_fusion)。
重要限制(Important Limits)
文档以四条限制收尾,这也是保守设计的具体体现:
- trace 只显示"实际发生了什么重叠",不显示"什么可以合法地重叠"(A trace shows what overlapped, not what could legally overlap)。不同流上并发的两个内核,并不能证明它们相互独立、没有数据依赖。
- 不同流上的两个内核不证明它们无依赖(Two kernels on different streams do not prove they are dependency-free)。
- 映射到的 Python scope 只是启动点线索,不是唯一相关的代码位置(A mapped Python scope is a launch-site clue, not the only relevant code location)。真实依赖可能来自更外层的作用域或张量别名。
- 被隐藏的内核仍然可能重要:如果它改变了占用率(occupancy)、launch 次数或周边调度,即使当前被掩盖,也可能在别的配置下成为瓶颈(A hidden kernel can still matter if it changes occupancy, launch count, or surrounding schedule)。
小结
SGLang 的 torch profiler 重叠启发式本质上是一套"宁缺毋滥"的三步流水线:先靠 mapping trace 恢复内核到 Python 源码的调用链,再靠 formal trace 用扫描线算法算出每个内核的 hidden/exclusive 比例与 headroom,最后用同一流相邻性与源归属构造依赖信号、压低通信内核的误报,产出带 P1–P5 优先级与六种动作建议的重叠机会表。理解这些规则后,你在解读 analyze_llm_torch_profile.py 输出的三表报告时,就能区分"真实的 overlap 余量"与"只是恰好并行"的假象,并借助 overlap-catalog.md 与 fuse-overlap-catalog.md 把每个机会落到具体的源码路径上验证。
【免费下载链接】sglangSGLang is a high-performance serving framework for large language models and multimodal models.项目地址: https://gitcode.com/GitHub_Trending/sg/sglang
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考