关于 llm-pipeline-analysis
用于分析 LLM 推理 Chrome trace 的工具集,可按层划分前向计算并输出时间表、内核明细及 Perfetto 导航范围,面向性能分析人员。其重点是依据模型配置和边界内核识别层结构,并比较不同前向轮次及层类型。
主要功能
- 01按层统计时间和内核类别
- 02区分冷启动与稳定前向轮次
- 03输出单层内核明细及差异
- 04生成 Perfetto 时间导航范围
适用场景
- 01定位耗时较高的层类型
- 02比较冷启动与稳定轮次
- 03选择代表层进行深度分析
- 04在 Perfetto 中跳转到指定层
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ bbuf/ ai-infra-auto-driven-skills --skill llm-pipeline-analysis安装后在 Claude Code 中输入/llm-pipeline-analysis确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
scripts/layer_kernel_breakdown.pylayer_timeline_analyzer.pymodel_profiles.pyperfetto_time_mapper.py详细介绍
LLM 流水线分析
概述
当整条轨迹的分析器摘要过于粗略时,可使用此工具。脚本会读取 Chrome 轨迹 JSON 文件,查找层边界锚点内核,将内核分组为前向传播和层,并输出计时表,供你在 Perfetto 中导航或进行详细计时分析。
适用场景
- 需要了解哪些层的耗时占比最高
- 模型包含交替的层类型(例如带有
compress_ratios的模型,如 DeepSeek-V4 NSA,或混合 GDN/GQA 堆栈,如 Qwen3.8-27B) - 需要比较冷启动与稳态前向传播
- 需要在 Perfetto UI 中导航到特定层
- 需要选出具有代表性的层进行深入分析
从制品验证输入
从运行清单、服务端参数和轨迹中解析模型配置、阶段、rank/设备以及 TP/EP/DP。只询问会影响分析的缺失信息。TP-0 标识的是 rank,而非 TP world size;不要默认未知运行使用 TP8/EP8 或 decode BS1。推测请求的 BS 与目标验证 M 不同。
如果没有可用配置,请使用明确指定的 profile 和经过验证的层数。
模型 Profile
脚本使用 ModelProfile 确定层边界检测和内核分类。Profile 会从 config.json 自动推断,也可通过 --profile 选择:
| Profile | 锚点内核 | 每层 Blocks 数 | 自动推断条件 |
|---|---|---|---|
dsv4_csa_hca | mhc_pre_big_fuse | 2 | DeepSeek-V4 或压缩回退 |
dsv41 | 明确验证的锚点 | 1(子层需覆盖) | V4.1 文本/封装器身份或 KV 来源层 |
dsv3_mla | 明确指定的后端锚点或残差边界 | 取决于后端 | 身份分发后为同质 MLA |
mla_dsa | 已验证的残差边界 | 2 | GLM-5/5.2/5.3、V3.2、DSA MLA |
kimi_k3 | 明确指定的 attn_res_fused(SGLang)/attn_res_fwd_online_v2_kernel(vLLM) | 2 + 每次前向传播一次输出聚合 | K3 / 带注意力残差的 Kimi linear |
glm5_next | mhc_pre_big_fuse | 2 | GLM-5.3-Flash |
hy_v4 | Triton 回退时明确指定的 ihc_pre_stage2 | 2 | Hy4(hpc 符号需检查轨迹) |
qwen4_exp | 明确指定的 grouped_gemma_rmsnorm | 2 | Qwen3.8-Flash-Next(vLLM 可能会融合 norm) |
nemotron_h | 明确指定的残差 norm | 1 | 根据配置,每个层对应一个 Mamba/注意力/MoE 块 |
longcat_flash | 明确指定的残差边界 | 4 | LongCat-Flash 架构 |
gemma4 | 明确指定的 _gemma_qkv_rmsnorm_kernel(SGLang CUDA) | 1 | Gemma4 文本/封装器身份 |
generic_addnorm | 已验证的融合加法 RMSNorm 或 allreduce 融合 | 2 | 其他已配置的模型 |
generic | 明确指定的锚点;仅将残差候选作为备选 | 1,残差候选则为 2 | 无配置时的回退 |
推断前会扁平化嵌套的 text_config、language_config 和 llm_config。模型身份优先于 kv_lora_rank:K3、GLM-5 Next、Hy4、dots3 和 LongCat 不得视为同质 V3 MLA。
从配置中读取层数:V4 Flash 有 43 层,Pro 有 61 层,V4.1 有 40 层。
这些锚点系列已通过 SGLang/vLLM 源码验证,但存在后端和阶段方面的注意事项;TensorRT-LLM/TokenSpeed 的调用节奏需要单独的轨迹证据。
前置条件
- Chrome 轨迹 JSON 格式(
.json或.json.gz)的torch.profiler轨迹 - 模型的
config.json(用于推断 profile、compress_ratios等) - 轨迹必须包含可识别的层边界锚点内核(从 profile 自动检测,或通过
--anchor-kernel指定)
层边界检测
这些脚本使用锚点 kernel 作为层边界标记。锚点和层结构由当前生效的 ModelProfile 决定。
首先查找模型在其阶段边界处的残差类型。SGLang 通过 python/sglang/srt/layers/layer_boundary/factories.py 声明 attention/FFN 边界(add-norm、gated、iHC、mHC、post-norm 和 stream)。后端分派决定可见的边界 kernel。
V4 目前从每个半层的 mhc_pre_big_fuse* 开始:先是 attention-pre,然后是 FFN-pre,每层两个锚点。融合的 post+pre 会在小 token 数的 SGLang 跟踪中移除 mhc_post_tilelang;仅对经过验证的未融合跟踪或 >32-token 路径保留该旧锚点。V4.1 使用前一个子层的 pre-mix,并禁用该跨层融合路径,因此始终需要明确的锚点证据。FlashMLA 的 flash_fwd_mla_combine 取决于后端和拆分数量;SM100 上的 SGLang V3 默认使用 TRT-LLM MLA,而 DSA 模型使用 DSA。
所有脚本都接受 --blocks-per-layer K --anchor-offset I --pid PID --device D。
I 是在所选 GPU 上经过验证的首层锚点,不能根据计数推断。混合 rank/设备以及模 N*K 后有余数的计数都会被拒绝。
计数可整除是必要条件,但并不足够:应先区分 target/draft 阶段、MTP/DSPARK pass 和 TBO microbatch。K3 额外的输出聚合要求这些计时分析器使用经过阶段筛选的跟踪;层跟踪辅助工具显式支持额外锚点。最后选定的 pass 在所选 GPU 的事件边界处结束,该边界本身必须经过验证,确认是一个完整 pass。锚点是导航区间;跨流 kernel 可能与这些区间重叠。
对于已编译的 vLLM 跟踪,norm 可能会降低为 Inductor kernel。请使用显式 norm 自定义算子或 eager 执行捕获简短的映射跟踪,并在实际测量的跟踪中验证 attention/后端锚点。
源码审查日期:2026-10-05:SGLang V4 分派, mHC kernel, vLLM mHC 分派。
脚本
1. layer_timeline_analyzer.py — 分层时间线和集群统计
# Show all forward passes summary (cold-start vs steady-state)
python3 scripts/layer_timeline_analyzer.py \
--trace /path/to/TP-0.trace.json.gz \
--config /path/to/config.json \
--show-all-passes
# Detailed per-layer breakdown for a specific forward pass
python3 scripts/layer_timeline_analyzer.py \
--trace /path/to/TP-0.trace.json.gz \
--config /path/to/config.json \
--fwd-pass 5
# Auto-select the first relatively stable pass window
python3 scripts/layer_timeline_analyzer.py \
--trace /path/to/TP-0.trace.json.gz \
--config /path/to/config.json
脚本会打印:
- 每层的实际耗时、持续时间总和以及类别细分(MLA、MoE、GEMM、NCCL、MHC、Hadamard)
- 按类型分组的层集群统计(CSA_C4、HCA_C128、HASH 等)
- 显示从冷启动到稳态增长的所有 pass 汇总
自动选择稳态要求连续两次第 0 层计时变化都在 5% 以内。该方法不使用绝对延迟阈值,因此适用于不同模型规模和加速器。如果不存在稳定窗口,请显式指定 --fwd-pass。
2. layer_kernel_breakdown.py — 分层 kernel 详情和计算流
# Single layer kernel dump
python3 scripts/layer_kernel_breakdown.py \
--trace /path/to/TP-0.trace.json.gz \
--config /path/to/config.json \
--fwd-pass 5 --layer 3
# Compute flow format (with model architecture summary and category column)
python3 scripts/layer_kernel_breakdown.py \
--trace /path/to/TP-0.trace.json.gz \
--config /path/to/config.json \
--fwd-pass 5 --layer 3 --format compute-flow
# JSON export
python3 scripts/layer_kernel_breakdown.py \
--trace /path/to/TP-0.trace.json.gz \
--config /path/to/config.json \
--fwd-pass 5 --layer 3 --format json
# Compare two layers side-by-side
python3 scripts/layer_kernel_breakdown.py \
--trace /path/to/TP-0.trace.json.gz \
--config /path/to/config.json \
--fwd-pass 5 --layer 2 --compare-layer 3
输出格式:
--format text(默认):分组汇总 + 按持续时间排序的热点 kernel,包含简化名称和百分比--format compute-flow:模型架构摘要 + 每个 kernel 的热点表,包含Category、%和ts_rel(ms)列--format json:一个按持续时间排序、可供机器读取的 JSON 文档;使用--compare-layer时,其中包含primary、comparison和kernel_diff- 比较两层时的 kernel 差异(各层独有的 kernel)
3. perfetto_time_mapper.py — Perfetto UI 时间导航
# Show all forward pass time ranges in Perfetto
python3 scripts/perfetto_time_mapper.py \
--trace /path/to/TP-0.trace.json.gz \
--config /path/to/config.json
# Layer-level time ranges for a specific forward pass
python3 scripts/perfetto_time_mapper.py \
--trace /path/to/TP-0.trace.json.gz \
--config /path/to/config.json \
--fwd-pass 5 --layers 2,3,38,42
脚本会打印:
- 以 Perfetto 相对秒数表示的前向 pass 时间范围
- 带有 compress_ratio 标签的每层开始/结束时间
工作流
第 1 步:识别稳态前向传递
python3 scripts/layer_timeline_analyzer.py \
--trace $TRACE --config $CONFIG --show-all-passes
查看“all-passes”表。第一轮是冷启动(token 数较少)。 使用脚本选出的第一个相对稳定窗口;如果耗时仍在变化,也可以 显式选择某一轮。
第 2 步:稳态轮次的逐层分解
python3 scripts/layer_timeline_analyzer.py \
--trace $TRACE --config $CONFIG --fwd-pass 5
识别:
- 哪种层类型占主导(CSA_C4 与 HCA_C128 与 HASH)
- 每种层类型中 MLA / MoE / GEMM / NCCL 的占比
- 哪种层类型最适合作为下一个优化目标
第 3 步:代表性层的计算流程
选择 1-2 个代表性层(每种瓶颈类型各选一个),然后:
# Human-readable compute flow table
python3 scripts/layer_kernel_breakdown.py \
--trace $TRACE --config $CONFIG \
--fwd-pass 5 --layer 3 --format compute-flow
# JSON export
python3 scripts/layer_kernel_breakdown.py \
--trace $TRACE --config $CONFIG \
--fwd-pass 5 --layer 3 --format json > /tmp/layer3_detail.json
--format compute-flow 输出包括:
- 顶部的模型架构摘要
- 每个内核的热点表,列为
# | Half | Category | Simplified Name | dur(us) | % | ts_rel(ms) | Input Dims - 默认按
dur(us)降序排列各行;使用ts_rel(ms)跳转回内核在跟踪记录中的位置。
第 4 步:比较层类型(可选)
python3 scripts/layer_kernel_breakdown.py \
--trace $TRACE --config $CONFIG \
--fwd-pass 5 --layer 2 --compare-layer 3
这会显示两种层类型之间的精确内核差异。
第 5 步:在 Perfetto UI 中导航(可选)
python3 scripts/perfetto_time_mapper.py \
--trace $TRACE --config $CONFIG \
--fwd-pass 5 --layers 2,3,38,42
使用打印出的时间范围直接在 Perfetto 中导航。
层类型分类
脚本根据 config.json 字段对层进行分类:
| 配置字段 | 值 | 层类型 | 描述 |
|---|---|---|---|
compress_ratios[i] | 0 | SWA_ONLY | 仅窗口注意力,不含压缩器/索引器 |
compress_ratios[i] | 4 | CSA_C4 | 压缩器 + lightning 索引器(Hadamard/paged-MQA/top-k)+ 稀疏注意力 |
compress_ratios[i] | 128 | HCA_C128 | 压缩器 + 所有压缩行和窗口;不含索引器 |
compress_ratios[i] | 2 / 1 | V41_C2 / V41_C1 | 源层压缩器/索引器;其他层共享 KV/索引 |
i < num_hash_layers | — | +HASH | 前 N 层中的哈希路由,可与 FIRST/FINAL 组合 |
i == 0 / N-1 | — | +FIRST / +FINAL | 位置标记,绝不会替代注意力/路由工作 |
V4 Flash/Pro 在 L0–2 使用哈希路由。V4.1 没有哈希层;其 KV 源层为
[2,8,14,20],索引源为 [2,8,14,20,24,28,32,36],候选源为
20,Engram 层为 [1,14]。选择代表性层时,请使用这些角色字段。Pro
以 ratio-128 层开头;不要假设它的前两层是 SWA。
K3 的 KDA 层 ID 从 1 开始编号,而 GLM-5 Next 使用从 0 开始编号的 KDA ID。
内核类别
内核根据当前 ModelProfile 的规则分类。标有 (DSv4) 的类别仅适用于
dsv4_csa_hca 配置;所有配置都包含通用类别。
| 类别 | 匹配模式 | 配置 | 典型占比(DSv4) |
|---|---|---|---|
| ★ MLA 注意力 | flash_fwd_splitkv_mla | DSv4, DSv3 | 21-33% |
| ★ MoE 融合 | fused_moe_kernel | DSv4, DSv3 | 11-17% |
| ● NCCL AllReduce | 不区分大小写的 allreduce、all_reduce、cross_device_reduce、reduce_scatter、NCCL/Lamport | 通用 | 5-8% |
| GEMM fp8 | deep_gemm | 通用 | 12-25% |
| GEMM bf16 | nvjet | 通用 | 11-13% |
| Hadamard 变换 | hadamard | DSv4 | 0-2.4% |
| 索引器缓存 | indexer | DSv4 | 0-0.1% |
| Paged MQA | paged_mqa_logits | DSv4 | 0-1.8% |
| MHC | mhc_pre_gemm_sqrsum、mhc_pre_big_fuse、mhc_post_tilelang | DSv4 | 10-15% |
| C4/C128 预填充 | c4_prefill、c128_prefill | DSv4 | 0-0.3% |
| RMSNorm | 不区分大小写的 rms_?norm、layernorm | 通用 | 1-2% |
| FP8 量化 | quant、Quant | 通用 | 1-2% |
| TopK | topk | 通用 | 0-0.7% |
| RoPE | deepseek_rope、fused_norm_rope | DSv4, DSv3 | 1-2% |
| 激活函数 | silu_mul_clamp、act_and_mul | 通用 | 0-0.5% |
| 其他 | — | 通用 | 2-5% |
报告检查清单
包括:
- 跟踪元数据:跟踪路径、模型配置路径、GPU 类型、TP/EP
- 模型架构摘要(来自
config.json):- 模型名称、num_layers、hidden_size、num_attention_heads、num_key_value_heads、head_dim
- 注意力类型(例如 csa_hca)、Q/O LoRA 秩
- MoE 配置:num_experts、topk、num_shared_experts、intermediate_size
- MHC 配置(如适用)
- NSA 配置(如适用):index_n_heads、index_head_dim、index_topk、qk_rope_head_dim、sliding_window
- compress_ratios 分布(各有多少层 CSA_C4 / HCA_C128 / SWA_ONLY / HASH)
- 按批次汇总前向传递的表格(来自
layer_timeline_analyzer.py --show-all-passes):- 列:Fwd#、Start(s)、End(s)、Duration(ms)、Avg Layer(ms)、First Layer(ms)、Notes
- 标明冷启动与稳态传递
- 选定的前向传递:索引及理由(冷启动还是稳态)
- 逐层墙钟时间和时长总和表格(来自
layer_timeline_analyzer.py --fwd-pass N):- 列:L、c_r、Type、Wall(ms)、SumDur(ms)、MLA、MoE、GEMM、NCCL、MHC、Hadam、AR#、K#
- 每行对应一层,并标注层类型
- 按类型分组的层集群统计表格:
- 列:Cluster、#、Avg Wall(ms)、Avg Sum(ms)、MLA%、MoE%、GEMM%、NCCL%、MHC%、Hadam%
- 标明瓶颈层类型及可能的下一个优化目标
- 代表性层的计算流表格:
- 由
layer_kernel_breakdown.py --format compute-flow生成 - 列:
# | Half | Category | Simplified Name | dur(us) | % | ts_rel(ms) | Input Dims - 默认按耗时最长的热点内核(
dur(us)降序)排列各行 - 可选导出为 JSON(
--format json)
- 由
- 按要求提供 Perfetto UI 时间范围
- 单行摘要:瓶颈层类型及可能的下一个优化目标