有人告诉我 GeForce GTX 480 GPU 可以同时运行 23,000 个 CUDA 线程。但是,我不知道为什么。
该 GPU 的每个核心包含 2 组 16 个 SIMD 单元。每个 SIMD 单元有 8 个 ALU 和指令上下文。GPU 上有 15 个核心。
因此,这个 GPU 难道不能同时运行 2 * 16 * 8 * 15 = 3840 个 CUDA 线程吗?
答案1
GPU 核心可以同时有效地运行多个线程,因为它们在线程之间切换的方式延迟隐藏。事实上,你需要每个核心运行多个线程以充分利用您的 GPU。
GPU 非常流水线,这意味着即使每个周期都有新指令启动,每个单独的指令也可能需要许多周期才能运行。有时,一条指令取决于前一条指令的结果,因此它不能启动(进入流水线),直到前一条指令完成(退出流水线)。或者它可能依赖于 RAM 中的数据,而这些数据需要几个周期才能访问。在 CPU 上,这会导致“管道停滞“(或“气泡”),这会导致部分流水线在若干个周期内处于空闲状态,只等待新指令启动。这浪费了计算资源,但却是不可避免的。
与 CPU 不同,GPU 核心能够非常快速地在线程之间切换 - 大约一个或两个周期。因此,当一个线程由于其下一个指令尚未启动而停滞几个周期时,GPU 可以切换到其他线程并启动其下一个指令。如果该线程停滞,GPU 会再次切换线程,依此类推。这些额外的线程在管道阶段中执行有用的工作,否则这些线程在这些周期中会处于空闲状态,因此如果有足够的线程来填补彼此的空白,GPU 可以在每个周期的每个管道阶段中工作。任何一个线程中的延迟都会被其他线程隐藏。
这与英特尔超线程功能所基于的原理相同,超线程功能使单个内核看起来像两个逻辑内核。在最坏的情况下,在这两个内核上运行的线程将相互竞争硬件资源,并且每个线程都以一半的速度运行。但在许多情况下,一个线程可以利用另一个线程无法利用的资源(目前不需要的 ALU、由于停顿而空闲的管道阶段),这样两个线程的运行速度都比单独运行时快 50% 以上。GPU 的设计基本上将这一优势扩展到两个以上的线程。
你可能会发现阅读 NVIDIA 的CUDA 最佳实践指南, 具体来说第十章(“执行配置优化”),它提供了有关如何安排线程以保持 GPU 繁忙的更详细信息。