[MLX] Support radix cache - #21509
Conversation
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
@yeahdongcn good work on this! Can you please make the PR description more detailed and concrete to help reviewers and future contributors better understand this PR? For example:
...and anything else that you think can be explained more clearly. Thank you for addressing these! It will help document the developed of the MLX backend much more clearly for future contributors to build off of your great code! |
Thanks for your questions. Please give me some time to prepare a write-up (AI-assisted).
Prefill
Decode
When
After prefill,
|
9d3667e to
4a8a2f7
Compare
|
Question about the deferred decode KV sync in Prefill KV is synced to Timeline:
Would it be safer to sync each new decode token to the pool eagerly (one scatter per step), or do you see a reason the current deferral is needed? |
Thanks for taking such a close look at the code! Yes, this is a real bug. Originally both prefill and decode sync were deferred to The fix follows the same principle as prefill (sync before the data is read). But after some experimentation, eager-per-step turned out to be wasteful. Pool reads only happen during extend/prefill ( @hnyls2002 Could you please check the latest commit and see if it makes sense? Thanks! |
|
@hnyls2002 @alexnails Ping 😄 |
|
|
||
| from sglang.srt.hardware_backend.mlx.kv_cache.contiguous_cache import ContiguousKVCache | ||
|
|
||
| _thread_local = threading.local() |
There was a problem hiding this comment.
does this impl break the chained decode stuff @changminbark is working on ?
There was a problem hiding this comment.
I'm not entirely sure. There are a few new changes built on top of my branch, so we may need to do some rebase/merge work.
There was a problem hiding this comment.
There's a good chance it may break it, so I will need to do some merge work and apply fixes.
alexnails
left a comment
There was a problem hiding this comment.
as this is self contained to MLX, LGTM. Just make sure CI passes and there are no build errors, etc
|
/tag-and-rerun-ci |
Signed-off-by: Xiaodong Ye <yeahdongcn@gmail.com>
Signed-off-by: Xiaodong Ye <yeahdongcn@gmail.com>
Signed-off-by: Xiaodong Ye <yeahdongcn@gmail.com>
Signed-off-by: Xiaodong Ye <yeahdongcn@gmail.com>
e651fc0 to
1287113
Compare
|
/rerun-failed-ci |
1 similar comment
|
/rerun-failed-ci |
|
/rerun-failed-ci |
1 similar comment
|
/rerun-failed-ci |
Signed-off-by: Xiaodong Ye <yeahdongcn@gmail.com>
Signed-off-by: Xiaodong Ye <yeahdongcn@gmail.com>
Motivation
This PR adds a radix cache to the MLX backend, bringing it closer to feature parity with the PyTorch-based implementation and improving prefill throughput for workloads with shared prefixes.
Modifications
Added a
kv_cache/sub-package under the MLX backend with the core radix-cache components: a flat KV pool (MlxKVPool) for MLX-native data storage (auto-sized from available Metal memory), two cache flavors for prefill (PoolBackedCache, zero-copy gather) and decode (ContiguousKVCache, slice-assignment), and a batched attention wrapper (MLXAttentionWrapper) for BS>1 decode with vectorized RoPE.Prefix-trie lookup, eviction, and slot allocation are handled by the scheduler's existing
RadixCacheandTokenToKVPoolAllocator— the MLX runner receivesprefix_slot_idsandnew_slot_idsfrom the scheduler and usesMlxKVPoolpurely as a data store.Updated
model_runner.pyto wire scheduler-provided prefix/slot info, pool management, and deferred sync into the prefill/decode lifecycle. Updatedtp_worker.pyto extractprefix_indices,out_cache_loc, andreq_pool_idxfromModelWorkerBatchand pass them to the MLX runner. Updatedbench_one_batch.pyto passdisable_radix_cache,mem_fraction_static, andpool_sizefor benchmarking.Logs
Accuracy Tests
Benchmarking and Profiling
Model: Qwen/Qwen3-0.6B
bs=1 input-len=60 output-len=100
bs=4 input-len=60 output-len=100
Checklist
Review Process
/tag-run-ci-label,/rerun-failed-ci,/tag-and-rerun-ci