CUDA - 多处理器、Warp大小和每个块的最大线程数:它们之间的确切关系是什么?

25
我知道CUDA GPU上有多个处理器,其中包含CUDA核心。在我的工作场所,我正在使用一款GTX 590,它包含512个CUDA核心,16个处理器,每个线程束大小为32。这意味着每个处理器中有32个CUDA核心,它们在同一个线程束中以完全相同的代码工作。最后,每个线程块的最大线程数是1024。
我的问题是块大小和处理器数量 - 线程束大小之间的确切关系。让我来解释一下我的理解:例如,我在GTX 590上分配了N个块,并将最大线程数设为1024。据我从CUDA编程指南和其他来源了解,硬件首先枚举块。在这种情况下,N个块中有16个被分配给不同的处理器。每个块包含1024个线程,硬件调度程序将32个线程分配到单个处理器中的32个核心中。同一处理器(线程束)中的线程处理同一行代码,并使用当前处理器的共享内存。如果当前32个线程遇到类似于内存读写的离片操作,则用当前块的另外一组32个线程替换它们。因此,在任何给定时间,单个块中实际上有32个线程正恰好并行运行在一个处理器上,而不是全部1024个线程。最后,如果一个块被完全处理,则从N个线程块列表中插入一个新的线程块到当前的处理器中。在执行CUDA内核时,总共有512个线程并行运行在GPU中。(我知道,如果一个块使用的寄存器比单个处理器可用的更多,则会将其分成两个处理器来工作,但假设在我们的情况下每个块都适合单个处理器。)
所以,我的CUDA并行执行模型正确吗?如果不是,错在哪里或缺少什么?我想微调我目前正在工作的项目,因此需要整个过程中最正确的工作模型。
1个回答

20
在我的工作场所,我正在使用一块GTX 590,其中包含512个CUDA核心,16个多处理器,warp大小为32。这意味着每个多处理器中有32个CUDA核心,它们在相同的warp中以完全相同的代码工作。最后,每个块的最大线程数为1024。
一块GTX 590包含您提到的数字的2倍,因为该卡上有2个GPU。以下是关于单个芯片的重点。
让我说出我对情况的理解:例如,我在GTX 590上分配具有最大线程数为1024的N个块。根据CUDA编程指南和其他来源,硬件首先枚举块。在这种情况下,从N个块中有16个分配给不同的多处理器。
块不一定均匀地分布在多处理器(SMs)上。如果您准确安排了16个块,则一些SM可能会获得2或3个块,而另一些则空闲。我不知道为什么。
每个块包含1024个线程,硬件调度程序将其中32个线程分配给单个多处理器中的32个核心。
线程与核心之间的关系并不那么直接。每个SM中有32个“基本”ALU。处理诸如单精度浮点和大多数32位整数和逻辑指令等内容。但是只有16个加载/存储单元,因此如果当前正在处理的warp指令是加载/存储,则必须对其进行两次调度。而且只有4个特殊功能单元,可以执行三角函数等操作。因此,这些指令必须进行32/4=8次调度。
同一个多处理器中的线程(warp)处理相同行的代码并使用当前多处理器的共享内存。
不,一个单独的SM中可以同时有许多超过32个线程在执行。如果当前的32个线程遇到像内存读写这样的片外操作,它们将被替换为当前块中另一组32个线程。因此,在任何给定时间,实际上有32个线程在单个块中在多处理器上完全并行运行,而不是1024个。
不,不仅是内存操作会导致warp被替换。ALU也深度流水线化,因此当仍在流水线中的值存在数据依赖性时,新的warp将被交换。因此,如果代码包含两条指令,其中第二条使用第一条的输出,那么当第一条指令的值通过管道传递时,warp将被暂停。
最后,如果一个块被多处理器完全处理,那么当前多处理器将插入来自N个线程块列表中的新线程块。
多处理器可以同时处理多个块,但一旦开始对其进行处理,块就无法移动到另一个MP。块中当前正在执行的线程数取决于块使用的资源量。 CUDA占用率计算器将根据您特定的内核的资源使用情况告诉您将同时飞行多少块。
最后,在CUDA内核执行期间,GPU中有总共512个线程并行运行。(我知道,如果一个块使用的寄存器比单个多处理器上可用的寄存器多,那么它将被分成两个多处理器工作,但假设在我们的情况下每个块都可以适合单个多处理器。)
不,一个块不能分成两个多处理器工作。整个块始终由单个多处理器处理。如果给定的多处理器没有足够的资源来处理至少一个块与您的内核,则会出现内核启动错误,您的程序将根本无法运行。
这取决于您如何定义“运行”线程。 GPU通常会有许多超过512个线程同时消耗芯片上的各种资源。

请查看@harrism在此问题的回答:CUDA:总共有多少并发线程?


1
谢谢你的回答。它让我更清楚了一些事情,但仍然有些困惑的地方。就我从你和@harrism的回答中所理解的而言,多处理器可以在同一时间处理多个块,并且最多可以有48个warp驻留在多处理器中。我的问题是,如果多处理器可以处理不同块的线程,那么它如何在这些块之间分配共享内存?我的意思是,共享内存大小约为48KB,一个块可能已经使用了大部分共享内存。 - Ufuk Can Bicici
1
共享内存是影响并发运行块数的潜在限制因素之一。如果一个块使用了超过可用共享内存的一半,那么只能有一个块同时运行。如果一个块使用了可用共享内存的1/2到1/3之间,那么可以同时运行两个块,以此类推。 - Roger Dahl
有许多关于Fermi架构的优秀分析可在网上找到。Beyond3D至少有几篇不错的文章。这是其中之一。虽然我觉得设计问题非常有趣,但我认为并不需要了解芯片的细节才能编写最佳GPU软件。实际上,CUDA C编程指南中的内容就足够了。 - Roger Dahl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接