当数据块的数量小于可用的SMs时,如何将其调度到CUDA中的SMs中?

当数据块的数量小于可用的SMs时,如何将其调度到CUDA中的SMs中?,cuda,profiling,gpu,nvidia,nvprof,Cuda,Profiling,Gpu,Nvidia,Nvprof,这个问题源于在内核中观察到的理论占用率和实际占用率之间的差异。我知道这一点,也知道 让我们考虑一个具有计算能力的GPU=6.1和15 SMS(GTX TITAN,PASCAL体系结构,芯片组GP104)。让我们考虑一个2304个元素的小问题。 如果我们将内核配置为512个线程,那么每个线程将处理一个元素,那么我们需要5个块来处理所有数据。而且内核非常小,在寄存器或共享内存方面,资源的使用没有任何限制 因此,理论占用率为1,因为可以在一个SM(2048个线程)中分配四个并发块,从而导致2048/3

这个问题源于在内核中观察到的理论占用率和实际占用率之间的差异。我知道这一点,也知道

让我们考虑一个具有计算能力的GPU=6.1和15 SMS(GTX TITAN,PASCAL体系结构,芯片组GP104)。让我们考虑一个2304个元素的小问题。 如果我们将内核配置为512个线程,那么每个线程将处理一个元素,那么我们需要5个块来处理所有数据。而且内核非常小,在寄存器或共享内存方面,资源的使用没有任何限制

因此,理论占用率为1,因为可以在一个SM(2048个线程)中分配四个并发块,从而导致2048/32=64个活动扭曲(最大值)

然而,英伟达探查仪(NVIDIA Prror)的占有率为0.215,可能与BSH映射到SMS的方式有关。那么,当数据块的数量小于可用的SMs时,如何将其调度到CUDA中的SMs中

选项1。-在一个SM中安排4个512线程块,在另一个SM中安排1个512线程块。在这种情况下,占用率将为(1+0.125)/2=0.56。我假设最后一个块只有512个线程中的256个处于活动状态,以到达数组的最后256个元素,并且它在第二个SM中分配。因此,考虑到扭曲粒度,只有8个扭曲处于活动状态

选项2。-将每个512块调度到不同的SMs。既然我们有15条短信,为什么只饱和一条短信和许多块呢?。在本例中,每个SMs有512/32=16个活动扭曲(除了最后一个,它只有256个活动线程)。因此,我们在四条短信中实现了0.25的入住率,在最后一条短信中实现了0.125的入住率,导致(0.25+0.25+0.25+0.25)/5=0.225

选项2更接近视觉探查器报告的占用率,我们认为这是幕后发生的事情。无论如何,值得一提的是:在CUDA中,当数据块的数量小于可用的SMs时,如何将数据块安排到SMs中?有文件记录吗

--
请注意这不是家庭作业。在使用不同的第三方库的项目中,这是一个真实的场景,在由多个内核组成的管道的某些步骤中,要处理的元素数量很少。

正如多年来对此问题发表的评论所指出的,块调度程序的行为尚未定义,而且也不能保证从硬件一代到硬件一代,从驱动程序/运行时版本到驱动程序/运行时版本,甚至从平台到平台都是相同的

当然,可以使用汇编指令插入代码,以提取时钟和SM ID,并运行一些案例来查看设备上发生了什么。正如格雷格·史密斯(Greg Smith)在评论中指出的那样,您可能会得出这样的结论:调度器的工作方式是广度优先,将SMs填充到最大可用占用率,但并不一定总是这样。最终,您尝试并利用您的发现构建的任何启发式都将依赖于未定义的行为


[根据评论汇总并添加为社区wiki条目,以将问题从CUDA标签的未答复队列中删除]

该行为未指定,可能会发生变化,从CUDA版本到CUDA版本,从一种设备类型到另一种设备类型。一般来说,根据我的观察,调度器将首先在空SMs上调度块,然后再将块添加到已驻留块的SMs。通过每个块观察简单测试用例的块调度/放置是相当简单的。然后,您可以将块计数从1更改为所需的任何数字,然后查看它们是如何调度的。您可能需要使用
clock64()
类型delay来强制块保持一段时间。最好的方法是编写您自己的工具,如@RobertCrovella所述。通常情况下,块首先以广度分布,直到GPU已满,然后在资源可用时按需分配。不建议依赖未记录的行为。