我已经使用 CUDA 几个星期了,但是我对块/扭曲/线程的分配有一些疑问。
我正在从教学的角度研究架构 (大学项目),所以达到最佳性能不是我关心的。
首先,我想知道我是否理解了这些事实:
程序员编写内核,并在线程块网格中组织其执行。
每个块都分配给一个流式多处理器 (SM)。一旦分配,它就不能迁移到另一个 SM。
每个 SM 将自己的块拆分为 Warps(当前最大大小为 32 个线程)。一个 warp 中的所有线程在 SM 的资源上并发执行。
线程的实际执行由 SM 中包含的 CUDA 核心执行。线程和内核之间没有特定的映射。
如果一个 warp 包含 20 个线程,但当前只有 16 个内核可用,则该 warp 将不会运行。
另一方面,如果一个块包含 48 个线程,它将被分成 2 个经线,如果有足够的内存可用,它们将并行执行。
如果一个线程在一个内核上启动,那么它会因内存访问或长浮点运算而停止,它的执行可能会在不同的内核上恢复。
他们是对的吗?
现在,我有一个 GeForce 560 Ti,所以根据规范它配备了 8 个 SM,每个 SM 包含 48 个 CUDA 内核(总共 384 个内核)。
我的目标是确保架构的每个核心都执行相同的指令。假设我的代码不需要比每个 SM 中可用的更多的寄存器,我想象了不同的方法:
我创建了 8 个块,每个块有 48 个线程,因此每个 SM 有 1 个块要执行。在这种情况下,48 个线程是否会在 SM 中并行执行(利用所有可用的 48 个内核)?
如果我启动 64 个 6 个线程块有什么区别吗? (假设它们将在 SM 之间均匀映射)
如果我在预定工作中“淹没”GPU(例如,每个创建 1024 个 1024 个线程的块)是否合理假设所有内核都将在某个点使用,并且将执行相同的计算(假设线程从不拖延)?
有没有办法使用探查器检查这些情况?
这个东西有引用吗?我阅读了 CUDA Programming guide 和“Programming Massively Parallel Processors”和“CUDA Application design and development”中专门介绍硬件架构的章节;但我无法得到准确的答案。
两个最好的引用是
NVIDIA Fermi Compute Architecture Whitepaper
GF104 Reviews
我会尽力回答你的每一个问题。
程序员将工作划分为线程,将线程划分为线程块,将线程块划分为网格。计算工作分配器将线程块分配给流式多处理器 (SM)。一旦一个线程块被分配给一个 SM,线程块的资源就会被分配(扭曲和共享内存),并且线程被分成 32 个线程组,称为扭曲。一旦分配了扭曲,它就称为事件扭曲。两个经线调度器每个周期选择两个事件经线并将经线分派(dispatch)到执行单元。有关执行单元和指令分派(dispatch)的更多详细信息,请参阅
1第 7-10 页和
2 .
4' . Laneid(经纱中的线程索引)和核心之间存在映射。
5' .如果一个经线包含少于 32 个线程,它在大多数情况下会像它有 32 个线程一样被执行。由于以下几个原因,warp 的事件线程可能少于 32 个:每个块的线程数不能被 32 整除,程序执行一个发散块,因此未采用当前路径的线程被标记为不事件,或者 warp 中的线程退出。
6' .一个线程块会被划分为
WarpsPerBlock = (ThreadsPerBlock + WarpSize - 1)/WarpSize
经纱调度器不需要从同一个线程块中选择两个经纱。
7' .执行单元不会因内存操作而停顿。如果在准备好分派(dispatch)指令时资源不可用,则将在将来资源可用时再次分派(dispatch)该指令。 Warp 可以在障碍处、内存操作、纹理操作、数据依赖性等处停滞…… 停滞的 warp 没有资格被 warp 调度程序选择。在 Fermi 上,每个周期至少有 2 个合格的扭曲是有用的,这样扭曲调度程序可以发出指令。
见引用
2 GTX480 和 GTX560 之间的差异。
如果您阅读引用资料(几分钟),我想您会发现您的目标没有意义。我会尽量回复你的观点。
1' .如果您启动 kernel<<<8, 48>>> 您将获得 8 个块,每个块有 2 个 32 和 16 个线程的扭曲。不能保证这 8 个块会分配给不同的 SM。如果 2 个块被分配给一个 SM,那么每个扭曲调度器都可以选择一个扭曲并执行扭曲。您将只使用 48 个内核中的 32 个。
2' . 8块48线程和64块6线程有很大区别。假设您的内核没有分歧,每个线程执行 10 条指令。
8 个块,48 个线程 = 16 个扭曲 * 10 条指令 = 160 条指令
64 个块和 6 个线程 = 64 个扭曲 * 10 条指令 = 640 条指令
为了获得最佳效率,工作分工应该是 32 个线程的倍数。硬件不会合并来自不同经线的线程。
3' .如果内核没有最大化寄存器或共享内存,GTX560 可以有 8 个 SM * 8 个块 = 64 个块或 8 个 SM * 48 个扭曲 = 512 个扭曲。在任何给定的时间,部分工作将在 SM 上活跃。每个 SM 有多个执行单元(超过 CUDA 核心)。在任何给定时间使用哪些资源取决于应用程序的扭曲调度程序和指令组合。如果你不做 TEX 操作,那么 TEX 单元将是空闲的。如果您不进行特殊的浮点运算,SUFU 单元将处于空闲状态。
4' . Parallel Nsight 和 Visual Profiler 展示
a.执行IPC
湾发行的IPC
C.每个事件周期的事件扭曲
d.每个事件周期的合格扭曲(仅限 Nsight)
e.经纱失速原因(仅限 Nsight)
f.每条指令执行的事件线程
分析器不显示任何执行单元的利用率百分比。对于 GTX560,粗略估计为 IssuedIPC/MaxIPC。
对于 MaxIPC 假设
GF100 (GTX480) 是 2
GF10x (GTX560) 是 4,但目标是 3 是更好的目标。
我是一名优秀的程序员,十分优秀!