You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It then uses a warp barrier, but that warp barrier only orders memory operations issued by the same warp, not other warps or other thread blocks, like the example is relying on.
Expected behavior
I expected the spin-loop to use acquire memory ordering.
Additional context
This is a customer request (ping me internally for more details if needed).
This issue has been labeled inactive-30d due to no recent activity in the past 30 days. Please close this issue if no further response or action is needed. Otherwise, please respond with a comment indicating any updates or changes to the original issue and/or confirm this issue still needs to be addressed. This issue will be labeled inactive-90d if there is no activity in the next 60 days.
This issue has been labeled inactive-90d due to no recent activity in the past 90 days. Please close this issue if no further response or action is needed. Otherwise, please respond with a comment indicating any updates or changes to the original issue and/or confirm this issue still needs to be addressed.
both acquire or relaxed work on this case as subsequent read is multimem.ld_reduce, which bypass l1. what acquire does is to CCTL.IVALL invalidate l1. l1 does not play in this story.
for good perf in this case, yes use relax is enough
for general purpose programing, use acquire is a good idea
will have some compiler optimization in future that allow use to use acquire and generate relaxed code based on use case
Hi @XiaoSongXS, I'm also studying this GEMM-RS kernel. There are 2 additional issues I want to get clarifications from you:
This is using gpu scope for both flag increment and flag polling. Why is sys scope not used here?
There is no fence between relaxed flag polling and LDMC. Shouldn't fence.proxy.alias be necessary? Is it the same reason as "CCTL.IVALL invalidate l1. l1 does not play in this story."? I noticed fence.proxy.alias compiles to MEMBAR.SC.SYS + CCTL.IVALL
This is using gpu scope for both flag increment and flag polling. Why is sys scope not used here?
U need to understand why u need sys scope. if u write data that will flush to ur local gpu l2, then u are using a gpu scope fence (regardless of wether it is ur local gpu thread or remote gpu thread consume this data, as long as the data land on local gpu l2). if u write data that will flush to remote gpu l2, then u need to use sys scope
in this case, the multimem.ld_reduce require all rank have the data in their gmem/l2, which means in epi we write data to local gpu l2, not remote gpu l2, thus the scope of gpu is what we need
There is no fence between relaxed flag polling and LDMC. Shouldn't fence.proxy.alias be necessary? Is it the same reason as "CCTL.IVALL invalidate l1. l1 does not play in this story."? I noticed fence.proxy.alias compiles to MEMBAR.SC.SYS + CCTL.IVALL
no, not the same reason. the principle is the same, u need to think about why u need alias fence. alias fence is needed when u have one PA that map to two VA, and u read/write one VA and later read/write that VA, and u want to ensure the prior VA write is flush to their desired scope (gpu/sys) and is sequential consistency is enforce.
but here, we already have a flag that ensure our data is in l2, and have a spin loop to ensure ldmc happen only after unlock, all those requirement have already satisfied, and thus no alias fence is needed.
alias fence is the most heavy fence, u should try avoid use it. think about what ur program actually need, and how other logic can be use to satisfy what u need.
U need to understand why u need sys scope. if u write data that will flush to ur local gpu l2, then u are using a gpu scope fence (regardless of wether it is ur local gpu thread or remote gpu thread consume this data, as long as the data land on local gpu l2). if u write data that will flush to remote gpu l2, then u need to use sys scope
Thanks for your insights. The description explains the scope modifier from the perspective of cache flushing behavior. In this way, does that mean it makes no sense to use release.sys for a store in any case as long as the dst is local gmem, since release.gpu has fulfilled the flushing purpose?
And similarly, if I am using regular ld from a local gmem, does that mean acquire.gpu is sufficient, regardless whether the producer is self GPU or remote GPU?
In this way, does that mean it makes no sense to use release.sys for a store in any case as long as the dst is local gmem, since release.gpu has fulfilled the flushing purpose?
Yes. What really matter here is NOT the scope of consumer and producer thread, but rather the scope of where ur memory write goes to.
And the release is only use when u need this "flush" behavior, if u just want local gpu l2 atomic, relaxed is what u need
And similarly, if I am using regular ld from a local gmem, does that mean acquire.gpu is sufficient, regardless whether the producer is self GPU or remote GPU?
Yes, as long as u spin loop pooling from local gpu flag and data, then .acquire.gpu is what u need. The symmetric paring of sys <-> sys is kind of overkill. sys <-> gpu is the minimal hw requirement
@bobboli I see you are a DevTech engineer. Based on Xiao Song's explanation here, I believe many comms kernels in FlashInfer can be further optimized by removing certain defensive fences!
@bobboli I see you are a DevTech engineer. Based on Xiao Song's explanation here, I believe many comms kernels in FlashInfer can be further optimized by removing certain defensive fences!
Unfortunately the A2A kernel in FI uses push to remote & pull from remote pattern, which can not benefit from this. But some others, such as AR, may be optimized.
@XiaoSongXS dumb question: why are you not worried about the compiler (ptxas) hoisting/reordering multimem.ld_reduce before the relaxed flag poll? My guesses:
there is a while spin control loop going on; or
there is a bar sync in between relaxed load and ld_reduce
But not sure which one is right, or if it is due to other reasons. The SASS code right now shows no reordering was done, but not sure if it is guaranteed to not reorder
this is a excellent question. And ur intuition is exactly correct
when a while loop exist, reorder does not happen.
bar.sync kind of ensure some reorder does not happen, but it is weaker, a few thing it ensure
if later operation is cuda core operation and have no memory dependency, then future operation can continue execute. this is what sass defer blocking means. (i think there are lots of hacky sass analysis repo, if ur interested in this, highly recommend dig into the sass)
if operation before and after is memory operation, then no reorder will happen (in most case yes, only a few case no). If this is not guaranteed, then below common pattern will break
__shared__ uint32_t shared_scratch_smem;
shared_scratch_smem[threadId.x] = threadIdx.x + 42;
__syncthreads(); // bar.sync, need to ensure prior memory op is not reorder after bar.sync, need to ensure later memory op is not reorder prior bar.syncuint32_t peer_val = shared_scratch_smem[32 - threadIdx.x];
A second thought on #3118, yes we should adopt this fix (i'll port this fix in another PR), relies on the compiler to do the optimization, and avoid hacking through the mem sys just to avoid one CCTL.IVALL (little perf hurt, nearly no influence) as it cause customer to be quite confused about what should be the correct model
And one thing on the acquire vs relaxed, we have two concept here that need to be clearly distinguish
wether compiler will reorganize the SASS code that break the release -> acquire pair
wether memory visibility is ensured if compiler dont reorder SASS.
For (1) I think the correct approach is to use .release + .acquire. try not hack through the compiler while loop, as the compiler while loop and bar.sync is "implicit", likely one day it break. the .acquire is a strong ensure provided by the ptx model
For (2) use correct scope for release + acquire will ensure this
Hey @XiaoSongXS, could I ask about the choice of gpu scope specifically for the flag increment as well?
My understanding of the kernel is that for some of the completed GEMM tiles, the incremented flag should go to the remote peer's L2 rather than a local L2 (since the RS warps use gpu scope polling), so using sys scope is more appropriate. However, I've not yet run into correctness issues from using a gpu scope flag increment.
Is there something else I've failed to consider when reasoning about the right scope for the flag increment?
29. Hey @XiaoSongXS, could I ask about the choice of gpu scope specifically for the flag increment as well?
My understanding of the kernel is that for some of the completed GEMM tiles, the incremented flag should go to the remote peer's L2 rather than a local L2 (since the RS warps use gpu scope polling), so using sys scope is more appropriate. However, I've not yet run into correctness issues from using a gpu scope flag increment.
Is there something else I've failed to consider when reasoning about the right scope for the flag increment?
this is indeed a very interesting question. the short answer is the flag update with release come with two part, (1) a atomic flag update, (2) a member fence. for the atomic flag update, using gpu scope or sys scope in reality have somewhat same hw path and behavior, so that is not the issue, for the member fence, that is the critical path and u need to make sure that part is correct.
so likely u may want to have flag update using gpu scope (as flag is on local gpu l2) and the member with sys scope. for this case u can use the st.release.sys as the sys scope flag update and gpu scope flag update are effectively doing somewhat same thing on hw.
Activity
brandon-yujie-sun commentedon Mar 20, 2026
@shubaoyu2
shubaoyu2 commentedon Mar 20, 2026
thanks for debugging this! here is the fix MR #3118
github-actions commentedon Apr 19, 2026
This issue has been labeled
inactive-30ddue to no recent activity in the past 30 days. Please close this issue if no further response or action is needed. Otherwise, please respond with a comment indicating any updates or changes to the original issue and/or confirm this issue still needs to be addressed. This issue will be labeledinactive-90dif there is no activity in the next 60 days.github-actions commentedon Jul 18, 2026
This issue has been labeled
inactive-90ddue to no recent activity in the past 90 days. Please close this issue if no further response or action is needed. Otherwise, please respond with a comment indicating any updates or changes to the original issue and/or confirm this issue still needs to be addressed.XiaoSongXS commentedon Jul 20, 2026
please ping Bangyu / Xiao on cutedsl distributed example. there is a reason we use relaxed here
XiaoSongXS commentedon Jul 20, 2026
both acquire or relaxed work on this case as subsequent read is multimem.ld_reduce, which bypass l1. what acquire does is to CCTL.IVALL invalidate l1. l1 does not play in this story.
for good perf in this case, yes use relax is enough
for general purpose programing, use acquire is a good idea
will have some compiler optimization in future that allow use to use acquire and generate relaxed code based on use case
gau-nernst commentedon Aug 4, 2026
Hi @XiaoSongXS, I'm also studying this GEMM-RS kernel. There are 2 additional issues I want to get clarifications from you:
gpuscope for both flag increment and flag polling. Why issysscope not used here?relaxedflag polling and LDMC. Shouldn'tfence.proxy.aliasbe necessary? Is it the same reason as "CCTL.IVALL invalidate l1. l1 does not play in this story."? I noticedfence.proxy.aliascompiles toMEMBAR.SC.SYS + CCTL.IVALLXiaoSongXS commentedon Aug 5, 2026
U need to understand why u need sys scope. if u write data that will flush to ur local gpu l2, then u are using a gpu scope fence (regardless of wether it is ur local gpu thread or remote gpu thread consume this data, as long as the data land on local gpu l2). if u write data that will flush to remote gpu l2, then u need to use sys scope
in this case, the
multimem.ld_reducerequire all rank have the data in their gmem/l2, which means in epi we write data to local gpu l2, not remote gpu l2, thus the scope of gpu is what we needXiaoSongXS commentedon Aug 5, 2026
no, not the same reason. the principle is the same, u need to think about why u need alias fence. alias fence is needed when u have one PA that map to two VA, and u read/write one VA and later read/write that VA, and u want to ensure the prior VA write is flush to their desired scope (gpu/sys) and is sequential consistency is enforce.
but here, we already have a flag that ensure our data is in l2, and have a spin loop to ensure ldmc happen only after unlock, all those requirement have already satisfied, and thus no alias fence is needed.
XiaoSongXS commentedon Aug 5, 2026
alias fence is the most heavy fence, u should try avoid use it. think about what ur program actually need, and how other logic can be use to satisfy what u need.
XiaoSongXS commentedon Aug 5, 2026
glad u bring this up and actually do some SASS level analysis, ur heading the right direction on advance cuda programing
bobboli commentedon Aug 5, 2026
Thanks for your insights. The description explains the scope modifier from the perspective of cache flushing behavior. In this way, does that mean it makes no sense to use
release.sysfor a store in any case as long as the dst is local gmem, sincerelease.gpuhas fulfilled the flushing purpose?bobboli commentedon Aug 5, 2026
And similarly, if I am using regular ld from a local gmem, does that mean
acquire.gpuis sufficient, regardless whether the producer is self GPU or remote GPU?XiaoSongXS commentedon Aug 5, 2026
Yes. What really matter here is NOT the scope of consumer and producer thread, but rather the scope of where ur memory write goes to.
And the
releaseis only use when u need this "flush" behavior, if u just want local gpu l2 atomic,relaxedis what u needXiaoSongXS commentedon Aug 5, 2026
Yes, as long as u spin loop pooling from local gpu flag and data, then
.acquire.gpuis what u need. The symmetric paring of sys <-> sys is kind of overkill. sys <-> gpu is the minimal hw requirementgau-nernst commentedon Aug 5, 2026
@bobboli I see you are a DevTech engineer. Based on Xiao Song's explanation here, I believe many comms kernels in FlashInfer can be further optimized by removing certain defensive fences!
bobboli commentedon Aug 5, 2026
Unfortunately the A2A kernel in FI uses push to remote & pull from remote pattern, which can not benefit from this. But some others, such as AR, may be optimized.
XiaoSongXS commentedon Aug 5, 2026
push to remote can adopt
st.async.releasetheasyncvarionshenrylhtsang commentedon Aug 11, 2026
@XiaoSongXS dumb question: why are you not worried about the compiler (ptxas) hoisting/reordering
multimem.ld_reducebefore the relaxed flag poll? My guesses:But not sure which one is right, or if it is due to other reasons. The SASS code right now shows no reordering was done, but not sure if it is guaranteed to not reorder
XiaoSongXS commentedon Aug 11, 2026
this is a excellent question. And ur intuition is exactly correct
XiaoSongXS commentedon Aug 11, 2026
A second thought on #3118, yes we should adopt this fix (i'll port this fix in another PR), relies on the compiler to do the optimization, and avoid hacking through the mem sys just to avoid one CCTL.IVALL (little perf hurt, nearly no influence) as it cause customer to be quite confused about what should be the correct model
XiaoSongXS commentedon Aug 11, 2026
And one thing on the acquire vs relaxed, we have two concept here that need to be clearly distinguish
For (1) I think the correct approach is to use
.release+.acquire. try not hack through the compiler while loop, as the compiler while loop and bar.sync is "implicit", likely one day it break. the.acquireis a strong ensure provided by the ptx modelFor (2) use correct scope for release + acquire will ensure this
ShawnWeiChew commentedon Oct 26, 2026
Hey @XiaoSongXS, could I ask about the choice of
gpuscope specifically for the flag increment as well?My understanding of the kernel is that for some of the completed GEMM tiles, the incremented flag should go to the remote peer's L2 rather than a local L2 (since the RS warps use
gpuscope polling), so usingsysscope is more appropriate. However, I've not yet run into correctness issues from using agpuscope flag increment.Is there something else I've failed to consider when reasoning about the right scope for the flag increment?
XiaoSongXS commentedon Oct 27, 2026
this is indeed a very interesting question. the short answer is the flag update with release come with two part, (1) a atomic flag update, (2) a member fence. for the atomic flag update, using gpu scope or sys scope in reality have somewhat same hw path and behavior, so that is not the issue, for the member fence, that is the critical path and u need to make sure that part is correct.
so likely u may want to have flag update using gpu scope (as flag is on local gpu l2) and the member with sys scope. for this case u can use the st.release.sys as the sys scope flag update and gpu scope flag update are effectively doing somewhat same thing on hw.