Skip to content

Commit 9ce6a2d

Browse files
authored
Skipping tcp tests, fixing ci (#3775)
Description: This PR resolves the CI hangs and provides a clear guide to users on how to migrate away from the legacy `tcp://` initialization method Check list: - [x] New tests are added (if a new feature is added) - [x] New doc strings: description and/or example code are in RST format - [ ] Documentation is updated (if required)
1 parent 538c58f commit 9ce6a2d

6 files changed

Lines changed: 60 additions & 29 deletions

File tree

ignite/distributed/comp_models/native.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ def _create_from_backend(
107107
rank: int | None = None,
108108
**kwargs: Any,
109109
) -> None:
110+
if init_method is not None and init_method.startswith("tcp://"):
111+
raise ValueError(
112+
f"TCP initialization via init_method='{init_method}' will hang. "
113+
"To fix this, please configure MASTER_ADDR and MASTER_PORT in the environment and "
114+
"use 'env://' (or omit init_method)."
115+
)
116+
110117
if backend == dist.Backend.NCCL and not torch.cuda.is_available():
111118
raise RuntimeError("Nccl backend is required but no cuda capable devices")
112119
self._backend = backend

ignite/distributed/launcher.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,6 @@ def training(local_rank, config, **kwargs):
132132
with idist.Parallel(backend=backend, init_method='file:///d:/tmp/some_file', nproc_per_node=4) as parallel:
133133
parallel.run(training, config, a=1, b=2)
134134
135-
Initializing the process using ``tcp://``
136-
137-
.. code-block:: python
138-
139-
with idist.Parallel(backend=backend, init_method='tcp://10.1.1.20:23456', nproc_per_node=4) as parallel:
140-
parallel.run(training, config, a=1, b=2)
141135
142136
143137
3) Single node, Multi-TPU training launched with `python`
@@ -233,6 +227,13 @@ def __init__(
233227
if value is not None:
234228
raise ValueError(f"If backend is None, argument '{name}' should be also None, but given {value}")
235229

230+
if init_method is not None and init_method.startswith("tcp://"):
231+
raise ValueError(
232+
f"TCP initialization via init_method='{init_method}' will hang. "
233+
"To fix this, please configure MASTER_ADDR and MASTER_PORT in the environment and "
234+
"use 'env://' (or omit init_method)."
235+
)
236+
236237
self.backend = backend
237238
self._spawn_params = None
238239
self.init_method = init_method

tests/ignite/conftest.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,15 +231,19 @@ def _setup_free_port(local_rank):
231231
@pytest.fixture()
232232
def distributed_context_single_node_nccl(local_rank, world_size):
233233
free_port = _setup_free_port(local_rank)
234+
os.environ["MASTER_ADDR"] = "localhost"
235+
os.environ["MASTER_PORT"] = str(free_port)
234236

235237
dist_info = {
236238
"backend": "nccl",
237239
"world_size": world_size,
238240
"rank": local_rank,
239-
"init_method": f"tcp://localhost:{free_port}",
241+
"init_method": "env://",
240242
}
241243
yield _create_dist_context(dist_info, local_rank)
242244
_destroy_dist_context()
245+
os.environ.pop("MASTER_ADDR", None)
246+
os.environ.pop("MASTER_PORT", None)
243247

244248

245249
@pytest.fixture()
@@ -253,8 +257,10 @@ def distributed_context_single_node_gloo(local_rank, world_size):
253257
init_method = f"file:///{temp_file.name.replace(backslash, '/')}"
254258
else:
255259
free_port = _setup_free_port(local_rank)
256-
init_method = f"tcp://localhost:{free_port}"
260+
init_method = "env://"
257261
temp_file = None
262+
os.environ["MASTER_ADDR"] = "localhost"
263+
os.environ["MASTER_PORT"] = str(free_port)
258264

259265
dist_info = {
260266
"backend": "gloo",
@@ -267,6 +273,9 @@ def distributed_context_single_node_gloo(local_rank, world_size):
267273
_destroy_dist_context()
268274
if temp_file:
269275
temp_file.close()
276+
else:
277+
os.environ.pop("MASTER_ADDR", None)
278+
os.environ.pop("MASTER_PORT", None)
270279

271280

272281
@pytest.fixture()
@@ -475,7 +484,9 @@ def distributed(request, local_rank, world_size):
475484
else:
476485
temp_file = None
477486
free_port = _setup_free_port(local_rank)
478-
init_method = f"tcp://localhost:{free_port}"
487+
init_method = "env://"
488+
os.environ["MASTER_ADDR"] = "localhost"
489+
os.environ["MASTER_PORT"] = str(free_port)
479490

480491
dist_info = {
481492
"world_size": world_size,
@@ -494,6 +505,9 @@ def distributed(request, local_rank, world_size):
494505
_destroy_dist_context()
495506
if temp_file:
496507
temp_file.close()
508+
else:
509+
os.environ.pop("MASTER_ADDR", None)
510+
os.environ.pop("MASTER_PORT", None)
497511

498512
elif request.param == "horovod":
499513
request.node.stash[is_horovod_stash_key] = True

tests/ignite/distributed/comp_models/test_native.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,8 @@ def _test__native_dist_model_create_from_context_set_local_rank(true_conf):
334334
def _test__native_dist_model_create_from_context_no_dist(true_backend, true_device):
335335
assert _NativeDistModel.create_from_context() is None
336336

337-
dist.init_process_group(true_backend, "tcp://0.0.0.0:2222", world_size=1, rank=0)
337+
store = dist.TCPStore("0.0.0.0", 2222, world_size=1, is_master=True)
338+
dist.init_process_group(true_backend, store=store, world_size=1, rank=0)
338339
dist.barrier()
339340

340341
_test__native_dist_model_create_from_context_no_local_rank()
@@ -358,7 +359,9 @@ def _test__native_dist_model_create_from_context_no_dist(true_backend, true_devi
358359
def _test__native_dist_model_create_from_context_dist(local_rank, rank, world_size, true_backend, true_device):
359360
assert _NativeDistModel.create_from_context() is None
360361

361-
dist.init_process_group(true_backend, "tcp://0.0.0.0:2222", world_size=world_size, rank=rank)
362+
is_master = rank == 0
363+
store = dist.TCPStore("0.0.0.0", 2222, world_size=world_size, is_master=is_master)
364+
dist.init_process_group(true_backend, store=store, world_size=world_size, rank=rank)
362365
dist.barrier()
363366
if torch.cuda.is_available():
364367
torch.cuda.set_device(local_rank)
@@ -397,7 +400,7 @@ def test__native_dist_model_create_no_dist_nccl(clean_env):
397400

398401

399402
@pytest.mark.distributed
400-
@pytest.mark.parametrize("init_method", [None, "tcp://0.0.0.0:22334", "FILE"])
403+
@pytest.mark.parametrize("init_method", [None, "FILE"])
401404
def test__native_dist_model_create_dist_gloo_1(init_method, get_fixed_dirname, local_rank, world_size):
402405
if init_method == "FILE":
403406
init_method = f"file://{get_fixed_dirname('native_dist_model_create_dist_gloo_1')}/shared"
@@ -418,7 +421,7 @@ def test__native_dist_model_create_dist_gloo_2(local_rank, world_size):
418421

419422
@pytest.mark.distributed
420423
@pytest.mark.skipif(torch.cuda.device_count() < 1, reason="Skip if no GPU")
421-
@pytest.mark.parametrize("init_method", [None, "tcp://0.0.0.0:22334", "FILE"])
424+
@pytest.mark.parametrize("init_method", [None, "FILE"])
422425
def test__native_dist_model_create_dist_nccl_1(init_method, get_fixed_dirname, local_rank, world_size):
423426
if init_method == "FILE":
424427
init_method = f"file://{get_fixed_dirname('native_dist_model_create_dist_nccl_1')}/shared"
@@ -444,7 +447,9 @@ def test__native_dist_model_create_dist_nccl_2(local_rank, world_size):
444447
def test__native_dist_model_warning_index_less_localrank(local_rank, world_size):
445448
assert _NativeDistModel.create_from_context() is None
446449

447-
dist.init_process_group("nccl", "tcp://0.0.0.0:2222", world_size=world_size, rank=local_rank)
450+
is_master = local_rank == 0
451+
store = dist.TCPStore("0.0.0.0", 2222, world_size=world_size, is_master=is_master)
452+
dist.init_process_group("nccl", store=store, world_size=world_size, rank=local_rank)
448453
dist.barrier()
449454
# We deliberately incorrectly set cuda device to 0
450455
torch.cuda.set_device(0)
@@ -496,7 +501,7 @@ def _test__native_dist_model_spawn(backend, num_workers_per_machine, device, ini
496501

497502
@pytest.mark.distributed
498503
@pytest.mark.skipif("WORLD_SIZE" in os.environ, reason="Skip if launched as multiproc")
499-
@pytest.mark.parametrize("init_method", [None, "CUSTOM_ADDR_PORT", "env://", "tcp://0.0.0.0:22334", "FILE"])
504+
@pytest.mark.parametrize("init_method", [None, "CUSTOM_ADDR_PORT", "env://", "FILE"])
500505
def test__native_dist_model_spawn_gloo(init_method, dirname):
501506
spawn_kwargs = {}
502507

@@ -532,7 +537,7 @@ def test__native_dist_model_spawn_gloo(init_method, dirname):
532537
@pytest.mark.distributed
533538
@pytest.mark.skipif("WORLD_SIZE" in os.environ, reason="Skip if launched as multiproc")
534539
@pytest.mark.skipif(torch.cuda.device_count() < 1, reason="Skip if no GPU")
535-
@pytest.mark.parametrize("init_method", [None, "CUSTOM_ADDR_PORT", "tcp://0.0.0.0:22334", "FILE"])
540+
@pytest.mark.parametrize("init_method", [None, "CUSTOM_ADDR_PORT", "FILE"])
536541
def test__native_dist_model_spawn_nccl(init_method, dirname):
537542
spawn_kwargs = {}
538543

@@ -720,3 +725,8 @@ def test__setup_ddp_vars_from_slurm_env_bad_configs():
720725
"SLURM_JOB_ID": "12345",
721726
}
722727
_setup_ddp_vars_from_slurm_env(environ)
728+
729+
730+
def test__native_dist_model_tcp_init_method_error():
731+
with pytest.raises(ValueError, match="will hang. To fix this, please configure MASTER_ADDR"):
732+
_NativeDistModel.create_from_backend(backend="gloo", init_method="tcp://10.1.1.20:23456", rank=0, world_size=1)

tests/ignite/distributed/test_launcher.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,6 @@ def _test_check_idist_parallel_torch_launch(init_method, fp, backend, nprocs):
103103
"init_method",
104104
[
105105
None,
106-
pytest.param(
107-
"tcp://0.0.0.0:29500",
108-
marks=pytest.mark.skipif(
109-
"dev" in torch.__version__,
110-
reason="Skip tcp:// init_method with torchrun on nightly due to incompatibility",
111-
),
112-
),
113106
"FILE",
114107
],
115108
)
@@ -241,7 +234,7 @@ def _test_func(index, ws, device, backend, true_init_method):
241234
@pytest.mark.distributed
242235
@pytest.mark.skipif("WORLD_SIZE" in os.environ, reason="Skip if launched as multiproc")
243236
@pytest.mark.skipif(not has_native_dist_support, reason="Skip if no native dist support")
244-
@pytest.mark.parametrize("init_method", ["env://", "tcp://0.0.0.0:29500", "FILE"])
237+
@pytest.mark.parametrize("init_method", ["env://", "FILE"])
245238
@pytest.mark.parametrize(
246239
"backend",
247240
["gloo", pytest.param("nccl", marks=pytest.mark.skipif(torch.cuda.device_count() < 1, reason="Skip if no GPU"))],
@@ -259,7 +252,7 @@ def test_idist_parallel_spawn_n_procs_native(init_method, backend, dirname):
259252
@pytest.mark.distributed
260253
@pytest.mark.skipif("WORLD_SIZE" not in os.environ, reason="Skip if not launched as multiproc")
261254
@pytest.mark.skipif(not has_native_dist_support, reason="Skip if no native dist support")
262-
@pytest.mark.parametrize("init_method", ["env://", "tcp://0.0.0.0:29500", "FILE"])
255+
@pytest.mark.parametrize("init_method", ["env://", "FILE"])
263256
@pytest.mark.parametrize(
264257
"backend",
265258
["gloo", pytest.param("nccl", marks=pytest.mark.skipif(torch.cuda.device_count() < 1, reason="Skip if no GPU"))],
@@ -296,3 +289,9 @@ def test_idist_parallel_spawn_params_xla():
296289
res = parallel._spawn_params
297290
assert "nproc_per_node" in res and res["nproc_per_node"] == 8
298291
assert "start_method" in res and res["start_method"] == "fork"
292+
293+
294+
def test_idist_parallel_tcp_init_method_error():
295+
with pytest.raises(ValueError, match="will hang. To fix this, please configure MASTER_ADDR"):
296+
with idist.Parallel(backend="gloo", init_method="tcp://10.1.1.20:23456", nproc_per_node=1) as parallel:
297+
pass

tests/ignite/distributed/utils/test_native.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def _test_native_distrib_single_node_launch_tool(backend, device, local_rank, wo
3838

3939
@pytest.mark.distributed
4040
@pytest.mark.skipif(not has_native_dist_support, reason="Skip if no native dist support")
41-
@pytest.mark.parametrize("init_method", [None, "tcp://0.0.0.0:22334", "FILE"])
41+
@pytest.mark.parametrize("init_method", [None, "FILE"])
4242
def test_native_distrib_single_node_launch_tool_gloo(init_method, get_fixed_dirname, local_rank, world_size):
4343
from datetime import timedelta
4444

@@ -56,7 +56,7 @@ def test_native_distrib_single_node_launch_tool_gloo(init_method, get_fixed_dirn
5656
@pytest.mark.distributed
5757
@pytest.mark.skipif(not has_native_dist_support, reason="Skip if no native dist support")
5858
@pytest.mark.skipif(torch.cuda.device_count() < 1, reason="Skip if no GPU")
59-
@pytest.mark.parametrize("init_method", [None, "tcp://0.0.0.0:22334", "FILE"])
59+
@pytest.mark.parametrize("init_method", [None, "FILE"])
6060
def test_native_distrib_single_node_launch_tool_nccl(init_method, get_fixed_dirname, local_rank, world_size):
6161
if init_method == "FILE":
6262
init_method = f"file://{get_fixed_dirname('native_distrib_single_node_launch_tool_nccl')}/shared"
@@ -80,7 +80,7 @@ def _test_native_distrib_single_node_spawn(init_method, backend, device, **kwarg
8080
@pytest.mark.distributed
8181
@pytest.mark.skipif(not has_native_dist_support, reason="Skip if no native dist support")
8282
@pytest.mark.skipif("WORLD_SIZE" in os.environ, reason="Skip if launched as multiproc")
83-
@pytest.mark.parametrize("init_method", [None, "tcp://0.0.0.0:22334", "FILE"])
83+
@pytest.mark.parametrize("init_method", [None, "FILE"])
8484
def test_native_distrib_single_node_spawn_gloo(init_method, dirname):
8585
from datetime import timedelta
8686

@@ -97,7 +97,7 @@ def test_native_distrib_single_node_spawn_gloo(init_method, dirname):
9797
@pytest.mark.skipif(not has_native_dist_support, reason="Skip if no native dist support")
9898
@pytest.mark.skipif("WORLD_SIZE" in os.environ, reason="Skip if launched as multiproc")
9999
@pytest.mark.skipif(torch.cuda.device_count() < 1, reason="Skip if no GPU")
100-
@pytest.mark.parametrize("init_method", [None, "tcp://0.0.0.0:22334", "FILE"])
100+
@pytest.mark.parametrize("init_method", [None, "FILE"])
101101
def test_native_distrib_single_node_spawn_nccl(init_method, dirname):
102102
if init_method == "FILE":
103103
init_method = f"file://{dirname}/shared"

0 commit comments

Comments
 (0)