Skip to content

[RCCL] stop encoding MLOPart in PCI function bits and misclassifying XGMI peers - #10640

Merged
wenkaidu merged 9 commits into
ROCm:developfrom
wenkaidu:fix/rccl-mlopart-xgmi-pci-alias
Aug 26, 2026
Merged

wenkaidu merged 9 commits into
ROCm:developfrom
wenkaidu:fix/rccl-mlopart-xgmi-pci-alias

Conversation

@wenkaidu

@wenkaidu wenkaidu commented Aug 24, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

RCCL topology on AMD compute-partitioned GPUs (gfx1250 DPX/XCP and MI300X CPX) was aborting or building a wrong graph. HIP reports logical partitions as extra PCI functions (.1–.7), but only the physical function .0 exists in sysfs as a GPU. NCCL 2.30’s MLOPart overlay originally used those same function bits, so the two encodings collided.

Technical Details

MLOPart is NVIDIA’s name for a logical GPU partition of one physical GPU (Blackwell/GB200 “uGPU”). CUDA exposes two devices that share a PCI BDF and tags the name as MLOPart0 / MLOPart1. NCCL 2.30 parses that string, then overlays a partition index onto the packed bus ID so the DEV nodes stay unique while still grouping as siblings when those bits are masked off.

RCCL reuses that overlay for HIP logical GPUs. HIP names have no "MLOPart" tag; the index is taken from the HIP PCI function instead. On this hardware the HIP aliases are not real endpoints: DRM/sysfs GPU is only ….00.0, and a non-zero function may be a NIC or missing entirely.

The overlay now sits above the 36-bit PCI bus ID (NCCL_TOPO_MLOPART_SHIFT=36, enable bit + 3-bit index, DEV_MAX=8) so partitions 0–7 hang off the physical PCI node without clobbering the function nibble. Genuine NVIDIA MLOPart siblings still group after masking.

Failures this PR fixes

  1. MLOPart overlay used PCI function bits [1:0]. HIP can expose sibling partitions as ….00.0 / .1 (and CPX .0–.7), so ncclTopoCheckMloPartBusId aborted even when HIP names have no "MLOPart" tag. A 2-partition mask also could not represent CPX.
  2. XGMI tclass came from sysfs at the HIP BDF. A HIP alias such as 0001:01:00.1 can be a NIC (0x028000) or missing, so a GPU–GPU hop was typed as a switch/NIC instead of NVL.
  3. HIP “fake” PCI functions were treated as extra endpoints. Logical GPUs were hung off a NIC node or a non-existent PCI function instead of the physical GPU.
  4. AllGather3 looked up the GPU by raw comm->busId. After the DEV overlay, node ids are NCCL_TOPO_GPU_LOCAL_ID of the overlaid DEV, so partition ranks missed. Match NCCL and use ncclTopoRankToIndex.
  5. XGMI DEV lookup used the raw HIP BDF. On packages where the physical GPU is already at a non-zero function (XCP .1), lookup must match overlay DEV on the same domain:bus:device regardless of physical function.
  6. Unconfigured ualink (link_type=invalid) is a node setup issue, not a missing interconnect. UALoE is used only when fabric is ready/active; otherwise fall back to 1-hop XGMI.

What changed

Issue Tracking

  • Move MLOPart overlay from PCI function [1:0] to [39:36] (SHIFT=36, mask 0xf << 36: enable + 3-bit index 0–7), below GPU local rank (bit 40). Real PCI IDs never occupy those bits.
  • Stamp mlopart from the HIP PCI function (0–7) when that function is not a GPU in sysfs. Remap HIP alias BDFs to the physical .0 PCI node and attach all partition s under it.
  • Stamp direct 1-hop XGMI (and UALoE) peers with tclass=0x120000 (PCI_ACCELERATOR_CLASS) at XML creation. AMD fill-missing-tclass trusts sysfs only for GPU / accelerator / NVSwitch; NIC or missing class stays accelerator.
  • ncclTopoGetDevForPciBusId: if the exact busId misses, match an overlay DEV on the same domain:bus:device whose MLOPart index equals the HIP function nibble (covers physical GPUs at .1).
  • alt_rsmi findCardForBdf: exact BDF first; if function ≠ 0 and miss, retry function 0.
  • AllGather3 / topo_expl: look up the GPU node by rank, not raw busId.
  • Tests: overlay vs function nibble; eight CPX partitions under one physical PCI; XGMI when the physical GPU is at .1; alt_rsmi fake-function fallback to fn 0. Init microtests stub ncclOsGetPciDeviceClassByBusId.

JIRA ID : ROCM-29722

Test Plan

  • rccl-UnitTestsFixturesDebug --gtest_filter='TopoTest.*'
  • rccl-UnitTestsAltRsmi --gtest_filter='AltRsmiTest.FabricInfo_FakePciFunctionFallsBackToFn0'
  • Topology dump with NCCL_CUMEM_ENABLE=0 NCCL_TOPO_DUMP_FILE=… on gfx1250 DPX (-np 2) and MI300X CPX (8 and 64 HIP devices)
  • Dump matches with default alt_rsmi (unset RCCL_USE_AMD_SMI_LIB)

Test Result

DebugFast + tests built. All 12 TopoTest cases passed (existing + overlay/CPX/XCP). Alt-RSMI fake-function fallback passed.

On MI300X CPX (8 physical GPUs × 8 HIP partitions): 8-GPU dump has mlopart=0..7 under one physical PCI (0000:0c:00.0); 64-GPU dump has 64 s with mlopart, 8 physical PCI parents, and XGMI links stamped tclass=0x120000.

On gfx1250 DPX, both ranks sit under 0001:01:00.0 with mlopart=0/1 and bidirectional XGMI. sendrecv_perf can still report an internal error after graph search on that package (nChannels / path typing); that is separate from PCI placement.

Submission Checklist

wenkaidu and others added 2 commits August 21, 2026 22:46
…ing XGMI peers

MLOPart is NVIDIA's name for a logical GPU partition of one physical GPU
(Blackwell/GB200 "uGPU"). CUDA exposes two devices that share a PCI BDF and
tags the name as MLOPart0/MLOPart1. NCCL 2.30 parses that string, then overlays
a 2-bit partition index onto the packed bus ID so the two DEV nodes stay unique
while still grouping as siblings when those bits are masked off. RCCL inherited
that overlay; AMD devices are not MLOPart (HIP names have no "MLOPart" tag, so
the index stays UNDEF).

The overlay originally used bits [1:0] of the packed PCI ID, which are the PCI
function field. That is free on NVIDIA GPUs (almost always function .0) but
collides on AMD multi-die/XCP parts that HIP reports as 0001:01:00.0 and
.1. The collision made ncclTopoCheckMloPartBusId abort init even when MLOPart
was unused, and masking would have wrongly treated those dies as one physical
GPU.

This relocates the overlay to bits [37:36], above the 36-bit PCI bus ID
(domain/bus/device/function) and below NCCL_TOPO_GPU_LOCAL_RANK_SHIFT (40).
That is safe because:
- A real PCI bus ID never occupies bits [37:36], so the collision check only
  fires on a malformed ID, not on a non-zero function.
- Genuine MLOPart siblings still differ only in bit 37 and still mask to a
  common base, so grouping, CXB sharing, and NCCL_TOPO_SPLIT_MLOPART behavior
  are unchanged.
- Non-MLOPart IDs pass through unchanged (NCCL_TOPO_MLOPART_BUSID is a no-op
  when mlopart is UNDEF).
- GPU local IDs still fit in NCCL_TOPO_ID_LOCAL_ID_MASK.

Separately, XGMI tclass was inferred from the peer's sysfs PCI class. On this
package, 0001:01:00.1 is a real NIC, so one direction of the XGMI link was
wired as a switch hop and path search failed. Direct single-hop XGMI targets
are GPUs by construction (they come from the accelerator enumeration), so
record tclass as 0x120000 at creation. UALoE/fabric links and user-supplied
NCCL_TOPO_FILE XML are unchanged: those paths either already have xgmi nodes
or still need the switch fallback.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep PCI function .1 distinct from the MLOPart overlay, and treat
XGMI tclass 0x120000 as a GPU so a sysfs-aliased NIC class cannot
drop the peer link.

Co-authored-by: Cursor <cursoragent@cursor.com>
@wenkaidu
wenkaidu requested review from a team August 24, 2026 17:17
@therock-pr-bot

therock-pr-bot Bot commented Aug 24, 2026 •

Copy link
Copy Markdown

✅ All Policy Checks Passed

Check Status Details
📝 PR Description ✅ Pass —
⛔ Forbidden Files ✅ Pass —
🧪 Unit Test ⚠️ Warning Error: Source/code files changed without an accompanying unit test.
Expected: add at least one test file named like test_<name>.py / test_<name>.cpp (or <name>_test.*).
Current: code file(s) changed: projects/rccl/src/graph/topo.cc, projects/rccl/src/graph/topo.h, projects/rccl/src/graph/xml.cc, projects/rccl/src/graph/xml.h, projects/rccl/src/init.cc (+6 more); no test file found
🚫 Draft PR 🔜 To Be Enabled —
🚩 Feature Flag 🔜 To Be Enabled —
📊 Code Coverage 🔜 To Be Enabled —

🎉 All policy checks passed!

📖 Need help? See the Policy FAQ for details on every check and how to fix failures.

🙋 Wish to Override Policy?

@pvallem

pvallem commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Unrelated to this PR, but it turned up while tracing the xgmi paths — src/graph/xml.cc:369 in ncclTopoXmlLoadGpu:

On the AMD branch handlers[] has one element, but xmlLoadSub is called with nHandlers=2, so the match loop reads handlers[1].name past the end of the array. Any <gpu> child that isn't <xgmi> trips it — test/graph/XmlTests.cpp:910 feeds <gpu><c2c/></gpu> and does exactly that. Upstream has two handlers and the #if here cuts it to one; ncclTopoXmlLoadNic a few lines down uses the matching count.

  NCCLCHECK(xmlLoadSub(file, xml, head, handlers, sizeof(handlers) / sizeof(handlers[0])));

Not this PR's to fix — flagging it for a follow-up.

Comment thread projects/rccl/src/graph/xml.cc Resolved
Comment thread projects/rccl/test/graph/TopoTests.cpp Resolved
Comment thread projects/rccl/src/graph/topo.h Resolved
Comment thread projects/rccl/src/graph/xml.cc Resolved
Comment thread projects/rccl/test/graph/TopoTests.cpp Resolved
Comment thread projects/rccl/test/graph/TopoTests.cpp Resolved
UALoE peers are enumerated GPUs, so reuse the same accelerator tclass
stamp as 1-hop XGMI instead of falling through to sysfs. Size AMD GPU
XML handlers correctly, assert the MLOPart bit placement, pin the PCI
function nibble in GetDevNodes, and unit-test the stamp/fill seam.
@wenkaidu

Copy link
Copy Markdown
Contributor Author

Unrelated to this PR, but it turned up while tracing the xgmi paths — src/graph/xml.cc:369 in ncclTopoXmlLoadGpu:

On the AMD branch handlers[] has one element, but xmlLoadSub is called with nHandlers=2, so the match loop reads handlers[1].name past the end of the array. Any <gpu> child that isn't <xgmi> trips it — test/graph/XmlTests.cpp:910 feeds <gpu><c2c/></gpu> and does exactly that. Upstream has two handlers and the #if here cuts it to one; ncclTopoXmlLoadNic a few lines down uses the matching count.

  NCCLCHECK(xmlLoadSub(file, xml, head, handlers, sizeof(handlers) / sizeof(handlers[0])));

Not this PR's to fix — flagging it for a follow-up.

fixed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates RCCL’s topology encoding and XML generation to avoid PCI function collisions when MLOPart is not in use on AMD multi-function/XCP devices, and to prevent misclassification of direct XGMI peers due to sysfs PCI-class aliasing.

Changes:

  • Move the MLOPart overlay bits off the packed PCI function field and into bits [37:36], with compile-time assertions to enforce non-overlap with PCI busId and GPU local-rank bits.
  • Stamp direct XGMI peer links with PCI_ACCELERATOR_CLASS (0x120000) at creation time and add a helper to fill missing link tclass only when unset.
  • Add unit tests covering MLOPart busId overlay behavior and XGMI tclass handling (including fill short-circuit and NVSwitch fallback).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
projects/rccl/src/graph/topo.h Relocates MLOPart overlay bits and adds static assertions guarding bit layout.
projects/rccl/src/graph/topo.cc Updates MLOPart collision-check comment and aligns C2C comment with new mask semantics.
projects/rccl/src/graph/xml.h Introduces PCI_ACCELERATOR_CLASS, declares ncclTopoXmlFillLinkTclass, and adds an AMD-only helper to stamp XGMI peers as accelerators.
projects/rccl/src/graph/xml.cc Uses the new XGMI stamping helper, factors tclass fill into ncclTopoXmlFillLinkTclass, and makes GPU-subnode parsing use the handler array size.
projects/rccl/test/graph/TopoTests.cpp Adds tests for MLOPart overlay vs PCI function bits and for accelerator-vs-NIC tclass behavior in XGMI link construction.
projects/rccl/test/graph/XmlTests.cpp Adds XML-level tests verifying XGMI peer stamping and tclass fill short-circuit/fallback behavior (HIP/AMD only).

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

wenkaidu and others added 6 commits August 24, 2026 21:25
DPX/XCP partitions have no extra PCI function: KFD/HIP still name them
as .1 while DRM and sysfs only expose .0 (and .1 may be a NIC). alt_rsmi
now retries card lookup with function 0, and XGMI tclass uses the
accelerator class unless sysfs is a real GPU or switch. UALoE is used
only when fabric is ready/active; unconfigured ualink is a setup issue
and falls back to 1-hop XGMI. Together with the MLOPart overlay move
off PCI function bits, topology works with or without ualink and with
or without RCCL_USE_AMD_SMI_LIB=1.
gfx1250 DPX exposes a second HIP GPU at function .1, but sysfs there is a
NIC. Attach both ranks under 0001:01:00.0 and stamp mlopart from the PCI
function (0/1) instead of creating a GPU under the NIC BDF.

Captured NCCL_TOPO_DUMP_FILE from sendrecv_perf -np 2 on this node:

<system version="2">
  <cpu host_hash="0x1c062a26c18304c3" numaid="0" affinity="00000000,00000000,ffffffff,ffffffff,00000000,00000000,ffffffff,ffffffff" arch="x86_64" vendor="AuthenticAMD" familyid="191" modelid="81">
    <pci busid="0000:01:00.0" class="0x060400" vendor="0x1dd8" device="0x0008" subsystem_vendor="0x1dd8" subsystem_device="0x5201" link_speed="32.0 GT/s PCIe" link_width="16">
      <pci busid="0000:04:00.0" class="0x020000" vendor="0x1dd8" device="0x1002" subsystem_vendor="0x1dd8" subsystem_device="0x5201" link_speed="32.0 GT/s PCIe" link_width="16">
        <nic>
          <net name="enp4s0np0" dev="0" latency="0" speed="100000" port="0" guid="0x0" maxconn="65536" gdr="0" net="1"/>
        </nic>
      </pci>
    </pci>
    <pci busid="0001:01:00.0" class="0x120000" vendor="0x1002" device="0x75c7" subsystem_vendor="0x1002" subsystem_device="0x75c1" link_speed="32.0 GT/s PCIe" link_width="16">
      <gpu dev="0" sm="96" gcn="gfx1250" arch="38911" rank="0" gdr="0" mlopart="0">
        <xgmi target="0001:01:00.1" count="1" tclass="0x120000" fabric_supported="0"/>
      </gpu>
      <gpu dev="1" sm="96" gcn="gfx1250" arch="38911" rank="1" gdr="0" mlopart="1">
        <xgmi target="0001:01:00.0" count="1" tclass="0x120000" fabric_supported="0"/>
      </gpu>
    </pci>
  </cpu>
</system>

Co-authored-by: Cursor <cursoragent@cursor.com>
After the DEV/MLOPart overlay, GPU node ids are NCCL_TOPO_GPU_LOCAL_ID of
the overlaid DEV busId, so ncclTopoIdToIndex(..., comm->busId) misses
partition ranks. Match NCCL and use ncclTopoRankToIndex.

Co-authored-by: Cursor <cursoragent@cursor.com>
fillInfo() now calls ncclOsGetPciDeviceClassByBusId for MLOPart PCI-function
fallback. Add a no-op stub that returns an empty device class so existing
tests' default busId=0 path stays benign (isGpu=0 -> no mloPart assignment).

Co-Authored-By: Claude <noreply@anthropic.com>
HIP CPX aliases .1-.7 are missing from sysfs; widen the DEV overlay so all eight partitions hang off the physical function-0 PCI node instead of colliding in a two-partition mask.

Co-authored-by: Cursor <cursoragent@cursor.com>
@wenkaidu
wenkaidu merged commit 5f38cd0 into ROCm:develop Aug 26, 2026
31 of 37 checks passed
@wenkaidu
wenkaidu deleted the fix/rccl-mlopart-xgmi-pci-alias branch August 26, 2026 22:50
nileshnegi added a commit that referenced this pull request Aug 27, 2026
#10640 set mloPart=0 for all GPUs at PCI function 0, which triggered
hasMloPart and disabled GIN. It also disabled NET GDR via paths.cc:517.

Fix fillInfo to only set mloPart for fake HIP functions (fn > 0 that
aren't GPUs in sysfs). fn=0 GPUs keep mloPart as NCCL_TOPO_UNDEF — we
can't distinguish non-partitioned GPUs from CPX partition 0, and
setting mloPart=0 breaks non-partitioned systems.

Also handle the edge case where device class lookup fails: leave
mloPart undefined to avoid misclassifying a real GPU at fn>0.

Co-Authored-By: Claude <noreply@anthropic.com>
@systems-assistant

Copy link
Copy Markdown
Contributor

TheRock Submodule Bump Activity

Newest first

sdarisala pushed a commit that referenced this pull request Aug 28, 2026
…XGMI peers (#10640)

## Motivation
RCCL topology on AMD compute-partitioned GPUs (gfx1250 DPX/XCP and
MI300X CPX) was aborting or building a wrong graph. HIP reports logical
partitions as extra PCI functions (.1–.7), but only the physical
function .0 exists in sysfs as a GPU. NCCL 2.30’s MLOPart overlay
originally used those same function bits, so the two encodings collided.

## Technical Details
MLOPart is NVIDIA’s name for a logical GPU partition of one physical GPU
(Blackwell/GB200 “uGPU”). CUDA exposes two devices that share a PCI BDF
and tags the name as MLOPart0 / MLOPart1. NCCL 2.30 parses that string,
then overlays a partition index onto the packed bus ID so the DEV nodes
stay unique while still grouping as siblings when those bits are masked
off.

RCCL reuses that overlay for HIP logical GPUs. HIP names have no
"MLOPart" tag; the index is taken from the HIP PCI function instead. On
this hardware the HIP aliases are not real endpoints: DRM/sysfs GPU is
only ….00.0, and a non-zero function may be a NIC or missing entirely.

The overlay now sits above the 36-bit PCI bus ID
(NCCL_TOPO_MLOPART_SHIFT=36, enable bit + 3-bit index, DEV_MAX=8) so
partitions 0–7 hang off the physical PCI node without clobbering the
function nibble. Genuine NVIDIA MLOPart siblings still group after
masking.

### Failures this PR fixes

1. MLOPart overlay used PCI function bits [1:0]. HIP can expose sibling
partitions as ….00.0 / .1 (and CPX .0–.7), so ncclTopoCheckMloPartBusId
aborted even when HIP names have no "MLOPart" tag. A 2-partition mask
also could not represent CPX.
2. XGMI tclass came from sysfs at the HIP BDF. A HIP alias such as
0001:01:00.1 can be a NIC (0x028000) or missing, so a GPU–GPU hop was
typed as a switch/NIC instead of NVL.
3. HIP “fake” PCI functions were treated as extra endpoints. Logical
GPUs were hung off a NIC node or a non-existent PCI function instead of
the physical GPU.
4. AllGather3 looked up the GPU by raw comm->busId. After the DEV
overlay, node ids are NCCL_TOPO_GPU_LOCAL_ID of the overlaid DEV, so
partition ranks missed. Match NCCL and use ncclTopoRankToIndex.
5. XGMI DEV lookup used the raw HIP BDF. On packages where the physical
GPU is already at a non-zero function (XCP .1), lookup must match
overlay DEV on the same domain:bus:device regardless of physical
function.
6. Unconfigured ualink (link_type=invalid) is a node setup issue, not a
missing interconnect. UALoE is used only when fabric is ready/active;
otherwise fall back to 1-hop XGMI.

## What changed

## Issue Tracking

- Move MLOPart overlay from PCI function [1:0] to [39:36] (SHIFT=36,
mask 0xf << 36: enable + 3-bit index 0–7), below GPU local rank (bit
40). Real PCI IDs never occupy those bits.
- Stamp mlopart from the HIP PCI function (0–7) when that function is
not a GPU in sysfs. Remap HIP alias BDFs to the physical .0 PCI node and
attach all partition <gpu>s under it.
- Stamp direct 1-hop XGMI (and UALoE) peers with tclass=0x120000
(PCI_ACCELERATOR_CLASS) at XML creation. AMD fill-missing-tclass trusts
sysfs only for GPU / accelerator / NVSwitch; NIC or missing class stays
accelerator.
- ncclTopoGetDevForPciBusId: if the exact busId misses, match an overlay
DEV on the same domain:bus:device whose MLOPart index equals the HIP
function nibble (covers physical GPUs at .1).
- alt_rsmi findCardForBdf: exact BDF first; if function ≠ 0 and miss,
retry function 0.
- AllGather3 / topo_expl: look up the GPU node by rank, not raw busId.
- Tests: overlay vs function nibble; eight CPX partitions under one
physical PCI; XGMI when the physical GPU is at .1; alt_rsmi
fake-function fallback to fn 0. Init microtests stub
ncclOsGetPciDeviceClassByBusId.

JIRA ID : ROCM-29722

## Test Plan

- rccl-UnitTestsFixturesDebug --gtest_filter='TopoTest.*'
- rccl-UnitTestsAltRsmi
--gtest_filter='AltRsmiTest.FabricInfo_FakePciFunctionFallsBackToFn0'
- Topology dump with NCCL_CUMEM_ENABLE=0 NCCL_TOPO_DUMP_FILE=… on
gfx1250 DPX (-np 2) and MI300X CPX (8 and 64 HIP devices)
- Dump matches with default alt_rsmi (unset RCCL_USE_AMD_SMI_LIB)

    
## Test Result
DebugFast + tests built. All 12 TopoTest cases passed (existing +
overlay/CPX/XCP). Alt-RSMI fake-function fallback passed.

On MI300X CPX (8 physical GPUs × 8 HIP partitions): 8-GPU dump has
mlopart=0..7 under one physical PCI (0000:0c:00.0); 64-GPU dump has 64
<gpu>s with mlopart, 8 physical PCI parents, and XGMI links stamped
tclass=0x120000.

On gfx1250 DPX, both ranks sit under 0001:01:00.0 with mlopart=0/1 and
bidirectional XGMI. sendrecv_perf can still report an internal error
after graph search on that package (nChannels / path typing); that is
separate from PCI placement.

## Submission Checklist

- [ ] Look over the contributing guidelines at
https://github.com/ROCm/rocm-systems/blob/develop/CONTRIBUTING.md.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Nilesh M Negi <Nilesh.Negi@amd.com>
Co-authored-by: Claude <noreply@anthropic.com>
wenkaidu added a commit that referenced this pull request Aug 29, 2026
## Motivation

PR 10640 is causing a multi node regression on MI355

## Technical Details

#10640 taught fillInfo() to derive the MLOPart partition index from the
HIP PCI
function, so DPX/XCP/CPX logical GPUs -- HIP aliases at function .1-.7
that are
not GPUs in sysfs -- hang off the physical function-0 PCI node. That
change also
set mloPart=0 for every GPU sitting at function 0, because a
non-partitioned GPU
and CPX partition 0 are indistinguishable at that point: both are
function 0 and
both are a real GPU in sysfs. As a result every ordinary MI300X GPU
leaves
    fillInfo() with mloPart=0 instead of NCCL_TOPO_UNDEF.

A defined mloPart is not inert. ncclTopoCheckGdr() bails out early for
any
partitioned GPU (paths.cc: mloPart != UNDEF && !NCCL_NET_GDR_MLOPART),
so NET
GDR is reported unavailable for every rank. ncclTopoComputePaths() then
takes
its no-GDR fallback and diverts each GPU<->NET path whose type is <
PATH_PHB
through the GPU's local CPU via addInterStep(). The rail-local GPU->NIC
hop,
PATH_PXB on these boxes, is rewritten to PATH_PHB; paths that were
already
    PHB/SYS are untouched.

    That silently breaks Rome preset matching. parseRomeSystem() records
gdrLevel[nic][gpu] = gpu->paths[NET][n].type, and permuteNetIds()
compares it
against the preset, which carries PATH_PXB on the rail diagonal. With
every
diagonal entry degraded to PATH_PHB no model can match, so
parseRome4P2H()
returns without a graph and ncclTopoCompute() falls through to the
generic
search -- losing the preset's ring/tree base and its tuning/ll128
options with
no warning. On an 8-GPU MI300X with the rail NICs present in the
topology
(single node under RCCL_ENABLE_INTRANET=1) the ring drops from 64
channels to 2.
The stamp also sets comm->hasMloPart on every comm, which is what #10817
    reported as disabling GIN.

Restrict the stamp to what it was meant for: a HIP alias function (fn >
0) that
is not a GPU in sysfs. Physical fn=0 GPUs keep mloPart =
NCCL_TOPO_UNDEF. CPX
    partition 0 stays unstamped since it cannot be told apart from a
non-partitioned GPU here, and mis-stamping the common case is much worse
than
    leaving partition 0 alone.

Verified on an 8-GPU MI300X (gfx942, 8 rail mlx5 HCAs pinned via
NCCL_IB_HCA)
    with RCCL_ENABLE_INTRANET=1. Before, RCCL_DUMP_ROME_MODEL_FILE shows
gpuIds={0x1000011000, ...} with a PATH_PHB gdrLevel diagonal and no
match;
after, bare BDFs ({0x11000, ...}), a PATH_PXB diagonal, and "Found
matching Rome
model index 40 ... NET mapping: 0 1 2 3 4 5 6 7" at 64 channels. 8-rank
    all_reduce to 64 MiB reports 0 wrong.
    
## Issue Tracking

     JIRA ID: AICOMRCCL-2213

## Test Plan

Add four host microtests around the guard that decides whether
fillInfo() stamps
an MLOPart partition index on a rank (init.cc:1092-1108), and repair the
fake
that had kept that path untestable. The UUT is #include'd by
init-test.cc, so
    fillInfo() is called directly -- no GPU and no ncclCommInit.

The guard has two operands, and each one rejects a different input, so
all four
    inputs are covered independently:

      FillInfo_PhysicalFunctionZeroGpu_LeavesMloPartUndefined
          0000:11:00.0 with an accelerator sysfs class, i.e. an ordinary
non-partitioned MI300X GPU. mloPart must stay NCCL_TOPO_UNDEF and the
fn==0 arm must short-circuit before the sysfs probe. This is the
regression test: against the pre-fix code it reports mloPart=0.
      FillInfo_AliasFunctionNotGpuInSysfs_StampsMloPartFromFunction
0000:11:00.1 with no sysfs entry, i.e. a CPX HIP alias. Must still be
stamped from the PCI function, and the probe must target the alias BDF
rather than the physical .0, which would report a GPU and lose the
partition. Pins the DPX/XCP/CPX behaviour #10640 added so the fn=0 fix
          cannot regress it.
      FillInfo_GpuAtNonZeroFunction_LeavesMloPartUndefined
0000:11:00.1 whose class is 0x030000, a real display-class GPU rather
than an alias. Here the class, not the function number, rejects the
          stamp, and the probe is still reached.
      FillInfo_FunctionAboveMloPartMax_LeavesMloPartUndefined
0000:11:00.f, the upper bound: 0xf does not fit the 3-bit index the DEV
          busId overlay carries, so it is rejected before the probe.

Two changes to the ncclOsGetPciDeviceClassByBusId fake make this
observable. It
now returns a class the caller can script, and records its call count
and the
    busId string it was handed, which is how a test sees that the guard
short-circuited rather than probing and rejecting. Its default also
changes from
"" to an accelerator class: "" is the HIP-alias shape (BDF absent from
sysfs),
not what sysfs reports for a GPU's own BDF. Under the old default, no
test that
leaves comm->busId at 0 could reach the fn==0 arm at all, which is how
the stamp
shipped with a green suite -- the line was covered while the taken arm
of
    `if (isGpu) info->mloPart = 0` never executed once.

That default was also disarming an assertion that was already correct.
InitTransportsRank_NoPeerWithMloPart_LeavesHasMloPartUnset covers the
accumulator at init.cc:1508, whose loop includes the caller's own rank
-- the
slot fillInfo fills -- so the stamp #10817 reported as disabling GIN is
now
observable there too. Measured against the pre-fix fillInfo, the suite
fails
    two tests rather than none.

## Test Result
Verified in both compile variants (rccl-UnitTestsMicroInit and
-uncached) under
    --gtest_shuffle: 260 and 259 tests green on the fixed code.

## Submission Checklist

- [ ] Look over the contributing guidelines at
https://github.com/ROCm/rocm-systems/blob/develop/CONTRIBUTING.md.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: sdarisala <59526515+sdarisala@users.noreply.github.com>
corey-derochie-amd pushed a commit that referenced this pull request Oct 14, 2026
…XGMI peers (#10640)

RCCL topology on AMD compute-partitioned GPUs (gfx1250 DPX/XCP and
MI300X CPX) was aborting or building a wrong graph. HIP reports logical
partitions as extra PCI functions (.1–.7), but only the physical
function .0 exists in sysfs as a GPU. NCCL 2.30’s MLOPart overlay
originally used those same function bits, so the two encodings collided.

MLOPart is NVIDIA’s name for a logical GPU partition of one physical GPU
(Blackwell/GB200 “uGPU”). CUDA exposes two devices that share a PCI BDF
and tags the name as MLOPart0 / MLOPart1. NCCL 2.30 parses that string,
then overlays a partition index onto the packed bus ID so the DEV nodes
stay unique while still grouping as siblings when those bits are masked
off.

RCCL reuses that overlay for HIP logical GPUs. HIP names have no
"MLOPart" tag; the index is taken from the HIP PCI function instead. On
this hardware the HIP aliases are not real endpoints: DRM/sysfs GPU is
only ….00.0, and a non-zero function may be a NIC or missing entirely.

The overlay now sits above the 36-bit PCI bus ID
(NCCL_TOPO_MLOPART_SHIFT=36, enable bit + 3-bit index, DEV_MAX=8) so
partitions 0–7 hang off the physical PCI node without clobbering the
function nibble. Genuine NVIDIA MLOPart siblings still group after
masking.

1. MLOPart overlay used PCI function bits [1:0]. HIP can expose sibling
partitions as ….00.0 / .1 (and CPX .0–.7), so ncclTopoCheckMloPartBusId
aborted even when HIP names have no "MLOPart" tag. A 2-partition mask
also could not represent CPX.
2. XGMI tclass came from sysfs at the HIP BDF. A HIP alias such as
0001:01:00.1 can be a NIC (0x028000) or missing, so a GPU–GPU hop was
typed as a switch/NIC instead of NVL.
3. HIP “fake” PCI functions were treated as extra endpoints. Logical
GPUs were hung off a NIC node or a non-existent PCI function instead of
the physical GPU.
4. AllGather3 looked up the GPU by raw comm->busId. After the DEV
overlay, node ids are NCCL_TOPO_GPU_LOCAL_ID of the overlaid DEV, so
partition ranks missed. Match NCCL and use ncclTopoRankToIndex.
5. XGMI DEV lookup used the raw HIP BDF. On packages where the physical
GPU is already at a non-zero function (XCP .1), lookup must match
overlay DEV on the same domain:bus:device regardless of physical
function.
6. Unconfigured ualink (link_type=invalid) is a node setup issue, not a
missing interconnect. UALoE is used only when fabric is ready/active;
otherwise fall back to 1-hop XGMI.

- Move MLOPart overlay from PCI function [1:0] to [39:36] (SHIFT=36,
mask 0xf << 36: enable + 3-bit index 0–7), below GPU local rank (bit
40). Real PCI IDs never occupy those bits.
- Stamp mlopart from the HIP PCI function (0–7) when that function is
not a GPU in sysfs. Remap HIP alias BDFs to the physical .0 PCI node and
attach all partition <gpu>s under it.
- Stamp direct 1-hop XGMI (and UALoE) peers with tclass=0x120000
(PCI_ACCELERATOR_CLASS) at XML creation. AMD fill-missing-tclass trusts
sysfs only for GPU / accelerator / NVSwitch; NIC or missing class stays
accelerator.
- ncclTopoGetDevForPciBusId: if the exact busId misses, match an overlay
DEV on the same domain:bus:device whose MLOPart index equals the HIP
function nibble (covers physical GPUs at .1).
- alt_rsmi findCardForBdf: exact BDF first; if function ≠ 0 and miss,
retry function 0.
- AllGather3 / topo_expl: look up the GPU node by rank, not raw busId.
- Tests: overlay vs function nibble; eight CPX partitions under one
physical PCI; XGMI when the physical GPU is at .1; alt_rsmi
fake-function fallback to fn 0. Init microtests stub
ncclOsGetPciDeviceClassByBusId.

JIRA ID : ROCM-29722

- rccl-UnitTestsFixturesDebug --gtest_filter='TopoTest.*'
- rccl-UnitTestsAltRsmi
--gtest_filter='AltRsmiTest.FabricInfo_FakePciFunctionFallsBackToFn0'
- Topology dump with NCCL_CUMEM_ENABLE=0 NCCL_TOPO_DUMP_FILE=… on
gfx1250 DPX (-np 2) and MI300X CPX (8 and 64 HIP devices)
- Dump matches with default alt_rsmi (unset RCCL_USE_AMD_SMI_LIB)

DebugFast + tests built. All 12 TopoTest cases passed (existing +
overlay/CPX/XCP). Alt-RSMI fake-function fallback passed.

On MI300X CPX (8 physical GPUs × 8 HIP partitions): 8-GPU dump has
mlopart=0..7 under one physical PCI (0000:0c:00.0); 64-GPU dump has 64
<gpu>s with mlopart, 8 physical PCI parents, and XGMI links stamped
tclass=0x120000.

On gfx1250 DPX, both ranks sit under 0001:01:00.0 with mlopart=0/1 and
bidirectional XGMI. sendrecv_perf can still report an internal error
after graph search on that package (nChannels / path typing); that is
separate from PCI placement.

- [ ] Look over the contributing guidelines at
https://github.com/ROCm/rocm-systems/blob/develop/CONTRIBUTING.md.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Nilesh M Negi <Nilesh.Negi@amd.com>
Co-authored-by: Claude <noreply@anthropic.com>
corey-derochie-amd pushed a commit that referenced this pull request Oct 15, 2026
…XGMI peers (#10640)

RCCL topology on AMD compute-partitioned GPUs (gfx1250 DPX/XCP and
MI300X CPX) was aborting or building a wrong graph. HIP reports logical
partitions as extra PCI functions (.1–.7), but only the physical
function .0 exists in sysfs as a GPU. NCCL 2.30’s MLOPart overlay
originally used those same function bits, so the two encodings collided.

MLOPart is NVIDIA’s name for a logical GPU partition of one physical GPU
(Blackwell/GB200 “uGPU”). CUDA exposes two devices that share a PCI BDF
and tags the name as MLOPart0 / MLOPart1. NCCL 2.30 parses that string,
then overlays a partition index onto the packed bus ID so the DEV nodes
stay unique while still grouping as siblings when those bits are masked
off.

RCCL reuses that overlay for HIP logical GPUs. HIP names have no
"MLOPart" tag; the index is taken from the HIP PCI function instead. On
this hardware the HIP aliases are not real endpoints: DRM/sysfs GPU is
only ….00.0, and a non-zero function may be a NIC or missing entirely.

The overlay now sits above the 36-bit PCI bus ID
(NCCL_TOPO_MLOPART_SHIFT=36, enable bit + 3-bit index, DEV_MAX=8) so
partitions 0–7 hang off the physical PCI node without clobbering the
function nibble. Genuine NVIDIA MLOPart siblings still group after
masking.

1. MLOPart overlay used PCI function bits [1:0]. HIP can expose sibling
partitions as ….00.0 / .1 (and CPX .0–.7), so ncclTopoCheckMloPartBusId
aborted even when HIP names have no "MLOPart" tag. A 2-partition mask
also could not represent CPX.
2. XGMI tclass came from sysfs at the HIP BDF. A HIP alias such as
0001:01:00.1 can be a NIC (0x028000) or missing, so a GPU–GPU hop was
typed as a switch/NIC instead of NVL.
3. HIP “fake” PCI functions were treated as extra endpoints. Logical
GPUs were hung off a NIC node or a non-existent PCI function instead of
the physical GPU.
4. AllGather3 looked up the GPU by raw comm->busId. After the DEV
overlay, node ids are NCCL_TOPO_GPU_LOCAL_ID of the overlaid DEV, so
partition ranks missed. Match NCCL and use ncclTopoRankToIndex.
5. XGMI DEV lookup used the raw HIP BDF. On packages where the physical
GPU is already at a non-zero function (XCP .1), lookup must match
overlay DEV on the same domain:bus:device regardless of physical
function.
6. Unconfigured ualink (link_type=invalid) is a node setup issue, not a
missing interconnect. UALoE is used only when fabric is ready/active;
otherwise fall back to 1-hop XGMI.

- Move MLOPart overlay from PCI function [1:0] to [39:36] (SHIFT=36,
mask 0xf << 36: enable + 3-bit index 0–7), below GPU local rank (bit
40). Real PCI IDs never occupy those bits.
- Stamp mlopart from the HIP PCI function (0–7) when that function is
not a GPU in sysfs. Remap HIP alias BDFs to the physical .0 PCI node and
attach all partition <gpu>s under it.
- Stamp direct 1-hop XGMI (and UALoE) peers with tclass=0x120000
(PCI_ACCELERATOR_CLASS) at XML creation. AMD fill-missing-tclass trusts
sysfs only for GPU / accelerator / NVSwitch; NIC or missing class stays
accelerator.
- ncclTopoGetDevForPciBusId: if the exact busId misses, match an overlay
DEV on the same domain:bus:device whose MLOPart index equals the HIP
function nibble (covers physical GPUs at .1).
- alt_rsmi findCardForBdf: exact BDF first; if function ≠ 0 and miss,
retry function 0.
- AllGather3 / topo_expl: look up the GPU node by rank, not raw busId.
- Tests: overlay vs function nibble; eight CPX partitions under one
physical PCI; XGMI when the physical GPU is at .1; alt_rsmi
fake-function fallback to fn 0. Init microtests stub
ncclOsGetPciDeviceClassByBusId.

JIRA ID : ROCM-29722

- rccl-UnitTestsFixturesDebug --gtest_filter='TopoTest.*'
- rccl-UnitTestsAltRsmi
--gtest_filter='AltRsmiTest.FabricInfo_FakePciFunctionFallsBackToFn0'
- Topology dump with NCCL_CUMEM_ENABLE=0 NCCL_TOPO_DUMP_FILE=… on
gfx1250 DPX (-np 2) and MI300X CPX (8 and 64 HIP devices)
- Dump matches with default alt_rsmi (unset RCCL_USE_AMD_SMI_LIB)

DebugFast + tests built. All 12 TopoTest cases passed (existing +
overlay/CPX/XCP). Alt-RSMI fake-function fallback passed.

On MI300X CPX (8 physical GPUs × 8 HIP partitions): 8-GPU dump has
mlopart=0..7 under one physical PCI (0000:0c:00.0); 64-GPU dump has 64
<gpu>s with mlopart, 8 physical PCI parents, and XGMI links stamped
tclass=0x120000.

On gfx1250 DPX, both ranks sit under 0001:01:00.0 with mlopart=0/1 and
bidirectional XGMI. sendrecv_perf can still report an internal error
after graph search on that package (nChannels / path typing); that is
separate from PCI placement.

- [ ] Look over the contributing guidelines at
https://github.com/ROCm/rocm-systems/blob/develop/CONTRIBUTING.md.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Nilesh M Negi <Nilesh.Negi@amd.com>
Co-authored-by: Claude <noreply@anthropic.com>
corey-derochie-amd pushed a commit that referenced this pull request Oct 15, 2026
…XGMI peers (#10640)

RCCL topology on AMD compute-partitioned GPUs (gfx1250 DPX/XCP and
MI300X CPX) was aborting or building a wrong graph. HIP reports logical
partitions as extra PCI functions (.1–.7), but only the physical
function .0 exists in sysfs as a GPU. NCCL 2.30’s MLOPart overlay
originally used those same function bits, so the two encodings collided.

MLOPart is NVIDIA’s name for a logical GPU partition of one physical GPU
(Blackwell/GB200 “uGPU”). CUDA exposes two devices that share a PCI BDF
and tags the name as MLOPart0 / MLOPart1. NCCL 2.30 parses that string,
then overlays a partition index onto the packed bus ID so the DEV nodes
stay unique while still grouping as siblings when those bits are masked
off.

RCCL reuses that overlay for HIP logical GPUs. HIP names have no
"MLOPart" tag; the index is taken from the HIP PCI function instead. On
this hardware the HIP aliases are not real endpoints: DRM/sysfs GPU is
only ….00.0, and a non-zero function may be a NIC or missing entirely.

The overlay now sits above the 36-bit PCI bus ID
(NCCL_TOPO_MLOPART_SHIFT=36, enable bit + 3-bit index, DEV_MAX=8) so
partitions 0–7 hang off the physical PCI node without clobbering the
function nibble. Genuine NVIDIA MLOPart siblings still group after
masking.

1. MLOPart overlay used PCI function bits [1:0]. HIP can expose sibling
partitions as ….00.0 / .1 (and CPX .0–.7), so ncclTopoCheckMloPartBusId
aborted even when HIP names have no "MLOPart" tag. A 2-partition mask
also could not represent CPX.
2. XGMI tclass came from sysfs at the HIP BDF. A HIP alias such as
0001:01:00.1 can be a NIC (0x028000) or missing, so a GPU–GPU hop was
typed as a switch/NIC instead of NVL.
3. HIP “fake” PCI functions were treated as extra endpoints. Logical
GPUs were hung off a NIC node or a non-existent PCI function instead of
the physical GPU.
4. AllGather3 looked up the GPU by raw comm->busId. After the DEV
overlay, node ids are NCCL_TOPO_GPU_LOCAL_ID of the overlaid DEV, so
partition ranks missed. Match NCCL and use ncclTopoRankToIndex.
5. XGMI DEV lookup used the raw HIP BDF. On packages where the physical
GPU is already at a non-zero function (XCP .1), lookup must match
overlay DEV on the same domain:bus:device regardless of physical
function.
6. Unconfigured ualink (link_type=invalid) is a node setup issue, not a
missing interconnect. UALoE is used only when fabric is ready/active;
otherwise fall back to 1-hop XGMI.

- Move MLOPart overlay from PCI function [1:0] to [39:36] (SHIFT=36,
mask 0xf << 36: enable + 3-bit index 0–7), below GPU local rank (bit
40). Real PCI IDs never occupy those bits.
- Stamp mlopart from the HIP PCI function (0–7) when that function is
not a GPU in sysfs. Remap HIP alias BDFs to the physical .0 PCI node and
attach all partition <gpu>s under it.
- Stamp direct 1-hop XGMI (and UALoE) peers with tclass=0x120000
(PCI_ACCELERATOR_CLASS) at XML creation. AMD fill-missing-tclass trusts
sysfs only for GPU / accelerator / NVSwitch; NIC or missing class stays
accelerator.
- ncclTopoGetDevForPciBusId: if the exact busId misses, match an overlay
DEV on the same domain:bus:device whose MLOPart index equals the HIP
function nibble (covers physical GPUs at .1).
- alt_rsmi findCardForBdf: exact BDF first; if function ≠ 0 and miss,
retry function 0.
- AllGather3 / topo_expl: look up the GPU node by rank, not raw busId.
- Tests: overlay vs function nibble; eight CPX partitions under one
physical PCI; XGMI when the physical GPU is at .1; alt_rsmi
fake-function fallback to fn 0. Init microtests stub
ncclOsGetPciDeviceClassByBusId.

JIRA ID : ROCM-29722

- rccl-UnitTestsFixturesDebug --gtest_filter='TopoTest.*'
- rccl-UnitTestsAltRsmi
--gtest_filter='AltRsmiTest.FabricInfo_FakePciFunctionFallsBackToFn0'
- Topology dump with NCCL_CUMEM_ENABLE=0 NCCL_TOPO_DUMP_FILE=… on
gfx1250 DPX (-np 2) and MI300X CPX (8 and 64 HIP devices)
- Dump matches with default alt_rsmi (unset RCCL_USE_AMD_SMI_LIB)

DebugFast + tests built. All 12 TopoTest cases passed (existing +
overlay/CPX/XCP). Alt-RSMI fake-function fallback passed.

On MI300X CPX (8 physical GPUs × 8 HIP partitions): 8-GPU dump has
mlopart=0..7 under one physical PCI (0000:0c:00.0); 64-GPU dump has 64
<gpu>s with mlopart, 8 physical PCI parents, and XGMI links stamped
tclass=0x120000.

On gfx1250 DPX, both ranks sit under 0001:01:00.0 with mlopart=0/1 and
bidirectional XGMI. sendrecv_perf can still report an internal error
after graph search on that package (nChannels / path typing); that is
separate from PCI placement.

- [ ] Look over the contributing guidelines at
https://github.com/ROCm/rocm-systems/blob/develop/CONTRIBUTING.md.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Nilesh M Negi <Nilesh.Negi@amd.com>
Co-authored-by: Claude <noreply@anthropic.com>
arvindcheru pushed a commit that referenced this pull request Oct 16, 2026
## Motivation

This PR fixes a performance regression introduced by 5f38cd0
(#10640). On 4 nodes of 8 MI355X GPUs with AINIC, `ncclGather` from 16
KB to 1 MB became 9 to 15% slower. The same commit also makes
communicator initialization fail when each rank can see only its own
GPU, for example with `HIP_VISIBLE_DEVICES` set to the local rank.

RCCL describes the GPUs of a node in a topology XML, where every GPU
node carries a `dev` index. Each process fills in only its own GPU and
gets the other GPUs of the node from its peers by merging their XML. So
`dev` must be the same in every process and must follow the physical
layout. It is used to:

- sort GPUs in the Rome topology models to match their predefined rings
and trees;
- assign NICs to GPUs;
- map a GPU back to its rank for PXN.

Before #10640, `dev` was the SMI index, which numbers GPUs in PCI bus
order regardless of device visibility. #10640 changed it to the HIP
device ordinal from `hipDeviceGetByPCIBusId`.

This breaks two things:

- On MI355X the HIP ordinals do not follow PCI order: the GPUs' PCI
buses in HIP order are 75, 05, 65, 15, f5, 85, e5, 95. RCCL then picks
different rings, trees and NICs per channel, and gather gets slower.
- The HIP ordinal depends on what each process can see. With one visible
GPU per rank, every process reports its GPU as ordinal 0, all GPUs of
the node end up with `dev=0`, and initialization fails.

This PR sets `dev` to the SMI index again and keeps the HIP ordinal only
for HIP API calls. It also fixes three callers of `ncclTopoGetLinkType`,
which looks GPUs up by `dev` but was given HIP ordinals or rank indices.

## Technical Details

- `ncclTopoGetXmlFromGpu` (`src/graph/xml.cc`) writes the SMI index into
the GPU node's `dev`. The HIP ordinal, renamed from `xmlDev` to
`hipDev`, is still used for `hipGetDeviceProperties` and to find
partition siblings in `ncclTopoXmlAddHipPartitionXgmi`. If
`hipDeviceGetByPCIBusId` fails, `ncclTopoFillGpu` now returns the error
instead of passing the SMI index to HIP as an ordinal.
- `selectTransport` (`src/transport.cc`) and `p2pSendSetup`
(`src/transport/p2p.cc`) pass `nvmlDev` instead of `cudaDev` to
`ncclTopoGetLinkType`. On ROCm, `nvmlDev` holds the SMI index from the
same lookup by PCI bus ID, so it equals the `dev` written above.
- The XGMI clique check in `initTransportsRank` (`src/init.cc`) passed
rank indices to `ncclTopoGetLinkType` and now passes each peer's
`nvmlDev`. With a GPU subset such as `HIP_VISIBLE_DEVICES=2,3`, the old
lookup missed both GPUs and halved the gfx906 channel multiplier.
- The parameters of `ncclTopoGetLinkType` (RCCL-only) are renamed from
`cudaDev1`/`cudaDev2` to `dev1`/`dev2`, together with the matching
locals in `src/graph/paths.cc`, because they are compared with `gpu.dev`
and are not HIP ordinals.
- New fixture tests `TopoGpuDev.*` (`test/graph/TopoGpuDevTests.cpp`,
built into `rccl-UnitTestsFixturesDebug`) check on real GPUs that each
rank's own GPU node carries `comm->nvmlDev` and that all `dev` values
are distinct. They run once with all GPUs visible and once with
`HIP_VISIBLE_DEVICES=1,0`, so on any host with two or more GPUs one of
the two runs fails on develop.
- `AsymmetricVisibility` (`test/AsymmetricVisibilityTests.cpp`, in
`rccl-UnitTests`) now takes a layout of N worker processes. The new
`AsymmetricVisibility.OneGpuPerRankAllReduce` runs one process per GPU,
each seeing only its own GPU. Two ranks are not enough to break develop;
one rank per GPU of an 8-GPU node is.
- The new tests are listed next to `TopoTest.*` and
`AsymmetricVisibility.CommInitRankAllReduce` in the test_runner plans,
and `TopoGpuDev.*` also in the fixtures-debug CTest categories.
- CHANGELOG entry under Resolved issues.

## Issue Tracking

JIRA ID: ROCM-31938, ROCM-33051

## Test Plan

MI355X (gfx950), 8 GPUs per node, AINIC (`NCCL_NET=ROCM-IB`,
`RCCL_AINIC_ROCE=1`), RCCL built against ROCm 7.0.1. Builds were
compared on the same nodes and interleaved in every round:

- before #10640: the parent of 5f38cd0;
- develop: 7a71bfb with only the new tests added;
- this PR.

Runs:

- `rccl-UnitTestsFixturesDebug --gtest_filter='TopoGpuDev.*:TopoTest.*'`
on one node.
- `AsymmetricVisibility` workers on one node for the one-GPU-per-rank
layout with 8 ranks and for the existing asymmetric layout.
- `gather_perf -b 1K -e 4M -f 2 -g 1 -n 20 -w 5 -c 1` on 4 nodes, 6
rounds, in two separate allocations.
- all_reduce, all_gather, reduce_scatter, alltoall, sendrecv, broadcast,
reduce and scatter from 1 KB to 64 MB on 4 nodes, 3 rounds, develop vs
this PR.
- `gather_perf` with `HIP_VISIBLE_DEVICES=$OMPI_COMM_WORLD_LOCAL_RANK`
and `NCCL_TESTS_DEVICE=0` on 1 and 2 nodes, with the topology dumped
through `NCCL_TOPO_DUMP_FILE`.

## Test Result

`gather_perf` on 4 nodes, median out-of-place time over 6 rounds:

| Size | before #10640 (us) | develop (us) | this PR (us) |
|---:|---:|---:|---:|
| 16 KB | 40.9 | 46.7 | 40.7 |
| 64 KB | 41.9 | 47.8 | 41.1 |
| 256 KB | 42.2 | 47.8 | 42.3 |
| 1 MB | 43.1 | 49.4 | 44.2 |

- The second 6-round run gave develop 1.09 to 1.15x and this PR 1.02 to
1.05x the time of the commit before #10640.
- Both `TopoGpuDev` tests fail on develop (for example rank 0 has `dev`
0 while its SMI index is 3) and pass with this PR. `TopoTest.*` passes
on both.
- One GPU per rank, 8 ranks: develop fails `ncclCommInitRank` with an
internal error, this PR passes the AllReduce check. The existing
asymmetric layout passes on both.
- Other collectives: within run-to-run noise of develop at every size.
- One visible GPU per rank: develop fails initialization on 1 node
(`TopoPreset: Local rank N not found in intra-node graph`) and on 2
nodes (`ncclInternalError` from Rome model matching), and its topology
dump shows `dev=0` for all eight GPUs. This PR runs, `dev` is 0 to 7,
and the rings match the run with all GPUs visible.
- `HIP_VISIBLE_DEVICES=2,3` on one node: initialization succeeds, `dev`
is the SMI index of each GPU, and all_reduce passes the data check.
- MI300X in SPX, DPX (16 GPUs) and CPX (63 GPUs), one node: `dev` equals
the SMI index and is distinct for every partition, with all GPUs visible
and with one visible GPU per rank. All runs pass the data check, and
timings match develop.

(AI Asist)

## Submission Checklist

- [x] Look over the contributing guidelines at
https://github.com/ROCm/rocm-systems/blob/develop/CONTRIBUTING.md.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants