Zenaique

Walk through how CUDA graphs reshape per step decode latency and when the win disappears

Short answer·Medium·4.0 · 0·~3 min·Asked atNVIDIASierraSourcegraph
Attempt it

Explain what CUDA graphs do during decode and why the speedup is most visible at small batch. Then identify two conditions under which CUDA graphs help less, or break entirely.

Free · 2 AI evals / day
TL;DR

CUDA graphs record the kernel-launch sequence of one decode step and replay the whole graph as a single submission, collapsing dozens of per-step CPU dispatches into one.

Memory aid
Sign in to see the mnemonic that makes this stick.
Easy to grasp

Picture a busy chef shouting instructions to a fast cook for each tiny task: chop, stir, pour, taste. The cook is so fast that most of the wall-clock time is the chef finishing one sentence and starting the next. CUDA graphs let the chef write the whole recipe down once and just say 'do that recipe' on every batch, so all the talking happens once. This makes a big difference when the cook is much faster than the chef can talk, which is exactly what happens during decode at small batch. But if the recipe changes every batch (different ingredients, different steps), writing it down does not help, and that is when CUDA graphs stop working.

Concept explanation~2 min read

Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.

CUDA graphs are one of the highest-leverage CPU-side optimizations in modern LLM serving, and one of the most counterintuitive at first glance. They do not make the GPU faster at anything. They eliminate the wall-clock time the GPU spends waiting for the next kernel to be dispatched.

The central insight is that GPU work and GPU dispatch are not the same cost. The GPU itself can execute kernels back to back with very little overhead once they are queued, but each kernel needs to be queued by the host CPU, and that dispatch has a non-trivial cost (10-30 microseconds on typical hardware). For workloads with many short kernels, the dispatch can become a larger share of wall-clock time than the actual compute.

LLM decode at small batch is exactly that workload. Each step fires hundreds of kernels, each kernel runs in tens of microseconds, and the GPU spends measurable time idle waiting for the next launch. CUDA graphs record the whole launch sequence once and replay it as a single submission, collapsing the cumulative dispatch overhead into a near-constant cost per step.

This deep dive walks through the source of the overhead, why decode hits it hardest, what CUDA graphs actually capture, and the production wrinkles (shape bucketing, memory cost, and the regimes where the optimization stops paying).

Where the overhead comes from

When the host CPU calls a kernel launch (e.g. via a CUDA runtime API or a PyTorch op), several things have to happen. The runtime builds a launch packet: which kernel binary to invoke, which arguments (including pointers, scalars, shapes), which grid and block dimensions, which stream. It checks for any pending dependencies. It enqueues the packet through the driver, which may involve a system call or shared-memory write to the kernel-launch ring buffer. Eventually the GPU's host interface reads the packet, validates it, and schedules the kernel on a streaming multiprocessor.

Most of this is fast in isolation, but the cumulative latency from the moment user code calls cudaLaunchKernel to the moment the GPU starts executing is roughly 10-30 microseconds on a typical system. Higher under host CPU pressure, with PCIe-attached devices, or with profiler hooks; lower with NVLink-attached devices and a quiet CPU.

For compute-bound workloads with long kernels (e.g. prefill on a large model, training step at large batch), this is invisible. The kernel itself runs for milliseconds, and a 20-microsecond dispatch is a rounding error.

For bandwidth-bound workloads with short kernels (decode at small batch), this is the dominant cost. A typical decode step on a 70B model launches hundreds of kernels across layer norms, qkv projections, attention forward, output projection, MLP layers, residuals, and sampling. At 10-30 us each, the cumulative dispatch can be several milliseconds per token, often larger than the GPU's actual time on task at small batch.

The observable signature in a profiler is gaps between adjacent kernels on the GPU timeline: the GPU finishes one kernel, sits idle for tens of microseconds, then starts the next. A continuous, gap-free GPU timeline indicates you are either compute-bound (kernels are long enough to overlap dispatch) or already using CUDA graphs.

What a CUDA graph captures
Why decode at small batch wins biggest
The shape-variability problem and how serving handles it
Memory and capture cost
Sign in to unlock the full deep dive.

Situations where this technique stops working.

Sign in to see when this approach fails.

2–4 min · Everything important, quickly.

Sign in to see the quick scan of the deep dive.
RegimePer-step time without graphsPer-step time with graphsWin
Small batch (1-4) on 7B-13B model~3-8 ms (mostly dispatch)~1.5-4 ms1.5-2x
Small batch on 70B model~25-30 ms (dispatch is ~10-20% of step)~22-26 ms1.1-1.3x
Large batch (32-64) on 70B~50-60 ms (dispatch <5%)~48-58 ms<1.05x
Variable-shape continuous batchingPer-step recapture costPer-bucket graphs + paddingDepends on bucket coverage

Real products, models, and research that use this idea.

  • vLLM captures CUDA graphs per (batch_size, max_seq_len) bucket and routes each scheduling step to the nearest bucket via padding.
  • TensorRT-LLM's runtime ships explicit CUDA-graph capture for decode with shape buckets defined at engine build time.
Sign in to see more production examples.

What an interviewer would ask next. Try answering before peeking at the approach.

QHow does CUDA graph replay differ from compiler-level kernel fusion?
A

Fusion reduces the number of kernels by merging adjacent ones into one larger kernel, so total launches drop. CUDA graphs keep the same kernels but eliminate the per-launch CPU overhead between them. The two compose: fuse what you can to reduce kernel count, then graph-capture what remains to eliminate the dispatch between them.

2 more follow-ups an interviewer would ask next. Sign in to reveal them.

Red flags & common mistakes

The phrases that signal junior thinking. Click to expand.

Most common mistake

Thinking CUDA graphs make the GPU work faster. The kernels themselves run at the same speed; CUDA graphs only remove the CPU-side dispatch overhead between them. The win comes from eliminating idle gaps, not from accelerating compute.

Sign in to see all red flags and common mistakes.

60 second bullets to scan on the way to the call.

  • Why kernel launch has a CPU-side cost (~10-30 us per launch)

  • Why decode at small batch is dominated by launch overhead

Sign in to unlock the revision sheet.

Primary sources. Browse if you want the original framing.

Similar questions

Same topic, related formats. Practice these next.

4 curated
Next question
What is the KV cache in transformer inference?
Flashcard·Easy