Skip to content

Commit 7213568

Browse files
authored
perf(recipe): enable Nemotron 3.5 MXFP8 full graphs on GB300 and VR200 (#6289)
Signed-off-by: Malay Nagda <malayn@nvidia.com>
1 parent 67a9b0d commit 7213568

4 files changed

Lines changed: 81 additions & 9 deletions

File tree

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
nemotron_3_super_bf16_with_nvfp4_mixed,
3333
nemotron_3_ultra_bf16_with_nvfp4_mixed,
3434
)
35+
from megatron.bridge.utils.cuda_graph import set_full_iteration_cuda_graph
3536

3637

3738
_TE_QUANT_CFG_PATH = Path(__file__).with_name("te_quant.cfg")
@@ -142,6 +143,20 @@ def _enable_nemotron_3_super_full_iteration(cfg: ConfigContainer) -> None:
142143
cfg.model.delay_wgrad_compute = False
143144

144145

146+
def _enable_nemotron_3_5_lightning_full_iteration(cfg: ConfigContainer) -> None:
147+
"""Enable full-iteration capture with static MoE buffers for Lightning."""
148+
set_full_iteration_cuda_graph(cfg.model)
149+
cfg.rng.te_rng_tracker = True
150+
cfg.model.use_te_rng_tracker = True
151+
152+
# Static receive capacity avoids dispatcher CPU synchronization during capture.
153+
# The training loop retries capacity overflows without padding.
154+
cfg.model.moe_expert_rank_capacity_factor = 1.5
155+
cfg.model.moe_use_grouped_tensor = True
156+
cfg.model.moe_paged_stash = False
157+
cfg.model.offload_modules = []
158+
159+
145160
def _apply_nemotron_3_ultra_perf_defaults(cfg: ConfigContainer) -> None:
146161
"""Apply shared Nemotron 3 Ultra perf defaults after recipe-specific overrides."""
147162

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
_apply_nemotron_3_ultra_fsdp_hsdp,
2424
_apply_nemotron_3_ultra_perf_defaults,
2525
_benchmark_common,
26+
_enable_nemotron_3_5_lightning_full_iteration,
2627
_enable_nemotron_3_super_full_iteration,
2728
_nemotron_3_super_nvfp4_precision,
2829
_nemotron_3_ultra_nvfp4_precision,
@@ -694,21 +695,19 @@ def _build_nemotron_3_5_lightning_gb300_mxfp8() -> ConfigContainer:
694695

695696

696697
def nemotron_3_5_lightning_pretrain_8gpu_gb300_fp8mx_config() -> ConfigContainer:
697-
"""Nemotron 3.5 Lightning pretrain: 8× GB300, MXFP8."""
698+
"""Nemotron 3.5 Lightning pretrain: 8× GB300, MXFP8 with full-iteration CUDA graph."""
698699
cfg = _build_nemotron_3_5_lightning_gb300_mxfp8()
699700
cfg.model.recompute_modules = []
700701
cfg.model.use_transformer_engine_op_fuser = True
701702
cfg.mixed_precision.fp8_dot_product_attention = True
702703
_enable_ncclep(cfg)
703-
# Device-side expert token counts: the legacy grouped MLP path syncs tokens_per_expert to the
704-
# host every layer, which serializes the CPU behind the GPU when dispatch is fast.
705-
cfg.model.moe_use_grouped_tensor = True
704+
_enable_nemotron_3_5_lightning_full_iteration(cfg)
706705
cfg.env_vars = {
707706
**COMMON_PERF_ENV_VARS,
708707
"CUDA_DEVICE_MAX_CONNECTIONS": 32,
709708
"NCCL_GRAPH_REGISTER": 0,
710-
"PYTORCH_CUDA_ALLOC_CONF": "expandable_segments:True",
711-
"TORCH_NCCL_AVOID_RECORD_STREAMS": 1,
709+
"PYTORCH_CUDA_ALLOC_CONF": "expandable_segments:True,graph_capture_record_stream_reuse:True",
710+
"TORCH_NCCL_AVOID_RECORD_STREAMS": 0,
712711
"NCCL_NVLS_ENABLE": 0,
713712
# NCCL EP dispatcher mode and one GPU per rank.
714713
"NCCL_EP_HT_EM_PULL_PUSH": 1,

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from megatron.bridge.perf_recipes.environment import COMMON_PERF_ENV_VARS
1717
from megatron.bridge.perf_recipes.nemotronh.common import (
1818
ConfigContainer,
19+
_enable_nemotron_3_5_lightning_full_iteration,
1920
)
2021
from megatron.bridge.perf_recipes.nemotronh.gb300.nemotronh import (
2122
_build_nemotron_3_5_lightning_gb300_bf16,
@@ -320,19 +321,20 @@ def nemotron_3_5_lightning_pretrain_8gpu_vr200_bf16_config() -> ConfigContainer:
320321

321322

322323
def nemotron_3_5_lightning_pretrain_8gpu_vr200_fp8mx_config() -> ConfigContainer:
323-
"""Nemotron 3.5 Lightning pretrain: 8× VR200, MXFP8 (alias of GB300)."""
324+
"""Nemotron 3.5 Lightning pretrain: 8× VR200, MXFP8 with full-iteration CUDA graph."""
324325
cfg = _build_nemotron_3_5_lightning_gb300_mxfp8()
325326
cfg.model.recompute_modules = []
326327
cfg.model.use_transformer_engine_op_fuser = True
327328
cfg.mixed_precision.fp8_dot_product_attention = True
329+
_enable_nemotron_3_5_lightning_full_iteration(cfg)
328330

329331
# Keep the VR200 launch environment explicit instead of inheriting it from GB300.
330332
cfg.env_vars = {
331333
**COMMON_PERF_ENV_VARS,
332334
"CUDA_DEVICE_MAX_CONNECTIONS": 32,
333335
"NCCL_GRAPH_REGISTER": 0,
334-
"PYTORCH_CUDA_ALLOC_CONF": "expandable_segments:True",
335-
"TORCH_NCCL_AVOID_RECORD_STREAMS": 1,
336+
"PYTORCH_CUDA_ALLOC_CONF": "expandable_segments:True,graph_capture_record_stream_reuse:True",
337+
"TORCH_NCCL_AVOID_RECORD_STREAMS": 0,
336338
"NCCL_NVLS_ENABLE": 0,
337339
"NUM_OF_HYBRID_EP_RANKS_PER_NVLINK_DOMAIN": 8,
338340
"NUM_OF_TOKENS_PER_CHUNK_COMBINE_API": 128,

‎tests/unit_tests/recipes/test_nemotron_3_5_lightning_perf_recipes.py‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
nemotron_3_nano_pretrain_16gpu_h100_fp8cs_config,
5858
)
5959
from megatron.bridge.training.config import ConfigContainer
60+
from megatron.bridge.utils.cuda_graph import cuda_graph_module_names, is_full_iteration_cuda_graph
6061

6162

6263
pytestmark = pytest.mark.unit
@@ -107,6 +108,10 @@
107108
nemotron_3_5_lightning_pretrain_8gpu_gb200_fp8mx_fsdp_config,
108109
nemotron_3_5_lightning_pretrain_8gpu_gb300_fp8mx_fsdp_config,
109110
)
111+
_FULL_ITERATION_MXFP8_RECIPES = (
112+
nemotron_3_5_lightning_pretrain_8gpu_gb300_fp8mx_config,
113+
nemotron_3_5_lightning_pretrain_8gpu_vr200_fp8mx_config,
114+
)
110115
_VR200_RECIPES = (
111116
nemotron_3_5_lightning_pretrain_8gpu_vr200_bf16_config,
112117
nemotron_3_5_lightning_pretrain_8gpu_vr200_fp8mx_config,
@@ -344,6 +349,12 @@ def test_nemotron_3_5_perf_recipes_inherit_nemotron_3_policy(
344349

345350
if recipe_factory in _B_MXFP8_RECIPES:
346351
assert cfg.env_vars == {**base_cfg.env_vars, "NVTE_CUTEDSL_FUSED_GROUPED_MLP": 1}
352+
elif recipe_factory in _FULL_ITERATION_MXFP8_RECIPES:
353+
assert cfg.env_vars == {
354+
**base_cfg.env_vars,
355+
"PYTORCH_CUDA_ALLOC_CONF": "expandable_segments:True,graph_capture_record_stream_reuse:True",
356+
"TORCH_NCCL_AVOID_RECORD_STREAMS": 0,
357+
}
347358
elif recipe_factory is not nemotron_3_5_lightning_pretrain_16gpu_h100_bf16_config:
348359
assert cfg.env_vars == base_cfg.env_vars
349360
assert cfg.model.calculate_per_token_loss == base_cfg.model.calculate_per_token_loss
@@ -394,6 +405,41 @@ def test_gb_mxfp8_enables_cutedsl_fusion(recipe_factory: Callable[[], ConfigCont
394405
assert cfg.comm_overlap.delay_wgrad_compute is False
395406

396407

408+
@pytest.mark.parametrize("recipe_factory", _FULL_ITERATION_MXFP8_RECIPES, ids=lambda recipe: recipe.__name__)
409+
def test_mxfp8_full_iteration_graph_config(recipe_factory: Callable[[], ConfigContainer]) -> None:
410+
"""Lightning full-iteration recipes satisfy graph and static MoE buffer constraints."""
411+
cfg = recipe_factory()
412+
413+
assert cfg.model.cuda_graph_impl == "full_iteration"
414+
assert cfg.model.cuda_graph_scope is None
415+
assert cfg.model.cuda_graph_modules == []
416+
assert is_full_iteration_cuda_graph(cfg.model)
417+
assert cfg.model.use_te_rng_tracker is True
418+
assert cfg.rng.te_rng_tracker is True
419+
assert cfg.rerun_state_machine.check_for_nan_in_loss is False
420+
assert cfg.ddp.check_for_nan_in_grad is False
421+
assert cfg.model.recompute_granularity is None
422+
assert cfg.model.offload_modules == []
423+
assert cfg.model.moe_expert_rank_capacity_factor == 1.5
424+
assert cfg.model.moe_use_grouped_tensor is True
425+
assert cfg.model.moe_paged_stash is False
426+
assert cfg.env_vars["TORCH_NCCL_AVOID_RECORD_STREAMS"] == 0
427+
assert "graph_capture_record_stream_reuse:True" in cfg.env_vars["PYTORCH_CUDA_ALLOC_CONF"]
428+
assert cfg.env_vars["NVTE_CUTEDSL_FUSED_GROUPED_MLP"] == 1
429+
assert cfg.env_vars["CUDNNFE_CLUSTER_OVERLAP_MARGIN"] == 8
430+
assert cfg.model.use_transformer_engine_op_fuser is True
431+
assert cfg.model.moe_mlp_glu_interleave_size is None
432+
assert cfg.model.high_priority_a2a_comm_stream is False
433+
assert cfg.model.moe_hybridep_num_sms_preprocessing == 108
434+
assert cfg.mixed_precision.fp8_dot_product_attention is True
435+
assert cfg.comm_overlap.overlap_moe_expert_parallel_comm is False
436+
assert cfg.comm_overlap.delay_wgrad_compute is False
437+
438+
# Validate against MCore as well as checking the unfinalized recipe settings.
439+
cfg.model.finalize()
440+
assert is_full_iteration_cuda_graph(cfg.model)
441+
442+
397443
@pytest.mark.parametrize("recipe_factory", _GB_FSDP_RECIPES, ids=lambda recipe: recipe.__name__)
398444
def test_gb_mxfp8_fsdp_skips_cutedsl_fusion(recipe_factory: Callable[[], ConfigContainer]) -> None:
399445
"""The Lightning GB MXFP8 FSDP variants remain outside the CutDSL tuning scope."""
@@ -542,6 +588,14 @@ def test_gb200_perf_recipe_topology(recipe_factory: Callable[[], ConfigContainer
542588
assert cfg.env_vars["NVLINK_DOMAIN_SIZE"] == 72
543589
assert cfg.env_vars["USE_MNNVL"] == 1
544590

591+
if recipe_factory is nemotron_3_5_lightning_pretrain_8gpu_gb200_fp8mx_config:
592+
assert cfg.model.cuda_graph_impl == "transformer_engine"
593+
assert cuda_graph_module_names(cfg.model) == ["attn", "mamba", "moe_router", "moe_preprocess"]
594+
assert cfg.model.moe_expert_rank_capacity_factor is None
595+
assert cfg.model.moe_paged_stash is False
596+
assert cfg.env_vars["PYTORCH_CUDA_ALLOC_CONF"] == "expandable_segments:True"
597+
assert cfg.env_vars["TORCH_NCCL_AVOID_RECORD_STREAMS"] == 1
598+
545599

546600
@pytest.mark.parametrize("recipe_factory", _GB300_RECIPES, ids=lambda recipe: recipe.__name__)
547601
def test_gb300_perf_recipe_topology(recipe_factory: Callable[[], ConfigContainer]) -> None:
@@ -619,6 +673,8 @@ def test_gb_fsdp_perf_recipe_defaults(recipe_factory: Callable[[], ConfigContain
619673
assert cfg.model.cuda_graph_impl == "none"
620674
assert cfg.model.cuda_graph_scope is None
621675
assert cfg.model.cuda_graph_modules == []
676+
assert cfg.model.moe_expert_rank_capacity_factor is None
677+
assert cfg.model.moe_paged_stash is False
622678
assert cfg.model.init_model_with_meta_device is True
623679

624680
assert cfg.mixed_precision.reuse_grad_buf_for_mxfp8_param_ag is False

0 commit comments

Comments
 (0)