3

我有一个需要使用全局内存的 CUDA (v5.5) 应用程序。理想情况下,我更喜欢使用常量内存,但我已经用尽了常量内存,溢出将不得不放在全局内存中。我还有一些变量需要偶尔写入(在 GPU 上进行一些缩减操作之后),我将其放置在全局内存中。

为了阅读,我将以一种简单的方式访问全局内存。我的内核在 for 循环中被调用,每次调用内核时,每个线程都将访问完全相同的全局内存地址,没有偏移。对于写入,在每次内核调用之后在 GPU 上执行缩减,并且我必须在循环的下一次迭代之前将结果写入全局内存。然而,在我的应用程序中,读取的次数远多于写入全局内存的次数。

我的问题是使用在全局(变量)范围内声明的全局内存是否比使用动态分配的全局内存有任何优势?我需要的全局内存量会根据应用程序而变化,因此动态分配会更可取。但是,我知道全局内存使用的上限,并且我更关心性能,因此我也可以使用我确信不会溢出的大型固定分配静态声明内存。考虑到性能,有什么理由更喜欢一种形式的全局内存分配而不是另一种?它们是否存在于 GPU 上的同一个物理位置并且它们的缓存方式是否相同,或者两种形式的读取成本是否不同?

4

2 回答 2

10

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

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

由于动态分配需要一些非零时间,因此可以通过在程序开始时使用静态(ie __device__)方法或通过运行时 API(iecudaMalloc等)执行一次分配来提高代码的性能。 ) 这避免了在代码的性能敏感区域花时间动态分配内存。

另请注意,我概述的 3 种方法虽然从设备代码具有类似 C/C++ 的访问方法,但从主机具有不同的访问方法。静态分配的内存使用运行时 API 函数访问,例如cudaMemcpyToSymboland cudaMemcpyFromSymbol,运行时 API 分配的内存通过普通cudaMalloc/cudaMemcpy类型函数访问,动态分配的全局内存(设备newmalloc)不能直接从主机访问。

于 2013-10-30T12:25:09.987 回答
1

首先,您需要考虑合并内存访问。你没有提到你正在使用的 GPU。在最新的 GPU 中,煤系内存读取将提供与恒定内存相同的性能。所以总是尽可能地让你的记忆以煤炭的方式读写。

另一个您可以使用纹理内存(如果数据大小适合它)。这个纹理内存有一些缓存机制。这以前在全局内存读取未合并的情况下使用。但最新的 GPU 在纹理和全局内存方面提供几乎相同的性能。

我不认为全局声明的内存比动态分配的全局内存具有更高的性能,因为合并问题仍然存在。在 CUDA 全局内存的情况下,在全局(变量)范围内声明的全局内存也是不可能的。可以全局(在程序中)声明的变量是常量内存变量和纹理,我们不需要将它们作为参数传递给内核。

有关内存优化,请参阅 cuda c 最佳实践指南http://docs.nvidia.com/cuda/cuda-c-best-practices-guide/#memory-optimizations中的内存优化部分

于 2013-10-30T01:44:54.507 回答