2010-12-20 79 views
3

上午在CUDA中實現了Eratosthenes的篩選器,並且我有一個非常奇怪的輸出。我使用無符號字符*作爲數據結構並使用以下宏來操作這些位。CUDA中的位陣列

#define ISBITSET(x,i) ((x[i>>3] & (1<<(i&7)))!=0) 
#define SETBIT(x,i) x[i>>3]|=(1<<(i&7)); 
#define CLEARBIT(x,i) x[i>>3]&=(1<<(i&7))^0xFF; 

我定了位,以表示它是一個素數,否則就= 0 這裏是我打電話給我的內核

size_t p=3; 
size_t primeTill = 30; 

while(p*p<=primeTill) 
{ 
    if(ISBITSET(h_a, p) == 1){ 
     int dimA = 30; 
     int numBlocks = 1; 
     int numThreadsPerBlock = dimA; 
     dim3 dimGrid(numBlocks); 
     dim3 dimBlock(numThreadsPerBlock); 
     cudaMemcpy(d_a, h_a, memSize, cudaMemcpyHostToDevice);   
     cudaThreadSynchronize();  
     reverseArrayBlock<<< dimGrid, dimBlock >>>(d_a, primeTill, p); 
     cudaThreadSynchronize();  
     cudaMemcpy(h_a, d_a, memSize, cudaMemcpyDeviceToHost); 
     cudaThreadSynchronize();  
     printf("This is after removing multiples of %d\n", p); 
     //Loop 
     for(size_t i = 0; i < primeTill +1; i++) 
     { 
      printf("Bit %d is %d\n", i, ISBITSET(h_a, i)); 
     } 
    }   
    p++; 
} 

這裏是我的內核

__global__ void reverseArrayBlock(unsigned char *d_out, int size, size_t p) 
{ 
int id = blockIdx.x*blockDim.x + threadIdx.x; 
int r = id*p; 
if(id >= p && r <= size) 
{ 
    while(ISBITSET(d_out, r) == 1){ 
     CLEARBIT(d_out, r); 
    } 

    // if(r == 9) 
    // { 
    // /* code */ 
    // CLEARBIT(d_out, 9); 
    // } 

} 

} 輸出應該是: 2,3,5,7,11,13,17,19,23,29 而我的輸出是: 2,3,5,9,7,11,13,17,19,23,29

如果你看看內核代碼,如果我取消註釋那些行,我會得到正確的答案,這意味着我的循環或檢查沒有任何問題!

回答

1

多個線程同時訪問全局內存中的相同字(char),因此寫入的結果被破壞。

你可以使用原子操作來防止這種情況,但更好的解決方案是改變你的算法:而不是讓每個線程都篩選2,3,4,5,...的倍數,讓每個線程檢查一個範圍[0..7],[8..15] ......以便每個範圍的長度是8位的倍數,並且不會發生衝突。

+0

此外,我會使用更大的單詞,如短褲或整數來存儲位數組,因爲「(如果讀取和寫入半換行中的線程可以合併爲32,64或128bytes,則訪問全局內存的速度最快)」 。 – 2011-03-17 14:31:59

1

我會建議用開始的方法替換宏。您可以使用前面有__host____device__的方法在必要時生成cpp和cu特定版本。這將消除預處理器做出意想不到的事情的可能性。

現在只需調試導致錯誤輸出的特定代碼分支,依次檢查每個階段是否正確,您就會發現問題。

+0

我會檢查一下,但經過一番思考,我認爲問題是由於線程間的競爭條件試圖改變同一個字符的值而發生的,我會回到我的發現。謝謝 – 2010-12-22 19:24:33