Video generation infra: bottlenecks and trade-offs

LLM-serving intuitions fail one by one on video generation — batching, acceleration, quality and streaming.

LLM serving has built up a fairly mature set of intuitions: decode is bound by memory bandwidth, so batching adds throughput almost for free; speculative decoding speeds things up without changing the output distribution; the KV cache is the main consumer of memory; TTFT and TBT describe the user experience. Video generation inference looks like a similar problem — the same Transformers, the same questions of scheduling, parallelism and memory — yet these intuitions fail almost one by one.

This post records where and why they fail. Public material mostly covers the parts of papers that worked or vendors’ final designs; the ideas that look reasonable but do not work are rarely written down, and this post starts from exactly such a case: a batching attempt that gained nothing. The numbers here are of three kinds: estimates derived from public model configs, measurements on a single A100 (marked “Measured” in the figures), and a few personal observations. Each states its conditions, and none is a complete benchmark.

01Batching: arithmetic intensity sets the room for batching

The original idea was to bring over LLM-style continuous batching: even though most of a DiT is compute-bound, its memory-bound operations might still gain from batching, so requests would be co-batched at denoising-step boundaries. With a 5B model and long chunks, the profile showed compute was still the bottleneck, and co-batching did not bring the expected gain.

In hindsight, this follows directly from arithmetic intensity. For a linear layer over M tokens with hidden size d, the compute is 2Md² FLOPs and the bf16 traffic is about 2(2Md + d²) bytes:

\[I = \frac{2Md^2}{2(2Md + d^2)} = \frac{Md}{2M + d}\quad \text{FLOP/byte}\]
Workload Tokens per forward pass M Intensity I
LLM decode, batch 1 1 ≈ 1
LLM decode, batch 32 32 ≈ 31
Wan 1.3B, 480p, 81 frames, batch 1 32,760 ≈ 750
Same, batch 4 131,040 ≈ 763

The LLM rows use d = 4096 and the Wan rows d = 1536; the VAE compresses 81 frames into 21 latent frames of 1,560 tokens each. An H100 SXM has about 989 TFLOPS of dense bf16 compute and about 3.35 TB/s of HBM bandwidth, so its ridge point is about 295 FLOP/byte. Only linear layers are counted, not attention or elementwise ops.

In LLM decode, going from batch 1 to 32 raises intensity about 30×, still below the ridge point, so batching pays off almost linearly. A single video DiT request is already far above the ridge point; a larger batch only pushes I toward its ceiling of d/2 = 768. From batch 1 to 4, intensity rises by only about 2%.

DiT throughput under batchingMeasured · NVIDIA A100-SXM4-40GB
MeasuredLinear scaling
batch 1
×1.00
batch 2
×1.01
batch 4
×1.01
Video throughput relative to batch 1, DiT only (the VAE does not run). The dashed line marks throughput that grows linearly with batch size. NVIDIA A100-SXM4-40GB × 1 · Wan2.1-T2V-1.3B-Diffusers · 832×480, 81 frames · DiT bf16 / VAE float32 · diffusers 0.36.0; 8 steps, CFG 5.0 (2 forward passes per step); median of 3 runs.

A larger model does not change this. For Wan2.2 TI2V 5B at 720p and 121 frames (27,280 tokens per forward pass), batch 2 still gives 1.00× the DiT throughput of batch 1; from batch 3 on, the job no longer fits on a 40 GB A100 even with the text encoder moved off the GPU. Batching does not raise throughput, and it runs into the memory limit first.

Solving I < 295 for M gives M < 295d / (d − 590): about 480 tokens at d = 1536 and about 330 at d = 5120. Linear layers return to the memory-bound regime only when a forward pass has a few hundred tokens, as in low-resolution text-to-image or very short clips.

So why doesn’t “exploiting the memory-bound operations” work either? Elementwise ops such as norms, activations and RoPE are indeed bandwidth-bound, but their intensity does not depend on batch size: batching scales their reads, writes and compute by the same factor, so the ratio stays the same. This overhead is better handled by kernel fusion than by batching.

For this kind of workload, then, scheduling is less about filling batches and more about when a request starts, which machine it runs on and how many GPUs it gets. SlackServe adjusts GPU resources, step count and resolution together under SLO constraints; TetriServe, for text-to-image, adjusts each request’s sequence-parallel degree per step; GF-DiT studies elastic parallel allocation. All three tune how many GPUs to give and how to split the work, not how many requests to merge.

02Acceleration: first ask which term it changes

One generation requestSchematic · widths are not durations
Text encoderonce
DiT denoising repeated N steps
VAE decodeonce
↓ NFew-step distillation
↓ tstepSparsity / quantization / kernels
↑ GSP / communication trade-offs
Fewer steps, faster steps, more GPUs: each changes a different variable, so their speedups cannot simply be multiplied.
\[\begin{aligned} T(G) &\approx T_{\mathrm{other}}(G) + N\,t_{\mathrm{step}}(G) \\ C &= G\,T(G) \end{aligned}\]

N is the step count and G the number of GPUs; tstep includes communication that is not hidden, and Tother collects encoding, decoding and other overhead. C is the GPU-seconds a request occupies on G GPUs.

Under this decomposition, the common techniques rank roughly as step distillation ≫ sparse attention ≈ quantization > diffusion caching > VAE optimization. The ranking rests on which term each technique changes and where its ceiling lies, not on a particular measurement; it can shift with model, resolution and length. Kernel fusion does not fit neatly into this ranking: its gain depends mainly on how much the baseline already fuses.

Step distillation changes N. Methods such as DMD2 and rCM compress 20–50 steps to about 4, and distilled models usually no longer need CFG, which saves another half of the compute. Its costs are in quality and training, not in the inference system.

Sparse attention changes only the attention part of tstep, so its gain is bounded by Amdahl’s law. If attention takes a fraction p of a step’s compute and is itself sped up s times:

\[S_{\mathrm{step}} = \frac{1}{(1-p) + p/s} \;\le\; \frac{1}{1-p}\]

Estimated by FLOPs, p is about 0.7 for Wan 1.3B at 480p and 81 frames, so even if attention vanished entirely, a step would get at most about 3.4× faster. Attention compute grows with the square of the token count, so higher resolution and longer videos raise p, and the ceiling with it.

That p is a FLOPs estimate; measured by kernel time it is lower. The figure below was measured on an A100 (bf16, the FlashAttention kernel behind PyTorch SDPA, the default diffusers implementation): attention takes about 52%, which caps the per-step speedup at about 2.1×. Another 29% goes to elementwise ops such as norms, modulation and type conversions, whose FLOPs are negligible but whose time is not.

GPU time in a DiT stepMeasured · NVIDIA A100-SXM4-40GB
GEMMAttentionOther
19%52%29%
Share of GPU kernel time in a 2-step DiT run without CFG. Kernels are grouped by name; see results/profile_top.csv. NVIDIA A100-SXM4-40GB × 1 · Wan2.1-T2V-1.3B-Diffusers · 832×480, 81 frames · DiT bf16 / VAE float32 · diffusers 0.36.0.

The same measurement on Wan2.2 TI2V 5B (720p, 121 frames, d = 3072) puts attention at only about 39%, a per-step ceiling of about 1.6×: with a larger hidden size and fewer tokens, the linear layers take a larger share.

Quantization also acts on tstep. FP8 has twice the peak compute of bf16, which is the theoretical ceiling for linear layers; methods like SageAttention extend quantization to attention. The real gain depends on the kernel implementation and on how much accuracy loss is acceptable.

Diffusion caching skips part of the computation in similar adjacent steps. It relies on adjacent steps being similar; in few-step models each step changes more, so there is less to reuse and quality is harder to control.

Kernel fusion targets the elementwise ops inside each step. Their FLOPs are negligible, yet in the profile above they take about 29% of kernel time; fusing norms, modulation and type conversions into neighboring kernels directly shortens tstep. That share comes from the default diffusers implementation without torch.compile, though; in an inference framework that already fuses these ops, much less is left.

VAE optimization handles the overhead outside the steps. It is barely visible in a 50-step model, but the smaller N gets, the larger Tother’s share: after distillation, encoding, decoding and data movement can go from negligible to significant. A faster step does not mean an equally faster request, and lower latency does not mean fewer GPU-hours.

In the A100 measurement below, VAE decoding takes only about 3% of end-to-end time at 50 steps with CFG; running the same checkpoint for just 4 steps without CFG raises that to about 43% (float32 VAE, no tiling).

End-to-end time breakdownMeasured · NVIDIA A100-SXM4-40GB
Text encoderDiT denoisingVAE decodeOther
50 steps · CFG
97%
183.8 s
4 steps · no CFG
56%43%
12.8 s
Share of end-to-end time per stage, with the total on the right. The few-step setting reuses the same undistilled checkpoint to measure time only; its output is not usable. NVIDIA A100-SXM4-40GB × 1 · Wan2.1-T2V-1.3B-Diffusers · 832×480, 81 frames · DiT bf16 / VAE float32 · diffusers 0.36.0; median of 3 runs.

The VAE’s cost is not only time: activations in the decoder grow with resolution and frame count. At the 480p, 81-frame setting below, the float32 VAE decode already peaks about 6.7 GB above DiT denoising; with tiling it drops to about the DiT’s level, at the cost of decode time (not measured here).

Peak memory per stageMeasured · NVIDIA A100-SXM4-40GB
Text encoder
14.0 GB
DiT denoising
15.3 GB
VAE decode
22.0 GB
VAE decode (tiling)
15.6 GB
Peak torch.cuda.max_memory_allocated() within each stage, including the resident model weights (13.8 GB). NVIDIA A100-SXM4-40GB × 1 · Wan2.1-T2V-1.3B-Diffusers · 832×480, 81 frames · DiT bf16 / VAE float32 · diffusers 0.36.0.

There is one more multi-GPU reason the speedups do not multiply: sparse attention reduces compute, but if the full K/V is still sent, the compute time that Ring uses to hide communication shrinks as well. A single-GPU gain has to be re-estimated in the multi-GPU setting.

Try step count, GPU count and communication overheadOpen calculator

An analytical estimate for seeing trends; the defaults are not calibrated against measurements.

03Quality: a harder constraint than speed

In LLM inference, one of the most influential speedups is lossless: speculative decoding guarantees the output distribution does not change. In video generation, the speedups with large gains — distillation, sparsity, quantization, caching — are almost all lossy. Quality evaluation also lacks a cheap, reliable metric like accuracy, so every speedup carries an extra evaluation cost.

Parallelism can change the result too. Different sequence-parallel splits, reduction orders and attention backends give different floating-point results; denoising can amplify those initial differences, so multi-GPU and single-GPU outputs may not look the same. Where reproducibility or A/B comparison matters, check this beforehand.

Length is limited by the training distribution. A bidirectional model’s usable length is usually close to its training length; beyond that, repetition or structural collapse is common. Simply extending the sequence means extrapolating positional encodings, which the inference system cannot solve on its own.

Changing the inference pipeline is riskier than it looks. Injecting the previous segment’s K/V into a bidirectional model, or adding an extra fusion module, both seem to carry information across segments; in my own attempts, though, the first thing such changes brought was unstable image quality. Possible causes include misaligned positional encodings and a train–inference mismatch, which I have not yet isolated one by one. Getting information in does not mean the model uses it as intended.

By contrast, video models are very sensitive to text conditioning. Without retraining, fuller and more consistent text descriptions may help cross-segment consistency more than changing the inference pipeline. This is the choice I made after experimenting so far, not a general conclusion.

04AR: fast is not enough, it has to keep up with playback

Causal generators such as CausVid and Self Forcing let video be produced segment by segment. Serving metrics map onto LLM ones: the wait for the first segment resembles TTFT, and the gap between segments resembles TBT. The difference is the playback buffer: as long as the next segment finishes before the buffer runs out, the gap itself is invisible to the user. The same generation speed can feel completely different depending on the buffer margin.

Same finish time, different stall riskTiming schematic
NowNext chunk done
Stream A
Playable buffer
Stream B
Buffer
Waiting
The next segment finishes at the dashed line. Stream A's buffer covers this generation; stream B runs out of buffer first. Lengths only illustrate the relationship.

SlackServe organizes resource allocation around exactly this remaining playable time. Serving goals closer to the user experience are therefore time to the first segment, playback stalls and control responsiveness, plus how many streams can be served under these constraints.

Autoregression also brings the KV cache back to video generation. History KV directly consumes the memory budget that streams share; for bf16 standard multi-head attention:

\[M_{\mathrm{KV}} = 4 L d\,n_{\mathrm{history}}\quad\text{bytes}\]
History KV per streamCapacity estimate · GB
1 frame
0.29
4 frames
1.15
16 frames
4.60
Frames are latent frames. Uses the dimensions of Wan2.1 1.3B: L = 30, d = 1536, and 1,560 tokens per frame at 480 × 832. This estimates only the KV of a same-sized AR model, excluding weights and activations, and does not imply that this bidirectional checkpoint natively supports a history cache.

Most current AR video models attend only within a local window; LongLive also keeps the first frame as a sink, the same idea as StreamingLLM. The window itself is the simplest form of KV compression: it caps each stream’s memory, at the cost of forgetting whatever falls outside it.

Since 2026, finer-grained KV compression has appeared on the generation side: Quant VideoGen quantizes the KV to 2 bits, and DensityKV and FrameFold select or merge history KV under a fixed budget. Video understanding started earlier: work such as InfiniPot-V compresses the KV of visual tokens in streaming video QA.

The two problems are not the same. On the understanding side, compression saves memory; the KV is only read by the question, and tokens can be selected based on it. On the generation side, the window already bounds memory, so compression is more about remembering a longer history within the same budget; and every compression error is reused as a condition for all later chunks and all denoising steps, where it may accumulate into drift segment after segment. Importance-based selection heuristics from the understanding side may therefore not carry over directly.

History length, the number of streams that fit and generation quality need to be weighed as one serving problem. This is one of the directions I consider most worth investing in.

05Frameworks: parallel libraries and serving systems

The following is based on the open-source code as of late October 2026. These projects move quickly, and details may have changed.

Given Section 01, the value of batching and step-level scheduling in these two serving frameworks may lie mostly outside video throughput: image and low-resolution requests are still in the range where batching works; step-level execution gives a hook for preemption, interleaving and resource adjustment; and a unified request interface makes it easier to share infrastructure with LLM serving. For high-resolution video requests, batching itself is most likely not where the gains come from.

06Directions worth watching

Not every direction leaves room for infra, but the following ones change the problems an inference system has to solve:

Looking back, video generation inference shares many components with LLM inference, but the bottleneck sits elsewhere: in compute, not bandwidth; in resource allocation, not batching; in quality constraints, not lossless speedups. Before carrying an LLM serving method over, first check that the assumption it relies on still holds.

October 2026. Personal observations are limited to the stated settings; quality comparisons are still to come. Schematics, intensities and capacities are estimates from public configs; figures marked "Measured" come from a single A100, with the setup in each caption.