ggml: treat experts as cache residents during MoE offloading - #3
Conversation
a702d5c to
35fd0c3
Compare
There was a problem hiding this comment.
Code Review
This pull request optimizes MoE weight offloading by tracking resident experts on the backend and only copying missing ones, reducing redundant data transfers. Changes include the introduction of the ggml_backend_sched_moe_loaded structure and updates to the scheduler's compute and lifecycle management logic. Feedback suggests explicitly invalidating the MoE resident state during a scheduler reset to maintain consistency when staging tensors are cleared.
I am having trouble creating individual review comments. Click here to see my feedback.
ggml/src/ggml-backend.cpp (1892-1898)
While the invalidation logic in ggml_backend_sched_compute_splits is robust enough to handle stale cache entries by checking src_data and dst_data pointers, it would be cleaner to explicitly invalidate the MoE resident state here when the scheduler is reset. Since hv_tensor_copies is cleared, the staging tensors are effectively deallocated, and the resident expert metadata should ideally reflect this state.
References
- Defensive programming: ensure that invalid states (stale cache entries after a reset) are explicitly handled or cleared to maintain consistency.
61edb86 to
a16c41a
Compare
a16c41a to
dc54faf
Compare
Overview
When MoE weights are offloaded from host memory, the scheduler copies the experts used by the current
GGML_OP_MUL_MAT_IDsplit into a backend-side staging tensor. In long prompt-cache workloads, the same staging tensor can be reused across turns, so experts copied for earlier tokens may still be resident.This change tracks resident MoE experts per scheduler tensor copy and treats the staging tensor as an expert cache:
ggml_bitset_tmissing_ids = used_ids & ~loaded_idsThe change is internal to
ggml/src/ggml-backend.cpp. It does not add a user-facing flag, public API, or backend-specific implementation.Benchmark Setup
dc54faf7fbuild-cuda13-clean/bin/llama-server, CUDA graphs off--cpu-moe,-c 65536,-ngl auto,-np 1--no-cache-promptexcept for the medium-turns context-fill suiteOnly CPU-MoE op-offload measurements are included below because that is the path changed by this PR.
Results
64k Multi-Prompt Op-Offload
This is the short steady-state control: 60s measured duration after ~10s warmup, comparing the resident-expert cache with a local cache-disabled control build on the same op-offload path.
Deltas:
+5.36%, avg latency-5.09%+5.43%, avg latency-3.49%Long-Context Prefill Pressure
Single cold request, no warmup, prompt-cache disabled, generated prompt calibrated through
/tokenize,max_tokens=128.Deltas:
7.03xfaster, latency-85.77%3.91xfaster, latency-74.45%Medium-Turn Context Fill
Sequential ~5k-token turns with prompt-cache enabled, stopping around 60k prompt tokens. This simulates a long chat where earlier prompt state is reused and reports processed prompt tokens separately from cached tokens.
Deltas:
4.34xfaster, processed prompt tok/s4.29x, latency-77.29%2.65xfaster, processed prompt tok/s2.62x, latency-62.61%Validation
git diff --checkcmake --build build-cuda13-clean --target llama-server test-backend-ops -j 10build-cuda13-clean/bin/test-backend-ops test -o MUL_MAT_ID:764/764 tests passedAI usage disclosure: YES - Codex assisted with local code review, benchmarking, cleanup, and preparing this fork-local staging PR. Before opening an upstream PR, I will manually review the patch and write/edit the final upstream PR text myself.