←Contents目錄
Chapter 4第 4 章
Chapter 4 of 13 · Part I · Foundations
第 4 章(共 13 章)· 第一部 · 基礎

Collective communication: algorithms, cost and the library that runs them集體通訊:演算法、成本與執行它們的函式庫

Learn how a collective is carried out step by step, how to predict its time from two numbers (latency and bandwidth), how NCCL turns a collective into network traffic, and how training hides collectives behind computation.了解集體操作如何一步一步執行、如何用兩個數字(延遲與頻寬)預測它的時間、NCCL 如何把集體操作變成網路流量,以及訓練如何把集體操作藏在計算後面。

≈ 55 min · 8 panels · 5 animations≈ 55 分鐘 · 8 個面板 · 5 個動畫Jump to the quiz ↓跳到測驗 ↓
Before you start
開始之前

This chapter builds on Chapters 2, 3. These earlier terms appear most often below; each chip links to its definition.

本章建立在第 2、3 章之上。下列較早定義的名詞在本章最常出現;點選即可回到它的定義。

New terms in this chapter (13)本章新名詞(13)

Each term is defined in the text where it first appears; the link jumps there. Terms from earlier chapters are listed under "Before you start".

每個名詞都在它第一次出現的段落中定義,點連結可跳過去。前面各章的名詞列在「開始之前」。

  • Ring all-reduce環狀 all-reduce Ranks pass chunks to their neighbor around a ring: a reduce-scatter then an all-gather. Each sends about 2× its buffer. 各 rank 沿環把資料塊傳給鄰居:先 reduce-scatter 再 all-gather。每個 rank 約送出緩衝區的 2 倍。
  • Bandwidth-optimal頻寬最優 An algorithm whose busiest rank sends the fewest bytes possible; for all-reduce, 2(N−1)/N times the buffer. 最忙的 rank 送出最少位元組的演算法;all-reduce 為緩衝區的 2(N−1)/N 倍。
  • α–β cost modelα–β 成本模型 Time of a collective ≈ α × (dependent steps) + bytes sent ÷ bandwidth; α is the latency of one step. 集體操作時間 ≈ α × (相依步數)+ 送出位元組 ÷ 頻寬;α 是每一步的延遲。
  • Tree, recursive doubling and halving樹、遞迴加倍與減半 Algorithms with about log₂N steps instead of 2(N−1): fewer steps, more bytes per step. 約 log₂N 步、而非 2(N−1) 步的演算法:步數少,每步位元組多。
  • Rabenseifner's algorithmRabenseifner 演算法 Recursive halving then doubling: the ring's byte count in only 2 log₂N steps, on a network where all pairs can talk at full rate. 先遞迴減半、再遞迴加倍:只用 2 log₂N 步達到環狀的位元組數;需要所有配對都能全速通訊的網路。
  • Hierarchical all-reduce階層式 all-reduce Reduce-scatter inside each server over NVLink, all-reduce one slice across servers among same-local-rank GPUs, then all-gather inside. 先在伺服器內以 NVLink 做 reduce-scatter,再在各伺服器本地 rank 相同的 GPU 間 all-reduce 一個切片,最後在伺服器內 all-gather。
  • In-network reduction網內歸約 Switches that add the data themselves, so each rank sends its buffer up once and receives the sum once. 由交換器自己做加總,每個 rank 只需送出一次緩衝區、接收一次總和。
  • NCCLNCCL NVIDIA's collective communication library; PyTorch calls it for every collective. NVIDIA 的集體通訊函式庫;PyTorch 的每個集體操作都呼叫它。
  • Communicator, channel通訊器(communicator)、通道(channel) A communicator is one group of ranks; a channel is one independent ring or tree inside it, with its own buffers and connection. 通訊器是一組 rank;通道是其中一個獨立的環或樹,有自己的緩衝區與連線。
  • SM (streaming multiprocessor)SM(串流多處理器) One of the ~130 compute units inside a GPU. NCCL runs each channel on one SM, taking it from computation. GPU 內約 130 個運算單元之一。NCCL 每個通道占用一個 SM,從運算中拿走。
  • Clear-to-send (CTS), receiver-driven admission允許傳送(CTS)、接收端准入 A small message in which the receiver names a free buffer slot; the sender may write only after it, which caps bytes in flight. 接收端指出一個空閒緩衝槽的小訊息;傳送端收到後才能寫入,因此限制了在途位元組。
  • Overlap, exposed communication重疊、暴露的通訊 Running communication while the GPU computes; the part that outlasts the computation is exposed and adds to the step time. 在 GPU 運算時同時進行通訊;比運算更久的部分即「暴露」,會加到步驟時間。
  • algbw, busbwalgbw、busbw The two numbers nccl-tests reports: buffer size ÷ time (algbw), and that rescaled by the algorithm's bytes so it compares with the link rate (busbw). nccl-tests 報告的兩個數字:緩衝區大小 ÷ 時間(algbw),以及依演算法位元組換算後可與鏈路速率比較的值(busbw)。

4.1The collectives, with sizes集體操作與它們的大小

Recall
回顧
Section 3.2 introduced the four collectives of training: all-reduce, reduce-scatter, all-gather and all-to-all. This chapter adds two rarer ones, broadcast and reduce, and then asks how each is carried out and how long it takes.
第 3.2 節介紹了訓練中的四種集體操作:all-reduce、reduce-scatter、all-gather 與 all-to-all。本章再加上兩種較少見的 broadcast 與 reduce,接著探討每一種如何執行、要花多久。
Collective集體操作Input → output per rank每 rank 的輸入 → 輸出Bytes sent per rank每 rank 送出位元組Who uses it誰在用
broadcastRoot has SS; all end with SS.根持有 SS;最後所有 rank 都有 SS。≈S\approx SLoading a checkpoint to a DP group (MegaScale)把檢查點載入 DP 群組(MegaScale)
reduceAll have SS; root ends with the sum.所有 rank 有 SS;根得到總和。N−1N S\tfrac{N-1}{N}\,SRare in training; loss logging訓練中少見;損失記錄
all-reduceAll have SS; all end with the sum.所有 rank 有 SS;所有 rank 得到總和。2(N−1)N S\tfrac{2(N-1)}{N}\,SClassic DP gradients; TP partial sums傳統 DP 梯度;TP 部分和
reduce-scatterAll have SS; each ends with S/NS/N of the sum.所有 rank 有 SS;每個得到總和的 S/NS/N。N−1N S\tfrac{N-1}{N}\,SZeRO / FSDP gradients; TP with sequence parallelZeRO / FSDP 梯度;TP 搭配序列平行
all-gatherEach has S/NS/N; all end with SS.每個有 S/NS/N;所有 rank 得到 SS。N−1N S\tfrac{N-1}{N}\,SFSDP parameters; CP keys and values; TPFSDP 參數;CP 的 key 與 value;TP
all-to-allEach has NN blocks of S/NS/N; block jj goes to rank jj.每個有 NN 塊各 S/NS/N;第 jj 塊送到 rank jj。N−1N S\tfrac{N-1}{N}\,SExpert parallelism (MoE); embedding lookups專家平行(MoE);embedding 查找
send / recvOne rank's SS moves to one other rank.一個 rank 的 SS 搬到另一個 rank。SSPipeline activations and their gradients管線的激活值與其梯度

Two patterns in the table matter for the rest of this chapter. First, an all-reduce is exactly a reduce-scatter followed by an all-gather, and its byte count is the sum of theirs. That is why ZeRO and FSDP, which split the two halves apart in time, move the same total bytes as classic data parallelism; they just move them at different moments and keep less memory. Second, the byte count per rank does not grow with NN for any collective in the table. What grows with NN is the number of dependent steps, which is the subject of the next section.

表中有兩個模式對本章其餘部分很重要。第一,all-reduce 正好是一個 reduce-scatter 接一個 all-gather,位元組數也是兩者之和。這就是為什麼把兩半在時間上拆開的 ZeRO 與 FSDP,搬動的總位元組數與傳統資料平行相同;它們只是在不同時刻搬、並佔用較少記憶體。第二,表中沒有任何集體操作的每 rank 位元組數會隨 NN 增長。隨 NN 增長的是相依步驟的數量,這是下一節的主題。

Panel 4.1 computes these byte counts for any NN and SS.

面板 4.1 為任何 NN 與 SS 算出這些位元組數。

Panel 4.1面板 4.1

Bytes each rank must send每個 rank 必須送出的位元組

Bytes sent per rank
每 rank 送出位元組
As a multiple of SS
相當於幾個 SS
All NN ranks together
全部 NN 個 rank 合計
Bytes ÷ 50 GB/s (400 Gb/s)
位元組 ÷ 50 GB/s(400 Gb/s)

The formulas are the lower bounds in the table above. The last tile is only the bandwidth term, with no α\alpha. Defaults: the 6.3 GB shard per rank of the Llama 3 405B example in Section 4.3 on 128 data-parallel ranks, which gives about 12.5 GB per rank and 0.25 s. For all-reduce the two bands show the reduce-scatter and the all-gather that it is made of. Move NN: the bytes per rank stop growing near 2S2S or SS, while the total over all ranks grows with NN.

公式是上表的下限。最後一格只有頻寬項,不含 α\alpha。預設值:第 4.3 節 Llama 3 405B 算例中每個 rank 6.3 GB 的分片,放在 128 個資料平行 rank 上,得到每 rank 約 12.5 GB、0.25 s。all-reduce 的兩條色帶是組成它的 reduce-scatter 與 all-gather。移動 NN:每 rank 的位元組數在 2S2S 或 SS 附近停止增長,而全部 rank 的總量隨 NN 增長。

The mapping from parallelism to collective is fixed by the mathematics of the split. DP averages gradients: all-reduce in the classic form, reduce-scatter plus all-gather in ZeRO and FSDP. TP splits a weight matrix, so every layer must all-reduce the partial products, or all-gather inputs and reduce-scatter outputs under sequence parallelism. EP routes each token to the rank holding its expert: an all-to-all by definition. PP hands activations to the next stage: a point-to-point send. CP in Llama 3 gathers the keys and values of the whole sequence: an all-gather (Llama 3 §3.3). The sizes differ by orders of magnitude: for GPT-3 175B at TP=8, PP=8, DP=512, HPN's Table 3 lists 560 MB of TP, 5.5 GB of DP and 6 MB of PP traffic, without saying over what period (Chapter 5 reads the table).

平行化到集體操作的對應由切分的數學決定。DP 要平均梯度:傳統形式是 all-reduce,ZeRO 與 FSDP 是 reduce-scatter 加 all-gather。TP 切分權重矩陣,所以每一層都必須對部分乘積做 all-reduce,或在序列平行下對輸入做 all-gather、對輸出做 reduce-scatter。EP 把每個 token 送到持有其專家的 rank:依定義就是 all-to-all。PP 把激活值交給下一個階段:點對點傳送。Llama 3 的 CP 收集整個序列的 key 與 value:all-gather(Llama 3 §3.3)。大小相差好幾個數量級:GPT-3 175B 在 TP=8、PP=8、DP=512 下,HPN 的 Table 3 列出 TP 560 MB、DP 5.5 GB、PP 6 MB,但沒有說明是多長時間內的量(第 5 章會解讀這張表)。

4.2The ring all-reduce環形 all-reduce

The naive way to average gradients is to send everything to one server, add it up, and send the result back. That server's link becomes the bottleneck. The ring algorithm avoids this. The GPUs form a ring. Each GPU's data is cut into NN chunks. In the first phase (reduce-scatter), each GPU passes one chunk to its neighbor and adds the chunk it receives. After N−1N-1 steps, every GPU holds the full sum of one chunk. In the second phase (all-gather), the complete chunks go around the ring again. After N−1N-1 more steps, every GPU has everything.

把梯度取平均最直覺的做法,是把所有東西送到一台伺服器加總再送回去。那台伺服器的鏈路就會成為瓶頸。環形演算法避開了這個問題。GPU 排成一個環,每顆 GPU 的資料切成 NN 塊。第一階段(reduce-scatter),每顆 GPU 把一塊傳給鄰居,並把收到的那塊加上去。經過 N−1N-1 步,每顆 GPU 都持有某一塊的完整總和。第二階段(all-gather),完整的塊再繞環一圈。再經過 N−1N-1 步,每顆 GPU 都拿到全部。

The number of bytes that each GPU sends is

每顆 GPU 送出的位元組數是

2⋅N−1N⋅S 2 \cdot \frac{N-1}{N} \cdot S

where SS is the size of its data. For large NN, this is almost exactly 2S2S, and it does not grow with NN. No algorithm can do better in bytes sent per GPU. That is what bandwidth-optimal means. The cost is latency: 2(N−1)2(N-1) sequential steps. For a ring of 1,000 GPUs, the steps add up. So NCCL uses rings for large messages and tree algorithms for small ones, and it builds hierarchical rings that stay inside a server first.

其中 SS 是它的資料大小。當 NN 很大時,這幾乎就是 2S2S,而且不隨 NN 增長。以每顆 GPU 送出的位元組數來看,沒有演算法能做得更好。這就是「頻寬最佳」的意思。代價是延遲:要跑 2(N−1)2(N-1) 個連續步驟。一千顆 GPU 的環,步數會累積得很多。所以 NCCL 對大訊息用環、對小訊息用樹狀演算法,並且會先建立留在伺服器內的階層式環。

The figure shows every step for four GPUs. Each GPU PiP_i starts with its own gradient gig_i, cut into four segments. A colored stripe in a segment means that GPU's data has been added into it. A "sends" row shows which segment each GPU passes to its right neighbor; the "after" row below it shows the result, with a red box around each segment that was just received and added.

下圖畫出四顆 GPU 的每一步。每顆 GPU PiP_i 一開始只有自己的梯度 gig_i,切成四段。某一段裡出現哪個顏色的條紋,代表那顆 GPU 的資料已經加進這一段。「送出」那一列顯示每顆 GPU 把哪一段傳給右鄰;下面的「後」那一列顯示結果,剛收到並加完的段用紅框標出。

P0: g0P0 的 g0s0段0s1段1s2段2s3段3P1: g1P1 的 g1s0段0s1段1s2段2s3段3P2: g2P2 的 g2s0段0s1段1s2段2s3段3P3: g3P3 的 g3s0段0s1段1s2段2s3段3Phase 1, reduce-scatter: each step, every GPU sends one segment to its right neighbor, which adds it第一階段 reduce-scatter:每一步每顆 GPU 送一段給右鄰,右鄰把它加上Phase 2, all-gather: the finished segments travel once more around the ring第二階段 all-gather:完成的段再沿環走一圈Start開始Step 1 sends步驟 1 送出P0from P3來自 P3After step 1步驟 1 後Step 2 sends步驟 2 送出P0from P3來自 P3After step 2步驟 2 後Step 3 sends步驟 3 送出P0from P3來自 P3After step 3步驟 3 後Step 4 sends步驟 4 送出P0from P3來自 P3After step 4步驟 4 後Step 5 sends步驟 5 送出P0from P3來自 P3After step 5步驟 5 後Step 6 sends步驟 6 送出P0from P3來自 P3After step 6步驟 6 後holds g0含 g0holds g1含 g1holds g2含 g2holds g3含 g3old value (no longer needed)舊值(不再需要)received this step本步收到Arrows go to the right neighbor; P3’s arrow leaves on the right and arrives at P0.箭頭=送給右鄰;P3 的箭頭往右出去,代表繞回 P0。
P0: g0P0 的 g0s0段0s1段1s2段2s3段3P1: g1P1 的 g1s0段0s1段1s2段2s3段3P2: g2P2 的 g2s0段0s1段1s2段2s3段3P3: g3P3 的 g3s0段0s1段1s2段2s3段3Phase 1, reduce-scatter: each step, every GPU sends one segment to its right neighbor, which adds it第一階段 reduce-scatter:每一步每顆 GPU 送一段給右鄰,右鄰把它加上Phase 2, all-gather: the finished segments travel once more around the ring第二階段 all-gather:完成的段再沿環走一圈Start開始Step 1 sends步驟 1 送出P0from P3來自 P3After step 1步驟 1 後Step 2 sends步驟 2 送出P0from P3來自 P3After step 2步驟 2 後Step 3 sends步驟 3 送出P0from P3來自 P3After step 3步驟 3 後Step 4 sends步驟 4 送出P0from P3來自 P3After step 4步驟 4 後Step 5 sends步驟 5 送出P0from P3來自 P3After step 5步驟 5 後Step 6 sends步驟 6 送出P0from P3來自 P3After step 6步驟 6 後holds g0含 g0holds g1含 g1holds g2含 g2holds g3含 g3old value (no longer needed)舊值(不再需要)received this step本步收到Arrows go to the right neighbor; P3’s arrow leaves on the right and arrives at P0.箭頭=送給右鄰;P3 的箭頭往右出去,代表繞回 P0。
Figure 4.1. Ring all-reduce on four GPUs. After the three reduce-scatter steps, every GPU owns one complete segment (all four colors): P0 owns segment 1, P1 segment 2, P2 segment 3, P3 segment 0. The three all-gather steps copy those finished segments around the ring until every GPU has all of them. Every step moves one segment, a quarter of the data, on every link at the same time.圖 4.1。四顆 GPU 的環形 all-reduce。三個 reduce-scatter 步驟之後,每顆 GPU 各擁有一段完整的段(四種顏色都有):P0 擁有段 1、P1 段 2、P2 段 3、P3 段 0。三個 all-gather 步驟再把這些完成的段沿環複製,直到每顆 GPU 都擁有全部。每一步在每條鏈路上同時搬一段,也就是四分之一的資料。Drawn for this primer; segment indices follow the standard ring schedule (GPU r sends segment r − s at reduce-scatter step s).

The ring, one step at a time環,一步一步來

The figure above showed the ring as a picture. Here is the index arithmetic, because it explains why every link is busy in every step, and that is the property that makes the ring bandwidth-optimal. Number the ranks 00 to N−1N-1 and cut each rank's buffer into NN chunks, also numbered 00 to N−1N-1. Rank ii always sends to rank i+1(modN)i+1 \pmod{N} and receives from rank i−1i-1.

上圖把環畫成一張圖。這裡給出索引算術,因為它解釋了為什麼每一步每條鏈路都在忙,而這正是讓環達到頻寬最佳的性質。把 rank 編號 00 到 N−1N-1,把每個 rank 的緩衝區切成 NN 塊,同樣編號 00 到 N−1N-1。rank ii 永遠送給 rank i+1(modN)i+1 \pmod{N},並從 rank i−1i-1 接收。

  1. Reduce-scatter, step ss (s=0,…,N−2s = 0, \dots, N-2). Rank ii sends chunk (i−s) mod N(i - s) \bmod N, which it has partly summed, to its right neighbor. The neighbor adds its own copy of that chunk to what arrives. After step ss, the chunk that rank ii has just received contains the contributions of s+2s+2 ranks. After N−1N-1 steps, rank ii holds the complete sum of exactly one chunk, number (i+1) mod N(i + 1) \bmod N, and partial sums of the others that it no longer needs.Reduce-scatter,第 ss 步(s=0,…,N−2s = 0, \dots, N-2)。rank ii 把它已部分加總的第 (i−s) mod N(i - s) \bmod N 塊送給右鄰。鄰居把自己那一塊加到收到的資料上。第 ss 步之後,rank ii 剛收到的那塊包含 s+2s+2 個 rank 的貢獻。N−1N-1 步之後,rank ii 持有恰好一塊的完整總和(第 (i+1) mod N(i + 1) \bmod N 塊),以及其他不再需要的部分和。
  2. All-gather, step ss (s=0,…,N−2s = 0, \dots, N-2). Rank ii sends the complete chunk (i+1−s) mod N(i + 1 - s) \bmod N to its right neighbor, which overwrites its partial sum with the finished one. After N−1N-1 steps every rank has every complete chunk.All-gather,第 ss 步(s=0,…,N−2s = 0, \dots, N-2)。rank ii 把完整的第 (i+1−s) mod N(i + 1 - s) \bmod N 塊送給右鄰,右鄰用完成品覆寫自己的部分和。N−1N-1 步之後每個 rank 都有每一塊完整的總和。

Count the traffic: in each of the 2(N−1)2(N-1) steps, all NN links carry one chunk of S/NS/N bytes at the same time, and no link is idle while another works. The bytes per rank are 2(N−1)×S/N2(N-1) \times S/N, as in the table. Count the latency too: a step cannot start until the previous chunk has fully arrived and been added, so the ring pays α\alpha a total of 2(N−1)2(N-1) times. NCCL pipelines several chunks through each ring, which hides part of each α\alpha, but the dependent chain still grows linearly with NN.

算一算流量:在 2(N−1)2(N-1) 步的每一步,全部 NN 條鏈路同時各承載一塊 S/NS/N 位元組,沒有鏈路在別人工作時閒著。每 rank 的位元組數是 2(N−1)×S/N2(N-1) \times S/N,與表中一致。也算一算延遲:前一塊完整到達並相加之後下一步才能開始,所以環要付 α\alpha 共 2(N−1)2(N-1) 次。NCCL 會讓數個 chunk 在每個環中管線化,隱藏每個 α\alpha 的一部分,但相依鏈仍隨 NN 線性增長。

The figure below writes the two index rules as a table of the chunk that each rank sends in each step.

下圖把兩條索引規則寫成一張表:每個 rank 在每一步送出哪個 chunk。

reduce-scatter, s = 0reduce-scatter,s = 0c0c1c2c3R0R1R2R3reduce-scatterall-gathers = 0s = 1s = 2s = 0s = 1s = 2R0→R1c0c3c2c1c0c3R1→R2c1c0c3c2c1c0R2→R3c2c1c0c3c2c1R3→R0c3c2c1c0c3c2Each column holds every chunk once: 4 links busy, 4 different chunks.每一欄每個 chunk 恰好出現一次:4 條鏈路都忙,載 4 個不同的 chunk。Orange: chunk c1 moves one rank per step.橘色:chunk c1 每一步前進一個 rank。shown at left即左圖
reduce-scatter, s = 0reduce-scatter,s = 0c0c1c2c3R0R1R2R3reduce-scatterall-gathers = 0s = 1s = 2s = 0s = 1s = 2R0→R1c0c3c2c1c0c3R1→R2c1c0c3c2c1c0R2→R3c2c1c0c3c2c1R3→R0c3c2c1c0c3c2Each column holds every chunk once: 4 links busy, 4 different chunks.每一欄每個 chunk 恰好出現一次:4 條鏈路都忙,載 4 個不同的 chunk。Orange: chunk c1 moves one rank per step.橘色:chunk c1 每一步前進一個 rank。shown at left即左圖
Figure 4.2. The send schedule of the ring all-reduce for N=4N = 4. Left: in reduce-scatter step 0, rank ii sends chunk ii to rank i+1i+1, so every link carries a different chunk. Right: the chunk that each rank sends in all six steps, (i−s) mod 4(i - s) \bmod 4 in the reduce-scatter and (i+1−s) mod 4(i + 1 - s) \bmod 4 in the all-gather. Every column contains each chunk once. Follow chunk c1 along the diagonal: it moves one rank per step, so each step depends on the step before it.圖 4.2。N=4N = 4 時環形 all-reduce 的傳送表。左:reduce-scatter 第 0 步,rank ii 把 chunk ii 送給 rank i+1i+1,所以每條鏈路載的 chunk 都不同。右:六步中每個 rank 送出的 chunk,reduce-scatter 是 (i−s) mod 4(i - s) \bmod 4,all-gather 是 (i+1−s) mod 4(i + 1 - s) \bmod 4。每一欄每個 chunk 恰好出現一次。沿對角線追蹤 chunk c1:它每一步前進一個 rank,所以每一步都依賴前一步。Drawn for this primer from the index rules above.

The figure below records the whole run for N=4N = 4 as seven snapshots of the grid of ranks and chunks. Panel 4.2 then animates the same rules for 4, 6 or 8 ranks.

下圖把 N=4N = 4 的整個過程記成 rank 與 chunk 網格的七張快照。面板 4.2 則用同樣的規則為 4、6 或 8 個 rank 做動畫。

start開始c0c1c2c3R01111R11111R21111R31111sent 0已送 0reduce-scatter 1reduce-scatter 第 1 步c0c1c2c3R01112R12111R21211R31121sent 1 × S/4已送 1 × S/4reduce-scatter 2reduce-scatter 第 2 步c0c1c2c3R01132R12113R23211R31321sent 2 × S/4已送 2 × S/4reduce-scatter 3reduce-scatter 第 3 步c0c1c2c3R01432R12143R23214R34321sent 3 × S/4已送 3 × S/4all-gather 1all-gather 第 1 步c0c1c2c3R04432R12443R23244R34324sent 4 × S/4已送 4 × S/4all-gather 2all-gather 第 2 步c0c1c2c3R04434R14443R23444R34344sent 5 × S/4已送 5 × S/4all-gather 3all-gather 第 3 步c0c1c2c3R04444R14444R24444R34444sent 6 × S/4已送 6 × S/41–3: partial sum1–3:部分和4: complete sum4:完整總和changed this step本步改變rows R0–R3: ranks列 R0–R3:rankcolumns c0–c3: chunks欄 c0–c3:chunkrank i → rank i + 1rank i → rank i + 1
start開始c0c1c2c3R01111R11111R21111R31111sent 0已送 0reduce-scatter 1reduce-scatter 第 1 步c0c1c2c3R01112R12111R21211R31121sent 1 × S/4已送 1 × S/4reduce-scatter 2reduce-scatter 第 2 步c0c1c2c3R01132R12113R23211R31321sent 2 × S/4已送 2 × S/4reduce-scatter 3reduce-scatter 第 3 步c0c1c2c3R01432R12143R23214R34321sent 3 × S/4已送 3 × S/4all-gather 1all-gather 第 1 步c0c1c2c3R04432R12443R23244R34324sent 4 × S/4已送 4 × S/4all-gather 2all-gather 第 2 步c0c1c2c3R04434R14443R23444R34344sent 5 × S/4已送 5 × S/4all-gather 3all-gather 第 3 步c0c1c2c3R04444R14444R24444R34444sent 6 × S/4已送 6 × S/41–3: partial sum1–3:部分和4: complete sum4:完整總和changed this step本步改變rows R0–R3: ranks列 R0–R3:rankcolumns c0–c3: chunks欄 c0–c3:chunkrank i → rank i + 1rank i → rank i + 1
Figure 4.3. The whole ring all-reduce for N=4N = 4 as snapshots after each of its 2(N−1)=62(N-1) = 6 steps. A number is how many ranks’ inputs a chunk has summed. In each reduce-scatter step every rank adds one incoming chunk, so the numbers climb by one along a diagonal; after three steps rank ii owns the finished chunk (i+1) mod 4(i+1) \bmod 4. The all-gather then copies the finished chunks around. Every step moves exactly one chunk of S/4S/4 on every link.圖 4.3。N=4N = 4 的完整環形 all-reduce,在 2(N−1)=62(N-1) = 6 步的每一步之後拍一張快照。數字是該 chunk 已加總了幾個 rank 的輸入。reduce-scatter 的每一步每個 rank 加上一個收到的 chunk,所以數字沿對角線逐一增加;三步之後 rank ii 持有完成的第 (i+1) mod 4(i+1) \bmod 4 塊。接著 all-gather 把完成的塊傳一圈。每一步每條鏈路恰好搬一塊 S/4S/4。Drawn for this primer from the index rules above (the same rules Panel 4.2 runs).
Panel 4.2面板 4.2

Ring all-reduce, step by step環形 all-reduce,一步一步看

Phase
階段
Step / total 2(N−1)2(N-1)
步數 / 總步數 2(N−1)2(N-1)
Bytes sent per rank so far
每 rank 至今送出
Links busy this step
本步忙碌的鏈路

Rows are ranks, columns are chunks. A cell's number is how many ranks' inputs that chunk has summed; green means complete. Orange arrows show the chunk each rank sends this step (rank ii → rank i+1i+1; the last rank wraps to rank 0). In every step all NN links carry exactly one chunk of S/NS/N bytes, so the total per rank is 2(N−1)/N×S2(N-1)/N \times S whatever NN is. Run honors reduced-motion settings.

列是 rank,欄是 chunk。格內數字是該塊已加總了幾個 rank 的輸入;綠色表示完整。橘色箭頭顯示本步每個 rank 送出的塊(rank ii → rank i+1i+1;最後一個 rank 繞回 rank 0)。每一步全部 NN 條鏈路各承載恰好一塊 S/NS/N 位元組,所以不論 NN 多大,每 rank 總量都是 2(N−1)/N×S2(N-1)/N \times S。「執行」會尊重減少動態效果的設定。

Animation 4.1 plays the same index rules on a physical ring of 3 to 8 ranks. Every link carries one chunk in every step, and each chunk fills as partial sums arrive.

動畫 4.1 在 3 到 8 個 rank 的實體環上播放同樣的索引規則。每一步每條鏈路都承載一塊,每塊隨著部分和抵達而逐漸填滿。

Animation 4.1動畫 4.1

The ring all-reduce on the ring在環上看環形 all-reduce

Rank ii sends to rank i+1i+1 (clockwise) and receives from rank i−1i-1, by the rules listed above: chunk (i−s) mod N(i - s) \bmod N in reduce-scatter step ss, and chunk (i+1−s) mod N(i + 1 - s) \bmod N in all-gather step ss. A chunk’s bar fills as ranks are added to it; green means all NN. Each chunk is S/NS/N bytes and each step is drawn as one transfer; NCCL also cuts each chunk into smaller pieces and pipelines them (Section 4.5).

rank ii 送給 rank i+1i+1(順時針),並從 rank i−1i-1 接收,依上面列出的規則:reduce-scatter 第 ss 步送第 (i−s) mod N(i - s) \bmod N 塊,all-gather 第 ss 步送第 (i+1−s) mod N(i + 1 - s) \bmod N 塊。塊的長條隨加入的 rank 而填滿;綠色表示全部 NN 個。每塊 S/NS/N 位元組,每一步畫成一次傳輸;NCCL 還會把每塊切成更小的片段並以管線方式傳送(第 4.5 節)。

4.3The α–β cost modelα–β 成本模型

The oldest and still most useful model of message passing, the α–β model, has two parameters. α\alpha is the latency of one message, from the decision to send until the receiver can act on the data, independent of size. β\beta is the time per byte, 1/B1/B for a link of bandwidth BB. A message of mm bytes costs α+m/B\alpha + m/B. A collective is a sequence of rounds in which every rank sends and receives at once, so its cost is

訊息傳遞最古老、也仍然最有用的模型——α–β 模型——有兩個參數。α\alpha 是一則訊息的延遲,從決定發送到接收端能使用資料,與大小無關。β\beta 是每個位元組的時間,對頻寬為 BB 的鏈路就是 1/B1/B。一則 mm 位元組的訊息成本為 α+m/B\alpha + m/B。集體操作是一連串每個 rank 同時發送與接收的回合,所以它的成本是

T=α×(number of dependent steps)+ bytes sent per rankB \begin{array}{l} T = \alpha \times (\text{number of dependent steps}) \\ \qquad +\ \dfrac{\text{bytes sent per rank}}{B} \end{array}
T=α×(相依步驟數)+ 每 rank 送出位元組數B \begin{array}{l} T = \alpha \times (\text{相依步驟數}) \\ \qquad +\ \dfrac{\text{每 rank 送出位元組數}}{B} \end{array}

The two terms come from different physics. α\alpha is set by software overhead, the NIC, and the propagation and switching delay of the path: tens of microseconds across several switch hops. Meta measured a round trip of about 22 µs across its training fabric, against the under-10 µs that NCCL's defaults assume (Meta RoCE paper, §6.1). β\beta is set by the slowest link: 400 Gb/s is 50 GB/s, so one gigabyte costs 20 ms. Everything in collective design is a trade between these two terms.

兩項來自不同的物理。α\alpha 由軟體開銷、NIC,以及路徑的傳播與交換延遲決定:跨數個交換器跳數時是數十微秒。Meta 量到跨訓練網路的往返約 22 µs,而 NCCL 的預設假設是低於 10 µs(Meta RoCE 論文,§6.1)。β\beta 由最慢的鏈路決定:400 Gb/s 是 50 GB/s,所以一 GB 要 20 ms。集體通訊設計中的一切都是這兩項之間的取捨。

The figure below takes the formula apart for the two algorithms that the next subsections derive, a ring and a tree on 4 ranks. The ring pays α\alpha six times and sends a small piece each time; the tree pays α\alpha twice and sends the whole buffer each time.

下圖把這條公式拆開,用的是接下來兩小節要推導的兩種演算法:4 個 rank 上的環與樹。環付六次 α\alpha、每次送一小片;樹只付兩次 α\alpha,但每次都送整個緩衝區。

α: latency of one stepα:每一步的延遲ring: S/N bytes per step環:每步送 S/N 位元組tree: all S bytes per step樹:每步送全部 S 位元組ring, N = 4環,N = 4α1α2α3α4α5α6ring, regrouped環,重新分組6α = 2(N−1)·α1.5·S/B = 2(N−1)/N·S/Btree (doubling), N = 4樹(倍增),N = 4αS/B1αS/B2tree, regrouped樹,重新分組2α2·S/B = log₂N·S/Btime時間TtreeTringDrawn with S/B = 4α, so the tree finishes first. With a larger S the ring’s smaller byte term wins.以 S/B = 4α 繪製,所以樹先完成;S 更大時,環較小的位元組項就會勝出。
α: latency of one stepα:每一步的延遲ring: S/N bytes per step環:每步送 S/N 位元組tree: all S bytes per step樹:每步送全部 S 位元組ring, N = 4環,N = 4α1α2α3α4α5α6ring, regrouped環,重新分組6α = 2(N−1)·α1.5·S/B = 2(N−1)/N·S/Btree (doubling), N = 4樹(倍增),N = 4αS/B1αS/B2tree, regrouped樹,重新分組2α2·S/B = log₂N·S/Btime時間TtreeTringDrawn with S/B = 4α, so the tree finishes first. With a larger S the ring’s smaller byte term wins.以 S/B = 4α 繪製,所以樹先完成;S 更大時,環較小的位元組項就會勝出。
Figure 4.4. The two terms of the cost model, drawn for four ranks. The ring pays α\alpha in each of its 2(N−1)=62(N-1) = 6 steps and sends S/NS/N each time; the doubling tree pays α\alpha only log⁡2N=2\log_2 N = 2 times but sends all of SS each time. Regrouping each bar gives α×steps+bytes/B\alpha \times \text{steps} + \text{bytes}/B.圖 4.4。成本模型的兩項,以四個 rank 繪製。環在 2(N−1)=62(N-1) = 6 步的每一步都付一次 α\alpha、每次送 S/NS/N;倍增樹只付 log⁡2N=2\log_2 N = 2 次 α\alpha,但每次送出全部的 SS。把每條長條重新分組,就得到 α×步數+位元組數/B\alpha \times \text{步數} + \text{位元組數}/B。Drawn for this primer from the formulas in this section.

Ring: bandwidth-optimal, latency-poor環:頻寬最佳,延遲不佳

In the ring all-reduce every rank sends S/NS/N bytes in each of 2(N−1)2(N-1) steps. Its cost is therefore

在環形 all-reduce 中,每個 rank 在 2(N−1)2(N-1) 步的每一步送出 S/NS/N 位元組。所以成本是

Tring=2(N−1) α+2(N−1)N⋅SB T_{\text{ring}} = 2(N-1)\,\alpha + \frac{2(N-1)}{N} \cdot \frac{S}{B}

The second term is as small as it can be: each rank must receive the other N−1N-1 contributions to the slice it will own, N−1N S\tfrac{N-1}{N}\,S bytes, and then the N−1N-1 finished slices it does not own, another N−1N S\tfrac{N-1}{N}\,S. No algorithm can deliver an all-reduce with fewer bytes into the busiest rank. The first term is the price. With 1,024 ranks and α=22 μs\alpha = 22\,\mu\text{s} the ring spends 2,046×22 μs=45 ms2{,}046 \times 22\,\mu\text{s} = 45\,\text{ms} in pure latency; for a 1 GB buffer the bandwidth term at 50 GB/s is 40 ms, so the ring is already more latency than data.

第二項已經小到不能再小:每個 rank 必須收到其他 N−1N-1 個對它將持有那一片的貢獻,即 N−1N S\tfrac{N-1}{N}\,S 位元組,然後再收到它不持有的 N−1N-1 片完成品,又是 N−1N S\tfrac{N-1}{N}\,S。沒有演算法能用更少進入最忙 rank 的位元組完成 all-reduce。第一項是代價。1,024 個 rank、α=22 μs\alpha = 22\,\mu\text{s} 時,環花 2,046×22 μs=45 ms2{,}046 \times 22\,\mu\text{s} = 45\,\text{ms} 的純延遲;對 1 GB 的緩衝區,50 GB/s 下的頻寬項是 40 ms,所以環的延遲已經多於資料。

Trees: latency-optimal, bandwidth-poor樹:延遲最佳,頻寬不佳

The opposite design is recursive doubling. In step kk each rank exchanges its whole buffer with the rank whose index differs in bit kk, and adds. After log⁡2N\log_2 N steps every rank holds the full sum. The cost is

相反的設計是遞迴倍增。在第 kk 步,每個 rank 與索引第 kk 位元不同的 rank 交換整個緩衝區並相加。log⁡2N\log_2 N 步之後每個 rank 都持有完整的總和。成本是

Ttree=(log⁡2N) α+(log⁡2N) SB T_{\text{tree}} = (\log_2 N)\,\alpha + (\log_2 N)\,\frac{S}{B}

For 1,024 ranks that is 10 steps instead of 2,046, but each rank now sends SS bytes ten times, five times more than the ring. Rabenseifner's algorithm (recursive halving for the reduce-scatter, doubling for the all-gather) gets the best of both in the model, 2(log⁡2N) α+2(N−1)N⋅S/B2(\log_2 N)\,\alpha + \tfrac{2(N-1)}{N} \cdot S/B, but needs a power-of-two NN and a fabric where every pair can talk at full rate at once. NCCL's own "tree" is a pipelined double binary tree that, in NVIDIA's description, keeps the byte count near the ring's while cutting the dependent steps to a logarithm. Treat the two formulas above as the ends of a spectrum and real implementations as points between them.

對 1,024 個 rank,那是 10 步而非 2,046 步,但現在每個 rank 要送 SS 位元組十次,是環的五倍。Rabenseifner 演算法(reduce-scatter 用遞迴減半,all-gather 用倍增)在模型中兼得兩者之長:2(log⁡2N) α+2(N−1)N⋅S/B2(\log_2 N)\,\alpha + \tfrac{2(N-1)}{N} \cdot S/B,但要求 NN 是 2 的冪,且網路要讓每一對都能同時以全速通訊。NCCL 自己的「tree」是管線化的雙二元樹,依 NVIDIA 的描述,它把位元組數維持在接近環的水準,同時把相依步驟減到對數級。把上面兩條公式當成一條光譜的兩端,真實實作則是中間的點。

The butterfly below shows both tree schemes on 8 ranks. The exchange pattern is the same in both: in step kk each rank pairs with the rank whose index differs in one bit. Recursive doubling sends the whole buffer in every step; recursive halving sends half of what is left.

下方的蝶形圖在 8 個 rank 上畫出這兩種樹狀方案。兩者的交換模式相同:第 kk 步每個 rank 與索引差一個位元的 rank 配對。遞迴倍增每一步都送整個緩衝區;遞迴減半只送剩下的一半。

recursivedoublingrecursivehalving遞迴倍增遞迴減半ranks, placed next to their partner in each step各 rank,每一步都排在夥伴旁邊start開始1R01R11R21R31R41R51R61R7step 1第 1 步partner i ⊕ 1夥伴 i ⊕ 12R02R12R22R32R42R52R62R7SS/2step 2第 2 步partner i ⊕ 2夥伴 i ⊕ 24R04R24R14R34R44R64R54R7SS/4step 3第 3 步partner i ⊕ 4夥伴 i ⊕ 48R08R48R18R58R28R68R38R7SS/8total sent per rank每個 rank 共送出Σ 3SΣ 7S/8
recursivedoublingrecursivehalving遞迴倍增遞迴減半ranks, placed next to their partner in each step各 rank,每一步都排在夥伴旁邊start開始1R01R11R21R31R41R51R61R7step 1第 1 步partner i ⊕ 1夥伴 i ⊕ 12R02R12R22R32R42R52R62R7SS/2step 2第 2 步partner i ⊕ 2夥伴 i ⊕ 24R04R24R14R34R44R64R54R7SS/4step 3第 3 步partner i ⊕ 4夥伴 i ⊕ 48R08R48R18R58R28R68R38R7SS/8total sent per rank每個 rank 共送出Σ 3SΣ 7S/8
Figure 4.5. Recursive doubling on 8 ranks. In step kk rank ii exchanges with rank i⊕2k−1i \oplus 2^{k-1} (its index with one bit flipped), and the number in each circle is how many ranks’ inputs it has summed: 1, 2, 4, then all 8 after log⁡28=3\log_2 8 = 3 steps. Recursive halving uses the same exchange pattern but sends only half of what is left, so its reduce-scatter totals 78 S\tfrac{7}{8}\,S; Rabenseifner’s algorithm follows it with the mirror-image all-gather.圖 4.5。8 個 rank 上的遞迴倍增。第 kk 步 rank ii 與 rank i⊕2k−1i \oplus 2^{k-1}(索引翻轉一個位元)交換,圓內數字是它已加總了幾個 rank 的輸入:1、2、4,log⁡28=3\log_2 8 = 3 步之後是全部 8 個。遞迴減半使用相同的交換模式,但只送剩下的一半,所以它的 reduce-scatter 總共是 78 S\tfrac{7}{8}\,S;Rabenseifner 演算法接著做鏡像的 all-gather。Drawn for this primer from the formulas in this section.

Animation 4.2 plays both schemes on 4 or 8 ranks. In recursive halving the partner distance doubles while the message halves; the all-gather then runs the same pairs in reverse order.

動畫 4.2 在 4 或 8 個 rank 上播放這兩種方案。遞迴減半時夥伴距離加倍、訊息減半;接著 all-gather 以相反順序走同樣的配對。

Animation 4.2動畫 4.2

Recursive halving and doubling, step by step遞迴減半與倍增,一步一步看

Each rank’s buffer is cut into NN chunks, A, B, … Halving + doubling is Rabenseifner’s algorithm: in reduce-scatter step kk, rank ii pairs with rank i⊕2k−1i \oplus 2^{k-1}, keeps one half of its current part, sends the other half and adds what arrives; the all-gather uses the same pairs in reverse order and copies instead of adding. With partners at distance 1 first, rank ii ends up owning the chunk whose index is ii with its bits reversed (rank 1 owns chunk E when N=8N = 8). Recursive doubling sends the whole buffer SS in every step. NN must be a power of two. The brackets on the left join the partners of the current step; a step is drawn as one exchange.

每個 rank 的緩衝區切成 NN 塊:A、B、… 減半 + 倍增就是 Rabenseifner 演算法:在 reduce-scatter 第 kk 步,rank ii 與 rank i⊕2k−1i \oplus 2^{k-1} 配對,保留目前那一份的一半、送出另一半,並把收到的加上去;all-gather 以相反順序走同樣的配對,改為複製而不相加。由於先與距離 1 的夥伴配對,rank ii 最後擁有的塊,其編號是 ii 的位元反轉(N=8N = 8 時 rank 1 擁有 E 塊)。遞迴倍增每一步都送整個緩衝區 SS。NN 必須是 2 的冪。左側的括號連起本步的夥伴;每一步畫成一次交換。

NCCL's double binary tree is built so that two trees can work at the same time (figure below). Each tree is an ordinary binary tree over the nodes, but no node is an inner node in both trees, so no node has to forward data in both. Inside a node the GPUs form a chain, and the tree branches only between nodes (Demystifying NCCL, HOTI 2025).

NCCL 的雙二元樹是為了讓兩棵樹能同時運作而建的(見下圖)。每棵樹都是節點上一棵普通的二元樹,但沒有節點同時是兩棵樹的內部節點,所以沒有節點必須在兩棵樹裡都轉送資料。在一個節點內,GPU 串成一條鏈,樹只在節點之間分支(Demystifying NCCL,HOTI 2025)。

tree 1樹 1inner nodes 0 2 4 6內部節點 0 2 4 604261357root根tree 2樹 2inner nodes 1 3 5 7內部節點 1 3 5 773150246root根No node is an inner node in both trees: here even nodes forward in tree 1 and odd nodes in tree 2.沒有節點同時是兩棵樹的內部節點:這裡偶數節點在樹 1 轉送,奇數節點在樹 2 轉送。=circle = server: its 8 GPUs form a chain; the tree branches only between servers一個圓 = 一台伺服器:其 8 顆 GPU 串成一條鏈,樹只在伺服器之間分支
tree 1樹 1inner nodes 0 2 4 6內部節點 0 2 4 604261357root根tree 2樹 2inner nodes 1 3 5 7內部節點 1 3 5 773150246root根No node is an inner node in both trees: here even nodes forward in tree 1 and odd nodes in tree 2.沒有節點同時是兩棵樹的內部節點:這裡偶數節點在樹 1 轉送,奇數節點在樹 2 轉送。=circle = server: its 8 GPUs form a chain; the tree branches only between servers一個圓 = 一台伺服器:其 8 顆 GPU 串成一條鏈,樹只在伺服器之間分支
Figure 4.6. The two complementary trees NCCL builds over 8 nodes: tree 2 is tree 1 mirrored (node rr becomes 7−r7 - r). Filled circles forward data; outlined circles are leaves. Because every node forwards in at most one tree, both trees can run at once, and in NVIDIA’s description each tree carries half of the buffer.圖 4.6。NCCL 在 8 個節點上建立的兩棵互補的樹:樹 2 是樹 1 的鏡像(節點 rr 變成 7−r7 - r)。實心圓轉送資料;空心圓是葉節點。因為每個節點最多只在一棵樹裡轉送,兩棵樹可以同時運作,依 NVIDIA 的描述每棵樹承載一半的緩衝區。Drawn for this primer from Demystifying NCCL (HOTI 2025) and NCCL’s tree construction.
Ring環Tree (binary)樹(二元)Rabenseifner
How data moves資料怎麼走around a ring, always to the same neighbor沿環走,永遠送給同一個鄰居up to the root, then back down往上到根,再往下swaps with a partner; the partner changes every step與夥伴交換;每一步換一個夥伴
Sequential steps循序步數2(N−1)2(N-1)≈2log⁡2N\approx 2\log_2 N2log⁡2N2\log_2 N
Steps for 1,024 GPUs1,024 顆 GPU 的步數2,0462020
Size of one message單則訊息大小S/NS/NSS, the whole bufferSS,整個緩衝區S/2, S/4, …, S/NS/2,\ S/4,\ \dots,\ S/N
Bytes sent per GPU每顆 GPU 送出的位元組2N−1NS≈2S2\tfrac{N-1}{N}S \approx 2SSS (a GPU at the bottom of the tree) to 3S3S (inner GPU: SS up, SS to each child), if not pipelined不切塊時,SS(葉)到 3S3S(內部 GPU:往上 SS、給每個子節點各 SS)2N−1NS≈2S2\tfrac{N-1}{N}S \approx 2S
Strength優點fewest possible bytes; only neighbor links are used位元組數最少;只用到相鄰的鏈路few steps, so low latency for small messages步數少,小訊息延遲低fewest bytes and few steps位元組少、步數也少
Weakness缺點steps grow with NN, so small messages are slow at scale步數隨 NN 增長,大規模時小訊息很慢each message carries all of SS; needs pipelining for large messages每則訊息都帶整個 SS;大訊息必須切塊串流NN should be a power of two; distant partners load more linksNN 最好是 2 的冪次;相隔遠的夥伴會占用更多鏈路
Typical use典型用途NCCL, large messagesNCCL,大訊息NCCL (two pipelined trees), small and medium messagesNCCL(兩棵切塊串流的樹),中小訊息MPI libraries, large messagesMPI 函式庫,大訊息

The crossover交叉點

Set the ring and doubling costs equal and solve for SS. The message size at which they tie is

令環與倍增的成本相等並解出 SS。兩者打平的訊息大小是

S∗=αB⋅2(N−1)−log⁡2Nlog⁡2N−2(N−1)/N S^* = \alpha B \cdot \frac{2(N-1) - \log_2 N}{\log_2 N - 2(N-1)/N}

Below S∗S^* the tree wins; above it the ring wins. The product αB\alpha B, the bytes a link carries during one latency, appears in every formula in this chapter. For N=128N = 128, α=22 μs\alpha = 22\,\mu\text{s} and B=50 GB/sB = 50\GBs, S∗S^* is about 49×1.1 MB≈54 MB49 \times 1.1\,\text{MB} \approx 54\,\text{MB}. Double the latency and the crossover doubles, so a library tuned for a 5 µs fabric chooses the wrong algorithm on a 22 µs one: its table is off by four times.

S∗S^* 以下樹勝出;以上環勝出。乘積 αB\alpha B——鏈路在一個延遲期間能承載的位元組數——出現在本章的每一條公式中。N=128N = 128、α=22 μs\alpha = 22\,\mu\text{s}、B=50 GB/sB = 50\GBs 時,S∗S^* 約為 49×1.1 MB≈54 MB49 \times 1.1\,\text{MB} \approx 54\,\text{MB}。延遲加倍,交叉點就加倍,所以為 5 µs 網路調校的函式庫在 22 µs 的網路上會選錯演算法:它的表差了四倍。

The figure below plots both formulas for these values. For small messages each curve is flat at its latency term, 254 α254\,\alpha for the ring and 7 α7\,\alpha for the tree. For large messages each curve rises with its byte term, and the ring's curve is lower because the ring sends fewer bytes.

下圖畫出這組數值下的兩條公式。小訊息時每條曲線平在它的延遲項:環是 254 α254\,\alpha,樹是 7 α7\,\alpha。大訊息時每條曲線隨它的位元組項上升,而環的曲線較低,因為環送的位元組較少。

1 KB1 MB1 GB100 µs1 ms10 ms100 ms1 s10 smessage size S (bytes, log scale)訊息大小 S(位元組,對數座標)all-reduce time T (log scale)all-reduce 時間 T(對數座標)N = 128 · α = 22 µs · B = 50 GB/sS* ≈ 54 MB254α ≈ 5.6 ms7α ≈ 154 µsTtreeTringTtree < TringTring < Ttree
Figure 4.7. Both formulas of this section for N=128N = 128, α=22 μs\alpha = 22\,\mu\text{s} and 400 Gb/s (log scales). For small messages each curve is flat at its latency term; for large ones each rises in proportion to its bytes, and the ring rises less because it sends fewer. The curves cross at S∗≈54 MBS^* \approx 54\,\text{MB}.圖 4.7。本節兩條公式在 N=128N = 128、α=22 μs\alpha = 22\,\mu\text{s}、400 Gb/s 下的曲線(雙對數座標)。小訊息時每條曲線平在它的延遲項;大訊息時隨位元組數成比例上升,而環因為送得較少,上升得較少。兩條曲線交於 S∗≈54 MBS^* \approx 54\,\text{MB}。Drawn for this primer from the formulas in this section.

Two worked examples兩個算例

A data-parallel gradient exchange. Llama 3 405B has 405 billion parameters; in bf16 the gradients are 810 GB. As a first estimate, let 128 data-parallel ranks each hold a full copy and all-reduce it over 400 Gb/s (50 GB/s) links with α=22 μs\alpha = 22\,\mu\text{s}. In the real run (Llama 3 Table 4, row 2) the model is also split by TP = 8 and PP = 16, so each DP rank owns only a shard, and FSDP's reduce-scatter plus all-gather moves that shard. Both are compared with one step of compute at 400 TFLOP/s per GPU on 16,384 GPUs with a 16M-token batch. The arithmetic, one question per row:

一次資料平行的梯度交換。Llama 3 405B 有 4,050 億個參數;bf16 的梯度是 810 GB。先做第一個估計:讓 128 個資料平行 rank 各持有一份完整副本,在 400 Gb/s(50 GB/s)鏈路上以 α=22 μs\alpha = 22\,\mu\text{s} 做 all-reduce。在真實運行中(Llama 3 Table 4 第二行)模型還被 TP = 8 與 PP = 16 切分,所以每個 DP rank 只持有一個分片,由 FSDP 的 reduce-scatter 加 all-gather 搬動。兩者都與一步的計算量比較:16,384 顆 GPU、每顆 400 TFLOP/s、16M token 批次。逐列計算如下:

Question問題Calculation算式Result結果
Full-copy all-reduce, bandwidth term (810 GB, 128 ranks, 50 GB/s)完整副本 all-reduce 的頻寬項(810 GB、128 個 rank、50 GB/s)2×127128×810÷502 \times \tfrac{127}{128} \times 810 \div 50≈32.1\approx 32.1 s
Full-copy all-reduce, latency term (254 dependent steps at α=22 μs\alpha = 22\,\mu\text{s})完整副本 all-reduce 的延遲項(254 個相依步驟,α=22 μs\alpha = 22\,\mu\text{s})254×22 μs254 \times 22\,\mu\text{s}≈5.6\approx 5.6 ms
Parameters per DP rank with TP = 8 and PP = 16 (Llama 3 Table 4, row 2)TP = 8、PP = 16 時每個 DP rank 的參數(Llama 3 Table 4 第二行)405×109÷(8×16)405 \times 10^{9} \div (8 \times 16)≈3.2×109\approx 3.2 \times 10^{9}parameters, 6.3 GB in bf16個參數,bf16 下 6.3 GB
FSDP reduce-scatter plus all-gather of that 6.3 GB shardFSDP 對這個 6.3 GB 分片做 reduce-scatter 加 all-gather2×127128×6.3÷502 \times \tfrac{127}{128} \times 6.3 \div 50≈0.25\approx 0.25 s
FLOP in one step: 6N6N per token, 16M tokens一步的 FLOP:每個 token 6N6N、16M 個 token6×405×109×16×1066 \times 405 \times 10^{9} \times 16 \times 10^{6}≈3.89×1019\approx 3.89 \times 10^{19} FLOP
Step time on 16,384 GPUs at 400 TFLOP/s each16,384 顆 GPU、每顆 400 TFLOP/s 的步時間3.89×1019÷(16,384×4.0×1014)3.89 \times 10^{19} \div (16{,}384 \times 4.0 \times 10^{14})≈5.9\approx 5.9 s
Sharded exchange as a share of the step, if nothing hides it若沒有任何隱藏,分片交換占一步的比例0.25÷5.90.25 \div 5.9≈4%\approx 4\%

The full-copy all-reduce would spend about 32 s per step on bandwidth, and its 5.6 ms latency term is nothing beside that. With the real layout the exchange is about 0.25 s, 4% of a 5.9 s step if nothing hides it; most of it is hidden (Section 4.7).

完整副本的 all-reduce 每步要花約 32 s 在頻寬上,它 5.6 ms 的延遲項相比之下微不足道。換成真實的配置,交換約 0.25 s;若沒有任何隱藏,占 5.9 s 一步的 4%;大部分都被隱藏了(第 4.7 節)。

A small tensor-parallel all-reduce. Take a 1 MB all-reduce among the 8 GPUs of one server, joined by NVSwitch at about 450 GB/s per GPU, and assume α=5 μs\alpha = 5\,\mu\text{s} inside the server (the exact value depends on the protocol). The ring takes 14 dependent steps and the doubling tree 3. The arithmetic, one question per row:

一次小的張量平行 all-reduce。取一台伺服器內 8 顆 GPU 之間 1 MB 的 all-reduce,GPU 由 NVSwitch 連接、每顆約 450 GB/s,並假設伺服器內 α=5 μs\alpha = 5\,\mu\text{s}(精確值取決於協定)。環要走 14 個相依步驟,倍增樹 3 個。逐列計算如下:

Question問題Calculation算式Result結果
Ring, latency term (14 steps at 5 µs)環的延遲項(14 步、每步 5 µs)14×514 \times 57070 µs
Ring, bandwidth term (1 MB at 450 GB/s)環的頻寬項(1 MB、450 GB/s)2×78×1 MB÷450 GB/s2 \times \tfrac{7}{8} \times 1\,\text{MB} \div 450\GBs≈3.9\approx 3.9 µs
Ring, total環的總耗時70+3.970 + 3.9≈74\approx 74 µs95% of it latency其中 95% 是延遲
Doubling tree, latency term (3 steps at 5 µs)倍增樹的延遲項(3 步、每步 5 µs)3×53 \times 51515 µs
Doubling tree, bandwidth term (the whole 1 MB, 3 times)倍增樹的頻寬項(整個 1 MB 送 3 次)3×1 MB÷450 GB/s3 \times 1\,\text{MB} \div 450\GBs≈6.7\approx 6.7 µs
Doubling tree, total倍增樹的總耗時15+6.715 + 6.7≈22\approx 22 µsabout 3.4 times faster than the ring比環快約 3.4 倍

The tree is more than three times faster, and 95% of the ring's time is latency. Small collectives are latency problems, and the link speed is almost irrelevant to them. That is the whole reason NCCL has more than one algorithm and protocol.

樹快了三倍多,而環的時間有 95% 是延遲。小的集體操作是延遲問題,鏈路速度對它們幾乎無關。這就是 NCCL 擁有多種演算法與協定的全部理由。

Panel 4.3面板 4.3

Collective cost explorer集體操作成本探索器

Time
耗時
Bytes sent per rank
每 rank 送出位元組
Dependent steps ×α{}\times \alpha
相依步驟 ×α{}\times \alpha
Bandwidth efficiency
頻寬效率

Defaults are the first worked example: ≈ 810 GB per rank on 128 ranks at 400 Gb/s with Meta's measured 22 µs latency (ring: about 32 s). The curves show time against message size for all three algorithms; the dot marks the ring/tree crossover S∗S^*. Efficiency\text{Efficiency} =(optimal bytes/B)÷time= (\text{optimal bytes} / B) \div \text{time}. The hierarchical model uses NVLink at 3.6 Tb/s inside each group of 8 and the slider bandwidth between groups, with the same α\alpha for every step. Try N=1,024N = 1{,}024 at 1 MB, then press NVLink and set N=8N = 8.

預設值是第一個算例:128 個 rank、每個 ≈ 810 GB、400 Gb/s、Meta 實測的 22 µs 延遲(環:約 32 s)。曲線是三種演算法的耗時對訊息大小;圓點標出環/樹的交叉點 S∗S^*。效率=(最佳位元組數/B)÷耗時\text{效率} = (\text{最佳位元組數} / B) \div \text{耗時}。階層式模型在每組 8 顆內使用 3.6 Tb/s 的 NVLink、組間使用滑桿頻寬,每一步用相同的 α\alpha。試試 N=1,024N = 1{,}024、1 MB,然後按 NVLink 並把 NN 設為 8。

Stop and think停下來想一想

In Panel 4.3, set N=1,024N = 1{,}024, S=1 MBS = 1\,\text{MB} and α=22 μs\alpha = 22\,\mu\text{s}. The ring takes about 45 ms and the tree about 0.4 ms. Now raise SS until the ring wins. How does the crossover move when you halve α\alpha to 11 µs? This is the decision NCCL makes, with a built-in table, at the start of every collective.

在面板 4.3 中設 N=1,024N = 1{,}024、S=1 MBS = 1\,\text{MB}、α=22 μs\alpha = 22\,\mu\text{s}。環大約要 45 ms,樹大約 0.4 ms。現在提高 SS 直到環勝出。把 α\alpha 減半到 11 µs 時交叉點怎麼移動?這就是 NCCL 在每次集體操作開始時,用內建的表所做的決定。

4.4Hierarchical collectives and in-network reduction階層式集體操作與網內歸約

A training server is two networks in one. Inside it, 8 GPUs share an NVSwitch fabric at about 3.6 Tb/s per GPU. Outside it, each GPU has a 400 Gb/s NIC. The gap is about 9× (Rail-only paper, §II). A flat ring across 1,024 GPUs ignores this: 7 of every 8 links in the ring would be NVLink and 1 of every 8 would be a NIC, and the ring runs at the pace of the slowest link, so the NVLink bandwidth is wasted.

一台訓練伺服器是兩個網路合在一起。在內部,8 顆 GPU 共用每顆約 3.6 Tb/s 的 NVSwitch 網路。在外部,每顆 GPU 有一張 400 Gb/s 的 NIC。差距約 9 倍(Rail-only 論文,§II)。跨 1,024 顆 GPU 的平面環忽略了這點:環中每 8 條鏈路有 7 條是 NVLink、1 條是 NIC,而環以最慢鏈路的速度前進,所以 NVLink 的頻寬被浪費。

The hierarchical all-reduce does the operation in three phases. First, a reduce-scatter inside each server over NVSwitch: 7 steps, 78 S\tfrac{7}{8}\,S bytes per GPU, at NVLink speed. Each GPU now owns one eighth of the server's partial sum. Second, an all-reduce across servers, but only among the GPUs that own the same eighth: GPU kk of every server forms a group of N/8N/8 ranks and all-reduces S/8S/8 bytes over the network. Third, an all-gather inside each server, again 7 steps at NVLink speed. The network now carries 2×N/8−1N/8×S/8≈S/42 \times \tfrac{N/8 - 1}{N/8} \times S/8 \approx S/4 bytes per GPU instead of 2S2S: eight times less. The rail-only paper's analysis found this for 16 DGX GH200 systems, where the high-bandwidth domain holds 256 GPUs: 98% of the all-reduce bytes crossed NVSwitch and 2% crossed the network.

階層式 all-reduce分三個階段做這件事。第一,在每台伺服器內透過 NVSwitch 做 reduce-scatter:7 步、每顆 GPU 78 S\tfrac{7}{8}\,S 位元組、NVLink 速度。現在每顆 GPU 持有該伺服器部分和的八分之一。第二,跨伺服器做 all-reduce,但只在持有同一個八分之一的 GPU 之間:每台伺服器的 GPU kk 組成 N/8N/8 個 rank 的群組,在網路上對 S/8S/8 位元組做 all-reduce。第三,在每台伺服器內做 all-gather,同樣 7 步、NVLink 速度。網路現在每顆 GPU 承載 2×N/8−1N/8×S/8≈S/42 \times \tfrac{N/8 - 1}{N/8} \times S/8 \approx S/4 位元組而非 2S2S:少了八倍。Rail-only 論文分析 16 台 DGX GH200 系統時發現這一點,那裡的高頻寬 domain 容納 256 顆 GPU:all-reduce 有 98% 的位元組跨 NVSwitch、2% 跨網路。

The figure below draws the three phases on two servers. Follow the slice that each GPU owns: only slice kk of GPU kk leaves the server, and it travels only to GPU kk of the other server.

下圖在兩台伺服器上畫出這三個階段。追蹤每顆 GPU 持有的那一片:只有 GPU kk 的第 kk 片會離開伺服器,而且只送到另一台伺服器的 GPU kk。

GPU 0GPU 1GPU 2GPU 3GPU 4GPU 5GPU 6GPU 7start: every GPU holds its whole buffer S, cut into 8 slices開始:每顆 GPU 持有整個緩衝區 S,切成 8 片AB① reduce-scatter in each server (NVSwitch): GPU k keeps slice k · 7/8·S per GPU① 伺服器內 reduce-scatter(NVSwitch):GPU k 留下第 k 片 · 每顆 7/8·SAB② all-reduce of slice k among the GPU k of every server (network) · ≈ S/4 per GPU② 各伺服器的 GPU k 之間對第 k 片做 all-reduce(網路)· 每顆 ≈ S/4AB③ all-gather in each server (NVSwitch): every GPU gets all 8 finished slices · 7/8·S③ 伺服器內 all-gather(NVSwitch):每顆 GPU 拿到全部 8 片完成品 · 7/8·SABown data自己的資料sum over one server一台伺服器的和sum over all GPUs全部 GPU 的和network網路one server (NVSwitch)一台伺服器(NVSwitch)
GPU 0GPU 1GPU 2GPU 3GPU 4GPU 5GPU 6GPU 7start: every GPU holds its whole buffer S, cut into 8 slices開始:每顆 GPU 持有整個緩衝區 S,切成 8 片AB① reduce-scatter in each server (NVSwitch): GPU k keeps slice k · 7/8·S per GPU① 伺服器內 reduce-scatter(NVSwitch):GPU k 留下第 k 片 · 每顆 7/8·SAB② all-reduce of slice k among the GPU k of every server (network) · ≈ S/4 per GPU② 各伺服器的 GPU k 之間對第 k 片做 all-reduce(網路)· 每顆 ≈ S/4AB③ all-gather in each server (NVSwitch): every GPU gets all 8 finished slices · 7/8·S③ 伺服器內 all-gather(NVSwitch):每顆 GPU 拿到全部 8 片完成品 · 7/8·SABown data自己的資料sum over one server一台伺服器的和sum over all GPUs全部 GPU 的和network網路one server (NVSwitch)一台伺服器(NVSwitch)
Figure 4.8. The hierarchical all-reduce on two 8-GPU servers. Each GPU’s buffer is drawn as 8 slices. Phase ① sums the server’s buffers over NVSwitch and leaves slice kk on GPU kk; phase ② is the only one that uses the network, and only GPU kk talks to GPU kk, carrying 2×N/8−1N/8×S/8≈S/42 \times \tfrac{N/8 - 1}{N/8} \times S/8 \approx S/4 per GPU; phase ③ spreads the finished slices back over NVSwitch.圖 4.8。兩台 8 顆 GPU 伺服器上的階層式 all-reduce。每顆 GPU 的緩衝區畫成 8 片。階段 ① 經 NVSwitch 加總伺服器內的緩衝區,把第 kk 片留在 GPU kk;階段 ② 是唯一使用網路的階段,而且只有 GPU kk 與 GPU kk 通訊,每顆 GPU 承載 2×N/8−1N/8×S/8≈S/42 \times \tfrac{N/8 - 1}{N/8} \times S/8 \approx S/4;階段 ③ 再經 NVSwitch 把完成的片段分送回去。Drawn for this primer from the three-phase description above and the Rail-only paper, §II.

Animation 4.3 plays the three phases on two servers of 4 GPUs each. Watch which half-slices leave the servers, and between which GPUs.

動畫 4.3 在兩台各有 4 顆 GPU 的伺服器上播放這三個階段。注意哪些半片離開伺服器,以及在哪些 GPU 之間流動。

Animation 4.3動畫 4.3

Hierarchical all-reduce: NVLink, then the network, then NVLink階層式 all-reduce:先 NVLink,再走網路,再 NVLink

Simplified to 2 servers of 4 GPUs (the figure above uses 8 GPUs per server), so a slice is S/4S/4 and each group of GPUs k holds only 2 GPUs. Phase 2 is then a ring all-reduce between 2 ranks: swap halves and add, then send the finished half back. Phases 1 and 3 are rings over NVSwitch in which GPU ii sends to GPU i+1i+1; the slice order is chosen so that GPU kk ends phase 1 owning slice kk. Bytes per GPU: G−1G S\tfrac{G-1}{G}\,S on NVLink in each of phases 1 and 3, and 2×M−1M×S/G2 \times \tfrac{M-1}{M} \times S/G on the network, for GG GPUs per server and MM servers.

簡化為 2 台各 4 顆 GPU 的伺服器(上圖每台 8 顆),所以一片是 S/4S/4,每組 GPU k 只有 2 顆 GPU。於是第 2 階段是 2 個 rank 之間的環形 all-reduce:先交換一半並相加,再把完成的一半送回去。第 1、3 階段是走 NVSwitch 的環,GPU ii 送給 GPU i+1i+1;片的順序安排成第 1 階段結束時 GPU kk 擁有第 kk 片。每顆 GPU 的位元組:第 1、3 階段各在 NVLink 上送 G−1G S\tfrac{G-1}{G}\,S,網路上送 2×M−1M×S/G2 \times \tfrac{M-1}{M} \times S/G,其中每台伺服器 GG 顆 GPU、共 MM 台伺服器。

In-network reduction. A switch that can add changes the byte count: each rank sends SS up once and receives the sum once, about SS per direction instead of 2S2S, with no NN-dependent step chain. NVIDIA's SHARP does this in InfiniBand switches, the H100 generation's NVSwitch can reduce inside the server, and Ultra Ethernet, an industry effort to extend Ethernet for AI and supercomputing (Chapter 7), has proposals for it. None of the training-network papers in this book rely on it, so treat the gain as something to measure, and remember that it needs switch state per collective, a scaling cost of its own.

網內歸約。一台能做加法的交換器會改變位元組數:每個 rank 把 SS 往上送一次、把總和收一次,每個方向約 SS 而非 2S2S,也沒有取決於 NN 的步驟鏈。NVIDIA 的 SHARP 在 InfiniBand 交換器中做這件事,H100 世代的 NVSwitch 可以在伺服器內歸約,Ultra Ethernet(擴充 Ethernet 以用於 AI 與超級電腦的業界計畫,第 7 章)也有相關提案。本書的訓練網路論文都不依賴它,所以把這個增益當成需要量測的東西,並記得它需要交換器為每個集體操作保存狀態,這本身就是一種擴展成本。

Stop and think停下來想一想

In Panel 4.3 choose "Hierarchical", N=1,024N = 1{,}024, S=1 GBS = 1\,\text{GB}, and compare the time and the network bytes with the flat ring. Then switch the collective to all-to-all. Why does the hierarchy stop helping? (Every byte of an all-to-all has a distinct destination, so grouping by server cannot remove network traffic; it can only reorder it.)

在面板 4.3 選「階層式」、N=1,024N = 1{,}024、S=1 GBS = 1\,\text{GB},比較耗時與網路位元組數和平面環的差異。然後把集體操作切到 all-to-all。為什麼階層不再有幫助?(all-to-all 的每個位元組都有不同的目的地,所以依伺服器分組無法移除網路流量,只能重新排序。)

4.5Inside NCCLNCCL 的內部

NCCL is NVIDIA's collective library. PyTorch calls it for every all-reduce. NCCL splits one collective into several parallel channels. Each channel is a ring or tree with its own buffers and its own network connection. In RDMA terms, each connection is a queue pair (QP). The number of channels and QPs decides how many network flows one collective creates. This matters in Chapter 8: more flows give the switches more chances to spread the load, and both Meta and Alibaba modified NCCL to control which path each flow takes.

NCCL 是 NVIDIA 的集體通訊函式庫。PyTorch 每次做 all-reduce 都會呼叫它。NCCL 會把一個集體操作切成數個平行的 channel。每個 channel 是一個環或樹,有自己的緩衝區與自己的網路連線。用 RDMA 的術語,每條連線就是一個 queue pair(QP)。channel 與 QP 的數量決定了一個集體操作會產生幾條網路流。這在第 8 章很重要:流越多,交換器就越有機會把負載分散;Meta 與 Alibaba 都修改了 NCCL,以控制每條流走哪條路徑。

NCCL is the library that turns a call such as all_reduce(tensor) into GPU kernels and network operations. Its vocabulary is small and worth knowing exactly, because the papers on this site tune its internals by name.

NCCL 是把 all_reduce(tensor) 這樣的呼叫變成 GPU kernel 與網路操作的函式庫。它的詞彙很少,值得精確掌握,因為本站的論文會指名調校它的內部。

Communicators and channels. A communicator is one group of NN ranks with a fixed numbering; a job has one per parallelism dimension. Inside it, NCCL builds one or more channels: independent copies of the algorithm, each a ring or tree over the same ranks with its own GPU thread block, staging buffers and connection to each neighbor. A collective is split across channels, so with 8 channels each ring carries one eighth of the message. More channels mean more concurrent flows and more copying threads, up to a few dozen; Meta's Table 2 reports about 4 connections per GPU for an all-reduce on 128 GPUs and about 15 for an all-to-all, before any of the extra connections described in Chapter 8.

Communicator 與 channel。communicator 是一組有固定編號的 NN 個 rank;一個任務在每個平行化維度各有一個。在它之內,NCCL 建立一個或多個 channel:演算法的獨立副本,每個都是同一組 rank 上的一個環或一棵樹,有自己的 GPU thread block、分段緩衝區,以及到每個鄰居的連線。一次集體操作會切到各 channel,所以 8 個 channel 時每個環承載訊息的八分之一。更多 channel 意味著更多並行的流與更多在複製的執行緒,上限是幾十個;Meta 的 Table 2 回報 128 顆 GPU 上 all-reduce 每顆 GPU 約 4 條連線、all-to-all 約 15 條,這是在加上第 8 章所說的額外連線之前。

The figure below follows one GPU's channels down to the wire. Each channel runs as one CUDA block on its own streaming multiprocessor (SM), one of the GPU's 132 processing units on an H100. Its staging buffer is cut into NCCL_STEPS slots (typically 8); a slot can be refilled only after the receiver has emptied it and said so with a tiny message called a clear-to-send (CTS), and different channels can leave through different NICs (Demystifying NCCL, HOTI 2025). So every extra channel takes an SM away from computation and adds a flow to the fabric.

下圖追蹤一顆 GPU 的 channel 一路到線上。每個 channel 以一個 CUDA block 在自己的串流多處理器(SM,H100 上 132 個處理單元之一)上執行。它的分段緩衝區切成 NCCL_STEPS 個槽(通常是 8 個);一個槽要等接收端清空它、並以一則稱為 clear-to-send(CTS)的極小訊息告知之後,才能再次填入;不同的 channel 可以從不同的 NIC 離開(Demystifying NCCL,HOTI 2025)。所以每多一個 channel,就從計算中拿走一個 SM,並在網路上多一條流。

GPU and its SMsGPU 與它的 SMch0ch1ch2ch31 channel = 1 CUDA block on 1 SM1 個 channel = 1 個 CUDA block = 1 個 SMstaging buffer ≈ 4 MB = 8 slots (NCCL_STEPS)分段緩衝區 ≈ 4 MB = 8 槽(NCCL_STEPS)one slot ≈ 512 KB on the wire每槽 ≈ 512 KB 上線NIC 0QPQPNIC 1QPQP2 channels per NIC每張 NIC 2 個 channeleach QP is one flow每個 QP 是一條流Meta (Chapter 8):Meta(第 8 章):4 or 16 QPs per connection每條連線 4 或 16 個 QPslot holding data in flight裝著在途資料的槽empty slot waiting for the receiver’s clear-to-send等待接收端 clear-to-send 的空槽
GPU and its SMsGPU 與它的 SMch0ch1ch2ch31 channel = 1 CUDA block on 1 SM1 個 channel = 1 個 CUDA block = 1 個 SMstaging buffer ≈ 4 MB = 8 slots (NCCL_STEPS)分段緩衝區 ≈ 4 MB = 8 槽(NCCL_STEPS)one slot ≈ 512 KB on the wire每槽 ≈ 512 KB 上線NIC 0QPQPNIC 1QPQP2 channels per NIC每張 NIC 2 個 channeleach QP is one flow每個 QP 是一條流Meta (Chapter 8):Meta(第 8 章):4 or 16 QPs per connection每條連線 4 或 16 個 QPslot holding data in flight裝著在途資料的槽empty slot waiting for the receiver’s clear-to-send等待接收端 clear-to-send 的空槽
Figure 4.9. One GPU’s side of a collective. Each channel is one CUDA block on its own SM, with its own staging buffer cut into NCCL_STEPS slots (8 here), and its own connection that leaves through one of the NICs; a switch sees each queue pair as one flow. More channels mean more SMs busy copying and more flows on the fabric.圖 4.9。一顆 GPU 這一側的集體操作。每個 channel 是一個占用獨立 SM 的 CUDA block,有自己的分段緩衝區(切成 NCCL_STEPS 個槽,這裡是 8),以及經由其中一張 NIC 離開的連線;交換器把每個 queue pair 視為一條流。channel 越多,忙著複製的 SM 越多,網路上的流也越多。Drawn for this primer from Demystifying NCCL (HOTI 2025) and Meta §4.2.

Chunks and the two-stage copy. Each channel moves data in pieces the size of a buffer slot. The GPU kernel copies a piece from the user's tensor into the channel's staging buffer, doing the arithmetic of the reduction on the way. A CPU thread called the proxy then issues the RDMA write that moves the piece into the matching staging buffer on the receiving rank. The receiver's kernel copies it out, adds it, and the slot is free again. In stock NCCL the staging buffer behind one channel is about 4 MB, divided into a small number of slots (8 in the versions we know), so each piece on the wire is on the order of half a megabyte. These sizes are tunable and they are what Meta and the Llama 3 team changed.

Chunk 與兩階段複製。每個 channel 以緩衝槽大小的片段搬資料。GPU kernel 把一片從使用者的張量複製到 channel 的分段緩衝區,順路做歸約的算術。一個稱為 proxy 的 CPU 執行緒接著發出 RDMA write,把這一片搬到接收端 rank 對應的分段緩衝區。接收端的 kernel 把它複製出來、相加,槽就再次空出。在原版 NCCL 中,一個 channel 背後的分段緩衝區約 4 MB,分成少數幾個槽(我們所知的版本是 8 個),所以線上每一片大約半 MB。這些大小都可調,也正是 Meta 與 Llama 3 團隊所改動的。

Panel 4.4 does this arithmetic for any message size, channel count and buffer size.

面板 4.4 為任何訊息大小、channel 數與緩衝區大小做這個算術。

Panel 4.4面板 4.4

Cut a message into channels and slots把訊息切成 channel 與槽

Bytes per channel S/CS/C
每個 channel 的位元組 S/CS/C
Piece on the wire
線上的一片
Pieces per channel = clear-to-sends
每個 channel 的片數 = clear-to-send 數
SMs busy copying
忙著複製的 SM

The arithmetic of this section, not a timing model. The buffer has NCCL_STEPS = 8 slots, so a piece is one eighth of the buffer, or the whole share of a channel if that is smaller. Each piece waits for one clear-to-send from the receiver. Defaults: 8 channels and stock NCCL's staging buffer of about 4 MB per channel, so a piece is about half a megabyte, as the text says; 64 MB is the size of AutoCCL's all-reduce in 9.3. More channels give each channel fewer pieces, but each channel takes one more SM from the computation.

這是本節的算術,不是時間模型。緩衝區有 NCCL_STEPS = 8 個槽,所以一片是緩衝區的八分之一;若 channel 分到的量更小,就是整份。每一片都要等接收端的一個 clear-to-send。預設值:8 個 channel,加上原版 NCCL 每個 channel 約 4 MB 的分段緩衝區,所以一片約半 MB,與正文相同;64 MB 是 9.3 中 AutoCCL 的 all-reduce 大小。channel 越多,每個 channel 的片數越少,但每多一個 channel 就從計算拿走一個 SM。

On InfiniBand and RoCE, each pair of connected ranks uses two reliable-connection QPs: the forward QP carries the RDMA writes of data, and the reverse QP carries the small clear-to-send writes (Demystifying NCCL, HOTI 2025). The figure below shows the whole path.

在 InfiniBand 與 RoCE 上,每一對相連的 rank 使用兩個 reliable-connection QP:正向的 QP 承載資料的 RDMA write,反向的 QP 承載小小的 clear-to-send 寫入(Demystifying NCCL,HOTI 2025)。下圖畫出整條路徑。

sender GPU + NIC發送端 GPU + NICreceiver GPU + NIC接收端 GPU + NIC① GPU copy + reduce① GPU 複製 + 歸約user tensor使用者張量channel bufferchannel 緩衝區CPU proxyCPU proxy③ GPU copy out③ GPU 複製出來channel bufferchannel 緩衝區user tensor使用者張量CPU proxyCPU proxy② RDMA write (data)② RDMA write(資料)data QP, forward資料 QP,正向posted only after a CTS收到 CTS 才提交CTS QP, reverseCTS QP,反向“slot k free, send ≤ size”「第 k 槽空了,可送 ≤ size」Bytes in flight ≤ channels × slots × slot size, as granted by the receiver.在途位元組 ≤ channel 數 × 槽數 × 槽大小,由接收端授權。The rate at which grants return sets how busy the link is.授權回來的速率決定鏈路有多忙。
sender GPU + NIC發送端 GPU + NICreceiver GPU + NIC接收端 GPU + NIC① GPU copy + reduce① GPU 複製 + 歸約user tensor使用者張量channel bufferchannel 緩衝區CPU proxyCPU proxy③ GPU copy out③ GPU 複製出來channel bufferchannel 緩衝區user tensor使用者張量CPU proxyCPU proxy② RDMA write (data)② RDMA write(資料)data QP, forward資料 QP,正向posted only after a CTS收到 CTS 才提交CTS QP, reverseCTS QP,反向“slot k free, send ≤ size”「第 k 槽空了,可送 ≤ size」Bytes in flight ≤ channels × slots × slot size, as granted by the receiver.在途位元組 ≤ channel 數 × 槽數 × 槽大小,由接收端授權。The rate at which grants return sets how busy the link is.授權回來的速率決定鏈路有多忙。
Figure 4.10. NCCL’s network path as Meta’s §5.2 describes it: a two-stage copy through fixed channel buffers, with the sender’s proxy allowed to post the RDMA write only after the receiver’s clear-to-send names a free slot. The data travels on one queue pair and the clear-to-send on a second queue pair in the opposite direction. The receiver, not the sender, admits data to the network.圖 4.10。依 Meta §5.2 描述的 NCCL 網路路徑:經過固定 channel 緩衝區的兩階段複製,發送端的 proxy 只有在接收端的 clear-to-send 指名一個空槽之後才能提交 RDMA write。資料走一個 queue pair,clear-to-send 走反方向的另一個 queue pair。是接收端而非發送端允許資料進入網路。Drawn for this primer from Gangidi et al., SIGCOMM 2024, and Demystifying NCCL (HOTI 2025).

The clear-to-send handshake is admission control. The proxy may not post a write into a slot until the receiver has said the slot is free, with a tiny control message that Meta's paper calls the clear-to-send (CTS). Because the number of slots is fixed, the data a sender can have on the wire toward one receiver is bounded by the slots granted and not yet reclaimed. This is receiver-driven admission: the receiver decides when bytes enter the network, and the sender cannot overrun it. It is why Meta could run its 400G network without the usual network-side controls (Chapter 7): when sixteen senders sent to one receiver at once, nothing backed up, because sixteen senders each limited to a few slots cannot exceed what the receiver's buffers can drain (Meta §5.2). A 2018 paper, IRN, proposed the same cap, one bandwidth-delay product per queue pair, inside the NIC (Chapter 7); NCCL enforces it in software, per channel.

Clear-to-send 交握就是許可控制。proxy 不能把寫入提交到某個槽,除非接收端用一則極小的控制訊息說該槽是空的,Meta 論文稱之為 clear-to-send(CTS)。因為槽數固定,發送端朝一個接收端在線上的資料量,受限於已授權且尚未回收的槽。這就是接收端驅動的許可:接收端決定位元組何時進入網路,發送端無法超越它。這正是 Meta 能讓 400G 網路不靠一般壅塞控制機制運行的原因(第 7 章):十六個發送端同時送往一個接收端時,什麼都沒有堵住,因為十六個各自只限幾個槽的發送端,無法超過接收端緩衝區能排空的量(Meta §5.2)。2018 年的 IRN 論文提出同樣的上限——每個 queue pair 一個頻寬延遲乘積——放在 NIC 內(第 7 章);NCCL 以軟體、逐 channel 執行它。

Protocols: Simple, LL, LL128. Independently of the algorithm, NCCL has three ways to tell the receiving kernel that data has arrived. Simple writes a block, then a flag; lowest overhead per byte, used for large messages. LL (low latency) puts a flag in every 16 bytes next to 8 bytes of data, so each small piece is usable the moment it lands, at the cost of half the bytes being flags. LL128 uses 128-byte lines with 120 bytes of payload, about 95% efficient, but relies on ordering guarantees that NVLink provides and not every network does. The thresholds change between versions; what stays true is that small messages take a flag-per-piece protocol to shave α\alpha, and large ones take the plain protocol to maximize BB.

協定:Simple、LL、LL128。與演算法無關,NCCL 有三種方式告訴接收端的 kernel 資料已到達。Simple 先寫一塊、再寫一個旗標;每位元組開銷最低,用於大訊息。LL(低延遲)在每 16 位元組中放一個旗標與 8 位元組資料,每個小片一落地就能使用,代價是一半的位元組是旗標。LL128 使用 128 位元組的行、120 位元組是資料,效率約 95%,但依賴 NVLink 提供而非每種網路都提供的順序保證。門檻隨版本改變;不變的是:小訊息用每片帶旗標的協定來削減 α\alpha,大訊息用普通協定來最大化 BB。

The figure below draws the three layouts. An LL unit is 8 bytes, 4 of data and a 4-byte flag written in one atomic store, so half of the bytes are data. An LL128 line is 120 bytes of data and an 8-byte flag. A measurement study of NCCL 2.19 reports about 1 µs per hop for LL at 25–50% of peak bandwidth, about 2 µs for LL128 at about 95%, and about 6 µs for Simple near peak. LL128 needs atomic 128-byte writes, so NCCL disables it on some PCIe systems (Demystifying NCCL, HOTI 2025).

下圖畫出三種格式。LL 的一個單位是 8 位元組:4 位元組資料加 4 位元組旗標,以一次原子寫入完成,所以一半的位元組是資料。LL128 的一行是 120 位元組資料加 8 位元組旗標。一項對 NCCL 2.19 的量測研究回報:LL 每跳約 1 µs、達到峰值頻寬的 25–50%;LL128 約 2 µs、約 95%;Simple 約 6 µs、接近峰值。LL128 需要 128 位元組的原子寫入,所以 NCCL 在某些 PCIe 系統上停用它(Demystifying NCCL,HOTI 2025)。

bytes on the wire (LL and LL128 to scale)線上的位元組(LL 與 LL128 依比例)SimpleLLLL128one large data block, then a flag after a memory fence先寫一大塊資料,記憶體 fence 之後再寫旗標data: one large chunk資料:一大塊fenceflag旗標16 B line = 2 × (4 B data + 4 B flag), one atomic store per 8 B16 位元組一行 = 2 ×(4 B 資料 + 4 B 旗標),每 8 B 一次原子寫入df128-byte line = 120 B data + 8 B flag128 位元組一行 = 120 B 資料 + 8 B 旗標120 B data120 B 資料8 B≈ 100% data≈ 100% 資料~6 µs per hop每跳 ~6 µsnear peak接近峰值50% data50% 資料~1 µs per hop每跳 ~1 µs25–50% of peak峰值的 25–50%120/128 ≈ 94% data120/128 ≈ 94% 資料~2 µs per hop每跳 ~2 µs~95% of peak峰值的 ~95%0326496128bytes位元組
bytes on the wire (LL and LL128 to scale)線上的位元組(LL 與 LL128 依比例)SimpleLLLL128one large data block, then a flag after a memory fence先寫一大塊資料,記憶體 fence 之後再寫旗標data: one large chunk資料:一大塊fenceflag旗標16 B line = 2 × (4 B data + 4 B flag), one atomic store per 8 B16 位元組一行 = 2 ×(4 B 資料 + 4 B 旗標),每 8 B 一次原子寫入df128-byte line = 120 B data + 8 B flag128 位元組一行 = 120 B 資料 + 8 B 旗標120 B data120 B 資料8 B≈ 100% data≈ 100% 資料~6 µs per hop每跳 ~6 µsnear peak接近峰值50% data50% 資料~1 µs per hop每跳 ~1 µs25–50% of peak峰值的 25–50%120/128 ≈ 94% data120/128 ≈ 94% 資料~2 µs per hop每跳 ~2 µs~95% of peak峰值的 ~95%0326496128bytes位元組
Figure 4.11. How NCCL’s three protocols tell the receiver that data has arrived. Simple writes a large block, then a flag after a memory fence; LL and LL128 put a flag in every line, so the receiver can use each line as soon as its flag changes. The latency and bandwidth figures are one study’s measurements of NCCL 2.19.圖 4.11。NCCL 三種協定如何告訴接收端資料已到達。Simple 先寫一大塊,記憶體 fence 之後再寫旗標;LL 與 LL128 在每一行都放旗標,所以接收端只要看到某一行的旗標改變就能使用那一行。延遲與頻寬數字是一項研究對 NCCL 2.19 的量測。Drawn for this primer from Demystifying NCCL (HOTI 2025), Section 4.2.

Auto-selection. At the start of every collective NCCL evaluates a cost model close to the α\alpha–β\beta model of Section 4.3 for every (algorithm, protocol) pair the machine supports, using latency and bandwidth tables measured for the platform, and picks the smallest predicted time for the message size. Roughly: tiny messages get a tree with LL, medium ones a tree or ring with LL128, large ones a ring with Simple; on NVSwitch systems an in-switch reduction may be chosen. Environment variables can force a choice, which is the tuning the Meta and Llama 3 papers describe. The point for a network engineer is that the choice depends on the latency the library believes it has. If the fabric is slower than the table says, every threshold is wrong at once.

自動選擇。在每次集體操作開始時,NCCL 對機器支援的每一組(演算法、協定),用為該平台量測的延遲與頻寬表,評估一個接近第 4.3 節 α\alpha–β\beta 模型的成本模型,並為該訊息大小選出預測時間最小的一組。粗略地說:極小的訊息用樹加 LL,中等的用樹或環加 LL128,大的用環加 Simple;在 NVSwitch 系統上可能選交換器內歸約。環境變數可以強制選擇,這就是 Meta 與 Llama 3 論文描述的調校。對網路工程師重要的是:這個選擇取決於函式庫相信自己擁有的延遲。如果網路比表上說的慢,所有門檻會同時出錯。

4.6Bytes in flight and the round trip在途位元組與往返時間

Here is the mechanism behind Meta's "more than 2×" result, in one formula. A link of bandwidth BB and round-trip time RTT\mathrm{RTT} holds B×RTTB \times \mathrm{RTT} bytes between the moment a sender starts and the moment the next grant can return: the bandwidth-delay product (BDP). At 400 Gb/s and 22 µs it is 400 Gb/s×22 μs≈1.1 MB400\Gbs \times 22\,\mu\text{s} \approx 1.1\,\text{MB}; at the under-10 µs NCCL's defaults assume, under 0.5 MB. Data that has been sent but not yet acknowledged, or here not yet granted again, is in flight. If the sender may have only WW bytes in flight, the link can be busy for at most W/BW/B of every RTT\mathrm{RTT}, so

這就是 Meta「超過 2 倍」結果背後的機制,用一條公式說完。頻寬 BB、往返時間 RTT\mathrm{RTT} 的鏈路,在發送端開始到下一個授權能回來之間,容納 B×RTTB \times \mathrm{RTT} 位元組:這是頻寬延遲乘積(BDP)。在 400 Gb/s 與 22 µs 下是 400 Gb/s×22 μs≈1.1 MB400\Gbs \times 22\,\mu\text{s} \approx 1.1\,\text{MB};在 NCCL 預設假設的低於 10 µs 下,低於 0.5 MB。已送出但尚未確認(在這裡是尚未再次獲得授權)的資料稱為在途資料。如果發送端只能有 WW 位元組在途,鏈路在每個 RTT\mathrm{RTT} 中最多忙 W/BW/B 的時間,所以

utilization=min⁡ ⁣(1, WB×RTT) \text{utilization} = \min\!\left(1,\ \frac{W}{B \times \mathrm{RTT}}\right)
使用率=min⁡ ⁣(1, WB×RTT) \text{使用率} = \min\!\left(1,\ \frac{W}{B \times \mathrm{RTT}}\right)

In NCCL, WW is the credit the receiver has granted: channels×slots×slot size\text{channels} \times \text{slots} \times \text{slot size}, as the figure above shows. Stock NCCL sizes those buffers for a round trip inside one rack. Meta measured about 22 µs across its fabric, more than twice that, so the granted credit covered less than half of the BDP and the 400G links sat idle between grants about half the time. No queue was building anywhere; the network was simply not being asked to carry anything. This is why out-of-the-box RoCE collectives ran at well under half of the hardware's capability, and why enlarging the channel buffers was the single largest gain (Meta §6.1). The Llama 3 team made the same change under the name NCCLX: chunk and transfer sizes re-tuned for a fabric where DP and PP traffic sees "tens of microseconds" of latency (Llama 3 §3.3.3).

在 NCCL 中,WW 是接收端授權的額度:channel 數×槽數×槽大小\text{channel 數} \times \text{槽數} \times \text{槽大小},如上圖所示。原版 NCCL 依單一機櫃內的往返時間設定這些緩衝區。Meta 量到跨網路約 22 µs,是它的兩倍以上,所以授權的額度不到 BDP 的一半,400G 鏈路在授權之間約一半時間閒置。沒有任何地方在排隊;網路只是沒有被要求承載任何東西。這就是為什麼開箱即用的 RoCE 集體通訊遠低於硬體能力的一半,也是為什麼加大 channel 緩衝區是最大的單一增益(Meta §6.1)。Llama 3 團隊以 NCCLX 之名做了同樣的改動:把 chunk 與傳輸大小重新調校給 DP 與 PP 流量會遇到「數十微秒」延遲的網路(Llama 3 §3.3.3)。

The figure below shows the slots on the wire. With eight small slots, the sender empties its window long before the first clear-to-send returns, and the link waits. With slots large enough that the eight of them cover B×RTTB \times \mathrm{RTT}, a grant always returns before the window runs out.

下圖畫出線上的槽。8 個小槽時,發送端在第一個 clear-to-send 回來之前早就送完視窗,鏈路只能等。槽大到 8 個合起來能覆蓋 B×RTTB \times \mathrm{RTT} 時,授權總是在視窗送完之前回來。

A · W = 8 small slots < B × RTT: the window is empty long before the first clear-to-send returnsA · W = 8 個小槽 < B × RTT:第一個 clear-to-send 回來之前,視窗早就送完了sender發送端receiver接收端RTT0123456701234567012idle閒置idle閒置B · W = 8 larger slots ≥ B × RTT: every grant returns before the window runs outB · W = 8 個較大的槽 ≥ B × RTT:每個授權都在視窗送完之前回來sender發送端receiver接收端RTT0123456701234567no idle time沒有閒置022 µs44 µstime時間data slot (digit = slot index)資料槽(數字 = 槽編號)clear-to-send freeing that slot釋放該槽的 clear-to-sendlink idle鏈路閒置
A · W = 8 small slots < B × RTT: the window is empty long before the first clear-to-send returnsA · W = 8 個小槽 < B × RTT:第一個 clear-to-send 回來之前,視窗早就送完了sender發送端receiver接收端RTT0123456701234567012idle閒置idle閒置B · W = 8 larger slots ≥ B × RTT: every grant returns before the window runs outB · W = 8 個較大的槽 ≥ B × RTT:每個授權都在視窗送完之前回來sender發送端receiver接收端RTT0123456701234567no idle time沒有閒置022 µs44 µstime時間data slot (digit = slot index)資料槽(數字 = 槽編號)clear-to-send freeing that slot釋放該槽的 clear-to-sendlink idle鏈路閒置
Figure 4.12. A sender with 8 slots on a 400 Gb/s path with a 22 µs round trip, drawn as a space–time diagram: each orange band is one slot crossing the network and each blue line is the clear-to-send that frees it. In A the 8 slots cover less than B×RTTB \times \mathrm{RTT}, so the sender waits for grants; in B they cover more, and the link never stops. The slot sizes are illustrative; the rule is utilization=min⁡(1,W/(B×RTT))\text{utilization} = \min(1, W/(B \times \mathrm{RTT})).圖 4.12。一個有 8 個槽的發送端,在 400 Gb/s、往返 22 µs 的路徑上,畫成時空圖:每一條橘色斜帶是一個穿越網路的槽,每一條藍線是釋放它的 clear-to-send。A 中 8 個槽覆蓋不到 B×RTTB \times \mathrm{RTT},所以發送端要等授權;B 中覆蓋得更多,鏈路從不停下。槽的大小是示意值;規則是 使用率=min⁡(1,W/(B×RTT))\text{使用率} = \min(1, W/(B \times \mathrm{RTT}))。Drawn for this primer from the slot mechanism in Section 4.5 and Meta §6.1.

Worked example: sizing a channel buffer算例:決定 channel 緩衝區大小

Worked example: sizing a channel buffer. A collective runs 16 flows between a pair of GPUs (Llama 3). All 16 share one 400G NIC, so the NIC as a whole needs about 1.1 MB in flight, about 70 KB per flow at 22 µs. If the library grants only 32 KB per flow, the NIC sends about 0.5 MB per RTT and the link runs at about 45% of line rate, close to the "well under half" that Meta observed out of the box. Double the RTT with more switches on the path or a long queue, and the same buffers halve throughput again. This is why the Llama 3 team wrote NCCLX with chunk sizes tuned to the measured latency rather than to a one-rack assumption.

實例:為 channel 緩衝區定大小。一個集體操作在一對 GPU 之間跑 16 條流(Llama 3)。16 條共用一張 400G NIC,所以整張 NIC 需要約 1.1 MB 在途,22 µs 時每條流約 70 KB。如果函式庫只給每條流 32 KB,NIC 每個 RTT 只送約 0.5 MB,鏈路跑在線速的約 45%,接近 Meta 開箱觀察到的「遠低於一半」。路徑上多幾台交換器或一條長佇列讓 RTT 加倍,同樣的緩衝區會讓吞吐再減半。這就是 Llama 3 團隊寫 NCCLX、把 chunk 大小調到實測延遲而非單機櫃假設的原因。

Animation 4.4 plays this worked example: data fills the pipe until the buffers run out, and then the link waits for the ACKs.

動畫 4.4 播放這個實例:資料填入管道直到緩衝用完,然後鏈路等待 ACK。

Animation 4.4動畫 4.4

Filling the bandwidth-delay product填滿頻寬延遲乘積

The window model of Panel 4.5 with the worked example's numbers: 16 flows, a 400G NIC, a 22 µs round trip and 11 µs each way. Data moves in 50 KB blocks, 1 µs each at 400G, so the BDP is 22 blocks and a window is rounded to whole blocks: 512 KB becomes 10 blocks, and the link is busy 45% (Panel 4.5: 47%). Each ACK that returns frees one block.

面板 4.5 的窗口模型,套用實例的數字:16 條流、一張 400G NIC、往返 22 µs、單向 11 µs。資料以 50 KB 的區塊移動,400G 下每塊 1 µs,所以 BDP 是 22 塊,窗口取整數塊:512 KB 變成 10 塊,鏈路忙碌 45%(面板 4.5:47%)。每回來一個 ACK 就釋出一塊。

Panel 4.5 lets you change the buffer per flow, the number of flows and the RTT, and shows how busy the link stays.

面板 4.5 讓你改變每條流的緩衝、流數與 RTT,並顯示鏈路能保持多忙。

Panel 4.5面板 4.5

Buffer per flow, RTT and a busy link每條流的緩衝、RTT 與忙碌的鏈路

BDP
BDP
In flight: flows × buffer
在途:流數 × 緩衝
Link busy
鏈路忙碌比例
Buffer per flow to fill the link
填滿鏈路所需的每流緩衝

A window model: each flow may have one buffer of data in flight, and then waits one round trip for the acknowledgement, so the link is busy for flows × buffer ÷ BDP of each round trip, at most 100%. Defaults are the worked example above: Llama 3's 16 flows per GPU pair, 32 KB per flow, a 400G NIC and Meta's measured 22 µs. 512 KB in flight against a 1.1 MB BDP keeps the link busy 47% of the time, which the text rounds to about 45%. Try 64 KB per flow, then double the RTT.

窗口模型:每條流最多有一份緩衝的資料在途,然後等一個往返的確認,所以每個往返中鏈路忙碌的比例是 流數 × 緩衝 ÷ BDP,最多 100%。預設值是上面的實例:Llama 3 每對 GPU 16 條流、每條流 32 KB、一張 400G NIC 與 Meta 實測的 22 µs。512 KB 在途、對 1.1 MB 的 BDP,鏈路有 47% 的時間在忙,正文四捨五入為約 45%。試試每條流 64 KB,再把 RTT 加倍。

Animation 4.5 plays the same loop in time. The sender spends one credit per slot, and each clear-to-send gives one back.

動畫 4.5 在時間軸上播放同一個循環。發送端每寫一個槽就用掉一個授權,每個 clear-to-send 還回一個。

Animation 4.5動畫 4.5

Clear-to-send credits gate the slotsclear-to-send 授權控管每個槽

One channel with 8 slots on a 400 Gb/s (50 GB/s) path with a 22 µs round trip, so B×RTT≈1.1 MBB \times \mathrm{RTT} \approx 1.1\,\text{MB}. The slot sizes are illustrative: they make WW half of B×RTTB \times \mathrm{RTT} or 1.5 times it. A slot is freed when its last byte reaches the receiver, and its credit returns half a round trip later, so a slot is reused one write time plus one RTT after it was written. The receiver is assumed to copy a slot out at once, and the clear-to-send never waits in a queue; the next paragraph adds that delay. Each step is 2.75 µs. The strip at the bottom records when the link carried data.

一個 channel、8 個槽,路徑為 400 Gb/s(50 GB/s)、往返 22 µs,所以 B×RTT≈1.1 MBB \times \mathrm{RTT} \approx 1.1\,\text{MB}。槽的大小是示意值:讓 WW 等於 B×RTTB \times \mathrm{RTT} 的一半或 1.5 倍。槽在最後一個位元組到達接收端時被釋放,它的授權再過半個往返回到發送端,所以一個槽在寫入後經過一次寫入時間加一個 RTT 才能再用。假設接收端立刻把槽複製出去,且 clear-to-send 不在佇列中等待;下一段會加上這段延遲。每一步是 2.75 µs。底部的長條記錄鏈路何時在傳資料。

The control message must not queue behind data. The formula uses RTT, but the real cycle is RTT plus however long the clear-to-send waits in a queue. A CTS is a few bytes; if it shares a switch queue with megabytes of data from other ranks, the sender's slots stay un-granted for as long as it waits. Meta measured a 90th-percentile CTS delay of 43 µs before tuning. At 400 Gb/s that stall is 2.15 MB of link capacity, twice the whole BDP, lost per grant cycle. A high-priority switch queue for CTS packets cut it to 4 µs (Meta §6.1). The requirement for full utilization is therefore

控制訊息不能排在資料後面。公式用的是 RTT,但真實的週期是 RTT 加上 clear-to-send 在佇列中等待的時間。一個 CTS 只有幾個位元組;如果它與其他 rank 的 MB 級資料共用一個交換器佇列,發送端的槽就有多久得不到授權,取決於它等多久。Meta 量到調校前 CTS 的第 90 百分位延遲是 43 µs。在 400 Gb/s 下,這個停頓是 2.15 MB 的鏈路容量——整個 BDP 的兩倍——在每個授權週期中損失。給 CTS 封包一個高優先權的交換器佇列,讓它降到 4 µs(Meta §6.1)。因此達到滿使用率的條件是

W≥B×(RTT+CTS delay) W \ge B \times (\mathrm{RTT} + \text{CTS delay})
W≥B×(RTT+CTS 延遲) W \ge B \times (\mathrm{RTT} + \text{CTS 延遲})

The figure below shows where the CTS delay comes from and how much credit each case needs.

下圖顯示 CTS 延遲從哪裡來,以及每種情況需要多少額度。

A. One shared queueA. 共用一個佇列CTS1 MB1 MB1 MBThe CTS leaves after the data ahead of it.CTS 要等前面的資料走完才能離開。B. CTS in a high-priority queueB. CTS 走高優先權佇列CTS1 MB1 MB1 MBThe CTS leaves first.CTS 最先離開。Grant cycle at 400 Gb/s (50 GB/s), and the credit W it needs400 Gb/s(50 GB/s)下的授權週期,以及它需要的額度 Wbefore調校前RTT 22 µsCTS 43 µs (p90)CTS 43 µs(p90)W ≥ 3.25 MBafter調校後RTT 22 µsCTS 4 µsCTS 4 µsW ≥ 1.3 MBBDP alone: 50 GB/s × 22 µs = 1.1 MB只算 BDP:50 GB/s × 22 µs = 1.1 MBW ≥ B × (RTT + CTS delay)W ≥ B × (RTT + CTS 延遲)
A. One shared queueA. 共用一個佇列CTS1 MB1 MB1 MBThe CTS leaves after the data ahead of it.CTS 要等前面的資料走完才能離開。B. CTS in a high-priority queueB. CTS 走高優先權佇列CTS1 MB1 MB1 MBThe CTS leaves first.CTS 最先離開。Grant cycle at 400 Gb/s (50 GB/s), and the credit W it needs400 Gb/s(50 GB/s)下的授權週期,以及它需要的額度 Wbefore調校前RTT 22 µsCTS 43 µs (p90)CTS 43 µs(p90)W ≥ 3.25 MBafter調校後RTT 22 µsCTS 4 µsCTS 4 µsW ≥ 1.3 MBBDP alone: 50 GB/s × 22 µs = 1.1 MB只算 BDP:50 GB/s × 22 µs = 1.1 MBW ≥ B × (RTT + CTS delay)W ≥ B × (RTT + CTS 延遲)
Figure 4.13. Why the clear-to-send needs its own queue. Top: in one shared queue, the few-byte CTS waits behind megabytes of data from other ranks; in a separate high-priority queue it leaves first. Bottom: the grant cycle that the credit WW must cover at 400 Gb/s, by W≥B×(RTT+CTS delay)W \ge B \times (\mathrm{RTT} + \text{CTS delay}), with Meta’s measured 22 µs round trip and CTS delays of 43 µs (90th percentile, before tuning) and 4 µs (with the high-priority queue). The data sizes in the queues are illustrative.圖 4.13。為什麼 clear-to-send 需要自己的佇列。上:在共用的佇列中,只有幾個位元組的 CTS 排在其他 rank 的 MB 級突發後面;在獨立的高優先權佇列中它最先離開。下:400 Gb/s 下額度 WW 必須涵蓋的授權週期,依 W≥B×(RTT+CTS 延遲)W \ge B \times (\mathrm{RTT} + \text{CTS 延遲}),使用 Meta 實測的 22 µs 往返,以及 43 µs(調校前,第 90 百分位)與 4 µs(使用高優先權佇列後)的 CTS 延遲。佇列中的資料大小是示意值。Drawn for this primer from Gangidi et al., SIGCOMM 2024, §6.1, and the formula above.

Why not grant everything? Because the bound is also the protection. The IRN paper capped bytes in flight per queue pair at one BDP of the longest path, 120 KB for 40 Gb/s links with six 2 µs hops, and showed that this alone kept switch queues short (Chapter 7). Meta's receiver-driven admission is the same idea at the library level, and it is why sixteen senders sending to one receiver did not back up. Grant too little and the link idles; grant too much and the switches overflow. The right value is one BDP plus the CTS delay per receiving link, both measured on the real fabric, not read from a default.

為什麼不全部授權?因為這個上限同時也是保護。IRN 論文把每個 queue pair 的在途位元組限制在最長路徑的一個 BDP——40 Gb/s 鏈路、六跳各 2 µs 下是 120 KB——並證明光是這樣就能讓交換器佇列保持很短(第 7 章)。Meta 的接收端驅動許可是同一個想法放在函式庫層,也是十六個發送端送往同一個接收端時沒有堵住的原因。授權太少鏈路閒置;授權太多交換器會溢出。正確的值是每條接收鏈路一個 BDP 加 CTS 延遲,兩項都在真實網路上量測,不能從預設值讀出。

Panel 4.6面板 4.6

Bytes in flight versus the link在途位元組與鏈路的對決

BDP=rate×RTT\mathrm{BDP} = \text{rate} \times \mathrm{RTT}
BDP=速率×RTT\mathrm{BDP} = \text{速率} \times \mathrm{RTT}
Needed incl. CTS delay
含 CTS 延遲所需
In flight allowed
允許的在途量
Achievable link utilization
可達到的鏈路使用率

Defaults: Meta's measured 22 µs RTT on a 400 Gb/s link with the CTS already prioritized (4 µs), and a granted credit of 4 channels × 128 KB chosen to represent buffers sized for a <10 µs fabric; the link is busy well under half the time, as the paper reports. "+ CTS at 43 µs" shows the un-prioritized control message. "Tuned" raises the credit above one BDP. "IRN 40G" reproduces IRN's 120 KB cap (40 Gb/s, six 2 µs hops each way). The buffer sizes are illustrative; only the rates, RTT and CTS delays are from the papers.

預設值:Meta 實測的 22 µs RTT、400 Gb/s 鏈路、CTS 已優先(4 µs),授權額度為 4 個 channel × 128 KB,用來代表為 <10 µs 網路設定的緩衝;鏈路忙碌時間遠低於一半,正如論文所報告。「+ CTS 43 µs」顯示未優先的控制訊息。「調校後」把額度提高到超過一個 BDP。「IRN 40G」重現 IRN 的 120 KB 上限(40 Gb/s、每方向六跳各 2 µs)。緩衝大小是示意值;只有速率、RTT 與 CTS 延遲來自論文。

Stop and think停下來想一想

In Panel 4.6, keep the tuned preset and raise the link rate to 800 Gb/s. What happens to utilization, and what must change to recover it? Then set RTT to 60 µs, which is a plausible cross-building path. The lesson: every speed upgrade and every change in how the network is wired re-opens the buffer question, because the BDP moved.

在面板 4.6 保持「調校後」預設,把鏈路速率提高到 800 Gb/s。使用率怎麼了?要恢復它必須改什麼?然後把 RTT 設到 60 µs,這是跨建築路徑的合理值。教訓:每一次速度升級與每一次網路接法的改動都會重新打開緩衝區的問題,因為 BDP 移動了。

4.7Overlap: hiding the collective重疊:把集體操作藏起來

A collective that runs while the GPUs compute costs nothing; one that runs while they wait costs its full time. The difference is overlap, and the rules of what can hide behind what come from the dependency structure of the training step.

在 GPU 計算時執行的集體操作不花任何成本;在 GPU 等待時執行的則花掉全部時間。差別就是重疊,而什麼可以藏在什麼後面的規則,來自訓練步的依賴結構。

Data parallel. The gradient of layer LL is complete as soon as the backward pass through it finishes, while layer L−1L-1 is still computing, so the reduce-scatter of one chunk of layers runs behind the backward computation of the next chunk. In FSDP the all-gather of the next chunk's parameters runs behind the current chunk's forward computation. MegaScale does both, and prefetches the first chunk's all-gather during data loading because it has nothing else to hide behind (MegaScale §3.2). Llama 3 goes further and does not re-shard parameters after the forward pass, which removes one all-gather from the backward pass.

資料平行。第 LL 層的梯度在反向經過它時就完成了,而第 L−1L-1 層仍在計算,所以一個 chunk 的層的 reduce-scatter 藏在下一個 chunk 的反向計算後面。在 FSDP 中,下一個 chunk 參數的 all-gather 藏在目前 chunk 的正向計算後面。MegaScale 兩者都做,並在載入資料時預先抓取第一個 chunk 的 all-gather,因為它沒有別的東西可藏(MegaScale §3.2)。Llama 3 更進一步,正向之後不重新分片參數,從反向中移除一次 all-gather。

Pipeline parallel. Stage kk must receive activations before it can compute, but it never has to wait for its own send to complete. MegaScale decouples the two, so the send of micro-batch mm runs in the background while stage kk computes on micro-batch m+1m+1. In the 1F1B steady state the sends and receives are asynchronous and hidden; the warm-up and cool-down phases are where the decoupling earns its 2.5 MFU points. Llama 3's schedule, with a tunable number of micro-batches in flight and asynchronous point-to-point communication, is the same idea.

管線平行。第 kk 階段必須先收到激活值才能計算,但從不需要等自己的 send 完成。MegaScale 把兩者解耦,讓 micro-batch mm 的 send 在背景執行,同時第 kk 階段對 micro-batch m+1m+1 計算。在 1F1B 穩態中 send 與 receive 是非同步且隱藏的;暖機與收尾階段才是解耦賺到 2.5 個 MFU 百分點的地方。Llama 3 的排程——可調的在途 micro-batch 數與非同步點對點通訊——是同一個想法。

Tensor parallel. Here the collective sits in the middle of a layer and nothing can run before its result is known, so the only way to hide it is to cut the work into pieces. MegaScale splits each large matrix multiplication into chunks and fuses the collective with it, so chunk kk computes while the all-gather or reduce-scatter of chunk k+1k+1 is in flight. These collectives run on NVLink with small pieces, which is where the LL and LL128 protocols matter most. The three overlaps are worth 6.2 MFU points in MegaScale's ablation: TP 2.2, PP 2.5, DP 1.5.

張量平行。這裡集體操作坐在一層的中間,結果出來之前什麼都不能跑,所以唯一能藏的方法是把工作切成小片。MegaScale 把每個大矩陣乘法切成多段並把集體操作與它融合,讓第 kk 段計算時第 k+1k+1 段的 all-gather 或 reduce-scatter 仍在傳輸中。這些集體操作走 NVLink、片段又小,正是 LL 與 LL128 協定最重要的地方。三種重疊在 MegaScale 的消融中值 6.2 個 MFU 百分點:TP 2.2、PP 2.5、DP 1.5。

The figure below draws this for one all-gather cut into four chunks.

下圖以切成四塊的一個 all-gather 畫出這件事。

A. Not chunked: the multiply waits for the whole all-gatherA. 不切塊:乘法要等整個 all-gatherall-gathermultiply乘法AGGPU waitsGPU 等待GEMM12B. Chunked (MegaScale): chunk k computes while chunk k+1 arrivesB. 切塊(MegaScale):第 k 塊計算時第 k+1 塊在傳all-gathermultiply乘法1234GEMM 1GEMM 2GEMM 3GEMM 49time (illustrative units)時間(示意單位)exposed: only the first chunk’s all-gather in B暴露:B 中只剩第一塊的 all-gather
A. Not chunked: the multiply waits for the whole all-gatherA. 不切塊:乘法要等整個 all-gatherall-gathermultiply乘法AGGPU waitsGPU 等待GEMM12B. Chunked (MegaScale): chunk k computes while chunk k+1 arrivesB. 切塊(MegaScale):第 k 塊計算時第 k+1 塊在傳all-gathermultiply乘法1234GEMM 1GEMM 2GEMM 3GEMM 49time (illustrative units)時間(示意單位)exposed: only the first chunk’s all-gather in B暴露:B 中只剩第一塊的 all-gather
Figure 4.14. Tensor-parallel overlap by chunking, as MegaScale §3.2 describes it. In A, the all-gather must finish before the matrix multiply (GEMM) can start, so the GPU waits for all of it. In B, the multiply of chunk kk runs while the all-gather of chunk k+1k+1 is in flight, and only the first chunk’s all-gather is exposed. The durations are illustrative. In MegaScale’s ablation (175B model, 256 Ampere GPUs, Table 3) the TP overlap added 2.2 MFU points.圖 4.14。以切塊達成的張量平行重疊,依 MegaScale §3.2 的描述。A 中 all-gather 必須完成,矩陣乘法(GEMM)才能開始,所以 GPU 要等整個 all-gather。B 中第 kk 塊的乘法執行時,第 k+1k+1 塊的 all-gather 正在傳送,只有第一塊的 all-gather 暴露。時間長度是示意值。在 MegaScale 的消融實驗中(175B 模型、256 顆 Ampere GPU、Table 3),TP 重疊帶來 2.2 個 MFU 百分點。Drawn for this primer from Jiang et al., NSDI 2024 (MegaScale), §3.2 and Table 3.

The condition, and what breaks it. Overlap works for a chunk only if

條件,以及什麼會打破它。重疊對一個 chunk 成立,只有當

Tcomm(chunk)≤Tcompute(chunk) T_{\text{comm}}(\text{chunk}) \le T_{\text{compute}}(\text{chunk})

In the α\alpha–β\beta model the communication of a chunk of PP parameters on a DP ring is 2(N−1) α+2(N−1)N⋅2P/B2(N-1)\,\alpha + \tfrac{2(N-1)}{N} \cdot 2P/B; the compute that hides it is also proportional to PP, with the batch size as a multiplier, so the ratio is a fixed property of the configuration. Now let the fabric deliver half the planned bandwidth, as Meta's did out of the box. Every network TcommT_{\text{comm}} doubles, the chunks closest to the line cross it first, and the largest transfers, the DP reduce-scatters, are exposed before the small TP collectives. The step grows by the exposed time and the MFU gained by overlap is handed back. This is why MegaScale puts network tuning and the straggler hunt in the same paper as the overlap schemes: they protect the assumption that overlap depends on.

在 α\alpha–β\beta 模型中,PP 個參數的 chunk 在 DP 環上的通訊是 2(N−1) α+2(N−1)N⋅2P/B2(N-1)\,\alpha + \tfrac{2(N-1)}{N} \cdot 2P/B;藏住它的計算也與 PP 成正比、多了批次大小作為乘數,所以比值是配置的固定性質。現在讓網路只提供規劃一半的頻寬,像 Meta 開箱時那樣。每個網路的 TcommT_{\text{comm}} 都加倍,最接近那條線的 chunk 最先越線,而最大的傳輸——DP 的 reduce-scatter——比小的 TP 集體操作更早暴露。步時間增加暴露的量,重疊賺到的 MFU 被交回去。這就是為什麼 MegaScale 把網路調校與 straggler 追捕和重疊方案放在同一篇論文:它們守護的是重疊所依賴的假設。

The figure below draws this for four chunks of a backward pass. At the planned bandwidth, each chunk's collective finishes before the next chunk is ready, and only the last one is exposed. At half the bandwidth, the collectives queue behind each other, and the exposed tail grows to several chunks.

下圖以反向計算的四個 chunk 畫出這件事。在規劃頻寬下,每個 chunk 的集體操作在下一個 chunk 準備好之前就完成,只有最後一個暴露。頻寬減半時,集體操作一個排在一個後面,暴露的尾巴變成好幾個 chunk 長。

planned bandwidth: T_comm(chunk) ≤ T_compute(chunk); only the last chunk is exposed規劃頻寬:T_comm(chunk) ≤ T_compute(chunk);只有最後一個 chunk 暴露backward compute反向計算gradient collective梯度集體操作chunk 1chunk 1chunk 2chunk 2chunk 3chunk 3chunk 4chunk 4exposed暴露half the bandwidth: every T_comm doubles, the collectives queue, the tail grows一半頻寬:每個 T_comm 加倍,集體操作排隊,尾巴變長backward compute反向計算gradient collective梯度集體操作chunk 1chunk 1chunk 2chunk 2chunk 3chunk 3chunk 4chunk 4exposed: the step waits暴露:這一步在等time時間backward done反向完成A chunk’s collective starts when backward has produced the chunk and the previous collective is done.一個 chunk 的集體操作,要等反向產生該 chunk、且前一個集體操作完成後才開始。
planned bandwidth: T_comm(chunk) ≤ T_compute(chunk); only the last chunk is exposed規劃頻寬:T_comm(chunk) ≤ T_compute(chunk);只有最後一個 chunk 暴露backward compute反向計算gradient collective梯度集體操作chunk 1chunk 1chunk 2chunk 2chunk 3chunk 3chunk 4chunk 4exposed暴露half the bandwidth: every T_comm doubles, the collectives queue, the tail grows一半頻寬:每個 T_comm 加倍,集體操作排隊,尾巴變長backward compute反向計算gradient collective梯度集體操作chunk 1chunk 1chunk 2chunk 2chunk 3chunk 3chunk 4chunk 4exposed: the step waits暴露:這一步在等time時間backward done反向完成A chunk’s collective starts when backward has produced the chunk and the previous collective is done.一個 chunk 的集體操作,要等反向產生該 chunk、且前一個集體操作完成後才開始。
Figure 4.15. Four chunks of a backward pass and their gradient collectives on a second stream. At the planned bandwidth each collective fits under the next chunk’s compute, and only the last one sticks out. At half the bandwidth each collective takes longer than a chunk of compute, they queue, and the step waits more than three chunks’ worth of time. The durations are illustrative.圖 4.15。反向計算的四個 chunk,以及它們在第二條串流上的梯度集體操作。在規劃頻寬下,每個集體操作都藏在下一個 chunk 的計算底下,只有最後一個露出來。頻寬減半時,每個集體操作都比一個 chunk 的計算久,它們排隊,這一步要多等超過三個 chunk 的時間。時間長度是示意值。Drawn for this primer from the overlap condition above and MegaScale §3.2.

Panel 4.7 applies the same rule to any number of chunks and any delivered bandwidth.

面板 4.7 把同一條規則用在任何 chunk 數與任何實際頻寬上。

Panel 4.7面板 4.7

Hidden or exposed藏住,還是暴露

Tcomm/TcomputeT_{\text{comm}} / T_{\text{compute}} per chunk, now
現在每個 chunk 的 Tcomm/TcomputeT_{\text{comm}} / T_{\text{compute}}
Exposed after backward
反向結束後暴露的時間
Share of communication hidden
被藏住的通訊比例

A model of the overlap condition of this section. Time is in units of one backward pass, cut into KK equal chunks. The collective of chunk kk starts when chunk kk is computed and the previous collective is done. Defaults are the illustrative durations of the figure above: each collective takes 0.8 of a chunk's compute, and only the last one is exposed. Choose 50% to get the lower half of that figure. The model leaves out α\alpha: every extra chunk adds a latency term to its collective (Section 4.3), so in practice more chunks stop helping.

這是本節重疊條件的模型。時間以一次反向計算為單位,切成 KK 個相等的 chunk。第 kk 個 chunk 的集體操作在該 chunk 算完、且前一個集體操作完成後開始。預設值是上圖的示意時間:每個集體操作花一個 chunk 計算時間的 0.8 倍,只有最後一個暴露。選 50% 就得到上圖的下半部。模型不含 α\alpha:每多一個 chunk,它的集體操作就多一個延遲項(第 4.3 節),所以實務上 chunk 多到某個程度就沒有幫助了。

A collective that cannot be hidden shows up directly in the MFU. Llama 3's context parallelism gathers keys and values in every attention layer, and the paper attributes a 3-point drop in MFU, from 41% to 38%, to that exposed all-gather (Table 4, rows 2 and 3). That is the cost of one collective per layer that has nothing to hide behind, at the scale of 16,384 GPUs.

藏不住的集體操作會直接出現在 MFU 上。Llama 3 的上下文平行在每個注意力層收集 key 與 value,論文把 MFU 從 41% 降到 38% 的 3 個百分點歸因於那個暴露的 all-gather(Table 4 第二、三行)。這就是每層一個無處可藏的集體操作,在 16,384 顆 GPU 規模上的代價。

4.8Measuring: algbw, busbw and efficiency量測:algbw、busbw 與效率

The standard tool is nccl-tests. It runs one collective at a sweep of sizes and reports two bandwidths. algbw, the algorithm bandwidth, is simply S/TS/T: the buffer size divided by the measured time. It is what the application experiences, and it is also the number that must be used in the overlap condition. busbw, the bus bandwidth, rescales algbw by the bytes the algorithm must actually move per rank, so that it can be compared with the link speed:

標準工具是 nccl-tests。它對一種集體操作掃過一系列大小,回報兩種頻寬。algbw(演算法頻寬)就是 S/TS/T:緩衝區大小除以量到的時間。它是應用程式感受到的值,也是重疊條件中必須使用的數字。busbw(匯流排頻寬)把 algbw 依演算法每 rank 實際必須搬動的位元組重新縮放,使它能與鏈路速度比較:

Collective集體操作busbw from algbw由 algbw 得到 busbwExample: algbw 25 GB/s on 64 ranks例:64 個 rank、algbw 25 GB/s
all-reducealgbw×2(N−1)N\mathrm{algbw} \times \tfrac{2(N-1)}{N}25×1.97=49.2 GB/s25 \times 1.97 = 49.2\GBs
reduce-scatter, all-gather, all-to-allalgbw×N−1N\mathrm{algbw} \times \tfrac{N-1}{N}25×0.98=24.6 GB/s25 \times 0.98 = 24.6\GBs
broadcast, reduce, send/recvalgbw×1\mathrm{algbw} \times 125 GB/s

The figure below takes the 64-rank example apart. algbw divides the buffer by the time; busbw divides the bytes that each rank actually sent by the same time.

下圖把 64 個 rank 的例子拆開。algbw 是緩衝區除以時間;busbw 是每個 rank 實際送出的位元組除以同一段時間。

One all-reduce on N = 64 ranks: buffer S, measured time T一次 N = 64 個 rank 的 all-reduce:緩衝區 S,量到時間 TS: the buffer the application handed inS:應用程式交給它的緩衝區Salgbw = S/T = 25 GB/s2(N−1)/N · S ≈ 1.97 S: the bytes each rank actually sent2(N−1)/N · S ≈ 1.97 S:每個 rank 實際送出的位元組1.97 Sbusbw = 49.2 GB/sbusbw from the same algbw of 25 GB/s, by collective同一個 algbw 25 GB/s 換算的 busbw,依集體操作algbwany collective任何集體操作25 GB/sall-reduce× 2(N−1)/N49.2 GB/sreduce-scatter, all-gather,all-to-all · × (N−1)/N24.6 GB/sbroadcast, reduce,send/recv · × 125 GB/s400 Gb/s link400 Gb/s 鏈路98% of the link鏈路的 98%02550 GB/s
One all-reduce on N = 64 ranks: buffer S, measured time T一次 N = 64 個 rank 的 all-reduce:緩衝區 S,量到時間 TS: the buffer the application handed inS:應用程式交給它的緩衝區Salgbw = S/T = 25 GB/s2(N−1)/N · S ≈ 1.97 S: the bytes each rank actually sent2(N−1)/N · S ≈ 1.97 S:每個 rank 實際送出的位元組1.97 Sbusbw = 49.2 GB/sbusbw from the same algbw of 25 GB/s, by collective同一個 algbw 25 GB/s 換算的 busbw,依集體操作algbwany collective任何集體操作25 GB/sall-reduce× 2(N−1)/N49.2 GB/sreduce-scatter, all-gather,all-to-all · × (N−1)/N24.6 GB/sbroadcast, reduce,send/recv · × 125 GB/s400 Gb/s link400 Gb/s 鏈路98% of the link鏈路的 98%02550 GB/s
Figure 4.16. What the two numbers divide by. algbw is the buffer over the time, what the application sees; busbw is the bytes each rank put on its link over the same time, so it can be laid against the link rate. The factor depends on the collective, as in the table above; only for broadcast, reduce and send/recv are the two equal.圖 4.16。兩個數字各自除的是什麼。algbw 是緩衝區除以時間,也就是應用程式看到的值;busbw 是每個 rank 在同一段時間放到鏈路上的位元組,所以能直接與鏈路速率比較。係數取決於集體操作,如上表;只有 broadcast、reduce 與 send/recv 的兩者相等。Drawn for this primer from the nccl-tests definitions and the example in the table above.

A busbw of 49.2 GB/s on a 400 Gb/s (50 GB/s) NIC means the link carried useful bytes 98% of the time. That ratio, busbw/link rate\mathrm{busbw} / \text{link rate}, is what "bandwidth efficiency" means in this chapter and in Panel 4.3, and it is only meaningful for large messages: at small sizes the time is α×steps\alpha \times \text{steps}, busbw collapses toward zero with nothing wrong, and the right metric is latency in microseconds. A healthy all-reduce curve from nccl-tests therefore rises steeply through the kilobyte sizes, bends around the crossover of Section 4.3, and flattens near the link rate above a few tens of megabytes. A curve that flattens at half the link rate, as Meta's did before tuning, points at the bytes-in-flight bound of Section 4.6, not at an overloaded network.

在 400 Gb/s(50 GB/s)的 NIC 上 busbw 為 49.2 GB/s,表示鏈路有 98% 的時間在承載有用的位元組。這個比值 busbw/鏈路速率\mathrm{busbw} / \text{鏈路速率},就是本章與面板 4.3 所說的「頻寬效率」,而且只對大訊息有意義:小尺寸時時間是 α×步數\alpha \times \text{步數},busbw 會塌向零而什麼都沒出錯,正確的指標是以微秒計的延遲。因此 nccl-tests 中健康的 all-reduce 曲線會在 KB 級大小陡升、在第 4.3 節的交叉點附近轉彎,並在幾十 MB 以上靠近鏈路速率處平坦。像 Meta 調校前那樣在鏈路速率一半處平坦的曲線,指向的是第 4.6 節的在途位元組上限,而不是網路超載。

The figure below sketches the two shapes.

下圖畫出這兩種形狀的示意。

025501 KB32 KB1 MB32 MB1 GBbusbw (GB/s)message size S (bytes, log scale)訊息大小 S(位元組,對數座標)link 50鏈路 50healthy: flat near the link健康:在鏈路附近變平flat at half: bytes in flight (Section 4.6)停在一半:在途位元組(第 4.6 節)latency-bound:延遲主導:read µs看 µsschematic shapes示意的形狀
025501 KB32 KB1 MB32 MB1 GBbusbw (GB/s)message size S (bytes, log scale)訊息大小 S(位元組,對數座標)link 50鏈路 50healthy: flat near the link健康:在鏈路附近變平flat at half: bytes in flight (Section 4.6)停在一半:在途位元組(第 4.6 節)latency-bound:延遲主導:read µs看 µsschematic shapes示意的形狀
Figure 4.17. The two shapes to look for in an all-reduce sweep from nccl-tests on a 400 Gb/s (50 GB/s) link, drawn schematically. A healthy curve rises through the kilobyte sizes, bends, and is flat near the link rate above a few tens of megabytes. In the shaded small sizes, busbw is near zero because the time is α×steps\alpha \times \text{steps}; read the latency there. A curve that is flat at half the link rate, as Meta’s was before tuning, points at the bytes-in-flight bound of Section 4.6, not at an overloaded network.圖 4.17。在 400 Gb/s(50 GB/s)鏈路上,nccl-tests 的 all-reduce 掃描中要找的兩種形狀,為示意圖。健康的曲線在 KB 級大小上升、轉彎,並在幾十 MB 以上靠近鏈路速率處變平。在加了底色的小尺寸區,busbw 接近零,因為時間是 α×步數\alpha \times \text{步數};那裡要看延遲。像 Meta 調校前那樣停在鏈路速率一半的曲線,指向第 4.6 節的在途位元組上限,而不是壅塞。Drawn for this primer from the description in this section; the curves are schematic.

Panel 4.8 turns one line of nccl-tests output into these numbers.

面板 4.8 把 nccl-tests 的一行輸出換算成這些數字。

Panel 4.8面板 4.8

Read one line of nccl-tests讀懂 nccl-tests 的一行

algbw =S/T= S/T
algbw =S/T= S/T
busbw
busbw
busbw ÷ 400 Gb/s link
busbw ÷ 400 Gb/s 鏈路

The nccl-tests definitions in the table above, with GB = 10910^9 bytes and a 400 Gb/s (50 GB/s) NIC per rank. Defaults: the example of the table, 1 GB in 40 ms on 64 ranks, so algbw is 25 GB/s, busbw is 49.2 GB/s and the link carried useful bytes 98% of the time. Type in a line from your own run. busbw above the NIC rate means that not all bytes crossed this NIC, for example over NVLink inside the server (Section 4.4). For small sizes, compare the time in µs with α×steps\alpha \times \text{steps} (Section 4.3), not busbw with the link.

採用上表 nccl-tests 的定義,GB = 10910^9 位元組,每個 rank 一張 400 Gb/s(50 GB/s)的 NIC。預設值是上表的例子:64 個 rank 上 1 GB 花 40 ms,所以 algbw 是 25 GB/s、busbw 是 49.2 GB/s,鏈路有 98% 的時間在承載有用的位元組。可以輸入你自己執行的一行。busbw 高於 NIC 速率,表示不是所有位元組都經過這張 NIC,例如在伺服器內走 NVLink(第 4.4 節)。小尺寸時,要把以 µs 計的時間與 α×步數\alpha \times \text{步數}(第 4.3 節)比較,而不是拿 busbw 與鏈路比較。

Three measured results anchor what "good" looks like. Meta: out of the box, RoCE collectives ran at well under half of the hardware's capability; co-tuning buffers, CTS priority and switch credits gave more than 2× in many cases (Meta §6.1). Alibaba: an all-reduce on 448 GPUs improved by up to 59.3% once the job fit inside one group of 1,024 GPUs that share a single layer of switches (HPN §9; Chapter 6). Meta again: a better way of spreading flows over the network's paths improved all-reduce by up to 40% (Meta §4.2; Chapter 8). None of these gains came from faster links; they came from letting the existing links carry bytes more of the time.

三個量測結果錨定了「好」長什麼樣。Meta:開箱即用時,RoCE 集體通訊遠低於硬體能力的一半;共同調校緩衝區、CTS 優先權與交換器 credit,在許多情況下帶來超過 2 倍(Meta §6.1)。阿里:任務一旦放進一個共用單層交換器的 1,024 顆 GPU 群組,448 顆 GPU 的 all-reduce 改善最多 59.3%(HPN §9;第 6 章)。再一次 Meta:更好地把流分散到網路的各條路徑上,讓 all-reduce 改善最多 40%(Meta §4.2;第 8 章)。這些增益沒有一個來自更快的鏈路;它們來自讓既有的鏈路有更多時間在承載位元組。

Chapter summary
本章摘要

Every collective's time is about α × (dependent steps) + (bytes each rank sends) ÷ (bandwidth). The ring all-reduce sends the fewest bytes, about 2S per rank, but needs 2(N−1) steps; trees need about log₂N steps but send more bytes. Small messages are latency problems and large ones bandwidth problems, and NCCL picks the algorithm per call. A hierarchical all-reduce reduces inside each server first, so only one eighth of the bytes cross the network, and only between GPUs of the same local rank. NCCL cuts a collective into channels and slots; a clear-to-send from the receiver admits each slot, so the bytes in flight must cover one bandwidth-delay product or the link idles. Collectives that overlap with computation cost nothing; the condition is that each chunk's communication finishes before its computation does.

每個集體操作的時間約為 α ×(相依步數)+(每個 rank 送出的位元組)÷(頻寬)。環形 all-reduce 送出的位元組最少,每個 rank 約 2S,但需要 2(N−1) 步;樹約需 log₂N 步,但送出較多位元組。小訊息是延遲問題,大訊息是頻寬問題,NCCL 每次呼叫時挑選演算法。階層式 all-reduce 先在每台伺服器內歸約,所以只有八分之一的位元組跨越網路,而且只在本地 rank 相同的 GPU 之間。NCCL 把一個集體操作切成多個 channel 與 slot;接收端以 clear-to-send 准許每個 slot,所以在途位元組必須涵蓋一個頻寬延遲乘積,否則鏈路會閒置。與計算重疊的集體操作不花時間;條件是每一塊的通訊都在它的計算結束前完成。

Where these ideas go next
這些概念接下來用在哪裡

Chapter 5 adds up the bytes and the time of one whole training step, and shows why the network decides how well thousands of GPUs scale.

第 5 章把一整個訓練步驟的位元組與時間加總起來,說明為何網路決定了數千顆 GPU 的擴展效果。

Optional · research frontier選讀 · 研究前沿Measuring inside the server: FabricPerf, InfiniteHBD, PingPoint量測伺服器內部:FabricPerf、InfiniteHBD、PingPointHow to observe an NVLink domain that has no NIC counters, how large a scale-up domain should be, and a GPU package treated as a network.如何觀察沒有 NIC 計數器的 NVLink 域、scale-up 域應該多大,以及把 GPU 封裝當成網路來看。Open →開啟 →

Guided readings for this chapter本章相關的論文導讀

Check your understanding檢驗你的理解