Day 01 我埋了一句話:「兩張卡的頻寬理論上可以疊加。疊不疊得起來?第 12 天見真章。」
今天見真章。答案比我當時想的麻煩:兩張卡各讀自己那半份權重時,504+504 是真的一起在工作;疊不起來的是把它們當成一條 1008 GB/s 的共享匯流排。差別就卡在中間那 72 次同步,得另外付帳。
而且我還記錯了一件事:我的 T2 只有一張卡。
Day 01 那張機器表把 T2 寫成「2× RTX 4070 Ti/12GB + 12GB」。錯的:T2 是單張 RTX 4070 Ti 12GB,Windows 11 + WSL,我把它跟公司那台雙卡工作機記混了(Day 08 開表登的其實已經是單卡數字)。
Day 02、03、04、07 提到「我的雙卡 24GB」的每一處一併更正;Day 09 之後的容量帳本來就照 12 GiB 算。好消息是這題不需要第二張卡。
有兩張卡的話,動模型之前先三行把地基查清楚:
nvidia-smi topo -m # 看 GPU0↔GPU1 是 PIX / PXB / PHB / NODE / SYS
nvidia-smi -q | grep -A 6 "Link Width" # 每張卡實際是 x16 還是 x8/x4
nvidia-smi -q | grep -A 4 "BAR1" # BAR1 涵蓋整張卡=ReBAR 有開的強訊號
topo -m 給的是路徑類型(繞過幾層 PCIe switch、host bridge、NUMA),不是實測 GB/s,也不給 lane 數(我這台實測 16x、gen 4、BAR1 16384 MiB)。消費主機板的 PCIe lane 是 CPU 發的零用錢,雙卡常見 x8/x8 或 x16 + x4(第二槽走晶片組,還跟 SSD、網卡搶上行)。
PCIe 4.0 x16 單向約 31.5 GB/s(16 GT/s × 16 lane × 128b/130b ÷ 8;PCI-SIG 公布的 64 GB/s 是雙向合計),x8 剩 15.8、x4 剩 7.9。對照每張卡自家 VRAM 的 504 GB/s:跨卡通道慢 16 到 64 倍。

圖 1:replica、PP、TP 每 token 的跨卡成本。
兩張卡服務同一顆模型有好幾種切法,這篇先看最常見的三種:replica 各放一份完整模型、PP(pipeline parallel)把層前後切開、TP(tensor parallel)把每一層垂直剖半;後面寫 TP2、PP2,那個 2 就是兩張卡。
PP 買的是容量,這不是修辭。同一顆 8B 起 vLLM(util 0.85、max-model-len 8192),profiler 把 10.19 GiB 的預算切完(權重加 non-torch 6.96、peak activation 1.73)之後,KV 只剩 1.51 GiB = 10,960 個 token。開了 8192 的 max-model-len,整張卡卻連兩條滿額 request 的 KV 都放不下。塞得下,但 8K 幾乎沒有併發餘裕。
換成 PP2,每卡只扛一半權重,騰出來的大部分可以留給 KV;每卡又只存自己那 18 層,同一條序列的佔用也少一半。兩邊一起算,KV 從 10,960 個 token 長到約 7 萬——同一顆模型、同樣兩張卡,差別在它現在真的能接客。(我只有一張卡,這格是照單卡 profiler 回推的;實際值由較吃緊的那個 stage 決定,還會受切點與 activation 配置影響。)
所以 Day 01 那個問題的精確版是:TP2 在被砍過 lane 的 PCIe 上,單流贏不贏得了單卡?
拿 Qwen3-8B 的 AWQ 版算一次:36 層、hidden 4096、bs=1。
檔案 6.10 GB,但 decode 每一步真正要讀的不是全部——embed_tokens 那 1.25 GB 每個 token 只查一行。每 step 大約要串流 4.85 GB(lm_head 要算 logits,仍得全讀)。這是從權重表推的 roofline 近似,不是 profiler 量到的 DRAM bytes。
一次 all-reduce 的 payload 是 1 × 4096 × 2 bytes = 8 KiB,一個 token 走 72 次(36 層 × 2),合計 576 KiB(0.59 MB)。在 31.5 GB/s 上是 0.019 ms——只佔待會要省下那筆的 0.4%。資料量不是問題。
再看省多少:
單卡 4.85 ÷ 504 = 9.63 ms/token(天花板)
TP2 2.43 ÷ 504 = 4.82 ms/token
省下 4.82 ms
4.82 ms ÷ 72 次 = 67 微秒/次
4.82 ms 就是 TP2 能付給 72 次同步的全部預算——平均一次 67 微秒。 這條線不需要第二張卡,是從帳面規格除出來的。
要小心它是什麼:67 微秒是「純權重頻寬模型下,每次 collective 還能多花的時間」,不是 PCIe 的往返延遲,也不是 cudaMemcpyPeer 量到的值。
除出來的天花板站不站得住?我把 8B 在這台跑了一次 bs=1(vLLM 0.27.1、in 1024/out 256、12 筆):median TPOT 11.99 ms,對 9.63 ms 是 80.3% 兌現率。Day 10 在同一台用 llama.cpp 量到的是 80%——換引擎、換量化格式仍落在同一帶(那邊的分母是權重檔案大小、沒扣 embedding,口徑略寬)。
這 80% 回頭也會鬆動那條線:若 TP2 同樣只兌現八成,半份權重要 6.0 ms 而不是 4.82,省下的變成 5.99 ms,預算就放寬到 83 微秒。67 給的是數量級,不是硬門檻。

圖 2:每次 collective 只花 20 微秒還贏得漂亮,150 微秒就整段賠回去。
這條線只管 decode。prefill 的 payload 隨 seq 線性長:seq=512 時一次從 8 KiB 變成 4 MiB,一輪 72 次合計 302 MB——就算 PCIe 4.0 x16 跑滿 31.5 GB/s,純搬資料的理論下限也要 9.6 ms。decode 的 collective 偏吃延遲,prefill 拉長後偏吃頻寬;而 prefill 那邊 TP 同時也把 GEMM 拆掉了,賺不賺得另外算。
67 微秒是什麼量級?這得看兩張卡能不能直接講話。
P2P 是兩張卡不經 CPU 記憶體、直接互讀 VRAM。沒有它,GPU 之間的交換得繞一趟主機記憶體,多出額外的複製與同步成本。
NVIDIA 沒明文寫「4090 這代禁 P2P」,但要用它得去 patch 開源核心驅動。他們 README 那組雙向約 50 GB/s、單向 cudaMemcpyPeer 約 24 GB/s,是 550 分支在 4090 上量的,別跟前面的 31.5 GB/s 上限混著讀。
自己驗的話:
git clone --depth 1 https://github.com/NVIDIA/cuda-samples.git
cd cuda-samples/cpp/5_Domain_Specific/p2pBandwidthLatencyTest # v13.3 起 Samples/ 改叫 cpp/
cmake -B build && cmake --build build # 舊的逐目錄 make 已經沒了
./build/p2pBandwidthLatencyTest # 或先看 nvidia-smi topo -p2p r

圖 3:只有 (b) 對 (c) 量得到 P2P 的價值,(a) 自己跟自己比是空轉。
網路上有些「實測 P2P 沒影響」的文章,其實對照組根本沒有變因。 原廠 driver 回報 P2P 不可用時,vLLM 本來就會停用 custom all-reduce、退回 NCCL,這時再設 NCCL_P2P_DISABLE=1,前後兩組一模一樣。反過來,P2P 一開,vLLM 可能改走自家的 custom all-reduce,NCCL_P2P_DISABLE=1 管不到它,得連 --disable-custom-all-reduce 一起才釘得住 backend。(我參考的那個 branch 停在 570.148.08,README 只點名 4090 和 5090。)
那買貴一點呢?RTX PRO 6000 Blackwell Workstation Edition,96GB GDDR7、1,792 GB/s,NVIDIA Marketplace 2026-08 標價 16,000 美元。
我找到的幾組公開雙卡部署,都額外動過 P2P/NCCL 的路徑:eordano 直接關掉(NCCL_P2P_DISABLE=1 加 --disable-custom-all-reduce,不加就沒辦法讓 TP 在 PCIe 上跑起來);ovidiudan 走另一條,顯式設 NCCL_P2P_LEVEL=SYS——那是把 P2P 放寬到跨 NUMA,不是關掉。
不是這張卡沒有 P2P,是開著會出事。 cuda-samples issue #390:cudaDeviceCanAccessPeer 回 Yes、simpleP2P 印出 103.88 GB/s,資料驗證卻是錯的;NCCL issue #1999 是另一種死法,兩張卡開著 P2P 跑 AllReduce 直接卡住,換三個 NCCL 版本都 100% 重現。能傳、傳得快、卻不能信——至少在那幾組 driver 與 CUDA 版本上。
而 vLLM 預設就信 driver 那句 Yes(VLLM_SKIP_P2P_CHECK 預設為 1,只問 capability、不實際驗)。driver 報 Yes 時,它不一定會替你攔下有問題的 P2P 路徑;要它真的動手驗,得設成 0。至於 tinygrad 那份 patch,只點名 4090 和 5090,我沒找到套在 RTX PRO 6000 上的公開成功回報。
他們的優先序也跟通訊帳一致,lastloop 的部署指南原文:
Do not use tensor-parallel (TP=2) — NCCL all-reduce over PCIe adds more latency than it saves for a 27B model
「adds more latency than it saves」正是那條 67 微秒的線,只是他們用實測講、我們用除法講。
vLLM 官方文件也是同一個方向:沒有 NVLink 的節點(它舉的例子是 L40S),優先用 pipeline parallelism 而不是 tensor parallelism,吞吐更高、通訊更少。
一句話收束:要總吞吐,塞得下就先 replica;要跨卡容量,PCIe 上先試 PP;要壓單請求延遲,TP 自己 A/B。到了 NVLink/NVSwitch 這種高頻寬互連,TP 才是更自然的起手式。
把兩張 4070 Ti 拆到兩台機器、用內網接起來,聽起來像是繞過 PCIe 的辦法。同一條式子代下去就知道行不行。
跨機器的瓶頸不是頻寬:8 KiB 的 payload 在 10 GbE(10 Gbit/s = 1.25 GB/s)上只要 6.6 微秒。殺你的是往返延遲,而且要乘以 72。
圖 4:8 KiB 加上各類互連的典型往返,對照 67 微秒那條線
一般 TCP/IP 的往返落在 100 到 200 微秒,×72 就是 7.7 到 14.9 毫秒,把省下來的 4.82 毫秒淹掉兩三倍。要過線得靠 RDMA 把往返壓進 20 微秒——這正是機房跨節點用 InfiniBand、而不是一般乙太網的原因。
但同一條爛線,PP 幾乎免疫。 它每個 token 只付一次 boundary:16 KiB 傳 13 微秒,加 200 微秒往返也才 0.21 毫秒。兩個 stage 依序跑完是 9.85 毫秒,對單卡的 9.63 只慢 2.3%——換來的是兩台機器的容量。
所以「兩台便宜的接起來」這條路走得通,只是走得通的是 PP,不是 TP。
一張卡就夠,主角是那條除法。把上面幾步併起來:
TP2 的每次 collective 預算 = 每 step 讀的權重 ÷ (4 × 帳面頻寬 × 層數)
分母的 4 = 讀一半(2)× 每層 2 次 all-reduce。代 8B 那組驗一次:4.85 ÷ (4 × 504 × 36) = 67 微秒,跟前面除出來的一樣。
式子還說了一件不直覺的事:分子是每 step 讀的權重、分母有層數,所以 dense 模型越重、越淺,門檻越鬆。餵不動 8B TP2 的互連,換更大的模型反而可能划算(hidden 變大時 payload 也跟著長,得各自再算)。大模型比較容易攤平同步成本,但機房真正的優勢還是 NVLink/NVSwitch。
有兩張卡的讀者可以幫我補這格,分三步:p2pBandwidthLatencyTest 看通不通、多快;simpleP2P 驗傳得對不對(#390 那個 103.88 GB/s 就是它抓出來的);再用 nccl-tests 的 all_reduce_perf -b 8K -e 8K -g 2 量 collective——把 vLLM 也釘在 NCCL,它的 time (us) 才對得上那 67 微秒。
能不能開、傳得快不快、傳得對不對、collective 多久,是四件事。
(我在單卡跑過 -g 1:8192 B 的 no-op all-reduce 仍要 6.56 微秒。不能直接當成雙卡的固定成本,但至少說明那 67 微秒從來不全是線上的傳輸時間,collective 本身也有軟體與同步開銷。)
NCCL_P2P_DISABLE=1 是空轉,vLLM 自己就退回 NCCL 了。而 16,000 美元的 RTX PRO 6000 有 P2P,已公開的案例卻因為 correctness 出錯或 NCCL hang 被迫把它關掉。明天,Day 13:四個引擎、兩台機器。llama.cpp、Ollama、vLLM、MLX——沒有任何一台機器能把四個同場跑齊。沒辦法同場的較勁怎麼比才公平?兩平台 × 各三引擎,共同基準線是誰,明天攤開。
咱們明天見。