Skip to content

fix(transformer): destroy model-parallel process groups in destroy_model_parallel - #345

Open
bilalsar wants to merge 2 commits into
ROCm:masterfrom
bilalsar:fix/apex-ut-pipeline-destroy-process-groups
Open

bilalsar wants to merge 2 commits into
ROCm:masterfrom
bilalsar:fix/apex-ut-pipeline-destroy-process-groups

Conversation

@bilalsar

@bilalsar bilalsar commented Oct 28, 2026 •

Copy link
Copy Markdown

Motivation

In short: destroy_model_parallel() never frees the communication groups it created, so a test that builds them repeatedly in one process runs GPUs with limited VRAM out of memory.

test_pipeline_parallel_fwd_bwd.NcclPipelineParallelForwardBackwardTest subtests fail on ROCm 10.3.0-20261027 (torch 2.15.0+rocm10.3.0a20261027) on Radeon hosts with HIP failure: 'out of memory' / NCCL split failed ... Failed to CUDA calloc 536870912 bytes. They passed on 10.0.0-20260729. All runs use apex 11867be, the release/1.15.0 pin in related_commits. The MI325X and MI350X hosts on the same build do not hit it.

Host GPUs Failing subtests Log
ctr-navi4x-aj63-ws13 2x RX 9060 XT (gfx1200, 16 GB) test_inference_no_pipelining, test_inference_pipelining_without_interleaving, test_inference_async_pipelining_without_interleaving, test_learning_no_pipelining, test_learning_pipelining_without_interleaving, test_learning_async_pipelining_without_interleaving job
ctr-navi4x-at48-ws008 4x Radeon (gfx1201, 32 GB) test_inference_no_pipelining, test_learning_no_pipelining log
ctr-navi4x-aj63-ws13:9196:9631 [0] [FATAL ERROR]: HIP failure: 'out of memory'
RuntimeError: Process 0 exited with error code 10 and exception:
RuntimeError: NCCL split failed: unhandled cuda error (run with NCCL_DEBUG=INFO for details)
NCCL Last Error: Failed to CUDA calloc 536870912 bytes

Technical Details

In short: destroy_model_parallel() now destroys the process groups before clearing its references to them.

apex/transformer/parallel_state.py: destroy_model_parallel() only set the group globals to None. _forward_backward_test_impl() calls initialize_model_parallel() / destroy_model_parallel() once per dtype and deallocate option (8 times) in one process, so every iteration left its RCCL communicators alive. Each holds about 512 MiB of device memory; on ctr-navi4x-aj63-ws13 rank 0 fails on its 32nd communicator split (31 x 512 MiB allocations logged with NCCL_DEBUG=INFO,ALLOC).

The new _destroy_model_parallel_process_groups() calls torch.distributed.destroy_process_group() once on each group this rank holds (the eight _*_GROUP globals), skipping None and GroupMember.NON_GROUP_MEMBER and destroying each group object only once. destroy_model_parallel() calls it first, then clears the globals as before.

Effect on other suites: this changes behaviour for every caller of destroy_model_parallel(): the 13 tests/L0/run_transformer files that call it, tests/L1/transformer/pipeline_parallel_fwd_bwd_ucc_async.py, and any user code. After the call, process-group handles obtained earlier from parallel_state are destroyed and must not be reused. In the full Apex_UT runs below, on 2 and 4 GPUs, every test that passed before still passes and no test hangs.

Related: the test_layers parity errors in the same Apex_UT runs are a separate root cause: #344.

Test Result

Full Apex_UT reruns through the frameworks-qa-ci Functional Test Runner with the same image as the nightly (rocm/frameworks-internal:rocm10.3.0a20261027_ubuntu26.04_py3.14_pytorch_2.15.0_31b8278), apex checked out at this PR's head 6c85b5a.

Failing: 11867be (pin) Passing: this PR 6c85b5a
ctr-navi4x-aj63-ws13 job run 40688983363 run 40782925437
6 pipeline subtests ERROR (HIP out of memory) ok
Apex_UT totals (303) 218 passed, 7 errors 224 passed, 1 error
ctr-navi4x-at48-ws008 job nightly log run 40782938832
test_inference_no_pipelining, test_learning_no_pipelining ERROR (HIP out of memory) ok
Apex_UT totals (303) 232 passed, 5 errors 234 passed, 3 errors

Errors left in the passing runs: test_layers test_all_gather_parity (both hosts) and test_reduce_scatter_parity (at48), fixed by #344, and test_cross_entropy on at48 (see Not covered). No new errors.

apex-pipeline-fwd-bwd-fail-hip-oom.log (run 40688983363, aj63)
ERROR: test_inference_async_pipelining_without_interleaving (test_pipeline_parallel_fwd_bwd.NcclPipelineParallelForwardBackwardTest...)
ERROR: test_inference_no_pipelining (test_pipeline_parallel_fwd_bwd.NcclPipelineParallelForwardBackwardTest...)
ERROR: test_inference_pipelining_without_interleaving (test_pipeline_parallel_fwd_bwd.NcclPipelineParallelForwardBackwardTest...)
ERROR: test_learning_async_pipelining_without_interleaving (test_pipeline_parallel_fwd_bwd.NcclPipelineParallelForwardBackwardTest...)
ERROR: test_learning_no_pipelining (test_pipeline_parallel_fwd_bwd.NcclPipelineParallelForwardBackwardTest...)
ERROR: test_learning_pipelining_without_interleaving (test_pipeline_parallel_fwd_bwd.NcclPipelineParallelForwardBackwardTest...)
ctr-navi4x-aj63-ws13:9196:9631 [0] [FATAL ERROR]: HIP failure: 'out of memory'
NCCL Last Error: Failed to CUDA calloc 536870912 bytes
...
|   303    |   218    |    0     |    7     |    78    |   225    |     FAIL     |
apex-destroy-model-parallel-pass-aj63.log (run 40782925437)
Checkout verified: 6c85b5a9bb013a64ed750725679dc1afe3188cd0
'/workspace/apex/apex/transformer/parallel_state.py' -> '/usr/local/lib/python3.14/dist-packages/apex/transformer/parallel_state.py'
dd538e7da4bec59b98e017caf40c9d55  /workspace/apex/apex/transformer/parallel_state.py
dd538e7da4bec59b98e017caf40c9d55  /usr/local/lib/python3.14/dist-packages/apex/transformer/parallel_state.py
test_inference_no_pipelining ... ok
test_learning_no_pipelining ... ok
test_inference_async_pipelining_without_interleaving ... ok
(all 6 pipeline subtests ok; no "out of memory" in the log)
ERROR: test_all_gather_parity (test_layers.NcclTensorParallelLayerTest.test_all_gather_parity)   <- fixed by #344
|   303    |   224    |    0     |    1     |    78    |   225    |     FAIL     |
apex-destroy-model-parallel-pass-at48.log (run 40782938832)
Checkout verified: 6c85b5a9bb013a64ed750725679dc1afe3188cd0
dd538e7da4bec59b98e017caf40c9d55  /workspace/apex/apex/transformer/parallel_state.py
[dist init] rank = 0, world_size = 4
test_inference_no_pipelining ... ok
test_learning_no_pipelining ... ok
ERROR: test_cross_entropy (test_cross_entropy.NcclVocabParallelCrossEntropyTest.test_cross_entropy)   <- not covered
ERROR: test_all_gather_parity (test_layers.NcclTensorParallelLayerTest.test_all_gather_parity)        <- fixed by #344
ERROR: test_reduce_scatter_parity (test_layers.NcclTensorParallelLayerTest.test_reduce_scatter_parity) <- fixed by #344
|   303    |   234    |    0     |    3     |    66    |   237    |     FAIL     |

How the PR commit was run: Apex_UT imports the apex installed in the docker image, not the checkout, so a library change does not reach the tests on its own. The jobs were dispatched from the frameworks-qa-ci branch test/apex-ut-commit-override, which lets apex_ut take an APEX_COMMIT_OVERRIDE SHA and copies the one file named in APEX_OVERLAY_FILE (here apex/transformer/parallel_state.py) from the checkout over the installed package. The matching MD5 lines above show the overlay. Everything else is the same as the nightly job.

Not covered:

  • test_cross_entropy.NcclVocabParallelCrossEntropyTest.test_cross_entropy on ctr-navi4x-at48-ws008 still fails with Failed to CUDA calloc 536870912 bytes inside initialize_model_parallel(), about 4 seconds after the test starts, with this change applied. Its cause is not established and this PR does not address it.
  • CI picks the fix up once related_commits points at an apex commit that contains it and the image is rebuilt from that pin (it pins release/1.15.0, so this needs a backport there too).

Submission Checklist

  • Change is limited to the failing code path
  • Validated on GPU CI jobs (failing and passing job links above)

…st iterations

Six NcclPipelineParallelForwardBackwardTest subtests fail on ROCm
10.3.0-20261027 on a 2x 16 GB gfx1200 host with "HIP failure: 'out of
memory'" / "NCCL split failed ... Failed to CUDA calloc 536870912 bytes".

_forward_backward_test_impl() runs initialize_model_parallel() /
destroy_model_parallel() once per dtype and deallocate option (8 times) in
one process. destroy_model_parallel() only sets the group globals to None,
so every iteration left its RCCL communicators alive. Each holds about
512 MiB of device memory, and rank 0 failed on its 32nd communicator split.

At the end of each iteration, call torch.distributed.destroy_process_group()
on every group this rank holds, then destroy_model_parallel() as before.
The change is limited to this test; destroy_model_parallel() is unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
@bilalsar

Copy link
Copy Markdown
Author

Validation, commit 8a0e1d3: fixed.

All 6 NcclPipelineParallelForwardBackwardTest subtests: ERROR (HIP out of memory, calloc 536870912) on 11867be → ok on 8a0e1d3, no OOM in the log. Apex_UT 218 passed / 7 errors → 224 passed / 1 error (the 1 left is test_all_gather_parity, fixed by #344). Host ctr-navi4x-aj63-ws13 (2x gfx1200, 16 GB), image rocm10.3.0a20261027_ubuntu26.04_py3.14_pytorch_2.15.0_31b8278.

Apex_UT tests that call initialize_model_parallel()/destroy_model_parallel()
repeatedly in one process run out of device memory on Radeon hosts on ROCm
10.3.0-20261027 ("HIP failure: 'out of memory'" / "NCCL split failed ...
Failed to CUDA calloc 536870912 bytes"): six test_pipeline_parallel_fwd_bwd
subtests on 2x gfx1200, and two of those plus test_cross_entropy on 4x gfx1201.

destroy_model_parallel() only set the group globals to None, so each
iteration's RCCL communicators stayed alive, about 512 MiB each, until the
process exited.

Call torch.distributed.destroy_process_group() on each group this rank holds
before clearing the globals. Groups the rank is not a member of are skipped,
and a group object is destroyed only once. This covers every caller, so the
pipeline-test-only teardown from the previous commit is removed.

Co-authored-by: Cursor <cursoragent@cursor.com>
@bilalsar bilalsar changed the title fix(tests): destroy model-parallel process groups between pipeline fwd/bwd test iterations fix(transformer): destroy model-parallel process groups in destroy_model_parallel Oct 28, 2026
@bilalsar

Copy link
Copy Markdown
Author

Validation, commit 6c85b5a (library fix in destroy_model_parallel()): fixed for the pipeline subtests.

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.

1 participant