Repository navigation
fix(cuda-device): run mbarrier init on one linear thread - #1349
Merged
nihalpasham merged 7 commits intoOct 19, 2026
Merged
Conversation
ManagedBarrier::init_by and inval_by selected the actor with threadIdx.x alone. In a 2D or 3D block that matches every thread with that x, so more than one thread executed mbarrier_init or mbarrier_inval. Select the thread by its x-major linear id instead. init() and inval() still pass 0, which is thread (0, 0, 0), and a 1D block still compares against threadIdx.x. Signed-off-by: YeonwooSung <neos960518@gmail.com>
…rier-init-one-thread
init_by and inval_by now compare thread::block_linear_thread_id_here() with the selector instead of a private copy of the x-major linearization. The private predicate and its tests are gone; one property test next to the shared helper in thread.rs checks that every in-range id selects one thread across 1D, 2D, 3D and non-power-of-two blocks and that an id equal to the thread count selects nobody. This also removes the test literal that failed clippy::identity_op under -D warnings, and the init_by and inval_by safety rules now require a block-uniform selector below the block's thread count. Signed-off-by: nihalpasham <nihalp@nvidia.com>
The thread-requirement table, the struct example and the from_static docs still described a thread-0-only protocol. from_static is a plain constructor every thread calls; init() and inval() are all-threads calls in which linear thread 0, that is thread (0, 0, 0), acts, and both synchronize the block, so the old from_static example that called init() inside a thread-0 branch put a block-wide sync in divergent code. The struct example also repeated the fence and sync that init() already performs. Signed-off-by: nihalpasham <nihalp@nvidia.com>
Add test_managed_barrier_2d: every thread calls init_by(128, 127) and inval_by(127), so block-linear thread 127, which is thread (31, 3, 0), runs mbarrier.init and mbarrier.inval; both coordinates of that thread are nonzero and no thread has threadIdx.x equal to the selector. Thread 0 fills the barrier word with all-ones first, a determinism aid that keeps the test independent of what shared memory held at launch. Each thread writes 42 when its row-major index equals its block rank, and the host returns an error on any other value. Against the previous election by threadIdx.x alone no thread matched the selector and the launch failed with error 719; with the block-linear election all 128 threads complete. Signed-off-by: nihalpasham <nihalp@nvidia.com>
A one-page figure for the book and the pull request, in the style of the tile-libraries direct-linkage figure. Signed-off-by: nihalpasham <nihalp@nvidia.com>
Collaborator
|
/ok to test fd2bb39 |
Collaborator
|
Thanks, this is the right fix:
At |
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.
What this adds
ManagedBarrier::init_byandinval_byelect the thread that runsmbarrier.initandmbarrier.invalby its block-linear id,threadIdx.x + blockDim.x * (threadIdx.y + blockDim.y * threadIdx.z), instead of bythreadIdx.xalone.init()andinval()still select id 0, which is thread (0, 0, 0) in every block layout, and 1D blocks keep the same thread as before.What we fixed
threadIdx.xwith the selector. In a 2D or 3D block that admits one thread per row for an in-rangexand no thread at all for a selector at or pastblockDim.x; both are undefined per the PTX ISA, and the second faults with error 719.thread::block_linear_thread_id_here(), the helper fix(cuda-device): select tcgen05 alloc warp by linear thread id #1351 added and the numberingthis_thread_block().thread_rank()uses, so warp election and thread election agree on how a block is numbered.from_static(),init()andinval()are all-threads calls, and thefrom_staticexample calledinit()insideif tid == 0, a block-wide sync inside a divergent branch.Contract
init_by(count, id)andinval_by(id): all threads of the block call them; the thread whose block-linear id equalsidruns the instruction.idmust be the same value in every thread and belowblockDim.x * blockDim.y * blockDim.z; an out-of-range id selects no thread, so the barrier is never initialized or invalidated.init()andinval()select id 0, thread (0, 0, 0).Implementation
barrier.rs:init_byandinval_bycomparecrate::thread::block_linear_thread_id_here()with the selector; these two sites are the only elections in the file, andinit/invaldelegate to them. The private copy of the formula and its tests are gone.thread.rstests: every in-range id selects one thread across 1D, 2D, 3D and non-power-of-two layouts, and an id equal to the thread count selects nobody.future_apis:test_managed_barrier_2dlaunches (32, 4, 1); every thread callsinit_by(128, 127),arrive,wait,inval_by(127); thread 0 fills the barrier word with all-ones first so a missing init faults instead of depending on what shared memory held; each thread writes 42 when its row-major index equals itsthread_rank(), and the host returns an error on any other value.mbarrier_initandmbarrier_invalintrinsics and the catalog are untouched; the defect was in the wrapper's election.Verification
Checked at
fd2bb3902(nightly-2026-10-11, RTX 5090, sm_120a):cargo test -p cuda-device --all-targetspasses with the new property test;cargo clippy --workspace --all-targets -- -D warningsis clean (the submitted head failed onclippy::identity_opin the removed tests); rustdoc with warnings as errors, fmt, the 18 guards and the lock check pass.future_apissource built against main'scuda-devicefails Test 6 withDriverError(719); this branch passes Tests 1 to 6 with memcheck, synccheck and racecheck clean.mbarrier.initand onembarrier.invalper kernel, guarded by the block-linear id; main guards ontid.xalone.Caveats
init()in a 2D block on main) runs silently on sm_120 and the sanitizers stay quiet; the PTX ISA rule is the evidence for it, not a runtime failure.future_apiskernels still callinval()insideif is_thread0after async_threads; that predates this change and is a follow-up.