advanced28 min studyLesson 704 in Engineering

Diverging generation branches copy the shared writable tail

Track partial-tail ownership through parallel generation, distinguish immutable full-prefix sharing from copy-on-write, and release pruned branches after outstanding accesses finish.

On this page

What you’ll understand

  • Explain why appending into a shared partial block requires private ownership.
  • Calculate physical blocks and copies for several diverging branches.
  • Distinguish original-paper copy-on-write behavior from version-specific prefix-cache implementations.

Generation branches can share the state of their common prompt, but they must not overwrite each other's later tokens. A partially filled final block is especially subtle: appending a token changes storage inside an allocation that may still be referenced by several branches. Copy-on-write gives the writer a private version while keeping old state valid for the other readers. The operation is about storage ownership, not about whether two branches are expected to choose different next words.

A full immutable prefix and a writable tail have different lifetimes

Suppose several branches begin from a prompt with full prefix blocks and one partial tail. The full blocks need no changes during append-only generation and can stay shared. The partial tail has unused slots, but those slots belong to a shared allocation whose logical contents will diverge as branches append. A branch must first obtain exclusive write ownership of that tail, usually by allocating a new block and copying the valid existing state. Empty tail capacity is not permission to mutate an allocation still visible through another branch's table.

The original PagedAttention paper describes block-granularity copy-on-write for parallel sampling and beam search. Do not confuse that mechanism with every later engine's prefix-cache policy: the separately cited vLLM 0.9.1 V1 prefix cache admits full blocks and documents append-only block tables with possible temporary duplicate full blocks. A lesson about the original branch-sharing design is not a promise that any particular V1 API exposes the same branching operation. Check the engine version, decoding support, and ownership implementation before using the accounting as an operational plan.

rb>1 ∧ write⁡(b)⟹private_copy⁡(b) before mutationr_b>1\ \land\ \operatorname{write}(b)\quad\Longrightarrow\quad\operatorname{private\_copy}(b)\ \text{before mutation}
This is a simplified ownership rule for a shared writable tail in the described copy-on-write design. r_b counts active owners of block b and all outstanding device accesses must be protected. A cache policy with additional immutable holds can require copying even when only one request remains; the rule is not a universal API guarantee.↔ Scroll wide equations horizontally.

Copies separate ownership without duplicating the whole prompt

For several branches sharing one partial tail, the first writer copies it and drops its reference to the original. Other writers repeat that process while the original remains multiply owned. When only one writer owns the original and no other hold forbids mutation, that writer can append in place. Allocate and complete the copy before publishing the writer's new table mapping to its mutation kernel. A data race or premature reference decrement can produce plausible but incorrect generated output instead of an obvious crash.

After each branch has private tail storage, later appends within that tail require no additional copy merely because the prompt was once shared. Crossing a block boundary allocates a new private block. Beam pruning or cancellation drops the abandoned branch's references; it does not invalidate shared blocks still used by surviving branches. Speculative execution adds temporary branch states that need the same ownership discipline when proposals are accepted or rolled back. Count transient copies and completion delays when reserving memory rather than budgeting only the final steady-state block graph.

Nshared=F+n,Ncopied=n(F+1),Δ=(n−1)FN_{\rm shared}=F+n,\qquad N_{\rm copied}=n(F+1),\qquad \Delta=(n-1)F
Assume n positive branches share F full immutable blocks plus one partial tail, every branch appends within its tail, no additional holds exist, and each ends with one private tail. Counts are physical blocks, excluding transient copies, metadata, and later growth. Delta is the saving compared with duplicating the entire prompt per branch.↔ Scroll wide equations horizontally.

Validate branch isolation as well as memory savings

Construct small deterministic tests in the actual engine: branch from a known prefix, force different continuations, cancel one branch, and compare surviving state with an independently recomputed reference. Inspect table mappings and ownership transitions around the tail boundary and copy completion. Memory savings alone cannot reveal a shared-tail corruption bug. Test cases should include exactly full prompts, one-slot tails, several simultaneous writers, and pruning while kernels are in flight. The number of logical branches is not itself the number of full prompt copies that must physically exist.

The cache lab provides only a private-working-set capacity analogy. Reset, explicitly set BOTH C=4 and s=2, predict zero hits in the initial sixteen requests, then Play or Step. Reset and re-set BOTH C=8 and s=2; predict eight hits because the cyclic working set has eight identities. N=min(4096,16+floor(2t)); edits retain t and recompute from empty. This model has no branches, aliases, copy-on-write, or asynchronous completion. It illustrates why additional distinct state can exceed a pool's capacity, while the branch and copy counts must come from the explicit example.

Fork a ten-token prompt into three writable branches

A prompt has ten retained tokens in four-token blocks: two full blocks and one partial tail. Three branches initially share all three blocks and each appends within its tail. Assume block copies copy one full allocated block of one MiB and no other holds exist.

  1. Initially there are three physical blocks and each has reference count three. The first writer copies the tail, reducing the original tail's count to two; the second does likewise, leaving count one.

  2. The final owner appends to the original tail in place after safe synchronization. Final storage is two shared full blocks plus three private tails, or five blocks, versus 3×3=9 without prompt sharing.

  3. Two tail copies duplicate two MiB of payload in this specified layout. Measure their reads, writes, and any temporary allocations separately when accounting for traffic and peak memory; the four-block steady-state saving alone does not describe those costs.

The result

Copy-on-write duplicates only the writable shared tail under these assumptions, preserving both prompt sharing and branch isolation.

Explore the model

Interactive lab

Interactive lab · cache

More distinct state can exceed the same fixed pool

For EACH run Reset, set BOTH C and s, predict, then Play or Step. With s=2, initial N=16 gives zero hits at C=4 and eight at C=8. N=min(4096,16+floor(2t)); edits retain t/recompute from empty. This deterministic LRU trace does not simulate branches, aliases, copies, refcounts, or GPU synchronization.

More distinct state can exceed the same fixed poolA 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. Current readings: Hits / requests: 0 / 16; Hit rate: 0%; Address-stream period: 16 addresses. All parameters are adjustable with the labeled controls below.Fully associative LRU cache after 16 deterministic requests: 0 hits and 16 misses.Most recent 16 requestsaddress = i × 3 mod 160M3M6M9M12M15M2M5M8M11M14M1M4M7M10M13MCurrent cache order · oldest → newest471013Latest address 13 · miss: inserted as newestToy address stream · period 16 · starts empty
Cached addressMiss / evictionMost recent request
Hits / requests
0 / 16
Hit rate
0%
Address-stream period
16 addresses
t = 0 s

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 forUse explicit ownership accounting for branching; a generic cache trace can illustrate capacity but cannot verify copy-on-write correctness.

Check your understanding

Three branches share a partially filled tail block, and one branch is about to append into it. What must happen in the described copy-on-write design?

Try it yourself

Four branches share three full blocks and one partial tail. Each needs one private tail after append, with no additional holds or growth. Calculate final shared-design blocks, unshared blocks, saved blocks, and tail copies if the last original owner writes in place.

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 F+n and n(F+1); only n−1 writers need a new tail copy.

Compare with the solution

The shared design uses 3+4=7 blocks versus 4×4=16 unshared, saving nine blocks. Three tail copies suffice because the last owner can use the original exclusively after synchronization. Additional cache holds or transient copies would change the operational budget.

Take it with you

  • A shared partial tail needs private ownership before branch-specific mutation.
  • Full-prefix sharing can persist while only writable tails are copied.
  • Version-specific support, transient memory, and asynchronous lifetimes matter as much as steady-state block counts.

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.