LeetLLM
My PlanLearnGlossaryTracksPracticeBlog
LeetLLM

Your go-to resource for mastering AI & LLM systems.

Product

  • Learn
  • Glossary
  • Tracks
  • Practice
  • Blog
  • RSS

Legal

  • Terms of Service
  • Privacy Policy

© 2026 LeetLLM. All rights reserved.

All Topics
Your Progress
0%

0 of 196 articles completed

🛠️Computing Foundations0/9
Git, Shell, Linux for AIDocker for Reproducible AIPython for AI EngineeringNumPy and Tensor ShapesCUDA for ML TrainingMPS & Metal for ML on MacData Structures for AISQL and Data ModelingAlgorithms for ML Engineers
📊Math & Statistics0/9
Gradients and BackpropVectors, Matrices & TensorsLinear Algebra for MLAdam, Momentum, SchedulersProbability for Machine LearningBayesian Inference from EvidenceStatistics and UncertaintyDistributions and SamplingHypothesis Tests, Intervals, and pass@k
📚Preparation & Prerequisites0/13
Neural Networks from ScratchCNNs from ScratchTraining & BackpropagationSoftmax, Cross-Entropy & OptimizationRNNs, LSTMs, GRUs, and Sequence ModelingAutoencoders and VAEsThe Transformer Architecture End-to-EndLanguage Modeling & Next TokensFrom GPT to Modern LLMsPrompt Engineering FundamentalsCalling LLM APIs in ProductionFirst AI App End-to-EndThe LLM Lifecycle
🧮ML Algorithms & Evaluation0/15
Linear Regression from ScratchLogistic Regression and MetricsDecision Trees, Forests, and BoostingReinforcement Learning BasicsValidation and LeakageStatistical Learning and GeneralizationConformal Prediction and UncertaintyClustering and PCAProbabilistic Generative ModelsCore Retrieval AlgorithmsDecoding AlgorithmsExperiment Design and A/B TestingCausal Inference and CounterfactualsPyTorch Training LoopsDataset Pipelines and Data Quality
📦Production ML Systems0/6
Feature Engineering for Production MLBatch and Streaming Feature PipelinesGradient Boosted Trees in ProductionRanking and Recommendation SystemsForecasting and Anomaly DetectionMonitoring Predictive Models
🧪Core LLM Foundations0/8
The Bitter Lesson & ComputeBPE, WordPiece, and SentencePieceStatic to Contextual EmbeddingsPerplexity & Model EvaluationFile Ingestion for AIChunking StrategiesLLM Benchmarks & LimitationsInstruction Tuning & Chat Templates
🧰Applied LLM Engineering0/25
Dimensionality Reduction for EmbeddingsCoT, ToT & Self-Consistency PromptingFunction Calling & Tool UseMCP & Tool Protocol StandardsContext EngineeringPrompt Injection DefenseResponsible AI GovernancePrivacy-Preserving Machine LearningData Labeling and Human FeedbackEvaluating AI AgentsProduction RAG PipelinesHybrid Search: Dense + SparseReranking and Cross-Encoders for RAGRAG Evaluation for Reliable AnswersLLM-as-a-Judge EvaluationBias & Fairness in LLMsHallucination Detection & MitigationLLM Observability & MonitoringExperiment Tracking with MLflow and W&BPrompt Optimization with DSPyModel Versioning & DeploymentSemantic Caching & Cost OptimizationLLM Cost Engineering & Token EconomicsModel Gateways, Routing, and FallbacksDesign an Automated Support Agent
🎓Portfolio Capstones0/9
Capstone: Delivery ETA PredictionCapstone: Product RankingCapstone: Demand ForecastingCapstone: Image Damage ClassifierCapstone: Production ML PipelineCapstone: Document QACapstone: Eval DashboardCapstone: Fine-Tuned ClassifierCapstone: Reproducible ML Study
🧠Transformer Deep Dives0/8
Sentence Embeddings & Contrastive LossEmbedding Similarity & QuantizationScaled Dot-Product AttentionVision Transformers and Image EncodersPositional Encoding: RoPE & ALiBiLayer Normalization: Pre-LN vs Post-LNMechanistic InterpretabilityDecoding Strategies: Greedy to Nucleus
🧬Advanced Training & Adaptation0/17
Scaling Laws & Compute-Optimal TrainingPre-training Data at ScaleBuild GPT from Scratch LabJAX for PyTorch ResearchersContinued Pretraining for Domain ShiftSynthetic Data PipelinesSupervised Fine-Tuning PipelineMixed Precision TrainingDistributed Training: FSDP & ZeROLoRA & Parameter-Efficient TuningTraining Run OperationsReward Modeling from Preference DataRLHF & DPO AlignmentConstitutional AI & Red TeamingRLVR & Verifiable RewardsKnowledge Distillation for LLMsModel Merging and Weight Interpolation
🤖Advanced Agents & Retrieval0/16
Vector DB Internals: HNSW & IVFAdvanced RAG: HyDE & Self-RAGGraphRAG & Knowledge GraphsRAG Security & Access ControlStructured Output GenerationReAct & Plan-and-ExecuteGuardrails & Safety FiltersCode Generation & SandboxingComputer-Use / GUI / Browser AgentsHuman-in-the-Loop Agent ArchitectureAI Coding Workflow with AgentsAgent Memory & PersistenceAgent Failure & RecoveryRecursive Language Models (RLM)Multi-Agent OrchestrationCapstone: Production Agent
⚡Inference & Production Scale0/31
Inference: TTFT, TPS & KV CacheMulti-Query & Grouped-Query AttentionKV Cache & PagedAttentionPrefix Caching and Prompt CachingFlashAttention & Memory EfficiencyContinuous Batching & SchedulingScaling LLM InferenceModel Parallelism for LLM InferenceAccelerator Architecture Field GuideCorrect GPU Profiling and BenchmarkingGPU Kernel Performance Engineering LabGPU Parallel Primitives LabGPU Compilers and Kernel LanguagesGEMM From Naive CUDA to Tensor CoresLow-Precision GPU ProgrammingGPU Runtime Execution LabAI-Generated Kernel EngineeringModel Quantization: GPTQ, AWQ & GGUFLocal LLM DeploymentSLM Specialization & Edge DeploymentSpeculative DecodingLong Context Window ManagementMixture of Experts ArchitectureMamba & State Space ModelsReasoning & Test-Time ComputeAdvanced MLOps & DevOps for AIGPU Serving & AutoscalingGPU Failure OperationsDistributed Inference Data PlaneServing Benchmark EngineeringA/B Testing for LLMs
🏗️System Design Capstones0/9
Content Moderation SystemCode Completion SystemMulti-Tenant LLM PlatformLLM-Powered Search EngineVision-Language Models & CLIPMultimodal LLM ArchitectureDiffusion Models: Images & TextReal-Time Voice AI AgentReasoning Agent System Design
🎤AI Lab Interviewing0/4
AI Lab Coding Interview: Python SystemsAI Lab System Design InterviewAI Lab Behavioral InterviewAI Lab Technical Presentation
🔬Project Deep Dives0/17
Deep Dive - vLLMDeep Dive - SkyRLDeep Dive - FlashAttentionDeep Dive - FlashInferDeep Dive - DeepGEMMDeep Dive - NCCLDeep Dive - MegatronDeep Dive - DeepSpeedDeep Dive - RayDeep Dive - MLflowDeep Dive - PyTorchDeep Dive - TransformersDeep Dive - SGLangDeep Dive - slimeDeep Dive - DeepEPDeep Dive - TinkerDeep Dive - Light-PEFT
Back to Topics
LearnProject Deep DivesDeep Dive - NCCL
⚡HardFine-Tuning & Training

Deep Dive - NCCL

Read NCCL as the communication engine beneath distributed AI: collective contracts, rings and trees, topology discovery, CUDA streams, transports, profiling, and hang diagnosis.

34 min read
Learning path
Step 185 of 196 in the full curriculum
Deep Dive - DeepGEMMDeep Dive - Megatron

Personalize this lesson

Adapt explanations and teaching visuals to your background and preferred voice.

The last chapter examined one GPU's matmul. Now suppose four GPUs each spend 8 ms computing local gradients. The step then waits 6 ms to combine a 256 MiB (mebibyte) gradient buffer from each GPU. These are illustrative timings, not a hardware benchmark.

A standalone communication test may call that transfer fast, while a real training step exposes more or less time depending on whether the move overlaps other work. If one GPU enters a different communication operation, the other three can wait at a call that looks like a network failure.

NCCL (NVIDIA Collective Communications Library, pronounced "nickel") is the library that coordinates that movement on NVIDIA systems. It provides collective operations such as all-reduce, reduce-scatter, all-gather, broadcast, and all-to-all, plus point-to-point send and receive. NCCL isn't a training framework or scheduler. PyTorch, DeepSpeed, Megatron, and serving runtimes decide what to communicate; NCCL decides how to move it across available GPU links.[1]Reference 1NVIDIA Collective Communication Library User Guidehttps://docs.nvidia.com/deeplearning/nccl/user-guide/index.html

Animated four-rank all-reduce of the first vector slot. Values 1, 10, 100, and 1000 move into a logical sum; four copies of 1111 then sit on ranks 0 through 3.
Final frame5.2s loop
Follow the first slot of the running example: 1, 10, 100, and 1000 become 1111 on every rank. The center sigma is logical ownership, not a claim that NCCL ships every byte through one physical reducer.

The collective contract

A rank is one participant in a communication group. A communicator records that group and maps ranks to devices. Each rank calls the same collective in the same order, with compatible counts and data types, the same reduction operation, and the same root when the operation has one. A root is a rank index, not a GPU device number. Breaking that agreement can cause a hang, crash, or corrupted result.[2]Reference 2NCCL Collective Operationshttps://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/collectives.html

For sum all-reduce over kkk ranks, rank rrr contributes a vector x(r)\mathbf{x}^{(r)}x(r) with NNN elements. Every rank receives:

yi=∑r=0k−1xi(r),i∈{0,…,N−1}.\mathbf{y}_i = \sum_{r=0}^{k-1} \mathbf{x}^{(r)}_i, \qquad i \in \{0, \ldots, N-1\}.yi​=r=0∑k−1​xi(r)​,i∈{0,…,N−1}.

Here, kkk is rank count, NNN is elements per input vector, and iii selects one element. This example requests ncclSum, not an average. NCCL also provides ncclAvg. The caller must choose the reduction and scaling needed by its training objective, without dividing twice.[3]Reference 3NCCL Typeshttps://docs.nvidia.com/deeplearning/nccl/user-guide/docs/api/types.html

Rank 0 calls all-reduce, while rank 1 calls broadcast on the same communicator. Why can neither operation finish?

Answer

Collectives are ordered group agreements. Each rank is waiting for peers to join the same operation with compatible arguments, but the two ranks entered different protocols.

Choose the operation from desired ownership

The output placement matters as much as the arithmetic. Use all-reduce when every rank needs the whole result. Reduce-scatter fits one reduced shard per rank. Existing shards become a complete tensor through all-gather.

OperationInput on each rankOutput ownershipCommon AI use
All-reduceSame-shaped tensorFull reduced tensor on every rankReplicated data-parallel gradients
Reduce-scatterSame-shaped tensorOne reduced chunk per rankSharded gradients in FSDP or ZeRO
All-gatherOne local chunkConcatenated chunks on every rankParameter or activation reconstruction
BroadcastFull tensor on rootRoot tensor copied to all ranksSeeds, metadata, or initial weights
All-to-allDestination chunksOne chunk from every sourceMoE token routing
Send / receivePoint-to-point bufferNamed peer onlyPipeline stage activations

Broadcast is the simple copy in that table: rank 0 keeps a buffer, and the others receive it. The animations below follow the operations whose ownership is easier to mix up, using the same four-rank numbers you'll compute by hand next.

Animated NCCL reduce-scatter on the four-rank running example. Matching chunk indices reduce to 1111, 2222, 3333, and 4444; rank r keeps only chunk r.
Final frame5.2s loop
Color marks chunk index. Matching slots reduce to 1111, 2222, 3333, and 4444, then rank r keeps only chunk r. Nobody finishes with a full tensor.
Animated NCCL all-gather on the four-rank running example. Shards 1111, 2222, 3333, and 4444 leave their owners, concatenate in rank order, and then copies of that full tensor sit on every rank.
Final frame5.2s loop
All-gather starts where reduce-scatter ends. The four owned shards concatenate in rank order, then every rank holds `[1111, 2222, 3333, 4444]`.
Animated NCCL all-to-all. Sixteen labeled payloads move from source-rank rows to destination-rank rows, preserving source identity while ownership changes.
Final frame5.2s loop
Read color as destination and the label as a source-to-destination address. Rank 2 finishes with one rank-2-bound payload from every source. This is an equal-chunk exchange, not a reduction.

NCCL's all-to-all uses equal-sized chunks. MoE routing may produce unequal token counts, so a runtime needs padding, matched point-to-point transfers, or another variable-size dispatch implementation. Don't assume the equal-chunk picture alone implements a complete MoE router. The guide also documents Gather (collect at a root) and Scatter (distribute from a root).[2]Reference 2NCCL Collective Operationshttps://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/collectives.html

An all-reduce can be implemented as reduce-scatter followed by all-gather. The first half adds corresponding chunks and leaves one finished chunk on each rank. The second half circulates those finished chunks until every rank has the full result. This is an equivalence of operations, not a claim that every NCCL algorithm executes these two API calls. Floating-point summation order can also change the last bits.[2]Reference 2NCCL Collective Operationshttps://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/collectives.html

Work one all-reduce by hand

Use four ranks with four-element vectors:

RankInput vector
0[1, 2, 3, 4]
1[10, 20, 30, 40]
2[100, 200, 300, 400]
3[1000, 2000, 3000, 4000]

Elementwise addition gives [1111, 2222, 3333, 4444]. NCCL's reduce-scatter contract places that result by rank index: rank 0 keeps 1111, rank 1 keeps 2222, rank 2 keeps 3333, and rank 3 keeps 4444. All-gather then shares those four owned chunks so every rank reconstructs the same vector.[2]Reference 2NCCL Collective Operationshttps://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/collectives.html

In fully sharded training, such as FSDP or ZeRO stage 3, each rank can keep a reduced gradient shard, update its optimizer and parameter shards, then gather parameters for later computation. That later gather is of updated parameters, not necessarily the same gradient buffer. Earlier ZeRO stages have different ownership rules.

After reduce-scatter in the four-rank example, rank 2 owns 3333. What extra operation is needed if rank 2 alone will update only that shard?

Answer

None for gradient ownership. All-gather is needed only when later computation requires every rank to reconstruct the full tensor or a full parameter bucket.

The sum is easy on paper. Moving those bytes without a central reducer that would serialize every link is the actual constraint. A ring is the bandwidth-friendly way to do that.

Why rings work well for large messages

A ring orders ranks so each sends to one neighbor and receives from another. Split a message into kkk chunks. Reduce-scatter circulates and combines chunks for k−1k-1k−1 steps. All-gather circulates the completed chunks for another k−1k-1k−1 steps.

Follow only chunk x2 (the third slot: 3, 30, 300, 3000) so the hops stay readable. The partial sum starts on rank 3 and walks clockwise until rank 2, which is the owner of index 2:

Neighbor hopRank that addsRunning sum for x2
start33000
103000 + 3 = 3003
213003 + 30 = 3033
323033 + 300 = 3333

After those three reduce-scatter hops, rank 2 owns 3333. Three all-gather hops then copy that finished shard to ranks 3, 0, and 1. Other chunks move on the same ring at the same time, offset by one slot, which is why a large buffer can keep every link busy.

Animated ring all-reduce following tensor chunk x2. The partial sum travels R3 to R0 to R1 to R2 during reduce-scatter and finishes as 3333 on rank 2. All-gather then circulates that completed shard from rank 2 around the ring.
Final frame8.5s loop
The token is chunk `x2` only. Reduce-scatter ends on rank 2 with `3333`, matching NCCL's rank-index ownership rule. All-gather then starts from that owner. The other three chunks are in flight on the same ring, just not drawn.

The next snippet is a CPU, standard-library model of that schedule, not a GPU kernel. It represents each chunk by one integer, so it accepts exactly kkk values from each of kkk ranks. It checks ownership and reconstruction without modeling CUDA streams, network progress, or floating-point error.

ring_allreduce.py
1inputs = [ 2 [1, 2, 3, 4], 3 [10, 20, 30, 40], 4 [100, 200, 300, 400], 5 [1000, 2000, 3000, 4000], 6] 7k = len(inputs) 8expected = [sum(row[i] for row in inputs) for i in range(k)] 9 10def ring_reduce_scatter(bufs): 11 k = len(bufs) 12 if not k or any(len(row) != k for row in bufs): 13 raise ValueError("expected k nonempty ranks with k scalar chunks each") 14 state = [list(row) for row in bufs] 15 for step in range(k - 1): 16 send = [state[r][(r - step - 1) % k] for r in range(k)] 17 for r in range(k): 18 recv_idx = (r - step - 2) % k 19 state[r][recv_idx] += send[(r - 1) % k] 20 return [state[r][r] for r in range(k)] 21 22def ring_all_gather(owned): 23 k = len(owned) 24 if not k: 25 raise ValueError("expected at least one owned shard") 26 result = [[None] * k for _ in range(k)] 27 for r, value in enumerate(owned): 28 result[r][r] = value 29 for step in range(k - 1): 30 snapshot = [row[:] for row in result] 31 for r in range(k): 32 src = (r - 1) % k 33 chunk = (src - step) % k 34 result[r][chunk] = snapshot[src][chunk] 35 return result 36 37owned = ring_reduce_scatter(inputs) 38gathered = ring_all_gather(owned) 39 40rank = 3 41total = inputs[rank][2] 42print("x2 path") 43print(f" rank {rank} holds {total}") 44while rank != 2: 45 rank = (rank + 1) % k 46 added = inputs[rank][2] 47 total += added 48 owned_note = " (owns chunk 2)" if rank == 2 else "" 49 print(f" rank {rank} adds {added} -> {total}{owned_note}") 50 51print(f"owned shards: {owned}") 52print(f"rank 0 after all-gather: {gathered[0]}") 53print(f"send volume factor 2*(k-1)/k = {2 * (k - 1) / k:.2f}") 54 55assert owned == expected == [1111, 2222, 3333, 4444] 56assert all(row == expected for row in gathered) 57 58# The functions derive rank count from their arguments, not the example above. 59for ranks in (1, 2, 3, 5): 60 rows = [[10 * r + i for i in range(ranks)] for r in range(ranks)] 61 reduced = [sum(row[i] for row in rows) for i in range(ranks)] 62 assert ring_reduce_scatter(rows) == reduced 63 assert ring_all_gather(reduced) == [reduced] * ranks 64for invalid in ([], [[1, 2]], [[1], [2, 3]]): 65 try: 66 ring_reduce_scatter(invalid) 67 except ValueError: 68 pass 69 else: 70 raise AssertionError("invalid chunk layout accepted") 71print("rank-count and shape checks passed")
Ring all-reduce toy
1x2 path 2 rank 3 holds 3000 3 rank 0 adds 3 -> 3003 4 rank 1 adds 30 -> 3033 5 rank 2 adds 300 -> 3333 (owns chunk 2) 6owned shards: [1111, 2222, 3333, 4444] 7rank 0 after all-gather: [1111, 2222, 3333, 4444] 8send volume factor 2*(k-1)/k = 1.50 9rank-count and shape checks passed

For message size MMM, each rank in a ring all-reduce sends about

Vsend=2k−1kM.V_{send} = 2\frac{k-1}{k}M.Vsend​=2kk−1​M.

Each rank receives the same volume. As kkk grows, that factor approaches 222, so the traffic looks like 2M2M2M per rank, not kMkMkM. The optimal-bandwidth result is for a point-to-point communication model, as analyzed by Patarasuk and Yuan. It isn't a universal byte lower bound for hardware with in-network reduction or multicast offload.[4]Reference 4Bandwidth Optimal All-Reduce Algorithms for Clusters of Workstationshttps://doi.org/10.1016/j.jpdc.2008.09.002

The same factor reappears in the nccl-tests busbw column. For this four-rank toy, the factor is 1.51.51.5; the measurement section turns that traffic factor into a concrete receipt and separates it from application time.[5]Reference 5NCCL Tests Performance Reportinghttps://github.com/NVIDIA/nccl-tests/blob/master/doc/PERFORMANCE.md

Rings pay in latency. The algorithm needs 2(k−1)2(k-1)2(k−1) neighbor steps, so a tiny message on thousands of ranks spends too much time starting rounds. Pipelining many chunks hides link delay for large buffers, but it can't erase startup cost for small ones.

Why trees help small and medium messages

A binary tree reduces values toward a root and broadcasts the answer back down. Tree depth grows roughly with log⁡2k\log_2 klog2​k, which cuts round count compared with a ring. One plain tree can overload internal ranks, so NCCL added complementary double binary trees that split data and swap leaf versus internal-node roles.[6]Reference 6Massively Scale Your Deep Learning Training with NCCL 2.4https://developer.nvidia.com/blog/massively-scale-deep-learning-training-nccl-2-4/

No algorithm wins for every tensor and topology. Rings favor sustained bandwidth. Trees favor fewer rounds. The NCCL 2.31 documentation names Ring, Tree, CollnetChain, CollnetDirect, NVLS, NVLSTree, and PAT as selectable algorithm families, plus Simple, LL, and LL128 protocols.[7]Reference 7NCCL Environment Variableshttps://docs.nvidia.com/deeplearning/nccl/user-guide/docs/env.html

Availability depends on the operation, hardware, network plugins, registration, and runtime tuning. Treat the names as candidates that explain a log, not as a menu that every host can run.

NCCL normally chooses algorithms and protocols from its topology and performance model. Forcing NCCL_ALGO or NCCL_PROTO can be useful for an experiment, but a fixed override can become wrong after hardware, message shapes, or NCCL versions change. Forcing LL128 on a path that doesn't support it can corrupt data, which is why the docs discourage protocol overrides except for diagnosis.[7]Reference 7NCCL Environment Variableshttps://docs.nvidia.com/deeplearning/nccl/user-guide/docs/env.html

Workload shapeLikely pressureWhat to inspect
Large gradient bucketsLink bandwidthRing or fabric-offload path, channel count, bus bandwidth
Tiny tensor-parallel reductionsStartup latencyTree-like path, protocol, launch gaps
MoE all-to-allImbalance and network injectionPer-peer bytes, hot experts, NIC rails
Pipeline send/receiveBubble and orderingStage timeline, peer pairing, stream waits
FSDP all-gatherBurst overlapBucket timing, parameter prefetch, compute coverage

A communicator is an ordered program

NCCL doesn't launch processes. A launcher such as MPI, Slurm, or torchrun starts them; application or framework bootstrap code exchanges a unique communicator ID and agrees on rank-to-device mapping. In a single process, ncclCommInitAll can handle this setup for a device list. Each rank within a communicator must use a distinct CUDA device.[8]Reference 8NCCL: Creating a Communicatorhttps://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/communicators.html

Each process then binds a rank to a CUDA device and creates its communicator. Only after that agreement can the ranks enqueue matching work.

After communicator creation, each rank can enqueue this C++ collective with its own buffers and CUDA stream, an ordered GPU work queue. This is an integration fragment, not a standalone executable: the caller supplies valid device buffers, a communicator, a stream, and an error-checking NCCLCHECK macro. It requires a CUDA/NCCL system and wasn't executed by the CPU examples.

all_reduce_step.cu
1NCCLCHECK(ncclAllReduce( 2 local_gradient, 3 global_gradient, 4 element_count, 5 ncclFloat32, 6 ncclSum, 7 communicator, 8 communication_stream));
CUDA stream timeline: a produced bucket becomes ready, reduce-scatter overlaps independent later compute, and a shard reader waits for communication completion.
Final frame6.7s loop
NCCL may start after a bucket-ready event while later backward kernels use independent buffers. The shard reader waits for the reduced-shard event. Updating parameters can require additional dependencies on backward computation that still reads those parameters.

For a successful call on a default blocking communicator outside a group, host return means work was enqueued, not completed. The producer must make local_gradient ready before communication reads it. A later CUDA event, stream dependency, or synchronization establishes when another kernel may consume global_gradient. Keep both buffers alive and avoid conflicting writes until the relevant work completes.[9]Reference 9NCCL CUDA Stream Semanticshttps://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/streams.html

Grouped calls can defer enqueue until ncclGroupEnd. A nonblocking communicator can return ncclInProgress; follow the documented completion/error polling before treating its stream work as enqueued. These are different boundaries from GPU completion.[10]Reference 10NCCL Group Callshttps://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/groups.html[3]Reference 3NCCL Typeshttps://docs.nvidia.com/deeplearning/nccl/user-guide/docs/api/types.html

When one thread manages several GPUs, group their matching calls with ncclGroupStart and ncclGroupEnd. A plain loop can block on its first device before the thread reaches the other ranks. Grouping doesn't relax collective order, including the documented order across communicators within a group.[10]Reference 10NCCL Group Callshttps://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/groups.html

Ordering stays global even when work is asynchronous. If one rank enters collective A then B while another enters B then A, stream scheduling can't repair the mismatch. Framework process groups and bucket schedulers exist partly to keep this distributed instruction stream identical across ranks.

💡 Key insight: An NCCL hang often begins before NCCL. One rank took a different branch, hit an out-of-memory error, loaded data slowly, or skipped a bucket. Peers then wait inside the next collective they all expected to share.

Topology turns one API into different routes

Two calls to ncclAllReduce can exercise very different hardware. Inside one server, bytes may travel through direct GPU peer access, NVLink, or NVSwitch. Across servers, the path can include PCIe, a network interface card (NIC), InfiniBand or RoCE, switches, and a remote host's reverse path.

Two separate paths: local GPU to NVSwitch to peer GPU, and cross-node GPU through PCIe, NIC A, network fabric, NIC B and PCIe to a remote GPU. NVSwitch is not a PCIe bridge.
Compare the short local route with the cross-node route. The same collective can be limited by NVLink locally, then by PCIe placement, NIC choice, rail balance, or network fabric once it leaves the host.

Read the matrix before changing a setting

On an NVIDIA host with the driver tools installed, start with host evidence before setting NCCL overrides. Run the topology query:

topology.sh
1nvidia-smi topo -m

nvidia-smi topo -m prints connections among GPUs and NICs, along with CPU and memory affinities. Its labels classify path relationships; they aren't achieved-bandwidth measurements.[11]Reference 11nvidia-smi documentationhttps://docs.nvidia.com/deploy/nvidia-smi/index.html

The exact matrix depends on the host. This excerpt is an illustrative shape, not a measurement:

nvidia-smi topo -m (illustrative)
1 GPU0 GPU1 GPU2 GPU3 NIC0 NIC1 2GPU0 X NV4 SYS SYS PIX SYS 3GPU1 NV4 X SYS SYS PIX SYS 4GPU2 SYS SYS X NV4 SYS PIX 5GPU3 SYS SYS NV4 X SYS PIX 6NIC0 PIX PIX SYS SYS X SYS 7NIC1 SYS SYS PIX PIX SYS X

Read the common cells as path hints:

CellPath classFirst hypothesis to test
NV4A bonded set of four NVLinksGPU traffic stays on the NVLink fabric
PIXAt most one PCIe switchGPU and NIC share a short PCIe route
PXBMultiple PCIe switchesExtra PCIe hops may add contention
PHBA PCIe host bridgeThe CPU or root complex sits on the route
NODEPCIe host bridges within one NUMA nodePlacement may cross a host-bridge boundary
SYSPCIe plus an interconnect between NUMA nodesRemote NUMA or fabric traffic may dominate

NV4 means four bonded links, not four times a measured rate. The matrix also doesn't draw switch nodes.

Separate the local GPU fabric from NIC access. A GPU may reach another GPU through NVSwitch, while reaching a NIC through PCIe. NVSwitch isn't a PCIe-to-network bridge. NCCL's PXN path can relay through an intermediate GPU with better NIC access; verify that distinct route in platform topology and logs. A host bridge on the route doesn't by itself mean the payload was copied through CPU memory.[7]Reference 7NCCL Environment Variableshttps://docs.nvidia.com/deeplearning/nccl/user-guide/docs/env.html

NCCL turns that topology hypothesis into a schedule. It discovers GPU, CPU, PCIe, NVLink, and network relationships, searches candidate graph layouts, and tunes a plan. GPUDirect remote direct memory access (RDMA) can let a NIC access GPU memory without staging the payload through ordinary CPU copies. Shared-memory and host-staged paths still matter when direct peer access isn't available.

Topology awareness can't create bandwidth that hardware lacks. A GPU behind the wrong PCIe root, a disabled link, a slow network interface, or oversubscribed switches still cap the collective. The library can select a better route only among paths it can discover and use.

The same all-reduce is fast within one server but slows sharply across two servers. What changed if tensor size and rank count stayed fixed?

Answer

The physical route changed. Cross-node traffic adds PCIe, network interfaces, and fabric links, so placement, rail balance, or network bandwidth can become the limit even though the collective API is unchanged.

Read one call through the source tree

The pinned source snapshot makes the runtime boundary concrete.[12]Reference 12NCCL Source Repositoryhttps://github.com/NVIDIA/nccl/tree/5067397c2676d5aed50042fc39e5c8ee96eb0027 Start with src/collectives.cc, where public functions such as ncclAllReduce package operation metadata.

The snapshot is commit 5067397c2676d5aed50042fc39e5c8ee96eb0027. The diagram is a responsibility map, not a literal stack trace: transport connections can be prepared before a device kernel runs, and not every path needs host proxy progress.

Diagram showing collectives.cc API + arguments, enqueue.cc work planning, graph/tuning.cc algo + protocol, and device/all_reduce.h CUDA choreography.
collectives.cc API + arguments, enqueue.cc work planning, graph/tuning.cc algo + protocol, and device/all_reduce.h CUDA choreography.

Use this source map instead of searching for one giant all-reduce loop:

Source areaResponsibilityQuestion to carry
src/init.cc, bootstrap.ccCommunicator setup and peer discoveryWhich ranks and devices joined?
src/graph/topo.cc, search.ccPhysical topology and graph searchWhich links can form rings or trees?
src/graph/tuning.ccAlgorithm, protocol, and channel modelWhy did this message get this plan?
src/enqueue.cc, collectives.ccHost API validation and work creationWhat exactly was enqueued?
src/device/*.h, primitives.hDevice-side copy and reduction stepsWhich rank sends, receives, or reduces next?
src/transport/*P2P, shared memory, sockets, InfiniBand, pluginsWhich physical route carries bytes?
src/proxy.ccHost proxy progress for transports that need itIs progress waiting on host or network work?
src/debug.cc, src/ras/Logs and reliability signalsWhat evidence identifies the failed rank or link?
src/nccl_device/, src/gin/Device-initiated collectives and GPU-side networkingDid a host enqueue start this, or did a device kernel?

The conventional host all-reduce path and the device-initiated interfaces aren't the same entry point. Reading only ncclAllReduce shows the contract, not the chosen schedule. Reading only a CUDA primitive shows local mechanics, not why the runtime picked that path.

How higher-level systems use NCCL

NCCL is shared infrastructure across training and inference. Its importance grows as model code partitions more tensors, because each partition boundary creates a communication event.

System patternNCCL trafficScaling failure when communication wins
Data-parallel trainingGradient all-reduceMore replicas yield diminishing tokens/sec
Fully sharded FSDP or ZeRO-3Reduce-scatter plus parameter all-gatherMemory fits, but layer gathers stall compute
Tensor parallelismFrequent activation reductions or gathersWide TP across slow links hurts every layer
Pipeline parallelismSend/receive activations and gradientsStage bubbles or peer waits grow
Expert parallelismAll-to-all token dispatch and combineHot experts create uneven peer traffic
Multi-GPU inferenceTensor-parallel reductions, KV or state exchangeInter-token latency rises despite idle FLOPs

DeepSpeed and Megatron build groups, buckets, overlap schedules, and sharding policies above NCCL. PyTorch exposes NCCL through torch.distributed. Specialized expert-routing libraries can use other communication implementations; don't infer that every GPU collective is an NCCL call. None of those layers remove the need to understand ownership and physical paths.

Choose the optimization target from operation shape. If tensor parallelism emits a small all-reduce in every transformer layer, lowering its launch latency may matter more than peak bandwidth. If data parallelism emits a few huge buckets, saturating network rails and overlapping buckets with backward compute matter more.

Measure bytes, rounds, and exposed time

Suppose six rounds each add 2 microseconds of startup, while 1 MB traverses a 50 GB/s path. The rough estimate is 12 microseconds of startup plus 20 microseconds of payload time, or 32 microseconds total. These decimal units and invented inputs illustrate a model, not an NCCL prediction.

Writing that calculation generally separates startup latency from payload time:

Tcollective≈Rα+VB,T_{collective} \approx R\alpha + \frac{V}{B},Tcollective​≈Rα+BV​,

where RRR is communication rounds, α\alphaα is per-round startup cost, VVV is bytes crossing the measured path, and BBB is achieved bandwidth. Real NCCL schedules add channels, protocol overhead, topology contention, and synchronization, but this equation tells you whether reducing rounds or moving bytes faster is the bigger target.

Small payloads make RαR\alphaRα visible. Large payloads make V/BV/BV/B visible. Keep that split in mind when you vary message size, rank count, or topology.

Turn one all_reduce_perf row into evidence

nccl-tests is a separate NVIDIA repository that checks both NCCL correctness and performance. First build it against your installed CUDA and NCCL (make, with CUDA_HOME and NCCL_HOME when needed); multi-process tests also require an MPI-enabled build. On one host with four visible GPUs, pin the scan to one payload size before comparing routes. This hardware-dependent command wasn't run for the lesson's CPU checks:

all_reduce_perf
1./build/all_reduce_perf -b 256M -e 256M -g 4 -n 20 -w 5 -c 1 -T 60

Here, -g 4 uses four GPUs per thread (one thread and process in this launch), -b and -e select 256 MiB, -n 20 requests 20 timed iterations, -w 5 adds five untimed warmups, and -c 1 requests one correctness-check iteration. -T 60 sets the test timeout in seconds. Check flags against your checkout: this description follows the public README consulted in September 2026.[13]Reference 13NCCL Testshttps://github.com/NVIDIA/nccl-tests

The following receipt has the shape of current all_reduce_perf output. Its 6.00 ms value is chosen for arithmetic, not measured from a named GPU, driver, NCCL build, or network:

all_reduce_perf (illustrative row)
1# 4 ranks · float32 sum · 5 warmups · 20 timed iterations · check=1 2# out-of-place in-place 3# size (B) count (elements) type redop root time algbw busbw #wrong time algbw busbw #wrong 4# (us) (GB/s) (GB/s) (us) (GB/s) (GB/s) 5 268435456 67108864 float sum -1 6000.0 44.74 67.11 0 6000.0 44.74 67.11 0

Start with units. size is 268,435,456 bytes, and count is 67,108,864 float32 elements. Since 6000 microseconds is 0.006 seconds, algorithmic bandwidth is 268,435,456/0.006=44.74268{,}435{,}456 / 0.006 = 44.74268,435,456/0.006=44.74 GB/s. It answers, "How quickly did this logical payload complete?"[5]Reference 5NCCL Tests Performance Reportinghttps://github.com/NVIDIA/nccl-tests/blob/master/doc/PERFORMANCE.md

For a four-rank all-reduce, the test's operation-based correction is 2(k−1)/k=2(4−1)/4=1.52(k-1)/k = 2(4-1)/4 = 1.52(k−1)/k=2(4−1)/4=1.5. Thus busbw is 44.74×1.5=67.1144.74 \times 1.5 = 67.1144.74×1.5=67.11 GB/s.[5]Reference 5NCCL Tests Performance Reportinghttps://github.com/NVIDIA/nccl-tests/blob/master/doc/PERFORMANCE.md

Read that as a normalized link-oriented score for comparing the same operation across systems. It isn't a packet counter or a promise that every physical mechanism moved exactly 1.5 payloads. The performance guide derives this factor for point-to-point collective traffic and lists different factors for reduce-scatter, all-gather, broadcast, reduce, and all-to-all.[5]Reference 5NCCL Tests Performance Reportinghttps://github.com/NVIDIA/nccl-tests/blob/master/doc/PERFORMANCE.md

The two halves of the row also answer a buffer question. Out-of-place uses separate send and receive buffers. In-place aliases them for all-reduce, which NCCL defines as sendBuff == recvBuff.[14]Reference 14NCCL In-place Operationshttps://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/inplace.html

#wrong reports elements that failed the requested correctness check. A zero count is necessary evidence for this row, but it doesn't cover a later stream or buffer-lifetime race in the application.[13]Reference 13NCCL Testshttps://github.com/NVIDIA/nccl-tests

For four ranks, 268435456 bytes divided by 0.006 seconds gives 44.74 GB/s algorithm bandwidth. Multiplying by 2(4-1)/4, or 1.5, gives 67.11 GB/s bus bandwidth. This is normalization, not measured link traffic.
The arithmetic connects logical bytes, elapsed time, and a collective-specific normalization. Neither bandwidth number identifies the physical route. Values are illustrative; application overlap needs a separate timeline.

In checkouts supporting -I 1, it adds per-iteration CUDA-event timing summaries. That shows timing spread, not proof of which rank caused a delay. Inspect per-rank traces for attribution. With only 20 samples, the reported nearest-rank p99 can equal the maximum; don't treat it as a stable tail estimate. Keep timing separate from correctness checks.[13]Reference 13NCCL Testshttps://github.com/NVIDIA/nccl-tests

Attach five pieces of evidence to a real performance claim:

EvidenceRecord beside the row
Hardware and softwareGPU model and count, host count, topology, CUDA, NCCL, framework, and nccl-tests versions
WorkloadPayload bytes, element count, rank count, and any aggregation or batch shape
Precision and pathDatatype, reduction op, in-place mode, and any forced algorithm or protocol
BaselineExact comparison command and equivalent tuning on the alternate route or build
CorrectnessCheck mode, tolerance or status, and #wrong for each buffer mode

The receipt isolates one collective. In an idealized training schedule, hiding 4 ms of a 6 ms collective leaves 2 ms exposed. Real overlap can slow compute or communication through resource contention, so establish the actual critical path from a trace.

Both schedules can produce the same receipt, so compare it with a profiler timeline and the stream event that makes the reduced buffer readable. algbw or busbw alone isn't a tokens-per-second or step-time result.

Run tests on the same hosts, GPUs, container settings, and network rails as the workload. A clean row establishes an isolated fabric baseline; it doesn't prove that model code, data loading, bucket timing, or stream dependencies expose the same time.

🎯 Production tip: Keep a small performance envelope by message size and rank count. One headline number hides the exact region where tensor-parallel latency or giant gradient buckets fail.

A clean receipt answers whether the fabric can move isolated bytes. It doesn't tell you why a live step exposed time or stopped, so the next question is causal: did ranks disagree, did a process fail, or did the route break?

Diagnose a hang without guessing

First classify whether ranks disagree, a process failed, or the network path is broken. A timeout stack that ends in NCCL doesn't distinguish those causes.

SymptomLikely classFirst evidence
One rank exited or OOMedMissing participantEarliest per-rank error, not peer timeouts
Same step hangs every runCollective order or shape mismatchPer-rank operation sequence and tensor metadata
Multi-node onlyInterface, firewall, NIC, or RDMA pathBootstrap and NET logs, host connectivity
Slow after scale-outTopology or stragglerTimeline by rank, link counters, nccl-tests
Container init failureShared memory or memlock/dev/shm, limits, NCCL warning
Wrong data without hangBuffer lifetime or stream dependencyCUDA events, producer and consumer streams

Set NCCL_DEBUG=WARN for explicit errors. Escalate briefly to NCCL_DEBUG=INFO with focused subsystems such as INIT,NET,GRAPH, and write one log per host and process when needed. NCCL documentation also covers shared-memory limits, network-interface selection, container configuration, and asynchronous error handling.[15]Reference 15NCCL Troubleshootinghttps://docs.nvidia.com/deeplearning/nccl/user-guide/docs/troubleshooting.html

Then compare all ranks at the first divergence. Check world size, rank-to-device mapping, collective name, count, dtype, root, communicator, and sequence number. If those match, test the path outside the application with nccl-tests and inspect the topology NCCL discovered.

Finally, restore automatic tuning after the experiment. Variables such as NCCL_SOCKET_IFNAME and NCCL_IB_HCA can be stable cluster configuration. Algorithm, protocol, and channel overrides are usually diagnostic controls, not permanent cargo cult.

Strengths and limits

NCCL is a small collective API over many NVIDIA GPU and network topologies. It fuses communication and reduction on device paths, picks algorithms at runtime, works from one process or many, and exposes plugins for network, tuner, profiler, and newer device-side interfaces.

Its limits are equally important:

  • NVIDIA GPU focus makes NCCL the wrong backend for CPU-only or non-NVIDIA collectives.
  • Collective correctness is distributed. NCCL can't repair mismatched control flow above it.
  • Topology selection can't fix bad cabling, oversubscription, NUMA placement, or unhealthy links.
  • Communication kernels consume GPU resources and can interfere with compute when overlap is poorly scheduled.
  • Environment overrides can hide one machine issue while hurting another.
  • Fast transport doesn't choose a good model-parallel strategy. A framework still owns groups, tensor layouts, and bucket timing.

Call NCCL when the job is on NVIDIA GPUs and bytes have to move inside a node or across nodes. Stay on the framework's process-group API unless you're building a runtime, fused kernel, or communication library that needs NCCL directly.

NVIDIA project, public source

NVIDIA develops NCCL and publishes the source in the NVIDIA/nccl repository. The repo accepts signed-off contributions under a Developer Certificate of Origin, asks large changes to begin with an issue and design discussion, and keeps tests in the separate NVIDIA/nccl-tests project.[12]Reference 12NCCL Source Repositoryhttps://github.com/NVIDIA/nccl/tree/5067397c2676d5aed50042fc39e5c8ee96eb0027

The public contributor history records individual work; it isn't a permanent ownership roster or support contract.[16]Reference 16NVIDIA NCCL Contributorshttps://github.com/NVIDIA/nccl/graphs/contributors

The pinned snapshot's license file needs a careful reading. Most project source uses Apache License 2.0, some parts retain original BSD terms, and borrowed files can carry their own licenses. "NCCL is BSD" or "every NCCL file is Apache-2.0" both erase that file-level boundary.[17]Reference 17NCCL Source Licensehttps://github.com/NVIDIA/nccl/blob/5067397c2676d5aed50042fc39e5c8ee96eb0027/LICENSE.txt

Research roots rather than one NCCL paper

NCCL doesn't have one canonical paper that defines the whole current implementation. Its core ideas come from collective-communication research plus years of topology, kernel, and transport engineering.

Patarasuk and Yuan derived a bandwidth lower bound for all-reduce and described a ring algorithm that reaches it for large messages.[4]Reference 4Bandwidth Optimal All-Reduce Algorithms for Clusters of Workstationshttps://doi.org/10.1016/j.jpdc.2008.09.002 NVIDIA's NCCL 2.4 engineering account explains why double binary trees reduce latency growth while retaining high aggregate bandwidth, and why NCCL switches between tree and ring paths.[6]Reference 6Massively Scale Your Deep Learning Training with NCCL 2.4https://developer.nvidia.com/blog/massively-scale-deep-learning-training-nccl-2-4/

Later hardware paths add NVSwitch collectives, in-network reduction, registration, multiple rails, and device-initiated communication. Those features change how an algorithm maps to hardware, but not the basic questions: who owns each chunk, how many rounds run, how many bytes cross each bottleneck, and when the consumer stream may read the result.

Source-reading exercise

Pick one all-reduce from a PyTorch profiler trace. Record tensor bytes, communicator size, duration, and whether compute overlaps it. Capture nvidia-smi topo -m beside the trace, then run nccl-tests near that message size on the same ranks.

Use the pinned source map to answer four questions:

  1. Which public function packages the operation?
  2. Which algorithm and protocol names appear in logs?
  3. Which graph and transport files correspond to the physical path?
  4. Which rank first diverges in the CPU operation-log example below?

Produce a small evidence table rather than a screenshot of a green benchmark. Connect logical operation, source path, topology labels, payload bytes, algbw, busbw, overlap time, correctness status, and first failure evidence. If the standalone row looks strong but the application still stalls, the table should make that boundary visible.

Without GPUs, compare planned collective logs instead. Each tuple below is (operation, count, dtype, reduction, root) for one communicator; None means an argument doesn't apply. This teaching checker compares completed logs. It neither runs NCCL nor detects a live network failure. A missing call is exercised locally, without leaving distributed processes hanging.

collective_log.py
1from itertools import zip_longest 2 3def first_divergence(logs): 4 if not logs: 5 raise ValueError("at least one rank log is required") 6 missing = object() 7 for step, calls in enumerate(zip_longest(*logs, fillvalue=missing)): 8 if any(call != calls[0] for call in calls[1:]): 9 return step 10 return None 11 12reduce = ("all_reduce", 4, "float32", "sum", None) 13broadcast = ("broadcast", 4, "float32", None, 0) 14baseline = [reduce, broadcast] 15assert first_divergence([baseline] * 4) is None 16cases = { 17 "missing call": [reduce], 18 "reordered calls": [broadcast, reduce], 19 "different count": [("all_reduce", 3, "float32", "sum", None), broadcast], 20 "different root": [reduce, ("broadcast", 4, "float32", None, 1)], 21} 22for name, changed in cases.items(): 23 logs = [baseline, baseline, changed, baseline] 24 step = first_divergence(logs) 25 assert step == (1 if name in ("missing call", "different root") else 0) 26 print(f"{name}: first disagreement at step {step}") 27 28payload_bytes, seconds, ranks = 256 * 2**20, 0.006, 4 29algbw = payload_bytes / seconds / 1e9 30busbw = algbw * 2 * (ranks - 1) / ranks 31assert round(algbw, 2) == 44.74 and round(busbw, 2) == 67.11 32print(f"illustrative receipt: algbw={algbw:.2f}, busbw={busbw:.2f} GB/s")
Find the first disagreement
1missing call: first disagreement at step 1 2reordered calls: first disagreement at step 0 3different count: first disagreement at step 0 4different root: first disagreement at step 1 5illustrative receipt: algbw=44.74, busbw=67.11 GB/s

Agreement doesn't establish correctness: all ranks could agree on the wrong operation, and a correct log says nothing about buffer lifetime. Compare these contracts with the intended model computation and actual stream dependencies.

Takeaways

  • A collective is an ordered agreement across ranks, not a remote function call.
  • All-reduce decomposes into reduce-scatter plus all-gather, which explains sharded-training traffic.
  • Rings achieve efficient point-to-point byte counts; trees cut rounds. Hardware offload and actual topology can change the best choice.
  • nvidia-smi topo -m gives path classes and affinities; it doesn't give achieved bandwidth.
  • For point-to-point all-reduce accounting, nccl-tests busbw is algbw times 2(k−1)/k2(k-1)/k2(k−1)/k, the same factor as ring send volume.
  • algbw describes an isolated logical payload. It isn't a substitute for an application's exposed step time after overlap.
  • CUDA streams make collectives asynchronous, but explicit dependencies still protect buffer correctness.
  • Debug the earliest rank divergence, then validate the fabric separately.

Mastery quiz

Complete the lesson

Mastery Check

Answer every question, then check your score. Score 75% or higher to mark this lesson complete.

1.Why can all-reduce be represented as reduce-scatter followed by all-gather?

Correct answer: Reduce-scatter computes reduced chunks and assigns one to each rank, then all-gather replicates those chunks.

The first phase combines corresponding elements and leaves one completed shard per rank. The second phase circulates those shards so every rank can reconstruct the full reduced tensor.

2.Four ranks contribute vectors [1,2,3,4], [10,20,30,40], [100,200,300,400], and [1000,2000,3000,4000]. After reduce-scatter, what does rank 2 own?

Correct answer: 3333, the reduced value for zero-based element index 2, which rank 2 owns after scattering.

Element index 2 sums to 3 + 30 + 300 + 3000 = 3333. The contract leaves chunk r on rank r after reduce-scatter, so rank 2 owns that scalar and doesn't need all-gather if it only updates its shard.

3.Which operation matches a sharded gradient where each rank should retain only its reduced output chunk?

Correct answer: Reduce-scatter

Reduce-scatter both reduces corresponding inputs and distributes one reduced partition to each rank. All-gather reconstructs a full tensor from already-owned chunks, while broadcast copies one root's value.

4.A 4-rank all-reduce uses a ring. Approximately how much message volume does one rank send for a message of size M?

Correct answer: 1.5M, from 2(k-1)M/k with k=4, counting one reduce-scatter and one all-gather phase.

The ring all-reduce send factor is 2(k-1)/k. For k=4, that is 2 × 3 / 4 = 1.5, covering reduce-scatter and all-gather traffic.

5.Why can a tree algorithm beat a ring for a small tensor?

Correct answer: Tree depth grows roughly with log⁡2k\log_2 klog2​k, so fewer startup rounds can help; the actual winner still depends on topology and payload.

Rings keep links busy for large payloads but need 2(k-1) neighbor steps. Trees reduce the number of rounds, which often matters more than bandwidth for small or medium messages.

6.An NCCL collective is enqueued on a communication stream while backward continues. When may an optimizer read the reduced shard?

Correct answer: After a CUDA event or stream dependency confirms the collective completed for that buffer.

The host call enqueues asynchronous device work. Overlap is safe when a readiness event or stream ordering makes the consumer wait for the reduced data, not merely when the enqueue function returns.

7.The same all-reduce is fast inside one server and slow across two servers with unchanged tensor size and rank count. Which boundary changed?

Correct answer: The physical path now includes PCIe, NIC, and fabric links, so topology or rail balance may dominate.

NCCL's API is unchanged, but the transport route is not. Cross-node collectives add interfaces, network fabric, and possible rail imbalance, so topology discovery and link counters become the first evidence.

8.All surviving ranks hang in the next collective, and one rank logged an OOM first. What diagnosis should come before forcing NCCL algorithms?

Correct answer: Treat the OOM as the earliest missing participant, then compare each rank's first error and operation sequence.

A collective requires all participants to enter the same ordered operation. A rank that exited or OOMed explains why peers wait; algorithm overrides can't repair a process-level failure.

9.A 4-rank nccl-tests run reports algbw 80 GB/s for all-reduce. What busbw value follows the article's correction?

Correct answer: 120 GB/s, because algbw 80 × 2(4-1)/4 gives the corrected bus-bandwidth estimate.

For all-reduce, busbw applies the ring traffic factor 2(k-1)/k. With four ranks the factor is 1.5, so 80 × 1.5 = 120 GB/s.

10.Which source statement matches NCCL's license boundary in the pinned tree?

Correct answer: Most source uses Apache-2.0, some files retain BSD terms, and borrowed files keep their own notices.

NCCL has mixed file-level licensing. The root terms don't erase retained BSD or borrowed-file notices, so redistribution requires checking the relevant source and dependency boundaries.

10 questions remaining.

Next Step
Continue to Deep Dive - Megatron

NCCL gives you the communication substrate. Megatron shows how tensor, pipeline, data, context, and expert parallel groups turn those collectives into one large-model training program.

PreviousDeep Dive - DeepGEMM
Share this article
XFacebookLinkedInBlueskyRedditHacker NewsEmail
References

NVIDIA Collective Communication Library User Guide

NVIDIA · 2026

https://docs.nvidia.com/deeplearning/nccl/user-guide/index.html

NCCL Collective Operations

NVIDIA · 2026

https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/collectives.html

NCCL Types

NVIDIA · 2026

https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/api/types.html

Bandwidth Optimal All-Reduce Algorithms for Clusters of Workstations

Patarasuk, P., & Yuan, X. · 2009 · Journal of Parallel and Distributed Computing

https://doi.org/10.1016/j.jpdc.2008.09.002

NCCL Tests Performance Reporting

NVIDIA and NCCL Contributors · 2026 · Official repository documentation

https://github.com/NVIDIA/nccl-tests/blob/master/doc/PERFORMANCE.md

Massively Scale Your Deep Learning Training with NCCL 2.4

Jeaugey, S. · 2019

https://developer.nvidia.com/blog/massively-scale-deep-learning-training-nccl-2-4/

NCCL Environment Variables

NVIDIA · 2026

https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/env.html

NCCL: Creating a Communicator

NVIDIA · 2026

https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/communicators.html

NCCL CUDA Stream Semantics

NVIDIA · 2026

https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/streams.html

NCCL Group Calls

NVIDIA · 2026

https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/groups.html

nvidia-smi documentation

NVIDIA · 2026

https://docs.nvidia.com/deploy/nvidia-smi/index.html

NCCL Source Repository

NVIDIA and NCCL Contributors · 2026

https://github.com/NVIDIA/nccl/tree/5067397c2676d5aed50042fc39e5c8ee96eb0027

NCCL Tests

NVIDIA and NCCL Contributors · 2026

https://github.com/NVIDIA/nccl-tests

NCCL In-place Operations

NVIDIA · 2026 · Official documentation

https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/inplace.html

NCCL Troubleshooting

NVIDIA · 2026

https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/troubleshooting.html

NVIDIA NCCL Contributors

NVIDIA and NCCL Contributors · 2026

https://github.com/NVIDIA/nccl/graphs/contributors

NCCL Source License

NVIDIA · 2026

https://github.com/NVIDIA/nccl/blob/5067397c2676d5aed50042fc39e5c8ee96eb0027/LICENSE.txt

Discussion

Questions and insights from fellow learners.

Discussion loads when you reach this section.