Chris Collins

Tools · ai

Attention and the KV cache, visually

How an LLM's KV cache works and what it costs — one decode step ("read five, compute one") and O(N²) vs O(N) work, MHA/GQA/MQA/MLA head sharing with the live cache size in decimal and binary units, a PagedAttention allocator simulation, FlashAttention's tiles and online softmax with HBM traffic, and long-context cache size, compression and attention FLOPs.

Added

How to use it

Five tabs follow the KV-cache section of AI Acceleration from one decode step up to a million-token context. Every setting can go in a link, and each worked example in the book has a preset (see Linking to an example).

Decode step

One layer generating token n + 1 with n tokens already in context. With a cache the step projects one new Query, Key and Value, reads the n cached Key/Value pairs, scores the Query against all n + 1 Keys, and appends the new pair. That is "read five, compute one" when n = 5. Switch to Without a cache and every Key and Value is projected again, n of them for nothing. Step through with ◀ ▶ or Play.

The chart adds this up over a whole generation of N tokens. Without a cache the K/V projections total 1 + 2 + … + N = N(N+1)/2, which is O(N²). With one they total N. The table gives the ratio, (N+1)/2. The cache does not remove the quadratic attention: step i still reads i − 1 cached pairs. That is why decode is limited by memory bandwidth.

Head sharing

Pick a model and an attention layout. The diagram shows which query heads share which K/V heads, and the cache size updates as you change things:

  • MHA: one K/V head per query head (64 on Llama-70B).

  • GQA: groups of query heads share a K/V head. Llama 3 70B uses 8, and a slider varies the count.

  • MQA: a single K/V head per layer.

  • MLA: DeepSeek’s multi-head latent attention caches a 576-value latent per layer (512 + 64 for RoPE) and rebuilds K and V from it.

Bytes per token = 2 × layers × KV heads × head dimension × bytes per value (MLA: layers × latent × bytes). For Llama 3 70B in FP16 that is 2 × 80 × 8 × 128 × 2 = 327,680 bytes = 320 KiB = 0.3125 MiB ≈ 0.328 MB. At 8,192 tokens that is 2.68 GB (2.5 GiB), and at 131,072 tokens 42.9 GB (40 GiB). Full MHA would be 8 times larger.

Every size is shown in both units. Decimal units: kB, MB, GB, TB = 103, 106, 109, 1012 bytes. Binary units: KiB, MiB, GiB, TiB = 210, 220, 230, 240 bytes. The book’s "0.31 MB per token", "2.5 GB" and "40 GB" are binary figures (MiB, GiB) labelled as MB and GB. Exactly 8,000 and 128,000 tokens give 2.62 GB and 41.9 GB.

PagedAttention

The same workload runs through two allocators over the same pool of KV-cache slots, shown side by side:

  • Naive: each request reserves one contiguous run of slots for its maximum length (4,000 by default) from the moment it is admitted.

  • Paged: the pool is cut into fixed-size blocks (16 tokens by default), and a request takes a new block only when its last one is full. Each request has a block table that maps its logical blocks to whichever physical blocks were free.

Each cell is one block. Strong colour means stored tokens, pale colour means reserved but empty. The table counts running and waiting requests, slots held against slots actually written, the waste, and how many decode steps it takes to finish everything. A shared prefix, such as a common system prompt, is stored once in purple blocks that every block table points at. Copying prefixes is what vLLM’s automatic prefix caching and SGLang’s RadixAttention avoid. When the paged pool runs out, the newest request is preempted and recomputed later, as vLLM does.

FlashAttention

A toy attention head (N tokens, head dimension d, random Q, K and V from a seed) worked tile by tile in FlashAttention-2 order. The outer loop runs over blocks of Br query rows, and the inner loop over blocks of Bc key/value columns. The score-matrix picture shows the tile currently in on-chip SRAM. Earlier tiles have been folded into the result and thrown away; none of them is ever written to HBM.

The table traces one query row through the online softmax. Each row keeps a running maximum m, a running sum ℓ and an unnormalised output O. When a block raises the maximum, the sums so far are multiplied by e^(m_old − m_new)^. After the last block the result matches standard attention, apart from about 10−16 of rounding difference.

The second panel compares HBM traffic for one head at real size. Unfused standard attention moves 4Nd + 4N² elements: it writes the score matrix, reads it back, writes the probabilities and reads them again. FlashAttention-2 moves 2Nd + 2Nd·⌈N/Br⌉ + N. Both are still quadratic in N; the paper’s bound is Θ(N²d²/M). FlashAttention’s traffic is smaller by about 2·Br/d, and the extra memory falls from N² to N.

Long context

KV-cache size from 1,000 to 10 million tokens on a log–log chart, against the memory of one GPU, an 8-GPU node and an NVL72 rack (≈13.5 TB). The compression options stack:

  • Eviction: SnapKV keeps about 50%, H2O keeps 20%, and StreamingLLM keeps 4 "sink" tokens plus a 4,092-token window.

  • Cache precision: FP8 or INT8 halves the cache, and INT4 quarters it.

  • CacheGen encoding divides it by about 4 for storage and transfer.

The tool reports whether the cache fits in the memory you chose beside the weights, how many such sequences fit, and how long one decode step takes to read the cache.

Prefill attention costs 4N²d FLOPs per layer per head: 2N²d for QKᵀ and 2N²d for PV, or half that with a causal mask. At 1M tokens and d = 128 this is 5.1 × 1014. The tool also gives the whole-model total, the context length at which attention FLOPs overtake the 2 × parameters × N of the weight matmuls (about 54,000 tokens for Llama 3 70B), and the time at the target’s dense peak.

The memory and throughput figures are in one table on the tab, with a vendor source for each row, as of October 2026. Throughput is dense BF16; NVIDIA’s headline numbers assume 2:4 sparsity and are twice as high.

Limits

  • All figures are first-principles estimates. Real servers need memory for activations, CUDA context and fragmentation, and real kernels reach only part of peak.

  • The paged simulation uses one request per batch slot, one token per step, and prefill in zero time. It preempts by recomputation and does not swap to CPU memory, and it shares only the full blocks of a prefix (the partial last block is copied).

  • The compression factors are the papers' headline figures. How much quality survives depends on the model and the task.

  • INT4 is counted as exactly half a byte, ignoring group scales. See the floating-point inspector for what block scales cost.

Related: softmax and attention (the attention equation as a heat map), AI hardware calculator (weights plus cache against GPU memory, the roofline, decode speed and cost), floating-point inspector (FP8, INT4 and block-scaled formats).

Companion to the KV cache, FlashAttention and PagedAttention section (Part III), Attention and the transformer, mapped to hardware (Part IX), the 70B worked example (Part IV) and Long-context inference of _AI Acceleration: From Transistors to Trillion-Parameter Models.

Sources

Linking to an example

Links can be written by hand: /tools/attention-kv/?<parameters>#<tab>, where the tab is decode, heads, paged, flash or long. An example= link with no #tab opens on that example’s tab. Share link builds a link from whatever is on screen. Token counts in ctx, N and seq accept 131072, 128k (= 128,000) and 1M (= 1,000,000). A context window called "128K" is usually 131,072 tokens, so write that number when you mean it. No parameter needs a `. In a link a ` means a space, but the token fields ignore spaces, so N=1e+6 still reads as 1,000,000.

Parameter Meaning Example

example

a book preset (below); other parameters in the same link override it

p04-kv-8k

model

llama3-70b, llama3-8b, llama31-405b, mistral-7b, deepseek-v3 or custom

llama3-70b

attn

attention layout: mha, gqa, mqa, mla

mha

kvh

K/V heads for GQA

8

fmt

cache format: fp16, fp8, int8, int4

fp8

L, qh, hd, lat, params

custom model: layers, query heads, head dimension, MLA latent per layer, parameters (billions)

L=32&qh=32&hd=128

ctx

context tokens on Head sharing

131072

batch

sequences on Head sharing

16

step

tokens already generated (Decode step), 1–60

5

cache

with a KV cache (1) or without (0)

0

gen

generation length N for the cumulative chart

1000

reqs, out, prompt, var

PagedAttention workload: requests, mean output and prompt tokens, ±% spread

reqs=1&out=60

shared

shared-prefix tokens

512

max

naive reservation per request (tokens)

4000

blk

block size (tokens)

16

pool

KV pool size (token slots)

16384

seed

workload seed

2

t

time (decode steps) shown

60

fn, fd, br, bc

FlashAttention toy: tokens, head dim, query-block rows, key-block columns

fn=16&br=4&bc=4

row

traced query row (0-based)

1

fs

tile step shown (0-based)

3

fseed

toy data seed

3

seq, tile, extra

real-size traffic: sequence length, query-block rows Br, extra N² passes

seq=32k

N

context tokens on Long context

1M

evict

none, snapkv, h2o, streaming

h2o

cg

CacheGen encoding on (1)

1

mem

memory target: h100, h200, b200, mi300x, hgx8, dgxb200, nvl72, gb300

nvl72

w

copies of the FP16 weights in that memory (0 = cache only)

1

causal

causal prefill FLOPs (1)

1

Presets for example=:

Name Tab Shows

p03-read-five

decode

Token 6: one new Q/K/V, five cached K/V pairs read, six dot products (open)

p03-no-cache

decode

The same step without a cache: all six K/V projections redone (open)

p03-token-50

decode

Token 50 without a cache redoes 49 projections; 1,275 over 50 tokens instead of 50 (open)

p03-cumulative

decode

Cumulative K/V projections over 1,000 tokens: 500,500 without a cache, 1,000 with (open)

p03-gqa

heads

Llama-70B with GQA: 327,680 B (0.3125 MiB) per token, 2.68 GB (2.5 GiB) at 8K (open)

p03-mha-8x

heads

The same model with full MHA: 8×, 21.5 GB (20 GiB) at 8K (open)

p03-mqa

heads

MQA: 40,960 B per token (open)

p03-mla

heads

DeepSeek-V3 MLA: 70,272 B per token (open)

p04-kv-8k

heads

The 70B worked example at 8,192 tokens: 2.68 GB (2.5 GiB) (open)

p04-kv-128k

heads

The same at 131,072 tokens: 42.9 GB (40 GiB) (open)

p04-kv-8000

heads

The book’s 8,000-token conversation: 2.62 GB (2.44 GiB) (open)

p04-kv-128000

heads

The book’s 128,000-token context: 41.9 GB (39.1 GiB) (open)

p03-mha-8000

heads

Full MHA on that conversation: 21 GB (19.5 GiB), 8 times the GQA cache (open)

p13-reasoning-30k

heads

A 30,000-token chain of thought: 9.83 GB (9.16 GiB) (open)

p03-paged-60

paged

One 60-token request: naive reserves 4,000 slots, paged holds four 16-token blocks (open)

p03-paged-pool

paged

24 short requests: naive fits 4 at a time, paged fits all of them (open)

p03-shared-prefix

paged

A 512-token shared prefix stored once in 32 blocks (open)

p03-flash

flash

FlashAttention tiling of an 8-token toy (open)

p03-online-softmax

flash

The running max rises and earlier sums are rescaled (open)

p03-flash-traffic

flash

HBM traffic at 4K tokens: standard against FlashAttention (open)

lc-128k

long

128K context: 42.9 GB (40 GiB) against GPU, node and rack memory (open)

lc-1m

long

1M tokens: 328 GB (305 GiB); attention 5.1 × 1014 FLOPs per layer per head (open)

lc-10m

long

10M tokens: 3.28 TB of cache (open)

lc-h2o

long

H2O keeps 20%: 65.5 GB at 1M (open)

lc-snapkv

long

SnapKV keeps about 50%: 164 GB at 1M (open)

lc-cachegen

long

CacheGen’s ≈4× encoding: 81.9 GB at 1M (open)

lc-int4

long

INT4 cache: 81.9 GB at 1M (open)

lc-streaming

long

StreamingLLM: constant 1.34 GB at 4M tokens (open)

p15-rack-ceiling

long

8,192-token sequences that fit in an NVL72 rack beside the weights (open)

Runs entirely in your browser; nothing you type leaves this page.