3d CUDALink:在z维中启动多个块

3d CUDALink:在z维中启动多个块,3d,cuda,wolfram-mathematica,stencils,3d,Cuda,Wolfram Mathematica,Stencils,我目前正在我的GPU(GTX560Ti)上运行一个简单的3D模具转换,使用Mathematica提供的CUDALink包装器。块维度现在对我来说并不重要,因为我没有使用任何共享内存或寻找优化(现在) 因此,我可以为blockDim.x和blockDim.y设置任何合理的数字。不管我设置了什么维度,包装器都会启动适当数量的块,没有问题。但是,在z维中,仅启动单个块。因此blockDim.z限制了我在该方向上可以计算的点数总数 为什么z方向上只有一个块?我如何解决这个问题? 作为参考,以下是我使用的

我目前正在我的GPU(GTX560Ti)上运行一个简单的3D模具转换,使用Mathematica提供的
CUDALink
包装器。块维度现在对我来说并不重要,因为我没有使用任何共享内存或寻找优化(现在)

因此,我可以为
blockDim.x
blockDim.y
设置任何合理的数字。不管我设置了什么维度,包装器都会启动适当数量的块,没有问题。但是,在z维中,仅启动单个块。因此
blockDim.z
限制了我在该方向上可以计算的点数总数

为什么z方向上只有一个块?我如何解决这个问题?

作为参考,以下是我使用的内核:

__global__ void conv(Real_t in[48][48][48], Real_t out[48][48][48], mint stencil[13][13][13], mint length, mint rad) {
    int x = threadIdx.x + blockIdx.x*blockDim.x;
    int y = threadIdx.y + blockIdx.y*blockDim.y;
    int z = threadIdx.z + blockIdx.z*blockDim.z;
    while (x<length||y<length||z<length) {
        out[x][y][z] = 0;
        for (int ix = -rad; ix <= rad; ix++) {
        for (int iy = -rad; iy <= rad; iy++) {
        for (int iz = -rad; iz <= rad; iz++) {
            if ( (fminf(x,fminf(y,z))-rad >= 0)
                && (fmaxf(x,fmaxf(y,z))+rad < length) )
                {out[x][y][z] += stencil[ix+rad][iy+rad][iz+rad]*in[ix+x][iy+y][iz+z];}
        }   }   }
        if (x<length) {
            x+= blockDim.x * gridDim.x;
        } else if (y<length) {
            y+= blockDim.y * gridDim.y;
        } else if (z<length) {
            z+= blockDim.z * gridDim.z;
        }
    }
}
为了说明我的问题,这里是我输出的一部分(显然我不能发布图像):


这是由
blockDim.z=10
生成的。零和分数是有用的值,但它们只是我初始化
out
数组时使用的值。仅计算前10列,对应于z方向上的单个块。(对于
1
64
(费米GPU的上限)之间的
blockDim.z
的任何值,这种行为都是可复制的。

好吧,我猜这种行为只是CUDAResources中的一个bug,而不是实际的编程问题。(尽管如此,只有一个块。我现在有一个解决方法。)

我使用
CUDAResourcesUninstall[]
删除了CUDAResources,重新启动了Mathematica,使用
CUDAResourcesInstall[“/path/to/paclet/file”,Update->True]重新安装了CUDAResources,并再次重新启动了Mathematica

然后,我将内核更改为以下代码:

Needs["CUDALink`"];
conv = CUDAFunctionLoad[code (*the kernel above, stored as a string*), "conv", {{_Real, _, "Input"}, {_Real, _, "Output"}, {_Integer , _, "Input"}, _Integer, _Integer}, {4, 4, 10}, "TargetPrecision" -> "Single", "XCompilerInstallation" -> "/usr/local/gcc44/bin/", "CleanIntermediate" -> False];
output = ConstantArray[1, {length, length, length}];
result =  conv[input, output, stencil, length, rad];
__global__ void conv(Real_t in[48][48][48], Real_t out[48][48][48], \
mint stencil[13][13][13], mint length, mint rad) {
    int x = threadIdx.x + blockIdx.x*blockDim.x;
    int y = threadIdx.y + blockIdx.y*blockDim.y;
    int z = threadIdx.z + blockIdx.z*blockDim.z;
    while (z<length) {
        out[x][y][z] = 0;
        for (int ix = -rad; ix <= rad; ix++) {
        for (int iy = -rad; iy <= rad; iy++) {
        for (int iz = -rad; iz <= rad; iz++) {
            if ( (fminf(x,fminf(y,z))-rad >= 0)
                && (fmaxf(x,fmaxf(y,z))+rad < length) )
                {out[x][y][z] += stencil[ix+rad][iy+rad][iz+rad]*in[ix+x][iy+y][iz+z];}
        }   }   }
        if (z<length) {
            z+= blockDim.z * gridDim.z;
        }
    }
}
\uuuuu global\uuuuuuu void conv(实输入[48][48][48],实输出[48][48]\
造币厂模板[13][13][13],造币厂长度,造币厂弧度){
int x=threadIdx.x+blockIdx.x*blockDim.x;
int y=线程IDX.y+块IDX.y*块DIM.y;
intz=threadIdx.z+blockIdx.z*blockDim.z;

虽然(CUDALink中的zauto编译是。除了GTX 560 Ti,您的系统中还有其他GPU吗?cc 1.x设备是。没有。
$lspci
仅列出560Ti,板载图形被禁用。
CUDAInformation[]
也非常清楚:
最大网格尺寸->{655356553565535}
。将
gridDim.z
写入
out[x][y][z]
但是,用
1
填充数组。因此包装器认为一个块就足够了。有可能覆盖它吗?我不想用C重写我的程序。通过添加一个指定所需网格维度的线程来修改
conv
调用。类似于:
result=conv[input,output,stencil,length,rad,{48,48,48}];
OK。这会导致以下错误:
CudFunction::invgrd:“使用无效的网格维度{48,48,48}调用CudLink。网格维度必须为正,并且必须是整数或整数列表。”
__global__ void conv(Real_t in[48][48][48], Real_t out[48][48][48], \
mint stencil[13][13][13], mint length, mint rad) {
    int x = threadIdx.x + blockIdx.x*blockDim.x;
    int y = threadIdx.y + blockIdx.y*blockDim.y;
    int z = threadIdx.z + blockIdx.z*blockDim.z;
    while (z<length) {
        out[x][y][z] = 0;
        for (int ix = -rad; ix <= rad; ix++) {
        for (int iy = -rad; iy <= rad; iy++) {
        for (int iz = -rad; iz <= rad; iz++) {
            if ( (fminf(x,fminf(y,z))-rad >= 0)
                && (fmaxf(x,fmaxf(y,z))+rad < length) )
                {out[x][y][z] += stencil[ix+rad][iy+rad][iz+rad]*in[ix+x][iy+y][iz+z];}
        }   }   }
        if (z<length) {
            z+= blockDim.z * gridDim.z;
        }
    }
}