Skip to content

Drop the unused NCCL process group from the distributed workers#224

Open
clemsgrs wants to merge 2 commits into
mainfrom
drop-unused-nccl-process-group
Open

Drop the unused NCCL process group from the distributed workers#224
clemsgrs wants to merge 2 commits into
mainfrom
drop-unused-nccl-process-group

Conversation

@clemsgrs

Copy link
Copy Markdown
Owner

Summary

The distributed workers built an NCCL process group with zero live collectives — every cross-rank exchange goes through the filesystem (shard files / final artifacts + the JSONL progress bridge). The group existed only so get_global_rank() / get_global_size() could call dist.get_rank() / dist.get_world_size(), values torchrun already exports as RANK / WORLD_SIZE. Cost: an NCCL init, a per-rank comms buffer, and a 14-day-timeout hang surface — for no benefit.

Changes

  • slide2vec/distributed/__init__.pyenable() records the torchrun-exported topology (RANK / WORLD_SIZE / LOCAL_RANK / LOCAL_WORLD_SIZE), or single-process defaults when launched bare, into module state and keeps only the torch.cuda.set_device() binding. It no longer calls init_process_group (the allow_nccl_timeout knob is gone with it). is_enabled() / get_global_* read that module state instead of a live process group. Drops the torch.distributed, datetime, and unused random imports.
  • pipeline_worker.py / direct_embed_worker.py — remove the now-dead dist.destroy_process_group() teardown and the torch.distributed import. Their encode logic is byte-identical modulo indentation (verified programmatically).
  • hf_login() — removes the dead dist.barrier() (and the now-unused is_enabled_and_multiple_gpus helper). The barrier only ever ran in the single-process parent, but was a latent hang: had it run multi-rank with HF_TOKEN unset, non-main ranks would return early while rank 0 blocked on the barrier alone.

Validation

  • Full non-heavy suite green (500 passed).
  • New/updated tests lock the contract: no init_process_group / destroy_process_group / barrier / collectives in the module (AST), set_device survives, no torch.distributed/datetime import, and get_global_rank/get_global_size/is_enabled read module state rather than a process group.
  • Live 2-rank torchrun launch (--nproc_per_node=2, 2× GPU): enable() reads the env, binds cuda:{local_rank}, and initializes no process group (dist.is_initialized() == False).

Closes #219

clemsgrs added 2 commits July 17, 2026 01:44
The distributed workers built an NCCL process group that ran zero live
collectives: every cross-rank exchange happens through the filesystem
(shard files / final artifacts + the JSONL progress bridge). The group
existed only so get_global_rank()/get_global_size() could call
dist.get_rank()/dist.get_world_size() — values torchrun already exports
as RANK / WORLD_SIZE. It cost an NCCL init, a per-rank comms buffer, and
a 14-day-timeout hang surface for no benefit.

distributed.enable() now records the torchrun-exported topology
(RANK / WORLD_SIZE / LOCAL_RANK / LOCAL_WORLD_SIZE) — or single-process
defaults when launched bare — into module state and keeps only the
torch.cuda.set_device() binding; it no longer calls init_process_group.
is_enabled()/get_global_* read that module state instead of a live
process group. The now-dead destroy_process_group() teardown and the
torch.distributed import are removed from pipeline_worker and
direct_embed_worker (their encode logic is unchanged).

Also removes the dead dist.barrier() from hf_login() (and the now-unused
is_enabled_and_multiple_gpus helper). The barrier only ever ran in the
single-process parent, but was a latent hang: had it run multi-rank with
HF_TOKEN unset, non-main ranks would return early while rank 0 blocked on
the barrier alone.

Validated with a live 2-rank torchrun launch: enable() reads the env,
binds cuda:{local_rank}, and initializes no process group.
Review follow-ups on the process-group removal (#219):

- slide2vec.distributed no longer reads or exports MASTER_ADDR / MASTER_PORT
  and loses _get_available_port() plus the socket import: those only located
  the env:// rendezvous for the process group that no longer exists. enable()
  still records and exports the four torchrun topology variables, and the
  bare-launch error now names the real failure (no torchrun env, no CUDA
  device) instead of "PyTorch distributed".
- Reword the get_global_rank/get_local_rank/get_local_size docstrings that
  still spoke of a "process group".
- Remove the five dead 'import torch.distributed as dist' +
  is_available/is_initialized stubs in the worker tests; they only
  neutralized the destroy_process_group teardown the workers no longer have.
  The AST contract test now also locks out the socket import.

Validated: full non-heavy suite green (500 passed); live 2-rank torchrun
against the working tree reports the correct topology, binds cuda:{0,1}, and
initializes no process group; a bare single-process enable() yields the
rank-0/world-1 defaults.
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.

Drop the unused NCCL process group from the distributed workers

1 participant