海光 DCU 算子优化:为什么 1.32x 仍可能不值得接入
摘要
性能表格最吸引眼球的通常是加速比,但在大模型推理中,真正决定端到端价值的往往是“每次调用究竟省了多少微秒”。
本文整理三组海光 DCU gfx936 本地实测。第一组 kernel 达到 1.31631x,第二组达到 1.18939x,第三组甚至完成了 314/314 的精确修复;但它们最终都没有进入完整服务。原因并不是实现失败,而是每层绝对节省只有 1.76-3.23 微秒,乘上层数后仍不足以改变约 44 ms/token 的 Decode 主体。
这篇文章讨论一种比“看加速比”更可靠的 DCU 优化预算方法。
1. 加速比会放大小算子的视觉效果
假设一个 kernel 从 13 微秒降到 10 微秒:
speedup = 13 / 10 = 1.30x absolute saving = 3 us1.30x 看起来很明显,但如果完整 Decode 每 token 需要 44 ms,那么单层 3 微秒只占:
3 us / 44,000 us = 0.0068%只有当这个 kernel 在很多层、每个 token 都稳定命中时,才可能积累出可见收益。
更实用的预算公式是:
saving_per_token = saving_per_call × calls_per_layer × layer_count × hit_rate然后再与完整 token 时间比较,而不是只看局部 speedup。
2. 案例一:1.31631x,但每层只省 3.10840 微秒
本地测试过一条 fused split GDR HIP kernel。CUDAGraph event median 使用 7 组样本,每组 400 次 replay:
| 路径 | 耗时 |
|---|---|
| 当前 Triton BF16 state | 12.93559 us |
| HIP FP32 swizzled state | 9.82719 us |
| 加速比 | 1.31631x |
| 每层节省 | 3.10840 us |
如果模型中有 48 个相关层,理想化累计节省为:
3.10840 us × 48 = 149.20 us/token = 0.14920 ms/token相对于约 44 ms 的 Decode 时间,上限约为 0.34%。
而且这个估算还没有计入:
- 状态格式转换;
- 额外 FP32 显存流量;
- runtime allocation;
- 图集成和 dispatch 开销。
也就是说,1.31631x 已经是好看的局部数字,但 3.10840 微秒才是决定是否继续投入的数字。
3. 案例二:适配真实布局后,2.89x 变成 1.19x
另一个 GDN 融合原型在上游布局中曾测到:
40.6752 us -> 14.0568 us speedup: 2.8936x saving: 26.6184 us/layer但真实 Qwen3.5 激活布局与该上游 kernel 的输入布局不同。把真实布局和必要的数据整理纳入公平比较后,最终 native flat-layout 结果是:
| 路径 | 耗时 |
|---|---|
| 真实布局基线 | 20.27239 us |
| native flat kernel | 17.04439 us |
| 加速比 | 1.18939x |
| 每层节省 | 3.22800 us |
48 层的理想累计节省:
3.22800 us × 48 = 154.944 us/token = 0.15494 ms/token这个结果并不差。它说明 kernel 已经正确适配了目标布局,也证明了局部融合有效。
但它同样无法跨过端点门槛:完整服务中还有大量 Linear、Attention、状态更新和运行时开销,0.15494 ms/token 很容易被稀释。
这个案例还说明一个常见问题:
上游 benchmark 的基线布局如果比本地生产布局更重,直接照搬加速比会高估收益。
4. 案例三:正确性完全修好,物理上限仍然太小
本地还研究过一种“快速近似结果 + 低置信度精确修复”的 GDN 输出方案。
经过 gfx936 MMAC 路径重建后,选中的 314 行实现了:
vendor exact: 314 / 314从正确性角度看,这是一个完整闭环。但 CUDAGraph 计时为:
| 路径 | 耗时 |
|---|---|
| vendor full | 55.0400 us |
| LLMM1 | 53.2800 us |
| 精确 repair 本身 | 21.4400 us |
| debug + repair | 61.6000 us |
这里有一个决定性的物理上限:
vendor - LLMM1 = 1.7600 us/layer 48 layers = 84.48 us/token即使假设置信度检测和修复完全免费,最多也只能省 1.76 微秒/层。真实实现必然还有检测、索引、repair 和写回开销,因此不可能从这条结构中获得更高的端到端收益。
正确性修到 314/314,并不能改变这条性能上限。
5. 什么时候加速比才有意义
加速比不是无用,而是必须与以下信息一起看:
| 问题 | 需要的证据 |
|---|---|
| 单次省多少 | 绝对微秒差 |
| 一枚 token 调用几次 | profile 调用计数 |
| 有多少层命中 | 模型结构 |
| 所有请求都命中吗 | dispatch marker |
| 能否与其他工作重叠 | CUDAGraph/trace |
| 集成需要额外转换吗 | 完整数据流计时 |
| 最终是否值得 | 端点 A/B |
尤其对 10-30 微秒级 kernel,1.2x、1.3x 很容易出现,但它们可能只对应 2-4 微秒的绝对节省。
相反,一个只快 1.08x 的大权重 GEMV,如果每 token 重复上百次,反而可能产生更明显的服务收益。
6. 给 DCU kernel 设立物理门槛
在写实现之前,可以先反推最低门槛。
假设目标是让 44 ms/token 的 Decode 改善 1%:
required saving = 44 ms × 1% = 0.44 ms/token如果目标 kernel 出现于 48 层:
required per-layer saving = 0.44 ms / 48 ≈ 9.17 us/layer如果还要考虑集成稀释、运行波动和额外开销,standalone 门槛应该更高,而不是刚好等于 9.17 微秒。
先算这个门槛,可以快速淘汰“比例很好看、绝对时间不够”的路线。
7. 海光 DCU 上为什么更要看绝对微秒
本文三组数据都来自 gfx936 的 device-event 或 CUDAGraph 计时。它们反映了海光 DCU kernel 评估中一个很实用的特点:很多 recurrent、gating 和 repair primitive 本身只有十几到几十微秒,比例很容易变得好看,但完整 Decode 仍是数十毫秒量级。
因此,在海光 DCU 上筛选新 kernel 时,可以先用下面的顺序:
gfx936 实机绝对微秒 -> 每 token 命中次数 -> 层数累计 -> 完整服务 TPOT这比先追求一个醒目的 speedup 更节省工程时间,也更适合在论坛中比较不同实现的真实价值。
8. 结论
三组本地 DCU 实验给出了相同结论:
- 1.31631x 对应 3.10840 us/layer;
- 1.18939x 对应 3.22800 us/layer;
- 314/314 精确修复的零成本上限也只有 1.7600 us/layer。
这些实现并非没有技术价值。它们证明了 kernel、布局和数值路径能够成立,但不足以改变完整服务的主要时间墙。
因此,评估 DCU 算子时,建议把表格第一列从 speedup 改成:
每层省多少微秒,每个 token 能累计多少毫秒。
加速比负责描述局部改善,绝对时间预算才负责决定工程方向。
本文数据来自本地固定环境的 CUDAGraph 与 standalone 测量。文中的端到端上限是基于实测每 token 时间和调用层数的物理估算,不等同于已经完成的服务吞吐结果。