我在CUDA中实施了Eratosthenes筛选,并且输出非常奇怪。我使用unsigned char *作为数据结构,并使用以下宏来操作位。
#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
如果您查看内核代码,如果我取消注释这些行,我将得到正确的答案,这意味着我的循环或我的检查没有任何问题!
答案 0 :(得分:1)
我建议用方法替换宏来开始。您可以使用前面带有__host__
和__device__
的方法在必要时生成cpp和cu特定版本。这将消除预处理器做出意外事情的可能性。
现在只调试导致错误输出的特定代码分支,检查每个阶段是否正确,你会发现问题。
答案 1 :(得分:1)
多个线程同时访问全局内存中的同一个字(char),因此写入的结果被破坏。
您可以使用原子操作来防止这种情况,但更好的解决方案是更改您的算法:不要让每个线程筛出2,3,4,5的倍数......让每个线程检查一个范围,如[ 0..7],[8..15],...这样每个范围的长度都是8位的倍数,不会发生碰撞。