[MLX] Add off-graph KV cache ring runtime - #21532
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/21532
Note: Links to docs will display an error until the docs builds have been completed. ✅ No FailuresAs of commit c921c59 with merge base 849f9d8 ( This comment was automatically generated by Dr. CI and updates every 15 minutes. |
This PR needs a
|
| // (the newest key belongs to the last query), so query i spans keys | ||
| // j - i <= S - T -- the same bound MLX's "causal" applies -- and the window | ||
| // adds the lower bound j - i > S - T - window. | ||
| inline array window_causal_mask(int T, int S, int window, StreamOrDevice s) { |
There was a problem hiding this comment.
Isn't there a field for mask on attendsepc?
Should the mask be constructed in the cache and handed back?
There was a problem hiding this comment.
Mlx doesnt have a window mode but for backends that takes window like flash attention it could just pass window parameter instead of materializing the mask
Summary
Adds ring (sliding-window) layers to the MLX KV cache, so a model can mix them with flat layers per layer. The window is expressed declaratively: AttendSpec gains a window on Causal (the mask_mod axis the header reserved), so the cache states the semantic and the handler materializes whatever the backend can't do natively. MLX SDPA has only ""/"causal"/"array" — no sliding-window mode — so the handler builds a banded bool mask, but only when the window is narrower than the span. A backend that supports windows natively would just forward the integer.
Files
handler uses it only when window < S, else plain "causal".
Testing
New: the mask is a band (checked against a hand-written 3×5 matrix, plus a window covering the span degenerating to causal); a ring decode past its window evicts the oldest and needs no mask; a multi-token step declares its window while a flat layer declares none; and a step whose runs wrap the ring is scattered and rejoined in logical order; the physical layout is out of order by then, so this pins the wrap handling.
cmake --preset mlx-release -DEXECUTORCH_BUILD_TESTS=ON
cmake --build cmake-out --target mlx_sequence_cache_test
ctest --test-dir cmake-out -R mlx_sequence_cache --output-on-failure