《CUDA Programming Guide》 1. Programming Model

§ 参考资料 共 1 条

CPU 和 GPU 分别被称为 Host 和 Device,其上的内存分别被称为 Host Memory 和 Device Memory

运行在 GPU 上的程序代码被称为 Device Code,其中的一个由 CPU 发起的、作为 GPU 执行入口的函数被叫做 Kernel,运行函数被称为 Launching Kernel

GPU Hardware Model

在硬件上,GPU 可以被视为许多 Streaming Multiprocessors(SM)的集合,若干个 SM 还会由 Graphics Processing Clusters(GPC)组织起来

每个 SM 包含独立的寄存器堆(Register File)、Unified Data Cache(可以用作 L1 Cache 或者 Shared Memory)和一堆 Functional Units

GPU 内的所有 SM 共享一个容量更大的 L2 缓存

和 CPU 一样,GPU 也采用虚拟内存寻址,它们共享一个统一的虚拟内存空间。系统中每个 GPU 的虚拟内存地址范围都是唯一的,且与 CPU 及系统内其他 GPU 的地址范围互不重叠

The CUDA programming model view of CPU and GPU components and connection

CUDA Software Model

Blocks, Clusters and Grids

有了 GPU 的硬件模型,CUDA 将所有线程组织成 Grid-Block-Thread 的三级结构,一个 Grid 包含若干个 Thread Block,而一个 Thread Block 包含若干个 Thread

一个 Thread 的 ID 可以由 Block 在 Grid 中的编号和 Thread 在对应 Block 中的编号来决定,这二级编号可以是 1、2 或者 3 维(仅仅是为了编程方便,本身不改变性能,本质上仍然被映射成一维)

Grid 中的每一个 Block 被动态分配给一个 SM,其中的所有 Thread 都会在一个 SM 中执行,这个 Block 会一直在分配的 SM 中执行直到结束(除非遇到 IO 等待,此时会挂起当前的 Block 运行另一个,直到等待完毕,此时的切换操作并不需要像 CPU 那样“保存现场-切换-恢复现场”,直接切换即可,因为上下文是 Block 的所有线程共有的)

一般来说,不要假设不同 Block 之间可以进行同步,也不能直接进行通信

在高版本的 CUDA 中,Grid 和 Block 之间还可以有一层 Cluster,这一层对应物理模型中的 GPC,同一个 Cluster 下的所有 Block 只会被分配到同一个 GPC 下的 SM 中。这为跨 Block 进行通信和同步提供了一点可能,可以通过 Cooperative Groups 提供的软件层面的接口来进行通信和同步,对性能有影响

Thread blocks scheduled on SMs

Warps and SIMT

接下来看 SM 是如何组织分配到的 Block 中所有 Thread 的执行的

一个 Block 中的线程按照线性 Thread ID,每连续 32 个线程组成一个 Warp,是 SM 的主要指令调度单位。一个 Warp 中线程的位置称为 Warp Lane(0 到 31),即 warp_id = tid / warpSizelane_id = tid % warpSize

不要依赖具体的 Warp 执行如何映射到实际硬件的具体细节

CUDA 使用 SIMT 模型描述 Warp 的执行,将多个线程打包成一个 Warp 执行,每个线程都可以有自己的控制流,这样的话可能会出现路径分叉(被称为 Warp Divergence),不同的 Thread 可能处在不同的执行路径上,Warp 会分别执行实际被选择的分支路径,标记成 Active

在一个指令发射周期中,Warp Scheduler 会从已经准备好的 Warp 中选择一个,并向其中当前处于 Active 的 Lane 发射下一条指令

当一个 Warp 暂时不能继续执行时(比如内存访问、数据依赖或同步),Scheduler 可以立即选择其他的 Ready Warp,通过这样的方式来隐藏执行和访存延迟