mcpField
L
llm-pipeline-analysis

llm-pipeline-analysis

github.com/bbuf开发1.1k54 次安装今天更新
代码仓库

关于 llm-pipeline-analysis

用于分析 LLM 推理 Chrome trace 的工具集,可按层划分前向计算并输出时间表、内核明细及 Perfetto 导航范围,面向性能分析人员。其重点是依据模型配置和边界内核识别层结构,并比较不同前向轮次及层类型。

主要功能

  1. 01按层统计时间和内核类别
  2. 02区分冷启动与稳定前向轮次
  3. 03输出单层内核明细及差异
  4. 04生成 Perfetto 时间导航范围

适用场景

  1. 01定位耗时较高的层类型
  2. 02比较冷启动与稳定轮次
  3. 03选择代表层进行深度分析
  4. 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.py
layer_timeline_analyzer.py
model_profiles.py
perfetto_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_hcamhc_pre_big_fuse2DeepSeek-V4 或压缩回退
dsv41明确验证的锚点1(子层需覆盖)V4.1 文本/封装器身份或 KV 来源层
dsv3_mla明确指定的后端锚点或残差边界取决于后端身份分发后为同质 MLA
mla_dsa已验证的残差边界2GLM-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_nextmhc_pre_big_fuse2GLM-5.3-Flash
hy_v4Triton 回退时明确指定的 ihc_pre_stage22Hy4(hpc 符号需检查轨迹)
qwen4_exp明确指定的 grouped_gemma_rmsnorm2Qwen3.8-Flash-Next(vLLM 可能会融合 norm)
nemotron_h明确指定的残差 norm1根据配置,每个层对应一个 Mamba/注意力/MoE 块
longcat_flash明确指定的残差边界4LongCat-Flash 架构
gemma4明确指定的 _gemma_qkv_rmsnorm_kernel(SGLang CUDA)1Gemma4 文本/封装器身份
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]0SWA_ONLY仅窗口注意力,不含压缩器/索引器
compress_ratios[i]4CSA_C4压缩器 + lightning 索引器(Hadamard/paged-MQA/top-k)+ 稀疏注意力
compress_ratios[i]128HCA_C128压缩器 + 所有压缩行和窗口;不含索引器
compress_ratios[i]2 / 1V41_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_mlaDSv4, DSv321-33%
★ MoE 融合fused_moe_kernelDSv4, DSv311-17%
● NCCL AllReduce不区分大小写的 allreduce、all_reduce、cross_device_reduce、reduce_scatter、NCCL/Lamport通用5-8%
GEMM fp8deep_gemm通用12-25%
GEMM bf16nvjet通用11-13%
Hadamard 变换hadamardDSv40-2.4%
索引器缓存indexerDSv40-0.1%
Paged MQApaged_mqa_logitsDSv40-1.8%
MHCmhc_pre_gemm_sqrsum、mhc_pre_big_fuse、mhc_post_tilelangDSv410-15%
C4/C128 预填充c4_prefill、c128_prefillDSv40-0.3%
RMSNorm不区分大小写的 rms_?norm、layernorm通用1-2%
FP8 量化quant、Quant通用1-2%
TopKtopk通用0-0.7%
RoPEdeepseek_rope、fused_norm_ropeDSv4, DSv31-2%
激活函数silu_mul_clamp、act_and_mul通用0-0.5%
其他—通用2-5%

报告检查清单

包括:

  1. 跟踪元数据:跟踪路径、模型配置路径、GPU 类型、TP/EP
  2. 模型架构摘要(来自 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)
  3. 按批次汇总前向传递的表格(来自 layer_timeline_analyzer.py --show-all-passes):
    • 列:Fwd#、Start(s)、End(s)、Duration(ms)、Avg Layer(ms)、First Layer(ms)、Notes
    • 标明冷启动与稳态传递
  4. 选定的前向传递:索引及理由(冷启动还是稳态)
  5. 逐层墙钟时间和时长总和表格(来自 layer_timeline_analyzer.py --fwd-pass N):
    • 列:L、c_r、Type、Wall(ms)、SumDur(ms)、MLA、MoE、GEMM、NCCL、MHC、Hadam、AR#、K#
    • 每行对应一层,并标注层类型
  6. 按类型分组的层集群统计表格:
    • 列:Cluster、#、Avg Wall(ms)、Avg Sum(ms)、MLA%、MoE%、GEMM%、NCCL%、MHC%、Hadam%
    • 标明瓶颈层类型及可能的下一个优化目标
  7. 代表性层的计算流表格:
    • 由 layer_kernel_breakdown.py --format compute-flow 生成
    • 列:# | Half | Category | Simplified Name | dur(us) | % | ts_rel(ms) | Input Dims
    • 默认按耗时最长的热点内核(dur(us) 降序)排列各行
    • 可选导出为 JSON(--format json)
  8. 按要求提供 Perfetto UI 时间范围
  9. 单行摘要:瓶颈层类型及可能的下一个优化目标

评论

支持 Markdown