## 开场
在海光 DCU 上优化 GEMM,常见做法是写一个新 kernel;但另一条更低成本的路线,是检查当前 rocBLAS/Tensile 库中是否已经存在更适合目标 shape 的 solution。
本地 Qwen3.5-27B 长上下文 实验中,我们没有全局替换 GEMM,也没有扫描所有 token 长度,而是只针对五个高频 q=4096 BF16 shape 选择更快的 Tensile solution。
最终同环境稳态 A/B 得到:
```text
output throughput : 16.428000 -> 16.583027 tok/s
gain: +0.9437%
mean TTFT: 3141.898 -> 3035.589 ms
texts: exact 10/10
tokens: 1809 -> 1809
```
这是一条很典型的海光 DCU vendor-library 优化:改动不大,收益也不是数量级提升,但方向稳定、数值精确,而且能够进入完整服务。
---
## 1. 为什么目标锁定 q=4096
长上下文 Prefill 会把输入分成较大的 token chunk。在这套本地运行路径中,q=4096 是重复出现的主要计算形状。
固定 M=4096 后,很多 Linear 会变成规则的大 GEMM。与 Decode 的 M=1 不同,这类问题具有:
- 足够大的并行度;
- 相对稳定的矩阵形状;
- 多层重复命中;
- 更容易被 Tensile 的固定 solution 覆盖。
因此,优化目标不是“所有 GEMM”,而是“完整 q=4096 chunk 中最常出现的五类 GEMM”。
---
## 2. 五个真实 BF16 shape
本地筛选的 shape 如下:
| 模块 | M | N | K |
|---|---:|---:|---:|
| MLP gate/up | 4096 | 34816 | 5120 |
| MLP down | 4096 | 5120 | 17408 |
| GDN output | 4096 | 5120 | 6144 |
| GDN qkvz | 4096 | 16384 | 5120 |
| Full-Attention QKV | 4096 | 14336 | 5120 |
这五项覆盖了 Qwen3.5 中 MLP、GDN 和 Full-Attention 的主要 Prefill 投影。
每个 shape 都使用原始 BF16 输入与输出,并保持 FP32 accumulation 语义。候选 solution 的完整 BF16 输出 hash 与默认 rocBLAS 路径一致。
换句话说,这次优化改变的是 vendor solution 选择,不是模型数学和数据类型。
---
## 3. Standalone 先回答两个问题
### 3.1 数值是否一致
五个 shape 的完整输出 hash 全部匹配默认 rocBLAS。
这里没有使用抽样误差或相对 L2 作为替代,而是对完整 BF16 输出进行比较。
### 3.2 是否有足够的物理预算
根据五个 shape 的 standalone 时间和每个 q=4096 chunk 中的实际调用次数,模型估算每个完整 chunk 可以节省约:
```text
39.5 ms
```
这个数字不能直接当作端点收益,但足够支持继续做完整服务 A/B。
如果 standalone 只省几毫秒/请求,进入端点后很可能被其他算子稀释;39.5 ms/chunk 至少跨过了继续验证的物理门槛。
---
## 4. 稳态端点协议
为了避免首次编译、图捕获和 shape cache 污染,每个新服务都运行:
```text
完整固定 10 请求一次,作为 prime
-> 再运行同一组 10 请求
-> 只记录第二次
```
基线与五-shape 配置使用相同:
- 海光 DCU gfx936 环境;
- 模型和 BF16 权重;
- 请求集;
- 编译缓存条件;
- 并发和采样参数。
唯一差异是五个 q=4096 GEMM 的 Tensile solution 选择。
---
## 5. 完整服务结果
| 指标 | 基线 | 五-shape 配置 |
|---|---:|---:|
| output throughput | 16.428000 tok/s | 16.583027 tok/s |
| 吞吐变化 | - | +0.9437% |
| mean TTFT | 3141.898 ms | 3035.589 ms |
| p99 TTFT | 3753.467 ms | 3640.119 ms |
| p99 TPOT | 43.752 ms | 43.818 ms |
| 输出 token | 1809 | 1809 |
| 文本 | 10/10 exact | 10/10 exact |
| failed | 0 | 0 |
mean TTFT 下降:
```text
3141.898 - 3035.589
= 106.309 ms
```
p99 TPOT 基本不变,符合优化位置:五个 solution 只作用于 q=4096 Prefill,不改变逐 token Decode 主路径。
这让结果的物理解释很干净:
```text
Prefill GEMM 更快
-> TTFT 下降
-> TPOT 基本不变
-> 完整输出保持一致
```
---
## 6. 为什么只选五个 shape
看到五个 shape 有收益后,很自然会想继续扩展到更多 token 长度和更多 solution。
但 shape-specific dispatch 的价值不取决于数量,而取决于:
```text
单次节省
× 实际命中次数
× 请求中的时间占比
```
q=4096 是高频主 chunk;大量尾部 M 值只在部分请求中出现。继续增加低频 rows 会扩大配置复杂度,却未必形成可测的端点收益。
因此,这次策略的关键不是“找到五个最快 solution”,而是:
> 只保留高覆盖、完整输出一致、端点能兑现的五个 solution。
---
## 7. 对海光 DCU 开发者的意义
rocBLAS/Tensile 已经为 gfx936 提供了大量预生成 kernel,但默认 heuristic 不一定在每个固定模型 shape 上选择局部最优解。
对于 shape 高度稳定的大模型 Prefill,可以考虑:
1. 从 profile 提取真实 M、N、K;
2. 用目标 DTK 环境筛选 Tensile solution;
3. 比较完整 BF16 输出;
4. 按真实调用次数估算绝对节省;
5. 用对称 warmup 的端点 A/B 验证 TTFT;
6. 把 solution 与 DTK、gfx936 和 shape 一起版本化。
Tensile solution index 具有环境依赖性。换 DTK、库文件或架构后,应重新验证,不能把本地编号当成通用参数传播。
---
## 8. 结论
五个 q=4096 BF16 GEMM solution 在海光 DCU 本地稳态服务中带来了:
```text
+0.9437% output throughput
-106.309 ms mean TTFT
10/10 文本一致
1809 -> 1809 tokens
failed = 0
```
它不是一个夸张的大幅加速,却是一条完整成立的 vendor-library 优化链路:
> 真实 shape、精确输出、足够的物理预算和端点 TTFT 同时对齐。
对于海光 DCU 长上下文 Prefill,合理选择现有 Tensile solution,有时比从零写 kernel 更快到达可用结果。
---
本文数据仅绑定本地 gfx936、对应 DTK/rocBLAS/Tensile 版本与 Qwen3.5 shape。不同软件版本或硬件型号需要重新筛选和验证。
————————————————
版权声明:本文为CSDN博主「che1524」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/che1524/article/details/162955866