Repository navigation
Conversation
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>
ncclDevrCommCreateInternal latches ginEnabled once ncclGinConnectOnce succeeds, then registers existing memories with GIN and updates existing windows. A failure in between left GIN latched with some memories unregistered and some windows missing their GIN handles. The next create saw ginEnabled, skipped activation, and built a GIN devcomm over them. Until the window update finishes, a failure now deregisters every memory this activation registered, frees the segment windows it attached, and clears the latch, so the next create activates GIN again from scratch. AICOMRCCL-2879 Co-authored-by: Cursor <cursoragent@cursor.com>
✅ All Policy Checks Passed
📖 Need help? See the Policy FAQ for details on every check and how to fix failures. |
There was a problem hiding this comment.
ARGUS
Findings
3 more finding(s), not posted inline
projects/rccl/src/dev_runtime.cc:861(Low) symGinActivationRollbackMemories is a third copy of the GIN teardown in symMemoryRegisterGin's fail path (793-801) and symMemoryUnregister (817-819); one shared helper would keep them in step.projects/rccl/test/host/dev-runtime-test.cc:5646(Low) No assertion that the rollback clears mems[0].ginHostWins, which caches goodHostWin; add one.projects/rccl/test/host/dev-runtime-test.cc:5659(Nit) Comment says a later valid create still connects, but the test runs one create; describe what it checks.
Bottom line: Worth settling before approval: the window rollback at dev_runtime.cc:2250 has no test; zeroing the requirement-builder fakes' output would let one reach it.
Comment @argus review to re-run, or @argus re-review after pushing.
| } | ||
| symMemoryDropRef(comm, mem); | ||
| fail_stream: | ||
| if (ginActivated && !ginActivationDone) symGinActivationRollbackWindows(devr, stream); |
There was a problem hiding this comment.
Medium
symGinActivationRollbackWindows has no test, so the suite passes with this call removed. The fixture stops early because the requirement-builder fakes at dev_runtime_micro_fakes.cc:498 leave the stack ncclDevResourceRequirements uninitialised, and line 2109 writes through outBufferHandle. Could those fakes zero their output? A test could then fail g_devrAllocAndPopulateSegmentWindows on a second GIN window. The first window's hook must return a shadow-pool object, since the default nullptr (dev_runtime_micro_fakes.cc:398) is skipped at line 838.
|
|
||
| // Undo an incomplete GIN activation in ncclDevrCommCreateInternal. Memories and | ||
| // windows that existed before it carried no GIN state, so everything GIN holds | ||
| // now came from this activation. |
There was a problem hiding this comment.
Low
Could this header fit the one-line budget? The safety argument still fits:
| // now came from this activation. | |
| // Undo a partial GIN activation; memories and windows held no GIN state before it. |
## 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 - [x] 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: Aurelien Bouteiller <aurelien.bouteiller@amd.com> Co-authored-by: amd-argus[bot] <321830313+amd-argus[bot]@users.noreply.github.com>
## 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>
Motivation
Follow-up to #13231, raised by Argus in its review there. Depends on #14321, which replaced #13231 with the same change on an upstream branch. This branch is stacked on #13231's commits from before the rebase, so only the last commit,
fix(rccl): roll back a GIN activation that fails after connect, belongs here. I will rebase once #14321 merges.#14321 sets
devr->ginEnabledonly afterncclGinConnectOncesucceeds. After that,ncclDevrCommCreateInternalstill registers every existing memory with GIN and then updates every existing window's GIN handles. If anything fails in that stretch (asymMemoryRegisterGincall,ncclGinDevCommSetup, stream creation, orsymWindowInitGin), GIN stays latched:ginSegmentInfosfreed, and memories later in the list were never registered.ncclGinDevCommSetup.ginActivatedfalse, skips both the registration and the window update, and still builds a full GIN devcomm. A laterncclCommWindowRegisteron one of those memories then indexes theginSegmentInfosthat was freed.Technical Details
ncclDevrCommCreateInternaltreats connect, registering the existing memories, and updating the existing windows as one activation. It records completion inginActivationDone, set once the window update loop finishes.symGinActivationRollbackWindows(on thefail_streampath, 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 thefailpath) deregisters every memory holdingginSegmentInfos, frees them, resetsnumGinSegmentsto 1 as for memory obtained before GIN, and clearsginEnabled.ginActivatedis only true whileginEnabledwas false, andginSegmentInfosand a window'sginMultiSegmentWinsare only set once GIN is enabled.ncclGinConnectOncekeepsconnectedtrue, so the retry does not reconnect. It re-registers the memories and updates the windows again.Issue Tracking
JIRA ID: AICOMRCCL-2879
Test Plan
DevrCommCreateInternalTest.GinRegisterFailsAfterConnect_RollsBackActivation: connect succeeds, and two GIN-capable memories are onmemHead. The first registers and the second fails. The test checks:ginEnabledis already true while registration runs.ginSegmentInfos, andginEnabledis false.run_host_tests.shdeps through run) inrocm/dev-ubuntu-22.04:7.2.Test Result
rccl-UnitTestsMicro: 1664 of 1664 passed, and every other host binary passed.dev_runtime.ccrollback reverted, the new test fails on theginEnabledcheck after the first create.devr->ginEnabled = true;removed, the new test fails on the check inside the register hook.ncclGinDevCommSetupor stream creation. The fixture cannot reach the devcomm build past the registration loop.Submission Checklist