cuda: grouped-expert MUL_MAT_ID for small MoE verify batches#38
cuda: grouped-expert MUL_MAT_ID for small MoE verify batches#38davide221 wants to merge 1 commit into
Conversation
Speculative-verify batches (2-16 tokens) route consecutive draft tokens to heavily overlapping expert sets, but the multi-token MoE MMVQ kernel reads each (token, slot) pair's expert weights independently. Measured on a 256-expert top-8 MoE, an 8-row verify batch reads 64 expert matrices per layer where only 39.4 distinct ones are needed (1.62x duplication); at 15 rows it is 120 vs 58.9 (2.04x). This adds an opt-in path (DFLASH_MMID_GROUPED=1) that rank-sorts the (token, slot) pairs by routed expert in a tiny capture-safe prep kernel, then runs a variant of mul_mat_vec_q_moe whose warp w processes sorted pair blockIdx.y*8+w instead of (slot, token). Same-expert pairs are adjacent after sorting, so the warps of a block share an expert and duplicate weight reads are served from L1/L2 instead of DRAM. Launch shape, per-warp structure, vec_dot sequence and warp reduction are identical to mul_mat_vec_q_moe, so outputs are bit-exact and CUDA-graph capture stays supported. DFLASH_MMID_GROUPED_TYPES bitmask selects quant types: 1 = Q4_K (default), 2 = Q6_K (also lifts the Q6_K MUL_MAT_ID MMVQ ceiling to 16, keeping CUDA graphs enabled for those batches), 4 = Q4_0/Q8_0/Q5_K. Model-agnostic for any MoE with n_expert_used <= 16. Measured on RTX 3090 (sm_86), Laguna XS 2.1 Q4_K_M target + DFlash drafter, greedy HumanEval prompts, outputs byte-identical: verify width 8: 212.0 -> 219.9 tok/s (+3.7%) verify width 15: ~157 -> 173.3 tok/s (~+10%) Gains grow with verify width (more expert overlap to dedup), which is what makes wide/hedged verify configurations cheaper.
There was a problem hiding this comment.
2 issues found across 1 file
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="ggml/src/ggml-cuda/mmvq.cu">
<violation number="1" location="ggml/src/ggml-cuda/mmvq.cu:253">
P3: The `MMID_META_GS` macro is defined but never read or written by any kernel. It creates a 257-int (~1 KB) gap in the meta allocation that serves no purpose. This inflates the per-call scratch allocation and makes the layout harder to follow. Consider removing the dead constant and collapsing the layout so `MMID_META_PT` directly follows `MMID_META_GE + MMID_GROUPED_MAX_PAIRS`, which would reduce `MMID_META_INTS` from 1026 to 769.</violation>
<violation number="2" location="ggml/src/ggml-cuda/mmvq.cu:1577">
P2: Enabling `DFLASH_MMID_GROUPED` can switch small MUL_MAT_ID calls on non-Turing+/non-NVIDIA devices into the new grouped CUDA path even though `get_mmvq_mmid_max_batch()` only enables this feature for NVIDIA Turing+. Consider applying the same compute-capability guard here so the opt-in path matches the routing/graph eligibility logic.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
|
||
| // [TAG_MMID_GROUPED] grouped-expert path for small MUL_MAT_ID batches. | ||
| if (ids && ncols_dst >= 2 && ncols_dst <= MMVQ_MAX_MOE_BATCH_SIZE && | ||
| mmid_grouped_env() && mmid_grouped_type_ok(src0->type)) { |
There was a problem hiding this comment.
P2: Enabling DFLASH_MMID_GROUPED can switch small MUL_MAT_ID calls on non-Turing+/non-NVIDIA devices into the new grouped CUDA path even though get_mmvq_mmid_max_batch() only enables this feature for NVIDIA Turing+. Consider applying the same compute-capability guard here so the opt-in path matches the routing/graph eligibility logic.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At ggml/src/ggml-cuda/mmvq.cu, line 1577:
<comment>Enabling `DFLASH_MMID_GROUPED` can switch small MUL_MAT_ID calls on non-Turing+/non-NVIDIA devices into the new grouped CUDA path even though `get_mmvq_mmid_max_batch()` only enables this feature for NVIDIA Turing+. Consider applying the same compute-capability guard here so the opt-in path matches the routing/graph eligibility logic.</comment>
<file context>
@@ -1294,6 +1572,25 @@ void ggml_cuda_mul_mat_vec_q(
+ // [TAG_MMID_GROUPED] grouped-expert path for small MUL_MAT_ID batches.
+ if (ids && ncols_dst >= 2 && ncols_dst <= MMVQ_MAX_MOE_BATCH_SIZE &&
+ mmid_grouped_env() && mmid_grouped_type_ok(src0->type)) {
+ const int np = (int) (nchannels_dst*ncols_dst);
+ GGML_ASSERT(np <= MMID_GROUPED_MAX_PAIRS && "DFLASH_MMID_GROUPED supports n_expert_used <= 16");
</file context>
| mmid_grouped_env() && mmid_grouped_type_ok(src0->type)) { | |
| mmid_grouped_env() && mmid_grouped_type_ok(src0->type) && | |
| GGML_CUDA_CC_IS_NVIDIA(ggml_cuda_info().devices[ggml_cuda_get_device()].cc) && | |
| ggml_cuda_info().devices[ggml_cuda_get_device()].cc >= GGML_CUDA_CC_TURING) { |
| #define MMID_GROUPED_MAX_TPG 8 | ||
| #define MMID_META_NG 0 | ||
| #define MMID_META_GE 1 | ||
| #define MMID_META_GS (MMID_META_GE + MMID_GROUPED_MAX_PAIRS) |
There was a problem hiding this comment.
P3: The MMID_META_GS macro is defined but never read or written by any kernel. It creates a 257-int (~1 KB) gap in the meta allocation that serves no purpose. This inflates the per-call scratch allocation and makes the layout harder to follow. Consider removing the dead constant and collapsing the layout so MMID_META_PT directly follows MMID_META_GE + MMID_GROUPED_MAX_PAIRS, which would reduce MMID_META_INTS from 1026 to 769.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At ggml/src/ggml-cuda/mmvq.cu, line 253:
<comment>The `MMID_META_GS` macro is defined but never read or written by any kernel. It creates a 257-int (~1 KB) gap in the meta allocation that serves no purpose. This inflates the per-call scratch allocation and makes the layout harder to follow. Consider removing the dead constant and collapsing the layout so `MMID_META_PT` directly follows `MMID_META_GE + MMID_GROUPED_MAX_PAIRS`, which would reduce `MMID_META_INTS` from 1026 to 769.</comment>
<file context>
@@ -233,8 +233,67 @@ static constexpr __host__ __device__ int get_mmvq_mmid_max_batch_rdna4(ggml_type
+#define MMID_GROUPED_MAX_TPG 8
+#define MMID_META_NG 0
+#define MMID_META_GE 1
+#define MMID_META_GS (MMID_META_GE + MMID_GROUPED_MAX_PAIRS)
+#define MMID_META_PT (MMID_META_GS + MMID_GROUPED_MAX_PAIRS + 1)
+#define MMID_META_PS (MMID_META_PT + MMID_GROUPED_MAX_PAIRS)
</file context>
|
Superseded: ggml is vendored into lucebox-hub now, PR moved there. |
What
Opt-in grouped-expert path for
MUL_MAT_IDon small token batches (2-16), targeting speculative-verify workloads on quantized MoE models. Enable withDFLASH_MMID_GROUPED=1.Why
Consecutive draft tokens route to heavily overlapping expert sets, but
mul_mat_vec_q_moereads each (token, slot) pair's expert weights independently. Measured on a 256-expert top-8 MoE (Laguna XS 2.1):How
[TAG_MMID_GROUPED]inmmvq.cu). Capture-safe: ids never leave the device, all launch shapes are static.mul_mat_vec_q_moewith one change: warpwprocesses sorted pairblockIdx.y*8 + winstead of(slot = blockIdx.y, token = w). Same-expert pairs are adjacent after sorting, so the warps of a block share an expert and duplicate weight reads hit L1/L2 instead of DRAM.vec_dotsequence and warp reduction are identical tomul_mat_vec_q_moe→ bit-exact outputs, CUDA-graph capture unaffected.DFLASH_MMID_GROUPED_TYPESbitmask:1= Q4_K (default),2= Q6_K (also lifts Q6_K's MUL_MAT_ID MMVQ ceiling to 16, keeping CUDA graphs on for those batches),4= Q4_0/Q8_0/Q5_K.n_expert_used <= 16(asserted).Results
RTX 3090 (sm_86), Laguna XS 2.1 Q4_K_M + DFlash drafter, greedy HumanEval prompts. Outputs byte-identical to baseline in all cases (verified per-prompt, identical accept trajectories):
Gains grow with verify width (more overlap to dedup), which lowers the marginal cost of wide/hedged verify configurations.
Notes
ggml_cuda_mul_mat_vec_q).Summary by cubic
Adds an opt-in grouped-expert path for
MUL_MAT_IDon small MoE verify batches (2–16 tokens) to reduce duplicate expert weight reads and speed up speculative verify. Outputs remain bit-exact and CUDA graph capture stays supported, with gains up to ~10% at width 15.DFLASH_MMID_GROUPED=1; control quant types viaDFLASH_MMID_GROUPED_TYPES(1=Q4_K default,2=Q6_K,4=Q4_0/Q8_0/Q5_K).(token, slot)pairs by expert; static launch shapes; capture-safe.mul_mat_vec_q_moeprocesses sorted pairs so warps share experts; same launch/warp structure → bit-exact outputs.MUL_MAT_IDbatch ceiling to 16 and keeps CUDA graphs on; asserted forn_expert_used <= 16; off by default.Written for commit 15b5b1b. Summary will update on new commits.