[None][fix] Avoid dp_size x ep_size double-count in MegaMoEDeepGemm SymmBuffer - #14213
Merged
lfr-0531 merged 2 commits intoMay 19, 2026
Conversation
…ymmBuffer Under attention DP, ``ModelConfig.__post_init__`` sets ``moe_max_num_tokens = max_num_tokens * dp_size``. The DG SymmBuffer allocator then scales the per-rank pool by ``num_ranks`` (= ep_size, which equals dp_size in the supported full-ADP topology asserted at construction). This double-counts the EP factor: the worst-case pool size becomes ``dp_size * ep_size * max_num_tokens * num_topk`` instead of ``dp_size * max_num_tokens * num_topk``. For a DEP=32 DSv4 run with max_num_tokens=1024, the over-sized SymmBuffer was 95 GiB per rank, OOMing the first two GEN nodes during weight load even on a 276 GiB GPU. Dividing the passed ``num_max_tokens_per_rank`` by ``ep_size`` when ADP is enabled cuts the buffer to ~3 GiB without changing correctness: the DG kernel still covers the worst case where every cluster token routes to one rank's local experts. Non-ADP paths (``use_dp == False``) and ADP+EP=1 are untouched. Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
Collaborator
Author
|
/bot run --disable-fail-fast |
Collaborator
|
PR_Github #48746 [ run ] triggered by Bot. Commit: |
Collaborator
|
PR_Github #48746 [ run ] completed with state |
Barry-Delaney
approved these changes
May 18, 2026
Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
Collaborator
|
/bot skip --comment "CI passed before, and only changed the code format in the latest commit." |
Collaborator
|
PR_Github #49048 [ skip ] triggered by Bot. Commit: |
Collaborator
|
PR_Github #49048 [ skip ] completed with state |
mingyangHao
added a commit
to mingyangHao/TensorRT-LLM
that referenced
this pull request
May 27, 2026
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>
1 task
mingyangHao
added a commit
to mingyangHao/TensorRT-LLM
that referenced
this pull request
May 28, 2026
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>
lfr-0531
pushed a commit
to lfr-0531/TensorRT-LLM
that referenced
this pull request
May 29, 2026
…ymmBuffer (NVIDIA#14213) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com> (cherry picked from commit 5a72fb3) Signed-off-by: Fanrong Li <lfr-0531@users.noreply.github.com>
lfr-0531
pushed a commit
to lfr-0531/TensorRT-LLM
that referenced
this pull request
Jun 1, 2026
…ymmBuffer (NVIDIA#14213) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com> (cherry picked from commit 5a72fb3) Signed-off-by: Fanrong Li <lfr-0531@users.noreply.github.com>
lfr-0531
pushed a commit
to lfr-0531/TensorRT-LLM
that referenced
this pull request
Jun 3, 2026
…ymmBuffer (NVIDIA#14213) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com> (cherry picked from commit 5a72fb3) Signed-off-by: Fanrong Li <lfr-0531@users.noreply.github.com>
lfr-0531
pushed a commit
to lfr-0531/TensorRT-LLM
that referenced
this pull request
Jun 7, 2026
…ymmBuffer (NVIDIA#14213) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com> (cherry picked from commit 5a72fb3) Signed-off-by: Fanrong Li <lfr-0531@users.noreply.github.com>
lfr-0531
pushed a commit
to lfr-0531/TensorRT-LLM
that referenced
this pull request
Jun 10, 2026
…ymmBuffer (NVIDIA#14213) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
lfr-0531
pushed a commit
to lfr-0531/TensorRT-LLM
that referenced
this pull request
Jun 11, 2026
…ymmBuffer (NVIDIA#14213) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
lfr-0531
pushed a commit
to lfr-0531/TensorRT-LLM
that referenced
this pull request
Jun 12, 2026
…ymmBuffer (NVIDIA#14213) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
lfr-0531
pushed a commit
to lfr-0531/TensorRT-LLM
that referenced
this pull request
Jun 12, 2026
…ymmBuffer (NVIDIA#14213) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com> (cherry picked from commit 5a72fb3) Signed-off-by: Fanrong Li <lfr-0531@users.noreply.github.com>
lfr-0531
pushed a commit
to lfr-0531/TensorRT-LLM
that referenced
this pull request
Jun 13, 2026
…ymmBuffer (NVIDIA#14213) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com> (cherry picked from commit 5a72fb3) Signed-off-by: Fanrong Li <lfr-0531@users.noreply.github.com>
lfr-0531
pushed a commit
to lfr-0531/TensorRT-LLM
that referenced
this pull request
Jun 16, 2026
…ymmBuffer (NVIDIA#14213) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com> (cherry picked from commit 5a72fb3) Signed-off-by: Fanrong Li <lfr-0531@users.noreply.github.com>
lfr-0531
pushed a commit
to lfr-0531/TensorRT-LLM
that referenced
this pull request
Jun 17, 2026
…ymmBuffer (NVIDIA#14213) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com> (cherry picked from commit 5a72fb3) Signed-off-by: Fanrong Li <lfr-0531@users.noreply.github.com>
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.
Summary
When attention DP is enabled, the DG MegaMoE
SymmBufferper-rank poolis sized as
dp_size * ep_size * max_num_tokens * num_topkinstead ofdp_size * max_num_tokens * num_topk— the EP factor is double-counted.On DEP=32 DSv4 (max_num_tokens=1024, num_topk=6, hidden=7168,
moe_intermediate=3072) this inflates the SymmBuffer to 95 GiB per rank
and OOMs the GEN ranks during model load on a 276 GiB GB300 GPU.
Root cause:
ModelConfig.__post_init__pre-multipliesmoe_max_num_tokens = max_num_tokens * dp_size.MegaMoEDeepGemm.__init__then forwards this value to
get_symm_buffer_for_mega_moe(...), whoselayout::Workspace/get_num_max_pool_tokens(DeepGEMM) furtherscales the pool by
num_ranks(=ep_size). Because the supportedfull-ADP topology asserts
ep_size == parallel_size == dp_size, thedp_sizefactor is applied twice.Fix: divide
self.max_num_tokensbyep_size(ceil) whenuse_dpis true andep_size > 1. The DG kernel still sees a poolsized for the worst case where every cluster token routes to one rank's
local experts — but the EP factor is no longer doubled.
Effect (theoretical, DSv4 routed expert, full ADP, max_num_tokens=1024):
Non-ADP paths (
use_dp == False) and ADP+EP=1 paths are not touched.Test plan
on rank 3 / rank 7 — verify SymmBuffer line reports ~3 GiB and GEN
workers reach the benchmark loop.
enable_attention_dp: false) MegaMoEconfig to confirm
self.max_num_tokensis unchanged in thatpath.
tests/unittest/_torch/modules/test_fused_moe.pyandtests/unittest/_torch/multi_gpu_modeling/test_deepseek.py—none of them exercise the ADP+EP>1 path covered by the fix, but
keep them green.
🤖 Generated with Claude Code