在CUDA中启动许多小内核有多糟糕?

时间:2014-11-20 11:13:17

标签: cuda

我有一个矩形网格。这些矩形中的每一个都由矩形网格点组成。矩形内的所有点都可以通过内核中完全相同的指令序列来处理。我将能够启动一个具有10000个点的内核来处理,其中每个线程将处理大约10-50个点。然而,矩形的边缘和角上的点将导致大量不同的指令序列。

从设计的角度来看,使用相同的指令序列为每组点启动内核会更容易。这意味着一些内核启动只会处理很少的点,可能不到10个。

所以我可能有4个内核启动,10000个点可以处理(每个线程10-50个点),也许30-100个内核启动,每个只有几个点(通常每个线程1个点)。

我完全不知道这是否可以接受,或者它是否会彻底破坏我的表现。如果你能给我一个粗略的估计或至少一些提示,我会很高兴,你可以考虑什么来估计。

2 个答案:

答案 0 :(得分:12)

这里有两个因素,我称之为启动开销执行开销

启动开销:启动内核的开销约为10us(即0.01ms)。它可能会少一点,它可能会更多,它将取决于您的系统整体以及相关的内核。此值假定您没有在Windows上作为图形卡运行(即没有WDDM)。

如果在启动之前有大量非阻塞GPU调用,则可以完全隐藏此启动开销。想到这一点的一种方法是,您已经准备好在GPU上执行任务队列,并且可以在执行某些操作时添加到该队列。启动开销是添加到队列的成本。只要队列中包含某些内容,您就不会看到启动开销会使GPU匮乏。

执行开销:一旦内核到达此队列的前端,它就会被执行。这里的开销也很小。我希望这可能是3-4us,但你的里程可能会有所不同。这与初始化和从全局内存移动数据以使内核运行有关。它还包括关闭成本。

使用流可以减少此执行开销。如果将小内核放在单独的流中,并将它们并发执行,则可以通过GPU上的其他计算隐藏此执行开销。您不会让整个GPU等待一个小问题通过它,而只有少量资源将等待,而GPU的其余部分继续处理您的主要问题。

答案 1 :(得分:4)

也许这应该是一个扩展的评论而不是一个答案,但我跳了它,无论如何都给你一些方向。

由于内核启动开销,启动许多小内核而不是大内核的性能限制。 This answer应该对此有所解释,并且还会链接有趣的资源。

但还有其他方法可以执行任务。假设你的系统(RAM)内存中有那么大的矩形网格,你必须将它以某种方式传输到GPU内存。这提供了使用内核传输重叠方法隐藏小内存传输时间的机会,即Asynchronous transfers。只有当内核花费足够的时间来完成矩形的计算时,此方法才有效。

如果您的所有网格同时适合您的GPU主内存,那么您可以从内核启动多个内核。 Here您可以找到有关该主题的更多信息(动态并行性),here是关于该方法减慢的另一个有趣问题。这种方法可能不会产生任何性能提升,因为它还需要一些时间来启动这些内核,但它是您的提议的替代方案,并保持简单性隐藏了主代码的一些复杂性。

作为一般建议,在大量较小的数据传输中更少的大数据传输因为,并且同样适用于内核以最小化开销。