llama.cpp 多 GPU 性能实测思路:2x V100 16GB 会比单卡 32GB 快吗?

整理 llama.cpp 多 GPU offload 的性能预期:单卡能放下时双卡不一定更快,单卡放不下时双卡主要价值是把模型留在 GPU 上,并说明 V100 PCIe 与 NVLink 对性能的影响。

大概结论:llama.cpp 多 GPU offload 不是“多一张卡就白捡一倍性能”。如果模型本来能完整放进一张 32GB 显卡,2x V100 16GB 通常不如单张 32GB 显卡省心,甚至可能更慢;如果模型单张 16GB 放不下,双卡的主要价值是“能把模型放进 GPU”,这时收益会很明显。

先分清 split mode

llama.cpp 的多 GPU 主要围绕 --split-mode--tensor-split 使用。实际讨论性能时,先要区分几种模式:

  • layer:按层切分到不同 GPU,兼容性较好,也是多数人优先尝试的方式。
  • tensor:把张量计算拆到多张 GPU 上,更接近并行计算,但更依赖 GPU 之间的互联带宽和后端支持。
  • row:旧的行切分方式,在不少场景里仍能看到,但新部署通常不建议优先从它开始。

简单说,layer 更像“把不同楼层放在不同卡上”,单 token 生成时不一定能让两张卡同时满负载;tensor 更像“同一层两张卡一起算”,理论上更能并行,但跨卡通信会成为关键瓶颈。

单卡 32GB 能放下时:双 16GB 不一定更快

如果模型和 KV cache 能完整放进一张 32GB 显卡,那么单卡通常更稳,也常常更快。对 1x V100 32GB 和 2x V100 16GB 这类同代硬件来说,后者未必能赢。

比较保守的预期是:2x V100 16GB 可能比单张 V100 32GB 慢 10% 到 40%,尤其是单人聊天、Continue Agent、代码问答这类一次主要生成一个回答的场景。

原因不复杂:多 GPU 不是简单合并显存。按层切分时,推理会在不同 GPU 之间流转,单 token 生成阶段经常是部分 GPU 等另一部分 GPU;按张量切分时,两张卡可以一起算,但中间结果需要跨卡同步,互联带宽和延迟会直接影响吞吐。

所以如果你的选择是:

  • 1x V100 32GB
  • 2x V100 16GB

并且目标模型单张 32GB 已经能完整放下,那么单张 32GB 往往是更舒服的选择。

单卡 16GB 放不下时:双卡价值很大

另一种情况完全不同:模型单张 16GB 放不下,但两张 16GB 合起来可以放下。

这时双卡的价值就很直接:

  • 单张 16GB:可能需要大量 CPU offload,速度明显变慢。
  • 2x 16GB:权重尽量留在 GPU 上,速度可能比 CPU/GPU 混跑快很多。

这种场景下,2x V100 16GB 不一定比单张 32GB 快,但它可能比“单张 16GB 加大量系统内存 offload”快几倍。也就是说,双卡的第一价值不是加速,而是避免模型被迫落到更慢的系统内存里。

V100 PCIe 和 V100 SXM2 差别很大

多 GPU 推理最容易被忽略的是互联。

如果是 V100 SXM2,并且机器里有 NVLink,跨卡通信带宽高很多。NVIDIA 的 V100 资料里,NVLink 互联最高可到 300GB/s。这种环境下,tensor 或更高 batch 的场景才更有机会接近甚至超过单卡表现。

如果是 V100 PCIe,情况就保守得多。V100 PCIe 的互联主要走 PCIe Gen3,资料里标的 interconnect bandwidth 是 32GB/s。这个带宽和 NVLink 不是一个量级,所以双卡经常出现“显存够了,但速度没有翻倍”的情况。

因此判断 2x V100 16GB 值不值得,不能只看显存相加是 32GB,还要看它们是 PCIe 版还是 SXM2/NVLink 版。

怎么选更实际

如果模型能放进单张 32GB 显卡,优先选单卡。它的延迟、稳定性和调参成本通常更好。

如果模型单张 16GB 放不下,而两张 16GB 能放下,双卡值得用。此时重点是让权重尽量留在 GPU,而不是期待性能线性翻倍。

如果是 V100 PCIe 双卡,优先尝试 --split-mode layer,把目标放在“能稳定跑”和“少走 CPU”上。

如果是 V100 SXM2/NVLink,才更值得测试 tensor 相关模式,尤其是 prefill、大 batch 或并发请求场景。

什么时候买 2x16GB,什么时候买 1x32GB

如果你只服务一个人,主要做聊天、代码补全、Continue Agent、长上下文问答,并且目标模型能放进 32GB,那么 1x32GB 通常更值得。它少了跨卡调度,延迟更稳定,排查问题也简单。

如果你已经有一张 16GB 卡,想用较低成本扩到能跑 30B、32B 或更高量化模型,2x16GB 就有意义。它不一定让 token/s 翻倍,但可以把原本必须 CPU offload 的权重留在 GPU 上。

如果你准备重新采购,优先级可以这样排:

  • 单模型、单用户、重视响应延迟:优先 1x32GB。
  • 模型单卡放不下、预算有限:可以考虑 2x16GB。
  • 有 NVLink 或 SXM2 机器:2x16GB 的可玩性明显高于普通 PCIe 双卡。
  • 未来想跑更长上下文:不要只看权重大小,还要预留 KV cache 显存。

layer split 和 tensor split 怎么用

实用建议是:先用 layer,再测 tensor

layer 适合作为默认起点。它按层分配模型,兼容性较好,对 PCIe 双卡更友好。缺点是生成阶段可能更像流水线,某些时刻只有一张卡在忙,另一张卡在等。

tensor 更适合互联带宽好的机器,例如 V100 SXM2/NVLink。它把同一层的部分计算拆到多张卡上,理论上更有并行空间,但跨卡同步更频繁。如果是 PCIe 双卡,tensor 可能会被通信开销吃掉收益。

实际测试时可以从这几组开始:

1
2
3
llama-bench -m model.gguf -ngl 99 --split-mode layer --tensor-split 1,1
llama-bench -m model.gguf -ngl 99 --split-mode tensor --tensor-split 1,1
llama-bench -m model.gguf -ngl 99 --split-mode layer --tensor-split 1,0

第三条不是为了长期使用,而是给单卡结果做一个参照。这样才能看出双卡到底是更快,还是只是把显存压力分摊出去了。

prefill 和 decode 为什么表现不同

本地大模型性能通常要分成两个阶段看:

  • prefill:处理输入 prompt,典型指标是 pp512 这类 prompt processing 吞吐。
  • decode:逐 token 生成回答,典型指标是 tg128 这类 token generation 吞吐。

prefill 更像大批量矩阵计算,batch 较大时更容易把 GPU 喂饱,也更可能从多 GPU 并行里受益。decode 是一个 token 接一个 token 生成,batch 小、同步频繁,跨卡通信和调度延迟更容易暴露出来。

所以你可能会看到一种结果:双卡的 pp512 更好,但 tg128 没明显提升,甚至更慢。对聊天和 Agent 来说,用户体感更接近 tg128;对长文档导入、批量预填充、并发服务来说,pp512 也很重要。

KV cache 会不会成为第二个显存瓶颈

会。很多人只算模型权重,忘了 KV cache。

模型权重决定“能不能加载模型”,KV cache 决定“能不能开足上下文”。上下文越长、并发越高、batch 越大,KV cache 占用越明显。你可能遇到这种情况:模型本体能放进 32GB,但一开 32K 或 64K 上下文,显存又不够了。

判断时至少要留出几块显存余量:

  • KV cache
  • CUDA graph 或后端运行时开销
  • prompt batch 和 ubatch
  • 系统桌面、驱动和其它进程占用

如果你用的是 2x16GB,显存不是一个完全等价的 32GB 大池子。某些缓冲区、KV cache 或中间张量仍然会受单卡剩余显存影响。测试长上下文时,最好直接用目标 --ctx-size 和目标并发数测,而不是只看模型能不能启动。

用 llama-bench 做自己的双卡测试

llama-bench 比直接聊天更适合做硬件对比,因为它会把 prompt processing 和 token generation 拆成可比较的指标。官方 README 的默认示例就是:

1
llama-bench -m model.gguf

对双 V100,可以至少测这几组:

1
2
3
4
5
6
7
8
# 单卡基线
CUDA_VISIBLE_DEVICES=0 llama-bench -m model.gguf -ngl 99

# 双卡 layer split
CUDA_VISIBLE_DEVICES=0,1 llama-bench -m model.gguf -ngl 99 --split-mode layer --tensor-split 1,1

# 双卡 tensor split
CUDA_VISIBLE_DEVICES=0,1 llama-bench -m model.gguf -ngl 99 --split-mode tensor --tensor-split 1,1

重点看两列:

  • pp512:prompt processing,长输入和批量预填充更相关。
  • tg128:token generation,单人聊天和 Agent 体感更相关。

测试时尽量固定模型、量化格式、上下文、batch、驱动版本和 llama.cpp 版本。每组多跑几次,取中位数,比只看一次结果可靠。最后再用真实工作流跑一遍,例如 Continue Agent、OpenAI-compatible server 或你自己的 RAG 请求,因为 benchmark 好看不代表交互体验一定更好。

一句话结论

2x V100 16GB 的优势主要是显存容量,而不是必然的生成速度。模型单卡能放下时,单张 32GB 往往更快、更稳;模型单卡放不下时,双 16GB 的价值就很大,因为它能避免大量 CPU offload。至于能不能更快,关键看 split mode、batch、模型大小,以及两张 V100 之间到底是 PCIe 还是 NVLink。

参考资料:

记录并分享
使用 Hugo 构建
主题 StackJimmy 设计