0

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

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

  1. dev_input 和 dev_output 未固定;
  2. dev_input 原样与 dev_input 大小 s*n,其中每个内核读取唯一数据(无读取冲突)
  3. 内核从常量内存中读取数据
  4. 每个块分配 10kb 的共享内存。
  5. 内核使用 60 个寄存器

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

干杯,塔纳西奥

罗伯特,非常感谢您的详细回答。这非常有帮助。我编辑了 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/

4

2 回答 2

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 个“打开”或当前计划的块。如果您要启动 2 个内核,每个内核有 61 个块,这可能足以填充 CC 3.5 设备上的“准备就绪”队列。换句话说,GPU 一次可以处理 2 个这样的内核。当其中一个内核的块“耗尽”时,工作分配器会安排另一个内核。第一个内核的块在大约一半的总时间​​中充分“耗尽”,因此下一个内核在前两个内核完成的一半左右被安排,所以在任何给定点(在时间轴上画一条垂直线)你有 2 个或 3 个内核同时执行。(根据图表,启动的第 3 个内核与前 2 个内核重叠了约 50%,我不同意您的说法,即每次连续内核启动之间有 3 毫秒的距离)。如果我们说在高峰期我们安排了 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 个块的内核被调度。在几个块耗尽之后(或者可能是因为 2 个内核被启动得足够近),第二个内核开始被调度,几乎同时。然后我们必须等待一段时间,让内核的块消耗殆尽,然后才能安排第三个内核,这很可能是在时间轴上指示的 50% 点。

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

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

  • C 编程指南有一个关于异步并发执行的部分。
  • NVIDIA 的 Steve Rennich 博士的 GPU 并发和流演示在 NVIDIA 网络研讨会页面上
于 2013-02-20T14:43:30.113 回答
0

到目前为止,我对 HyperQ 的体验是我的内核的 2-3 (3.5) 倍并行化,因为内核通常更大,可以进行更复杂的计算。对于小内核,情况就不同了,但通常内核更复杂。

Nvidia 在他们的 cuda 5.0 文档中也回答了这个问题,即更复杂的内核将减少并行化的数量。

但是,GK110 仅允许这样做就有很大的优势。

于 2013-05-22T08:29:22.197 回答