这似乎是一个简单的问题,但我无法在任何地方找到答案。 我有一个全局函数,我可以像这样调用:
func<<<nbBlocks,nbThreadByBlock, nbBytesOfSharedMmy>>>(args);
如果我理解正确,我永远不能使用超过1024的nbThreadByBlock,但我怎么能动态地知道我的函数nbThreadByBlock
和我的GPU允许的func
的最大值?
我认为,如果我的func
函数使用更多局部变量,那么每个块的最大线程数会减少吗?
关于我可以使用的块总数,是否有上限?我在想,如果我放置的块多于可能的块,它们将按顺序处理,是真的吗?
谢谢!
答案 0 :(得分:1)
下面的代码
cudaDeviceProp deviceProp;
cudaGetDeviceProperties(&deviceProp, 0); //assuming current device ID is 0
将设备的属性收集到deviceProp
。正如您所看到的here,在成功调用cudaGetDeviceProperties
后,您将能够访问具有您所需设备属性的deviceProp
成员。例如,deviceProp.maxThreadsPerMultiProcessor
表示每个多处理器的最大线程数,deviceProp.maxThreadsPerBlock
表示每个块的最大线程数等。
每个块的适当线程数以及调用函数的块总数主要取决于您的设备属性和程序。您调用的每个块占用SM的一部分。多少取决于您的块请求的资源:线程,寄存器和共享内存 考虑这个例子。假设您的设备SM最多可以有2048个线程,48 KB的共享内存和64 KB的寄存器。如果您的块需要512个线程,并且同时使用SM可用的所有共享存储器和寄存器,则在SM中具有相同特性的另一个块是不可能的。因此,您无法使用2048减去512个潜在的SM线程,将最大占用率降低到25%。现在,如果您通过将块中的线程数增加到1024来设计块,则可以使用相同数量的寄存器和共享内存,将占用率增加一倍至50%。
通常不建议使用大量的块。 GPU将新块安排到可用的SM。如果所有SM都被占用,它会对块进行排队,直到SM有足够的空闲资源用于块。调度新块有GPU的开销(尽管很小)。找到最佳块大小后,您可以通过SM计算(或分析)块的占用率,然后调用占用所有GPU SM的块数。如果您需要更多块,则可以重用已完成其工作的块的线程 例如转换
GPU_kernel<<<1024,512>>>();
其中
__global__ void GPU_kernel(void){
unsigned int tid = (blockIdx.x * blockDim.x) + threadIdx.x;
//rest of code
}
到
GPU_kernel<<<(number_of_SMs*number_of_blocks_per_SM),512>>>();
其中
__global__ void GPU_kernel(void){
unsigned int tid = (blockIdx.x * blockDim.x) + threadIdx.x;
for (; tid < 1024*512; tid += blockIdx.x* gridDim.x ) {
//rest of code
}
}
通常会带来更好的表现。
另请注意,在上面的代码中,我还没有包含正确的CUDA错误检查。请应用您自己的方法来处理可能的错误。说明here。