ggml: add optional asynchronous weight prefetching - #291
Conversation
Bring the moe-cache backend set (CUDA/Metal/Vulkan expert cache), the single-GPU auto relaxation, and the Muse Glimmer base sync onto the prefetch-weights branch. Resolved the scheduler-wiring conflicts in ggml-backend.cpp, llama-context.cpp, and llama-bench.cpp by taking the authoritative both-features-merged content from the moe-cache branch, where prefetch and moe-cache already coexist (verified: the 289-to-moe-cache delta for these files is exactly the prefetch feature, zero moe-cache divergence). Assisted-by: Buffy
The conditional worked for MSVC shared builds but disagreed with the macro
on two other configurations:
- MinGW defines _WIN32, so the condition took the no-explicit-extern arm
while GGML_API took the visibility arm, which has no extern. That makes
the line a second definition again, the exact bug the comment above it
warns about.
- Static builds have no GGML_SHARED, so GGML_API is plain 'extern' and the
explicit extern was still emitted, leaving 'extern extern' and C2159 on
MSVC static.
Adding extern to the visibility branch makes GGML_API carry it on every
path, so the use site needs no condition and there is nothing to keep in
sync later.
Expansion on all five configurations:
static extern int ...
shared ELF __attribute__((visibility("default"))) extern int ...
shared MSVC dllexport __declspec(dllexport) extern int ...
shared MSVC dllimport __declspec(dllimport) extern int ...
shared MinGW __attribute__((visibility("default"))) extern int ...
This also matches what PRs TheTom#289 and TheTom#291 already carry, so the two will no
longer conflict.
|
I reviewed the current head after the base merge. The latest commit only brings the branch current; the prefetch implementation itself is unchanged. I am holding this one for evidence, not because the idea is unwelcome. This changes the central graph splitter, allocation lifetimes, and cross-stream event ordering. The upstream source PR is still open and conflicting, and an upstream reviewer specifically called out event synchronization as unresolved. Its performance reports are also mixed, with MoE workloads sometimes moving more data and regressing. That matters more in this fork because prefetch and the GPU MoE cache now share the scheduler. Only CUDA advertises Please post controlled
Also run a deterministic output or perplexity comparison with prefetch off/on. A longer generation run is useful for catching event-ordering failures that a short benchmark can miss. The current WebGPU wasm failure is unrelated. That job mixed wasm32 system libraries into a wasm64 link. A fresh matrix is running after the base updates. I also cleaned up the title and PR description so the scope and current review status are clear. |
|
@TheTom I believe the evidence does not pan this out as a feasible idea. pr/prefetch-weights - Evidence Summary and VerdictDate: 2026-08-20. Branch: pr/prefetch-weights @ 2d5f621. Verdict: kill the prefetch idea as implementedThe measured evidence shows the mechanism targets the wrong bottleneck in What prefetch was supposed to do
Measured resultsAll runs: llama-bench, identical model/flags per pair, q8_0 KV cache, MoE model: Laguna-S-2.1 118B.A8B UD-Q5_K_M (81.82 GiB), experts on CPUPlacement pinned with
Notes:
Dense model: Qwen3.8-27B UD-Q5_K_XL (19.43 GiB)Offload sweep,
Why the idea fails
Scorecard
What survives
Outstanding items if anyone re-litigates
Mac note (from earlier scoping)Prefetch cannot help Apple Silicon: Metal reports Part 2 - MoE cache on Apple Silicon (Metal) - still wantedBuild with A/B arms, identical except cache: # off
... --fit off --moe-cache off -c 8192 -ngl 99 -fa on ...
# auto
... --fit on --moe-cache auto -c 8192 -ngl 99 -fa on ...Same fixed workload, one warmup request discarded, 3+ timed runs, report Metal v1 caveats: synchronous fills (no background worker yet), fused SwiGLU |
|
Agreed. This is a good kill decision. The warmup correction matters, and the MoE cache interaction settles it: a narrow 4% dense prefill win does not justify the scheduler and event complexity when the same flag costs 18 to 19% MoE prefill, 6% decode, and about 3.6 GiB of cache capacity. Thanks for doing the full A/B and closing it on evidence. Keeping the MoE cache work separate is the right outcome. |
Overview
Backports the asynchronous weight-prefetch work from ggml-org#21067 and integrates it with this fork's MoE cache scheduler changes.
--prefetch-weights 0|1, default offprefetch_weightsreporting tollama-benchReview status
The branch is current with
feature/turboquant-kv-cache. Fork-specific CUDA performance and correctness validation is still required before merge, particularly with MoE cache enabled.AI usage disclosure: Yes