Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin support #263

Open
wants to merge 50 commits into
base: main
Choose a base branch
from
Open

Plugin support #263

wants to merge 50 commits into from

Conversation

TaekyungHeo
Copy link
Member

@TaekyungHeo TaekyungHeo commented Oct 14, 2024

Summary

This PR introduces plugins to CloudAI. Plugins are tests that run either before or after each test in a test scenario. They are defined globally within a test scenario and are automatically executed for each test. There are two types of plugins: prologues and epilogues. Prologues run before the tests, while epilogues are executed after the tests. Multiple prologues and epilogues can be specified in each scenario.

An example of how plugins are defined within a test scenario:

name = "nccl-test"

prologue = "nccl_test_prologue"
epilogue = "nccl_test_epilogue"

[[Tests]]
id = "Tests.1"
test_name = "nccl_test_all_reduce"
num_nodes = "2"
time_limit = "00:20:00"

[[Tests]]
id = "Tests.2"
test_name = "nccl_test_all_gather"
num_nodes = "2"
time_limit = "00:20:00"
  [[Tests.dependencies]]
  type = "start_post_comp"
  id = "Tests.1"

You can see the prologue and epilogue fields. These are used to look up the corresponding plugin file. A plugin file is a separate test scenario file as shown below:

name = "nccl_test_prologue"

[[Tests]]
id = "Tests.1"
test_name = "nccl_test_all_reduce"
time_limit = "00:20:00"

If any of the tests in the prologue fail, the main test or the epilogue tests will not run. In other words, the main test and epilogue run conditionally when the prologue is successful. The tests in plugins have time limits, just as tests in the main scenario do. Output files should be stored in the output directory, in a subdirectory called "prologue" or "epilogue," following a proper directory hierarchy. Plugins are not supported for NeMo 1.0 (NeMo launcher).

Note

Test Plan

  1. CI passes
  2. Manual run
    2.1 Success
$ cloudai run --system-config ~/cloudaix-main/conf/common/system/israel_1.toml --tests-dir conf/common/test --test-scenario conf/common/test_scenario/nccl_tes
t.toml
/.autodirect/mswg2/E2E/theo/venv/lib/python3.10/site-packages/requests/__init__.py:102: RequestsDependencyWarning: urllib3 (1.26.19) or chardet (5.2.0)/charset_normalizer (2.0.12) doesn't match a supported ver
sion!
  warnings.warn("urllib3 ({}) or chardet ({})/charset_normalizer ({}) doesn't match a supported "                                                                                                                
[INFO] System Name: Israel-1                                                                            
[INFO] Scheduler: slurm                                                                                 
[INFO] Test Scenario Name: nccl-test                                                                    
[INFO] Checking if test templates are installed.                                                        
[INFO] Test Scenario: nccl-test                                                                         

Section Name: Tests.1                                                                                   
  Test Name: nccl_test_all_reduce                                                                       
  Description: all_reduce                                                                               
  No dependencies                                                                                       
[INFO] Initializing Runner [RUN] mode                                                                   
[INFO] Creating SlurmRunner                                                                             
[INFO] Starting test scenario execution.                                                                
[INFO] Starting test: Tests.1                                                                           
[INFO] Running test: Tests.1                                                                            
[INFO] Executing command for test Tests.1: sbatch /auto/e2e/israel1/workload_results/nccl-test_2024-10-25_22-05-46/Tests.1/0/cloudai_sbatch_script.sh
[INFO] Job completed: Tests.1
[INFO] All test scenario results stored at: /auto/e2e/israel1/workload_results/nccl-test_2024-10-25_22-05-46
[INFO] All test scenario execution attempts are complete. Please review the 'debug.log' file to confirm successful completion or to identify any issues.
$ cd /auto/e2e/israel1/workload_results/nccl-test_2024-10-25_22-05-46/Tests.1/0
$ ls
cloudai_sbatch_script.sh  epilogue  prologue  stderr.txt  stdout.txt

$ ls prologue/nccl_test_all_reduce/
stderr.txt  stdout.txt

$ ls epilogue/nccl_test_all_gather/
stderr.txt  stdout.txt

2.2 Failure

$ cloudai run --system-config ~/cloudaix-main/conf/common/system/israel_1.toml --tests-dir conf/common/test --test-scenario conf/common/test_scenario/nccl_test.toml
/.autodirect/mswg2/E2E/theo/venv/lib/python3.10/site-packages/requests/__init__.py:102: RequestsDependencyWarning: urllib3 (1.26.19) or chardet (5.2.0)/charset_normalizer (2.0.12) doesn't match a supported version!
  warnings.warn("urllib3 ({}) or chardet ({})/charset_normalizer ({}) doesn't match a supported "
[INFO] System Name: Israel-1
[INFO] Scheduler: slurm
[INFO] Test Scenario Name: nccl-test
[INFO] Checking if test templates are installed.
[INFO] Test Scenario: nccl-test

Section Name: Tests.1
  Test Name: nccl_test_all_reduce
  Description: all_reduce
  No dependencies
[INFO] Initializing Runner [RUN] mode
[INFO] Creating SlurmRunner
[INFO] Starting test scenario execution.
[INFO] Starting test: Tests.1
[INFO] Running test: Tests.1
[INFO] Executing command for test Tests.1: sbatch /auto/e2e/israel1/workload_results/nccl-test_2024-10-25_22-16-25/Tests.1/0/cloudai_sbatch_script.sh
[ERROR] Job 383928 for test Tests.1 failed: Missing success indicators in /auto/e2e/israel1/workload_results/nccl-test_2024-10-25_22-16-25/Tests.1/0/stdout.txt: '# Out of bounds values', '# Avg bus bandwidth'. These keywords are expected to be present in stdout.txt, usually towards the end of the file. Please review the NCCL test output and errors in the file. Ensure the NCCL test ran to completion. You can run the generated sbatch script manually and check if /auto/e2e/israel1/workload_results/nccl-test_2024-10-25_22-16-25/Tests.1/0/stdout.txt is created and contains the expected keywords. If the issue persists, contact the system administrator.
[INFO] Terminating all jobs...
[INFO] All jobs have been killed.

Copy link
Contributor

@amaslenn amaslenn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For existing prologue we use real NCCL run. In your examples it seems that we are switching to some predefined commands.

  1. How are we going to generate it?
  2. Will that cover our needs? cc @srivatsankrishnan

I do have some code related notes, but let's leave it for later discussion.

@TaekyungHeo
Copy link
Member Author

@amaslenn

How are we going to generate it?

Yes, it is one of the main design choices that we need to make.

@amaslenn
Copy link
Contributor

Yes, it is one of the main design choices that we need to make.

Can we rely on existing mechanisms? Each plugin will be defined as a regular Test TOML, meaning we can generate a CLI for it for a particular system. This is what we do now and it seems to cover all our needs for this feature.

@TaekyungHeo TaekyungHeo force-pushed the plugin-jan branch 15 times, most recently from 7594c19 to 852fee8 Compare October 24, 2024 19:54
@TaekyungHeo TaekyungHeo reopened this Oct 29, 2024
Copy link
Contributor

@amaslenn amaslenn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tried verify-configs with these changes? Will prologue/epilogue names be checked for existence?

tests/ref_data/gpt-plugin.sbatch Outdated Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we name file gpt-no-prologue.sbatch? We don't use epilogue here, this could be a nice additional test though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please find the updated names.

@@ -136,8 +139,14 @@ def _parse_data(self, data: Dict[str, Any]) -> TestScenario:
total_weight = sum(tr.weight for tr in ts_model.tests)
normalized_weight = 0 if total_weight == 0 else 100 / total_weight

prologue, epilogue = None, None
if ts_model.prologue:
prologue = self.plugin_mapping.get(ts_model.prologue)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we handle situation when specified name doesn't exist in the mapping?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I chose not to raise an exception when plugins are missing. The plugins will not be executed, and I have added warning messages.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is about meeting expectations, ours and our users'. Warning will likely go unnoticed, so we should answer to ourselves:

  1. If we raise an error here, it will make the plugin feature more visible to users, while we prefer it to "just work".
  2. However, plugins are meant to save time on costly runs. If we let it proceed without plugins when they’re enabled, it won’t fulfil its intended purpose.

src/cloudai/_core/test_scenario_parser.py Outdated Show resolved Hide resolved
@@ -49,14 +49,21 @@ def __init__(self, system_config_path: Path) -> None:
self.system_config_path = system_config_path

def parse(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this should be inlined into parse function:

... # same as it is

plugin_test_path = Path("conf/plugin/test")
try:
    plugin_tests = (
        self.parse_tests(list(plugin_test_path.glob("*.toml")), system) if plugin_test_path.exists() else []
    )
except TestConfigParsingError:
    exit(1)  # exit right away to keep error message readable for users

filtered_tests = tests
test_scenario: Optional[TestScenario] = None
if test_scenario_path:
    test_mapping = {t.name: t for t in tests}
    plugin_test_scenario_mapping = ... # load mapping here
    try:
        test_scenario = self.parse_test_scenario(test_scenario_path, test_mapping, plugin_test_scenario_mapping)
    except TestScenarioParsingError:
        exit(1)  # exit right away to keep error message readable for users
    scenario_tests = set(tr.test.name for tr in test_scenario.test_runs)
    filtered_tests = [t for t in tests if t.name in scenario_tests]

return system, filtered_tests, test_scenario

Let's also define two constants for paths:

PLUGINS_ROOT = Path("conf/plugin")
PLUGINS_TESTS_ROOT = PLUGINS_ROOT / "tests"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please find the updated code.

@TaekyungHeo
Copy link
Member Author

@amaslenn , I ran verify-configs and got this warning

$ cloudai verify-configs conf
[WARNING] Test configuration directory not provided, using all found test TOMLs in the specified directory.
[INFO] Checked systems: 3, all passed
[INFO] Checked tests: 40, all passed
[WARNING] System configuration not provided, mocking it.
[WARNING] Prologue 'nccl_test_prologue' not found in plugin mapping. Ensure that a proper plugin directory is set under the working directory.
[WARNING] Epilogue 'nccl_test_epilogue' not found in plugin mapping. Ensure that a proper plugin directory is set under the working directory.
[INFO] Checked scenarios: 9, all passed
[INFO] Checked 52 configuration files, all passed


_, tests, _ = parser.parse(tests_dir, Path())

filtered_test_names = {t.name for t in tests}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we simplify to assert tests == {"test-1"}?

_, filtered_tests, _ = parser.parse(tests_dir, test_scenario_path)

filtered_test_names = {t.name for t in filtered_tests}
assert len(filtered_tests) == 2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[minor] IMO it is OK to simplify to have only one regular test and one plugin.


test_mapping = {t.name: t for t in tests}
plugin_test_scenario_mapping = {}
if PLUGIN_ROOT.exists() and list(PLUGIN_ROOT.glob("*.toml")):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's log.debug the existence of these directories and files, could be useful in future.

@@ -136,8 +139,14 @@ def _parse_data(self, data: Dict[str, Any]) -> TestScenario:
total_weight = sum(tr.weight for tr in ts_model.tests)
normalized_weight = 0 if total_weight == 0 else 100 / total_weight

prologue, epilogue = None, None
if ts_model.prologue:
prologue = self.plugin_mapping.get(ts_model.prologue)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is about meeting expectations, ours and our users'. Warning will likely go unnoticed, so we should answer to ourselves:

  1. If we raise an error here, it will make the plugin feature more visible to users, while we prefer it to "just work".
  2. However, plugins are meant to save time on costly runs. If we let it proceed without plugins when they’re enabled, it won’t fulfil its intended purpose.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Jan25 Jan'25 release feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants