Repository navigation
Selene: store only what a request may resume, once, and use VRAM for snapshots - #168
Merged
Merged
Conversation
yatesdr
force-pushed
the
selene-tiering
branch
from
November 2, 2026 17:30
a499cb9 to
a0adb62
Compare
Every host record kept its row (the resume state at that exact point),
so DRAM and disk held one row per checkpoint for as long as the record
lived. A growing conversation only resumes at its tip, at branch points
and at roots, so the rows of interior records were dead weight: on a
single long agent conversation rows were 93% of the bytes copied.
A non-root record whose row is redundant (exactly one committed child in
that tier) now drops its row and keeps its pages as soon as the child is
ready, in standalone memory, in the composite tier and on disk (a cheap
truncate of the row segment; a record spilled after its child exists is
written without its row). Leaves, branch points and roots keep their
rows. The rule lives in one predicate (Index::row_redundant). Removal
waits while anything still reads the row (restores, pool exports,
announcement hashing, retirement, spill writes, disk pins). Lookup
matches row-less records only as page carriers, so a restore never uses
a missing row; a later fork or rewind resumes at the nearest record with
a row and prefills the rest. A row dropped before announcement hashing
finished is no longer announced as present. A failed truncate submission
is counted and does not stop polling. A thinned DRAM point that cannot
regain its row reports Retry(Slabs). Recovery drops page-only records
with no children, which can only appear after a crash or a drain timeout
(memory-only children are lost then, as documented for local mode).
Metric: flare_host_cache_rows_thinned_total{tier}.
Validation: upstream CI's Linux commands: selene with test-support 381
passed, selene-manager all passed, helios (runtime-package,server) the same 1181 passed / 7 failed as main (main's DeepSeek tokenizer-fixture defect); new tests cover chain thinning in
memory, composite and disk, branches, forks and rewinds restored through
disk, deferral during spills and reads, recovery of straight chains and
crash shapes, pool export of thinned records and disk re-announcement.
Two existing tests' slot/call counts changed for the earlier row release
(explained in the tests). Independent review: no must-fix findings.
Design-Signed-Off-By: yatesdr; design-review=1c01
Every rank's share of each host record was stored separately, although
for layouts that replicate their cache across tensor-parallel ranks the
shares are byte-identical: on DeepSeek V4.1 TP4, 75% of host bytes were
duplicates.
At copy-out Selene now decides per record, separately for its pages and
its row, whether every local rank's share holds identical data (a memcmp
of the unpadded plane and row bytes, never padding, then one hash of the
stored share). If so, one share is stored and the record header (version
2) marks pages and/or row as replicated; restore copies the one share to
every local rank, verifying its checksum first. Otherwise the record is
stored per rank exactly as before. The DRAM decision is carried to disk;
only the disk-only path detects, from the first window, and a later
window that differs abandons that one store (counted, never a partial
file). Version-1 records still recover. Layouts without replicated data
(TP1, head-sharded caches) are unaffected. Pool publications and
memory-only split pools stay per rank. An older binary treats version-2
files as invalid and removes them.
Metrics: flare_host_cache_packed_records_total{tier},
flare_host_cache_per_rank_records_total{tier},
flare_host_cache_abandoned_stores_total.
Also tightens row thinning from the previous change: a row whose
truncate submission fails is no longer counted as thinned or as a
dropped record and stays usable. Pool announcement refuses packed
records explicitly instead of relying on call order.
Validation: upstream CI's Linux commands: selene with test-support 389
passed, selene-manager all passed, helios the same 1182 passed / 7
failed as main (main's DeepSeek tokenizer-fixture defect). Tests cover
identical, mixed and differing shares, non-4 KiB plane sizes with reused
slots, DRAM packing, promote and restore, multi-window disk-only spills
in any order, abandoned stores, restart recovery including a version-1
file written by the previous code, T1 row thinning on compact records,
and checksum failures. Two independent reviews; no open findings.
Not yet run: GPU restore oracle, long-run packed fraction, and timing of
the packing on the memory thread.
Design-Signed-Off-By: yatesdr; design-review=1c01
Every published checkpoint was copied to the host store at publish time. On a growing conversation about four checkpoints are published per turn and the next request resumes at one: a message checkpoint is shadowed a few tokens later by its own prompt checkpoint, and a reply-end checkpoint is rarely resumed by clients that re-render the reply. The scheduler now defers the host offer (never the GPU capture) of a message checkpoint whose own prompt checkpoint follows less than one page later, and of terminal checkpoints. A deferred checkpoint is offered when a request resumes exactly at it (it is still on the GPU and pinned by that request), or, for a message checkpoint whose prompt capture could not get a snapshot, at that point while the request still pins it. A preempted request's terminal checkpoint counts as resumed, and a deferred message checkpoint is offered when its request is cancelled or fails. The parent reported for a publication is the nearest offered ancestor, with the tail pages since it. When the GPU compacts an offered checkpoint whose heir was not offered, the pool hears the first offered descendant as the heir, so announced chains stay connected; a deferred checkpoint that became a branch point is offered as the heir. Captures, prefill cuts, GPU retention and eviction order are unchanged; the rule uses only page size and the selected message boundaries. Validation: upstream CI's Linux commands: selene with test-support 389 passed, selene-manager all passed, helios the same 1187 passed / 7 failed as main (main's DeepSeek tokenizer-fixture defect), scheduler tests all pass. Tests cover deferral at page boundaries, offer on reuse, the capture-failure and preemption paths, parent and tail reporting, compaction with a deferred heir in pool mode, and output lengths 1 and 3. Independent review; findings addressed. Not yet run on a GPU. Design-Signed-Off-By: yatesdr; design-review=1c01
Snapshot capacity was fixed at eight rows per concurrent request (256 at concurrency 32) regardless of memory. On a long agent conversation the GPU therefore evicted 94% of the checkpoints it created while 55-73% of its KV pool sat free, and the host store refilled what the GPU dropped. Capacity is now whatever the borrowable KV backing can alias, which the planner already computes and caps by memory and virtual extent; rows and request pages keep yielding to each other through the existing pressure eviction. The per-request capture budget stays at most eight, so prefill cuts are unchanged. No package re-export is needed. The design docs (core design, runtime package, CLI) describe the memory-bounded capacity. Validation: upstream CI's Linux commands: helios the same 1190 passed / 7 failed as main (main's DeepSeek tokenizer-fixture defect), selene and selene-manager all passed. Tests: capacity grows with memory, the per-request budget stays eight, cached rows yield backing to admission. CPU measurements at 256 vs 1,350 rows: blocked snapshot search 7.2 vs 80.5 us, median leaf eviction 2.0 vs 13.6 us, reclaiming 128 rows 0.49 vs 1.98 ms. Not yet run on a GPU. Design-Signed-Off-By: yatesdr; design-review=1c01
yatesdr
force-pushed
the
selene-tiering
branch
from
November 2, 2026 19:29
a0adb62 to
ebebf1c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
This PR makes the host cache tiers (DRAM and disk) hold far less data for the same conversations, and stops the GPU from evicting snapshots it could keep.
Changes
flare_host_cache_rows_thinned_total{tier}.flare_host_cache_packed_records_total{tier},flare_host_cache_per_rank_records_total{tier},flare_host_cache_abandoned_stores_total.Behaviour changes
Testing
DeepSeek V4.1 Flash, TP4, on an SM120 host (4x RTX PRO 6000), production-style flags (MTP 5, 32 slots, 16 GiB host memory, 120 GB disk limit, 60 s shutdown drain). Base is the parent commit (upstream main plus #141/#142). Single conversation: 170 turns to about 130k tokens, once with a client that echoes the reply back unchanged and once with a client that re-renders it. Concurrent: 32 conversations for 30 minutes.
Single long conversation
32 concurrent conversations, 30 minutes
Idle TTFT of a cached turn at 130k tokens is 0.30 s on both sides, and engine time, GPU wait on the host and probe latency are the same, so no scan or packing cost shows at this scale. The packing time itself is not exposed as a metric and was not measured directly.
Correctness (this change only)
Unit tests (Linux, upstream CI commands): selene 388 pass (with test-support); selene-manager passes; helios 1191 pass and 7 fail, the same 7 as on main (a DeepSeek tokenizer-fixture defect). New tests cover chain thinning in memory, composite and disk, forks and rewinds restored through disk, identical, mixed and differing shares, multi-window disk-only spills in any order, abandoned stores, recovery including a version-1 file written by the previous code, deferral at page boundaries, offer on reuse, capture-failure and preemption paths, compaction with a deferred heir, and capacity growing with memory.
Notes