GPGPU:用于1D线程索引的CUDA内核配置 - 线程,块,共享内存和寄存器

时间:2013-05-31 16:47:04

标签: c++ c cuda gpu gpgpu

假设我有N个任务,其中每个任务都可以由GPU上的单个线程执行。假设N = GPU上的线程数。

问题1: 以下是启动最大大小的1D内核的适当方法吗? GPU上存在的所有N个线程都会执行工作吗?

cudaDeviceProp  theProps;

dim3 mygrid(theProps.maxGridSize[0], 1, 1);
dim3 myblocks(theProps.maxThreadsDim[0], 1, 1);

mykernel<<<mygrid, myblocks>>>(...);

问题2:cudaDeviceProp::maxThreadsPerBlock相关的属性cudaDeviceProp::maxThreadsDim[0]是什么?他们有什么不同?可以cudaDeviceProp::maxThreadsPerBlock代替上面的cudaDeviceProp::maxThreadsDim[0]吗?

问题3: 假设我想在块中的线程之间平均分配块的共享内存,并且我希望每个线程可用的共享内存量最多。然后我应该最大化块的数量,并最小化每个块的线程数,对吧?

问题4: 为了确认(在回顾关于SO的相关问题之后),在上面的线性(1D)网格/块方案中,全局唯一线程索引是unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x。正确?

1 个答案:

答案 0 :(得分:2)

建议每个问题提出一个问题。有各种各样的问题使得任何人都很难给出完整的答案。这不是一个真正的教程服务。您应该利用现有的documentationwebinars,当然还有许多其他可用资源。

  

以下是启动最大大小的1D内核的适当方法吗? GPU上存在的所有N个线程都会执行工作吗?

这当然是可能的,所有启动的线程(比如称为N)都可用于执行工作,它将启动最大(1D)大小的网格。但是你为什么要这么做呢?大多数cuda编程方法都不是以此为目标开始的。网格应根据算法确定大小。如果1D网格大小似乎是限制器,您可以通过在内核中执行循环来处理每个线程的多个数据元素,或者启动2D网格以绕过1D网格限制。 cc3.x设备的限制已经扩展。

  

与cudaDeviceProp :: maxThreadsDim [0]相关的属性cudaDeviceProp :: maxThreadsPerBlock是什么?他们有什么不同?可以用cudaDeviceProp :: maxThreadsPerBlock代替上面的cudaDeviceProp :: maxThreadsDim [0]吗?

第一个是多维块中线程总数的限制(即threads_x * threads_y * threads_z)。第二个是对第一维(x)尺寸的限制。对于1D线程块,它们是可互换的,因为y和z维度为1.对于多维块,存在多维限制以通知用户例如maxThreadsDim[0]*maxThreadsDim[1]*maxThreadsDim[2]的线程块不合法。

  

假设我想在块中的线程之间平均分配块的共享内存,并且我希望每个线程可用的共享内存量最多。然后我应该最大化块的数量,并最小化每个块的线程数,对吧?

同样,我对这种方法有点怀疑。但是,每个线程可能的共享内存字节的理论最大值将由最小线程数的线程块实现。但是,允许线程块使用所有可用的共享内存可能导致一次只有一个可以驻留在SM上的线程块。这可能会对入住产生负面影响,这可能会对绩效产生负面影响。有许多有用的建议可用于选择线程块大小,以最大限度地提高性能。我不能在这里总结一下。但是我们想要选择线程块大小作为warp大小的倍数,我们通常希望每个线程块有多个warp,并且所有其他条件相同,我们希望启用最大占用率(这与可以驻留在一个线程块上的线程块数相关) SM)。

  

为了确认(在回顾SO上的相关问题之后),在上面的线性(1D)网格/块方案中,全局唯一线程索引是无符号的int tid = blockIdx.x * blockDim.x + threadIdx.x。正确?

是的,对于1-D线程块和网格结构,此行将提供全局唯一的线程ID:

unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;