[Draft][None][fix] MegaMoEDeepGemm: use engine max_num_tokens directly - #14605
Closed
mingyangHao wants to merge 2 commits into
Closed
[Draft][None][fix] MegaMoEDeepGemm: use engine max_num_tokens directly#14605mingyangHao wants to merge 2 commits into
mingyangHao wants to merge 2 commits into
Conversation
mingyangHao
requested review from
Barry-Delaney and
lfr-0531
and removed request for
QiJune
May 27, 2026 02:18
mingyangHao
requested review from
JunyiXu-nv and
suyoggupta
and removed request for
a team
May 28, 2026 08:58
The MegaMoEDeepGemm wrapper previously read ``model_config.moe_max_num_tokens`` to size its DG SymmBuffer pool and then divided by ``ep_size`` (per NVIDIA#14213) to undo the auto-multiply that ``ModelConfig.__post_init__`` applies for allgather-based backends. Under ``FUSED_COMM`` scheduler (always used by mega_moe), ``FusedCommMoEScheduler._strip_adp_padding`` slices ``x`` to the local rank's tokens before ``run_moe``, so the per-call ``x.shape[0]`` is bounded by the engine's per-instance ``max_num_tokens`` and never by ``dp_size * max_num_tokens``. The auto-multiply is therefore semantically wrong for mega_moe and the divide is a workaround for the wrong source. Two failure modes of the multiply-then-divide dance: 1. If a deployed binary lacks the divide (e.g. binaries built before NVIDIA#14213 landed on this branch), the auto-multiplied value is used as- is, so the cubin's ``num_max_tokens_per_rank`` is baked at ``dp_size * engine.max_num_tokens`` instead of ``engine.max_num_tokens`` (e.g. 65664 vs 8448 on DSv4-Pro @ DEP=8). Measured cost on B300 DEP=8, balanced 8192 tok/rank: 4.03 ms -> 3.39 ms median per-call (-19%), plus the SymmBuffer pool drops from ~3.6 GB to ~470 MB (-7.6x). 2. If a user explicitly sets ``moe_config.max_num_tokens`` in yaml, ``__post_init__`` skips the auto-multiply, but the wrapper still divides, so the per-rank cap becomes ``yaml_value / ep_size`` (too small by ep_size). The line-667 runtime assert then fires for every request whose per-rank tokens exceed that. Read ``model_config.max_num_tokens`` directly instead. The other consumers of ``moe_max_num_tokens`` (fused_moe_cutlass, fused_moe_deepgemm, communication_factory) keep the auto-multiplied value, which is correct for those allgather paths. Test plan: - ``pre-commit run`` clean on the modified file (ruff, ruff-format, codespell, copyright, DCO). - TestDeepSeekV4Flash::test_nvfp4_4gpus_static_eplb[MEGAMOE_DEEPGEMM] on 4x B300 NVFP4 + static EPLB: PASSED. lm-eval GSM8K accuracy 95.262 vs reference 95.110 (threshold 91.907). Runtime ~15 min. - bench_moe at 8192 tok/rank DEP=8 (--analysis kernels --iters 12 --warmup 2) confirms cubin params after fix: sm100_fp8_fp4_mega_moe_impl<8448, 7168, 3072, 384, 6, 2, 192, ..., 414720, 6635520, ...> with mega_moe per-call median 2.62 ms. Signed-off-by: Mingyang Hao <mingyangh@nvidia.com>
mingyangHao
force-pushed
the
fix/megamoe-engine-max-tokens
branch
from
May 28, 2026 09:12
dae6fa8 to
606aa08
Compare
…ime threshold Adds a new ``MoeConfig.backend = "MEGAMOE_AUTO"`` that picks between ``MegaMoEDeepGemm`` and ``TRTLLMGenFusedMoE`` at module construction time based on per-rank ``max_num_tokens`` vs a configurable threshold (default 1024, matching SGLang's ``SGLANG_OPT_DEEPGEMM_MEGA_MOE_NUM_MAX_TOKENS_PER_RANK``). ## Motivation Measured at DEP=8 on B300 DSv4-Pro W4A8_MXFP4_MXFP8 (bench_moe perfect balanced, mean kernel time): | Per-rank tokens | MEGAMOE | TRTLLM-gen NVLINK_ONE_SIDED | DG heuristic E/W | |-----------------|---------|------------------------------|------------------| | 1024 | 0.53 ms | 0.84 ms | 8 | | 2048 | 0.90 ms | 1.12 ms | 6 | | 4096 | 1.54 ms | 2.08 ms | 4 | | 8192 | 2.93 ms | 4.04 ms | 2 | | 16384 | 5.85 ms | 9.21 ms | 2 | MEGAMOE wins on bench across this range, but under prod sustained cross-tray NVLink load (GB300 NVL72, CTX worker spanning 2 trays), the MEGAMOE fused-collective path absorbs ~1.6x extra overhead while TRTLLM-gen's separate-kernel pipeline is largely insensitive. Measured on 0528 prod trace: MEGAMOE 4.66 ms/call at 8k tok/rank (vs bench 2.93 ms). TRTLLM-gen at the same shape in prod is ~3.5 ms (normalized from the 0512 DEP=4 trace). Crossover sits near 1k-2k tokens/rank in real deployments. ## Behavior When ``backend = MEGAMOE_AUTO``: - If ``model_config.max_num_tokens <= megamoe_max_tokens_per_rank``, use ``MegaMoEDeepGemm`` (subject to existing capability gate: W4A8_MXFP4_MXFP8 quant, SM100/SM103, bundled DG mega_moe surface). - Otherwise, use ``TRTLLMGenFusedMoE`` (subject to its existing quant capability gate). - On either gate failure, falls back to ``CutlassFusedMoE`` with a warning. Each fallback logs the input it had so misconfigurations are diagnosable. This is module-construction-time selection, not per-call dispatch. Per-call dispatch would require holding both backend instances with double SymmBuffer / double expert-weight layouts at runtime (~3 GB/rank extra HBM on DSv4-Pro). Disagg deployments naturally satisfy the construction-time-only constraint: the CTX worker's large ``max_num_tokens`` (e.g. 8192) selects TRTLLMGen while the GEN worker's small ``max_num_tokens`` (e.g. 512) selects MegaMoE — both from a single yaml that says ``backend: MEGAMOE_AUTO``. ## Files - ``tensorrt_llm/llmapi/llm_args.py``: Add ``MEGAMOE_AUTO`` to ``MoeConfig.backend`` literal; add ``megamoe_max_tokens_per_rank`` field (default 1024). - ``tensorrt_llm/_torch/model_config.py``: Pass ``megamoe_max_tokens_per_rank`` through ``ModelConfig``. - ``tensorrt_llm/_torch/pyexecutor/model_loader.py``: Wire from ``llm_args.moe_config`` into ``ModelConfig``. - ``tensorrt_llm/_torch/modules/fused_moe/create_moe.py``: Add the ``MEGAMOE_AUTO`` factory branch. Test plan: - ``pre-commit run`` clean on all four modified files. - Spot-check with mock ``model_config``: ``max_num_tokens=512`` -> MegaMoEDeepGemm; ``max_num_tokens=8192`` -> TRTLLMGenFusedMoE; ``max_num_tokens=1024`` (boundary) -> MegaMoEDeepGemm. - Follow-up: extend ``TestDeepSeekV4Flash::test_nvfp4_4gpus_static_eplb`` to parametrize ``MEGAMOE_AUTO`` and verify both branches load + run GSM8K on a real prefill/decode mixed yaml. Signed-off-by: Mingyang Hao <mingyangh@nvidia.com>
mingyangHao
force-pushed
the
fix/megamoe-engine-max-tokens
branch
from
May 28, 2026 09:26
606aa08 to
b13075a
Compare
Collaborator
Author
|
/bot run |
Collaborator
|
PR_Github #50751 [ run ] triggered by Bot. Commit: |
Collaborator
|
PR_Github #50751 [ run ] completed with state |
jieli-matrix
approved these changes
Jun 3, 2026
Collaborator
|
Close this PR temporarily. |
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.
The MegaMoEDeepGemm wrapper previously read
model_config.moe_max_num_tokensto size its DG SymmBuffer pool and then divided byep_size(per #14213) to undo the auto-multiply thatModelConfig.__post_init__applies for allgather-based backends.Under
FUSED_COMMscheduler (always used by mega_moe),FusedCommMoEScheduler._strip_adp_paddingslicesxto the local rank's tokens beforerun_moe, so the per-callx.shape[0]is bounded by the engine's per-instancemax_num_tokensand never bydp_size * max_num_tokens. The auto-multiply is therefore semantically wrong for mega_moe and the divide is a workaround for the wrong source.Two failure modes of the multiply-then-divide dance:
If a deployed binary lacks the divide (e.g. binaries built before [None][fix] Avoid dp_size x ep_size double-count in MegaMoEDeepGemm SymmBuffer #14213 landed on this branch), the auto-multiplied value is used as- is, so the cubin's
num_max_tokens_per_rankis baked atdp_size * engine.max_num_tokensinstead ofengine.max_num_tokens(e.g. 65664 vs 8448 on DSv4-Pro @ DEP=8). Measured cost on B300 DEP=8, balanced 8192 tok/rank: 4.03 ms -> 3.39 ms median per-call (-19%), plus the SymmBuffer pool drops from ~3.6 GB to ~470 MB (-7.6x).If a user explicitly sets
moe_config.max_num_tokensin yaml,__post_init__skips the auto-multiply, but the wrapper still divides, so the per-rank cap becomesyaml_value / ep_size(too small by ep_size). The line-667 runtime assert then fires for every request whose per-rank tokens exceed that.Read
model_config.max_num_tokensdirectly instead. The other consumers ofmoe_max_num_tokens(fused_moe_cutlass, fused_moe_deepgemm, communication_factory) keep the auto-multiplied value, which is correct for those allgather paths.Test plan:
pre-commit runclean on the modified file (ruff, ruff-format, codespell, copyright, DCO).@coderabbitai summary
Description
Test Coverage
PR Checklist
Please review the following before submitting your PR:
PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.
PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.
Test cases are provided for new code paths (see test instructions)
If PR introduces API changes, an appropriate PR label is added - either
api-compatibleorapi-breaking. Forapi-breaking, includeBREAKINGin the PR title.Any new dependencies have been scanned for license and vulnerabilities
CODEOWNERS updated if ownership changes
Documentation updated as needed
Update tava architecture diagram if there is a significant design change in PR.
The reviewers assigned automatically/manually are appropriate for the PR.
Please check this after reviewing the above items as appropriate for this PR.
GitHub Bot Help
To see a list of available CI bot commands, please comment
/bot help.