Repository navigation
[HIP] [Perf] Specialize partial tiles in two-stage custom all-reduce - #5807
Merged
Merged
Conversation
Run complete tiles through the original shared-memory loop and reduce the remaining packs in their owner threads without conditional barriers. Preserve the upstream write-mode and fused barrier fixes and add exact changing-input eager/graph regression coverage. Signed-off-by: Andreas Karatzas <akaratza@amd.com>
Contributor
🏷️ CI GuideRuns automatically on every PR:
Extended tests (opt-in via labels):
PR title tags & labels: |
Signed-off-by: Andreas Karatzas <akaratza@amd.com>
vgokhale
approved these changes
Sep 25, 2026
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.
Proposed modifications
has_tailparameter.packed_reduce, preserving their original owner threads and output indices.has_tail=false, removing tail predicates and restoring the generated aligned kernel from before [HIP] fix(custom_all_reduce): uniform trip count for the block barriers #5694.(1023,512),(1024,512), and(1025,512)cases in the existing default benchmark sweep, keeping the list sorted, deduplicated, and within its configured size cutoff.Microbenchmarks and performance comparison
This follows merged #5694 and targets current
main; it preserves that PR's correctness fixes while specializing the plain read path. The benchmark study used four gfx950 GPUs at TP4 and a commonv0.1.22.post1base (b4d9154d125e09efbe098d986e40fea3549c1244). The correct comparison baseline applied #5694's three barrier hunks (5e77166e0c627caa109046f6469de8220efa5ba6) to that base. These are the historical isolated-kernel measurements, not a newly timed end-to-end run of currentmain.The study completed 44 variant runs: three alternating-order rounds for focused and broad sweeps, and five for eight additional BF16 shapes. Each case used five warmups and seven samples: 64 calls per eager sample, or 64 captured calls replayed ten times per graph sample. CUDA-event timing excludes input preparation and checking; eager results include Python launch/allocation gaps. Latencies are the median across rounds of each round's maximum per-rank sample median. Percentage changes are medians of paired within-round ratios and need not equal ratios of the displayed latencies.
For
(1025, 512), lower latency is better:The full sweep includes BF16/FP16/FP32 at
(1023,512),(1024,512), and(1025,512); 43 dtype/size configurations spanning 8 KiB–8 MiB and per-rank tails of 1/63/64/65/127 packs; and BF16(M,2880)forM=120,121,127,157,160,161,256,512. Compared with the unsafe pre-#5694 release, the proposed specialization's largest observed case-level median increases were 0.56% graph and 1.92% eager; the initial whole-message naive fallback cost about 29% on the reported BF16 graph case. The unsafe release is a historical timing reference only.The host was shared, the other four GPUs were busy, and three to five rounds do not establish a general sub-percent regression bound. Timed graph replays reuse inputs within a sample; the separate changing-input regression provides stronger race coverage. TP8/gfx942 configurations and end-to-end model throughput were not measured. This PR keeps the upstream write-mode dispatch, including its partial-tile handling.
Validation
The previously tested tail specialization passed 8,400 changing-input checks per rank at TP4 across BF16/FP16/FP32 and 600 per rank at TP2. The unmodified vLLM PR #58433 test file passed all four BF16/MXFP8 TP2/TP4 cases in 74.15 seconds. The unsafe release failed the reported shape at eager iteration 0, with 125 mismatches and a maximum absolute error of 22. The actual main-based branch and pristine
mainboth clean-built for gfx950. All 48 gfx950 specialized read-kernel variants match the previously tested tail kernels byte-for-byte, including resource metadata; all 24 current-main read variants match the benchmarked #5694 baseline. All 24 PR write-kernel variants match pristine main. On the actual current-main PR branch, BF16/FP16/FP32 TP4 each passed six shapes with 100 eager and 100 graph iterations per shape. The unmodified vLLM integration suite passed again: 4 passed in 71.75 seconds, covering BF16/MXFP8 at TP2/TP4. Ruff, Black, Python syntax, and diff checks passed.Follow-up validation repeated the unchanged vLLM test group in 50 fresh pytest processes: 200/200 cases passed, with zero failures, errors, skips, timeouts, or retries (68.2 minutes). Six runs emitted TCPStore shutdown warnings while all tests passed. The kernel and compiled collective library are unchanged by the benchmark-list follow-up.
The three boundary sizes also passed 18/18 cases through the existing benchmark at TP4: BF16/FP16/FP32 in eager and graph modes. Profiler records confirmed the intended two-stage tail specialization for both neighbors and the aligned specialization for the middle size on all four ranks; 21 size-list/cutoff checks passed. These benchmark checks use the existing random-input tolerance. The default sweep now includes these shapes without
-s, for example:Regression command (repeat for
fp16andfp32):HIP_VISIBLE_DEVICES=0,1,2,3 python op_tests/multigpu_tests/test_custom_allreduce.py \ --regression -t 4 -d bf16 --iterations 100Standalone microbenchmark reproducer
Build/install each revision using the repository's usual source-build instructions, save the following as
bench_allreduce_tail.py, and run it against each revision. The output records the loaded collective library's SHA256, per-rank timings, and correctness results. Alternate revision order between repeated runs.HIP_VISIBLE_DEVICES=0,1,2,3 python bench_allreduce_tail.py \ --output latency.json --case-set all --dtypes bf16 fp16 fp32 \ --modes eager graph --calls 64 --replays 10 --samples 7 --warmup 5History and motivation
This work began when vLLM PR #58433 intermittently failed TP4 tests in Buildkite build #90750 despite passing on retry. The
(1025, 512)case exposed block barriers inside a loop whose iteration count differed between threads at a partial tile. A local regression reproduced corruption in the original release. Routing partial messages to the naive kernel restored correctness but increased BF16 graph latency by about 29%. Merged AITER PR #5694 fixes the barrier defect with uniform loop bounds. This follow-up retains its write-mode and fused fixes while specializing complete tiles and leftover packs in the plain read kernel. The motivation is to preserve the correctness fix with minimal performance cost and keep the original test shapes and assertions.AI assistance was used for implementation, investigation, and validation.