[release/2.12] Fix hardcoded rendezvous ports in distributed tests (#195994) - #3653
Merged
Conversation
…ytorch#195994) ## Summary Three paths in the distributed test infrastructure hardcode a rendezvous port, so any two distributed test processes on the same host contend for it. `PythonProcessGroupExtensionTest` in `test_c10d_common.py` and `_dynamo_dist_per_rank_init` in `common_distributed.py` both pin `MASTER_PORT=6789`, and `DynamoDistributedSingleProcTestCase` pins 12355. The `_dynamo_dist_per_rank_init` path is the widest: it backs roughly a hundred tests across `test_dynamo_distributed.py`, `test_inductor_collectives.py`, `test_compute_comm_reordering.py`, and `test_aten_comm_compute_reordering.py`. A sequential run never sees the collision. The ROCm full-suite executor runs 16 tasks in parallel, and the loser either dies with `DistNetworkError ... port: 6789 ... EADDRINUSE` or attaches to the other run's TCPStore and hangs until the 300s harness timeout. Every path now rendezvouses over a file rather than a TCP port. `PythonProcessGroupExtensionTest` uses the per-test temp file that `MultiProcessTestCase` already creates and propagates to every rank, wrapped in `dist.FileStore(self.file_name, self.world_size)` and passed as `store=`; `ProcessGroupWithDispatchedCollectivesTests` in the same file and `DistributedTestBase.create_pg` already do exactly this, and the `store=` form sidesteps the win32 `file://` URL quirk that `_init_methods` works around. `_dynamo_dist_per_rank_init` gains an `rdvz_file` keyword and builds its `FileStore` from that; its context manager has no access to the harness state, so each call site passes `self.file_name` explicitly. `DynamoDistributedSingleProcTestCase` allocates its own temp file in `setUpClass` and drops the `MASTER_ADDR`/`MASTER_PORT` patch entirely. `find_free_port` was considered and rejected for both paths. It binds and closes, so another of the parallel tasks can still claim the port in the window before the store binds it, and keeping the reservation alive does not work either: TCPStore would have to bind that same port itself, and its `master_listen_fd` cannot be inherited through spawn under an `env://` rendezvous. The file rendezvous has no such gap. The `env://` fallback in `_dynamo_dist_per_rank_init` is kept for callers that pass no `rdvz_file`, so out-of-tree users of the helper keep their current behavior. No in-tree caller takes it. The nine `PythonProcessGroupExtensionTest` tests that rendezvous no longer exercise TCPStore. That is acceptable: they test the Python process-group extension API, and TCPStore has dedicated coverage elsewhere in the same file. ## Test Plan Reproduction requires concurrency; every affected test passes when run on its own. Which instance fails is nondeterministic, and a losing instance may report the 300s timeout rather than EADDRINUSE. Concurrent instances of the `test_c10d_common.py` tests. Before the change one instance fails with EADDRINUSE on port 6789 while the other completes in ~336s because of the 300s hang; after it both pass in ~39s, and a four-way stress passes in every instance: ``` cd test/distributed for i in 1 2 3 4; do python -m pytest test_c10d_common.py -q -k PythonProcessGroupExtensionTest & done; wait ``` Same for the dynamo path, on disjoint GPUs so the port is the only shared resource. Otherwise NCCL resource exhaustion from oversubscribing the GPUs masks the port conflict with a different failure. One instance fails with EADDRINUSE before the change; both pass after it: ``` cd test/distributed HIP_VISIBLE_DEVICES=0,1 python -m pytest test_dynamo_distributed.py -q -k test_ddp_baseline_aot_eager_multiprocess & HIP_VISIBLE_DEVICES=2,3 python -m pytest test_dynamo_distributed.py -q -k test_ddp_baseline_aot_eager_multiprocess & wait ``` No regressions. On 8x MI300-class GPUs with 2.13.0+rocm10.0.0rc4, giving 32 passed, 11 passed, and 21 passed / 7 skipped respectively: ``` cd test/distributed PYTORCH_TEST_WITH_ROCM=1 python -m pytest test_c10d_common.py -q PYTORCH_TEST_WITH_ROCM=1 python -m pytest test_c10d_object_collectives.py test_c10d_logger.py -q PYTORCH_TEST_WITH_ROCM=1 python -m pytest test_dynamo_distributed.py -q -k TestMultiProc ``` On 4x gfx90a with HIP 7.14, covering the rewritten single-process harness, giving 32 passed: ``` cd test/distributed python -m pytest test_dynamo_distributed.py -q -k TestSingleProc ``` Authored with the assistance of an AI coding assistant. Pull Request resolved: pytorch#195994 Approved by: https://github.com/jeffdaily Co-authored-by: Jeff Daily <jeff.daily@amd.com> (cherry picked from commit 8b8a766) Cherry-pick conflicts were limited to test bodies that exist on main but not on release/2.12 (test_overlap_scheduling_flex_attention_backward and the three test_manual_bucketing_*_with_intermediate_deps / test_manual_bucketing_ag_forward_and_backward tests in test_aten_comm_compute_reordering.py, and test_new_group_delegates_to_pg in test_c10d_common.py). Those hunks were dropped; every _dynamo_dist_per_rank_init call site that does exist on this branch takes rdvz_file, and the torch/testing/_internal/common_distributed.py change applies identically to the release/2.13 backport. Co-authored-by: Cursor <cursoragent@cursor.com>
pragupta
deleted the
albmalamd/cherry-pick/2.12/195994-fix-hardcoded-rendezvous-ports-in-distributed-tests
branch
September 17, 2026 16:45
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three paths in the distributed test infrastructure hardcode a rendezvous port, so any two distributed test processes on the same host contend for it.
PythonProcessGroupExtensionTestintest_c10d_common.pyand_dynamo_dist_per_rank_initincommon_distributed.pyboth pinMASTER_PORT=6789, andDynamoDistributedSingleProcTestCasepins 12355. The_dynamo_dist_per_rank_initpath is the widest: it backs roughly a hundred tests acrosstest_dynamo_distributed.py,test_inductor_collectives.py,test_compute_comm_reordering.py, andtest_aten_comm_compute_reordering.py. A sequential run never sees the collision. The ROCm full-suite executor runs 16 tasks in parallel, and the loser either dies withDistNetworkError ... port: 6789 ... EADDRINUSEor attaches to the other run's TCPStore and hangs until the 300s harness timeout.Every path now rendezvouses over a file rather than a TCP port.
PythonProcessGroupExtensionTestuses the per-test temp file thatMultiProcessTestCasealready creates and propagates to every rank, wrapped indist.FileStore(self.file_name, self.world_size)and passed asstore=;ProcessGroupWithDispatchedCollectivesTestsin the same file andDistributedTestBase.create_pgalready do exactly this, and thestore=form sidesteps the win32file://URL quirk that_init_methodsworks around._dynamo_dist_per_rank_initgains anrdvz_filekeyword and builds itsFileStorefrom that; its context manager has no access to the harness state, so each call site passesself.file_nameexplicitly.DynamoDistributedSingleProcTestCaseallocates its own temp file insetUpClassand drops theMASTER_ADDR/MASTER_PORTpatch entirely.find_free_portwas considered and rejected for both paths. It binds and closes, so another of the parallel tasks can still claim the port in the window before the store binds it, and keeping the reservation alive does not work either: TCPStore would have to bind that same port itself, and itsmaster_listen_fdcannot be inherited through spawn under anenv://rendezvous. The file rendezvous has no such gap.The
env://fallback in_dynamo_dist_per_rank_initis kept for callers that pass nordvz_file, so out-of-tree users of the helper keep their current behavior. No in-tree caller takes it.The nine
PythonProcessGroupExtensionTesttests that rendezvous no longer exercise TCPStore. That is acceptable: they test the Python process-group extension API, and TCPStore has dedicated coverage elsewhere in the same file.Test Plan
Reproduction requires concurrency; every affected test passes when run on its own. Which instance fails is nondeterministic, and a losing instance may report the 300s timeout rather than EADDRINUSE.
Concurrent instances of the
test_c10d_common.pytests. Before the change one instance fails with EADDRINUSE on port 6789 while the other completes in ~336s because of the 300s hang; after it both pass in ~39s, and a four-way stress passes in every instance:Same for the dynamo path, on disjoint GPUs so the port is the only shared resource. Otherwise NCCL resource exhaustion from oversubscribing the GPUs masks the port conflict with a different failure. One instance fails with EADDRINUSE before the change; both pass after it:
No regressions. On 8x MI300-class GPUs with 2.13.0+rocm10.0.0rc4, giving 32 passed, 11 passed, and 21 passed / 7 skipped respectively:
On 4x gfx90a with HIP 7.14, covering the rewritten single-process harness, giving 32 passed:
Authored with the assistance of an AI coding assistant.
Pull Request resolved: pytorch#195994
Approved by: https://github.com/jeffdaily
(cherry picked from commit 8b8a766)
Cherry-pick conflicts were limited to test bodies that exist on main but not on release/2.12 (test_overlap_scheduling_flex_attention_backward and the three test_manual_bucketing_*_with_intermediate_deps / test_manual_bucketing_ag_forward_and_backward tests in test_aten_comm_compute_reordering.py, and test_new_group_delegates_to_pg in test_c10d_common.py). Those hunks were dropped; every _dynamo_dist_per_rank_init call site that does exist on this branch takes rdvz_file, and the torch/testing/_internal/common_distributed.py change applies identically to the release/2.13 backport.