fix: synchronize custom collectives before return#4082
Conversation
Co-authored-by: ColorsWind <14761584+ColorsWind@users.noreply.github.com>
🏷️ CI GuideRuns automatically on every PR:
Extended tests (opt-in via labels):
|
There was a problem hiding this comment.
Pull request overview
This PR adds an explicit end-of-kernel cross-rank synchronization to custom collective GPU kernels that directly read peer input buffers, preventing the kernel from returning before all peer reads complete (avoiding races when the caller immediately reuses/overwrites the input, e.g., under CUDA graph / overlapped execution).
Changes:
- Add
end_sync<ngpus, true>(sg, self_sg, rank)to all-gather kernels after completing peer-input reads. - Add
end_sync<ngpus, true>(sg, self_sg, rank)to reduce-scatter kernels after completing peer-input reads/reductions. - Add
end_sync<ngpus, true>(sg, self_sg, rank)to the 1-stage fused all-reduce + RMSNorm kernels after the main compute loop.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Performance Testbenchmark script: https://gist.github.com/jpy794/d1ffc4a89c9ce6f36e57374a41a004ae
|
|
Related to #3514, which fixed this same race for |
Motivation
This PR fixes a race in custom collective kernels where a collective may return before all peer reads from the input buffer have completed.
In CUDA graph / overlapped execution scenarios, the caller may reuse or overwrite the input tensor immediately after the custom collective returns. Without an end-of-kernel synchronization, another rank can still be reading that input buffer, which can lead to corrupted collective outputs. The repro script demonstrates this by filling the input with NaNs right after the collective and checking whether NaNs leak into the output.
cc @ColorsWind
Technical Details
This change adds
end_sync<ngpus, true>(sg, self_sg, rank)before returning from custom collective kernels that directly read peer input buffers.Covered paths in
csrc/include/custom_all_reduce.cuhinclude:all-gather kernels:
allgather_naiveallgather_vecallgather_lastdimreduce-scatter kernels:
reduce_scatter_split_first_dimreduce_scatter_split_lastdim_naivereduce_scatter_split_lastdimreduce_scatter_split_middim_naivereduce_scatter_split_middim1-stage fused all-reduce + RMSNorm kernels:
The synchronization ensures that all ranks complete their remote reads before any rank is allowed to proceed and potentially mutate or recycle its input buffer.
Test Plan
Use the custom collective race repro script here https://gist.github.com/jpy794/a2849ad6d3d2a3f0d1a03c6c1ec977ac
rm -rf aiter/aiter/jit/module_custom_all_reduce.so \ aiter/aiter/jit/build/module_custom_all_reduce python custom_collective_race_repro.pyThe repro captures a CUDA graph that repeatedly:
Expected result after this fix: all ranks report bad_nan_rows=0.
Test Result
Submission Checklist