用于多个内核的Cuda Stream Processing消歧

tha*_*los 0 concurrency cuda cuda-streams

关于Cuda流处理多个内核的几个问题.在具有3.5个功能的kepler设备中假设s流和内核,其中s <= 32.内核使用大小为n的dev_input数组和大小为s*n的dev输出数组.内核从输入数组中读取数据,将其值存储在寄存器中,对其进行操作并将其结果写回位于s*n + tid的dev_output.

我们的目标是每次使用n个流中的一个来运行相同的内核.与simpleHyperQ示例类似.你能否评论以下任何一项是否以及如何影响并发?

  1. dev_input和dev_output没有固定;
  2. dev_input因为它是vs dev_input size s*n,其中每个内核读取唯一数据(没有读取冲突)
  3. 内核从常量内存中读取数据
  4. 每个块分配10kb的共享内存.
  5. 内核使用60个寄存器

任何好的评论将不胜感激...... !!!

欢呼,Thanasio

罗伯特,非常感谢你的详细解答.这非常有帮助.我编辑了4,每块10kb.所以在我的情况下,我发布了61个块和256个线程的网格.内核受计算限制.我启动了8个相同内核的流.描述它们然后我看到前两个之间非常好的重叠然后它变得越来越糟.内核执行时间约为6ms.在前两个流执行几乎完全并发后,其余的流之间的距离为3ms.关于5,我使用具有255寄存器文件的K20.所以我不希望那里有弊端.我真的不明白为什么我没有达到相当于为gk110s指定的并发性.

请看下面的链接.有一个名为kF.png的图像.它显示了流的分析器输出.. !!!

https://devtalk.nvidia.com/default/topic/531740/cuda-programming-and-performance/concurrent-streams-and-hyperq-for-k20/

Rob*_*lla 6

内核之间的并发性取决于许多因素,但许多人忽略的只是内核的大小(即网格中的块数).大小可以自己有效利用GPU的内核通常不会在很大程度上同时运行,即使他们这样做,也几乎没有吞吐量优势.GPU内部的工作分配器通常会在内核启动后立即开始分配块,因此如果一个内核在另一个内核之前启动,并且两者都有大量的块,那么第一个内核通常会占用GPU,直到它接近完成后,第二个内核的块将被调度和执行,可能只有少量的"并发重叠".

主要的一点是,具有足够"块填充GPU"的块的内核将阻止其他内核实际执行,除了调度之外,这在计算机3.5设备上没有任何不同.此外,不仅仅为内核指定一些参数作为一个整体,而且在块级别指定启动参数和统计信息(例如寄存器使用,共享内存使用情况等)有助于提供清晰的答案.计算3.5架构在这个领域的好处仍然主要来自"少量"块的"小"内核,试图一起执行.Compute 3.5在那里有一些优势.

您还应该查看此问题的答案.

  1. 当内核使用的全局内存未固定时,它会影响数据传输的速度,也会影响复制和计算的重叠能力,但不会影响两个内核并发执行的能力.然而,复制和计算重叠的限制可能会扭曲您的应用程序的行为.
  2. 不应该有"阅读冲突",我不确定你的意思.允许两个独立的线程/块/网格读取全局内存中的相同位置.通常,这将在L2缓存级别进行整理.只要我们谈论的只是读取,就不会有冲突,也不会对并发产生特别的影响.
  3. 常量内存是一种有限的资源,在设备上执行的所有内核之间共享(尝试运行deviceQuery).如果你还没有超过设备总数限制,那么唯一的问题就是利用常量缓存,以及缓存抖动等问题.除了这种二级关系,对并发没有直接影响.
  4. 识别每个块的共享内存而不是每个内核会更有启发性.这将直接影响可以在SM上安排的块数.但是,如果您指定了每个内核的启动配置以及启动调用的相对时间,那么回答这个问题也会更加清晰. 如果共享内存恰好是调度的限制因素,那么您可以将每个SM的总可用共享内存除以每个内核使用的数量,以便基于此了解可能的并发性.我个人认为,每个网格中的块数可能是一个更大的问题,除非你的内核每个网格使用10k但在整个网格中只有几个块.
  5. 我在这里的评论与我对4的响应几乎相同.看看你的设备的deviceQuery,如果寄存器成为每个SM上调度块的限制因素,那么你可以按照每个SM的寄存器使用量来划分每个SM的可用寄存器内核(再次,讨论每个块的寄存器使用和内核中的块数)更有意义,以发现限制可能是什么.

同样,如果你有合理大小的内核(数百或数千个块或更多),那么工作分配器对块的调度很可能是内核之间并发量的主要因素.

编辑:回应问题中发布的新信息.我看过kF.png

  1. 首先让我们从每个SM角度的块进行分析.CC 3.5允许每个SM有16个"开放"或当前调度的块.如果要启动每个61块的2个内核,这可能足以填满CC 3.5设备上的"准备就绪"队列.换句话说,GPU一次可以处理其中的两个内核.当其中一个内核的块"消耗"时,另一个内核由工作分配器调度.第一个内核的块在大约一半的总时间​​内"充分消耗",以便下一个内核在前两个内核完成的大约中途进行调度,因此在任何给定点(在时间轴上绘制一条垂直线)你有2个或3个内核同时执行.(根据图表,启动的第3个内核与前2个内核重叠约50%,我不同意你的说法,即每个连续的内核启动之间有3ms的距离).如果我们说在峰值时我们有3个内核被调度(有很多垂直线将与3个内核时间线相交)并且每个内核有大约60个块,那么大约是180个块.您的K20有13个SM,每个SM最多可以安排16个块.这意味着在峰值时你可以安排大约180个区块(可能),而理论峰值为16*13 = 208.所以你在这里非常接近最大值,而且你可能得到的更多.但也许你认为你只有120/208,我不知道.
  2. 现在让我们从共享内存的角度来看一看.一个关键问题是您的L1 /共享分割的设置是什么?我相信每个SM默认为48KB的共享内存,但如果你改变了这个设置,那将非常重要.无论如何,根据您的声明,每个预定的块将使用10KB的共享内存.这意味着我们最多可以为每个SM调度大约4个块,或者4*13个总块=最多可以在任何给定时间调度的52个块.你明显超过了这个数字,所以我可能没有足够的信息来了解内核的共享内存使用情况.如果你真的使用10kb/block,这或多或少会阻止你一次执行多个内核的线程块.可能仍有一些重叠,我相信这可能是您申请中的实际限制因素.60个块的第一个内核被安排.在几个块流失之后(或者可能因为两个内核一起足够靠近地启动),第二个内核开始进行调度,因此几乎同时进行.然后我们必须等待一段时间才能在第3个内核可以调度之前排出内核的块数,这可能是时间轴中指示的50%点.

无论如何,我认为上面的分析1和2清楚地表明,基于内核结构中固有的限制,您可以从设备中获得大部分功能.(我们可以根据寄存器进行类似的分析,以发现这是否是一个重要的限制因素.)关于这句话:"我真的不明白为什么我没有实现相当于gk110s指定的并发..."我希望你看到并发规范(例如32个内核)是最大规范,并且在大多数情况下,在达到可以同时执行的最大内核数量限制之前,您将遇到其他类型的机器限制.

编辑:关于文档和资源,我从上面链接到Greg Smith的答案提供了一些资源链接.这里还有一些:

  • C编程指南有一节关于异步并发执行.
  • NVIDIA的Steve Rennich博士的GPU Concurrency和Streams演示在NVIDIA网络研讨会页面上