优化Qwen3 - FP8模型L40S卡性能提升18%

我在之前的博客中介绍了自己写的 SM89 上的 FP8 Blockwise GEMM CUDA kernel。后来看到 Qwen3 官方文档中的 H20 卡上的性能测试数据,本文仿照 Qwen3 文档的测试方法,对新 Kernel 进行更多 Qwen3 FP8 模型在 L40S 的对比性能测试。

总结放最前

对下面的速度指标可以有几个观察:

  1. 新 Kernel 平均提升性能 18%。依照 Qwen3 官方的测试用例,平均下来新 Kernel 对端到端推理的性能优化幅度是 18%。
  2. 速度优化的比例随着模型参数的增加先升后降。大概是因为最小模型的参数量太小,调度占比更高;而更大的模型参数量太大,访存占比升高。
  3. A3B 的模型优于 4B 的模型。但我在更多的测试后发现,A3B 仅在 batch_size 2 以下性能优于 4B,在超过 2 以后,A3B 的性能曲线增长远不如 4B 的性能曲线。我的测试在 L40S 上,4B 的最大吞吐大约是 A3B 的 1.7 倍,8B 的最大吞吐大约是 A3B 的 1.4 倍。这大概是因为 A3B 模型计算时需要更多的显存带宽。
  4. 新 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-FP841.0%43.4%
Qwen3-1.7B-FP869.0%68.8%
Qwen3-4B-FP885.4%86.2%
Qwen3-8B-FP892.0%92.2%
Qwen3-14B-FP889.2%86.2%
Qwen3-32B-FP880.8%83.8%
Qwen3-30B-A3B-FP890.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)

输入H20L40S-tritonL40S-cuda速度提升ITL-tritonITL-cuda
1458.03250.36303.09+21.1%3.983.28
61441572.95805.75936.57+16.0%4.944.24
143362689.081270.001427.09+12.0%6.265.57
307203819.861773.351918.70+8.0%8.978.28

4.2 Qwen3-1.7B-FP8 (SGLang sm89-fp8 branch)

输入H20L40S-tritonL40S-cuda速度提升ITL-tritonITL-cuda
1333.90148.35197.24+32.9%6.735.05
61441198.20518.43661.93+27.7%7.696.01
143362095.61877.281071.52+22.1%9.087.43
307203165.321356.381576.85+16.2%11.7410.07

4.3 Qwen3-30B-A3B-FP8 (SGLang sm89-fp8 branch)

输入H20L40S-tritonL40S-cuda速度提升ITL-tritonITL-cuda
1155.55102.83117.38+14.2%9.708.49
6144551.34377.75426.18+12.8%10.549.34
14336945.13680.58757.84+11.4%11.7010.50
307201405.911133.151238.20+9.3%14.0512.85

4.4 Qwen3-4B-FP8 (SGLang sm89-fp8 branch)

输入H20L40S-tritonL40S-cuda速度提升ITL-tritonITL-cuda
1200.6175.19103.18+37.2%13.289.67
6144662.26278.90370.24+32.8%14.3110.76
143361066.23498.17638.03+28.1%16.0212.50
307201467.71821.341002.76+22.1%19.4215.90

4.5 Qwen3-8B-FP8 (SGLang sm89-fp8 branch)

输入H20L40S-tritonL40S-cuda速度提升ITL-tritonITL-cuda
1150.2553.4766.56+24.5%18.6915.00
6144516.64202.20248.00+22.7%19.7516.10
14336859.92371.91447.97+20.5%21.4717.82
307201242.24641.60751.65+17.2%24.8821.23

4.6 Qwen3-14B-FP8 (SGLang sm89-fp8 branch)

输入H20L40S-tritonL40S-cuda速度提升ITL-tritonITL-cuda
197.1134.2039.30+14.9%29.2225.46
6144342.95130.36148.56+13.9%30.6526.89
14336587.33246.01278.15+13.1%32.4828.72
30720880.72441.62492.80+11.6%36.1732.40

4.7 Qwen3-32B-FP8 (SGLang sm89-fp8 branch)

输入H20L40S-tritonL40S-cuda速度提升ITL-tritonITL-cuda
146.1715.9518.31+14.8%62.7054.59
6144165.7161.3670.13+14.3%65.1456.98
14336287.60117.39133.28+13.5%68.0959.96
30720436.59FAILFAIL

在 32 张 L40S/L20 上运行 DeepSeek-R1/V3 原版 FP8 模型

上文讲到,FP8 模型之所以无法 TP32 运行,主要因为 DeepSeek R1/V3 模型保存的参数是 FP8 128x128 量化的。Attention 还好,128 个头做 TP16 或者 TP32 都没问题,问题主要出在专家的计算上。

前三层 MLP 的 intermediate_size 是 18432,18432 做 TP16 是 1152,相当于 9 个 128。但如果做了 TP32,就是 4.5 个 128,这会导致参数无法切分在 128 边界上,无法支持按 128 block 量化。路由专家也类似,moe_intermediate_size 做 TP32 相当于 0.5 个 128。

缩小 DeepSeek-R1/V3 的量化块到 64x64

如果想支持 TP32,一个很显然的路径就是把量化方式改成按 64x64 分块量化。本来这是一个比较复杂的操作,但我想了一个取巧的办法:直接把 128x128 的缩放系数,复制到 4 份。

为了方便理解这个方案,我画了一张图。假设我们有一个 4x8 的 INT32 矩阵,按照 4x4 block 量化到 INT8,它会分成 1x2 个 4x4 的块,每块一个缩放系数,那就是 1x2 个缩放系数。如下图所示,第一个块的缩放系数是 7.3465,它是通过第一个块里的最大绝对值 |-933|/127 得到的,同理第二个缩放系数来自 974/127。

那如果我想将它的量化 block 缩小到 2x2,理论上我应该计算每个 2x2 block 的最大绝对值,然后 /127 得到缩放系数,这样精度损失最小。可是我嫌麻烦,偷个懒,我直接把 4x4 的缩放系数复制 4 份,虽然精度有损失,但好处是在计算上与 4x4 的量化结果完全一致。换句话说,就是原汁原味,纯血参数。

将这个逻辑迁移到 DeepSeek FP8 量化的 128x128 block 缩小到 64x64,原理是一样的,也是将 scale 参数矩阵进行 2x2 等值扩充。通过非常简单的参数处理,就能够实现将 DeepSeek 原始模型转成 64x64 的分块量化,然后就可以用 SGLang 加载运行了。

运行方法

我们以昨天发布的 DeepSeek-V3-0324 为例,逐步说明如何使用这种方法在 L40S 和 L20 上运行 FP8 满血+纯血版的 DeepSeek-V3-0324,不需要等待美团再发布 INT8 版本。

假设你已经下载好了模型,在 /workspace/DeepSeek-V3-0324/。那你需要先下载我的开发分支,并通过源代码安装它(如果遇到困难,建议你在 SGLang 的开发 Docker 中执行它):

git clone -b l40s-dsfp8 https://github.com/solrex/sglang.git
cd sglang
pip install -e "python[all]" --find-links https://flashinfer.ai/whl/cu124/torch2.5/flashinfer-python

然后用下面这个脚本,将 128x128 量化的 DeepSeek-V3-0324,转换到 64x64 量化的 DeepSeek-V3-0324-Block64x64:

python3 scripts/resize_block_size.py /workspace/DeepSeek-V3-0324/

当你在 4 台(或 8 台)机器上都完成了 SGLang 安装和参数拷贝后,就可以用下面的命令来启动 SGLang 服务了。注意替换 MASTER_IP、mlx5_? 和 TCP_IFACE 到正确的值。

# MASTER_IP: 主节点 IP
# TCP_IFACE: 主网卡接口名,可通过 ifconfig 获取

# 主节点
NCCL_DEBUG=INFO NCCL_IB_GID_INDEX=3 NCCL_IB_HCA=mlx5_? NCCL_SOCKET_IFNAME=TCP_IFACE GLOO_SOCKET_IFNAME=TCP_IFACE python3 -m sglang.launch_server --model /workspace/DeepSeek-V3-0324-Block64x64/ --tp 32 --dist-init-addr MASTER_IP:5000 --nnodes 4 --node-rank 0 --trust-remote --enable-torch-compile --torch-compile-max-bs 32 --cuda-graph-max-bs 32 --host 0.0.0.0 --port 8000

# 从节点 1
NCCL_DEBUG=INFO NCCL_IB_GID_INDEX=3 NCCL_IB_HCA=mlx5_? NCCL_SOCKET_IFNAME=TCP_IFACE GLOO_SOCKET_IFNAME=TCP_IFACE python3 -m sglang.launch_server --model /workspace/DeepSeek-V3-0324-Block64x64/ --tp 32 --dist-init-addr MASTER_IP:5000 --nnodes 4 --node-rank 1 --trust-remote --enable-torch-compile --torch-compile-max-bs 32 --cuda-graph-max-bs 32

# 从节点 2
NCCL_DEBUG=INFO NCCL_IB_GID_INDEX=3 NCCL_IB_HCA=mlx5_? NCCL_SOCKET_IFNAME=TCP_IFACE GLOO_SOCKET_IFNAME=TCP_IFACE python3 -m sglang.launch_server --model /workspace/DeepSeek-V3-0324-Block64x64/ --tp 32 --dist-init-addr MASTER_IP:5000 --nnodes 4 --node-rank 2 --trust-remote --enable-torch-compile --torch-compile-max-bs 32 --cuda-graph-max-bs 32

# 从节点 3
NCCL_DEBUG=INFO NCCL_IB_GID_INDEX=3 NCCL_IB_HCA=mlx5_? NCCL_SOCKET_IFNAME=TCP网卡 GLOO_SOCKET_IFNAME=TCP网卡 python3 -m sglang.launch_server --model /workspace/DeepSeek-V3-0324-Block64x64/ --tp 32 --dist-init-addr MASTER_IP:5000 --nnodes 4 --node-rank 3 --trust-remote --enable-torch-compile --torch-compile-max-bs 32 --cuda-graph-max-bs 32

性能

在 MASTER 节点使用下面的命令进行性能测试(需要先下载测试数据集 ShareGPT_Vicuna_unfiltered/ShareGPT_V3_unfiltered_cleaned_split.json),输入固定 200,输出固定 200,并发 128,测试两轮。

python3 -m sglang.bench_serving --backend sglang-oai --dataset-path /workspace/ShareGPT_Vicuna_unfiltered/ShareGPT_V3_unfiltered_cleaned_split.json --dataset-name random --random-range-ratio 1 --random-input-len 200 --random-output-len 200  --request-rate 128 --num-prompt 256 --max-concurrency 128 --host localhost --port 8000

我测试的性能指标是:

============ Serving Benchmark Result ============
Backend: sglang-oai
Traffic request rate: 128.0
Max reqeuest concurrency: 128
Successful requests: 256
Benchmark duration (s): 98.63
Total input tokens: 51200
Total generated tokens: 51200
Total generated tokens (retokenized): 50971
Request throughput (req/s): 2.60
Input token throughput (tok/s): 519.11
Output token throughput (tok/s): 519.11
Total token throughput (tok/s): 1038.22
Concurrency: 127.26
----------------End-to-End Latency----------------
Mean E2E Latency (ms): 49032.00
Median E2E Latency (ms): 49199.08
---------------Time to First Token----------------
Mean TTFT (ms): 8294.87
Median TTFT (ms): 8306.07
P99 TTFT (ms): 15599.09
---------------Inter-Token Latency----------------
Mean ITL (ms): 205.47
Median ITL (ms): 183.05
P95 ITL (ms): 187.48
P99 ITL (ms): 243.63
Max ITL (ms): 11274.90
==================================================

对照上一篇博客《刷新 32 张 L40S 运行 DeepSeek-R1-INT8 的性能数据》,看起来 FP8 Block 量化的性能比 INT8 Channel 量化的性能要差一些。

代码改动

这次的代码改动不大,主要是参数转换脚本,和一些针对 64x64 的 tunning,以及 warning 的修复。整理好后我会提个 PR 给 SGLang,但这次我不确定这个 PR 是否会被接受,感兴趣的同学可以直接看这个 commit:https://github.com/solrex/sglang/commit/03d34078d8d65983aabc0386391743cc43f535ed or https://github.com/sgl-project/sglang/pull/4860

地震

正当我写到这的时候,忽然手机通知地震了。生平第一次收到,记录一下。我完全没震感,但是有朋友感觉到了。

刷新 32 张 L40S 运行 DeepSeek-R1-INT8 的性能数据

前一篇博客《使 SGLang 支持在 32 张 L40S 上运行 DeepSeek-R1》中提到我那非常特殊的 L40S 显卡配置,结果发现是个大乌龙。

首先,这台机器有 PCIE 4.0 Switch,每张 Switch 上插了 4 张 L40S 显卡。我误会的 PCI-to-PCI 应该是挂了一个给监控屏用的小显卡。

其次,有一张网卡插错位置了。本来应该每 4 张显卡配 1 张双口网卡,其中一张没插到对应的 Switch 上。

最后,3 张网卡 6 个网口,只启用了 1 个网口,有 5 个网口没启用。

所以,实际上所有机内通信走的都是 PCIE,所有跨机通信走的都是主网卡,这……只能怪自己没经验,默认以为交过来的环境都是对的。

折腾了几天,总算搞对了,正确的拓扑如下:

主网卡两个网口做了链路聚合,用作 TCP 通信;PCIE Switch 上的 4 个网口专用作 RDMA 通信。同机两个 NUMA 域双卡之间通信,走 PCIE 大概 11GB/s,走 GDRDMA 能提升到 19GB/s。最关键的是多机通信,从单网口的小水管提升到了 4 网口 GDRDMA。

采用与上篇文章同样不严谨的测试方式:

# 128 并发
[TP0] Decode batch. #running-req: 128, #token: 86816, token usage: 0.44, gen throughput (token/s): 777.92, #queue-req: 0, # 之前 565.73, 1.37x
# 32 并发
[TP0] Decode batch. #running-req: 32, #token: 8923, token usage: 0.04, gen throughput (token/s): 457.66, #queue-req: 0, # 之前 260.73,1.75x
# 4 并发
[TP0] Decode batch. #running-req: 4, #token: 1437, token usage: 0.01, gen throughput (token/s): 153.98, #queue-req: 0, # 之前 42.3,3.64x
# 1 并发
[TP0] Decode batch. #running-req: 1, #token: 482, token usage: 0.00, gen throughput (token/s): 49.02, #queue-req: 0, # 之前 26,1.88x

固定 200 输入,200 输出,128 并发,2 轮请求:

============ Serving Benchmark Result ============
Backend: sglang-oai
Traffic request rate: 128.0
Max reqeuest concurrency: 128
Successful requests: 256
Benchmark duration (s): 87.57
Total input tokens: 51200
Total generated tokens: 51200
Total generated tokens (retokenized): 51023
Request throughput (req/s): 2.92
Input token throughput (tok/s): 584.64
Output token throughput (tok/s): 584.64 # 之前 391.47,1.49x
Total token throughput (tok/s): 1169.28
Concurrency: 127.23
----------------End-to-End Latency----------------
Mean E2E Latency (ms): 43524.37
Median E2E Latency (ms): 43246.71
---------------Time to First Token----------------
Mean TTFT (ms): 7225.06
Median TTFT (ms): 6769.52
P99 TTFT (ms): 14229.37
---------------Inter-Token Latency----------------
Mean ITL (ms): 182.87
Median ITL (ms): 162.95
P95 ITL (ms): 166.60
P99 ITL (ms): 202.39
Max ITL (ms): 13711.39
==================================================

可以看到,修复网络本身存在的问题以后,推理性能提升还是很显著的。

one more thing

前一篇文章提到: L40S/L20 虽然支持 FP8 精度,却不能运行 FP8 的 DeepSeek-V3/R1。这个问题搞定了,我已经实现在 L40S 上运行原始 FP8 参数的 DeepSeek-R1,满血+纯血。等我整理一下代码,下篇博客来介绍一下。

使 SGLang 支持在 32 张 L40S/L20 上运行 DeepSeek-R1

我提交的 PR: Support serving DeepSeek-R1-Channel-INT8 with 32 L40S. #4418 [1] 已经合入到了 SGLang 的主干,也许这是第一个用 PCIE 互联的 GPU 小卡跑通 DeepSeek-R1 推理的例子。

有一些遇到的问题分享一下,在适配别的 GPU 时可以用来参考。

背景

因为 128x128 block 量化的 DeepSeek-R1/V3,参数维度在除 32 时,会遇到商无法被 128 整除的问题,所以即使 L40S 支持 FP8,也无法直接用 TP32 运行 DeepSeek-R1/V3。

感谢美团提供了 channel 量化的 DeepSeek-R1 参数 DeepSeek-R1-Channel-INT8 [2],并且在 SGLang 代码库做了适配。这让我可以在 48G 显存的 L40S 上尝试一下运行满血版(int8 量化) DeepSeek-R1,但尝试过程没有我预期的顺利,遇到了不少问题。

问题

一、shared memory OutOfResources

  File "/sgl-workspace/sglang/python/sglang/srt/layers/attention/triton_ops/extend_attention.py", line 356, in extend_attention_fwd
_fwd_kernel[grid](
...
File "/usr/local/lib/python3.10/dist-packages/triton/compiler/compiler.py", line 374, in _init_handles
raise OutOfResources(self.metadata.shared, max_shared, "shared memory")
triton.runtime.errors.OutOfResources: out of resource: shared memory, Required: 102400, Hardware limit: 101376. Reducing block sizes or `num_stages` may help.

服务启动正常,收到推理请求后,Attention kernel 报 shared memory 资源不足。我刚开始没理解这个问题,后来看了下代码,发现 triton attention 代码中对不同类型的 GPU 架构设置了不同的 block size。L40S 属于 SM89 架构,但 SM89 都归类到了 SM80 架构里。

查了一下 CUDA 编程手册,SM89 的 shared memory 大小是 100K,但 SM80 是 160K。我猜测大概率就是这个问题,所以给 SM89 单独加了个分支,缩小了 SM89 的 block size,解决了这个问题。

后来发现 sglang/test/srt/test_triton_attention_kernels.py 可以完美复现这个问题,而我却傻乎乎地每次重启整个服务去测试正确性。

二、gemm executioin failed RuntimeError

  File "/usr/local/lib/python3.10/dist-packages/sgl_kernel/ops/__init__.py", line 118, in int8_scaled_mm
return torch.ops.sgl_kernels.int8_scaled_mm(
File "/usr/local/lib/python3.10/dist-packages/torch/_ops.py", line 1116, in __call__
return self._op(*args, **(kwargs or {}))
RuntimeError: gemm executioin failed, error: Error Internal

收到推理请求后,有很大的概率触发这个错误,但也有小概率能完成一次推理。所以我没想到是算子问题,我以为是显存不足。调了半天各种显存占用的参数,后来没办法了才回过头来看实际的算子调用。

又是跟上面类似的问题,sgl_kernel 中自定义的 int8 gemm 算子将 SM89 归类到 SM80 进行矩阵计算的 dispatch。这显然会遇到与上面类似的问题,但是我又不知道 SM89 该怎么进行 dispatch,看起来需要做很多 benchmark 或者计算才能确定。

于是我就去翻 TensorRT-LLM 和 vLLM,让我给翻到了 vLLM 的实现,我就照着 vLLM 对 SM89 的 dispatch 逻辑抄了一遍。这次我学乖了,先看看有没有 test。跑通了 sglang/sgl-kernel/tests/test_int8_gemm.py,才去进行集成测试。

三、sub-optimal MoE

Using default MoE config. Performance might be sub-optimal! Config file not found at /usr/local/lib/python3.10/site-packages/sglang/srt/layers/moe/fused_moe_triton/configs/E=256,N=64,device_name=NVIDIA_L40S,dtype=int8_w8a8.json

这是一个次要问题,看起来是一个专门的配置没有找到。后来我研究了一下,应该是 triton 版本的 fused_moe 需要读取一个在每种类型的 GPU 上都 benchmark 过的最好配置来运行。

python  benchmark/kernels/fused_moe_triton/tuning_fused_moe_triton.py \
--model /workspace/DeepSeek-R1-Channel-INT8 --tp-size 32 --dtype int8_w8a8 --tune

我按照文档的要求,在 L40S 上跑了一下 bench,把最终输出的文件拷贝到对应的位置就好了。这个 bench 真的要跑好久,大概两三个小时。

性能

我这 4 台 L40S 的硬件配置有些特殊:它是单机 8 卡,PCIE 4.0 连接到主机,但它既不是 2-2-4,也不是 2-2-8。

20250322:其实是硬件配置错误,详见:《刷新 32 张 L40S 运行 DeepSeek-R1-INT8 的性能数据

其中 4 张卡直插 PCIE 上,另外 4 张卡通过一个 PCI-to-PCI Bridge 插到 PCIE 上。为了弥补这样连接的带宽缺陷,PCI-to-PCI Bridge 上还接了 2 个 100Gb/s 的 RDMA 网卡。主机上每个 NUMA 域,分别也有 2 个 100Gb/s 的 RDMA 网卡。

所以这 8 张显卡,6 张网卡,拓扑如下所示:

我也实在算不出来这玩意儿的互联带宽。逻辑上来说,这大概相当于用 4 PCIE 4.0 GPU + 2 RDMA 网卡的性能,所以也许这个 4 x 8卡,实际上相当于 8 x 4卡。以下性能评测结果供参考。

下面是加载时的显存使用情况:

[TP0] Load weight end. type=DeepseekV3ForCausalLM, dtype=torch.bfloat16, avail mem=22.43 GB, mem usage=21.27 GB.
[TP0] Memory pool end. avail mem=7.95 GB
[TP0] Capture cuda graph begin. This can take up to several minutes. avail mem=7.92 GB
[TP0] Capture cuda graph end. Time elapsed: 411.41 s. avail mem=5.89 GB. mem usage=2.02 GB.
[TP0] max_total_num_tokens=201723, chunked_prefill_size=8192, max_prefill_tokens=16384, max_running_requests=2049, context_len=163840

下面是使用固定 200 token 输入时,不同并发下的净 decode 速度。因为 bench 速度太慢,我也懒得等最终的结果,所以这里直接节取了 log。

# 128 并发
[TP0] Decode batch. #running-req: 128, #token: 86816, token usage: 0.43, gen throughput (token/s): 565.73, #queue-req: 0,
# 32 并发
[TP0] Decode batch. #running-req: 32, #token: 8923, token usage: 0.04, gen throughput (token/s): 260.73, #queue-req: 0,
# 4 并发
[TP0] Decode batch. #running-req: 4, #token: 1439, token usage: 0.01, gen throughput (token/s): 42.30, #queue-req: 0,
# 1 并发
[TP0] Decode batch. #running-req: 1, #token: 482, token usage: 0.00, gen throughput (token/s): 26.00, #queue-req: 0,

这是固定 200 输入,200 输出,128 并发,2 轮请求的完整压测结果:

============ Serving Benchmark Result ============
Backend: sglang-oai
Traffic request rate: 128.0
Max reqeuest concurrency: 128
Successful requests: 256
Benchmark duration (s): 130.79
Total input tokens: 51200
Total generated tokens: 51200
Total generated tokens (retokenized): 50992
Request throughput (req/s): 1.96
Input token throughput (tok/s): 391.47
Output token throughput (tok/s): 391.47
Total token throughput (tok/s): 782.94
Concurrency: 127.49
----------------End-to-End Latency----------------
Mean E2E Latency (ms): 65135.99
Median E2E Latency (ms): 64974.27
---------------Time to First Token----------------
Mean TTFT (ms): 17554.19
Median TTFT (ms): 19216.02
P99 TTFT (ms): 21662.98
---------------Inter-Token Latency----------------
Mean ITL (ms): 239.84
Median ITL (ms): 220.95
P95 ITL (ms): 233.20
P99 ITL (ms): 299.49
Max ITL (ms): 16077.21
==================================================

链接

[1] https://github.com/sgl-project/sglang/pull/4418

[2] https://huggingface.co/meituan/DeepSeek-R1-Channel-INT8

[3] https://github.com/vllm-project/vllm/blob/main/csrc/quantization/cutlass_w8a8/scaled_mm_c2x_sm89_int8_dispatch.cuh