2010-12-20 36 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