Repository navigation
Replace MoE LRU cache with a 50/50 SLRU cache - #30637
Conversation
|
@am17an since you did the original LRU version |
|
I'll run some tests |
am17an
left a comment
There was a problem hiding this comment.
I see a small but consistent gain with this PR
|
I seem to have got a regression on GLM 5.3 Flash, from about 15 tg/s to about 12.5. This is my configuration:
Running on Arch Linux with latest updates, on the following hardware:
|
Did you narrow it down to this PR specifically, or was it a regression just after pulling the latest master? There have been a lot of changes recently. Eyeballing the config, I think it's plausible that this PR would cause a regression in your use case because your cache (4500MiB) is so tiny relative to the size of the model. In particular (thanks to Astra for doing some of this math):
So prior to this PR, an entire token's worth of experts fit in the cache, with room to spare for some prior experts. This PR splits the cache space in half, so you end up with an old set and a new set but neither set has room for a single token's worth of experts, and I can easily imagine that causing a bunch of bad cache churn behaviour. Ultimately this is a very theoretical explanation since I don't have your system or full config, but... it's a definite maybe. If you have ~3GiB of system ram to spare I would suggest offloading one more layer of experts and using the space savings for a much bigger cache (i.e. just |
|
If my analysis is correct, then it is up to the maintainers whether this case is sufficiently important to warrant a revert or not. One alternative would be to print a warning when the configured cache is small enough to cause significant churn, i.e. something like (AI-written PoC, I haven't actually tried this): Though even in this case, having a small cache may be better than no cache at all, it's hard to say. Edit: Or even falling back to a non-split LRU cache for small cache sizes might not be too hard. Though we may still want a warning for caches that are particularly tiny. |
Resolve conflicts with master (1b29621): - llama-moe-cache: master turned the LRU into an SLRU (ggml-org#30637). Rename the PR's profile prefill, hit counting and adaptive-swap code to the SLRU struct (moe_cache_slru); plan() keeps n_hit_profile and clears from_profile on a fill. - llama-graph: keep the PR's host_ids parameter and add master's build_hadamard_input call in build_lora_mm_id; apply master's MELLUM precision condition inside the PR's build_experts lambda. - llama-context: keep the hybrid graph-node reservation next to master's new sampler node count. - server-context: keep master's "graph reallocs" log and the PR's MoE cache stats. - test-llama-archs: master refactored tensor filling; port the quantized expert branch to it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Terminology: "1x" means the cache is large enough to hold exactly one complete token's worth of experts. Via Astra I ran a variety of further experiments. Some condensed findings:
These results very roughly match/explain the regression seen by @kudraw, though the reported regression is still on the larger side of what I'd expect. Implications / proposals:
|
|
Perhaps there is an adjustment needed in the |
|
@kudraw #30848 should fix the regression in your config by falling back to LRU for small caches. Please give it a try. I have left it in draft because it is AI written and I haven't given it a thorough look yet, but it is only +14/-10. @am17an unfortunately I only have the one weird box to do my tests on. It is asymmetric multi-GPU which has let me try a few different options, but it is unusual (my RAM is only about as fast as my PCI bus) and without more combinations of speeds I am hesitant to draw too many broad recommendations, thus why I was fairly conservative in proposing this PR (and I still managed to miss a case and cause a regression). I have thought a bit about how we would choose I'm at the end of my day here (EST), and I will probably be busy with my day job for a bit. When I get a chance to come back to this, I will see what I can cook up. P.S. You are welcome to take #30848 out of draft and ship it if you like the shape. |
|
Hi @eapache , thank you for your patience and your work. I tested your patch (nothing formal, I use a couple of fixed prompts via llama-cli to test generation speed), here the results:
It seems that the patch restored the original performance :D, I see the hit rate was very low on b11741 for this particular moe cache configuration. Just to clarify my hardware, I'm on Ryzen 9 9950x3d 16 cores, 128 GiB RAM DDR5 6400 CL40 and GPU NVIDIA RTX PRO 4500 Blackwell Workstation Ed. 32 GB. Motherboard is an ASUS ProArt B850-CREATOR WIFI NEO. @am17an about the bus, I'm on PCI-e 5.0, your patches were great for Qwen 3.8 Flash Next (I got Q8 from about 22 t/s to above 30 in the latest builds). At work I've a server with an RTX A4500 20GB on PCI-e 3.0 and effectively the cache doesn't help much. Anyway, tell me if I can help with more tests (also on other models) or make more rigorous ones. Thank you! PS: I'm on CEST +0200, so I can do something only when I go back from work, in the evening. |
|
Thanks! I had a clever idea and pushed another commit to #30848 which I think will work even better for these middle-small caches and have taken it out of draft. Please give it a try! |
|
Hi @eapache , I've tested again with the newer commit, here the results (I've added a column to the previous table):
Not bad :). |
Overview
Turn the simple LRU cache for MoEs into a 50/50 split LRU cache. Think similar to generational garbage collection, where there is an older stable set and a younger more volatile set. This performs about 1-5% better than simple LRU in my various tests.
Additional information
I had Astra manage a fairly extensive set of experiments across two GPUs (a 3060 on a slow PCI bus and a 4500 on a fast one), two models (Gemma4-26B-A4B and Qwen3.8-Flash-Next) and a wide variety of proposed mechanisms (LFU, leaving rare experts to execute on CPU, and many others and hybrid tunings). This approach gave the best improvement without any regressions, and was also conveniently one of the simplest.
Depending on the constraints of the system there are some approaches that can squeeze out another 5% or so, but those approaches tend to perform worse than plain LRU on other versions of the setup.
Requirements