Skip to content

fix(rccl): latch GIN only after a successful connect - #14321

Merged
dlamd1dai merged 4 commits into
developfrom
users/dondai/rccl-gin-connect-retry
Oct 27, 2026
Merged

dlamd1dai merged 4 commits into
developfrom
users/dondai/rccl-gin-connect-retry

Conversation

@dlamd1dai

Copy link
Copy Markdown
Contributor

Motivation

Replaces #13231 with the same commits on an upstream branch, so the RCCL coco PR gate runs without a fork override. The earlier review, including the Argus threads and Aurelien's and Kapil's approvals, is on #13231.

Found while reviewing #13228. If ncclGinConnectOnce fails, the next ncclDevrCommCreateInternal on the same communicator can divide by zero in ginDevCommSetupWithBackend.

ncclDevrCommCreateInternal set devr->ginEnabled = true as soon as GIN was requested, before trying to connect, and no failure path cleared it. A connect that fails before backends[].ginCommCount is assigned leaves that count at 0, as it was at plugin registration. On retry, ginEnabled is already true, so connect is skipped. Setup then runs ROUNDUP(nContextsTotal, backend->ginCommCount) with a count of 0.

Two argument checks after the latch (a world GIN barrier on a rail connection, and a custom stride of 0) returned with GIN already latched. That left the communicator in the same state.

Technical Details

  • ncclDevrCommCreateInternal now sets devr->ginEnabled only after ncclGinConnectOnce succeeds. A failed connect, or an early argument rejection, leaves GIN unlatched, so the next create connects again. ncclGinConnectOnce already closes partial connections and leaves connected false on failure, so calling it again is safe.
  • The comment on the latch starts with RCCL: and notes that upstream latches before connect, so a future NCCL sync keeps it after connect.
  • ginDevCommSetupWithBackend is unchanged. After this change, a ginCommCount of 0 means connect never completed, and clamping it there would hide that.
  • Test fakes: dev_runtime_micro_fakes gets a g_devrGinConnectOnce hook, modeled on g_devrRmaProxyConnectOnce, so a test can make connect fail.

Not changed: if connect succeeds and a later step fails (GIN registration of existing memory, ncclGinDevCommSetup, or the window GIN-handle update), GIN stays latched as before. #14231 handles that case.

Issue Tracking

JIRA ID: AICOMRCCL-2879

Test Plan

  • New DevrCommCreateInternalTest.GinConnectFails_RetryConnectsAgain: connect fails twice. The test checks that ginEnabled stays false and that the second create calls connect again.
  • New DevrCommCreateInternalTest.WorldGinBarrierOnRail_RejectedWithoutLatchingGin: the early rejection does not call connect and does not latch GIN.
  • Full host-test suite, built host-only with run_host_tests.sh in rocm/dev-ubuntu-22.04:7.2, after rebasing onto develop.

Test Result

  • After the rebase: 7909 of 7909 host tests passed across 32 binaries, including both new tests and develop's GinSignalRegions_UseLargestRoundedContextCount.
  • With the dev_runtime.cc change reverted, GinConnectFails_RetryConnectsAgain fails on the ginEnabled check.

Submission Checklist

dlamd1dai and others added 4 commits October 26, 2026 14:45
ncclDevrCommCreateInternal set devr->ginEnabled before ncclGinConnectOnce
and never cleared it. A failed connect left ginCommCount at 0, so a retry
skipped the reconnect and divided by zero in ginDevCommSetupWithBackend.
Set the latch only once connect succeeds, so the next create reconnects.

AICOMRCCL-2879

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: amd-argus[bot] <321830313+amd-argus[bot]@users.noreply.github.com>
…est fast

The suggestion apply left both comment lines in place, and EXPECT_FALSE let a latched ginEnabled fall through into a host-test divide by zero.

Co-authored-by: Cursor <cursoragent@cursor.com>
Upstream sets ginEnabled before ncclGinConnectOnce. Tag the comment RCCL:
so a future NCCL sync keeps the latch after connect.

AICOMRCCL-2879

Co-authored-by: Cursor <cursoragent@cursor.com>
@therock-pr-bot

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/dev_runtime.cc, projects/rccl/test/host/dev-runtime-test.cc, projects/rccl/test/host/fakes/dev_runtime_micro_fakes.cc, projects/rccl/test/host/fakes/dev_runtime_micro_fakes.h; 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?

@Kapil-Shyam-Pawar Kapil-Shyam-Pawar 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.

lgtm
#13231 was reviewed and approved
just switching from fork here

@amd-argus amd-argus Bot 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.

ARGUS

Bottom line: Looks approval ready.

Comment @argus review to re-run, or @argus re-review after pushing.

Comment thread projects/rccl/src/dev_runtime.cc Resolved
@github-actions

Copy link
Copy Markdown
Contributor

pr-rocm-systems-14321-oci-rccl-pr-smoke

Builds

Stack Component Version Commit Status Build time
pr-14321_rccl-debug_rocm-10.1-ga gcc-13.2 13.2.0 13.2.0 cached
pr-14321_rccl-debug_rocm-10.1-ga rocm-10.1-ga 10.1.0 10.1.0 cached
pr-14321_rccl-debug_rocm-10.1-ga openmpi-5.0.8 5.0.8 5.0.8 cached
pr-14321_rccl-debug_rocm-10.1-ga rccl-pr-14321 f6f5cb8 f6f5cb8 cached
pr-14321_rccl-debug_rocm-10.1-ga rccl_gtest-pr-14321-debug f6f5cb8 f6f5cb8 cached
pr-14321_rccl-perf_rocm-10.1-ga gcc-13.2 13.2.0 13.2.0 cached
pr-14321_rccl-perf_rocm-10.1-ga rocm-10.1-ga 10.1.0 10.1.0 cached
pr-14321_rccl-perf_rocm-10.1-ga openmpi-5.0.8 5.0.8 5.0.8 cached
pr-14321_rccl-perf_rocm-10.1-ga rccl-pr-14321 f6f5cb8 f6f5cb8 cached
pr-14321_rccl-perf_rocm-10.1-ga rccl-tests-develop-perf develop f731cdd cached
pr-14321_rccl-perf_rocm-10.2-latest gcc-13.2 13.2.0 13.2.0 cached
pr-14321_rccl-perf_rocm-10.2-latest rocm-10.2-latest 10.2.0rc0 10.2.0rc0 cached
pr-14321_rccl-perf_rocm-10.2-latest openmpi-5.0.8 5.0.8 5.0.8 cached
pr-14321_rccl-perf_rocm-10.2-latest rccl-pr-14321 f6f5cb8 f6f5cb8 cached
pr-14321_rccl-perf_rocm-10.2-latest rccl-tests-develop-perf develop f731cdd cached
rocm-10.1-ga_rccl-develop-perf gcc-13.2 13.2.0 13.2.0 cached
rocm-10.1-ga_rccl-develop-perf rocm-10.1-ga 10.1.0 10.1.0 cached
rocm-10.1-ga_rccl-develop-perf openmpi-5.0.8 5.0.8 5.0.8 cached
rocm-10.1-ga_rccl-develop-perf rccl-develop develop f731cdd cached
rocm-10.1-ga_rccl-develop-perf rccl-tests-develop-perf develop f731cdd cached

Failures

No failing tests in this run.

15 tests skipped.

@github-actions

Copy link
Copy Markdown
Contributor

pr-rocm-systems-14321-ruby64-rccl-pr-smoke

Builds

Stack Component Version Commit Status Build time
pr-14321_rccl-debug_rocm-10.1-ga gcc-11.5 11.5.0 11.5.0 cached
pr-14321_rccl-debug_rocm-10.1-ga rocm-10.1-ga 10.1.0 10.1.0 cached
pr-14321_rccl-debug_rocm-10.1-ga openmpi-4.0.2 4.0.2rc3 4.0.2rc3 cached
pr-14321_rccl-debug_rocm-10.1-ga rccl-pr-14321 f6f5cb8 f6f5cb8 cached
pr-14321_rccl-debug_rocm-10.1-ga rccl_gtest-pr-14321-debug f6f5cb8 f6f5cb8 cached
pr-14321_rccl-perf_rocm-10.1-ga gcc-11.5 11.5.0 11.5.0 cached
pr-14321_rccl-perf_rocm-10.1-ga rocm-10.1-ga 10.1.0 10.1.0 cached
pr-14321_rccl-perf_rocm-10.1-ga openmpi-4.0.2 4.0.2rc3 4.0.2rc3 cached
pr-14321_rccl-perf_rocm-10.1-ga rccl-pr-14321 f6f5cb8 f6f5cb8 cached
pr-14321_rccl-perf_rocm-10.1-ga rcclt-develop-perf develop 9ba6a40 cached
pr-14321_rccl-perf_rocm-10.2-latest gcc-11.5 11.5.0 11.5.0 cached
pr-14321_rccl-perf_rocm-10.2-latest rocm-10.2-latest 10.2.0rc0 10.2.0rc0 cached
pr-14321_rccl-perf_rocm-10.2-latest openmpi-4.0.2 4.0.2rc3 4.0.2rc3 cached
pr-14321_rccl-perf_rocm-10.2-latest rccl-pr-14321 f6f5cb8 f6f5cb8 cached
pr-14321_rccl-perf_rocm-10.2-latest rcclt-develop-perf develop 9ba6a40 cached
rocm-10.1-ga_rccl-develop-perf gcc-11.5 11.5.0 11.5.0 cached
rocm-10.1-ga_rccl-develop-perf rocm-10.1-ga 10.1.0 10.1.0 cached
rocm-10.1-ga_rccl-develop-perf openmpi-4.0.2 4.0.2rc3 4.0.2rc3 cached
rocm-10.1-ga_rccl-develop-perf rccl-develop develop 9ba6a40 cached
rocm-10.1-ga_rccl-develop-perf rcclt-develop-perf develop 9ba6a40 cached

Failures

No failing tests in this run.

15 tests skipped.

@dlamd1dai
dlamd1dai merged commit 06b5066 into develop Oct 27, 2026
133 of 145 checks passed
@dlamd1dai
dlamd1dai deleted the users/dondai/rccl-gin-connect-retry branch October 27, 2026 16:00
@systems-assistant

Copy link
Copy Markdown
Contributor

TheRock Submodule Bump Activity

Newest first

dlamd1dai added a commit that referenced this pull request Oct 30, 2026
## Motivation

Replaces #14231 with the same commits on an upstream branch, so the RCCL
coco PR gate runs without a fork override. The earlier review is on
#14231.

Follow-up to #14321 (merged), raised by Argus in its review of #13231.

#14321 sets `devr->ginEnabled` only after `ncclGinConnectOnce` succeeds.
After that, `ncclDevrCommCreateInternal` still registers every existing
memory with GIN and then updates every existing window's GIN handles. If
anything fails in that stretch (a `symMemoryRegisterGin` call,
`ncclGinDevCommSetup`, stream creation, or `symWindowInitGin`), GIN
stays latched:

- The memory that failed to register has its `ginSegmentInfos` freed,
and memories later in the list were never registered.
- Windows never got their GIN handles, because the window update runs
after `ncclGinDevCommSetup`.
- The next create computes `ginActivated` false, skips both the
registration and the window update, and still builds a full GIN devcomm.
A later `ncclCommWindowRegister` on one of those memories then indexes
the `ginSegmentInfos` that was freed.

## Technical Details

- `ncclDevrCommCreateInternal` treats connect, registering the existing
memories, and updating the existing windows as one activation. It
records completion in `ginActivationDone`, set once the window update
loop finishes.
- On any failure before that point:
- `symGinActivationRollbackWindows` (on the `fail_stream` path, while
the stream is still alive) frees the segment windows attached to
existing windows, clears their GIN handles, and copies the cleared
window to the device.
- `symGinActivationRollbackMemories` (on the `fail` path) deregisters
every memory holding `ginSegmentInfos`, frees them, resets
`numGinSegments` to 1 as for memory obtained before GIN, and clears
`ginEnabled`.
- When the window rollback runs, `fail_stream` synchronizes the stream
before destroying it. A retry rebuilds those windows on a new stream,
which is not ordered after this one.
- Rolling back everything GIN holds is safe because nothing had GIN
state before this activation. `ginActivated` is only true while
`ginEnabled` was false, and `ginSegmentInfos` and a window's
`ginMultiSegmentWins` are only set once GIN is enabled.
- `ncclGinConnectOnce` keeps `connected` true, so the retry does not
reconnect. It re-registers the memories and updates the windows again.
- Failures after the window update are unchanged. GIN is then fully
activated for every existing memory and window, and keeping it latched
is correct.
- As with the connect retry in #14321, the rollback assumes the failure
happened on every rank.

## Issue Tracking

JIRA ID: AICOMRCCL-2879

## Test Plan

- New
`DevrCommCreateInternalTest.GinRegisterFailsAfterConnect_RollsBackActivation`:
connect succeeds, and two GIN-capable memories are on `memHead`. The
first registers and the second fails. The test checks:
  - `ginEnabled` is already true while registration runs.
- After the failure, the first memory is deregistered, neither memory
keeps `ginSegmentInfos`, and `ginEnabled` is false.
- A second create connects and registers again, then rolls back the same
way.
- New
`DevrCommCreateInternalTest.StreamCreateFailsAfterGinRegister_RollsBackActivation`:
connect succeeds and both memories register, then stream creation fails.
The test checks that both memories are deregistered, neither keeps
`ginSegmentInfos` or `ginHostWins`, and `ginEnabled` is false.
- Full host-test pipeline (`run_host_tests.sh` deps through run) in
`rocm/dev-ubuntu-22.04:7.2`.

## Test Result

- On `develop` at `060a14eb23`: `rccl-UnitTestsMicro` 2232 of 2232
passed, and every other host binary passed.
- With `ginActivationDone = true;` moved right after the register loop,
`StreamCreateFailsAfterGinRegister_RollsBackActivation` fails (no
deregistrations, `ginEnabled` still true), while
`GinRegisterFailsAfterConnect_RollsBackActivation` still passes.
- Before the rebase, with the `dev_runtime.cc` rollback reverted,
`GinRegisterFailsAfterConnect_RollsBackActivation` failed on the
`ginEnabled` check after the first create. With `devr->ginEnabled =
true;` removed, it failed on the check inside the register hook.
- Not covered by host tests: the window rollback, which needs a window
in `winSorted` that this fixture does not build, and a failure inside
`ncclGinDevCommSetup`, which the fixture fakes as always succeeding.

## Submission Checklist

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


Made with [Cursor](https://cursor.com)

---------

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.

3 participants