AI Infra Interviews logo
Distributed Training & Parallelism / 07
mediumNewNVIDIAGoogle

Derive the cost of a ring all-reduce. Why is it bandwidth-optimal, and where does it stop scaling?

Two phases, n minus one steps each, one slice per step: the derivation that gives 2(n−1)/n times the buffer per rank, the argument that no algorithm can beat it on bytes, and the latency term that makes NCCL switch to trees at scale.

Updated Sep 2026 · Grounded in real AI infrastructure interview loops and written to a senior-engineer editorial bar, with every number worked and every diagram hand-built.

TL;DR: A ring all-reduce over n ranks splits the buffer into n slices and runs two phases, reduce-scatter and all-gather, each with n−1 steps in which every rank sends and receives one slice. Each phase moves (n−1)/n of the buffer per rank, so the total is 2(n−1)/n × S per rank, which tends to 2S and does not grow with n. That is optimal in bytes, since every rank must receive at least (n−1)/n × S of other ranks' data to compute the sum and another (n−1)/n × S to hold the result. Its weakness is latency: 2(n−1) sequential steps, each paying the link's round trip, which is why NCCL switches to tree algorithms for small buffers at large n.

How to approach it

Set up the problem precisely: n ranks, each with a buffer of S bytes, and every rank must end with the elementwise sum. Then describe the ring's two phases with a small n so the interviewer can see each step. Count the bytes per rank per phase and add them. Give the lower bound so the word "optimal" has a proof behind it. Then write the full cost model with a latency term and show the crossover. Finish with what NCCL actually does.

A strong answer

A typical situation: a candidate is asked why gradient synchronization costs "about twice the model" and not "n times the model", and the answer is the ring.

Set up: n ranks in a logical ring, each holding a buffer of S bytes, which is cut into n equal slices of S/n. Rank i starts by sending slice i to rank i+1.

Phase 1, reduce-scatter, n−1 steps. In each step every rank sends one slice to its right neighbor and receives one slice from its left neighbor, adding the received slice into its own copy. After n−1 steps, each rank holds the fully reduced sum for exactly one slice: rank i owns the complete sum of slice i−1 (indices modulo n). Every rank sent n−1 slices, so it moved (n−1) × S/n bytes.

Phase 2, all-gather, n−1 steps. Each rank sends the completed slice it owns to its right neighbor, which stores it and forwards it in the next step. After n−1 steps every rank has every completed slice. Again each rank sent n−1 slices, (n−1) × S/n bytes.

rendering diagram…
inputs:  n ranks, buffer S bytes, per-rank link bandwidth B, per-step latency α

bytes sent per rank:
  reduce-scatter = (n−1) × S/n
  all-gather     = (n−1) × S/n
  total          = 2 (n−1)/n × S

time (bandwidth term only) = 2 (n−1)/n × S ÷ B

example: S = 16 GB (an 8B model's bf16 gradient), n = 64, B = 50 GB/s
  bytes per rank = 2 × 63/64 × 16 GB = 31.5 GB
  time           = 31.5 ÷ 50 = 0.63 s
same S at n = 8 over NVLink, B = 900 GB/s:
  bytes per rank = 2 × 7/8 × 16 GB = 28 GB
  time           = 28 ÷ 900 = 31 ms

sanity: doubling n from 64 to 128 changes 2(n−1)/n from 1.969 to 1.984, under 1%;
        the per-rank bytes are flat in n, which is what "scales" means here.

Why no algorithm does better on bytes. Each rank must end with the sum, which depends on all n inputs, so it must receive information from n−1 other ranks about every element. The minimum is (n−1)/n × S received in the reduction phase (it already holds its own 1/n contribution to each slice, but even in the most favorable arrangement it must take in the other ranks' contributions for the slice it reduces, and the reduced results for the slices it does not) plus (n−1)/n × S received in the distribution phase for the slices reduced elsewhere. Under the model where every rank has one link in and one link out and bandwidth is the constraint, 2(n−1)/n × S is the floor and the ring meets it. Ring vs Tree All-Reduce has the comparison with the alternatives.

Where it stops scaling. The bandwidth term is flat in n, but the ring takes 2(n−1) sequential steps and every step pays a fixed latency α: the time to launch the transfer, traverse the switch, and synchronize with the neighbor. The full cost is:

T_ring = 2 (n−1) × α + 2 (n−1)/n × S ÷ B

with α ≈ 10 µs across an InfiniBand fabric:
  n = 64,   S = 16 GB:  latency 1.3 ms, bandwidth 630 ms  → bandwidth dominates
  n = 1,024, S = 16 GB: latency 20 ms,  bandwidth 640 ms  → still fine
  n = 1,024, S = 1 MB:  latency 20 ms,  bandwidth 0.04 ms → latency dominates by 500×

sanity: small buffers at large n are the failure case, and they are common:
        DDP buckets of 25 MB, per-layer FSDP gathers, and any collective
        launched for a scalar such as a gradient norm.

A tree all-reduce (a reduce up a binary tree and a broadcast down) takes about 2 log₂(n) steps instead of 2(n−1), so at n = 1,024 it pays 20 latencies instead of 2,046, at the cost of a bandwidth term that is worse by a constant. NCCL and Collective Algorithms describes how NCCL picks: it models both costs per collective size and topology and chooses ring for large buffers and tree for small ones, and NCCL_ALGO=Ring or Tree overrides it for measurement. On NVSwitch systems there is a third option, NVLS, where the switch itself performs the reduction and the per-GPU traffic drops toward S.

Decision: the ring is the right mental model and the right algorithm for the large gradient and weight collectives of training. The condition that reverses it is the buffer-size-to-rank-count ratio; when S/n falls below a few hundred kilobytes, latency terms take over and trees, or fusing the small collectives into larger ones, win.

The reversal condition: small buffers, where the ring's 2(n−1) latency term dominates and a tree wins. NCCL switches on its own, and NCCL_DEBUG=INFO prints which algorithm it chose, which is worth reading before tuning anything by hand.

What interviewers probe next

  • "Why does a reduce-scatter cost half an all-reduce?" It is exactly phase 1: (n−1)/n × S per rank, which is why ZeRO-3 can replace an all-reduce with a reduce-scatter plus a later all-gather at the same total bytes.
  • "How does a 2D torus change this?" Rings run along each dimension, so a 2D ring all-reduce does two smaller rings of √n ranks each, cutting the latency term to about 4(√n − 1) at the same bandwidth term.
  • "What is the bandwidth in the formula when links are bidirectional?" The ring sends and receives at the same time on different links, so B is the per-direction figure; a "900 GB/s" NVLink number is bidirectional and the honest B is 450 GB/s.
  • "Does the reduction arithmetic ever matter?" At n = 1,024 with bf16 buffers, yes: the sum order differs from a serial sum, so results are not bitwise reproducible across world sizes, and NCCL reduces in the buffer's dtype unless told otherwise.

Common mistakes

  • Quoting 2S per rank without knowing it is 2(n−1)/n and why.
  • Claiming ring all-reduce is "O(n)" in cost; the bytes are constant in n and only the latency term is linear.
  • Forgetting the latency term entirely, then being unable to explain why NCCL has a tree algorithm.
  • Using the bidirectional link figure as the per-direction bandwidth.

Key takeaways

  • Reduce-scatter then all-gather, each (n−1)/n × S per rank; total 2(n−1)/n × S, which tends to 2S.
  • Bandwidth-optimal: every rank must receive at least that much to hold the full sum.
  • Full cost 2(n−1) α + 2(n−1)/n × S/B; the latency term wins for small S at large n, and NCCL switches to tree there.
  • 16 GB at n = 64 over 50 GB/s is 0.63 s; the same at n = 8 over NVLink is 31 ms.
That one was free — and so are 10 answers per topic without an account. Signing in doubles that to 20, opens the Plus lessons in the courses, and remembers which topics you keep getting wrong.no card · Google sign-in · nothing to cancel
HOW DID IT GO?
0
READING SIGNED OUT

Signing in doubles your free answers, from 10 to 20 per topic, and the site starts remembering you: mastery per topic, bookmarks, and a next-focus recommendation. Free, no card.

Sign in free

The concepts behind this question

Ranked by how closely each one overlaps this question's topic, so the first card is the thing to read if the answer above moved too fast.

Foundational
🔌 Networking & Storage
NCCL and Collective AlgorithmsNCCL is the library every PyTorch collective lands in, and its choice of ring or tree, channel count and protocol decides whether an all-reduce runs at fabric speed or at a third of it. Knowing what NCCL_DEBUG=INFO prints, and which environment variable changes which decision, is the difference between tuning a cluster and guessing at it.
Foundational
🕸️ Distributed Training
Collective Communication PrimitivesAll-reduce, all-gather, reduce-scatter, all-to-all and broadcast are the five operations every parallelism strategy is built from, and each has a fixed per-rank traffic cost you can compute before a job runs. Knowing those volumes for a named model is how you decide whether a layout is compute-bound or waiting on the network.
Advanced
🕸️ Distributed Training🔒 Premium
Ring vs Tree All-ReduceA ring all-reduce moves the minimum possible bytes per rank but takes 2(N-1) steps, so its latency grows with the number of GPUs; a tree finishes in a logarithmic number of steps but is harder to keep bandwidth-optimal. NCCL keeps both, chooses per message size and rank count, and reading its choice is how you diagnose a collective that is slower than the fabric allows.
Foundational
🕸️ Distributed Training
Data Parallelism and DDPData parallelism gives every GPU a full copy of the model, feeds each a different slice of the batch, and averages the gradients with an all-reduce so every replica takes the same optimizer step. It is the first parallelism every training job uses, and the tokens-per-GPU arithmetic behind it decides whether the communication hides behind the backward pass or dominates the step.
UP NEXT ON YOUR JOURNEY
FEDITOR'S NOTE

Scored on deriving both phases rather than reciting the formula, on the lower-bound argument for bandwidth optimality, and on knowing that the (n−1) × latency term is why ring loses to tree for small buffers and large n.

DISCUSSION · 0

No comments yet — be the first to share your approach.