用atomics产生错误答案的CUDA内核

时间:2012-07-30 03:30:48

标签: cuda gpu gpgpu

我正在尝试理解CUDA编程模型及其功能。作为练习,我试图通过函数调用将以下循环结构转换为高效的CUDA内核

//function call
bool gmul(int rowsize,int *Ai,int *Bj,int colsize)
{
    for(int i = 0;i < rowsize;i++)
    {
        for(int j = 0;j < colsize;j++)
        {
            if(Ai[i] == Bj[j])
            {
                return true;
            }
        }
    }
    return false;
}

//Some for loop in main function is as follows

for(i = 0;i < q ;i++)
    {
        cbeg = Bjc[i];
        cend = Bjc[i+1];        
        for(j = 0;j < m;j++)
        {
            beg = Aptr[j];
            end = Aptr[j+1];            
            if(gmul(end - beg,Acol + beg,Bir + cbeg,cend - cbeg))
            {   
                temp++;             
            }                       
        }
        Cjc1[i+1] = temp ;              
    } 

我的函数调用内核如下。

    __device__ bool mult(int colsize,int rowsize,int *Aj,int *Bi,int *val)
    {       
        for(int j = 0; j < rowsize;j++)
        {           
           for(int k = 0;k < colsize;k++)
            {   
              if(Aj[j] == Bi[k])
               {    
                return true;
                }                               
            }           
        }
            return false;       
    }


__global__ void kernel(int *Aptr,int *Aj,int *Bptr,int *Bi,int rows,int cols,int *count,int *Cjc)
    {
        int tid = threadIdx.x + blockIdx.x * blockDim.x;
        int i;
        if(tid < cols)
        {
            int beg = Bptr[tid];
            int end = Bptr[tid+1];
            for(i = 0;i < rows;i++)
            {
                int cbeg = Aptr[i];
                int cend = Aptr[i+1];
                if(mult(end - beg,cend - cbeg,Aj+cbeg,Bi+beg,count))
                {
                    //atomicAdd(count,1);
                                    //Changes made are in next line
                              atomicAdd(Cjc+tid+1,1);           
                }
            }
            //atomicAdd(Cjc+tid+1,*count);              
        }               
    }

我想要的是每当__device__ mult返回true值时,我的全局内核函数应该递增该特定线程的计数器,并且一旦for循环(在内核函数中)结束,它应该将值存储到Cjc数组中,并将count移交给其他线程以进行递增操作。但是,我没有得到预期的价值。所有线程完成执行后,我在Cjc数组中得到的所有内容都是最终计数。

我正在使用带有CC 2.0的GTX 480

关于为什么我对此CUDA内核得到错误答案或优化的任何建议/提示将不胜感激。 提前致谢。 的 * ** * **** 解决 * ** * ** * ****

现在,我面临的一个问题是,每当我达到4000以上时,我就会将数组中所有元素的值都设为0。以下是我启动内核的方法。

    int numBlocks,numThreads;

        if(q % 32 == 0)
        {
            numBlocks = q/32;
            numThreads = 32;
        }
        else
        {
            numBlocks = (q+31)/32;
            numThreads = 32;
        }
findkernel<<<numBlocks,numThreads>>>(devAptr,devAcol,devBjc,devBir,m,q,d_Cjc);          

我想知道我正在越过块或网格尺寸的任何限制但是对于CC 2.0,我认为我发布足够的块和线程是不对的。我想知道为什么所有的答案都是0

1 个答案:

答案 0 :(得分:1)

您编写了并行线程,无需同步即可读写count。线程以不可预测的顺序并发运行,因此线程以不可预测的顺序原子地修改count和读取count。表达式*count将根据确切的执行顺序产生不同的结果。

  

一旦for循环(在内核函数中)结束,它应该将值存储到Cjc数组中,并将count移交给其他线程以进行递增操作。

没有同步,因此没有线程等待另一个线程完成循环。而不是让所有线程共享count的相同存储,为什么不给每个线程一个不同的存储空间?然后线程不会影响彼此的结果。您可以在此之后运行扫描内核以组合结果。