[cudax] Isolate and synchronize reduce scratch - #10985
Draft
tpn wants to merge 1 commit into
Draft
Conversation
Mapped warp groups synchronize independently, but reduce used one shared scratch object. Concurrent siblings could corrupt CUB storage, partials, and broadcast results. Passing owning groups by value could also destroy copied synchronizer state. Give each physical block warp its own temporary and value slot. Use the exact static block extent when available and the architectural 32-warp bound otherwise. Reject noncontiguous mappings until a safe physical membership traversal is available. Add the collective barriers required before block, cluster, grid, and mapped-group scratch is reused by a later call. Add repeated regressions for direct, nested, and viewed mappings with static and dynamic extents, plus block, cluster, and grid scratch reuse. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Trent Nelson <trent@trent.me>
Contributor
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
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.
Why this is needed
coop::reducekeeps its temporary storage internally. The mapped warp-groupoverload previously indexed that storage using a warp's rank within its group.
That rank is local to each group, but sibling groups have independent
synchronizers and may execute concurrently.
For example, partitioning a seven-warp block into groups of three produces:
Physical warps 0 and 3 could therefore use the same CUB
WarpReduce::TempStorageat the same time. The groups also shared partial andbroadcast storage. A barrier within one group does not synchronize the other
group.
The block, cluster, and grid implementations had a related lifetime problem.
Their scratch storage persists across calls, but some paths returned before
every participant had finished consuming it. A subsequent reduction could
overwrite that storage while the previous root was still reading it.
Mapped groups were also passed by value. Some group objects own synchronizer
state, so destroying the parameter copy could tear down copied synchronization
state independently of the original owner.
Examples
Independently synchronized warp groups shared the same slots
The following pattern creates two valid three-warp groups in one block. The
final warp does not participate.
With a 224-thread launch, both groups execute the same
reducespecialization:
Each group numbers its warps from zero. Before this change, physical warp 0 and
physical warp 3 both selected temporary slot 0, physical warps 1 and 4 selected
slot 1, and so on. Since the groups synchronize independently, CUB temporary
storage and partial results could be modified concurrently.
Back-to-back reductions could reuse scratch too early
Ordinary repeated use was enough to expose the missing terminal barriers:
This pattern applies to
this_block,this_cluster,this_grid, and mappedgroups. Without a terminal collective, non-root participants could enter the
next iteration and overwrite scratch while the previous root was still
consuming it.
Block broadcast could reactivate aliased storage too soon
The block implementation uses a union because the CUB temporary storage and
broadcast value do not need to coexist after the collective finishes:
The old sequence effectively did this:
The fixed sequence separates the storage lifetimes and protects the returned
value from the next invocation:
What changed
Mapped warp-group reductions now assign storage by physical block-warp rank:
const&, preserving the owning synchronizer'slifetime.
The implementation requires a statically sized, contiguous mapping. It uses the
exact physical warp count when the block extents are static. For runtime block
extents, it uses the architectural bound of 32 warps per block, derived from
CUDA's maximum of 1024 threads per block. Larger thread counts associated with
some architectures describe residency per SM, not the size of one thread
block.
The collective paths now synchronize before scratch is repurposed or reused:
broadcast member.
synchronization.
terminal collective before returning.
barrier that protects the next invocation.
These barriers add synchronization cost, but they are required while
reduceowns implicit shared or global scratch.
Follow-ups
Support runtime block extents in
this_warpThe separate
this_warpoverload still computes its shared-memory array bounddirectly from
static_extent. A runtime block configuration therefore failsduring compilation:
This defect predates the mapped-group change. It should be fixed separately
after defining the behavior of a terminal partial warp.
Make temporary storage caller-provided
reduce.cuhalready notes that implicit scratch is temporary API design.Caller-provided storage would make ownership explicit and could remove the
terminal barriers added here.
It should also replace the global grid-partial array. Two concurrent launches
of the same grid-reduction specialization currently refer to the same global
storage:
The streams may execute concurrently, allowing the two grids to overwrite each
other's partial results.
Define the contract for future strided mappings
The currently supported contiguous mappings assign unit ranks in ascending
physical-warp order. The physical-slot calculation relies on that property.
Before adding strided or permuted mappings, the mapping API should expose a
physical base rank or a dedicated order-preserving trait rather than treating
contiguity alone as sufficient.