feat: Topology aware placement - #2612
Merged
Merged
Conversation
Contributor
Author
|
/okay to test b9bed0a |
4 tasks
youngeunkwon0405
force-pushed
the
youngeunk/topology-aware-placement
branch
2 times, most recently
from
May 28, 2026 20:49
f205d3c to
37452f1
Compare
Contributor
Author
|
/okay to test 37452f1 |
ananthsub
reviewed
May 28, 2026
tdene
added a commit
to tdene/RL
that referenced
this pull request
May 29, 2026
Signed-off-by: Teodor-Dumitru Ene <teodord.ene@gmail.com>
youngeunkwon0405
force-pushed
the
youngeunk/topology-aware-placement
branch
2 times, most recently
from
June 3, 2026 21:23
12ea627 to
3dab75e
Compare
Signed-off-by: Terry Kong <terryk@nvidia.com>
…d_bundle Consolidate the two per-bundle GPU-info gather paths (RayVirtualCluster's inline loop and SGLang's separate path) onto a single get_reordered_bundle that gathers via _get_gpu_id_info and orders via _sort_bundle_indices_by_topology, returning (reordered_bundle_indices, reordered_gpu_ids, nvlink_domain_per_bundle_index). - Removes the duplicated per-bundle gather loop in _get_sorted_bundle_indices. - Fixes an undefined GetGPUIDActor reference: its class definition was dropped when this branch was rebased onto main, leaving get_reordered_bundle calling a nonexistent symbol. It now uses the surviving _get_gpu_id_info task. - SGLang placement becomes topology-aware on topology-probed clusters; without NVLink-domain resources it falls back to the identical (node_id, gpu_id) ordering, so behavior is unchanged on non-topology clusters (incl. CI). All 30 topology unit tests pass. Signed-off-by: Terry Kong <terryk@nvidia.com>
terrykong
force-pushed
the
youngeunk/topology-aware-placement
branch
from
June 22, 2026 19:43
0f2632b to
6874bf5
Compare
terrykong
enabled auto-merge (squash)
June 22, 2026 22:24
Collaborator
|
/ok to test 6874bf5 |
ananthsub
previously approved these changes
Jun 23, 2026
The SGLang server fails to start during CUDA graph capture with
"CuTe Experimental module is only supported on Cuda toolkit 13.1 and
above!", so every unit test that spins up a real SGLang server errors at
fixture setup ("Server process terminated unexpectedly"). This reproduces
on main and is not caused by this branch - it is the same environment
failure that prompted the temporary SGLang test skip in #2881.
Skip the five sglang unit-test modules that launch a real server:
test_sglang_generation, test_sglang_launch, test_sglang_worker_init,
test_sglang_worker_memory, and test_weight_update_real. The router-only and
utils smoke tests are left enabled since they do not start a server.
Signed-off-by: Terry Kong <terryk@nvidia.com>
Collaborator
|
/ok to test 4b82af4 |
yuki-97
approved these changes
Jun 23, 2026
This was referenced Jun 24, 2026
ashors1
pushed a commit
that referenced
this pull request
Jun 27, 2026
Signed-off-by: Youngeun Kwon <youngeunk@nvidia.com> Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com> Signed-off-by: Terry Kong <terryk@nvidia.com> Co-authored-by: Ananth Subramaniam <ansubramania@nvidia.com> Co-authored-by: Terry Kong <terryk@nvidia.com> Signed-off-by: Anna Shors <ashors@nvidia.com>
tdene
added a commit
to tdene/RL
that referenced
this pull request
Jul 29, 2026
Signed-off-by: Teodor-Dumitru Ene <teodord.ene@gmail.com>
tdene
added a commit
to tdene/RL
that referenced
this pull request
Aug 4, 2026
Signed-off-by: Teodor-Dumitru Ene <teodord.ene@gmail.com>
tdene
added a commit
to tdene/RL
that referenced
this pull request
Aug 5, 2026
Signed-off-by: Teodor-Dumitru Ene <teodord.ene@gmail.com>
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.
What does this PR do?
Adds topology-aware NVLink-domain placement for all NeMo-RL training algorithms (GRPO, SFT, DPO, RM, distillation). On multi-rack GB200 NVL72 (or any cluster where nodes are grouped into NVLink switch fabrics), this ensures that tensor-parallel and pipeline-parallel groups stay within the same NVLink domain, so collective operations use NVLink instead of InfiniBand.
How it works
1. Cluster setup —
ray.subray.subruns a topology probe on each node at cluster start. The probe reads two pieces of information and registers them as Ray custom resources:nvlink_domain_<ClusterUUID>1.0nvidia-smi -qClusterUUID — all nodes sharing a NVLink switch fabric get the same UUIDtopo_rankSLURM_TOPOLOGY_ADDR(block.node) →SLURM_PROCID→ hostname digitsNo changes to
ray.subinvocation are required — the probe runs unconditionally and falls back silently when topology info is unavailable (e.g. DGX/HGX, non-SLURM environments).2. YAML configuration
Set
cluster.segment_sizeto the number of training nodes per NVLink domain segment:segment_size: null(the default in all exemplar configs) disables topology-aware placement and falls back to standard Ray scheduling.The value to use depends on your hardware:
segment_size: 18.segment_size= number of nodes that share one NVLink switch fabric.3. How training node selection works
When
segment_sizeis set, NeMo-RL:ray.nodes()for each node'snvlink_domain_*andtopo_rankcustom resources.topo_rank.segment_sizenodes each) from domains in topological order untilnum_nodestraining nodes are claimed.segment_sizetoRayVirtualClusterso that rank assignment within each placement group also follows the topological order (domain_min_topo_rank→topo_rank→gpu_id).If no NVLink domain info is found (nodes have no
nvlink_domain_*resource), the feature degrades gracefully to unordered placement with a warning.4. Inference segment size (non-colocated GRPO)
For non-colocated GRPO, the inference cluster segment size is derived automatically from the generation config — you do not need to set it manually:
Inference topology constraints are applied only when
nodes_per_instance > 1(cross-node model parallelism) andinference_nodesis divisible bynodes_per_instance. Inference nodes are allocated from the nodes not claimed by training, so the two pools never overlap.Example (40 nodes, 5 NVLink domains × 8 nodes each,
segment_size=8, training on 24 nodes, vLLM TP=32,gpus_per_node=8):gpus_per_instance = 32,nodes_per_instance = 4.Issues
N/A
Testing
Validated on the current branch HEAD on two clusters — GB200 (hsg) and H100 (cw-dfw) — across both SGLang and Megatron backends, with
cluster.segment_sizeset.GB200 (hsg) — NVL72 rack = 18 nodes × 4 GPU; one rack = one NVLink domain
Performance — Megatron MoE, cross-rack expert parallelism (the feature's target case):
examples/configs/recipes/llm/grpo-qwen3-30ba3b-8n4g-megatron.yaml(Qwen3-30B-A3B GRPO),expert_model_parallel_size=8(each EP group spans 2 nodes), TP=PP=1.segment_size=2(ON) vsnull(OFF) in the same allocation (null≡mainbehavior, feature gated off). Mean of steps 6–12:policy_and_reference_logprobs(EP all-to-all fwd pass)policy_training(fwd+bwd+optim)With the EP group kept inside one NVLink domain (ON), the expert all-to-all runs over NVLink instead of InfiniBand (OFF). The end-to-end step gain (~2%) is diluted by generation (which the feature does not affect); the training collectives — especially the logprob forward pass — improve ~5–27%.
Functional — SGLang generation with the feature:
grpo-qwen2.5-math-1.5b-instruct-1n8g-fsdp2tp1-sglang.yaml, 1 node × 4 GPU,segment_size=1, 5 steps: ✅ completed.H100 (cw-dfw) — 8 GPU/node, no multi-node NVLink fabric
Functional "nothing broken" with the feature enabled (1 node × 8 GPU,
segment_size=1, 5 steps each):grpo-qwen2.5-math-1.5b-instruct-1n8g-fsdp2tp1-sglang.yaml: ✅ completed.grpo-llama3.2-1b-instruct-1n8g-megatron.yaml: ✅ completed.On H100 the cross-rack perf benefit is not expected (NVLink domains are per-node); this confirms the feature degrades to a correct no-op and breaks nothing on that architecture.
Unit tests:
tests/unit/distributed/test_topology_placement.py(30 tests) pass.Before your PR is "Ready for review"
Pre checks:
tests/unit/distributed/test_topology_placement.py)Additional Information
segment_size: nullis added to all exemplar configs underexamples/configs/*.yamlas the documented default.cluster.segment_sizekey.prepare_segment_topologyhelper invirtual_cluster.pycentralises the probe-and-select logic so algorithms don't duplicate it.