Skip to content

perf(cache): write rotating-cache warmup rows in place - #1963

Merged
inureyes merged 1 commit into
mainfrom
update/issue-1962-rotating-kv-inplace
Sep 24, 2026
Merged

inureyes merged 1 commit into
mainfrom
update/issue-1962-rotating-kv-inplace

Conversation

@inureyes

Copy link
Copy Markdown
Member

Follow-up to #1961: RotatingKVCache now writes decode rows in place while it is still filling its sliding window. Every such row lands on a slot that was never valid, so the dense cache's ownership proof applies unchanged: the cache's own last write produced the current buffers and the row lands at that write's length. After the window is full a step overwrites the oldest slot, which a prompt-cache snapshot may still hold, so those writes keep the copying slice_update.

Measurement

M1 Ultra, mlxcel-bench-decode with bench_decode.sh's arguments (pp512, tg128), two runs per arm against main (rotating path off), load 6 to 7.5:

Model window main this PR
Gemma 3 4B IT 4-bit 1024 100.57, 100.77 102.75, 104.79
Gemma 4 12B IT 4-bit 1024 36.08, 36.48 37.65, 37.06
Gemma 4 E4B IT 4-bit 512 78.40, 80.11 78.78, 80.10
gpt-oss 20B mxfp4-q4 128 100.86, 100.59 101.34, 98.08

The 1024-window models decode inside the warmup phase at this condition; the 512- and 128-window models fill their windows during the prompt and decode in the steady state, which is unchanged by design. Record: docs/benchmark_results/rotating-kv-inplace-write-m1ultra-2026-09-24.md.

Validation

  • Greedy output byte-identical with MLXCEL_KV_INPLACE_WRITE on and off for Gemma 3 4B, Gemma 4 12B, Gemma 4 E4B, gpt-oss 20B and EXAONE 4.0 1.2B (two prompts, 300 tokens).
  • New test: warmup writes leave a shared snapshot's rows intact and a wrapped overwrite copies; allowing the steady state to write in place makes it fail.
  • make verify-test: 11431 passed, 0 failed. Workspace clippy and fmt pass.
  • Not measured: contexts past the window, CUDA and ROCm.

Closes #1962

RotatingKVCache kept the copying slice_update after #1959 moved the dense FP16 cache to in-place decode writes, so sliding-window layers still copied their whole buffer every decode step while the previous pipelined step held it.

While the cache is still filling its window, each decode token lands on a slot that was never valid. Those writes now go through inplace_slice_write under the same proof as the dense cache: the cache's own last write produced the current buffers and the row lands at that write's length. After the window is full a step overwrites the oldest slot, which a prompt-cache snapshot may still hold and whose sharing cannot be detected, so those writes keep copying. MLXCEL_KV_INPLACE_WRITE=0 still restores the copying path everywhere.

M1 Ultra, pp512/tg128 against main: Gemma 3 4B and Gemma 4 12B (window 1024) about +3% decode; Gemma 4 E4B (512) and gpt-oss 20B (128) unchanged, as they decode past their windows. Greedy output identical on five models. A new test checks that warmup writes leave a shared snapshot intact and a wrapped overwrite copies; letting the steady state write in place fails it.

Closes #1962
@inureyes inureyes added status:review Under review type:performance Performance improvements priority:medium Medium priority area:core mlxcel-core: MLX FFI, primitives, KV cache, layers platform:macos macOS (Apple Silicon) specific labels Sep 24, 2026
@inureyes
inureyes merged commit 2c42188 into main Sep 24, 2026
20 checks passed
@inureyes inureyes added status:done Completed and removed status:review Under review labels Sep 24, 2026
@inureyes
inureyes deleted the update/issue-1962-rotating-kv-inplace branch October 6, 2026 12:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core mlxcel-core: MLX FFI, primitives, KV cache, layers platform:macos macOS (Apple Silicon) specific priority:medium Medium priority status:done Completed type:performance Performance improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf(cache): write rotating-cache warmup rows in place

1 participant