From 68ffdc37d05f55a5b5e482328f489c20851831f2 Mon Sep 17 00:00:00 2001 From: Juntao Wang Date: Mon, 2 Feb 2026 08:24:09 +0200 Subject: [PATCH 1/5] Fix nsys field merging behavior --- src/cloudai/models/scenario.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cloudai/models/scenario.py b/src/cloudai/models/scenario.py index 276cac2e5..b4b915ae7 100644 --- a/src/cloudai/models/scenario.py +++ b/src/cloudai/models/scenario.py @@ -108,7 +108,7 @@ def tdef_model_dump(self, by_alias: bool) -> dict: "extra_env_vars": self.extra_env_vars if self.extra_env_vars else None, "cmd_args": self.cmd_args.model_dump(by_alias=by_alias) if self.cmd_args else None, "git_repos": [repo.model_dump() for repo in self.git_repos] if self.git_repos else None, - "nsys": self.nsys.model_dump() if self.nsys else None, + "nsys": self.nsys.model_dump(exclude_unset=True) if self.nsys else None, } return {k: v for k, v in data.items() if v is not None} From 21772334ee1d05dbb28304cd20e6aa6230ad86b2 Mon Sep 17 00:00:00 2001 From: Juntao Wang Date: Mon, 2 Feb 2026 08:24:39 +0200 Subject: [PATCH 2/5] Add `TestNsysMerging` --- tests/test_test_scenario.py | 173 ++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/tests/test_test_scenario.py b/tests/test_test_scenario.py index c2af1373b..95d4787ba 100644 --- a/tests/test_test_scenario.py +++ b/tests/test_test_scenario.py @@ -515,3 +515,176 @@ def test_get_reporters_nccl(self): assert len(reporters) == 2 assert NcclTestPerformanceReportGenerationStrategy in reporters assert NcclTestPredictionReportGenerationStrategy in reporters + + +class TestNsysMerging: + """Tests for nsys configuration merging behavior.""" + + def test_nsys_partial_override_preserves_base_config( + self, test_scenario_parser: TestScenarioParser, slurm_system: SlurmSystem + ): + """When scenario specifies only some nsys fields, base config fields should be preserved.""" + from cloudai.core import NsysConfiguration + + test_scenario_parser.test_mapping = { + "nccl": NCCLTestDefinition( + name="nccl", + description="desc", + test_template_name="NcclTest", + cmd_args=NCCLCmdArgs(docker_image_url="fake://url/nccl"), + nsys=NsysConfiguration( + enable=True, + nsys_binary="/custom/nsys", + output="/base/output", + trace="cuda,nvtx", + sample="cpu", + ), + ) + } + model = TestScenarioModel.model_validate( + toml.loads( + """ + name = "test" + + [[Tests]] + id = "1" + test_name = "nccl" + + [Tests.nsys] + output = "/scenario/output" + """ + ) + ) + tdef = test_scenario_parser._prepare_tdef(model.tests[0]) + + assert tdef.nsys is not None + # The output should be overridden from scenario + assert tdef.nsys.output == "/scenario/output" + # But other fields should be preserved from base config + assert tdef.nsys.nsys_binary == "/custom/nsys" + assert tdef.nsys.trace == "cuda,nvtx" + assert tdef.nsys.sample == "cpu" + assert tdef.nsys.enable is True + + def test_nsys_multiple_fields_override( + self, test_scenario_parser: TestScenarioParser, slurm_system: SlurmSystem + ): + """When scenario specifies multiple nsys fields, all specified should override.""" + from cloudai.core import NsysConfiguration + + test_scenario_parser.test_mapping = { + "nccl": NCCLTestDefinition( + name="nccl", + description="desc", + test_template_name="NcclTest", + cmd_args=NCCLCmdArgs(docker_image_url="fake://url/nccl"), + nsys=NsysConfiguration( + enable=True, + nsys_binary="/base/nsys", + output="/base/output", + trace="cuda", + force_overwrite=False, + ), + ) + } + model = TestScenarioModel.model_validate( + toml.loads( + """ + name = "test" + + [[Tests]] + id = "1" + test_name = "nccl" + + [Tests.nsys] + output = "/new/output" + force_overwrite = true + """ + ) + ) + tdef = test_scenario_parser._prepare_tdef(model.tests[0]) + + assert tdef.nsys is not None + # Specified fields should be overridden + assert tdef.nsys.output == "/new/output" + assert tdef.nsys.force_overwrite is True + # Unspecified fields should be preserved + assert tdef.nsys.nsys_binary == "/base/nsys" + assert tdef.nsys.trace == "cuda" + assert tdef.nsys.enable is True + + def test_nsys_scenario_adds_to_base_without_nsys( + self, test_scenario_parser: TestScenarioParser, slurm_system: SlurmSystem + ): + """When base has no nsys config, scenario nsys should be applied.""" + test_scenario_parser.test_mapping = { + "nccl": NCCLTestDefinition( + name="nccl", + description="desc", + test_template_name="NcclTest", + cmd_args=NCCLCmdArgs(docker_image_url="fake://url/nccl"), + # No nsys in base config + ) + } + model = TestScenarioModel.model_validate( + toml.loads( + """ + name = "test" + + [[Tests]] + id = "1" + test_name = "nccl" + + [Tests.nsys] + output = "/scenario/output" + trace = "cuda,nvtx" + """ + ) + ) + tdef = test_scenario_parser._prepare_tdef(model.tests[0]) + + assert tdef.nsys is not None + assert tdef.nsys.output == "/scenario/output" + assert tdef.nsys.trace == "cuda,nvtx" + # Default values should apply for unspecified fields + assert tdef.nsys.enable is True + assert tdef.nsys.nsys_binary == "nsys" + + def test_nsys_disable_override( + self, test_scenario_parser: TestScenarioParser, slurm_system: SlurmSystem + ): + """Scenario can disable nsys that was enabled in base config.""" + from cloudai.core import NsysConfiguration + + test_scenario_parser.test_mapping = { + "nccl": NCCLTestDefinition( + name="nccl", + description="desc", + test_template_name="NcclTest", + cmd_args=NCCLCmdArgs(docker_image_url="fake://url/nccl"), + nsys=NsysConfiguration( + enable=True, + output="/base/output", + ), + ) + } + model = TestScenarioModel.model_validate( + toml.loads( + """ + name = "test" + + [[Tests]] + id = "1" + test_name = "nccl" + + [Tests.nsys] + enable = false + """ + ) + ) + tdef = test_scenario_parser._prepare_tdef(model.tests[0]) + + assert tdef.nsys is not None + assert tdef.nsys.enable is False + # Output should still be preserved from base + assert tdef.nsys.output == "/base/output" From 46da5fe8de66cce31509df91bfbabfafaa760909 Mon Sep 17 00:00:00 2001 From: Juntao Wang Date: Mon, 2 Feb 2026 08:25:53 +0200 Subject: [PATCH 3/5] Update copyright year --- src/cloudai/models/scenario.py | 2 +- tests/test_test_scenario.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cloudai/models/scenario.py b/src/cloudai/models/scenario.py index b4b915ae7..751915095 100644 --- a/src/cloudai/models/scenario.py +++ b/src/cloudai/models/scenario.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES -# Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/test_test_scenario.py b/tests/test_test_scenario.py index 95d4787ba..e40bb59c9 100644 --- a/tests/test_test_scenario.py +++ b/tests/test_test_scenario.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES -# Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); From a3c6cf3ad23597c30f4dab44629b31bc4e5adcba Mon Sep 17 00:00:00 2001 From: Juntao Wang Date: Mon, 2 Feb 2026 08:38:34 +0200 Subject: [PATCH 4/5] Linting --- tests/test_test_scenario.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/test_test_scenario.py b/tests/test_test_scenario.py index e40bb59c9..4d571e0b3 100644 --- a/tests/test_test_scenario.py +++ b/tests/test_test_scenario.py @@ -566,9 +566,7 @@ def test_nsys_partial_override_preserves_base_config( assert tdef.nsys.sample == "cpu" assert tdef.nsys.enable is True - def test_nsys_multiple_fields_override( - self, test_scenario_parser: TestScenarioParser, slurm_system: SlurmSystem - ): + def test_nsys_multiple_fields_override(self, test_scenario_parser: TestScenarioParser, slurm_system: SlurmSystem): """When scenario specifies multiple nsys fields, all specified should override.""" from cloudai.core import NsysConfiguration @@ -650,9 +648,7 @@ def test_nsys_scenario_adds_to_base_without_nsys( assert tdef.nsys.enable is True assert tdef.nsys.nsys_binary == "nsys" - def test_nsys_disable_override( - self, test_scenario_parser: TestScenarioParser, slurm_system: SlurmSystem - ): + def test_nsys_disable_override(self, test_scenario_parser: TestScenarioParser, slurm_system: SlurmSystem): """Scenario can disable nsys that was enabled in base config.""" from cloudai.core import NsysConfiguration From 614bfd179e9a76a877691ba2ce3b8dc73f04635f Mon Sep 17 00:00:00 2001 From: Juntao Wang Date: Mon, 2 Feb 2026 08:46:50 +0200 Subject: [PATCH 5/5] Cleanup docstrings --- tests/test_test_scenario.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tests/test_test_scenario.py b/tests/test_test_scenario.py index 4d571e0b3..9e305d093 100644 --- a/tests/test_test_scenario.py +++ b/tests/test_test_scenario.py @@ -518,12 +518,9 @@ def test_get_reporters_nccl(self): class TestNsysMerging: - """Tests for nsys configuration merging behavior.""" - def test_nsys_partial_override_preserves_base_config( self, test_scenario_parser: TestScenarioParser, slurm_system: SlurmSystem ): - """When scenario specifies only some nsys fields, base config fields should be preserved.""" from cloudai.core import NsysConfiguration test_scenario_parser.test_mapping = { @@ -558,16 +555,13 @@ def test_nsys_partial_override_preserves_base_config( tdef = test_scenario_parser._prepare_tdef(model.tests[0]) assert tdef.nsys is not None - # The output should be overridden from scenario assert tdef.nsys.output == "/scenario/output" - # But other fields should be preserved from base config assert tdef.nsys.nsys_binary == "/custom/nsys" assert tdef.nsys.trace == "cuda,nvtx" assert tdef.nsys.sample == "cpu" assert tdef.nsys.enable is True def test_nsys_multiple_fields_override(self, test_scenario_parser: TestScenarioParser, slurm_system: SlurmSystem): - """When scenario specifies multiple nsys fields, all specified should override.""" from cloudai.core import NsysConfiguration test_scenario_parser.test_mapping = { @@ -603,10 +597,8 @@ def test_nsys_multiple_fields_override(self, test_scenario_parser: TestScenarioP tdef = test_scenario_parser._prepare_tdef(model.tests[0]) assert tdef.nsys is not None - # Specified fields should be overridden assert tdef.nsys.output == "/new/output" assert tdef.nsys.force_overwrite is True - # Unspecified fields should be preserved assert tdef.nsys.nsys_binary == "/base/nsys" assert tdef.nsys.trace == "cuda" assert tdef.nsys.enable is True @@ -614,7 +606,6 @@ def test_nsys_multiple_fields_override(self, test_scenario_parser: TestScenarioP def test_nsys_scenario_adds_to_base_without_nsys( self, test_scenario_parser: TestScenarioParser, slurm_system: SlurmSystem ): - """When base has no nsys config, scenario nsys should be applied.""" test_scenario_parser.test_mapping = { "nccl": NCCLTestDefinition( name="nccl", @@ -644,12 +635,10 @@ def test_nsys_scenario_adds_to_base_without_nsys( assert tdef.nsys is not None assert tdef.nsys.output == "/scenario/output" assert tdef.nsys.trace == "cuda,nvtx" - # Default values should apply for unspecified fields assert tdef.nsys.enable is True assert tdef.nsys.nsys_binary == "nsys" def test_nsys_disable_override(self, test_scenario_parser: TestScenarioParser, slurm_system: SlurmSystem): - """Scenario can disable nsys that was enabled in base config.""" from cloudai.core import NsysConfiguration test_scenario_parser.test_mapping = { @@ -682,5 +671,4 @@ def test_nsys_disable_override(self, test_scenario_parser: TestScenarioParser, s assert tdef.nsys is not None assert tdef.nsys.enable is False - # Output should still be preserved from base assert tdef.nsys.output == "/base/output"