AI engineering and inferenceLoading progress…

Copy-on-write

Allocate logical token blocks to physical KV-cache blocks and quantify internal waste and shared-prefix behavior.

Copy-on-write

Shared blocks are read-only in spirit. But sequences that share a prefix eventually diverge: one appends a token into a block that another sequence also uses. Writing in place would change the other's cache. Copy-on-write fixes this: each block has a reference count; if the block to be written has a count above 1, the writer takes a new block, copies the contents, lowers the old block's count and points its own table at the copy.

#0A ×1
#1A ×1
#2free
#3free
#4free
#5free
#6free
#7free
#8free
#9free
sequencetokensblock table (logical → physical)
A20[0, 1]
free blocks: 8 of 10 in use: 2 (×n = reference count, striped = shared)
A allocated with 20 tokens

Editing a shared block in place would change the other sequence's cached state too. So the writer gets a private copy first; the reference count of the old block drops by one.

Press fork B, then B appends a token. Watch block 1 split into two blocks.

Predict first. Why avoid editing a block used by another sequence in place?

Chapter context

Contiguous reservation can waste memory when sequence lengths differ or grow unpredictably. Paging separates a sequence's logical block order from the physical blocks storing its cache.

Chapter reference: math, worked example & code

This section belongs to the whole chapter, so it is the same on every lesson in it and may cover a different lesson's topic. The code for the experiment you just ran is inside the experiment itself.

Math and notation

For length T and block capacity P:

nblocks=⌈T/P⌉,slots=P⌈T/P⌉,slack=slots−T.n_{blocks}=\lceil T/P\rceil,\quad slots=P\lceil T/P\rceil,\quad slack=slots-T.

Slack as a fraction of allocated slots is slack/slots. State the denominator when reporting waste percentages.

Worked example

A sequence has 33 tokens and blocks hold 16. It requires ceil(33/16)=3 blocks, allocating 48 token slots. Fifteen slots are unused, so internal slack is 15/48=31.25% of this allocation. It is not 31.25% of all GPU memory, and shared blocks change total ownership accounting.

Reference code

The following example uses the Python standard library and does not call a remote service.

from math import ceil,isclose
tokens,capacity=33,16
blocks=ceil(tokens/capacity)
slots=blocks*capacity
assert blocks == 3 and slots == 48
assert slots-tokens == 15
assert isclose((slots-tokens)/slots,.3125)

Python examples are provided for study and local execution; this page does not execute Python.

Common mistakes

Paging improves allocation flexibility but does not make memory unlimited. Logical block order differs from physical layout. Internal slack and external fragmentation are different kinds of waste.