mirror of
https://github.com/deepseek-ai/DeepEP.git
synced 2026-11-05 00:47:32 +00:00
[GH-ISSUE #136] L1::no_allocate is not safe to load volatile data #118
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
deepseek-ai/DeepEP#118
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @Yinghan-Li on GitHub (Apr 27, 2025).
Original GitHub issue: https://github.com/deepseek-ai/DeepEP/issues/136
for the ptx instruction
ld.global.nc.L1::no_allocate.L2::256Byou mentioned, on devices which global memory is cached in L1 by default, such as Volta to Blackwell (sm70+), it's equivalent told.global.L1::no_allocate.L2::256B.L1::no_allocatemeans the memory instruction doesn't allocate L1 cache line or check 'hit on miss' (the address is on the same cache line with a previous cache missed memory request), so access the data in a stale L1 cache line will not fetch the cache line from L2 or DRAM, and can not get the updated data from other SM.@LyricZhao commented on GitHub (Apr 27, 2025):
Maybe not exactly? From SASS level, it is. But for NVCC,
.ncseems giving more opportunities to optimize, e.g. IIRC, normal loads can not do automatic NVCC unrolling.I am not sure about the hardware impl, but the behavior is tested to be correct. See README for how we found this.
Correct me if I am wrong :)
@Yinghan-Li commented on GitHub (Apr 28, 2025):
yes, for sm70+ ISA, SASS of
ld.global.nc.L1::no_allocateandld.global.L1::no_allocateareLDG.E.NA.[...].CONSTANTandLDG.E.NA[...], they are the same for memory coherence (cross SMs coherence is not guaranteed for both), butncmeans the memory is read only and the address is not an alias of other pointers, so the compiler will reuse the data via registers and prune redundant memory instructions, and performance may be better withnc.whileandforloop can be unrolled or not usually depend on the loop stop condition and resource limitation (such as registers, barriers), if the loop stop condition can be evaluated at compile time and resource is enough, the loop can be unrolled, evenasm volatilesegment orld.volatile.globalorld.global.cginstructions inside the loop.memory coherence, for example the 'producer-consumer' case, producer warp on SM0 store data to a buffer in global memory and consumer warp on SM1 load the data from buffer,
ld.global.nc.L1::no_allocateis not safe. if the buffer's cache line was accessed byLDGinstructions exceptLDG.NAon SM1 before the producer warp's store instruction, the L1 cache line was already allocated on SM1.LDG.NAmeans do not allocate new L1 cache line and check 'hit on miss', but for L1 hit requests, it returns data from L1 cache. so the consumer warp on SM1 load data in buffer byLDG.NAorLDG.NA.CONSTANTmay get a stale data,ld.global.cg (LDG.STRONG.GPU)should be used in such case.further more, Ampere gpus with partitioned crossbar (L2 cache is also partitioned), such as A100, two L2 partitions are coherent. DRAM split to 8KB pages and each page associate with only 1 L2 partition. SMs are also split to 2 groups and each group connect 1 L2 partition directly, so for each SM, there are 1 near L2 partition (low latency) and 1 far L2 partition (cross L2 fabric, long latency).
LDG.STRONG.GPUallocate L2 cache line only in the DRAM page associated L2 partition,LDG.NAallocate cache line in both L2 partitions. so for the size of hot read-only data is not more than half of L2 size,LDGorLDG.NAmay be better because all SMs can access data from near-L2-partition. ifL2_size/2 < readonly_hot_data_size,LDG.STRONG.GPUmay be better because there's no redundant L2 cache line and L2 hit rate can be better. for L2 cache read-after-write intensive case,LDG.STRONG.GPUmay be better because of the additional L2 cache line synchronization cost ofLDG.NA.Hopper GPU's L2 is also 2 partitoned, but there's a
L2 cache request coalescer (LRC), L2 cache latency and bandwidth for all SMs are almost the same,LDG.NAandLDG.STRONG.GPUare usually the same except the default L2 cache line evict priority. for a prior STG (all STG except STG.NA) accessed 128B line,LDG.NAon the same SM access data in the 128B line will also allocate 32B L1 cache line, even the 'NA' means L1 no allocate.@LyricZhao
@LyricZhao commented on GitHub (Apr 28, 2025):
Got it, and thanks very much for your detailed explanation! I will fix the related code later (towards semantic correctness).