Beh*_*adX 8 gpu coalesce shared-memory
我有'N'个线程同时在设备上执行,它们需要从全局内存中浮动M*N. 访问全局内存合并的正确方法是什么?在这件事情上,共享内存如何帮助?
Cyg*_*sX1 15
通常,当相邻线程访问存储器中的相邻单元时,可以实现良好的合并访问.所以,如果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])
Run Code Online (Sandbox Code Playgroud)
(以上假设数组大小是线程数的倍数)
因此,如果线程数是32的倍数,则内存访问将是好的.
请再次注意:我是从CUDA程序员的角度谈论的.对于不同的GPU /环境,您可能需要更少或更多的线程来实现完美的内存访问合并,但应该应用类似的规则.
"32"与经线大小有关,它与全局存储器并行访问吗?
虽然不是直接的,但有一些联系.全局内存分为32,64和128字节的段,可通过半warp访问.您为给定的内存提取指令访问的段越多,它就越长.您可以在"CUDA编程指南"中阅读更多详细信息,这一主题有一整章:"5.3.最大化内存吞吐量".
另外,我听说了一些关于共享内存来本地化内存访问.这是内存合并的首选还是有其自身的困难?
共享内存在芯片上更快,但其大小有限.内存不像全局一样被分段,你可以几乎随机访问,无需花费.但是,存在宽度为4字节的存储体线(32位int的大小).每个线程访问的内存地址应该是16(或32,取决于GPU)不同的模块.所以,地址[tid*4]
会慢得多[tid*5]
,因为第一个只能访问0,4,8,12和后者0,5,10,15,4,9,14 ......(bank id = address modulo 16) ).
同样,您可以在CUDA编程指南中阅读更多内容.