我在之前的博客中介绍了自己写的 SM89 上的 FP8 Blockwise GEMM CUDA kernel。后来看到 Qwen3 官方文档中的 H20 卡上的性能测试数据,本文仿照 Qwen3 文档的测试方法,对新 Kernel 进行更多 Qwen3 FP8 模型在 L40S 的对比性能测试。
总结放最前
对下面的速度指标可以有几个观察:
- 新 Kernel 平均提升性能 18%。依照 Qwen3 官方的测试用例,平均下来新 Kernel 对端到端推理的性能优化幅度是 18%。
- 速度优化的比例随着模型参数的增加先升后降。大概是因为最小模型的参数量太小,调度占比更高;而更大的模型参数量太大,访存占比升高。
- A3B 的模型优于 4B 的模型。但我在更多的测试后发现,A3B 仅在 batch_size 2 以下性能优于 4B,在超过 2 以后,A3B 的性能曲线增长远不如 4B 的性能曲线。我的测试在 L40S 上,4B 的最大吞吐大约是 A3B 的 1.7 倍,8B 的最大吞吐大约是 A3B 的 1.4 倍。这大概是因为 A3B 模型计算时需要更多的显存带宽。
- 新 Kernel 下 L40S 的平均吞吐是 H20 的 56% (triton:47%)。可以用作单卡运行 Qwen3 模型时,L40S 和 H20 的性价比大略预估。
下面是具体的测试环境和测试数据:
1. 测试环境
硬件使用的是 NVIDIA L40S,评测的每个模型都跑在 1 张 L40S 卡上。Docker 使用的是 SGLang 的开发镜像:lmsysorg/sglang:dev。
SGLang 和 SGL-Kernel 可以根据我的这篇博客中介绍的方法自行编译,或者从下面链接下载我编译好的 Python wheel 包: https://github.com/solrex/sglang/releases/tag/sm89-fp8 然后通过下面命令安装:
pip install sgl_kernel-0.1.5-cp39-abi3-linux_x86_64.whl
pip install sglang-0.4.6.post5-py3-none-any.whl
2. 测试设置
SGLang 的测试设置基本与 Qwen3 官方的测试设置相同,启动参数主要设置了这些。因为下面测试的 batch size 只有 1,所以 --cuda-graph-max-bs 只设置了 8,正常批量压测时最好设置到 64 以上。
python3 -m sglang.launch_server --model-path MODEL_PATH --tp 1 --allow-auto-truncate --enable-mixed-chunk --context-length 40960 --enable-torch-compile --torch-compile-max-bs 8 --cuda-graph-max-bs 8 --port ****
使用以上方式启动,使用的是默认的 FP8 Blockwise Triton Kernel;如果希望使用新的 CUDA 实现的 FP8 Blockwise Kernel,只需要在启动前增加环境变量:
export SGLANG_SUPPORT_CUTLASS_BLOCK_FP8=1
所以后面的测试,主要是比较 Triton 和 CUDA 实现的 FP8 Blockwise GEMM Kernel 的性能区别。
指标中加上“triton”前后缀的,即为 Triton Kernel 的指标;指标中加上“cuda”前后缀的,即为我新实现的 CUDA Kernel 的指标。
3. 准确率速测
首先测一下新 Kernel 的实现是否有严重的问题,这里使用 SGLang 代码库中的 benchmark/gsm8k 进行一下速测。速测有 512 token 截断,测试 500 条,仅用于粗略比较是否有 bug,不能充分说明模型的能力差距。
速测命令如下,通过 port 将请求发送给不同的模型:
python3 bench_sglang.py --num-questions 500 --port ****
模型 | triton-准确率 | cuda-准确率 |
---|---|---|
Qwen3-0.6B-FP8 | 41.0% | 43.4% |
Qwen3-1.7B-FP8 | 69.0% | 68.8% |
Qwen3-4B-FP8 | 85.4% | 86.2% |
Qwen3-8B-FP8 | 92.0% | 92.2% |
Qwen3-14B-FP8 | 89.2% | 86.2% |
Qwen3-32B-FP8 | 80.8% | 83.8% |
Qwen3-30B-A3B-FP8 | 90.6% | 88.2% |
可以看到我写的 CUDA Kernel 在准确率上与官方的 triton Kernel 没有明显的差距。
4. 性能测试结果
为了与 Qwen3 官方的性能指标进行对齐,我采用了完全相同的请求参数,即:batch_size 固定为 1,生成长度固定为 2048,输入长度使用 1、6144、14336、30720,速度指标使用 (输入+输出)/时间。
Qwen3 官方如此设置大概是为了照顾 Transformers 库,但这种测试方式并不常见。batch_size 为 1 很难测出来最大吞吐,30K 的输入长度在业务场景下也不算常见,最终指标受 prefill 影响很大。为了显示生成的性能,我增加了一列平均 ITL 指标。
指标列说明:
- 输入:输入的长度,单位是 token;
- H20:Qwen3 官方文档中 H20 的速度,单位是 tokens/s;
- L40S-triton:L40S 上 SGLang 官方 triton FP8 blockwise GEMM 实现的速度,单位是 tokens/s;
- L40S-cuda:L40S 上替换为我实现的 CUDA Kernel 实现的速度,单位是 tokens/s;
- 速度提升的百分比:L40S-cuda / L40S-triton - 100%
- ITL-triton:SGLang 官方 triton 实现下生成每个 token 的平均间隔,单位是毫秒 ms;
- ITL-cuda:我的 CUDA 实现下生成每个 token 的平均间隔,单位是毫秒 ms;
4.1 Qwen3-0.6B-FP8 (SGLang sm89-fp8 branch)
输入 | H20 | L40S-triton | L40S-cuda | 速度提升 | ITL-triton | ITL-cuda |
---|---|---|---|---|---|---|
1 | 458.03 | 250.36 | 303.09 | +21.1% | 3.98 | 3.28 |
6144 | 1572.95 | 805.75 | 936.57 | +16.0% | 4.94 | 4.24 |
14336 | 2689.08 | 1270.00 | 1427.09 | +12.0% | 6.26 | 5.57 |
30720 | 3819.86 | 1773.35 | 1918.70 | +8.0% | 8.97 | 8.28 |
4.2 Qwen3-1.7B-FP8 (SGLang sm89-fp8 branch)
输入 | H20 | L40S-triton | L40S-cuda | 速度提升 | ITL-triton | ITL-cuda |
---|---|---|---|---|---|---|
1 | 333.90 | 148.35 | 197.24 | +32.9% | 6.73 | 5.05 |
6144 | 1198.20 | 518.43 | 661.93 | +27.7% | 7.69 | 6.01 |
14336 | 2095.61 | 877.28 | 1071.52 | +22.1% | 9.08 | 7.43 |
30720 | 3165.32 | 1356.38 | 1576.85 | +16.2% | 11.74 | 10.07 |
4.3 Qwen3-30B-A3B-FP8 (SGLang sm89-fp8 branch)
输入 | H20 | L40S-triton | L40S-cuda | 速度提升 | ITL-triton | ITL-cuda |
---|---|---|---|---|---|---|
1 | 155.55 | 102.83 | 117.38 | +14.2% | 9.70 | 8.49 |
6144 | 551.34 | 377.75 | 426.18 | +12.8% | 10.54 | 9.34 |
14336 | 945.13 | 680.58 | 757.84 | +11.4% | 11.70 | 10.50 |
30720 | 1405.91 | 1133.15 | 1238.20 | +9.3% | 14.05 | 12.85 |
4.4 Qwen3-4B-FP8 (SGLang sm89-fp8 branch)
输入 | H20 | L40S-triton | L40S-cuda | 速度提升 | ITL-triton | ITL-cuda |
---|---|---|---|---|---|---|
1 | 200.61 | 75.19 | 103.18 | +37.2% | 13.28 | 9.67 |
6144 | 662.26 | 278.90 | 370.24 | +32.8% | 14.31 | 10.76 |
14336 | 1066.23 | 498.17 | 638.03 | +28.1% | 16.02 | 12.50 |
30720 | 1467.71 | 821.34 | 1002.76 | +22.1% | 19.42 | 15.90 |
4.5 Qwen3-8B-FP8 (SGLang sm89-fp8 branch)
输入 | H20 | L40S-triton | L40S-cuda | 速度提升 | ITL-triton | ITL-cuda |
---|---|---|---|---|---|---|
1 | 150.25 | 53.47 | 66.56 | +24.5% | 18.69 | 15.00 |
6144 | 516.64 | 202.20 | 248.00 | +22.7% | 19.75 | 16.10 |
14336 | 859.92 | 371.91 | 447.97 | +20.5% | 21.47 | 17.82 |
30720 | 1242.24 | 641.60 | 751.65 | +17.2% | 24.88 | 21.23 |
4.6 Qwen3-14B-FP8 (SGLang sm89-fp8 branch)
输入 | H20 | L40S-triton | L40S-cuda | 速度提升 | ITL-triton | ITL-cuda |
---|---|---|---|---|---|---|
1 | 97.11 | 34.20 | 39.30 | +14.9% | 29.22 | 25.46 |
6144 | 342.95 | 130.36 | 148.56 | +13.9% | 30.65 | 26.89 |
14336 | 587.33 | 246.01 | 278.15 | +13.1% | 32.48 | 28.72 |
30720 | 880.72 | 441.62 | 492.80 | +11.6% | 36.17 | 32.40 |
4.7 Qwen3-32B-FP8 (SGLang sm89-fp8 branch)
输入 | H20 | L40S-triton | L40S-cuda | 速度提升 | ITL-triton | ITL-cuda |
---|---|---|---|---|---|---|
1 | 46.17 | 15.95 | 18.31 | +14.8% | 62.70 | 54.59 |
6144 | 165.71 | 61.36 | 70.13 | +14.3% | 65.14 | 56.98 |
14336 | 287.60 | 117.39 | 133.28 | +13.5% | 68.09 | 59.96 |
30720 | 436.59 | FAIL | FAIL |