A KV block table maps logical token ranges to a managed device pool
Translate token positions into block slots, quantify tail slack, and distinguish application-managed KV paging from operating-system pages or automatic host swapping.
On this page
The question for today
What you’ll understand
- Calculate logical block and offset for a token index.
- Count fixed-size KV blocks and final-block slack for a request.
- Explain pool, table, and kernel responsibilities without equating them to OS demand paging.
A growing request need not own one physically contiguous region large enough for its eventual output. A serving runtime can divide its KV state into fixed-token blocks and provide attention kernels with a table mapping each logical block to physical storage. This indirection makes allocation and sharing more flexible, but the table is part of a specialized runtime contract. It does not mean the operating system will automatically swap attention state to host memory whenever a request exceeds the device's available capacity.
Separate logical order from physical placement
Let a block hold a fixed number of token positions across the relevant cache layout. A token's zero-based logical index determines a block number and an offset within that block. A per-request table then supplies the corresponding physical pool identifier, so consecutive logical blocks can live far apart in the device pool. Attention kernels must follow this mapping while preserving the original sequence order and valid token lengths. Reordering physical addresses does not permit changing causal positions or interpreting uninitialized tail slots as real cached tokens.
The original PagedAttention work applies the analogy of virtual-memory pages to application-managed attention storage. The analogy explains indirection, fixed allocation units, and sharing; it is not an identity between GPU KV blocks and OS virtual pages. A KV block can span many hardware pages and tensors, and its token capacity is a serving configuration choice. Host offload, device transfer, and preemption need explicit mechanisms. The kernel and scheduler must agree on block-table representation, head layout, dtype, and lifetime for the indirection to be correct.
Fixed blocks remove one fragmentation problem, not every overhead
With interchangeable equal-size blocks, a request can use any available pool entries without requiring one large contiguous region inside that pool. Its final block may still have unused token slots, and block tables, reference counts, hashes, alignment, and per-layer layouts consume additional memory. An allocator can reserve a large device tensor for the pool even while many application blocks are idle, so framework allocated bytes can remain high after request completion. Measure pool occupancy separately from the amount of device memory reserved to hold the entire pool.
A smaller block reduces worst-case tail waste but increases table entries and may make transfers or kernel access less efficient. A larger block can reduce metadata overhead while wasting more space for many short requests. The best size depends on measured sequence lengths and kernel behavior rather than a universal percentage rule. Cached full prefixes can also leave zero-reference blocks holding reusable content until reclaimed. Such blocks occupy physical pool slots, yet their contents may be evictable; distinguish them from actively referenced blocks when counting admission headroom.
Allocation and reclamation must preserve table validity
Allocate a new pool block before publishing a table entry that kernels can use, initialize the required state, and retain ownership until outstanding accesses finish. A stale table entry after a physical block has been recycled can silently read another request's KV values rather than produce a clean allocation error. Coordinate table updates, launches, completion events, and cleanup so reclamation occurs at a safe boundary. The vLLM 0.9.1 prefix-cache design distinguishes the block pool, free queue, cached-block mapping, and per-request block lists; those roles illustrate why free and unreferenced are operational states with explicit transitions.
The cache lab only models a bounded pool of reusable identities. Reset, explicitly set BOTH capacity C=4 and stride s=4, predict twelve hits among sixteen requests at t=0, then Play or Step. Reset and re-set BOTH C=3 and s=4; predict zero hits. Playback uses N=min(4096,16+floor(2t)); edits retain t and recompute from empty. There are no token positions, block tables, device addresses, live-reference pins, or kernel completion events. Its equal-size entries illustrate a capacity boundary without implementing safe KV allocation or OS paging.
Work it through
Map one position and count the request's tail slack
A fictional request retains thirty-five tokens in blocks of sixteen token slots. Its logical block table is [7,2,9]. Map zero-based token index thirty-four, then calculate allocated slots and slack; ignore metadata and sharing.
Logical block is floor(34/16)=2 and offset is 34 mod16=2. The table maps logical block two to physical pool block nine.
The request needs ceil(35/16)=3 blocks, providing 3×16=48 token slots. Only thirty-five represent valid retained positions.
Slack is 48−35=13 token slots in the final block. At 128 KiB per token slot in this hypothetical layout, capacity is six MiB, with 1.625 MiB of slack; physical IDs do not change those counts.
Indirection preserves logical order across noncontiguous blocks, while the final block still has measurable internal slack.
The living notebook
Explore the model
Interactive lab · cache
Equal-size entries provide a limited pool analogy
For EACH run Reset, set BOTH C and s, predict, then Play or Step. At t=0/N=16, (4,4) gives twelve hits and (3,4) gives zero. N=min(4096,16+floor(2t)); edits retain t/recompute from empty. No KV block table, token offset, live pin, device allocation, or host paging is implemented.
- Hits / requests
- 0 / 16
- Hit rate
- 0%
- Address-stream period
- 16 addresses
A fully associative LRU cache starts empty and requests address (i·s) mod 16. Hits move an address to the newest position; misses evict the oldest when full. Playback starts with 16 requests and adds two per second, capped at 4096 explicitly simulated requests. This toy stream is not a processor-cache benchmark. 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 forA block pool's capacity and mapping contract must be understood separately from OS memory management.
Pause & reason
Check your understanding
Your turn
Try it yourself
For positive length T=65 and block size B=16, calculate block count and slack. Map zero-based position sixty-four to its logical block and slot. What remains unknown without the block table?
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Use ceiling division for capacity and floor/remainder for the position.
Compare with the solution
Five blocks provide eighty slots, so slack is 80−65=15. Position sixty-four is in logical block four at offset zero. The physical block identifier and layout-specific byte address remain unknown until the table and tensor layout are supplied.
Keep the idea
Take it with you
- Block tables preserve logical sequence order over noncontiguous physical KV storage.
- Equal-size blocks avoid contiguous-allocation requirements inside the pool but retain tail slack and metadata.
- Allocation and recycling need safe ownership and kernel-completion boundaries.
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.