Repository navigation
Conversation
…by shared subnet The gather served exactly two ranks: one peer, one HCA pair, chosen by index. Worlds of three and four are the ones a GB10 mesh actually wants, and on a crossed mesh the index pairing is wrong as well - port h on one box is a different cable from port h on its peer - which is what made a queue pair refuse RTR on a three-box triangle. This makes the one-shot gather serve two to four ranks, and derives each peer's HCA pairing from the /24 its RoCE GIDs share instead of from the index, falling back to the index when no subnet matches (a switched fabric) and refusing when the peers disagree on the link count, since the kernel waits on one count for every peer. Every rank RDMA-writes its shard to each peer's region and the kernel polls each peer's flag. Measured on a three-rank GB10 triangle, one stream: a working all-gather where none existed before, and about +2% decode over the same three ranks served as two plus a spare, matching the +2.2% an independent prototype reported for the same change. The test that claimed to check the peer/slot bijection asserted that every rank, including the rank itself, appeared among its peers - which cannot hold for any correct mapping, so it failed at every world and would have shipped red. It now asserts the real invariant: the w-1 peers cover every rank except mine, and mine is never covered. roce.zig was at 597 lines against the repository's 600-line module limit, so the ABI declarations and the region layout move into roce_abi.zig and roce_region.zig, with the peer index maps and their tests alongside them. roce.zig is 563 lines; the lean checker stays at its baseline 428 and the host suite at its baseline failure set.
369055c to
46418f8
Compare
|
Thanks @BadAd84. Pairing each peer's rails by the /24 its GIDs share is the right fix for a crossed mesh, and the peer and slot maps check out ( We've answered #1288: three and four ranks go through fabric/tp's
Worlds above two also stay opt-in until a cold-prompt receipt is in: in #1288's runs, prompts were 1.5-2.2% slower while the wire shared NCCL's NIC functions. Small: |
…ver lends a port twice Review 5: Layout.of placed a full slots*s past instead of past the flags region, so TP=2's region grew by two slots and the flags overlapped send. now follows the flags' own size. Review 2: with no shared subnet the index fallback paired every peer with HCAs 0..n-1, so two peers could be paired over one port and the other port over a cable that does not reach. A port is now marked once it faces a peer, the fallback takes only untaken ports, and it refuses when none is left rather than inventing a link.
|
Thank you - the two layout questions are fixed and pushed on top.
Still open, and I would rather list them than imply otherwise:
Also noted that #1288 has been answered through |
Review 3: the tests moved to roce_region.zig when the layout did, but nothing referenced that file from a test root, so the suite fell from 257 tests to 256 and still passed with a line in that file deliberately broken. zig/src/cuda/root.zig now references it beside roce.zig. Proof, by his own experiment: with roce_region.zig:83 changed to expect the opposite, test-runtime-host exits 1 and reports the failure; restored, it exits 0.
|
…t it Review 1, and it was a real deadlock: selectLinks failing returned from the setup before group.gather, while every other rank was already waiting inside that gather for this rank's bit. One rank could not use RoCE, so all of them hung instead of falling back to NCCL. The selection is now a flag rather than an early return: a refusal is logged, connect is skipped, and the rank reaches the gather with a false bit. The gather's existing check then tears the group down on every rank and NCCL carries the gathers, which is the fallback the log line already promised.
That leaves only item 4 open on this PR - worlds above two staying opt-in until there is a cold-prompt receipt, which I accept given the 1.5-2.2% prompt cost in #1288. If the change should be scoped to |
|
Thanks @BadAd84 for the quick fixes. Yes, please cut it down as you offered: keep |
|
Thanks @BadAd84 for the quick fixes. We checked them on the head:
The merge with current main is clean, and The main ask stands. Please cut this PR down to
Three and four ranks go to fabric/tp's
When the no-shared-/24 rule moves to Once it's cut down, we'll run TP=2 on a crossed pair and on a straight pair. We'll check tokens against main and that the RoCE gather comes up on both ranks, then take decode speed rounds. |
A heads-up so the same work isn't done twice: the |
|
Ok yeah, thanks for flagging #1516 before I took this further. For 2 ranks main already works: the 2-rank path swaps one peer's blob and needs no /24 rule, because with a single peer there is only one link choice per side anyway. Nothing is left to fix on the refusal front either: both stages are symmetric exchanges, the blob and then the connected bit, so neither rank can return past a wait its peer is still in. Everything here is the wider pairing, so cutting it to 2 ranks leaves a no-op. I would rather pull it than land that, which is what I am doing. I also ran #1516 on our ring, since I offered. Built from
So it boots and serves correctly at world 3 on a crossed mesh, which is the important part, but no transport gain is measurable here, and For reference, the mesh this was measured on: spark4 P2p1s0f0 10.0.146.4 reaches spark6 P2p1s0f1, P2p1s0f1 10.0.145.4 reaches spark5 P2p1s0f0, p1s0f0 10.0.46.4 reaches spark6 p1s0f1, p1s0f1 10.0.45.4 reaches spark5 p1s0f0, spark5 to spark6 on 10.0.156 and 10.0.56. Pairing peers by port index joins the wrong cables there; pairing by shared /24 joins the right ones. |
Thanks for running it. Both runs gathered over NCCL, which fits the equal speeds, the one digest and the silent log: on main and in #1516, GLM keeps every world above two on NCCL whatever the comm setting (its own RoCE gather stops at two ranks), and #1516 changes only fabric/tp, which GLM does not reach on its own. Your own build's 46.12 against 44.84 on the same ring is a useful measure of what a RoCE gather is worth there at world 3. GLM borrows For #1516 on its own, the direct check is |
Makes the one-shot RoCE all-gather serve two to four ranks instead of exactly two, and derives each
peer's HCA pairing from the /24 its RoCE GIDs share instead of from the index.
Follows the question in #1288, from the other side: rather than lending small gathers to another path,
this makes
cuda/roce.zig's own gather serve the wider world.Why
Two things were two-rank-shaped:
both[1 - group.rank]), refusing any world but 2.links[p][i] = i). On a crossed mesh - port h on one box isa different cable from port h on its peer - that pairing is wrong and the queue pair refuses RTR.
What changes
peerRank/myIndexAtdefine the mapping for any world: peerpof rankris(r + 1 + p) % world,and a write to rank
rlands in the slotr's peer list holds for the sender.recv_peer_stride,flag_peer_stride); every rank RDMA-writes itsshard to each peer's region and the kernel polls every peer's flag.
selectHyperlinkspairs by shared subnet, falling back to index-h when no subnet matches (a switchedfabric) and refusing when the peers disagree on the link count, since the kernel waits on one count for
every peer.
TF_ROCE_MULTI=1is not needed; the world decides.Measured
Three GB10s, TP=3, one stream, 400-token decode, 3 rounds, same checkpoint and image:
RoCE all-gather: 3 rank(s), 1 link(s) over 2 HCA(s));The transport is a data mover: it changes which bytes arrive where, not any arithmetic. The existing
gather tests pass, the served replies are unaffected, and
test-cuda-hostruns at its baseline failureset (26, all pre-existing and unrelated - see below).
Two things a reviewer should know
A test of ours was asserting something impossible.
RoCE gather: peer and slot indices agree at every worldmarkedseen[r]for thew-1peers - all of themr != meby construction - and then requiredevery index in
0..wto have been seen, includingme, which is never a peer of itself. It failed atevery world for any correct mapping, so it tested nothing and would have shipped red. It now asserts the
real invariant: the peers cover every rank except mine, and mine is never covered.
The file was already at the module limit.
cuda/roce.zigwas 597 lines against the repository's 600,so the ABI declarations move to
roce_abi.zigand the region layout, peer index maps and their tests toroce_region.zig.roce.zigis 562 lines.lean_check.pyreports 428 problems, the branch's baseline;test-cuda-hostreports 26 failures, the baseline.Verified on hardware after the move: the image builds, serves and answers at TP=3 (
up in 64 s).