Point-to-point pipeline deadlocks
Trace communication matching, wait cycles, collective order, and buffer ownership instead of assuming asynchronous calls guarantee progress.
On this page
The question for today
What you’ll understand
- Build a wait-for trace for a small communication cycle.
- Check message identity, group, order, shape, and participation.
- Separate progress guarantees from bandwidth bounds and timeout detection.
A pipeline can hang while every GPU is healthy if its ranks wait for communication that the schedule never posts. A wrong peer, reversed collective order, missing rank, or reused buffer can produce different failures with similar symptoms. This lesson scopes concrete API rules to PyTorch 2.8 distributed communication, while using explicit blocking assumptions for the hand traces. Nonblocking initiation enables some legal schedules; it is not a universal deadlock cure.
Match both endpoints of every logical message
A tensor transfer needs a sender, receiver, process group, direction, compatible shape and dtype, and the intended microbatch or virtual-boundary identity. Some backends match by communication order rather than supporting every tagging scheme, so source-level identifiers alone do not guarantee matching. Log the schedule’s logical identity even when the backend protocol uses ordered operations. Two equal-shaped messages swapped between microbatches can complete transport successfully while corrupting the gradient computation; progress and numerical correctness require separate checks.
PyTorch 2.8 documents that batched isend/irecv ordering must match the remote endpoint’s operations. With NCCL, set the intended current CUDA device and respect the special participation rule if the batch is the first collective call for its group. A subgroup-only pattern that is legal later is not automatically legal during that initialization case. When several process groups or collectives interact, maintain the required consistent creation and execution order across ranks; a local code path can otherwise wait for a different collective than its peer entered.
A request object does not remove dependencies
If every rank performs a blocking receive before posting the send that would satisfy another rank, the schedule can have no first enabled action. Posting nonblocking operations with the required matching order can break that artificial dependency, but immediately waiting on a send before posting its needed receive can recreate a cycle. Draw which action each wait requires, including collectives and CUDA-stream dependencies. The relevant graph is the wait-for graph of the actual implementation, not merely the model’s forward dependency graph.
Keep send storage valid and unmodified until the documented completion conditions permit reuse, and do not consume a receive destination before it is ready on the consumer’s execution stream. Host return and device completion differ for CUDA operations. An implementation can therefore appear to make progress while racing over a buffer. Capture request completion, stream ordering, and buffer ownership in the trace alongside message matching. Correctness requires those lifetimes even if a communication benchmark reports excellent bandwidth.
Diagnose missing progress with bounded evidence
Collect rank-local logs with operation sequence, peer and group identity, tensor metadata, and completion events. A timeout identifies failure to meet a progress bound; it does not repair a bad schedule or prove which rank caused it. Distinguish a rank that exited, a missing participant, a mismatched collective, and a legal but overloaded transfer path. Reproduce with two or three ranks and small deterministic tensors before adding full training state. A recovery strategy must use the runtime’s supported fault behavior rather than assuming an interrupted communicator is immediately reusable.
The modular lab visualizes only a three-node cycle. Reset, set modulus to 3 and additive step to 1, predict the return point, then Step three times. The residues return to zero after visiting three positions. This arithmetic is not a wait-for graph execution: it has no blocked ranks, posted requests, tensor matching, collectives, or failure model. Use the separate hand trace to explain why a particular cycle has no enabled action, rather than treating any cyclic topology as a deadlock.
Work it through
Three receives with no first send
Three ranks first execute blocking receives in a cycle: rank zero waits for one, one waits for two, and two waits for zero. Each posts its corresponding send only after its receive returns. Assume no other work can supply these messages. After redesign, suppose three four-MiB messages share one serial four-GiB/s bottleneck.
The trace has three blocked ranks and three wait edges forming a directed cycle. No rank has reached its send, so no required receive can complete under the stated assumptions. There is no finite bandwidth-derived completion time for this schedule.
Redesign the initiation and wait order so matching sends and receives can be posted according to the backend’s contract, then wait only after the needed peers can participate. This requires checking endpoint order and lifetime, not merely renaming calls asynchronous.
For the separate valid-progress bandwidth model, payload totals 12 MiB. Its movement lower bound is 12/4096 seconds, approximately 2.930 milliseconds, before startup, contention, and synchronization costs.
A dependency repair establishes the possibility of progress; a transfer-volume calculation applies only after that repair.
The living notebook
Explore the model
Interactive lab · modular
A cycle is topology, not a progress proof
Reset, set modulus m = 3 and additive step a = 1, predict the period, then Step three times to return to zero. This modular orbit illustrates cyclic node labels only; it does not execute blocking communication or detect pipeline deadlocks.
- Residue r0
- 0
- Orbit period · m/gcd(m,a)
- 12
- Distinct residues visited
- 1 of 12
Addition modulo m starts at zero: rₙ = na mod m. Playback advances two additions per second. The orbit has period m/gcd(m,a), including period one for a = 0. This is not a cryptographic security test or a primality algorithm. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forA deadlock argument needs blocked-action dependencies and no enabled progress, not merely a cyclic connection diagram.
Pause & reason
Check your understanding
Your turn
Try it yourself
Two ranks each post a nonblocking send, immediately wait for it, and only then post their receive. Explain why progress is not guaranteed by that structure. Separately, compute the movement lower bound for one eight-MiB payload over an assumed eight-GiB/s bottleneck after a valid matching schedule exists.
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Do not assume unlimited eager buffering or a receive that has not been posted. Keep the correctness argument separate from byte accounting.
Compare with the solution
Without a backend guarantee that both sends complete without posted matching receives, each wait can prevent the peer from reaching its receive. Post and order operations according to the supported communication contract before dependent waits. For the separate progressing payload model, 8/8192 seconds is approximately 0.977 milliseconds. That lower bound does not promise completion of the original blocked schedule or waive buffer-lifetime requirements.
Keep the idea
Take it with you
- Message matching includes logical identity, group, endpoint order, and tensor metadata.
- Nonblocking calls still require a dependency-respecting initiation and wait order.
- Timeouts and bandwidth estimates answer different questions from a progress proof.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.