GPU 的内存总线不仅仅是 48 字节宽(这会很麻烦,因为它不是 2 的幂)。相反,它由 6 个内存通道组成,每个通道有 8 个字节(64 位)。内存事务通常比通道宽度宽得多,以便利用内存的突发模式。良好的事务大小从 64 字节开始,以产生大小为 8 的突发,这与计算能力 1.x 设备上的半扭曲的 16 个 32 位字很好地匹配。
128 字节宽的事务仍然要快一些,并且与计算能力 2.0(及更高版本)设备的经线宽 32 位字访问相匹配。高速缓存行也是 128 字节宽以匹配。请注意,所有这些访问必须在事务宽度的倍数上对齐,以便映射到单个内存事务。
现在关于您的实际问题,最好的办法可能是什么都不做,让缓存对其进行排序。这与您在共享内存中显式执行的方式相同,只是它由缓存硬件为您完成,并且不需要代码,这应该会使其速度稍快一些。唯一需要担心的是有足够的缓存可用,这样每个warp 可以有必要的32×32×4 字节= 4kbytes 的缓存用于字宽(例如float)或8kbytes 用于双重访问。这意味着限制同时处于活动状态的 warp 的数量是有益的,以防止它们破坏彼此的缓存行。
对于特殊优化,也可以使用像float2
or这样的向量类型float4
,因为所有支持 CUDA 的 GPU 都有将 8 或 16 个字节映射到同一线程的加载和存储指令。然而,在计算能力 2.0 及更高版本上,我并没有真正看到在一般矩阵转置情况下使用它们的任何优势,因为它们会更多地增加每个 warp 的缓存占用空间。
由于 16kB 缓存 / 48kB 共享内存的默认设置只允许每个 SM 四个 warp 一次执行转置(前提是您同时没有其他内存访问),因此选择 48kB 缓存 /使用cudaDeviceSetCacheConfig()
. 较新的设备具有更大的缓存并提供更多不同的拆分以及选择使用超过 48kB 的共享内存。详细信息可以在链接的文档中找到。
为了完整起见,我还将提到计算能力 3.0 引入的 warp shuffle 指令允许在 warp 内交换寄存器数据,而无需通过缓存或共享内存。有关详细信息,请参阅CUDA C 编程指南的附录 B.22。
(请注意,存在没有此附录的编程指南版本。因此,如果在您的副本中附录 B.13 是关于其他内容的,请通过提供的链接重新加载它)。