7900XTX 四种双卡方案实测
-
双 7900XTX 上 B760M:硬件情况、两种卡对比、四种双卡方案实测
机器
- 板 U:B760M(DDR4),CPU 是 RPL ES,P 核 5.0 / E 核 4.0,内存 64G DDR4-2666
- 卡:蓝宝石 PULSE 7900XTX + 一张涡轮公版 7900XTX
- 电源 1000W,双卡满载整机峰值 636W,够用
插槽拓扑:PULSE 走 CPU 的 x16(Gen4 x16 满速,实测 27.7GB/s),涡轮走 PCH 的 x4(Gen3 x4,实测 3.6GB/s)。两张卡挂在不同的 root 口下面,没有 P2P,跨卡流量都走内存弹跳。
两张卡本体对比(同配置同 prompt 实测)
同一颗 die(0x744c / gfx1100),裸算力一个水平(8GB sum 454 vs 460 GB/s,GEMM 同速),差别全在 VBIOS:
PULSE(老卡) 涡轮(新卡) 负载实际 sclk 2677 MHz 2137 MHz 显存 mclk 1249 MHz 1249 MHz 功耗墙 / 实测均值 303W / 290W(peak 314) 257W / 203W(peak 219) 满载温度 52-55°C 53-55°C decode(生产配置,256tok) 63.9 t/s 52.2 t/s(-18%) prefill(2K) 790 t/s 605 t/s(-23%) 每瓦 decode 0.205 tok/W 0.235 tok/W(反高 15%) 涡轮跑 203W 离自己的 257W 墙还远,说明不是功耗受限,是 VBIOS 频率表出厂就低。两张卡 cap_max 都是 350W,但 RDNA3 在 Linux 下没有 pp_od_clk_voltage,频率表拉不动,写大功耗墙也没用(它根本没顶到)。所以这 -18% 是永久的,好在温度能效都健康,当副卡完全合格。
TP2 的坑(PCH 平台必看)
vLLM 开
--tensor-parallel-size 2直接hipErrorInvalidState (401),而且错误永远跟着 PCH 那张卡走。排查到底发现是硬件+驱动叠加:
- RCCL 2.30.4 的 kernel 被 device-link 无条件挂了 hidden hostcall buffer,hostcall 门铃就是 PCIe 原子写
- lspci 看 AtomicOp Completer:CPU 口
00:01.0全部+,PCH 口00:1c.0全部-(Routing- 32bit- 64bit- 128bitCAS-),这些是只读硬件位,setpci 没救 - 于是 amdgpu 在 PCH 卡上禁 atomics,HIP 运行时直接拒发 kernel → 401
修法用的是 rocm-systems#11277 这个未合并 PR 的思路:装载期标记 hostcall 不可满足,
HIP_HOSTCALL_ALLOW_MISSING=1时放行为 null buffer。kernel 真去执行 hostcall 才会 fault,而 RCCL 热路径从不 printf,所以安全(PR 作者和本机双重验证过)。自己编了一份 clr,几个坑:ROCM_KPACK_ENABLED=ON必须开,不开 torch 的 kernel 全 SIGSEGV- TheRock wheel 的 torch 按绝对路径加载 SDK 库,LD_LIBRARY_PATH 换不动运行时 → 用 docker 单文件 bind-mount 直接盖掉 wheel 里的
libamdhip64.so - 容器里 apt 基本残废,GL/X11/zstd 头文件直接从 ubuntu pool 下 deb 解压出个 prefix 传给 cmake
弄完 torchrun 双卡 allreduce 通过,TP2 一次点火成功。
四种方案实测
统一口径:2K token 随机词表 prompt × 强制生成 256 token,E2E 聚合 tok/s。随机词表对投机解码是 worst case,数字看相对差距比看绝对值有意义。llama.cpp 并发下它自报的 predicted_per_second 会虚高(报过 600+),只信 tokens/wall。
模型:Qwen3.8 27B(llama.cpp 用 UD-Q4_K_S;vLLM 用 W4A16 GPTQ);Strata 部分是 Flash-Next IQ3_XXS。
并发 A 双实例副本 B vLLM TP2 B+MTP3 C llama.cpp 切层 D Strata 层切 1 59.4 / 46.1 29.6 46.7 32.4 80.5* 2 64.6 56.3 — 32.0 — 4 53.3 97.0 50.3 30.5 53.8 8 58.1 118.3 — 30.5 ≈N4(串行队列) *A 那格 59.4/46.1 = 两张卡各自实例单发各一个;D 是 Flash-Next IQ3_XXS 不是 27B,只看趋势。
A 双实例副本:每卡一个 llama.cpp,带全套投机。单请求延迟全场最好,N=2 之后排队,聚合封顶 58-65。隔离干净,这是日常默认形态。
B TP2:并发近线性,N=8 的 118 是副本天花板的两倍。代价:要补丁运行时(上面的配方)。MTP3 投机对单请求 +58%(29.6→46.7),但 N=4 反而 97→50,投机和连续批处理不对付,按场景开。
C llama.cpp 切层:
--device Vulkan1,Vulkan2 --tensor-split 1,1能跑,但 30-32 永平线。原因是每个 decode 步都要把另一半层的结果从 PCH x4 拉回来,每 token 一次跨卡同步,这块板上就是自残。数据放这就是让大家别踩。D Strata 层切:官方 docs/MULTI_GPU.md 的流水线层切,跟 C 完全不是一回事——token 每个验证窗只跨卡一次(几百 KB pinned RAM),x4/x1 槽官方明文能用,实测 PCH 卡拿一半层照常工作。两点经验:
- 必须
STRATA_SPLIT_OVERLAP=1。不开的话层切 decode 倒退(官方 2×XTX 数据 53 vs 单卡 70),开了和单卡持平。本机:单卡 79.7 vs 层切 80.5,零损失。 - 收益全在 prefill 和容量:9.6K prompt 900→1100 t/s(+21%),双卡专家缓存 22577/24576 对约 99.8% 驻留(单卡 96-97%)。
--batch多会话模式试了,聚合没涨还把单流砍半,没必要。并发它还是一问一答的串行队列,跟 TP2 没得比。
长上下文
TP2 大 prompt 冷填是另一个量级:130K token 冷填 77 秒(1684 t/s);单卡副本 186K 深度实测 620 秒(300 t/s),速率差 5.6 倍。128K 和 160K 的三针大海捞针全过。160K 深度 fresh prefill 会掉到 359 t/s,可复现,还没调好(批长和 attention backend 待试),先如实报。
结论
- 日常用双实例副本:隔离、延迟最好、零额外依赖。第二张卡最大的实际收益就是它——两个会话各占一张卡互不打架,外加副卡常驻 60-90 t/s 的第二实例。
- 多并发或者大 prompt 冷填,TP2 按需点火:聚合 2 倍、冷填 5.6 倍。PCH 平台的 atomics 修复照上面配方走一遍就能用。
- llama.cpp 切层在这类板子(CPU x16 + PCH x4)上是负优化,数据就是 30 一条横线。
- Strata 玩家:层切可以用,前提 SPLIT_OVERLAP,收益在 prefill 和专家驻留,别指望并发。
- 单会话速度双卡救不了,天花板就是单卡。预算有限又只想加单流速度的,省下钱。
- 涡轮版/公版涡轮当副卡合适:便宜,能效还高 15%,接受 -18% 就行。
附:复现要点
vLLM TP2 关键参数:
--tensor-parallel-size 2 --disable-custom-all-reduce --dtype bfloat16 NCCL_P2P_DISABLE=1 HSA_ENABLE_SDMA=0 NCCL_PROTO=Simple HIP_HOSTCALL_ALLOW_MISSING=1 # 补丁运行时配套无 P2P 平台 allreduce 走 host transport,Simple 协议实测优于 auto。Strata 层切配置就三行:
"gpu": [0,1]+"layer_split": "auto"+ 环境变量STRATA_SPLIT_OVERLAP=1,卡序不用管,引擎自动把快卡放末级(head+draft 在快卡上)。欢迎交流,尤其是同样 PCH 口插卡想走 TP2 的,atomics 这个坑应该不止我碰到。
一句话:双7900xtx没啥明显收益
-
-