Repository navigation
Conversation
Cherry-picks the put-chunk fix from users/dondai/gin-stage2j-sdma-A1457-a2av-wip for AllToAll ONLY, without merging the other GIN-SDMA collective designs. Root cause (8x MI355X, ROCm 7.13, NCCL_GIN_TYPE=5, alltoall_perf -D 3/-D 4): a single fused COPY_LINEAR_WAIT_SIGNAL_MI4 descriptor at/above 256 MiB/peer stalls the SDMA engine, so the copy never lands and its SignalInc never fires -> every rank spins forever in waitSignal (hang, not a miscompare). At 2 GiB total / 8 ranks each put is 256 MiB/peer -> hang; 256 MiB and 1 GiB totals (<=128 MiB/peer) pass. Fix: add the self-contained, namespaced gin_sdma_collective_policy.h (source of truth for kGinPutMaxBytes and the new kGinSdmaSafeCopyBytes = 128 MiB) and a ginPutChunked() helper in common.h that segments each GIN-tier put to <=128 MiB, carrying the SignalInc only on the final in-order segment so signal accounting is unchanged. Rewire the three A2A GIN put sites (GinHybrid -D 3 and Hybrid -D 4 remote-peer loops) to ginPutChunked(). Measured hang-free with no bandwidth loss (busbw ~423 GB/s, matching the 1 GiB case and the NCCL_GIN_ANVIL_MAX_PUT_CHUNK env workaround). Co-authored-by: Cursor <cursoragent@cursor.com> (cherry picked from commit 7e5d8fc)
The put-chunk fix includes gin_sdma_collective_policy.h from common.h, but the rccl-tests build hipifies each COMMON_FILES entry into a private hipify/ dir and compiles against that dir only. The new header was not in COMMON_FILES, so the hipified common.h failed with "gin_sdma_collective_policy.h file not found". Add it to COMMON_FILES so it is copied/hipified alongside common.h. Co-authored-by: Cursor <cursoragent@cursor.com> (cherry picked from commit a4cc49e)
…tion Address review feedback on the >1 GiB A2A put-chunk fix. The trailing SignalInc on the final segment is only safe because the Anvil-SDMA backend selects the SDMA queue per issuer (blockId, warpId), not per peer, so a message issued entirely by one thread keeps all its segments + the signal on the same in-order queue even when NCCL_GIN_ANVIL_SDMA_NUM_CHANNELS > 1. Spell out this ordering guarantee and the single-thread-per-peer caller contract (don't split one peer's message across warps while carrying the signal on one), so the helper isn't misused in a way that could reorder the signal ahead of data under multi-channel. Co-authored-by: Cursor <cursoragent@cursor.com>
| // (silent data corruption). If you ever need that pattern, drain with a Flush | ||
| // (or force NUM_CHANNELS=1 / SPREAD_CHANNELS=0) before signaling. | ||
| template <typename RemoteAction> | ||
| __device__ __forceinline__ void ginPutChunked( |
There was a problem hiding this comment.
There's no regression test for the chunking here. Could we add the following test cases?
-
A host unit test of the segment math (pure integer arithmetic, no GPU needed) over bytes = {0, 128MiB, 128MiB+1, 256MiB, 1GiB, 2GiB}, asserting exactly one signal is carried, no segment exceeds 128MiB, and the segments sum back to bytes. (
gin_sdma_collective_policy.halready advertises aGIN_SDMA_HOST_ONLYGoogleTest path that is defined but currently unused.) -
An AllToAll correctness test above 128MiB/peer (exercises the new multi-segment loop) and above 1GiB/peer (crosses the 1GiB 30-bit truncation boundary), using exact-integer datatypes so a truncated or stale tail can't be masked by float tolerance.
-
The original 2GiB-total AllToAll hang repro as a guard that it now completes (MI355X + ROCm 7.13, NCCL_GIN_TYPE=5).
Today there's no AllToAll test in rccl-tests and the pytest byte_range caps at 128M total, so nothing reaches the new multi-segment path.
There was a problem hiding this comment.
Sure. I will add my test code into the "rccl-tests/" directory.
There was a problem hiding this comment.
Added all three in 73e0a47.
-
Host unit test (no GPU). I factored the segmentation arithmetic out of the
__device__ginPutChunkedinto two pure functions ingin_sdma_collective_policy.h—ginPutSegmentCount()andginPutSegmentAt()(pluskGinPutSegBytes = min(reliability, correctness caps)) — and rewrote the device loop to drive off them, so the code the test exercises is exactly what runs on device.test/gin_sdma_policy_test.cpp(GoogleTest, compiled host-only viaGIN_SDMA_HOST_ONLY) asserts overbytes = {0, 1, 128MiB, 128MiB+1, 256MiB, 1GiB, 1GiB+1, 2GiB}— plus a dense +/-2 B scan around every cap multiple — that no segment exceeds 128 MiB, the segments tile[0,bytes)contiguously and sum back tobytes, and exactly one final (signal-carrying) segment lands on the tail. Wired opt-in via-DBUILD_TESTS=ON(find/fetch GTest), ctest labelunit. (This re-establishes theGIN_SDMA_HOST_ONLYpath you noted — it's now actually used.) -
AllToAll correctness (GPU).
test/test_AllToAll.pydrives the realGinHybridAlltoAllKernel(-D 3,NCCL_GIN_TYPE=5, SDMA tier forced viaNCCL_GIN_ANVIL_SDMA_THRESHOLD*=0) at 256 MiB/peer (>128 MiB → multi-segment loop) and 2 GiB/peer (>1 GiB → crosses the 30-bit truncation boundary), with exact-integer dtypes (int32/int64/uint8) and the built-in data check (-c 1), so a truncated/stale tail can't hide under float tolerance (nonzero exit on any wrong element). -
Hang guard (GPU). The original 2 GiB-total repro (256 MiB/peer at 8 ranks) is a dedicated completion sentinel: a subprocess timeout converts a reintroduced SDMA hang into a test failure instead of stalling the runner.
The two GPU tests need an 8x MI355X-class node + MPI + a GIN-SDMA build, so the module skips unless RCCL_TESTS_GIN_SDMA_A2A=1 (size/np/timeout configurable via env); the host unit test runs anywhere. The device loop is behavior-identical to the prior do/while, so no functional change to the shipping path.
There was a problem hiding this comment.
Ran both test tiers on hardware:
Host unit test — built googletest 1.14.0 and compiled gin_sdma_policy_test.cpp host-only (-DGIN_SDMA_HOST_ONLY -Wall -Wextra): all 5 cases pass, warning-clean (fixed one -Wdangling-else in 579861c).
GPU AllToAll (8x MI355X, ROCm 7.13, NCCL_GIN_TYPE=5, force-single-channel) — -D 3, SDMA tier forced, int32, built-in data check:
| case | per-peer | segments | busbw | #wrong |
|---|---|---|---|---|
| >128 MiB/peer | 256 MiB | 2×128 MiB | ~424 GB/s | 0 |
| >1 GiB/peer | 2 GiB | 16×128 MiB (crosses 30-bit boundary) | ~428 GB/s | 0 |
| 2 GiB-total hang guard | 256 MiB | 2×128 MiB | ~424 GB/s | 0, no hang |
Running the suite on-hardware surfaced two gaps I fixed in 51c2af8:
- The test now forwards the env the GIN-SDMA backend actually needs to initialize (always
NCCL_GIN_ENABLE=1, plus deployment-specific vars viaRCCL_TESTS_A2A_XENVand launcher opts viaRCCL_TESTS_MPI_OPTS) — the minimal 3-var version couldn't bring GIN up on the cluster. - On the hang timeout it now SIGKILLs the whole launcher process group (new session), so a wedged run can't orphan ranks that pin the GPUs / exhaust SDMA queues for later cases.
There was a problem hiding this comment.
Added and relocated. The host unit test is now projects/rccl/test/gin/gin_sdma_policy_test.cpp, wired into the rccl suite as rccl-UnitTestsGinSdmaPolicy. It exercises the pure segment math (ginPutSegmentCount()/ginPutSegmentAt(), no GPU) over {0, 128MiB, 128MiB+1, 256MiB, 1GiB, 2GiB} and asserts contiguous tiling with exactly one final (signal-carrying) segment — 5/5 pass, warning-clean.
Addresses the AllToAll put-chunk review (ordering vs. multi-channel SDMA): the trailing SignalInc on ginPutChunked's final segment is only correctly ordered behind the data if all of a message's segments share one in-order SDMA queue. Rather than rely on that precondition, force a single SDMA channel so the multi-channel reorder window cannot exist at all. - gin_plugin_anvil_sdma.cc: ginAnvilSdmaNumChannels() now returns 1 unconditionally and no longer reads NCCL_GIN_ANVIL_SDMA_NUM_CHANNELS. The per-(peer,channel) queue / effectiveChannel / dirty / Flush machinery is retained and simply runs with numChannels==1, so nothing downstream changes. This also removes reachability of a separate fail-loud "unhandled system error" observed at >=4 channels and >=256 MiB/peer. - common.h: simplify the ginPutChunked ordering comment to the single-channel guarantee (a HW SDMA queue is a strict in-order FIFO, so the trailing signal still means "the whole message landed"). - gin_sdma_collective_policy.h: drop the NUM_CHANNELS reference in the AllReduce two-shot CTA-cap note. - GinAnvilPlugin_test.cpp: repurpose the former env-clamp test to assert numChannels==1 even when NCCL_GIN_ANVIL_SDMA_NUM_CHANNELS is set (env ignored). Verified on 8x MI355X (NCCL_GIN_TYPE=5, -D 3, all-SDMA): with env NCCL_GIN_ANVIL_SDMA_NUM_CHANNELS=8 the backend init reports "1 ch" and AllToAll at 256 and 512 MiB/peer passes with #wrong=0 (~405-420 GB/s), no hang or abort. Co-authored-by: Cursor <cursoragent@cursor.com>
The header was seeded from the full GIN-SDMA collective design (Broadcast /
AllGather / AllToAll{,v} / Scatter / Gather / SendRecv / ReduceScatter /
AllReduce tiers, env/threshold resolution, CTA-count ladders, devReqs, etc.),
but this branch only lands the AllToAll 128 MiB put clamp. On this branch the
sole consumer is common.h::ginPutChunked, which references exactly two symbols:
kGinPutMaxBytes and kGinSdmaSafeCopyBytes.
Drop everything else (all tier predicates, chunk/alignment math, env parsing,
DevReqs, and the collective-specific constants) so the header carries only the
two put-size limits actually used here, with their rationale. This also removes
stale references to sources not in this branch (e.g. all_reduce.cu) and to the
now-removed NUM_CHANNELS tunable. Addresses the review request to keep the new
header scoped to what this PR needs (754 -> 52 lines). No functional change.
Co-authored-by: Cursor <cursoragent@cursor.com>
…ding) - common.h: make ginPutChunked's kMax `constexpr` (both operands are constexpr, so the min is a compile-time constant). - gin_sdma_collective_policy.h: drop "MI355X" from the kGinSdmaSafeCopyBytes inline comment; the measurement platform is already stated in the block comment above, and the reliable-copy limit is not conceptually tied to one ASIC. Co-authored-by: Cursor <cursoragent@cursor.com>
Adds the coverage requested in review for ginPutChunked's segmentation, at
three levels:
1. Host unit test (no GPU). Factor the put-segmentation arithmetic out of the
__device__ ginPutChunked into two pure functions in
gin_sdma_collective_policy.h -- ginPutSegmentCount() and ginPutSegmentAt()
(plus kGinPutSegBytes = min(reliability, correctness caps)) -- and drive the
device loop from them, so the exact code that runs on device is what the test
exercises. test/gin_sdma_policy_test.cpp (GoogleTest, compiled host-only via
GIN_SDMA_HOST_ONLY) asserts, over bytes = {0, 1, 128MiB, 128MiB+1, 256MiB,
1GiB, 1GiB+1, 2GiB} and a dense scan around every cap multiple, that: no
segment exceeds 128 MiB, segments tile [0,bytes) contiguously and sum back to
bytes, and exactly one final (signal-carrying) segment lands on the tail.
Wired opt-in via -DBUILD_TESTS=ON (find/fetch GTest), ctest label "unit".
2. AllToAll correctness (GPU). test/test_AllToAll.py drives the real
GinHybridAlltoAllKernel (-D 3, NCCL_GIN_TYPE=5, SDMA tier forced) at
256 MiB/peer (>128 MiB, multi-segment loop) and 2 GiB/peer (>1 GiB, crosses
the 30-bit truncation boundary) with exact-integer dtypes (int32/int64/uint8)
and the built-in data check, so a truncated/stale tail can't hide under float
tolerance (nonzero exit on any wrong element).
3. Hang guard (GPU). The original 2 GiB-total repro (256 MiB/peer at 8 ranks) as
a completion sentinel: a subprocess timeout turns a reintroduced SDMA hang
into a test failure instead of stalling the runner.
The GPU tests need an 8x MI355X-class node + MPI + a GIN-SDMA build, so the
module is skipped unless RCCL_TESTS_GIN_SDMA_A2A=1 (config via env). The host
unit test runs anywhere. No functional change to the shipping code path (the
device loop is behavior-identical to the prior do/while).
Co-authored-by: Cursor <cursoragent@cursor.com>
Built googletest 1.14.0 and ran gin_sdma_policy_test host-only (-DGIN_SDMA_HOST_ONLY, -Wall -Wextra): all 5 cases pass. The interior-segment EXPECT_EQ inside `if (i+1<n)` tripped -Wdangling-else (the macro expands to an if/else); wrap it in braces so the suite compiles clean under -Wall. Co-authored-by: Cursor <cursoragent@cursor.com>
…roup Ran the suite on 8x MI355X (ROCm 7.13, force1ch) and hardened it from what the run exposed: - Forward the env the GIN-SDMA backend actually needs. The prior version only passed NCCL_GIN_TYPE + thresholds, which is not enough to enable GIN on a real cluster (setup failed in HIP before the collective ran). Always inject NCCL_GIN_ENABLE=1, and take deployment-specific vars from RCCL_TESTS_A2A_XENV (e.g. HSA_FORCE_FINE_GRAIN_PCIE=1, NCCL_CUMEM_ENABLE=1, RCCL_ENABLE_INTRANET=1) plus launcher options from RCCL_TESTS_MPI_OPTS (e.g. --allow-run-as-root -mca ...). Binary path overridable via RCCL_TESTS_A2A_EXE. GIN enablement is site-specific, so it stays operator-provided rather than hard-coded. - Launch the run in a new session and, on the hang timeout, SIGKILL the whole process group. Previously a wedged launcher left orphaned ranks pinning the GPUs and exhausting SDMA queues for subsequent tests; killing the group makes the hang guard self-contained. Verified green on 8x MI355X: 256 MiB/peer (multi-segment) and 2 GiB/peer (crosses the 1 GiB 30-bit boundary; 16x128 MiB segments) int32 -> #wrong=0 (busbw ~424-428 GB/s), and the 2 GiB-total guard completes with no hang. Co-authored-by: Cursor <cursoragent@cursor.com>
…ssion tests) into -wip Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # projects/rccl-tests/src/common.h # projects/rccl-tests/src/gin_sdma_collective_policy.h
| const size_t size = count * sizeof(T); | ||
| for (int r=tid; r<devComm.nRanks; r+=nthreads) { | ||
| gin.put(ncclTeamWorld(devComm), r, | ||
| ginPutChunked(gin, ncclTeamWorld(devComm), r, |
There was a problem hiding this comment.
GinAlltoAllKernel and HybridAlltoAllKernel are the entry points for the other GIN backends as well, not just SDMA, so this will cap puts for proxy, and rocshmem gda too
It would be good to validate with NCCL_GIN_TYPE=2 and 4
Would it make sense to put the chunking in ncclGinApi_Put<NCCL_NET_DEVICE_GIN_ANVIL_SDMA> instead, the way the proxy backend already does?
That would fix the hang for all GIN SDMA callers and not just alltoall_perf
rocm-systems/projects/rccl/src/include/nccl_device/gin/proxy/gin_proxy.h
Lines 214 to 242 in ea5a1ab
There was a problem hiding this comment.
The GDA gin has the same limitation (1GB message size), but I agree with Nusrat that this should not surface in user code.
There was a problem hiding this comment.
Good catch — you're right that GinAlltoAllKernel/HybridAlltoAllKernel are shared by all GIN backends, so capping there was not necessary for proxy and GDA. Fixed in 92b25f7: the size cap now lives inside the SDMA backend's Put API (ncclGinApi_Put<NCCL_NET_DEVICE_GIN_ANVIL_SDMA>), and the kernels are back to a plain gin.put(). Proxy (type 2) and GDA (type 4) are no longer capped by construction — they don't touch the SDMA segmentation path at all.
I haven't been able to get a clean type 2/4 datapoint yet (the RDMA host I have, dell300x, has a broken bnxt_re ABI in-container), but since the kernel path for those types is now byte-for-byte the pre-PR gin.put(), there's no behavioral change to validate. SDMA (type 5) is validated on 8x MI355X up to 2 GiB — no hang, 0 wrong, ~426 GB/s.
There was a problem hiding this comment.
Agreed on both points. As of 92b25f7 the chunking is entirely inside the SDMA backend gin.put() and no longer in user/test code. On the GDA 1 GiB limit: this PR scopes its fix to SDMA only (GDA's kernel path is unchanged here). The same internal-segmentation pattern could be applied to the GDA backend's Put as a follow-up if we want gin.put() to be size-agnostic there too — happy to file that separately.
| const size_t size = count * sizeof(T); | ||
| for (int r=tid; r<devComm.nRanks; r+=nthreads) { | ||
| gin.put(ncclTeamWorld(devComm), r, | ||
| ginPutChunked(gin, ncclTeamWorld(devComm), r, |
There was a problem hiding this comment.
Will applications call gin.puChunked()? This looks like a new API that has been added in RCCL and not present in NCCL. The ideal solution would be to gin.put() internally calling gin.putChunked() for large messages. Otherwise, if an application calls gin.put() with large sizes, it may still hit the hang issue.
There was a problem hiding this comment.
Agreed, and that's exactly what 92b25f7 does. There's no ginPutChunked() anymore — it's removed from rccl-tests. Segmentation is now internal to gin.put() for the SDMA backend: a large put is split into <=128 MiB SDMA copies inside ncclGinApi_Put<ANVIL_SDMA>, invisible to callers. No new user-facing API, and it matches NCCL's gin.put() surface.
| // vs the 1 GiB total case). 128 MiB is proven safe with zero measured perf loss; | ||
| // do not raise without re-measuring. ginPutChunked segments every GIN-tier put | ||
| // to this size, so it protects ALL GIN-SDMA collectives that route through it. | ||
| static constexpr size_t kGinSdmaSafeCopyBytes = 128ull * 1024 * 1024; // 128 MiB (reliable single-copy max) |
There was a problem hiding this comment.
This is entirely empirical do we have any understanding why the limit is not 1G as well here?
There was a problem hiding this comment.
It's two different limits. 1 GiB (kGinPutMaxBytes) is the hard correctness bound — the SDMA linear-copy count field is 30 bits. 128 MiB (kGinSdmaSafeCopyBytes) is the empirical reliability bound: on MI355X + ROCm 7.13 a fused COPY_LINEAR_WAIT_SIGNAL at/above 256 MiB/peer stalls the engine (the original hang). 128 MiB is the largest power-of-two tier below that stall threshold, and it shows no measured bandwidth loss vs. the 1 GiB case (~426 GB/s at 2 GiB). The code takes min(kGinSdmaSafeCopyBytes, kGinPutMaxBytes) so if the empirical limit is ever raised it can never exceed the descriptor bound.
| #include <gtest/gtest.h> | ||
|
|
||
| #include <cstddef> | ||
| #include <vector> | ||
|
|
||
| #include "gin_sdma_collective_policy.h" |
There was a problem hiding this comment.
| #include <gtest/gtest.h> | |
| #include <cstddef> | |
| #include <vector> | |
| #include "gin_sdma_collective_policy.h" | |
| #include <cstddef> | |
| #include <vector> | |
| #include <gtest/gtest.h> | |
| #include "gin_sdma_collective_policy.h" |
There was a problem hiding this comment.
Adopted, with the path updated for the relocation: the test now lives under projects/rccl/test/gin/ and includes the shipped nccl_device/gin/anvil_sdma/gin_anvil_sdma_put_policy.h (the old gin_sdma_collective_policy.h is gone).
The <=128 MiB segmentation was living in the shared rccl-tests A2A kernels (GinAlltoAllKernel/HybridAlltoAllKernel), which are the entry points for ALL GIN backends (proxy, rocSHMEM GDA, Anvil-SDMA), so it wrongly capped puts for proxy and GDA and exposed an app-visible ginPutChunked() helper that has no NCCL equivalent. Move the size cap into the SDMA backend's Put API (ncclGinApi_Put<NCCL_NET_DEVICE_GIN_ANVIL_SDMA>): large puts are split into <= kGinPutSegBytes (128 MiB) SDMA copies, with the fused signal (or the explicit SignalInc) carried only on the final segment. The backend runs a single in-order SDMA queue per peer (numChannels forced to 1), so the trailing signal still means the whole message landed. A <=128 MiB put stays a single segment, so the common path is unchanged. - Ship the limits + pure segment math as a device header (gin_anvil_sdma_put_policy.h, host-compilable for the unit test) and add it to the rccl install manifest. - Relocate the host segment-math unit test to projects/rccl/test/gin. - Revert the rccl-tests kernels to plain gin.put(); drop ginPutChunked, the rccl-tests policy header, and the BUILD_TESTS wiring. Scopes the fix to SDMA, keeps chunking out of user code, and leaves proxy/GDA kernels uncapped. Validated on 8x MI355X (gfx950): A2A up to 2 GiB completes with no hang, 0 wrong, ~426 GB/s at 2 GiB. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Follow-up work is stacked on top of this PR: dlamd1dai#1 — "rccl-tests/gin-sdma: in-device (wall_clock64) A2A timing mechanism". It is based on this PR's head branch ( |
|
@abouteiller @pvallem — this PR is approved and Root cause of the red check. The build and SLURM submission succeed; the sole failure in the compute-node logs (node The node's
Corroborating validation of the SDMA fix:
Request: since the state is Follow-on work (devtime, GDA unit tests) is stacked on this branch and will rebase once this merges. |
Mirror the AllToAll GIN-SDMA >1 GiB hang-fix tests (PR ROCm#9927) for AllGather so the multi-channel/SDMA ordering concern is covered by an automated test, not just manual runs. Drives GinHybridAllGatherKernel (-D 3, NCCL_GIN_TYPE=5) with the SDMA tier forced (threshold=0) at per-rank chunks that cross the <=128 MiB segmentation boundary (256 MiB -> 2 seg, 2 GiB -> 16 seg), plus a 2 GiB-total completion guard with a subprocess timeout that turns a reintroduced SDMA hang into a failure. Exact-integer dtypes + built-in data check (-c 1) so a truncated /stale tail can't hide under float tolerance. Opt-in via RCCL_TESTS_GIN_SDMA_AG (needs an 8x MI355X-class node + MPI + a GIN-SDMA build); config mirrors test_AllToAll.py (NP/launcher/xenv/exe/timeout). Includes the harness's intermittent gfx950 cuMem-VMM connectivity-gate retry so the transient abort doesn't flake the test; a genuine data-check mismatch is never retried. Verified on 8x MI355X: 2 GiB-total hang guard passes, 0 wrong, ~425 GB/s (SDMA/SIMPLE tier, 2x128 MiB segments). Co-authored-by: Cursor <cursoragent@cursor.com>
Mirror the AllToAll GIN-SDMA >1 GiB hang-fix tests (PR ROCm#9927) for AllGather so the multi-channel/SDMA ordering concern is covered by an automated test, not just manual runs. Drives GinHybridAllGatherKernel (-D 3, NCCL_GIN_TYPE=5) with the SDMA tier forced (threshold=0) at per-rank chunks that cross the <=128 MiB segmentation boundary (256 MiB -> 2 seg, 2 GiB -> 16 seg), plus a 2 GiB-total completion guard with a subprocess timeout that turns a reintroduced SDMA hang into a failure. Exact-integer dtypes + built-in data check (-c 1) so a truncated /stale tail can't hide under float tolerance. Opt-in via RCCL_TESTS_GIN_SDMA_AG (needs an 8x MI355X-class node + MPI + a GIN-SDMA build); config mirrors test_AllToAll.py (NP/launcher/xenv/exe/timeout). Includes the harness's intermittent gfx950 cuMem-VMM connectivity-gate retry so the transient abort doesn't flake the test; a genuine data-check mismatch is never retried. Verified on 8x MI355X: 2 GiB-total hang guard passes, 0 wrong, ~425 GB/s (SDMA/SIMPLE tier, 2x128 MiB segments). Co-authored-by: Cursor <cursoragent@cursor.com> (cherry picked from commit 38b741a)
|
The merging of the target branch closed the PR automatically, work is not to be discarded just need to change the target branch to develop. |
| hostfile = request.config.getoption("--hostfile") | ||
| launch = [LAUNCHER, "-np", str(NP)] + MPI_OPTS | ||
| if hostfile: | ||
| launch += ["-host", hostfile] |
There was a problem hiding this comment.
In Open MPI -host expects a comma separated list of hosts, not a hostfile, the option is --hostfile.
| # | ||
| # These drive the real GinHybridAlltoAllKernel (deviceImpl 3, NCCL_GIN_TYPE=5) | ||
| # at per-peer transfer sizes that cross the two single-descriptor limits the | ||
| # 128 MiB SDMA copy clamp guards. The clamp now lives in the Anvil-SDMA backend |
There was a problem hiding this comment.
There is nothing specific to SDMA as far as I can tell in that tester and it could be used to validate the same feature in GDA (or other GIN transports for that matter), maybe scrubbing the ANVIL_SDMA from the comments and function names would be good.
…large message A2A hang Rebased onto develop; supersedes ROCm#9927.
Port reconciled ddai-artifacts from meta-repro-wip for PR ROCm#9927 validation: NCCL_GIN_TYPE=5 smoke gate, COLLECTIVE=a2a fast-build preset, and stage3c Dockerfile ONLY_FUNCS quoting fix. Co-authored-by: Cursor <cursoragent@cursor.com>
…large message A2A hang Rebased onto develop; supersedes ROCm#9927. Co-authored-by: Cursor <cursoragent@cursor.com>
Port reconciled ddai-artifacts from meta-repro-wip for PR ROCm#9927 validation: NCCL_GIN_TYPE=5 smoke gate, COLLECTIVE=a2a fast-build preset, and stage3c Dockerfile ONLY_FUNCS quoting fix. Co-authored-by: Cursor <cursoragent@cursor.com>
Port reconciled ddai-artifacts from meta-repro-wip for PR ROCm#9927 validation: NCCL_GIN_TYPE=5 smoke gate, COLLECTIVE=a2a fast-build preset, and stage3c Dockerfile ONLY_FUNCS quoting fix. Co-authored-by: Cursor <cursoragent@cursor.com>
…ge A2A hang Segment large gin.put() calls in the Anvil-SDMA backend Put, port the per-ctx signal-slot init fix, and add host/device tests plus opt-in rccl-tests AllToAll coverage. Rebased onto current develop with minimal alltoall.cu and test CMakeLists deltas. Supersedes ROCm#9927. Co-authored-by: Cursor <cursoragent@cursor.com>
Port reconciled ddai-artifacts from meta-repro-wip for PR ROCm#9927 validation: NCCL_GIN_TYPE=5 smoke gate, COLLECTIVE=a2a fast-build preset, and stage3c Dockerfile ONLY_FUNCS quoting fix. Co-authored-by: Cursor <cursoragent@cursor.com>
…ge A2A hang Segment large gin.put() calls in the Anvil-SDMA backend Put, port the per-ctx signal-slot init fix, and add host/device tests plus opt-in rccl-tests AllToAll coverage. Rebased onto current develop with minimal alltoall.cu and test CMakeLists deltas. Supersedes ROCm#9927. Co-authored-by: Cursor <cursoragent@cursor.com>
Mirror the AllToAll GIN-SDMA >1 GiB hang-fix tests (PR ROCm#9927) for AllGather so the multi-channel/SDMA ordering concern is covered by an automated test, not just manual runs. Drives GinHybridAllGatherKernel (-D 3, NCCL_GIN_TYPE=5) with the SDMA tier forced (threshold=0) at per-rank chunks that cross the <=128 MiB segmentation boundary (256 MiB -> 2 seg, 2 GiB -> 16 seg), plus a 2 GiB-total completion guard with a subprocess timeout that turns a reintroduced SDMA hang into a failure. Exact-integer dtypes + built-in data check (-c 1) so a truncated /stale tail can't hide under float tolerance. Opt-in via RCCL_TESTS_GIN_SDMA_AG (needs an 8x MI355X-class node + MPI + a GIN-SDMA build); config mirrors test_AllToAll.py (NP/launcher/xenv/exe/timeout). Includes the harness's intermittent gfx950 cuMem-VMM connectivity-gate retry so the transient abort doesn't flake the test; a genuine data-check mismatch is never retried. Verified on 8x MI355X: 2 GiB-total hang guard passes, 0 wrong, ~425 GB/s (SDMA/SIMPLE tier, 2x128 MiB segments). Co-authored-by: Cursor <cursoragent@cursor.com> (cherry picked from commit 38b741a)
…ge A2A hang Segment large gin.put() calls in the Anvil-SDMA backend Put, port the per-ctx signal-slot init fix, and add host/device tests plus opt-in rccl-tests AllToAll coverage. Rebased onto current develop with minimal alltoall.cu and test CMakeLists deltas. Supersedes #9927. Co-authored-by: Cursor <cursoragent@cursor.com>
…ge A2A hang Segment large gin.put() calls in the Anvil-SDMA backend Put, port the per-ctx signal-slot init fix, and add host/device tests plus opt-in rccl-tests AllToAll coverage. Rebased onto current develop with minimal alltoall.cu and test CMakeLists deltas. Supersedes #9927. Co-authored-by: Cursor <cursoragent@cursor.com>
…ge A2A hang Segment large gin.put() calls in the Anvil-SDMA backend Put, port the per-ctx signal-slot init fix, and add host/device tests plus opt-in rccl-tests AllToAll coverage. Rebased onto current develop with minimal alltoall.cu and test CMakeLists deltas. Supersedes #9927. Co-authored-by: Cursor <cursoragent@cursor.com>
Mirror the AllToAll GIN-SDMA >1 GiB hang-fix tests (PR ROCm#9927) for AllGather so the multi-channel/SDMA ordering concern is covered by an automated test, not just manual runs. Drives GinHybridAllGatherKernel (-D 3, NCCL_GIN_TYPE=5) with the SDMA tier forced (threshold=0) at per-rank chunks that cross the <=128 MiB segmentation boundary (256 MiB -> 2 seg, 2 GiB -> 16 seg), plus a 2 GiB-total completion guard with a subprocess timeout that turns a reintroduced SDMA hang into a failure. Exact-integer dtypes + built-in data check (-c 1) so a truncated /stale tail can't hide under float tolerance. Opt-in via RCCL_TESTS_GIN_SDMA_AG (needs an 8x MI355X-class node + MPI + a GIN-SDMA build); config mirrors test_AllToAll.py (NP/launcher/xenv/exe/timeout). Includes the harness's intermittent gfx950 cuMem-VMM connectivity-gate retry so the transient abort doesn't flake the test; a genuine data-check mismatch is never retried. Verified on 8x MI355X: 2 GiB-total hang guard passes, 0 wrong, ~425 GB/s (SDMA/SIMPLE tier, 2x128 MiB segments). Co-authored-by: Cursor <cursoragent@cursor.com> (cherry picked from commit 38b741a)
Mirror the AllToAll GIN-SDMA >1 GiB hang-fix tests (PR ROCm#9927) for AllGather so the multi-channel/SDMA ordering concern is covered by an automated test, not just manual runs. Drives GinHybridAllGatherKernel (-D 3, NCCL_GIN_TYPE=5) with the SDMA tier forced (threshold=0) at per-rank chunks that cross the <=128 MiB segmentation boundary (256 MiB -> 2 seg, 2 GiB -> 16 seg), plus a 2 GiB-total completion guard with a subprocess timeout that turns a reintroduced SDMA hang into a failure. Exact-integer dtypes + built-in data check (-c 1) so a truncated /stale tail can't hide under float tolerance. Opt-in via RCCL_TESTS_GIN_SDMA_AG (needs an 8x MI355X-class node + MPI + a GIN-SDMA build); config mirrors test_AllToAll.py (NP/launcher/xenv/exe/timeout). Includes the harness's intermittent gfx950 cuMem-VMM connectivity-gate retry so the transient abort doesn't flake the test; a genuine data-check mismatch is never retried. Verified on 8x MI355X: 2 GiB-total hang guard passes, 0 wrong, ~425 GB/s (SDMA/SIMPLE tier, 2x128 MiB segments). Co-authored-by: Cursor <cursoragent@cursor.com> (cherry picked from commit 38b741a)
Mirror the AllToAll GIN-SDMA >1 GiB hang-fix tests (PR ROCm#9927) for AllGather so the multi-channel/SDMA ordering concern is covered by an automated test, not just manual runs. Drives GinHybridAllGatherKernel (-D 3, NCCL_GIN_TYPE=5) with the SDMA tier forced (threshold=0) at per-rank chunks that cross the <=128 MiB segmentation boundary (256 MiB -> 2 seg, 2 GiB -> 16 seg), plus a 2 GiB-total completion guard with a subprocess timeout that turns a reintroduced SDMA hang into a failure. Exact-integer dtypes + built-in data check (-c 1) so a truncated /stale tail can't hide under float tolerance. Opt-in via RCCL_TESTS_GIN_SDMA_AG (needs an 8x MI355X-class node + MPI + a GIN-SDMA build); config mirrors test_AllToAll.py (NP/launcher/xenv/exe/timeout). Includes the harness's intermittent gfx950 cuMem-VMM connectivity-gate retry so the transient abort doesn't flake the test; a genuine data-check mismatch is never retried. Verified on 8x MI355X: 2 GiB-total hang guard passes, 0 wrong, ~425 GB/s (SDMA/SIMPLE tier, 2x128 MiB segments). Co-authored-by: Cursor <cursoragent@cursor.com> (cherry picked from commit 38b741a)
Mirror the AllToAll GIN-SDMA >1 GiB hang-fix tests (PR ROCm#9927) for AllGather so the multi-channel/SDMA ordering concern is covered by an automated test, not just manual runs. Drives GinHybridAllGatherKernel (-D 3, NCCL_GIN_TYPE=5) with the SDMA tier forced (threshold=0) at per-rank chunks that cross the <=128 MiB segmentation boundary (256 MiB -> 2 seg, 2 GiB -> 16 seg), plus a 2 GiB-total completion guard with a subprocess timeout that turns a reintroduced SDMA hang into a failure. Exact-integer dtypes + built-in data check (-c 1) so a truncated /stale tail can't hide under float tolerance. Opt-in via RCCL_TESTS_GIN_SDMA_AG (needs an 8x MI355X-class node + MPI + a GIN-SDMA build); config mirrors test_AllToAll.py (NP/launcher/xenv/exe/timeout). Includes the harness's intermittent gfx950 cuMem-VMM connectivity-gate retry so the transient abort doesn't flake the test; a genuine data-check mismatch is never retried. Verified on 8x MI355X: 2 GiB-total hang guard passes, 0 wrong, ~425 GB/s (SDMA/SIMPLE tier, 2x128 MiB segments). Co-authored-by: Cursor <cursoragent@cursor.com> (cherry picked from commit 38b741a)
Mirror the AllToAll GIN-SDMA >1 GiB hang-fix tests (PR ROCm#9927) for AllGather so the multi-channel/SDMA ordering concern is covered by an automated test, not just manual runs. Drives GinHybridAllGatherKernel (-D 3, NCCL_GIN_TYPE=5) with the SDMA tier forced (threshold=0) at per-rank chunks that cross the <=128 MiB segmentation boundary (256 MiB -> 2 seg, 2 GiB -> 16 seg), plus a 2 GiB-total completion guard with a subprocess timeout that turns a reintroduced SDMA hang into a failure. Exact-integer dtypes + built-in data check (-c 1) so a truncated /stale tail can't hide under float tolerance. Opt-in via RCCL_TESTS_GIN_SDMA_AG (needs an 8x MI355X-class node + MPI + a GIN-SDMA build); config mirrors test_AllToAll.py (NP/launcher/xenv/exe/timeout). Includes the harness's intermittent gfx950 cuMem-VMM connectivity-gate retry so the transient abort doesn't flake the test; a genuine data-check mismatch is never retried. Verified on 8x MI355X: 2 GiB-total hang guard passes, 0 wrong, ~425 GB/s (SDMA/SIMPLE tier, 2x128 MiB segments). Co-authored-by: Cursor <cursoragent@cursor.com> (cherry picked from commit 38b741a)
Mirror the AllToAll GIN-SDMA >1 GiB hang-fix tests (PR #9927) for AllGather so the multi-channel/SDMA ordering concern is covered by an automated test, not just manual runs. Drives GinHybridAllGatherKernel (-D 3, NCCL_GIN_TYPE=5) with the SDMA tier forced (threshold=0) at per-rank chunks that cross the <=128 MiB segmentation boundary (256 MiB -> 2 seg, 2 GiB -> 16 seg), plus a 2 GiB-total completion guard with a subprocess timeout that turns a reintroduced SDMA hang into a failure. Exact-integer dtypes + built-in data check (-c 1) so a truncated /stale tail can't hide under float tolerance. Opt-in via RCCL_TESTS_GIN_SDMA_AG (needs an 8x MI355X-class node + MPI + a GIN-SDMA build); config mirrors test_AllToAll.py (NP/launcher/xenv/exe/timeout). Includes the harness's intermittent gfx950 cuMem-VMM connectivity-gate retry so the transient abort doesn't flake the test; a genuine data-check mismatch is never retried. Verified on 8x MI355X: 2 GiB-total hang guard passes, 0 wrong, ~425 GB/s (SDMA/SIMPLE tier, 2x128 MiB segments). Co-authored-by: Cursor <cursoragent@cursor.com> (cherry picked from commit 38b741a)
Summary
Fixes a hang in GIN-SDMA AllToAll for transfers >1 GiB on MI355X + ROCm 7.13 (
NCCL_GIN_TYPE=5/SDMA). A single fusedCOPY_LINEAR_WAIT_SIGNALdescriptor at/above 256 MiB/peer stalls the SDMA engine, so the copy never lands and itsSignalIncnever fires, leaving every rank spinning inwaitSignal.The size cap now lives inside the Anvil-SDMA backend Put API, not in the shared rccl-tests A2A kernels.
GinAlltoAllKernel/HybridAlltoAllKernelare the entry points for all GIN backends (proxy, rocSHMEM GDA, Anvil-SDMA), so capping there wrongly throttled proxy/GDA and exposed an app-visibleginPutChunked()helper with no NCCL equivalent. Moving the cap into the backend scopes the fix to SDMA and keeps chunking out of user code.What changed
ncclGinApi_Put<NCCL_NET_DEVICE_GIN_ANVIL_SDMA>(gin_anvil_sdma.h): a large put is split into<= kGinPutSegBytes(128 MiB) SDMA copies. The fused signal (or the explicitSignalInc) is carried only on the final segment. The backend runs a single in-order SDMA queue per peer (numChannelsforced to 1, see852d20d4b9), so the trailing signal still means the whole message has landed. A<=128 MiBput stays a single segment, so the common path is unchanged.gin_anvil_sdma_put_policy.h(new device header): ships the two put-size limits —kGinPutMaxBytes(1 GiB, the 30-bit descriptor count bound) andkGinSdmaSafeCopyBytes(128 MiB, the empirical single-copy limit) — plus the pure segment math (ginPutSegmentCount(),ginPutSegmentAt()). Host-compilable (GIN_SDMA_HOST_ONLY) so the unit test links without a GPU. Added to the rccl install manifest.projects/rccl/test/gin/gin_sdma_policy_test.cppand wired into the rccl test suite (rccl-UnitTestsGinSdmaPolicy): asserts segment counts and contiguous, single-final-signal tiling over{0, 128MiB, 128MiB+1, 256MiB, 1GiB, 2GiB}.gin.put(): droppedginPutChunked, the rccl-testsgin_sdma_collective_policy.h, and theBUILD_TESTSwiring.Why 128 MiB and not 1 GiB
1 GiB is the hard correctness bound (30-bit descriptor count). 128 MiB is the empirical reliability bound: on MI355X + ROCm 7.13 a fused copy+signal at/above 256 MiB stalls the engine. 128 MiB is the largest tier that never stalls, with no measured bandwidth loss vs. the 1 GiB case.
Test plan
rccl-UnitTestsGinSdmaPolicy): segment math correct over the boundary set, exactly one final signal — 5/5 pass, warning-clean.alltoall_perf(SDMA) on 8x MI355X (gfx950), 256 MiB -> 2 GiB total: no hang at any size (incl. 256M/512M/1G/2G per-peer),#wrong = 0, ~426 GB/s busbw at 2 GiB. Segmentation exercised (2 GiB total -> 256 MiB/peer -> 2 x 128 MiB segments).NCCL_GIN_TYPE=2(proxy) /4(GDA) unaffected — now guaranteed by construction (kernels use plaingin.put()); clean datapoint pending a host with a working RDMA stack.Made with Cursor