Skip to content

Add pre-test hook support for MegatronBridge workload#957

Merged
podkidyshev merged 8 commits into
NVIDIA:mainfrom
saivishal1999:spothula/nccl-alltoall-pre-hook
Jul 9, 2026
Merged

Add pre-test hook support for MegatronBridge workload#957
podkidyshev merged 8 commits into
NVIDIA:mainfrom
saivishal1999:spothula/nccl-alltoall-pre-hook

Conversation

@saivishal1999

Copy link
Copy Markdown
Contributor

MegatronBridge's gen_exec_command uses setup_experiment.py to generate its own sbatch, bypassing CloudAI's normal pre_test injection. This adds support by submitting the pre-hook as a separate sbatch first, then passing dependency=afterok:<job_id> to setup_experiment.py via --additional_slurm_params so Slurm gates training on pre-hook success.

  • _gen_pre_hook_sbatch: generates standalone sbatch for pre-hook tests, injecting main test's nnodes so srun allocates all training nodes
  • _collect_additional_slurm_params: extracted from _build_launcher_parts so the base params can be built in Python and dependency appended at bash runtime after the pre-hook job ID is known
  • _wrap_launcher_for_job_id_and_quiet_output: submits pre-hook sbatch, captures job ID, builds --additional_slurm_params with dependency

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds optional pre-test sbatch handling for Megatron-Bridge Slurm command generation, refactors shared SBATCH resource directive assembly, and introduces a new NCCL min_busbw command argument with updated srun generation for non-MPI subtests.

Changes

Megatron-Bridge pre-hook sbatch flow

Layer / File(s) Summary
Entry point and pre-hook script generation
src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py
gen_exec_command branches on test_run.pre_test, builds launcher state without duplicating Slurm params, and creates a standalone pre-hook sbatch script that runs per-node pre-test srun checks with bandwidth validation and failure aggregation.
Wrapper submission and dependency injection
src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py
_wrap_launcher_for_job_id_and_quiet_output accepts the pre-hook path and base params, submits the pre-hook, parses its job ID, injects afterok dependency params, and optionally captures a running node list before launching the main command.
Conditional Slurm params in launcher parts
src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py
_build_launcher_parts now gates --additional_slurm_params behind include_slurm_params, so the main launcher can omit those params when the wrapper injects them later.

Shared SBATCH resource directive assembly

Layer / File(s) Summary
Resource directive helper and caller split
src/cloudai/systems/slurm/slurm_command_gen_strategy.py
_append_resource_directives centralizes reservation, node allocation, GPU, task, time limit, and extra SBATCH argument handling, while _append_sbatch_directives now keeps only output, error, partition, and optional account directives before calling the helper.

NCCL bus bandwidth threshold

Layer / File(s) Summary
NCCL argument filtering
src/cloudai/workloads/nccl_test/nccl.py, src/cloudai/workloads/nccl_test/slurm_command_gen_strategy.py
NCCLCmdArgs adds min_busbw, and NCCL Slurm command generation skips that field when building forwarded CLI arguments.
Non-MPI srun prefix handling
src/cloudai/workloads/nccl_test/slurm_command_gen_strategy.py
gen_srun_prefix rewrites the inherited srun prefix from --mpi=<...> to --ntasks=1 for non-_mpi subtests, and generate_test_command switches ngpus formatting for single-process runs.

Estimated code review effort: 4 (Complex) | ~45 minutes

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding pre-test hook support for the MegatronBridge workload.
Description check ✅ Passed The description directly matches the implemented MegatronBridge pre-hook and dependency-handling changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py`:
- Around line 133-136: The pre-hook sbatch generation in build_sbatch_lines is
dropping excluded nodes when get_cached_nodes_spec() only provides num_nodes.
Update the sbatch line assembly so self.test_run.exclude_nodes is preserved even
in the --nodes path, not just when node_list is present, and keep the existing
behavior around num_nodes in SlurmCommandGenStrategy while ensuring excluded
nodes are still passed through.
- Around line 117-118: The pre-test node assignment in
slurm_command_gen_strategy.py is using the read-only TestRun.nnodes property,
which will fail before sbatch generation. Update the loop in the strategy method
that iterates over self.test_run.pre_test.test_runs to assign the underlying
mutable field num_nodes instead of nnodes, keeping the existing logic that
copies the parent test run’s node count into each pre-test run.
- Line 139: The pre-hook submission in gen_pre_test / SlurmCommandGenStrategy
currently only propagates PRE_TEST_SUCCESS, so a failed pre-test can still let
the sbatch wrapper exit successfully and release the main job. Update the
command assembly around sbatch_lines.extend and pre_hook_cmds to explicitly exit
non-zero when the pre-test check fails, using the gen_pre_test-generated success
flag as the gate so the pre-hook sbatch cannot complete as success on failure.
- Around line 344-350: Make the include_slurm_params parameter keyword-only in
_build_launcher_parts so it cannot be passed positionally and the FBT001/FBT002
warning is eliminated. Update the _build_launcher_parts function signature to
force include_slurm_params as a keyword-only argument, and ensure any internal
call sites use the named argument form; the existing keyword-based caller should
continue to work unchanged.
- Around line 268-270: The shell wrapper in the Slurm command generation logic
is inserting base Slurm args directly into the ADDITIONAL_SLURM_PARAMS
assignment, which can allow shell expansion and produce a leading separator when
the base value is empty. Update the Megatron bridge’s slurm_command_gen_strategy
around the ADDITIONAL_SLURM_PARAMS construction to safely quote/escape
base_slurm_params before embedding it in the shell snippet, and adjust the
PRE_HOOK_JOB_ID append logic so it only adds the dependency separator when
ADDITIONAL_SLURM_PARAMS already has content. Use the existing command assembly
in the strategy method that emits these lines to keep the fix localized.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: dce884bc-1a4a-49c7-bf8d-0aa679ff96f6

📥 Commits

Reviewing files that changed from the base of the PR and between 5e0c351 and a5f95a4.

📒 Files selected for processing (1)
  • src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py

Comment thread src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py Outdated
Comment thread src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py Outdated
Comment thread src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py Outdated
Comment thread src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py Outdated
Comment thread src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py
@podkidyshev

Copy link
Copy Markdown
Contributor

@saivishal1999 please resolve coderabbit comments

Comment thread src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py`:
- Around line 299-301: The `capture_nodelist` parameter in
`SlurmCommandGenStrategy` should be keyword-only to match the existing
`include_slurm_params` pattern and clear the FBT001/FBT002 warning. Update the
affected method signature in `slurm_command_gen_strategy.py` to make
`capture_nodelist` keyword-only, and ensure any call sites use the keyword form
while keeping the existing named invocation compatible.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: b2b19501-1bf3-4c77-9c80-043760100c93

📥 Commits

Reviewing files that changed from the base of the PR and between a5f95a4 and c198031.

📒 Files selected for processing (3)
  • src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py
  • src/cloudai/workloads/nccl_test/nccl.py
  • src/cloudai/workloads/nccl_test/slurm_command_gen_strategy.py

Comment thread src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/cloudai/workloads/nccl_test/slurm_command_gen_strategy.py`:
- Around line 34-43: The `_mpi` suffix check is duplicated in both
`gen_srun_prefix` and `generate_test_command`, so extract it into a shared
helper or property on this strategy class such as an `is_single_process`
accessor. Update both call sites to use that single source of truth in
`NCCLTestDefinition`-based logic so the naming convention is maintained in one
place and the two methods cannot drift.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 49d63a27-0267-4e3e-9ec4-b187c1038374

📥 Commits

Reviewing files that changed from the base of the PR and between c198031 and 18711a8.

📒 Files selected for processing (1)
  • src/cloudai/workloads/nccl_test/slurm_command_gen_strategy.py

Comment thread src/cloudai/workloads/nccl_test/slurm_command_gen_strategy.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py (1)

315-330: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Unbounded while true can hang the submit process forever.

This loop only breaks on _state = "RUNNING". Two reachable paths never satisfy that:

  • The pre-hook fails/gets cancelled while PENDING, so it leaves the queue and squeue returns empty.
  • A short pre-hook transitions PENDING → RUNNING → COMPLETED between two 10s polls, so RUNNING is never observed.

In both cases _state becomes empty and the loop spins indefinitely (sleep 10), blocking the wrapper on the submit node. Additionally, Line 328 appends nodelist= unconditionally, so if capture fails PRE_HOOK_NODES is empty and --additional_slurm_params gets a dangling nodelist=.

Break out on a terminal/empty state and only append the nodelist when non-empty.

🐛 Proposed fix
                     "while true; do",
                     '    _state=$(squeue -j "$PRE_HOOK_JOB_ID" -h -o "%T" 2>/dev/null || true)',
                     '    if [ "$_state" = "RUNNING" ]; then',
                     '        PRE_HOOK_NODES=$(squeue -j "$PRE_HOOK_JOB_ID" -h -o "%N" 2>/dev/null | head -1 || true)',
                     "        break",
                     "    fi",
+                    '    if [ -z "$_state" ]; then',
+                    '        echo "Pre-hook $PRE_HOOK_JOB_ID left the queue before RUNNING was observed." >&2',
+                    "        break",
+                    "    fi",
                     "    sleep 10",
                     "done",
-                    'ADDITIONAL_SLURM_PARAMS="${ADDITIONAL_SLURM_PARAMS};nodelist=${PRE_HOOK_NODES}"',
+                    'if [ -n "$PRE_HOOK_NODES" ]; then',
+                    '    ADDITIONAL_SLURM_PARAMS="${ADDITIONAL_SLURM_PARAMS};nodelist=${PRE_HOOK_NODES}"',
+                    "fi",
                     "",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py` around
lines 315 - 330, The nodelist capture logic in slurm_command_gen_strategy.py can
hang forever because the `while true` loop in the `capture_nodelist` block only
exits on `RUNNING` and never handles empty or terminal states. Update the
`capture_nodelist` branch in `slurm_command_gen_strategy.py` to break on
failed/cancelled/completed or empty `_state`, and only add
`nodelist=${PRE_HOOK_NODES}` to `ADDITIONAL_SLURM_PARAMS` when `PRE_HOOK_NODES`
is non-empty. Use the existing `capture_nodelist` setup, `PRE_HOOK_JOB_ID`, and
`PRE_HOOK_NODES` symbols to locate the fix.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py`:
- Around line 315-330: The nodelist capture logic in
slurm_command_gen_strategy.py can hang forever because the `while true` loop in
the `capture_nodelist` block only exits on `RUNNING` and never handles empty or
terminal states. Update the `capture_nodelist` branch in
`slurm_command_gen_strategy.py` to break on failed/cancelled/completed or empty
`_state`, and only add `nodelist=${PRE_HOOK_NODES}` to `ADDITIONAL_SLURM_PARAMS`
when `PRE_HOOK_NODES` is non-empty. Use the existing `capture_nodelist` setup,
`PRE_HOOK_JOB_ID`, and `PRE_HOOK_NODES` symbols to locate the fix.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 6c358501-1776-4c18-8ca3-00d4ad44528b

📥 Commits

Reviewing files that changed from the base of the PR and between 18711a8 and 1d26948.

📒 Files selected for processing (2)
  • src/cloudai/systems/slurm/slurm_command_gen_strategy.py
  • src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py

saivishal1999 and others added 5 commits July 8, 2026 16:48
MegatronBridge's gen_exec_command uses setup_experiment.py to generate its
own sbatch, bypassing CloudAI's normal pre_test injection. This adds support
by submitting the pre-hook as a separate sbatch first, then passing
dependency=afterok:<job_id> to setup_experiment.py via --additional_slurm_params
so Slurm gates training on pre-hook success.

- _gen_pre_hook_sbatch: generates standalone sbatch for pre-hook tests,
  injecting main test's nnodes so srun allocates all training nodes
- _collect_additional_slurm_params: extracted from _build_launcher_parts
  so the base params can be built in Python and dependency appended at
  bash runtime after the pre-hook job ID is known
- _wrap_launcher_for_job_id_and_quiet_output: submits pre-hook sbatch,
  captures job ID, builds --additional_slurm_params with dependency

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
tr.nnodes is a read-only property backed by num_nodes; set num_nodes
directly so srun gets -N<main_job_nodes> instead of -N1.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…Bridge

- _gen_pre_hook_sbatch: loop-based independent per-node alltoalls (32 x srun --nodelist=$_node),
  busbw threshold check via awk (min_busbw from hook TOML), exit 1 on failure to block training,
  forwards extra_srun_args (e.g. --segment) as #SBATCH directives so pre-hook gets same node
  placement constraints as training
- _wrap_launcher_for_job_id_and_quiet_output: submit pre-hook as separate sbatch, pass
  dependency=afterok:<id> to setup_experiment.py; poll indefinitely until pre-hook RUNNING,
  capture nodelist, pass to training via --additional_slurm_params
- NCCLCmdArgs: add optional min_busbw field for per-hook threshold configuration
- NcclTestSlurmCommandGenStrategy: exclude min_busbw from CLI args forwarded to nccl binary

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Switch alltoall_perf from MPI multi-process to single-process multi-GPU
mode: replace --mpi=pmix with --ntasks=1 and use -g <ngpus> instead of
--ngpus so one process drives all GPUs directly.
…thod

Extract resource-related SBATCH directives (reservation, distribution,
nodelist/exclude, gpus-per-node/gres, ntasks-per-node, time limit,
extra_sbatch_args) into a new base class method _append_resource_directives.

Refactor _append_sbatch_directives to call it, and update
MegatronBridge _gen_pre_hook_sbatch to use it instead of reimplementing
a subset of directives — fixing missing: distribution, exclude_nodes,
ntasks-per-node, gres, and extra_sbatch_args in the pre-hook.
@saivishal1999
saivishal1999 force-pushed the spothula/nccl-alltoall-pre-hook branch from 1d26948 to aa0aba2 Compare July 8, 2026 23:52

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/cloudai/systems/slurm/slurm_command_gen_strategy.py`:
- Line 390: The assignment in SlurmCommandGenStrategy._add_reservation usage is
redundant because the method mutates the existing content list and returns the
same object. Update the surrounding code in slurm_command_gen_strategy.py to
call _add_reservation(content) without reassigning content, keeping the in-place
mutation pattern consistent and removing the unnecessary no-op.

In `@src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py`:
- Around line 315-330: The nodelist capture loop in the pre-hook wrapper can
wait forever if the job never reaches RUNNING or exits between polls; update the
logic in the nodelist_lines block to handle terminal states and add a maximum
wait timeout. Use the existing PRE_HOOK_JOB_ID and squeue polling to detect
COMPLETED/FAILED/CANCELLED (or empty output after the job leaves the queue),
then break with an error instead of looping forever. Keep the current
capture_nodelist behavior, but make the shell snippet fail fast when the
pre-hook is no longer runnable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: e979cbb7-15d5-4a9e-a7cf-5f8a813df648

📥 Commits

Reviewing files that changed from the base of the PR and between 1d26948 and aa0aba2.

📒 Files selected for processing (4)
  • src/cloudai/systems/slurm/slurm_command_gen_strategy.py
  • src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py
  • src/cloudai/workloads/nccl_test/nccl.py
  • src/cloudai/workloads/nccl_test/slurm_command_gen_strategy.py

Comment thread src/cloudai/systems/slurm/slurm_command_gen_strategy.py Outdated
Comment thread src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py
- Fix infinite nodelist poll loop: detect terminal Slurm states
  (FAILED/CANCELLED/COMPLETED/TIMEOUT/gone) and exit with error instead
  of spinning forever
- Remove redundant reassignment of _add_reservation return value; the
  method mutates content in-place
- Extract _is_single_process property in NcclTestSlurmCommandGenStrategy
  to deduplicate the endswith("_mpi") check across gen_srun_prefix and
  generate_test_command
- Fix docstring and formatting issues flagged by ruff
- Assert pre_test is not None before accessing .test_runs in
  _gen_pre_hook_sbatch; pyright can't infer the caller already guards it
- Handle list branch of subtest_name Union type in _is_single_process;
  subtest_name is Union[Literal[...], list[Literal[...]]] so .endswith()
  requires narrowing to str first
Terminal state detection was already added; this adds a 3600s (1h) hard
ceiling so the loop cannot spin indefinitely when the pre-hook job stays
PENDING longer than expected. Exits with an error after timeout.
Comment thread src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py
Comment thread src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py
Comment thread src/cloudai/workloads/megatron_bridge/slurm_command_gen_strategy.py
Comment thread src/cloudai/workloads/nccl_test/nccl.py
@podkidyshev
podkidyshev merged commit 0de6ca8 into NVIDIA:main Jul 9, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants