实现入住率低的原因

Causes of Low Achieved Occupancy

Nvidia web-site 提到了实现占用率低的几个原因,其中包括块之间工作负载分配不均,导致块囤积共享内存资源并且直到块完成才释放它们。建议是减小块的大小,从而增加块的总数(当然,假设我们保持线程数不变)。

在 Whosebug 上 也给出了很好的解释。

鉴于上述信息,正确的做法不应该是(为了最大限度地提高性能)简单地将块的大小设置得尽可能小(等于 warp 的大小,比如 32 个线程)?也就是说,除非您需要确保更多线程需要通过共享内存进行通信,否则我假设。

Given aforementioned information, shouldn't the right course of actions be (in order to maximize performance) simply setting the size of a block as small as possible (equal to the size of a warp, say 32 threads)?

没有。

如文档 here 中所示,每个多处理器的块数存在限制,使用 32 个线程块时,最大理论占用率为 25% 或 50%,具体取决于你 运行 内核在什么硬件上。

通常,尽可能使用小块但大到足以使设备饱和(每个块 64 或 128 个线程,具体取决于设备)是一种很好的方法 - 这并不总是可行的,因为您可能想要同步线程或通信通过共享内存。

拥有大量小块允许 GPU 执行某种 "autobalancing" 并保留所有 SM 运行。

这同样适用于 CPU - 如果您有 5 个独立的任务,每个任务需要 4 秒才能完成,但您只有 4 个核心,那么它将在 8 秒后结束(在前 4 秒内有 4 个核心运行 在前 4 个任务上,然后 1 个核心在最后一个任务上 运行,3 个核心空闲)。 如果您能够将整个工作划分为 20 个任务,这些任务需要 1 秒,那么整个工作将在 5 秒内完成。所以有很多小任务有助于利用硬件。

在 GPU 的情况下,您可以拥有大量活动块(在 Titan X 上是 24 SM x 32 活动块 = 768 块)并且可以很好地使用此功能。 无论如何,您并不总是需要使设备完全饱和。在许多任务中,我可以看到每个块使用 32 个线程(因此可能占用 50%)提供与每个块使用 64 个线程相同的性能。 最后,要做一些基准测试,并在给定硬件的给定情况下选择最适合您的东西。