CUDA中的3D索引访问非线性扩散

时间:2013-03-02 15:11:43

标签: 3d cuda

我正在编写我的第一个用于2D / 3D非线性扩散的CUDA代码。 2D案例工作正常,但我正在努力与3D。基本上我在有限差分计算的阶段得到零,并且令人惊讶的是'deltaN'(请参见下面的代码)给出了正确的答案,但其他的却没有用(零回答)。我正在尝试处理256x256x256音量。有什么建议吗?谢谢!

 #define BLKXSIZE 8
 #define BLKYSIZE 8
 #define BLKZSIZE 8
 #define idivup(a, b) ( ((a)%(b) != 0) ? (a)/(b)+1 : (a)/(b) )

void AnisotropDiff_GPU(double* A, double* B, int N, int M, int Z, double sigma, int iter, double tau, int type)
{ 
// Nonlinear Diffusion in 3D 
double *Ad;     

dim3 dimBlock(BLKXSIZE, BLKYSIZE, BLKZSIZE);           
dim3 dimGrid(idivup(N,BLKXSIZE), idivup(M,BLKYSIZE), idivup(Z,BLKYSIZE));    

cudaMalloc((void**)&Ad,N*M*Z*sizeof(double));  
cudaMemcpy(Ad,A,N*M*Z*sizeof(double),cudaMemcpyHostToDevice);  

int n = 1;
while (n <= iter) {    
anis_diff3D<<<dimGrid,dimBlock>>>(Ad, N, M, Z, sigma, iter, tau, type);  
n++;}
cudaMemcpy(B,Ad,N*M*Z*sizeof(double),cudaMemcpyDeviceToHost);
cudaFree(Ad);
}

这是计算有限差分的部分

 __global__ void anis_diff3D(double* A, int N, int M, int Z, double sigma, int iter, double tau, int type)
{

 int xIndex = blockDim.x * blockIdx.x + threadIdx.x;
 int yIndex = blockDim.y * blockIdx.y + threadIdx.y;
 int zIndex = blockDim.z * blockIdx.z + threadIdx.z;

 if ( (xIndex < N) && (yIndex < M) && (zIndex < Z) )
 {
    int index_out = xIndex + M*yIndex + N*M*zIndex;

    double deltaN=0, deltaS=0, deltaW=0, deltaE=0, deltaU=0, deltaD=0;
    double cN, cS, cW, cE, cU, cD;

    int indexN = (xIndex-1) + M*yIndex + N*M*zIndex;
    int indexS = (xIndex+1) + M*yIndex + N*M*zIndex;
    int indexW = xIndex + M*(yIndex-1) + N*M*zIndex;
    int indexE = xIndex + M*(yIndex+1) + N*M*zIndex;
    int indexU = xIndex + M*yIndex + N*M*(zIndex-1);
    int indexD = xIndex + M*yIndex + N*M*(zIndex+1);


    if (xIndex>1)
        deltaN = A[indexN]-A[index_out];
    if (xIndex<N)
        deltaS = A[indexS]-A[index_out];    
    if (yIndex>1)
        deltaW = A[indexW]-A[index_out];    
    if (yIndex<M)
        deltaE = A[indexE]-A[index_out];
    if (zIndex>1)
        deltaU = A[indexU]-A[index_out];    
    if (zIndex<Z)
        deltaD = A[indexD]-A[index_out];

   A[index_out] = deltaN ; // works for deltaN but not for deltaS, deltaW... . 

 }

非常感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

对于您尝试在内核中计算的某些值,您有越界索引。

如果使用上一个内核行编译代码,请执行以下操作:

A[index_out] = deltaS ;

然后使用cuda-memcheck运行它,cuda-memcheck将报告越界访问:

========= Invalid __global__ read of size 8
=========     at 0x000000b0 in anis_diff3D(double*, int, int, int, double, int, double, int)
=========     by thread (7,7,7) in block (31,31,31)
=========     Address 0x408100000 is out of bounds

那是怎么回事?我们来看看你的指数计算:

int indexS = (xIndex+1) + M*yIndex + N*M*zIndex;

对于网格中的最后一个线程(块(31,31,31)中的线程(7,7,7)),此索引计算索引超出内存数组的末尾{ {1}}在这一行中:

A

您必须处理这些边界条件才能使事情正常运行。

虽然我们已经做到了,如果你已经完成error checking,你的内核就会抛出一个错误。请注意,根据您选择存储在内核末尾的值,编译器可能会优化其他计算,从而导致内核看起来运行正常(例如,如果存储deltaN而不是deltaS)。以下是包含错误检查的代码示例:

    deltaS = A[indexS]-A[index_out];

编辑我编辑了上面的代码,将索引计算限制在定义数组的边界。这应该可以防止越界访问。从算法的角度来看,我不知道是否合情合理。