CUDA全局内存的合并访问(个人理解)

每个warp去访问全局内存,会有400-600个时钟周期的内存延迟,这个代价很昂贵,所以为了减少访问全局内存的指令次数,我们将满足字节大小和对齐要求的warp合并起来访问全局内存,从而减少对全局内存的访问次数,提高GPU性能。

关于warp指令基础知识

1)什么是warp?

一个线程warp包括32条线程(我的电脑是1个warp包括32条线程)。它位于多处理器中。

2)warp指令

发射warp的一个指令,即该warp的32条线程一起执行的该条指令。多处理器会花费 该条指令 个时钟周期。

3)控制流指令

任何流控制指令( if , switch , do , for , while )都会导致warp内的线程分流,则warp要多执行该分流线程的指令,增加指令总数,花费更多的时钟周期。为了优化性能,应减少warp内的线程分流。

4)内存指令

多处理器使用4个时钟周期去发射warp的一条内存指令。当访问共享内存时,会有4个时钟周期的内存延时。访问全局内存时,会有400-600个时钟周期延时。

如果在等待全局内存访问完成期间,线程调度器可以发射足够多的独立算术指令,则大部分全局内存访存延迟可以被隐藏掉。(即内核流水线化,边访问,边计算。)

5)内存带宽(吞吐量)

每个内存空间的有效带宽主要取决于访存模式。

因为设备内存与片上内存相比具有更高的延迟和更低的带宽,所以设备内存访问必须最小化,典型的编程模式是将来自设备内存的数据存储到共享内存中。

全局内存的合并

全局内存空间没有高速缓存,所以最重要的是按照正确的访问模式获得最大的内存带宽,尤其是已知对设备内存的访问有多昂贵时。

1.设备能够在单个指令将32位、64位、128位从全局内存读取到寄存器中。
2.在执行单个读取或写入指令期间,每个 半warp 中同时访问全局内存地址的每个线程应该进行排列,以便内存访问可以合并到单个邻近的、对其的内存访问。
(这里我们直接使用整个warp的合并)

所以这些warp访问的首地址(WarpBaseAddress)应该对齐
32 * sizeof(type)个字节(type为线程所访问的内存的数据类型。)若所访问的内存首地址为0,则每个warp的首地址应为32 * sizeof(type)的倍数才算是对齐,这个时候就可以将这些warp合并起来去访问全局内存,若有warp没有对齐,则需要再次发射访问全局内存的指令,而这个指令是很昂贵的。

对于驻留在全局内存中的变量,其任何地址 BaseAddress 始终对齐至少256个字节,所以为了满足内存, WarpBaseAddress-BaseAddress应是32*sizeof(type)的倍数。