Skip to content

Commit b69936c

Browse files
committed
fix(performance): apply recipe env in container
1 parent 76f5f20 commit b69936c

3 files changed

Lines changed: 92 additions & 22 deletions

File tree

‎scripts/performance/perf_plugins.py‎

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@
3737

3838

3939
try:
40-
from utils.utils import WorkloadBaseConfig, get_workload_base_config
40+
from utils.utils import WorkloadBaseConfig
4141
except (ImportError, ModuleNotFoundError):
42-
from .utils.utils import WorkloadBaseConfig, get_workload_base_config
42+
from .utils.utils import WorkloadBaseConfig
4343

4444
logger: logging.Logger = logging.getLogger(__name__)
4545
NSYS_SQLITE_EXPORT_ARG = "--export=sqlite"
@@ -495,16 +495,13 @@ def get_lock_gpu_freq_srun_cmd(job_dir, freq_mhz):
495495
else lock_freq_cmd
496496
)
497497

498-
def setup(self, task: Union["run.Partial", "run.Script"], executor: "run.Executor"):
499-
"""Enable the performance environment settings"""
500-
workload_base_config = get_workload_base_config(
501-
self.model_family_name,
502-
self.model_recipe_name,
503-
self.gpu,
504-
self.compute_dtype,
505-
self.train_task,
506-
self.config_variant,
507-
)
498+
def setup_recipe_environment(
499+
self,
500+
task: Union["run.Partial", "run.Script", None],
501+
executor: "run.Executor",
502+
workload_base_config: WorkloadBaseConfig,
503+
) -> None:
504+
"""Apply recipe-dependent environment settings inside the training container."""
508505
tp_size = self.tp_size if self.tp_size is not None else workload_base_config.tensor_model_parallel_size
509506
pp_size = self.pp_size if self.pp_size is not None else workload_base_config.pipeline_model_parallel_size
510507
cp_size = self.cp_size if self.cp_size is not None else workload_base_config.context_parallel_size
@@ -554,15 +551,6 @@ def setup(self, task: Union["run.Partial", "run.Script"], executor: "run.Executo
554551
nccl_pp_comm_chunksize = None
555552
self._set_nccl_pp_comm_chunksize(task, executor, nccl_pp_comm_chunksize, pp_size)
556553

557-
# Configure manual garbage collection
558-
self._set_manual_gc(task, executor, self.enable_manual_gc, self.manual_gc_interval)
559-
560-
# Improve perf by steering power to tensor cores, may not work on all systems
561-
self._set_vboost(task, executor, self.enable_vboost)
562-
563-
# Lock GPU graphics clock frequency for stable performance measurements
564-
self._set_lock_gpu_freq(task, executor, self.lock_gpu_freq)
565-
566554
# Set model-specific environment variables
567555
self._set_model_specific_environment_variables(
568556
task,
@@ -582,6 +570,14 @@ def setup(self, task: Union["run.Partial", "run.Script"], executor: "run.Executo
582570
if self.deterministic:
583571
self._set_determinism_env_vars(executor)
584572

573+
def setup(self, task: Union["run.Partial", "run.Script"], executor: "run.Executor"):
574+
"""Apply launcher-only settings without importing Megatron-Bridge on the login node."""
575+
# Recipe-dependent environment variables are applied by run_script_with_env.py
576+
# inside the training container, where the flat recipe can be imported safely.
577+
self._set_manual_gc(task, executor, self.enable_manual_gc, self.manual_gc_interval)
578+
self._set_vboost(task, executor, self.enable_vboost)
579+
self._set_lock_gpu_freq(task, executor, self.lock_gpu_freq)
580+
585581

586582
@dataclass
587583
class PyTorchProfilerPluginScriptArgs:
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Resolve recipe-dependent perf environment variables, then exec run_script.py.
16+
17+
This entrypoint runs inside the training container. It keeps recipe imports off
18+
the dependency-light login node while ensuring environment variables are present
19+
before the training Python process imports Torch, Transformer Engine, or Megatron.
20+
"""
21+
22+
import os
23+
import sys
24+
from pathlib import Path
25+
26+
from argument_parser import parse_cli_args
27+
from perf_plugins import PerfEnvPlugin
28+
from utils.utils import _workload_base_config_from_recipe, get_perf_recipe_by_name
29+
30+
31+
class _EnvironmentExecutor:
32+
"""Minimal executor adapter used by PerfEnvPlugin's environment helpers."""
33+
34+
def __init__(self) -> None:
35+
self.env_vars = os.environ
36+
37+
38+
def main() -> None:
39+
"""Apply the selected recipe's environment and replace this process with run_script.py."""
40+
parser = parse_cli_args()
41+
args, _ = parser.parse_known_args()
42+
43+
recipe = get_perf_recipe_by_name(
44+
model_recipe_name=args.model_recipe_name,
45+
task=args.task,
46+
num_gpus=args.num_gpus,
47+
gpu=args.gpu,
48+
precision=args.compute_dtype,
49+
config_variant=args.config_variant,
50+
)
51+
workload_base_config = _workload_base_config_from_recipe(recipe, num_gpus=args.num_gpus)
52+
53+
plugin = PerfEnvPlugin(
54+
moe_a2a_overlap=args.moe_a2a_overlap,
55+
tp_size=args.tensor_model_parallel_size,
56+
pp_size=args.pipeline_model_parallel_size,
57+
cp_size=args.context_parallel_size,
58+
ep_size=args.expert_model_parallel_size,
59+
model_family_name=args.model_family_name,
60+
model_recipe_name=args.model_recipe_name,
61+
gpu=args.gpu,
62+
compute_dtype=args.compute_dtype,
63+
train_task=args.task,
64+
config_variant=args.config_variant,
65+
deterministic=args.deterministic,
66+
)
67+
plugin.setup_recipe_environment(None, _EnvironmentExecutor(), workload_base_config)
68+
69+
run_script = Path(__file__).with_name("run_script.py")
70+
os.execvpe(sys.executable, [sys.executable, str(run_script), *sys.argv[1:]], dict(os.environ))
71+
72+
73+
if __name__ == "__main__":
74+
main()

‎scripts/performance/setup_experiment.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
from .perf_plugins import NsysPlugin, PerfEnvPlugin, PyTorchProfilerPlugin
5353

5454
SCRIPT_DIR = Path(__file__).parent.resolve()
55-
ENTRYPOINT_PEFORMANCE = "run_script.py"
55+
ENTRYPOINT_PEFORMANCE = "run_script_with_env.py"
5656
ENTRYPOINT_RECIPE = "run_recipe.py"
5757

5858
logging.basicConfig(level=logging.DEBUG)

0 commit comments

Comments
 (0)