## 实验摘要
低精度通常意味着更少的显存流量和更高的矩阵指令吞吐,因此“FP8/INT8 应该更快”是一个合理假设。
本文报告两组海光 DCU gfx936 本地实验:
1. M=4096 大 GEMM 的运行时动态 INT8;
2. 长序列 Attention 的 FP8 KV Cache。
两组实现都成功运行,输出 finite 且可重复;INT8 kernel 甚至确认生成了原生 INT8 MMAC 指令。但最终结果分别只有 BF16 路径的 0.03409x-0.03888x 和 0.3566x-0.4101x。
结论不是“低精度在 DCU 上无效”,而是:
> 如果低精度转换无法在热路径之外摊销,转换与反量化成本可能远大于节省的带宽和计算。
---
## 1. 实验一:M=4096 动态 INT8 GEMM
### 1.1 实验形状
~~~text
M = 4096
N = 34816
K = 5120
输入权重 = BF16
候选计算 = invocation-local INT8
~~~
候选每次调用都直接读取 BF16 权重,在 kernel 内计算 scale、量化为 INT8、执行 INT8 MMAC,再完成反量化。
它没有复用预量化权重,因此测试的是“运行时动态量化能否靠原生 INT8 指令获得净收益”。
### 1.2 能力验证
在 gfx936 上,64x64x64 探针可以正常编译和执行。生成汇编中确认出现:
~~~text
v_mmac_i32_16x16x32_i8
~~~
两个候选输出都满足:
- finite;
- 重复运行确定;
- 相对 L2 位于 0.00787-0.01258。
因此,失败原因不是“编译器没有使用 INT8 指令”。
### 1.3 性能结果
| 路径 | 耗时 | 相对 BF16 | relative L2 |
|---|---:|---:|---:|
| rocBLAS BF16 | 4.371945 ms | 1.00000x | 参考 |
| 动态 INT8 scalar scale | 128.237834 ms | 0.03409x | 0.011867 |
| 动态 INT8 row/column scale | 112.447805 ms | 0.03888x | 0.007887 |
BF16 路径在该形状上达到约 334.01 TFLOP/s。动态 INT8 虽然使用了原生 MMAC,但仍慢了一个数量级以上。
### 1.4 为什么会这样
每个 live tile 都要重复完成:
~~~text
读取 BF16 权重
-> 计算 max/reduction
-> 生成 scale
-> rounding 和 INT8 conversion
-> INT8 MMAC
-> dequantization
~~~
而 M 维包含多个独立 block,同一权重 tile 的量化工作会被重复执行。
理论上的 INT8 计算优势,无法覆盖:
- BF16 权重仍然要完整读取;
- scale reduction;
- 数据转换;
- 反量化;
- tile 间无法复用的量化成本。
---
## 2. 实验二:FP8 KV Cache Attention
### 2.1 实验范围
第二组实验固定:
~~~text
Q dtype: BF16
K/V dtype: FP8 e4m3fn
cache layout: NHD paged KV
计时: CUDAGraph
样本: 2 组 × 每组 20 次 replay
~~~
候选使用 page-contiguous 遍历,希望减少通用 FP8 路径中的页表和地址计算开销。
### 2.2 性能结果
| KV 长度 | BF16 路径 | 通用 FP8 | Page-contiguous FP8 | FP8/BF16 |
|---:|---:|---:|---:|---:|
| 8192 | 0.084160 ms | 0.211556 ms | 0.205236 ms | 0.4101x |
| 16384 | 0.120100 ms | 0.337748 ms | 0.323552 ms | 0.3712x |
| 32768 | 0.278532 ms | 0.797231 ms | 0.781087 ms | 0.3566x |
三种长度的几何平均:
~~~text
FP8 page-contiguous / BF16 page-contiguous
= 0.3786x
~~~
这里的 0.3786x 表示 FP8 更慢,不是更快。换算后,FP8 路径约为 BF16 的 2.4-2.8 倍耗时。
Page-contiguous FP8 相比通用 FP8 快约 2%-4%,且两者逐位一致,说明地址遍历优化本身有效;但它只消除了 FP8 路径中的小部分开销。
### 2.3 数值结果
FP8 相对 BF16 的误差为:
| KV 长度 | relative L2 | p99 abs | max abs |
|---:|---:|---:|---:|
| 8192 | 0.03863 | 0.001709 | 0.002380 |
| 16384 | 0.03868 | 0.001282 | 0.001892 |
| 32768 | 0.03883 | 0.000916 | 0.001404 |
输出都为 finite,FP8 page-contiguous 与通用 FP8 在三种长度上逐位一致。因此数据能够区分两个问题:
1. 新地址遍历实现是否正确:是;
2. FP8 相对 BF16 是否值得:在这条路径上不是。
---
## 3. 两组实验的共同点
### 3.1 低精度存储不等于低精度热路径
动态 INT8 仍需读取 BF16 权重;FP8 KV 在参与 BF16 dot 之前仍需软件反量化。数据更小,并不代表计算链路已经原生低精度化。
### 3.2 转换成本必须被复用
低精度最有利的情况通常是:
- 权重或缓存已经以目标格式存在;
- scale 可以跨大量计算复用;
- 硬件支持端到端的低精度 load、dot 和 accumulate;
- 不需要在每个 tile 重复量化。
本实验恰好相反:转换位于高频热路径,并且难以摊销。
### 3.3 原生指令存在仍不够
动态 INT8 已确认使用 v_mmac_i32_16x16x32_i8,但整体只有 0.03409x-0.03888x。
这说明性能链路是:
~~~text
总耗时
= 数据准备
+ scale/reduction
+ conversion
+ MMAC
+ dequantization
+ writeback
~~~
只优化其中的 MMAC,并不能保证整个 kernel 更快。
---
## 4. 低精度实验应怎样设门槛
建议至少同时报告:
1. 原始数据读取量;
2. 转换是否发生在计时窗口内;
3. scale 的生命周期和复用次数;
4. 汇编是否真的使用目标指令;
5. 低精度与 BF16 的完整链路耗时;
6. finite、relative L2、p99 abs 和 max abs;
7. CUDAGraph 与完整服务是否得到相同方向。
如果转换不在计时窗口内,也必须明确说明预处理成本和缓存生命周期,否则低精度结果很容易被高估。
---
## 5. 这组结果反映了海光 DCU 的什么
动态 INT8 汇编已经确认使用 gfx936 原生 v_mmac_i32_16x16x32_i8 指令,因此不能把失败简单归因于“海光 DCU 没有 INT8 能力”。FP8 KV 也能稳定运行,page-contiguous 地址路径还能比通用 FP8 略快。
真正没有打通的是端到端数据流:BF16 到低精度的转换、scale reduction 和反量化仍停留在高频热路径。
这对海光 DCU 低精度开发的启示是:硬件指令可用性只是第一关。下一步更值得关注的是 DTK/算子库能否提供原生低精度 load、dot、accumulate,以及 scale 和低精度表示能否被足够多的计算复用。
## 6. 结论
本地两组 DCU 实测得到:
~~~text
动态 INT8 M=4096 GEMM:
0.03409x / 0.03888x BF16 性能
FP8 KV page-contiguous:
0.3786x BF16 性能
relative L2 约 0.0386-0.0388
~~~
两条路径都不是因为“不能运行”而失败。它们能够编译、执行并产生稳定输出,INT8 也确实使用了原生 MMAC。
真正的问题是,低精度转换发生在热路径中,且无法被足够多的计算复用。
因此,对 DCU 低精度优化更准确的提问不是:
> INT8 或 FP8 的峰值有多高?
而是:
> 从 BF16 输入到最终输出的完整数据流,是否真的减少了总工作量?
---
本文数据只代表该 gfx936 软件路径、模型形状和实现方式。它不否定具有预量化权重、原生 FP8 dot 或不同 scale 生命周期的其他低精度方案。