[英]Understanding the method for OpenCL reduction on float
通過此鏈接 ,我嘗試了解內核代碼的操作(此內核代碼有2個版本,一個版本具有volatile local float *source
,另一個版本具有volatile global float *source
,即local
和global
版本)。 下面我以local
版本:
float sum=0;
void atomic_add_local(volatile local float *source, const float operand) {
union {
unsigned int intVal;
float floatVal;
} newVal;
union {
unsigned int intVal;
float floatVal;
} prevVal;
do {
prevVal.floatVal = *source;
newVal.floatVal = prevVal.floatVal + operand;
} while (atomic_cmpxchg((volatile local unsigned int *)source, prevVal.intVal, newVal.intVal) != prevVal.intVal);
}
如果我理解得很好,由於限定符“ volatile
”,每個工作項都共享對source
變量的訪問,不是嗎?
之后,如果我使用一個工作項,則代碼會將operand
數值添加到newVal.floatVal
變量中。 然后,在執行此操作之后,我調用atomic_cmpxchg
函數,該函數檢查先前的賦值( preVal.floatVal = *source;
和newVal.floatVal = prevVal.floatVal + operand;
)是否已經完成,即通過將存儲在地址source
處的值與preVal.intVal
。
在此原子操作期間(根據定義,它不是不可中斷的),因為source
存儲的值不同於prevVal.intVal
,所以source
存儲的新值是newVal.intVal
,它實際上是一個浮點數(因為它被編碼為4個字節,例如整數)。
我們可以說每個工作項都具有對位於source address
處的值的互斥訪問(我是指鎖定訪問)。
但是對於each work-item
線程, while loop
是否只有一個迭代?
我認為會有一次迭代,因為比較“ *source== prevVal.int ? newVal.intVal : newVal.intVal
”總是將newVal.intVal
值分配給存儲在source address
值,不是嗎?
歡迎任何幫助,因為我還不了解此內核代碼的所有技巧。
更新1:
抱歉,我幾乎了解所有這些實用程序,尤其是在while loop
:
第一種情況:對於給定的單線程,在調用atomic_cmpxchg之前,如果prevVal.floatVal
仍等於*source
,那么atomic_cmpxchg
將更改source
指針中包含的值並返回old pointer
包含的值,該值等於prevVal.intVal
,因此我們從while loop
中斷。
第二種情況:如果在prevVal.floatVal = *source;
指令和對atomic_cmpxchg
的調用,值*source
已更改(由另一個線程??),然后atomic_cmpxchg返回的old
值不再等於prevVal.floatVal
,因此while loop
的條件為true,我們一直待在此循環中,直到以前的條件不再檢查。
我的解釋是正確的嗎?
謝謝
如果我理解得很好,由於限定符“
volatile
”,每個工作項都共享對源變量的訪問,不是嗎?
volatile
是C語言的關鍵字,可防止編譯器優化對內存中特定位置的訪問(換句話說,在該內存位置的每次讀取/寫入時強制進行加載/存儲)。 它對基礎存儲的所有權沒有影響。 在這里,它用於強制編譯器在每次循環迭代時從內存中重新讀取source
(否則編譯器將被允許將負載移到循環外,這會破壞算法)。
do {
prevVal.floatVal = *source; // Force read, prevent hoisting outside loop.
newVal.floatVal = prevVal.floatVal + operand;
} while(atomic_cmpxchg((volatile local unsigned int *)source, prevVal.intVal, newVal.intVal) != prevVal.intVal)
刪除限定符(為簡單起見)並重命名參數后, atomic_cmpxchg
的簽名如下:
int atomic_cmpxchg(int *ptr, int expected, int new)
它的作用是:
atomically {
int old = *ptr;
if (old == expected) {
*ptr = new;
}
return old;
}
總而言之,每個線程分別執行以下操作:
*source
當前值從內存加載到preVal.floatVal
newVal.floatVal
計算*source
的newVal.floatVal
atomic_cmpxchg == newVal.intVal
的結果表示比較交換成功,則中斷。 否則,交換不會發生,請轉到1,然后重試。 上面的循環最終終止,因為最終 ,每個線程都成功完成了atomic_cmpxchg
。
我們可以說每個工作項都具有對位於源地址的值的互斥訪問(我是指鎖定訪問)。
互斥鎖是鎖,而這是一種無鎖算法。 OpenCL可以使用自旋鎖(也可以通過原子實現)來模擬互斥鎖,但這不是一個。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.