Repository navigation
[MoE] Expert pool follow-ups: MTP, Marlin 32 GiB bank guard, prefill staging - #51
Open
wyj-IIRtyj wants to merge 3 commits into
Open
wyj-IIRtyj wants to merge 3 commits into
wyj-IIRtyj wants to merge 3 commits into
Conversation
Keep MoE layers that do not use the NVFP4 method (e.g. an MTP head the checkpoint leaves in BF16) out of the pool instead of rejecting them, and size the decode lanes for 1 + num_speculative_tokens tokens per request. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Yongjie Wang <141611724+wyj-IIRtyj@users.noreply.github.com>
Marlin MoE adds the int64 expert offset of its weight operand into a 32-bit index in 16-byte units, so a bank weight tensor above 32 GiB reads out of bounds (an illegal memory access in profile_run). Reject such banks at installation and report the largest --moe-expert-pool-rows that fits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Yongjie Wang <141611724+wyj-IIRtyj@users.noreply.github.com>
Marlin reads its weight operand once per M-block, so on the partition path every non-resident expert crossed PCIe several times per prefill step. Prefill steps of at least 512 tokens now copy each layer's non-resident rows into one of two device buffers by DMA on a side stream, one layer ahead of the compute, and run Marlin on that buffer instead of the host view. On by default (--moe-expert-pool-prefill-staging); costs two layers of expert weights in GPU memory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Yongjie Wang <141611724+wyj-IIRtyj@users.noreply.github.com>
4 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Three independent follow-ups to vllm-project#56177 (on top of its head
3e13f466), from serving GLM-5.3-Flash NVFP4 with the expert pool at 1M context on 2x RTX PRO 6000 (TP=2). Each commit stands alone and can be cherry-picked separately.Claims
796df0733). MoE layers that do not use the NVFP4 method, such as the BF16 MTP head of an NVFP4 checkpoint, now keep their experts on the GPU (one warning) instead of failing the layer guard (... got UnquantizedFusedMoEMethod). The decode lanes are sized for1 + num_speculative_tokenstokens per request; previously, for example,--max-num-seqs 1with 3 speculative tokens sent every verify step (4 tokens) down the partition path.d2a05d42b). Marlin MoE adds the int64 expert offset of its weight operand intoint b_gl_rd, which is counted in 16-byte units (csrc/moe/marlin_moe_wna16/marlin_template.hL698/L706, unchanged on main). Any bank weight tensor above 32 GiB is therefore read out of bounds.--moe-expert-pool-rows 240on GLM-5.3-Flash TP=2 (over 10,000 bank rows of 4 MiB w13, about 39.5 GiB) died with an illegal memory access inprofile_run. A direct kernel check, shown below, puts the bound exactly at 8192 rows of 4 MiB. Such a configuration now fails at installation withuse --moe-expert-pool-rows <= 193.25bbec966). TTFT at 81.6K input tokens drops from 67.6 s to 13.0 s and at 12.5K from 9.6 s to 1.8 s, with decode unchanged. On by default;--no-moe-expert-pool-prefill-stagingturns it off.Validation
Setup:
nvidia/GLM-5.3-Flash-NVFP4, 2x RTX PRO 6000 Blackwell (SM120, PCIe, GPU-GPU P2P), TP=2,--moe-backend marlin --moe-expert-pool-rows 193 --kv-cache-dtype fp8 --max-model-len 1048576 --max-num-seqs 4,FULL_DECODE_ONLY, MTP with 3 speculative tokens ("moe_backend": "triton"for the BF16 draft). Measurements use single requests, synthetic prompts and a streaming client.The end-to-end numbers come from vLLM 0.32.0 with the pool applied. The
expert_pool/package and its tests are byte-identical to3e13f466, and the hook files were ported. That build ran the same staging and MTP logic, but enabled staging through an environment variable rather than the new flag, and had no bank-size check. They were not measured on a wheel built from this branch.--max-num-batched-tokens3e13f466)[1] On this hybrid model, align-mode prefix caching clips non-final prefill chunks to multiples of the 4608-token mamba block, so 8192 actually runs 4608-token steps.
nvidia-smi dmon: each 4096-token step pulled ~141 GB over PCIe for a ~28 GB non-resident set. Marlin reads its B operand once per M-block, so every non-resident expert crossed PCIe about 5 times.get_weather) through the OpenAI API.Tests, on one RTX PRO 6000 (SM120). Same environment boundary as in vllm-project#56177: the Python sources of this branch over the vLLM 0.32.0 wheel. The
expert_pool/package is byte-identical to this branch, and the hook files are ported.The new staging test runs the real Marlin kernel. It asserts that staging happened (two layers staged, eight rows copied, resident rows untouched) and that the output is byte-identical to the host-view read.
Marlin bound, checked directly: one NVFP4 expert (K=4096, N=1024, a 4 MiB w13 row) is placed at row 0 and at the last row of
rows-row weight tensors, and the same 8 tokens are routed to each copy through the pool's align-and-remap path. Routing to an all-zero row instead changes the output, which confirms the physical row id is honored.CUDA error: an illegal memory access was encounteredpre-commit run --from-ref 3e13f466 --to-ref HEAD: all hooks pass (ruff, typos, markdownlint, mypy, SPDX, config docstrings).Details
Prefill staging (
stage.py).copy_from the pinned source) on a side stream: layer i+1 is copied while layer i computes, ordered with events andwait_stream. A Triton gather kernel reached the same ~52 GB/s, but it competes with the expert GEMM for SMs.Tradeoffs:
VLLM_GPU_SYNC_CHECK=errorwould flag it. Decode is unaffected.MTP. The layer guard now rejects only NVFP4 layers on a non-Marlin backend. Any other MoE layer is left out of the pool, which also covers FP8 draft heads. A model where no layer is pooled therefore loads with all experts on the GPU, behind a single warning.
Bank-size guard. Only the weight operands are checked. The scale and global-scale pointers are advanced per expert in 64-bit arithmetic, so they are not affected. A kernel-side fix would advance B the same way (pointer per expert instead of an int offset). It is not included here because it needs a rebuilt
_moe_C, and on main no single MoE layer comes near 32 GiB.Related work. These commits target vllm-project#56177's branch rather than main because they depend on it.
b_gl_rd,B_expert_off, int32/32-bit index) and found none.--offload-backend uvapath. It copies right before the expert kernel and, as its description notes, stages only weights carrying the UVA marker. It therefore does not cover the pool's host view.AI assistance (Claude Code) was used to prepare these changes. I reviewed every changed line and ran the tests above.
🤖 Generated with Claude Code