Kernel fusion: remove traffic without hiding resource costs
Compare materialized and fused pointwise stages while accounting for intermediate rounding, registers, spills, occupancy, and other consumers.
On this page
The question for today
What you’ll understand
- Count logical intermediate traffic eliminated by a simple fusion.
- Explain how larger live ranges can increase registers or spills.
- Validate semantic equivalence and end-to-end performance instead of assuming fewer launches is always faster.
Fusion combines stages so an intermediate value can remain local instead of being written out and read back. That can save traffic and launch overhead, but the intermediate must remain somewhere while later work uses it. Longer live ranges consume registers or other storage, and changed arithmetic boundaries can change rounding. Count both what disappears and what becomes more expensive.
Eliminate only an intermediate the graph can truly lose
Consider two pointwise stages producing t=f(x) and then y=g(t), with no other consumer of t. Separate kernels can read x, write t, read t, and write y. A fused kernel can compute both stages for an element and write only y. This is a simple local dependency: it does not require a grid-wide synchronization between stages. If another branch needs t, the implementation may still need to materialize it or recompute it. The full computation graph determines which traffic is actually removable.
A reduction or cross-block dependency can make fusion more complicated than placing source statements next to one another. Threads consuming a globally complete intermediate need a supported coordination design, not an ordinary block barrier pretending to cover the device. Also preserve the numerical operation the user requested. A materialized lower-precision intermediate introduces a conversion that unrestricted fused arithmetic might omit; contracting a multiply and add can change rounding. Decide whether the contract permits that difference or requires an explicit cast or other preservation of the intermediate semantics.
Longer live ranges can consume the saved bandwidth
A fused kernel can retain more values per thread at once, increasing register demand. That may reduce the number of resident blocks or force some values into local memory. In CUDA terminology, local memory is private-addressed storage that can be backed through the device-memory hierarchy, not a promise of a fast on-chip register. Caches may satisfy some spilled accesses, but spills still add work and can undo traffic savings. Inspect compiler resource reports and profiling evidence rather than assuming the source-level number of variables equals allocated registers.
A register-only residency bound divides a multiprocessor's register capacity by registers per block, but actual residency also depends on allocation granularity, thread and warp limits, shared memory, block limits, and architecture. Restricting the register count can raise the bound while adding spills or instruction overhead. Higher occupancy is not automatically higher throughput. A kernel with fewer resident blocks may benefit from reuse or fewer instructions, while another needs more independent warps to hide latency. Compare the mechanism with measured stalls and complete workload time.
Measure a complete graph under the same semantics
Compare separate and fused versions with the same shapes, layouts, dtypes, masks, and precision policy. Include temporary allocation and conversion only according to the production boundary, and report both kernel-only and end-to-end results when useful. Check whether fusion removes useful overlap with other work or changes scheduling for a small batch. Revalidate edge rows and nonfinite behavior after combining reductions or normalization. A faster output that omitted a required intermediate consumer or changed the function is not evidence of an optimization.
The roofline lab isolates the potential traffic benefit. Reset, set I=2 and B=100, predict ceiling 200 GFLOP/s, then Play or Step. Separately Reset, set I=4 and B=100, predict 400 GFLOP/s, then Play or Step. Its compute ceiling stays at 1,000 GFLOP/s. The model cannot change register allocation, produce spills, or fuse a graph. Use the twofold synthetic bound as a hypothesis for eliminating intermediate bytes, then explain what compiler and timing evidence would show whether register pressure or another bottleneck prevented that gain.
Work it through
Count saved bytes and a coarse register tradeoff
Two same-width pointwise stages process one million four-byte elements with no other intermediate consumer. Separately, a fictional multiprocessor has 65,536 register units and blocks of 256 threads; compare 32 versus 64 units per thread.
Ideal separate logical traffic is 4×1,000,000×4=16 MB. Fused logical traffic is 2×1,000,000×4=8 MB, saving 8 MB under the defined boundary.
At 32 register units per thread, a block uses 256×32=8,192 units and the coarse register-only bound allows at most eight blocks. At 64 units, a block uses 16,384 and the bound falls to four.
The byte saving and bound change do not determine the winner. Actual allocation granularity, other resource limits, spills, scheduling, and semantic preservation must be measured in the complete comparison.
Fusion can halve this ideal traffic while reducing a register-only residency bound. Neither fact alone establishes the resulting execution time.
The living notebook
Explore the model
Interactive lab · roofline
Traffic savings produce a conditional ceiling change
Reset, set I=2 and B=100, predict 200 GFLOP/s, then Play or Step. Separately Reset, set I=4 and B=100, predict 400 GFLOP/s, then Play or Step. The fixed 1,000-GFLOP/s model has no fusion graph, registers, spills, launch overhead, or occupancy.
- 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 forEliminated intermediate bytes are one benefit to compare with the resources fusion requires.
Pause & reason
Check your understanding
Your turn
Try it yourself
An intermediate tensor has 262,144 two-byte elements and no other consumer. Find the ideal write-plus-read bytes removable by fusion. Name a semantic reason the fused computation could still differ.
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Count one write and one read of the intermediate, then consider a materialized dtype conversion.
Compare with the solution
Removable logical traffic is 2×262,144×2=1,048,576 bytes, exactly 1 MiB. If the separate intermediate rounded to a lower-precision format while the fused path retained a wider value, later results can differ. Other consumers, masks, and reduction order also need preservation under the actual contract.
Keep the idea
Take it with you
- Fusion can remove intermediate traffic only when the graph and semantics permit it.
- Longer live ranges trade traffic against registers, spills, and scheduling.
- Use complete correctness and timing evidence instead of launch count or occupancy alone.
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.