Skip to content

Commit 2610525

Browse files
malay-nagdaclaude
andcommitted
perf(ncclep): right-size the NCCL EP receive budget
The NCCL EP receive buffer is sized at moe_expert_rank_capacity_factor x the ideal token count, and every MoE activation saved for backward inherits that padding. At 1.5 that accounted for 86.8 GB of the 114.1 GB step peak on nemotron_3_nano_8gpu_gb300_bf16 (+45.9 GB mem-max-allocated vs the HybridEP baseline) and 135.3 GB on qwen3_30b_a3b gb300 bf16, which OOMed. These recipes set moe_router_force_load_balancing, so the routing is balanced by construction. Measured against the ragged HybridEP receive buffers, the worst case is 1.0072x the ideal token count over 2208 samples for nemotron_3_nano and 1.0050x over 930 samples for qwen3_30b_a3b. Drop the factor to 1.05, which still leaves 7x (nemotron_3_nano) to 10x (qwen3_30b_a3b) the observed excess and recovers ~26 GB and ~40 GB respectively. PagedStashRunner is wired on the capacity factor rather than on paged stashing, so if a routing ever does exceed the static budget it replays the step dropless and grows the budget: an underestimate costs a rerun, not correctness. Also gate moe_paged_stash on the quantized recipes. PagedStashManager only stashes tensors carrying TE's grouped_tensor_scale_inv attribute, so in BF16 nothing is ever stashed and the run logs "Paged stash: max_tokens_dict is None, skipping stash buffer allocation" - it was pure hook overhead. The MXFP8 recipes keep it, where it allocates a real pool and does cut the transient peak. Signed-off-by: Malay Nagda <malayn@nvidia.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 8af2c24 commit 2610525

6 files changed

Lines changed: 34 additions & 14 deletions

File tree

‎src/megatron/bridge/perf_recipes/nemotronh/common.py‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,13 @@ def _enable_ncclep(cfg: ConfigContainer, *, mxfp8: bool, moe_a2a_overlap: bool)
8787
cfg.comm_overlap.delay_wgrad_compute = False
8888

8989
cfg.model.offload_modules = []
90-
cfg.model.moe_paged_stash = True
91-
cfg.model.moe_expert_rank_capacity_factor = 1.5
90+
# The static receive buffer is sized at capacity_factor x the ideal token count, and every MoE
91+
# activation saved for backward inherits that padding. These recipes force-balance the router,
92+
# so the measured worst case is only 1.008x ideal; 1.5 padded all of it by 50%. PagedStashRunner
93+
# replays the step dropless and grows the budget if a routing ever exceeds this.
94+
cfg.model.moe_expert_rank_capacity_factor = 1.05
95+
# Paged stashing only captures TE's quantized grouped tensors, so it is a no-op outside MXFP8.
96+
cfg.model.moe_paged_stash = mxfp8
9297
cfg.model.moe_paged_stash_buffer_size_factor_cuda = 1.2
9398
cfg.model.moe_paged_stash_buffer_size_factor_cpu = 1.0
9499

‎src/megatron/bridge/perf_recipes/qwen/common.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,11 @@ def _enable_ncclep_full_iteration_mxfp8(cfg: ConfigContainer) -> None:
7070
cfg.model.offload_modules = []
7171
cfg.model.moe_pad_experts_for_cuda_graph_inference = True
7272
cfg.model.moe_paged_stash = True
73-
cfg.model.moe_expert_rank_capacity_factor = 1.5
73+
# The static receive buffer is sized at capacity_factor x the ideal token count, and every MoE
74+
# activation saved for backward inherits that padding. These recipes force-balance the router,
75+
# so the measured worst case is only ~1.005x ideal; 1.5 padded all of it by 50%.
76+
# PagedStashRunner replays the step dropless and grows the budget if a routing exceeds this.
77+
cfg.model.moe_expert_rank_capacity_factor = 1.05
7478
cfg.model.moe_paged_stash_buffer_size_factor_cuda = 1.2
7579
cfg.model.moe_paged_stash_buffer_size_factor_cpu = 1.0
7680

‎src/megatron/bridge/perf_recipes/qwen/gb200/qwen3_moe.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,11 @@ def qwen3_30b_a3b_pretrain_8gpu_gb200_bf16_ncclep_config() -> ConfigContainer:
281281

282282
_benchmark_common(cfg, cross_entropy_impl="native")
283283

284-
cfg.model.moe_expert_rank_capacity_factor = 1.5
284+
# The static receive buffer is sized at capacity_factor x the ideal token count, and every MoE
285+
# activation saved for backward inherits that padding. This recipe force-balances the router, so
286+
# the measured worst case is only ~1.005x ideal; 1.5 padded all of it by 50%. PagedStashRunner
287+
# replays the step dropless and grows the budget if a routing ever exceeds this.
288+
cfg.model.moe_expert_rank_capacity_factor = 1.05
285289
cfg.model.moe_grouped_gemm = True
286290
cfg.model.use_transformer_engine_op_fuser = True
287291

‎src/megatron/bridge/perf_recipes/qwen/gb300/qwen3_moe.py‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,10 +291,13 @@ def qwen3_30b_a3b_pretrain_8gpu_gb300_bf16_ncclep_config() -> ConfigContainer:
291291
# cfg.model.moe_router_padding_for_quantization = True
292292

293293
cfg.model.offload_modules = []
294-
cfg.model.moe_paged_stash = True
295-
cfg.model.moe_expert_rank_capacity_factor = 1.5
296-
cfg.model.moe_paged_stash_buffer_size_factor_cuda = 1.2
297-
cfg.model.moe_paged_stash_buffer_size_factor_cpu = 1.0
294+
# Paged stashing only captures TE's quantized grouped tensors, so it is a no-op in BF16.
295+
cfg.model.moe_paged_stash = False
296+
# The static receive buffer is sized at capacity_factor x the ideal token count, and every MoE
297+
# activation saved for backward inherits that padding. This recipe force-balances the router, so
298+
# the measured worst case is only ~1.005x ideal; 1.5 padded all of it by 50%. PagedStashRunner
299+
# replays the step dropless and grows the budget if a routing ever exceeds this.
300+
cfg.model.moe_expert_rank_capacity_factor = 1.05
298301

299302
# Keep process settings next to the recipe so users can see the exact benchmark environment.
300303
cfg.env_vars = {

‎tests/unit_tests/recipes/test_nemotron_3_5_lightning_perf_recipes.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,7 @@ def test_ncclep_perf_recipe_defaults(recipe_factory: Callable[[], ConfigContaine
226226
assert cfg.model.moe_mlp_glu_interleave_size == 32
227227

228228
assert cfg.model.offload_modules == []
229-
assert cfg.model.moe_paged_stash is True
230-
assert cfg.model.moe_expert_rank_capacity_factor == 1.5
229+
assert cfg.model.moe_expert_rank_capacity_factor == 1.05
231230
assert cfg.model.moe_paged_stash_buffer_size_factor_cuda == 1.2
232231
assert cfg.model.moe_paged_stash_buffer_size_factor_cpu == 1.0
233232

@@ -248,8 +247,11 @@ def test_ncclep_perf_recipe_defaults(recipe_factory: Callable[[], ConfigContaine
248247

249248
if "fp8mx" in recipe_factory.__name__:
250249
assert cfg.model.moe_router_padding_for_quantization is True
250+
assert cfg.model.moe_paged_stash is True
251251
else:
252252
assert cfg.model.moe_router_padding_for_quantization is False
253+
# Paged stashing only captures TE's quantized grouped tensors, so it is a no-op in BF16.
254+
assert cfg.model.moe_paged_stash is False
253255

254256

255257
@pytest.mark.parametrize(

‎tests/unit_tests/recipes/test_qwen_perf_recipes.py‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def test_qwen3_30b_gb200_bf16_ncclep_config():
6868

6969
assert cfg.model.moe_token_dispatcher_type == "flex"
7070
assert cfg.model.moe_flex_dispatcher_backend == "ncclep"
71-
assert cfg.model.moe_expert_rank_capacity_factor == 1.5
71+
assert cfg.model.moe_expert_rank_capacity_factor == 1.05
7272
assert cfg.model.moe_grouped_gemm is True
7373
assert cfg.model.use_transformer_engine_op_fuser is True
7474
assert cfg.model.moe_ncclep_zero_copy is False
@@ -83,7 +83,7 @@ def test_qwen3_30b_gb200_mxfp8_ncclep_config():
8383

8484
assert cfg.model.moe_token_dispatcher_type == "flex"
8585
assert cfg.model.moe_flex_dispatcher_backend == "ncclep"
86-
assert cfg.model.moe_expert_rank_capacity_factor == 1.5
86+
assert cfg.model.moe_expert_rank_capacity_factor == 1.05
8787
assert cfg.model.moe_ncclep_zero_copy is False
8888
assert cfg.model.moe_paged_stash is True
8989
assert cfg.model.moe_grouped_gemm is True
@@ -101,7 +101,9 @@ def test_qwen3_30b_gb300_bf16_ncclep_config():
101101

102102
assert cfg.model.moe_token_dispatcher_type == "flex"
103103
assert cfg.model.moe_flex_dispatcher_backend == "ncclep"
104-
assert cfg.model.moe_expert_rank_capacity_factor == 1.5
104+
assert cfg.model.moe_expert_rank_capacity_factor == 1.05
105+
# Paged stashing only captures TE's quantized grouped tensors, so it is a no-op in BF16.
106+
assert cfg.model.moe_paged_stash is False
105107
assert cfg.model.moe_grouped_gemm is True
106108
assert cfg.model.use_transformer_engine_op_fuser is True
107109
assert cfg.model.moe_ncclep_zero_copy is False
@@ -119,7 +121,7 @@ def test_qwen3_30b_gb300_mxfp8_ncclep_config():
119121

120122
assert cfg.model.moe_token_dispatcher_type == "flex"
121123
assert cfg.model.moe_flex_dispatcher_backend == "ncclep"
122-
assert cfg.model.moe_expert_rank_capacity_factor == 1.5
124+
assert cfg.model.moe_expert_rank_capacity_factor == 1.05
123125
assert cfg.model.moe_ncclep_zero_copy is False
124126
assert cfg.model.moe_paged_stash is True
125127
assert cfg.model.moe_grouped_gemm is True

0 commit comments

Comments
 (0)