我正在研究GPU Tesla M6。根据其数据表,Tesla M6具有12个多处理器,每个处理器最多可容纳32个常驻块。因此,整个设备上驻留的最大块总数为384。
现在,我有一个大小为(512,1408)的数据矩阵。我编写了一个内核,并将每个块的线程数设置为64(1D块,每个线程一个数据元素),所以1D网格大小为512 * 1408/64 = 11264个块,这远远超出了驻留块的数量在GPU上。但是,整个程序仍然可以运行并输出正确的结果。
我想知道为什么代码可以执行,尽管实际的块数超过了驻留的块数?这是否意味着性能下降?你能给我详细解释吗?谢谢!
答案 0 :(得分:3)
线程块中的线程可以相互依赖。诸如协作组之类的编程模型允许使用比线程块更大的组。网格中的线程块数可以比驻留线程块数大几个数量级(例如,最小为1个线程块,GV100支持84 x 32 2688驻留线程块)。
计算工作分配器将线程块分配给SM。如果抢占了网格,则状态将被保存并随后恢复。当线程块中的所有线程完成时,线程块资源被释放(翘曲插槽,寄存器,共享内存),并通知计算工作分配器。计算工作分配器将继续为SM分配线程块,直到网格中的所有工作完成为止。
答案 1 :(得分:3)
根据您的计算,GPU可以容纳的块多于驻留的块。
GPU会在SM上加载尽可能多的块,其余的将在队列中等待。当街区完成他们在SM上的工作并退休时,他们为从队列中选择新街区并使其成为“居民”打开了空间。最终,GPU以这种方式处理所有块。
这种方法并不一定有什么问题;这是GPU编程的典型代表。它并不一定意味着性能下降。但是,一种调整内核以获得最大性能的方法是根据可以“驻留”的块数来选择块数。如果正确完成,可以计算多少个居民比您概述的要复杂。它需要占用分析。 CUDA提供了occupancy API以便在运行时进行此分析。
此方法还将需要设计内核,该内核可以使用任意或固定大小的网格完成工作,而不是根据问题大小选择的网格大小。一种典型的方法是grid-stride loop。
如果将诸如网格跨度循环之类的内核设计与基于占用率分析的运行时块选择结合起来,则仅使用“驻留”在GPU上的块即可完成工作;无需排队,等待。这可能有或没有任何明显的性能优势。只有通过基准测试,您才能确定。
我建议在询问后续问题之前先阅读我链接的两篇文章。 cuda
标签上还存在许多问题,讨论了此答案中的概念。