GLM-5.2 128K 推理提速近 60%:vLLM 的 DCP 配置拷贝 bug 被揪出并修复
社区用户在 4×DGX Spark 集群上把 GLM-5.2 NVFP4 的 128K 上下文推理从约 15 tok/s…
在 4 张 NVIDIA DGX Spark(GB10)组成的集群上,社区开发者「local-inference-lab」把智谱 GLM-5.2 NVFP4 的 128K 上下文长文本推理速度从约 15 tok/s 拉到了 22–24 tok/s——近乎六成的提升。这次提速不是靠换模型或换硬件,而是来自一行缺失的 vLLM 配置拷贝逻辑被补上,以及整套推理栈 rebase 到更新分支后的净收益。整个过程同时把此前只能在「32K 速度」与「128K 长度」之间二选一的尴尬 trade-off 一并消除。
性能对比:从 15 到 24 tok/s
旧配置(DCP4 / 128K / MTP1)现在都被同一套 DCP4 / 128K 路径覆盖,并可叠加 MTP3 或 MTP4:
- 解码速度(短代码生成,热路径):旧 14.5–15.2 tok/s → 新 22–23 tok/s。
- MTP 接受率:旧版仅 MTP1,接受率约 0.74;新版 MTP1/2/3 分别为 0.90 / 0.79 / 0.67;递归复用的 MTP4 在第 4 位置仍可维持约 0.84。
- 上下文长度:131,072 token。
- 硬件与预算:4× GB10 Spark + MikroTik RoCE,单 rank KV 预算 1.81 GB,与旧配置完全一致。
作者同时给出经验性配置建议:MAX_CUDAGRAPH_CAPTURE_SIZE 需为 num_speculative_tokens + 1 预留余量(例如 MTP4 设为 10),否则启动会报「No valid cudagraph sizes」;MTP3 是保守默认,MTP4 是峰值配置,但偶尔会因 host paging 受影响。
bug 根因:Draft 模型没继承 DCP 配置
vLLM 的 SpeculativeConfig.create_draft_parallel_config() 在为目标模型构造投机解码的 Draft 模型并行配置时,不会拷贝 decode_context_parallel_size 字段,而是在 Draft 侧默认回退为 1。在 TP4 / DCP4 的实际部署下,结果非常隐蔽:
- Draft 模型的 KV cache、metadata、稀疏 indexer 状态被正确地按 DCP 分片(写入端跑在 Target 配置下)。
- 但 Draft 的 attention 完全「以为」自己不在 DCP 下:没有 query all-gather、没有 LSE 合并,全局 top-k 索引被当作本地四分之一缓存来用。
- Tensor dump 显示:四个 rank 中有三个在 attention 处选出空索引,对 64 个 head 中的 48 个直接吐出全零。
- 更「邪恶」的是:紧接着的
o_proj是 row-parallel,其 TP all-reduce 会把四个 rank 不一致的部分结果加成一个所有 rank 完全 bit-identical 的 hidden state——这意味着常规的 cross-rank 一致性校验全都干净通过,bug 完美隐藏在下一层算子背后。
这解释了为什么 MTP1 还能勉强撑住约 0.75 的接受率——单步投机靠 Target 传进来的 hidden state 信号弥补——而 MTP2/3 的递归会因为逐层叠加误差而崩盘,也解释了为什么 KV interleave、ag_rs vs a2a、global vs rank-local top-k、CUDA graph vs eager 等各种旋钮调到底都无法缓解,因为根本不在那条路径上。
排查过程与修复
排查排除了「上游已修」「我自己的旧 fork」「配置类假设」三类可能后,作者在 MLA 解码路径里埋了一个环境变量门控的 tap,导出每层 Draft 的 post-allgather query、实际消费的 top-k、per-rank partial + LSE、merge 输出、metadata 以及原始 fp8 KV 页。DCP1 下用 fp64 参考实现对去量化后的 fp8_ds_mla 缓存跑 attention,与 kernel 输出余弦相似度 ≥ 0.9999,确认探针可信。改到 DCP4 后立即看到 impl.dcp_world_size == 1、合并输出与 partial 完全一致(即根本没跑合并)、DCP 本地序列长度 6/6/5/5 被喂给非 DCP attention 等异常,反向回溯到 create_draft_parallel_config 大约二十分钟。
修复本体约 10 行,对应上游较新 runner 路径已存在的逻辑(这也是大 SM120 机器从未遇到此问题的原因——它们跑在已有修复的代码路径上)。PR 已以草稿形式挂在 github.com/local-inference-lab/vllm/pull/72,并附三份针对 GLM routed checkpoint 的配套补丁与完整证据。
复现与生产化
部署脚本、镜像配方仍集中于原仓库 m9e/blackwell-llm-docker 的 recipes/4x-spark-cluster/glm52-b12x-spark/ 目录下。新引入的生产入口为 start-glm52-production.sh,固定使用 DCP4 / MTP3 / 128K,关闭诊断输出;底层 base image 已升级到 local-inference-lab/vllm 的 eldritch 分支(6 月 29 日 + b12x),叠 5 个文件 overlay——包括原帖里的 Spark Ray-startup 修复、post-load malloc_trim,以及这次的 DCP Draft 修复。脚本侧的 build 入口亦同步更新,开发者可直接基于新配置跑出文中给出的 22–24 tok/s。
