Repository navigation
Conversation
ctx.all_gather called ctx.store once per destination, and every call loaded heap_bases twice (source and destination base). A load issued after a store cannot be hoisted above it, and waiting for that load also waits for every earlier store, so the compiler emitted s_waitcnt vmcnt(0) before each of the 128 stores of a 256x256 fp16 tile, serializing the remote stores. Load the local and all peer heap bases once before the first store, keep each peer as a scalar pointer delta, and write to peers in a per-rank rotated order starting with the local copy. The assembly now has a single vmcnt(0) in the epilogue and no loads between stores. Co-Authored-By: Claude <noreply@anthropic.com>
persistent_all_gather called iris.store once per remote destination inside the tile loop, so every store re-loaded heap_bases twice and was preceded by an s_waitcnt vmcnt(0). persistent_all_gather_partitioned did the same translation after every tile's store even though its destination never changes. Translate the output base once per peer before the tile loop and store through the pre-translated pointers. The persistent kernel now writes the local copy first and peers in a per-rank rotated order, matching the Gluon all-gather. Co-Authored-By: Claude <noreply@anthropic.com>
Translating the destination base once before the tile loop made persistent_all_gather_partitioned 5-12% slower at 64 or fewer programs (for example 4.2 ms -> 4.6 ms at M=16384, N=4096, 64 programs), so restore the original per-tile iris.store there. Only the persistent kernel keeps the hoisting. Co-Authored-By: Claude <noreply@anthropic.com>
Keep the original destination loop, its local-store branch and its ascending order. Only translate the output base for every destination before the tile loop and replace the iris.store call with a tl.store through the pre-translated pointer. Co-Authored-By: Claude <noreply@anthropic.com>
dsidler
marked this pull request as ready for review
November 5, 2026 08:01
dsidler
requested review from
BKP,
artulab,
drprajap,
efric,
mawad-amd,
neoblizz and
nirvedhmeshram
as code owners
November 5, 2026 08:01
mawad-amd
reviewed
Nov 5, 2026
| @@ -104,8 +114,6 @@ def persistent_all_gather( | |||
| # Send local shard data to all destination ranks | |||
| # Each rank's input goes to output[group_rank * M : (group_rank + 1) * M, :] on all ranks | |||
| for i in tl.static_range(world_size): | |||
Collaborator
There was a problem hiding this comment.
can we do the traffic shaping here too? this still loops 0..world_size-1 with local in the middle, so every rank writes to the same peer at the same time. context.py does local-first + rotated order like #594
|
|
||
| # Start with the local copy, then write to peers in a per-rank rotated order so that each | ||
| # destination sees a different writer at any given moment. | ||
| tl.store(dst_ptr, tile.data, mask=combined_mask) |
Collaborator
There was a problem hiding this comment.
local store lost its hint — the old self.store passed hint=(1, tile.block_n) for every dest including self. the remote stores below still get max_contiguous/multiple_of but this one doesnt
Write the local copy first and the peers in a per-rank rotated order in persistent_all_gather, matching ctx.all_gather and the Gluon all-gather, so each destination sees one writer at a time. Also apply the same max_contiguous/multiple_of hint to the local store in ctx.all_gather that the remote stores and the old self.store path had. Co-Authored-By: Claude <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ctx.all_gathercalledctx.storeonce per destination, and every call did twotl.load(heap_bases + rank)(source and destination base). A load issued after a store cannot be hoisted above it, and waiting for that load also waits for every earlier store, so the compiler put ans_waitcnt vmcnt(0)in front of each store. On gfx942vmcntcounts stores too, so the remote stores were effectively serialized.This loads the local and all peer heap bases once before the first store, keeps each peer as a scalar pointer delta (
peer_base - local_base), and then issues plain stores. The local copy goes first and peers are written in a per-rank rotated order (rank + 1,rank + 2, ...), the same idea as the Gluon all-gather in #594. No API change.Assembly (256x256 fp16 tile,
_fused_matmul_all_gather_kernel, gfx942)s_waitcnt vmcnt(0)in the epilogueBenchmark
benchmark/ops/bench_matmul_all_gather.py, the CU-basedmatmul_all_gather, 8 ranks, fp16, N=3584, K=8192, two runs each on currentmain:Triton CCL all-gather (
iris/ccl/triton/all_gather.py)The same pattern is applied to
persistent_all_gather, which callediris.storeper remote destination inside the tile loop. The output base is translated once per peer before the tile loop; the local copy is written first and peers in rotated order, like the Gluon version in #594.persistent_all_gather_partitionedis left as it was: hoisting its single destination base out of the tile loop made it 5-12% slower at 64 or fewer programs.Assembly of
persistent_all_gather(gfx942): global loads 13-14 -> 1,vmcnt(0)drains 9 -> 2-3, stores immediately after a drain 8/8 -> 5/8 (I did not look into the remaining 5).benchmark/ccl/bench_all_gather.py,persistent, 8 ranks, fp16, N=4096, two runs each. With 64 or more programs the kernel is link-bound and the change is neutral. With a small CU budget, issue serialization limits it and the change helps:🤖 Generated with Claude Code