2017-03-03 61 views
1

我想寫一個內核來獲取字符串的字符頻率。打開CL內核 - 每個工作項目覆蓋全局內存?

首先,這裏是我的代碼有內核現在:

_kernel void readParallel(__global char * indata, __global int * outdata) 
{ 
     int startId = get_global_id(0) * 8; 
     int maxId = startId + 7; 

     for (int i = startId; i < maxId; i++) 
     { 
      ++outdata[indata[i]]; 
     } 
} 

變量inData保存在全局存儲器的字符串,outdata是256個int值在全局存儲器陣列。每個工作項都從字符串中讀取8個符號,並應增加數組中適當的ASCII碼。代碼編譯並執行,但outdata包含的次數少於inData中的字符數。我認爲問題在於工作項目會覆蓋全局內存。如果你能給我一些提示來解決這個問題,那將會很好。

順便說一下。我是OpenCL的新手;-),是的,我在其他問題上尋找解決方案。

回答

1

您正在使用全局存儲器的效果不是原子C++-oriented description of what those areanother description by the Intel TBB folks)。會發生什麼情況,按時間順序,是:

一些工作組 「線程」 負載outData[123]到某個寄存器r1

...大量的工作,閱讀和寫作,恰巧,包括 outData[123] ...

同一工作組「線程」增量r1

...很多的工作,閱讀和寫作,恰巧,包括 outData[123] ...

同一工作組「線程」寫入r1outData[123]

所以,寫入outData[123]值「扔掉」在讀取和寫入之間的時間段更新(I」 m忽略了平行寫入腐敗的可能性,而不是其中的一個勝出)。

你需要做的是兩種:

  • 使用原子操作 - 最少修改你的代碼,但效率非常低,因爲它系列化你的工作在很大程度上,或
  • 使用特定於工作項目,特定於經紗和/或特定工作組的部分結果需要更少/更便宜的同步,並在完成大量工作後最終將其組合。

在一個不相關的注意事項,並作爲@huseyintugrulbuyukisik正確地指出,您的代碼使用簽署char值索引數組。爲了解決這個問題,執行下列操作之一:

  • 重新解釋那些char的作爲unsigned chars數組索引(和讀取陣列時重新解釋背面
  • 向上轉型炭值到更大的整數類型,並添加128爲了得到一個偏移量outArray
  • 定義你的內核只支持ASCII字符(不高於127),在這種情況下,你可以忽略這個問題(雖然這將是一個潛在的不速之客,如果你得到無效的輸入。
  • 如果你只關心的頻率(但在輸入中也可以有非打印字符),您可以在計算字符之前執行運行時檢查。
+1

此外char也可以是負數,並且下溢輸入數組c> 127。無符號字符正在爲我工​​作 –

+0

使用無符號字符和原子操作爲我做了。謝謝。 –

+0

@j_ice:你表示感謝你通過提出一個好答案的答案;如果它解決了您的問題 - 您將其標記爲已接受。如果不是這樣,那麼在評論中,其他人可以解釋什麼是缺失/不正確。 – einpoklum