[英]What is the best way to launch a GPU kernel to do calculation on a 3D data set?
我正在使用CUDA对可能较大的3D数据集进行计算。 我认为最好先看到一个简短的代码片段:
void launch_kernel(/*arguments . . . */){
int bx = xend-xstart, by = yend-ystart, bz = zend-zstart;
dim3 blocks(/*dimensions*/);
dim3 threads(/*dimensions*/);
kernel<<blocks, threads>>();
}
我有一组3D单元,我需要启动一个内核来计算每个单元。 问题在于输入大小可能超过GPU的能力,尤其是线程。 所以这样的代码:
void launch_kernel(/*arguments . . . */){
int bx = xend-xstart, by = yend-ystart, bz = zend-zstart;
dim3 blocks(bx,by,1);
dim3 threads(bz);
kernel<<blocks, threads>>();
}
...效果不好。 因为尺寸为1000x1000x1000怎么办? -我无法在每个块中启动1000个线程。 甚至更好,如果尺寸为5x5x1000? -现在我几乎没有启动任何块,但是需要以硬件的5x5x512 b / c启动内核,并且每个线程将执行2次计算。 我也不能仅仅将所有维度混合在一起,将一些z放入块中,而将某些z放入线程b / c中,我需要能够识别内核中的维度。 目前:
__global__ void kernel(/*arguments*/){
int x = xstart + blockIdx.x;
int y = ystart + blockIdx.y;
int z = zstart + threadIdx.x;
if(x < xend && y < yend && z < zend){
//calculate
}
}
我需要一种可靠,有效的方法来找出这些变量:
块x尺寸,块y尺寸,线程x(以及y?和z?),一旦我通过blockIdx和threadIdx进入内核时的x,y,z,并且,如果输入超出硬件,则a的数量我在内核计算中的for循环中为每个维度选择“步骤”。
如有疑问,请询问。 这是一个棘手的问题,这一直困扰着我(特别是因为我启动的块/线程数量是性能的主要组成部分)。 对于不同的数据集,此代码的决策需要自动化,但我不确定如何有效地做到这一点。 先感谢您。
我认为您在很大程度上使这里的事情复杂化。 基本问题似乎是您需要在1000 x 1000 x 1000计算域上运行内核。 因此,您需要1000000000个线程,这完全在所有CUDA兼容硬件的能力之内。 因此,只需使用至少具有执行计算所需线程数的标准2D CUDA执行网格(如果您不知道该怎么做,请在注释中添加注释,然后将其添加到答案中),然后在内核调用中使用一点设置功能是这样的:
__device__ dim3 thread3d(const int dimx, const int dimxy)
{
// The dimensions of the logical computational domain are (dimx,dimy,dimz)
// and dimxy = dimx * dimy
int tidx = threadIdx.x + blockIdx.x * blockDim.x;
int tidy = threadIdx.y + blockIdx.y * blockDim.y;
int tidxy = tidx + gridDim.x * tidy;
dim3 id3d;
id3d.z = tidxy / dimxy;
id3d.y = tidxy / (id3d.z * dimxy);
id3d.x = tidxy - (id3d.z * dimxy - id3d.y * dimx);
return id3d;
}
[免责声明:在浏览器中编写,请勿编译,请勿运行,未经测试。 使用风险自负]。
此函数将从CUDA 2D执行网格返回3D域(dimx,dimy,dimz)中的“逻辑”线程坐标。 在内核开始时调用它,如下所示:
__global__ void kernel(arglist, const int dimx, const int dimxy)
{
dim3 tid = thread3d(dimx, dimxy);
// tid.{xyx} now contain unique 3D coordinates on the (dimx,dimy,dimz) domain
.....
}
请注意,建立该网格有很多整数计算开销,因此您可能要考虑为什么真正需要3D网格。 您会感到惊讶的是,实际上并不需要很多次,并且可以避免很多设置开销。
我将首先使用cudaGetDeviceProperties()
查找GPU的计算能力,以便您确切知道GPU允许每个块有多少个线程(如果您的程序需要通用化以便可以在任何支持CUDA的设备上运行)。
然后,使用该数字,我将在测试输入尺寸的if
语句中进行大量嵌套。 如果所有尺寸都足够小,则可以(不大可能)有一个(bx,by,bz)线程块。 如果这不起作用,则找到可以放入一个块并根据该块进行分区的最大尺寸(或两个尺寸)。 如果这不起作用,则必须对最小尺寸进行分区,以使其一部分适合一个块,例如(MAX_NUMBER_THREADS_PER_BLOCK,1,1)
线程和(bx/MAX_NUMBER)THREADS_PER_BLOCK,by,bz)
假设bx<by<bz
和bx>MAX_NUMBER_THREADS_PER_BLOCK
。
对于每种情况,您将需要不同的内核,这有点麻烦,但最终还是可以完成的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.