CUDA基本概念
主机(host)
通常将起控制作用的CPU称为主机(host)
设备(device)
将起加速作用的 GPU 称为设备(device)
流处理器(streaming processor)
物理上,GPU最基本的处理单元为SP(streaming processor),又称为CUDA core,主要包括若干整数型运算的核心、若干单精度浮点数运算的核心、若干双精度浮点数运算的核心、若干单精度浮点数超越函数的特殊函数单元、若干混合精度的张量核心(有伏特架构引进,适用于机器学习)。
最后具体的指令和任务都是在SP上处理的,GPU进行并行计算,即为多个SP同时做处理。
每个核心可以在一个时钟周期内执行一个线程。
流多处理器(streaming multiprocessor)
流多处理器SM(streaming multiprocessor)则是GPU的核心,又称为GPU大核,是GPU并行计算的核心单元。
一个典型的SM包括以下几个组件:
- 核心SP
- 共享内存/一级缓存 ShareMem/Cache
- 寄存器文件Reg File
- 加载/存储单元LD/ST
- 特殊功能单元SFU
- 线程束调度器 Warp Sched
每个SM包含多个流处理器SP(CUDA core),以及共享内存、寄存器等资源,所以每个SM都可以并行执行多个线程。
每个流式多处理器可以视为具有较小结构的CPU,支持指令并行(多发射)。
不同的NVIDIA GPU架构(例如Turing, Pascal, Maxwell, Kepler等)具有不同的SM设计和资源配置。
例如,某些架构可能在每个SM上有更多的CUDA核心,而其他架构可能有更多的共享内存或寄存器。
SM可以并发地执行许多线程,一般可以同时调度多个线程块。SM的基本执行单元是线程束(thead warp),线程束包含32个线程,这些线程同时执行相同的指令,但是每个线程都包含自己的指令地址计数器和寄存器状态,也有自己独立的执行路径,这导致了即便线程束中的线程同时从同一程序地址执行,但是可能具有不同的行为(比如遇到了分支结构,一些线程可能进入这个分支,但是另外一些有可能不执行,它们只能死等(因为GPU规定线程束中所有线程在同一周期执行相同的指令)),这被称为"线程束分化"。当线程块被划分到某个SM上时,它将进一步划分为多个线程束,因为这才是SM的基本执行单元,但是一个SM同时并发的线程束数是有限的。这是因为资源限制,SM要为每个线程块分配共享内存,而也要为每个线程束中的线程分配独立的寄存器。
全局内存(Global Memory)
GPU的主存储器,容量较大,但访问速度较慢。
所有的线程都可以对全局内存进行读写。缓存可加速对全局内存的访问。所有通过cudaMalloc分配的存储器都是全局内存。
共享内存(Shared Memory)
每个SM内部的高速缓存,供同一SM内的线程共享。
访问速度比全局内存快得多。
寄存器(Registers)
每个线程的私有存储空间,用于保存临时变量。
寄存器是访问速度最快的空间。
当我们在核函数中不加修饰的声明一个变量,那该变量就是寄存器变量,如果在核函数中定义了常数长度的数组,那也会被分配到Registers中;寄存器变量是每个线程私有的,当这个线程的核函数执行完成后,寄存器变量也就不能访问了。
寄存器是比较稀缺的资源,空间很小,Fermi架构中每个线程最多63个寄存器,Kepler架构每个线程最多255个寄存器;一个线程中如果使用了比较少的寄存器,那么SM中就会有更多的线程块,GPU并行计算速度也就越快。
如果一个线程中变量太多,超出了Registers的空间,这时寄存器就会发生溢出,就需要其他内存(Local Memory)来存储,当然程序的运行速度也会降低。
本地内存(Local Memory)
Local Memory也是每个线程私有的,但却是存储在于Global Memory中的。在核函数中符合存储在寄存器中但不能进入核函数分配的寄存器空间中的变量将被存储在Local Memory中。
Local Memory中可能存放的变量有以下几种:
- 使用未知索引的本地数组
- 较大的本地数组或结构体
- 任何不满足核函数寄存器限定条件的变量
常量内存
线程(Thread)、线程块(Block)、网格(Grid)
GPU使用线程(Thread)作为最小的执行单位。
线程被组织成线程块(Block),多个线程块组成网格(Grid)。
以上图为例子,把网格和线程块都看作一个三维的矩阵。这里假设网格是一个333的三维矩阵, 线程块是一个444的三维矩阵。
线程束(Warp)
线程束(warp)作为并行处理的基石,通过将线程组合成一个执行单元,简化了线程管理,使线程间能够共享数据和资源,并通过有效的调度掩盖内存延迟。
Nvidia把32个threads组成一个warp,warp是调度和运行的基本单元。它们会被同时调度到一个SM上执行。
核函数
核函数是运行在GPU上的函数,可以并行执行,核函数通过特殊的语法和关键字定义,并且是 GPU 编程的核心。
定义核函数:
- 必须使用限定词__global__修饰
- 核函数返回值必须是void
- 核函数通常以<<<blockNum, threadNum>>>形式来配置执行线程和块
参考文档
https://blog.csdn.net/qq_42761751/article/details/144297840
https://zhuanlan.zhihu.com/p/544864997