CUDA中的全局内存和动态全局内存分配

3
我有一个CUDA(v5.5)应用程序需要使用全局内存。理想情况下,我希望使用常量内存,但我已经用尽了常量内存,溢出的部分必须放在全局内存中。我还有一些变量需要偶尔写入(在GPU上进行一些约简操作之后),并将其放置在全局内存中。
对于读取,我将以简单的方式访问全局内存。我的内核在for循环内调用,在每次内核调用时,每个线程将以没有偏移量的方式访问完全相同的全局内存地址。对于写入,在每次内核调用之后,在GPU上进行约简操作,必须在循环的下一次迭代之前将结果写入全局内存。但是,在我的应用程序中,从全局内存中读取的次数要比写入的次数多得多。
我的问题是,使用全局(变量)作用域中声明的全局内存是否比使用动态分配的全局内存具有优势?我需要的全局内存量将根据应用程序而变化,因此出于这个原因,动态分配更可取。但是,我知道我全局内存使用的上限,并且更关心性能,因此也可以使用静态声明内存,使用一个足够大的固定分配,确保不会溢出。从性能的角度考虑,是否有理由更喜欢一种形式的全局内存分配而不是另一种?它们是否存在于GPU上的同一个物理位置,并且它们被缓存的方式相同,或者两种形式的读取成本不同?
2个回答

11

全局内存可以通过静态分配(使用__device__)、动态分配(使用设备端mallocnew)和通过CUDA运行时(例如使用cudaMalloc)进行分配。

上述所有方法都分配物理上相同类型的内存,即从板载(但不是芯片上的)DRAM子系统中划出的内存。无论如何分配,该内存具有相同的访问、合并和缓存规则(因此具有相同的一般性能考虑)。

由于动态分配需要一些非零时间,因此通过在程序开始时执行一次分配(使用静态方法即__device__或通过运行时API即cudaMalloc等)可能会提高代码的性能,从而避免在代码的性能敏感区域动态分配内存所需的时间。同时请注意,我概述的三种方法虽然具有类似于C/C++的设备代码访问方法,但其主机访问方法不同。静态分配的内存使用运行时API函数(如cudaMemcpyToSymbolcudaMemcpyFromSymbol)进行访问,运行时API分配的内存则通过普通的cudaMalloc/cudaMemcpy类型函数进行访问,而动态分配的全局内存(设备newmalloc)无法直接从主机访问。

1
谢谢,这完全回答了我提出的问题,还解决了我没有问到的一些问题。 - Michael Puglia

1
首先,您需要考虑合并内存访问。您没有提到使用的GPU。在最新的GPU中,合并内存读取将提供与常量内存相同的性能。因此,请尽可能以合并方式进行内存读写。
另外,您可以使用纹理内存(如果数据大小适合)。这个纹理内存有一些缓存机制。以前在全局内存读取不连续的情况下使用过它。但是,最新的GPU对纹理和全局内存几乎具有相同的性能。
我认为,在动态分配的全局内存上声明的全局内存不会比全局内存提供更好的性能,因为合并问题仍然存在。此外,在CUDA全局内存的情况下,无法在全局(变量)范围内声明全局内存。可以在程序中全局声明的变量是常量内存变量和纹理,我们不需要将其作为参数传递到内核中。
有关内存优化,请参见cuda c最佳实践指南中的内存优化部分http://docs.nvidia.com/cuda/cuda-c-best-practices-guide/#memory-optimizations

感谢您提供指针。我正在使用亚马逊AWS上的Tesla M2050s。我了解到了合并问题。但是,静态分配的全局内存与动态分配的全局内存之间的合并读取是否有任何区别是问题的关键。此外,我不确定最后一行说“唯一的全局声明变量是常量内存变量和纹理”。根据此文档(https://developer.nvidia.com/content/how-access-global-memory-efficiently-cuda-cc-kernels),CUDA全局内存中存在全局(变量)范围。不过,该链接并没有解决我的原始问题。 - Michael Puglia
有关内存优化,请参阅CUDA C最佳实践指南中的内存优化部分:http://docs.nvidia.com/cuda/cuda-c-best-practices-guide/#memory-optimizations - Sijo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接