GPU Kernel Fusion

Kernel fusion (also called operator fusion) is the optimization of combining several separate GPU operations into a single kernel, so that intermediate results stay in fast on-chip memory instead of being written out to and read back from HBM between every step. It is the single most important trick a deep-learning compiler applies, because the operations that dominate a modern model are limited by memory bandwidth and kernel-launch overhead, not by arithmetic — and fusion attacks exactly those two costs.

Most deep-learning operators are memory-bound, which is why fusion pays off. An elementwise add, a GELU, a bias, a layer-norm — each does trivial arithmetic per element but must stream its entire input and output through global memory. Run them as separate kernels and each one pays a full HBM read plus a full HBM write, and the GPU's compute units sit mostly idle waiting on bandwidth. Fuse a chain of them into one kernel and you read the input once, do all the arithmetic while the data sits in registers, and write the result once. The floating-point work is unchanged; what disappears is the traffic to HBM and all but one of the kernel launches.

Fusion comes in a few distinct shapes. *Vertical* (producer-consumer) fusion merges a chain where each op consumes the previous op's output — a matmul feeding a bias feeding an activation — and keeps the hand-off in registers or shared memory. *Horizontal* fusion batches independent operations that share inputs, or many tiny operations, into one launch to amortize dispatch overhead and raise occupancy. *Epilogue* fusion folds the cheap elementwise tail (bias, activation, residual add) directly into a compute-bound kernel's writeback stage, as cuBLASLt and CUTLASS do for GEMMs — you get the elementwise work essentially for free while the matmul result is still in registers.

The roofline is the clean way to see what fusion does. Every kernel has an arithmetic intensity — FLOPs performed per byte moved — and the roofline model says a kernel is memory-bound until that intensity is high enough to saturate the compute units. A lone elementwise op has terrible intensity (a couple of FLOPs per element read and written) and lives deep in the memory-bound region. Fusing a chain divides the same FLOPs by far fewer bytes, pushing the fused kernel rightward toward the compute-bound ridge. Fusion does not add arithmetic; it deletes the bytes in the denominator.

Not everything fuses the same way, and some fusions are whole algorithms. Elementwise chains and reductions fuse readily; compute-bound matmuls and convolutions are already efficient and typically only fuse their epilogues. Operations with a global dependency need more care — a softmax needs a full-row max and sum before it can normalize — which is why the highest-value fusions are redesigned algorithms rather than mechanical merges. FlashAttention is the canonical example: it fuses the entire query-key-softmax-value pipeline into one kernel using an online-softmax recurrence, so the enormous N-by-N score matrix is never written to HBM at all. Compilers such as TorchInductor, XLA, and TensorRT find the easy fusions automatically; the hard ones are still written by hand in Triton or CUDA.

Fusion typeWhat it mergesPrimary win
Vertical (producer→consumer)a chain like matmul → bias → GELUintermediates stay on-chip, fewer HBM trips
Horizontalindependent ops sharing inputs / many tiny opsone launch, higher occupancy
Epilogueactivation / bias / residual into a GEMM writebackelementwise tail is nearly free
Whole-algorithm (e.g. FlashAttention)tiled QK·softmax·V via online softmaxthe N×N score matrix never touches HBM
UNFUSED — 6 HBM TRIPS add mul relu T0→HBM T1→HBM T2→HBM HBM (6 round-trips) write write write read read memory BW = bottleneck ① Pointwise fusion add / mul / relu — always fusible, no data deps ② Reduction fusion softmax / layernorm — online Welford algorithm keeps fused ③ Compiler auto-fusion Inductor / XLA / nvFuser detect patterns; emit 1 kernel FUSED — 2 HBM TRIPS fused_kernel_0 (single GPU kernel launch) SRAM / registers (on-chip) add mul relu T1, T2 stay on-chip no HBM write/read HBM (2 round-trips only) read ×1 write ×1 3× less memory traffic same compute, higher throughput Unfused latency 6× Fused latency 2× Why it works GPU occupancy limited by memory BW, not compute FLOPs. Keeping intermediates in SRAM eliminates the HBM round-trip penalty entirely. ROOFLINE — FUSION SHIFT Performance (TFLOP/s) Arithmetic Intensity (FLOP/byte) 0 50 100 150 200 2 4 6 8 Peak Compute Mem BW ridge U unfused AI≈1.5 F fused AI≈4.5 3× AI shift Fusion Impact (A100 benchmarks) Pointwise chain (add+mul+relu) 2.8× faster Softmax (3-pass → 1-pass) 1.9× faster LayerNorm (Welford fused) 1.6× faster FlashAttention (full QKV fused) 4× faster

Read fusion through a *how-many-times-does-this-data-cross-HBM* lens rather than a *how-many-FLOPs-does-this-do* lens: the arithmetic in a transformer's pointwise and normalization layers is almost free, so the compiler's job — and yours, when you drop into Triton — is to keep intermediates on-chip and collapse many launches into one, which is why the same math can run several times faster with no change to the numbers it computes.

Take gpu kernel fusion further

Ask the copilot about this term, or have our engineers assess it against your process.