Blackwell FP4 MoE:把 live-row 边界贯穿整个 FFN
从 vLLM #59044 看 padding 跳过、CUDA graph 动态计数与性能证据的边界
目录
9 月 29 日日报已经记录 #59044 的性能摘要。本篇进一步固定 PR head,分析 expert endpoint 如何连接 scatter、两次 grouped GEMM 与 fused SiLU 量化,以及为什么少做 padding 工作不等于释放 workspace。该 PR 仍未合并,所有 GPU 性能均为作者报告。
1. 为什么 GEMM 跳过 padding 还不够?
MoE 先把 token 按 expert 聚集,再执行 gate/up 投影、激活与量化、down 投影,最后反排列与加权归并。实际路由数量随 batch 改变,但 grouped GEMM 的对齐和 CUDA graph 的容量预留会让物理 buffer 大于有效 token 集合。只让 GEMM 少算无效行,中间 SiLU+mul+FP8 quant 仍可能遍历完整 buffer。
#59044 的源码变化跨过了这个算子边界:scatter 生成每个 expert 的真实结束位置,两次 GEMM 使用 prefix-sum layout,中间 packed-UE8M0 激活量化也接收相同 endpoint。改变的是执行范围与布局元数据,而 activation workspace 仍按原来的 M_sum 容量分配。
截至 2026-09-30 08:00 UTC 核验,PR 为 open、draft=false、未合并;固定 head 是 85285b44a87257ece81f9df7560a3f79c35acb68。PR 正文还留有“draft”描述,本文按 GitHub API 的结构化状态记录,不能把实现存在写成正式版本已经发布。
- 本篇是对已有日报条目的源码深化,不把 9 月 28 日提交伪装为过去 24 小时的新功能
- 新 prefix-sum 分支由 SM10.x family guard 启用;作者硬件测试为 GB200,不能据此宣称 SM103 已验证
- 激活 masking 的具体入口是 SILU + UE8M0 packed scale;其他 gated activation 或 scale-format 分支不能直接套用同样的收益
2. endpoint 到底编码了什么?
这里的 prefix sum 不是对原始 token counts 做一次普通累加。设对齐量 A、expert e 的有效行数 n[e]:先对之前各 expert 的数量向上对齐,得到 start[e];end[e] 再等于 start[e]+n[e]。因此 endpoint 包含之前 expert 留出的对齐间隙,却不把本 expert 的尾部 padding 算成 live row。
以 A=128、counts=[96,0,129,1] 为例,start=[0,128,128,384],end=[96,128,257,385]。第二个 expert 为空,但其 endpoint 是 128;第三个 expert 从 128 开始,而不是从原始 counts 的累积值 96 开始。理解这点,才能正确地从上一 endpoint 重建当前起点。
源码中 scatter 在现有步骤内写出 int32 endpoint,不需要为了 activation 把 counts 读回 CPU。DeepGemmFP4Experts.apply 把同一个 grouped_layout 交给 FC1、_act_mul_quant 与 FC2。激活 kernel 用 program_id(2) 选 expert,只循环 [start,end);输出 padding 保持未写,消费者必须继续遵守相同有效区间。
这是一份生产者与消费者共同遵守的范围契约:跳过写入之所以可行,是因为后面的 GEMM 不把间隙当成真实 token;不能把未写 buffer 当作已经清零。原有 mk_alignment_scope 与相关 zero-padding 保护也没有因这份元数据而被整体移除。
同样出现 prefix sum,也不一定意味着跳过 padding。SGLang 的 DeepEP v2 expanded-prefill 提案 #37261 在固定 head 802c326 中,把每个 expert 的结束位置再次向上对齐,再为整个区间填写 m_indices;区间内的 padding 仍参与 GEMM,其输出由 combine 忽略,只有所有区间之外的 capacity tail 才保留 −1 sentinel。这条路径主要消除 dispatch 后的额外 scatter 拷贝,与本文把真实 end 贯穿两个 GEMM 和激活算子的 live-row 契约不同。比较实现时应检查消费者究竟读取真实 end 还是 aligned end,不能仅凭元数据叫 prefix sum 就归为同一种优化。该 SGLang 提案仍未合并,此处只作源码语义对照。
概念伪代码(根据源码独立整理)
start[0] = 0
start[e] = align_up(end[e-1], A)
end[e] = start[e] + count[e]
live_rows[e] = [start[e], end[e])
scatter → endpoint[E]
FC1(endpoint) → SiLU+mul+quant(endpoint) → FC2(endpoint)
注意:workspace capacity 保持原值;endpoint 不是新的 allocation size。支持横向滑动查看
3. CUDA graph 重放时,哪些东西可以改变?
图捕获需要稳定的工作区与 launch 结构,并不要求每次重放的 expert counts 相同。此实现保留容量与 endpoint tensor 的地址,让设备侧内容随当前路由更新。激活 launch 从原来的二维 grid 变为带 expert 维度的三维 grid,kernel 运行时读取 endpoint,再在 grid-stride loop 中遍历各自有效区间。
当调用方没有 expert_ends 时,wrapper 保留原 dense launch;EXPERT_ALIGNMENT 是编译期参数,缺少元数据时相关 load 会被编译掉。带 metadata 的路径会多做边界读取与调度,因此“全满 buffer”必须单独测,不能只展示高 padding 比例下的优势。
新增 GPU 测试先捕获 graph,再把 counts 反转后重放;把无效输入填成 NaN、无效输出填成字节哨兵,检查 live FP8 与 packed scale 逐位一致,并检查 padding 输出没被触碰。空 expert、全空 counts、clamp 和 group-size 变化也被纳入用例。它检验的是动态有效范围,而不仅是一次随机输入的近似数值一致。
本次另做了一个 CPU 范围模型检查,覆盖 2,004 组 counts,完成 24,048 项索引检查:验证 endpoint 递推与源码中“前序对齐 counts 求和”一致,以及模拟 grid-stride 访问恰好覆盖 live rows。它只检查整数索引语义,不运行 Triton、DeepGEMM、FP8 算术或 GPU graph,也不构成性能复现。
4. 9.36% 和 6.09× 分别证明了什么?
作者的主要 FFN 配对实验使用 8×GB200、DeepSeek-V4-Flash revision 60d8d70770c6776ff598c94bb586a859a38244f1、EP8/DP8/TP1、DeepEP V2 + DeepGEMM,取第 10 层同一份真实输入、每 GPU 512 tokens。基线与候选两边已经都启用 prefix-sum GEMM,差异只在 activation 是否拿到 expert bounds。完整 FFN 从 425.5 降至 385.7 μs,即延迟下降 9.36%,约 1.103×。
单独 profile 的 activation 是 76.0→20.7 μs;另一个独立量化 microbenchmark 在 3,072 live / 28,672 allocated rows、hidden=2,048 时为 63.984→10.510 μs,约 6.09×。不同 rank 的 expert 负载和 combine 汇合会影响完整 FFN,因此不能把局部 kernel 倍数直接写成模型吞吐提升。更早的 stock→prefix-sum 717.4→428.7 μs 来自另一轮配对,也不应和本轮结果拼成同一次端到端加速。
布局 metadata 从 28,672 个 int32 变为 32 个 int32,算术上是 112 KiB→128 bytes;这不是主 activation workspace 的缩小。满 buffer 对照还显示某些 shape 有成本:28,672×2,048 的 metadata-aware kernel 为 64.822 μs,对原 dense 的 64.082 μs,约慢 1.15%。
GSM8K 的 1,253/1,319→1,259/1,319 是作者准确性检查结果,不能称为质量提高。作者重复未改动的 control 也观察到答案正确性翻转。测试运行时是固定镜像加局部 Python/kernel 函数覆盖,不是完整重建当时 main;独立读者也未取得并重跑外部完整 FFN/评测编排。
5. 如何验证这条路径值得部署?
合理的判断是:当静态容量明显大于当前 live rows,且 packed activation 路径真实命中时,把布局边界贯穿 FFN 能减少无效工作。它没有自动解决 expert 负载倾斜、all-to-all 通信、工作区容量或整个 serving 栈的问题。
复现实验应分别保留 stock、prefix-sum only、prefix-sum+activation masking 三组,固定模型 revision、镜像、GPU 拓扑、路由输入与 graph 模式。先检查实际 dispatch 与 installed source hashes,再做正确性、kernel timing、完整 FFN 和端到端服务四层对照。下面是待验证计划,尚未在本次运行执行。
关联的 PD/C2C 专题讨论通信与计算的共同关键路径。本篇消除部分 expert 计算空耗后,dispatch、combine 或跨 rank 汇合在总时间中的占比可能上升;这只是后续 profiling 应检查的方向,并非已经观察到的新瓶颈。
- 覆盖 live/capacity 比、空 expert、倾斜路由、小 batch 与满 buffer;记录分 rank 分布,避免只看所有 rank 的中位数
- 对 GPU graph 连续改变 counts,验证 live 值、packed scales 与 invalid-row 哨兵;模型级检查用重复对照估计原有数值噪声
- 记录 FC1、activation、FC2、dispatch/combine 与同步等待的独立时间;服务层测吞吐、TPOT/P99 和延迟约束下的 goodput
- 峰值 HBM 与 workspace 大小单独测量,不能用 metadata 省下的约 112 KiB 代替显存容量结论
- 如果满 buffer 或小 batch 的调度成本抵消收益,应考虑适用范围或策略阈值;任何自动切换仍是待评估设计
主要结论
- 1.endpoint 编码的是带对齐间隙的 live-row 结束位置,不是原始 counts 的普通前缀和
- 2.同一范围契约必须跨越两次 GEMM 与中间 activation;padding 未写要求消费者不读作有效数据
- 3.少执行、少 metadata、少 workspace 是三个不同结论;本实现没有缩小主 activation workspace
- 4.作者报告的 9.36% 是局部 FFN 配对收益,不能推广成全模型或全部 Blackwell 配置的承诺
待验证问题
- 真实 serving 流量中的 live/capacity 分布与最慢 expert rank 是否足以保留 FFN 收益?
- 在 SM103、其他激活函数或不同 scale format 下,dispatch 与性能边界如何变化?
- 动态启停 expert-aware activation 能否覆盖满 buffer 的额外成本,又不破坏 graph 稳定性?
来源与核验边界
- [1] vLLM PR #59044:当前状态、作者测试与适用边界
- [2] 固定 head:scatter 生成带对齐间隙的 endpoint
- [3] 固定 head:布局元数据分配与原 scatter 路径
- [4] 固定 head:设备/激活 guard 与三阶段数据流
- [5] 固定 head:packed SiLU kernel 的边界与 launch
- [6] 固定 head:graph replay、poisoned padding 与 bitwise 测试
- [7] 评审讨论:CUDA 与 ROCm 测试范围仍需区分
- [8] SGLang 固定 head:对齐区间包含 padding,capacity tail 才保留 sentinel
- [9] SGLang 固定 head:对应区间与 sentinel 测试定义
来源状态核验于 2026-09-30 08:00 UTC;本篇由 AI 辅助检索、阅读固定版本源码并整理,属于已有日报的源码深化。GPU 性能与模型准确性均来自 PR 作者报告,本次没有运行 GPU 或独立复现;仅执行了 CPU 整数范围模型检查,其结果不代表实际 kernel 正确性。原 PR 同样披露使用 Codex 辅助实现与验证。 2026-10-01 补充 SGLang DeepEP v2 的 aligned-segment 源码对照,固定 head 802c326;vLLM 原 PR 的 head 和未合并状态经复核未变。本次新增部分仅阅读源码与测试定义,没有运行相关 CPU/GPU 测试。