参考
- Exploring the GPU Architecture
- GPU vs CPU: What Are The Key Differences?
- Everything You Need to Know About GPU Architecture and How It Has Evolved
- 深入GPU硬件架构及运行机制
- 如何设置CUDA Kernel中的grid_size和block_size?
SIMD和SIMT
SISD:单一的指令流执行单一的数据流,即每条指令只能执行其对应的一个数据,也不会有不同的核执行不同的指令流,即只有一个核心。
SIMD:该架构只有一个控制单元和一个指令内存,因此同一时刻只能有一条指令被执行,但是这条指令可以同时处理多个数据,类似于指令的操作数不再是针对单个数字,而是针对向量。例如在SISD情境下,如果abc都是四维数据,我们想要执行
c = a + b
:ADD c.x, a.x, b.xADD c.y, a.y, b.yADD c.z, a.z, b.zADD c.w, a.w, b.w
但是在SIMD下,只需要执行一条指令即可:
SIMD_ADD c, a, b
MISD:不同的指令对同一数据进行操作,很少使用。
MIMD:指令和数据都可以并行,不同的核心可以对不同的数据执行不同的指令流,可以认为是多个SISD的并行?
SIMT:可以认为是SIMD的升级版,同一条指令可以被多个并发线程执行,并且不同线程执行的统一指令,其操作数也可以不同。
Fermi架构
- 有16个SM (Streaming Processor),即上图黑框
- 上图右侧为SM,一个SM拥有:
- 2个Warp,每个Warp有16个Core
- 16组LD/ST(加载处理单元)
- 4个SFU(特殊函数处理单元)
- shared memory
- 每个Warp包括:
- 16个Core
- 一个Warp Scheduler
- 一个Dispatch Unit
- 每个Core(Streaming Processor,SP)包括:
- 一个 INT Unit(整数计算单元、ALU)
- 一个 FP Unit(浮点计算单元)
CUDA
cuda核函数启动时,主要是如下形式:
cuda_kernel<<>>(...)
- grid_size:dim3型数据,例如x、y和z,设置了grid的维度。x * y * z就等于启动的blocks的数目。Grid中所有的线程共享global memory。
- blcok_size:dim3型数据,设置了每个block的维度。例如x * y * z就等于每个block包含的线程(thread)数目。block内部的线程可以同步,可以访问shared memory。
- Ns:默认为0,代表在shared memory中,可以为每个block动态申请的memory,大小是字节数。
- stream:就是指明该核函数匹配的stream,默认是0,即GPU中默认的stream。
与GPU架构的联系和层次
- Cuda中的 Thread:就对应GPU中的Core。
- Cuda中的 block:可以认为它可以由多个warp组成,也就是由多个thread构成,但是其不够大过SM,也就是说,一个block中的所有thread,都必须是同一个SM中的,这样才能使用shared memory。
- warp:是调度和运行的基本单元,规定了block中 32个 thread 组成一个 warp,如果最后剩下的thread不够32个,也要占一个warp。因此,block_size最好是32的整数倍。warp中的32个thread每次都会执行同一条指令,也就是SIMT。
- 对于Cuda中的block,其在同一个SM上运行,但是可被调度到不同的SM中。同一个SM可以同时运行多个block(并发执行)。但是SM中的资源有限,例如shared memory或者寄存器,因此有限制:
Maximum number of resident blocks per SM
和Maximum number of resident threads per SM
。因为有该限制,一个block中的thread数目应该尽量大于SM的core数目/SM最多驻留block数目
,不同的架构比值不同,例如对GTX 1080 Ti 是 2048 / 32 = 64。128作为block的通用值比较合适。 - 一个SM可以并行执行多个warp,这主要由一个SM有几个warp scheduler决定。但是这并行执行的多个warp,是只能属于同一个block还是可以属于多个不同的block?似乎可以属于不同的block,感觉有多种说法。