我正在编写我的第一个用于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... .
}
非常感谢您的帮助!
答案 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];
编辑我编辑了上面的代码,将索引计算限制在定义数组的边界。这应该可以防止越界访问。从算法的角度来看,我不知道是否合情合理。