[英]What Rules does compiler have to follow when dealing with volatile memory locations?
[英]When to use volatile with shared CUDA Memory
在什么情況下你應該在 CUDA 內核的共享內存中使用volatile
關鍵字? 我知道volatile
告訴編譯器永遠不要緩存任何值,但我的問題是關於共享數組的行為:
__shared__ float products[THREADS_PER_ACTION];
// some computation
products[threadIdx.x] = localSum;
// wait for everyone to finish their computation
__syncthreads();
// then a (basic, ugly) reduction:
if (threadIdx.x == 0) {
float globalSum = 0.0f;
for (i = 0; i < THREADS_PER_ACTION; i++)
globalSum += products[i];
}
在這種情況下,我是否需要products
具有揮發性? 每個數組條目只能由單個線程訪問,除了最后,所有內容都由線程 0 讀取。編譯器是否有可能緩存整個數組,所以我需要它是volatile
,還是只緩存元素?
謝謝!
如果您沒有將共享數組聲明為volatile
,那么編譯器可以通過將它們定位在寄存器(其范圍特定於單個線程)中來自由地優化共享內存中的位置,對於任何線程,它都可以選擇。 無論您是否僅從一個線程訪問該特定共享元素,都是如此。 因此,如果您使用共享內存作為塊的線程之間的通信工具,最好將其聲明為volatile
。 但是,這種通信模式通常還需要執行障礙來強制執行讀/寫的順序,因此請繼續閱讀下面的障礙。
顯然,如果每個線程只訪問它自己的共享內存元素,而從不訪問與另一個線程關聯的元素,那么這無關緊要,編譯器優化不會破壞任何東西。
在您的情況下,您有一段代碼,其中每個線程都在訪問它自己的共享內存元素,並且唯一的線程間訪問發生在一個很好理解的位置,您可以使用內存柵欄功能強制編譯器驅逐臨時存儲在寄存器中的任何值,返回到共享數組。 因此,您可能認為__threadfence_block()
可能有用,但就您而言, __syncthreads()
已經內置了內存防護功能。 因此,您的__syncthreads()
調用足以強制線程同步以及強制將共享內存中的任何寄存器緩存值驅逐回共享內存。
順便說一句,如果代碼末尾的縮減涉及性能問題,您可以考慮使用並行縮減方法來加快速度。
簡單地說,對於其他會來這里的人:
調用__syncthreads()
將共享內存聲明為volatile
更強。 __syncthreads()
導致來自給定工作組的所有線程一起停止在 1 個公共點並同步內存。
volatile
OTOH 通過阻止編譯器進行任何緩存優化(因此可能會帶來成本),在線程之間保持給定的內存緩沖區一致,但每個線程都可以按照自己的節奏自由運行,這使得編譯器/硬件能夠執行各種調度優化。
(但請注意,如果寫入由超過 1 個處理器指令組成,則 volatile不能保證數據完整性)
總而言之,當您只需要線程之間的內存一致性,而不是在 1 點一起停止時, volatile
通常提供比__syncthreads()
更好的性能。 但是,您的數量可能會有所不同,具體取決於特定的算法甚至輸入數據,因此如果您需要壓縮最后一點性能,請測試這兩種方法。
此外,如果工作組中的活動線程的數量小於 SIMD 寬度(warp 大小),則可以使用volatile
代替__synchthreads()
,因為同一 warp 中的所有線程都同步執行指令。 例如,請參見對並行縮減算法的最后一個包裝展開優化(幻燈片 21-23),該算法首先使用__synchthreads()
,然后僅在活動線程數小於 warp 大小時才依賴volatile
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.