如何在CUDA中安全地将全局内存中的数据加载到共享内存中?

时间:2015-06-14 10:59:03

标签: c++ cuda

我的内核:

__global__ void myKernel(float * devData, float * devVec, float * devStrFac,
int Natom, int vecNo) {

extern __shared__ float sdata[];
int idx = blockIdx.x * blockDim.x + threadIdx.x;

float qx=devVec[3*idx];
float qy=devVec[3*idx+1];
float qz=devVec[3*idx+2];
__syncthreads();//sync_1

float c=0.0,s=0.0;
for (int iatom=0; iatom<Natom; iatom += blockDim.x) {
    float rtx = devData[3*(iatom + threadIdx.x)];//tag_0
    float rty = devData[3*(iatom + threadIdx.x)+1];
    float rtz = devData[3*(iatom + threadIdx.x)+2];
    __syncthreads();//sync_2
    sdata[3*threadIdx.x] = rtx;//tag_1
    sdata[3*threadIdx.x + 1] = rty;
    sdata[3*threadIdx.x + 2] = rtz;
    __syncthreads();//sync_3

    int end_offset=  min(blockDim.x, Natom - iatom);

    for (int cur_offset=0; cur_offset<end_offset; cur_offset++) {
        float rx = sdata[3*cur_offset];
        float ry = sdata[3*cur_offset + 1];
        float rz = sdata[3*cur_offset + 2];
        //sync_4  
        float theta = rx*qx + ry*qy + rz*qz;

        theta = theta - lrint  (theta);
        theta = theta * 2 * 3.1415926;//reduce theta to [-pi,pi]

        float ct,st;
        sincosf(theta,&st,&ct);

        c += ct;
        s += st;
    }

}

devStrFac[idx] += c*c + s*s;
}

为什么需要“__syncthreads()”标记为sync_2?没有sync_2,sdata []得到错误的数字,我得到错误的结果。行“tag_1”使用行“tag_0”的结果,所以在我看来sync_2是不需要的。我哪里错了?如果由于无序指令执行,我应该将__syncthreads()放在行“sync_4”中?

1 个答案:

答案 0 :(得分:2)

考虑线程块的一个warp完成第一次迭代并开始下一次迭代,而其他warp仍然在第一次迭代时工作。如果您在标签NullPointerException处没有__syncthreads,那么您将最终将此扭曲写入共享内存,而其他人正在从该共享内存中读取,这是竞争条件。

为了清楚起见,您可以将此sync2标签__syncthreads()移至外圈的末尾。

"cuda-memcheck --tool racecheck"应该告诉你问题出在哪里。