天天看点

CUDA全局内存读取

正如前文所述,CUDA全局内存的访问是通过”内存事务“实现的,其分类128字节(L1/L2缓存均参与)和32字节(L2缓存参与)两种。本文则主要介绍全局读取的加载示例,分为”缓存加载(L1+L2)“和”非缓存加载(L2)“,代码会贴在后面。

一.缓存加载(L1+L2)

这种情况下,”内存事务“中加载的缓存粒度是128字节。 (1)对齐合并访问,线程束首地址对齐128字节,且连续访问128字节内存。只需一次”128字节内存事务“即可完成内存请求。效率100%。

CUDA全局内存读取

  (2)访问对齐,随机访问128字节内存。由于所请求的内存地址仍然在一个缓存行中,因此,也只需一次”128字节内存事务“即可完成内存请求。效率100%。

CUDA全局内存读取

 (3)非对齐的连续访问,线程束请求的字节未对齐128,而是分布在两个128字节段范围内。由于启用L1缓存,因此加载必须从首地址128的倍数开始,因此需要加载0-127和127-255两个”128字节内存事务“才能完成内存请求。其中一半数据是请求之外的,因此效率=请求加载的全局内存/所需加载的全局内存=50%。 这主要是由于缓存的加载模式导致,因为缓存不是一次性只加载一个数据,而是一批数据,如128字节,而且又必须保证对齐操作,这就导致了加载的浪费。

CUDA全局内存读取

(4)同一warp中线程只访问一个地址。只需要一个”128内存事务“就可以完成请求,但是效率却非常低。因为所需4字节,而加载了128字节。效率为4/128=3.125%。

CUDA全局内存读取

(5)最坏的情况,warp中32线程所请求的内存全部分散,因此加载的”内存事务“的可能在0-32之间不等。完成一次内存请求最差需要进行32次”内存事务“,而加载的128字节中,却只有4字节是warp所需的。

CUDA全局内存读取

二.非缓存加载(L2)

这种情况下,”内存事务“中加载的缓存粒度是32字节,这是比128字节更细粒度的加载,会对非对齐或非合并的访问带来好处。类似地,对比上述情况,逐一分析。 (1)对齐合并访问,一个warp的128字节的请求,需要4个32字节”内存事务“完成。效率100%。

CUDA全局内存读取

(2)对齐,但访问是不连续。所需地址将占用4个内存段,不会产生加载浪费。效率100%。

CUDA全局内存读取

(3)非对齐的连续访问。由于请求内存首地址没有对齐128字节,请求的地址最多落在5个内存段中,总线利用率至少为80%,相比缓存加载50%有了很大的提供,这主要是由于加载了更少的未请求字节。

CUDA全局内存读取

(4)warp中线程束访问一个内存地址。效率为4/32=12.5。非缓存加载要优于缓存加载。

CUDA全局内存读取

(5)warp中线程的请求内存地址全部分散,则需要的”内存事务“的也是0-32个,但每个内存事务是32字节,而不再是128字节。这也是非缓存加载优于缓存加载的地方。

CUDA全局内存读取

继续阅读