我有一些未知大小的矩阵在两个方向上从10-20.000不等 .
我设计了一个带有(x; y)块和(x; y)线程的CUDA内核 .
由于矩阵的宽度/高度不是我的维度的倍数,因此让事情起作用是一种可怕的痛苦,并且代码变得越来越复杂以获得合并内存读取 .
除此之外,内核的大小越来越大,使用越来越多的寄存器来检查是否正确......所以我认为这不是我应该采用的方式 .
我的问题是:如果我完全消除块并只创建一个x; y线程的网格怎么办?如果没有很多块,SM单元会出现问题吗?
我可以消除块并使用大量线程还是必须进行块细分?
2 回答
你实际上不能只创建一个“线程网格”,因为你必须将线程组织成块,每个块最多可以有512个线程 . 但是,您可以通过每个块使用1个线程来有效地执行此操作,这将导致1 x 1块的X x Y网格 . 但是,由于以下几个因素,这将导致非常糟糕的性能:
根据CUDA编程指南,SM可以随时处理最多8个块 . 这将限制每个SM 8个线程,这甚至不足以填充单个warp . 如果你有48个CUDA核心,你将只能在任何给定的时间处理384个线程 .
在SM上只有8个线程可用,将会有太少的warp来隐藏内存延迟 . GPU将花费大部分时间等待内存访问完成,而不是进行任何计算 .
您将无法合并内存读取和写入,从而导致内存带宽使用不足 .
您实际上无法利用共享内存,因为这是块中线程之间的共享资源 .
虽然必须确保块中线程的正确性是令人讨厌的,但是您的性能将比您的“线程网格”理念要好得多 .
这是我用来将需要
num_threads
的给定任务划分为块和网格的代码 . 是的,你可能最终会启动到很多块(但只有很少的块),你可能最终会得到比实际更多的实际线程,但这种方式很容易和有效 . 请参阅下面的第二个代码示例,了解我的简单内核边界检查 .PS:我总是有
block_size == 128
因为它在多核占用,寄存器使用,共享内存要求和所有内核的合并访问之间进行了很好的权衡 .用于计算良好网格大小的代码(主机):
用于计算唯一线程ID和检查边界(设备)的代码:
我不认为这需要很多努力/注册/代码行来检查是否正确 .