如何使用合并的内存访问

Posted

技术标签:

【中文标题】如何使用合并的内存访问【英文标题】:How to use coalesced memory access 【发布时间】:2011-09-27 15:23:59 【问题描述】:

我有 'N' 个线程要在设备上同时执行,它们需要从全局内存中浮动 M*N。访问合并的全局内存的正确方法是什么?在这件事上,共享内存有什么帮助?

【问题讨论】:

【参考方案1】:

通常,当相邻线程访问内存中的相邻单元时,可以实现良好的合并访问。所以,如果tid 持有你线程的索引,那么访问:

arr[tid] --- 完美结合 arr[tid+5] --- 几乎是完美的,可能是错位 arr[tid*4] --- 不再那么好,因为差距 arr[random(0..N)] --- 太可怕了!

我是从 CUDA 程序员的角度说的,但类似的规则也适用于其他地方,即使是在简单的 CPU 编程中,虽然影响不大。


“但是我有这么多数组,每个人的线程数都比我的线程数长大约 2 到 3 倍,使用像“arr[tid*4]”这样的模式是不可避免的。有什么办法可以解决这个问题?”

如果偏移量是某个更高的 2 次方的倍数(例如 16*x 或 32*x),则不是问题。所以,如果你必须在 for 循环中处理一个相当长的数组,你可以这样做:

for (size_t base=0; i<arraySize; i+=numberOfThreads)
    process(arr[base+threadIndex])

(以上假设数组大小是线程数的倍数

所以,如果线程数是 32 的倍数,内存访问会很好。

再次注意:我是从 CUDA 程序员的角度说的。对于不同的 GPU/环境,您可能需要更少或更多线程来实现完美的内存访问合并,但应该适用类似的规则。


“32”与全局内存并行访问的warp大小有关吗?

虽然不是直接的,但有一定的联系。全局内存分为 32、64 和 128 字节的段,由半扭曲访问。对于给定的内存获取指令,您访问的段越多,执行的时间就越长。您可以在“CUDA 编程指南”中阅读更多详细信息,该主题有一整章:“5.3. 最大化内存吞吐量”。

另外,我听说了一点关于共享内存的本地化内存访问。这是内存合并的首选还是有其自身的困难? 共享内存位于芯片上,速度要快得多,但它的大小是有限的。内存没有像全局那样分段,您几乎可以随机访问,没有惩罚成本。但是,存在宽度为 4 字节(32 位 int 大小)的内存条行。每个线程访问的内存地址应该是不同的模 16(或 32,取决于 GPU)。因此,地址[tid*4] 将比[tid*5] 慢得多,因为第一个地址只能访问银行 0、4、8、12,而后面的地址是 0、5、10、15、4、9、14,...(银行 id = 地址模 16)。

同样,您可以在 CUDA 编程指南中阅读更多内容。

【讨论】:

谢谢。但是我有这么多的数组,每个人的长度都比我的线程数长 2 到 3 倍,使用像“arr[tid*4]”这样的模式是不可避免的。有什么办法可以解决这个问题? 再次感谢您。 “32”是否与并行访问全局内存的扭曲大小有关?如果是这样,这是在这组线程中不过度访问每个内存段的技巧。我对吗?另外,我听说过一些关于共享内存的本地化内存访问。这是内存合并的首选还是有其自身的困难? 再次感谢您。我可以发现,对于“全局”内存访问,线程所需的内存地址的合并(相邻)是关键,而在“共享”内存中,线程发出的非冲突地址是关键。我说的对吗?

以上是关于如何使用合并的内存访问的主要内容,如果未能解决你的问题,请参考以下文章

Python Pandas 合并导致内存溢出

shmget 如何分配内存?无法使用线性寻址访问(地址边界错误)

如何基于公共列合并两个 FMResultSet?

如何分配具有连续内存的二维数组?如何使用它来访问行和列?给我一个例子

如何通过多个 VC 访问公共内存位置?

访问内存时如何通知操作系统内核?