Measure the boundary instead of declaring every graph break a failure
Account for compilation, eager regions, dispatch, synchronization, and fusion limits using a fictional pipeline and a synthetic roofline ceiling.
On this page
The question for today
What you’ll understand
- Explain the correctness and performance roles of eager fallback boundaries.
- Calculate a complete cold-to-warm execution budget.
- Distinguish measured boundary cost from a memory-throughput upper bound.
A graph break marks a boundary in captured execution, and its consequence depends on the surrounding work. It can prevent profitable fusion or introduce dispatch and synchronization, yet it can also preserve a small host interaction outside a large efficiently compiled region. Removing a break by changing semantics is not a performance improvement. The useful engineering question is which correct arrangement minimizes the relevant workload's cost, including capture, compilation, artifact reuse, eager work, and the conditions under which measurements were completed.
Locate both the cause and the actual boundary work
In PyTorch 2.9's documented partial-capture model, unsupported operations or data-dependent host behavior can lead to eager execution between captured regions. A value inspection that requires a device result on the host can also expose synchronization cost, though a graph break does not universally imply a device synchronization. Capture options and supported operations are version-sensitive. Inspect diagnostics and a profiler for the exact program instead of inferring cost solely from the number of graphs shown in a report.
Some boundaries are intentional. A request logger might be tiny relative to the matrix product before and after it, or an infrequently executed error path may not justify aggressive capture work. Conversely, a break inside a short operation repeated hundreds of times can dominate launch and dispatch costs. Count frequency as well as duration. Preserve equivalent input preparation, host behavior, and device completion when comparing alternatives; otherwise removing a log operation or failing to wait for work can look like a compiler speedup.
Bigger capture does not guarantee better kernels
Combining regions may avoid materializing an intermediate or launching another kernel. It can also enlarge live ranges, increase register pressure, alter scheduling opportunities, or create a more expensive compilation. These effects depend on operation shapes and the backend. A fully captured graph is therefore useful evidence about representability, not a universal certificate of faster execution. Choose performance hypotheses with an identified mechanism, such as removing a repeated host round trip, then test that mechanism with controlled inputs.
For memory-sensitive operations, reduced traffic can raise a throughput ceiling without establishing the achieved rate. The roofline model divides operation count by bytes moved at a stated memory boundary; its bandwidth term is an upper bound under that model. Do not substitute allocation size for actual traffic or count a read only once when the implementation reloads it. Fusion can change both traffic and other bottlenecks, and a boundary change may affect dispatch without changing arithmetic intensity at all.
Separate cold, warm, and changing-contract measurements
Report the initial call and steady compatible calls separately, then add a workload that changes relevant guards. Include repetitions and a declared aggregation rule rather than selecting the fastest sample without context. For asynchronous accelerators, wait for the result at the chosen measurement boundary, as the JAX JIT documentation demonstrates. Also record what warm-up did: it may populate artifact caches, memory pools, and device libraries. Those effects are real parts of the experiment, not automatically costs of the same compiler stage.
In the roofline lab, Reset and set both I=8 FLOP/byte and B=80 GB/s. Predict the ceiling 640 GFLOP/s, then Play or Step to trace it. Reset and set both I=16,B=80 for the separate ceiling 1,000 GFLOP/s. These are hypothetical intensity choices rather than the measured effect of deleting a graph break. Playback only traces the selected roof. Use this instrument to distinguish a potential traffic benefit from a guaranteed runtime saving, then return to the actual program's synchronized measurements.
Work it through
Include eager and boundary work in the break-even point
A fictional eager function takes 5 ms per call. A staged alternative costs 100 ms to compile, then spends 2.5 ms in compiled tensor work, 0.5 ms in retained eager work, and 0.5 ms in boundary overhead per call. Assume additive nonoverlapping completed timings and one artifact.
Add the staged per-call terms: 2.5+0.5+0.5=3.5 ms. The complete staged budget is 100+3.5N ms, not just the 2.5N tensor term.
Solve 100+3.5N<5N, giving N>100/1.5≈66.67. The first whole-number saving occurs at sixty-seven compatible calls.
At one hundred calls, staged costs 450 ms and eager 500 ms, a fifty-millisecond modeled saving. If repeated compilation or a synchronization cost was omitted, this conclusion must be recalculated.
This boundary-containing arrangement can still be profitable. The arithmetic neither proves every break harmless nor proves that capturing the retained eager region would improve the result.
The living notebook
Explore the model
Interactive lab · roofline
Separate a traffic ceiling from a boundary timing measurement
Fresh Reset → set both I=8,B=80 predicts 640 GFLOP/s; Reset → set both I=16,B=80 predicts 1,000 GFLOP/s. Play or Step traces the fixed synthetic roof. No compiler, launch overhead, graph break, or synchronization is simulated.
- Attainable ceiling
- 640 GFLOP/s
- Ridge intensity
- 12.5 FLOP/byte
- Ceiling regime
- Memory-bound ceiling
Synthetic roofline ceiling min(1000, B·I), in GFLOP/s, with B in decimal GB/s and I in FLOP/byte. Playback traces the roof without changing the selected kernel. This upper-bound model is not a measured throughput prediction, hardware comparison or price model. 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 higher theoretical ceiling is a performance hypothesis that still needs equivalent completed-work measurements.
Pause & reason
Check your understanding
Your turn
Try it yourself
Suppose a rewrite removes the 0.5 ms boundary term but raises compilation cost from 100 to 180 ms, while tensor and retained eager work stay at 3 ms total. Compare both staged alternatives over one hundred calls.
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
The original staged total was 450 ms. Account for the larger one-time cost before crediting the per-call saving.
Compare with the solution
The rewrite costs 180+100×3=480 ms, thirty milliseconds more than the original 100+100×3.5=450 ms. It still beats the assumed 500 ms eager total by twenty milliseconds, but it is worse than the boundary-containing alternative at this call count. The rewrite's eighty-millisecond extra compilation needs more than 160 calls to recover through a half-millisecond saving per call; at 160 the alternatives tie.
Keep the idea
Take it with you
- Graph breaks can preserve useful eager behavior while creating workload-dependent costs.
- Capture size and kernel performance are separate questions.
- Compare complete synchronized budgets and keep throughput ceilings distinct from measurements.
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.