Skip to content

read-write: growing conversations lose local prefix-cache hits on ~41 % of continuation turns and are served by restores (23 s) instead; hot turns 37 s vs 15 s in restore-only #61

Description

@sethforprivacy

Summary

In read-write mode with tail-cow-v2 + async page capture, a growing multi-turn conversation loses its local (GPU) prefix-cache hits on a large share of continuation turns; those turns are then served by a SparkCache restore of the conversation's own earlier turns (published minutes before) at 10-30 s per turn instead of a ~1 s local hit. In restore-only mode the same conversation shape keeps 87-97 % local hits. Paired 60-minute soaks with fresh, never-published conversations on the same lane, same day, same launcher (four GB10, GLM-5.3 TP4/DCP4, image 0d4029b3…, sparkcache 6605717, 300 s lease, 4.32M-token KV pool never above 28 % used).

Setup

Replay: 4 concurrent agents, each a conversation starting at 106-340K tokens and growing ~2K tokens per turn (assistant reply + "tool result"), thinking on, 512-token replies, a small image every 10th turn, new conversation after 160K. Fresh seed per arm, so no cross-run restores are possible. usage.prompt_tokens_details.cached_tokens is recorded per turn (it reports local prefix-cache hits in this build).

Result

read-write restore-only (SPARKCACHE_ACCESS_MODE=restore-only, async capture off)
turns in 60 min / prompt tokens 263 / 36.9M 195 / 26.6M
continuation turns (same conversation, +<10K tokens) 247 183
… with cached_tokens < 50 % of prompt 102 (41 %), median 23.4 s 30 (16 %), median 166 s
… with ≥ 50 % local cache 145, median 37.0 s 153, median 15.2 s
post-soak idle 5K-prompt decode (3 probes) 34.4 / 26.4 / 20.5 tok/s 35.2 / 30.5 / 29.4 tok/s

One agent's trace in read-write (prompt size / local cached % / latency):

t1 105k/0%/355s  t2 107k/96%/93s  t3 109k/97%/32s … t8 118k/98%/19s
t9 120k/0%/15s  t10 122k/0%/11s  t11 124k/0%/21s … t22 145k/0%/30s
t23 147k/98%/16s  t24 149k/98%/15s  t25 151k/0%/10s … t30 161k/0%/37s

A 120-145K prompt cannot be recomputed in 11-30 s on this lane (restore-only's genuine misses take ~166 s under the same load), so the 0 % turns were restored from the page store: the local prefix cache no longer held the conversation's previous turns although KV usage stayed under 28 % and the 300 s lease had not expired between turns (turns arrive every 15-40 s). The same agent shape in restore-only stays at 87-97 % local hits.

Two effects follow: (1) hot continuation turns are 2.5× slower in read-write (37 s vs 15 s), which on this traffic outweighs the per-publish cost measured on an idle lane (-10 % first token for a new 5K prompt); (2) the post-soak slowdown reported in #60. Read-write still completes more turns overall because it rescues genuinely new/evicted contexts (restore-only's 30 misses at 166 s), which is the value of the store — but the rescued case should be the exception, not 41 % of continuation turns.

Question / ask

How are a finished request's KV blocks returned to vLLM after the async capture completes (delayed free / get_finished)? If they are freed without their block hashes staying in the local prefix cache, or if the lease/COW ownership makes the next turn's lookup miss locally, that would explain the trace. A per-request counter of "local hit vs external restore vs recompute" tokens in the connector's metrics would make this visible without a replay harness.

Data (per-turn logs, CSVs, probe JSON) in our site repo docs/weekend-2026-09-05/evidence/soak-fair-*; happy to rerun with an instrumented build.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions