我有'N'个线程同时在设备上执行,它们需要M * N从全局内存中浮动。访问全局内存合并的正确方法是什么?在这个问题上,共享内存如何帮助?
答案 0 :(得分: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])
(以上假设数组大小是多个的线程数)
因此,如果线程数是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, ...(银行ID =地址模16)。
同样,您可以在CUDA编程指南中阅读更多内容。