CUDA - 多处理器、Warp 大小和每个块的最大线程数:确切的关系是啥?

Posted

技术标签:

【中文标题】CUDA - 多处理器、Warp 大小和每个块的最大线程数:确切的关系是啥?【英文标题】:CUDA - Multiprocessors, Warp size and Maximum Threads Per Block: What is the exact relationship?CUDA - 多处理器、Warp 大小和每个块的最大线程数:确切的关系是什么? 【发布时间】:2012-07-18 20:38:29 【问题描述】:

我知道 CUDA GPU 上有包含 CUDA 内核的多处理器。在我的工作场所,我正在使用 GTX 590,它包含 512 个 CUDA 内核、16 个多处理器,并且 warp 大小为 32。所以这意味着每个多处理器中有 32 个 CUDA 内核,它们在相同的代码中完全相同地工作.最后,每个块大小的最大线程数是 1024。

我的问题是块大小和多处理器计数 - warp 大小是如何完全相关的。说一下我对这种情况的理解:例如我在 GTX 590 上分配了 N 个最大 threadPerBlock 大小为 1024 的块。据我从 CUDA 编程指南和其他来源了解,这些块首先由硬件枚举.在这种情况下,N 个块中的 16 个被分配给不同的多处理器。每个块包含 1024 个线程,硬件调度程序将其中 32 个线程分配给单个多处理器中的 32 个内核。同一多处理器(warp)中的线程处理同一行代码并使用当前多处理器的共享内存。如果当前的 32 个线程遇到像内存读写这样的片外操作,它们将被当前块中的另一组 32 个线程替换。因此,实际上单个块中有 32 个线程完全在任何给定时间在多处理器上并行运行,而不是全部 1024。最后,如果一个块完全由多处理器处理,N个线程块列表中的一个新线程块被插入到当前的多处理器中。最后,在 CUDA 内核执行期间,GPU 中总共有 512 个线程并行运行。 (我知道如果一个块使用的寄存器比单个多处理器上可用的寄存器多,那么它会被划分为在两个多处理器上工作,但在我们的例子中假设每个块都可以适合单个多处理器。)

那么,我的 CUDA 并行执行模型是否正确?如果没有,有什么问题或遗漏?我想微调我正在处理的当前项目,所以我需要整个事情中最正确的工作模型。

【问题讨论】:

【参考方案1】:

在我的工作场所,我正在使用 GTX 590,它包含 512 个 CUDA 内核、16 个多处理器,并且扭曲大小为 32。因此这意味着每个多处理器中有 32 个 CUDA 内核,它们在相同的代码上运行相同的经线。最后,每个块大小的最大线程数是 1024。

GTX590 包含您提到的数字的 2 倍,因为卡上有 2 个 GPU。下面,我重点介绍单芯片。

说说我对情况的理解:比如我在GTX 590上分配了N个block,最大threadPerBlock大小为1024。据我从CUDA编程指南和其他来源了解到,首先枚举blocks由硬件。在这种情况下,N 个块中的 16 个被分配给不同的多处理器。

块不一定均匀分布在多处理器 (SM) 上。如果您恰好安排了 16 个块,则一些 SM 可以获得 2 或 3 个块,而其中一些则空闲。我不知道为什么。

每个块包含 1024 个线程,硬件调度程序将其中 32 个线程分配给单个多处理器中的 32 个内核。

线程和内核之间的关系并不是那么直接。每个 SM 中有 32 个“基本”ALU。处理单精度浮点和大多数 32 位整数和逻辑指令的指令。但是只有16个加载/存储单元,所以如果当前正在处理的warp指令是加载/存储,则必须调度两次。而且只有 4 个特殊功能单元,可以做三角函数之类的事情。所以这些指令必须安排 32 / 4 = 8 次。

同一多处理器(warp)中的线程处理同一行代码并使用当前多处理器的共享内存。

不,一个 SM 中可以同时“运行”的线程超过 32 个。

如果当前 32 个线程遇到像内存读写这样的片外操作,它们会被当前块中的另一组 32 个线程替换。因此,在一个单独的块中实际上有 32 个线程在任何给定时间在多处理器上并行运行,而不是全部 1024。

不,不仅仅是内存操作会导致扭曲被替换。 ALU 也是深度流水线的,因此当仍在流水线中的值发生数据依赖关系时,新的扭曲将被交换。因此,如果代码包含两条指令,其中第二条使用第一条的输出,则扭曲将被暂停,而第一条指令的值通过管道。

最后,如果一个块被一个多处理器完全处理,N个线程块列表中的一个新线程块被插入到当前的多处理器中。

一个多处理器一次可以处理多个块,但一个块一旦开始处理就不能移动到另一个 MP。块中当前正在运行的线程数取决于该块使用了多少资源。 CUDA 占用计算器会根据您的特定内核的资源使用情况告诉您同时有多少块正在运行。

最后,在 CUDA 内核执行期间,GPU 中总共有 512 个线程并行运行。 (我知道如果一个块使用的寄存器比单个多处理器上可用的寄存器多,那么它会被划分为在两个多处理器上工作,但在我们的例子中假设每个块都可以适合单个多处理器。)

不,一个块不能被划分为在两个多处理器上工作。整个块总是由单个多处理器处理。如果给定的多处理器没有足够的资源来处理您的内核至少一个块,您将收到内核启动错误并且您的程序将根本无法运行。

这取决于您如何将线程定义为“正在运行”。 GPU 通常会有超过 512 个线程同时消耗芯片上的各种资源。

请参阅@harrism 在此问题中的回答:CUDA: How many concurrent threads in total?

【讨论】:

感谢您的回答。它使一些事情更清楚,但我仍然有一些困惑的地方。据我从您的回答和@harrism 的回答中了解到,多处理器可以同时处理多个块,并且多处理器中最多可以有 48 个扭曲。我的问题是,如果多处理器可以处理不同块的线程,它如何在这些块之间划分共享内存?我的意思是,共享内存的大小约为 48KB,一个块可能已经在使用其中的大部分。 共享内存是可以同时运行多少块的潜在限制因素之一。如果一个块使用了超过一半的可用共享内存,那么一次只能运行一个块。如果一个块使用 1/2 到 1/3 的可用共享内存,则 2 个可以并发运行,依此类推。 网上有很多优秀的费米架构分析。 Beyond3D 至少有几个不错的。 Here's one。虽然我发现设计问题非常有趣,但我认为没有必要在接近如此细节的任何地方了解芯片才能编写最佳 GPU 软件。真的,CUDA C 编程指南中的内容就是你所需要的。

以上是关于CUDA - 多处理器、Warp 大小和每个块的最大线程数:确切的关系是啥?的主要内容,如果未能解决你的问题,请参考以下文章

CUDA 的 resident warp 问题

CUDA 中每个 Warp 关系的数据大小到指令

CUDA:每个多处理器的线程数和每个块的线程数的区别是啥? [复制]

CUDA中的warp和bank的机制是啥?

两个块可以在同一个warp中执行吗?

为啥要费心去了解 CUDA Warps?