Skip to content

Commit 0d10840

Browse files
committed
fix test bugs
1 parent b6007b3 commit 0d10840

1 file changed

Lines changed: 78 additions & 6 deletions

File tree

fastvideo/tests/distributed/test_ring_attention.py

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,13 @@ def log(message: str) -> None:
464464

465465
log("reference saved")
466466

467+
# Rank 0 performs extra reference computation and file I/O. Keep the
468+
# other ranks alive until that work is complete so they do not tear
469+
# down NCCL while rank 0 is still using the CUDA context.
470+
dist.barrier()
471+
torch.cuda.synchronize(device)
472+
log("worker complete; all ranks ready for teardown")
473+
467474
finally:
468475
if dist.is_available() and dist.is_initialized():
469476
log("destroying torch distributed process group")
@@ -613,6 +620,13 @@ def log(message: str) -> None:
613620

614621
log("reference saved")
615622

623+
# The subgroup communicators are destroyed collectively by
624+
# cleanup_dist_env_and_memory(). Do not let nonzero ranks enter that
625+
# teardown while rank 0 is still computing/saving the reference.
626+
dist.barrier()
627+
torch.cuda.synchronize(device)
628+
log("worker complete; all ranks ready for teardown")
629+
616630
finally:
617631
log("tearing down FastVideo distributed state")
618632
cleanup_dist_env_and_memory()
@@ -656,15 +670,20 @@ def _run_torchrun(
656670
env.update(
657671
{
658672
"PYTHONUNBUFFERED": "1",
659-
"NCCL_DEBUG": env.get("NCCL_DEBUG", "INFO"),
660-
"TORCH_DISTRIBUTED_DEBUG": env.get(
661-
"TORCH_DISTRIBUTED_DEBUG",
662-
"DETAIL",
663-
),
664673
"TORCH_NCCL_ASYNC_ERROR_HANDLING": "1",
665674
}
666675
)
667676

677+
# Detailed distributed logging is useful when diagnosing a hang, but it
678+
# must not be the default test environment. In particular, PyTorch's
679+
# DETAIL wrapper can deadlock a raw NCCL P2P send/recv on some NCCL and GPU
680+
# combinations before Ring Attention itself is reached. Preserve any
681+
# values explicitly supplied by the caller, and only provide verbose
682+
# defaults when the test-specific debug switch is enabled.
683+
if env.get("FASTVIDEO_RING_TEST_DEBUG") == "1":
684+
env.setdefault("NCCL_DEBUG", "INFO")
685+
env.setdefault("TORCH_DISTRIBUTED_DEBUG", "DETAIL")
686+
668687
# # Some containerized hosts have broken CUDA P2P/IPC/SHM paths while
669688
# # NCCL socket transport remains functional. Keep normal NCCL behavior by
670689
# # default, but allow an explicit correctness-only socket fallback.
@@ -707,6 +726,59 @@ def _run_torchrun(
707726
)
708727

709728

729+
@pytest.mark.parametrize(
730+
("debug_enabled", "expected_nccl", "expected_torch"),
731+
[
732+
(False, None, None),
733+
(True, "INFO", "DETAIL"),
734+
],
735+
)
736+
def test_torchrun_debug_defaults_are_opt_in(
737+
monkeypatch: pytest.MonkeyPatch,
738+
tmp_path: Path,
739+
debug_enabled: bool,
740+
expected_nccl: str | None,
741+
expected_torch: str | None,
742+
) -> None:
743+
"""The harness must not enable distributed debug wrappers by default."""
744+
captured_env: dict[str, str] = {}
745+
746+
class _CompletedProcess:
747+
pid = 1
748+
749+
@staticmethod
750+
def wait(timeout: int | None = None) -> int:
751+
del timeout
752+
return 0
753+
754+
def fake_popen(
755+
cmd: list[str],
756+
*,
757+
env: dict[str, str],
758+
start_new_session: bool,
759+
) -> _CompletedProcess:
760+
del cmd, start_new_session
761+
captured_env.update(env)
762+
return _CompletedProcess()
763+
764+
monkeypatch.delenv("NCCL_DEBUG", raising=False)
765+
monkeypatch.delenv("TORCH_DISTRIBUTED_DEBUG", raising=False)
766+
if debug_enabled:
767+
monkeypatch.setenv("FASTVIDEO_RING_TEST_DEBUG", "1")
768+
else:
769+
monkeypatch.delenv("FASTVIDEO_RING_TEST_DEBUG", raising=False)
770+
monkeypatch.setattr(subprocess, "Popen", fake_popen)
771+
772+
_run_torchrun(
773+
script_path=Path(__file__),
774+
nproc_per_node=2,
775+
output_path=tmp_path / "unused.pt",
776+
)
777+
778+
assert captured_env.get("NCCL_DEBUG") == expected_nccl
779+
assert captured_env.get("TORCH_DISTRIBUTED_DEBUG") == expected_torch
780+
781+
710782
def test_multi_gpu_ring_attention_matches_full_attention(
711783
tmp_path: Path,
712784
) -> None:
@@ -843,4 +915,4 @@ def _parse_args() -> argparse.Namespace:
843915
else:
844916
_run_multi_gpu_worker(
845917
Path(args.output),
846-
)
918+
)

0 commit comments

Comments
 (0)