我正在使用CUDA(实际上,如果差异很重要,我正在使用pyCUDA)并在数组上执行一些计算。我正在启动一个内核,网格为320 * 600线程。在内核中,我使用以下方法声明两个20000个组件的线性阵列:


 float test [20000]
 float test2 [20000]&#xA ;


 使用这些数组,我执行简单的计算,例如用常量值填充它们。关键是内核正常执行并且正确执行计算(您可以看到这填充了一个带有随机测试组件的数组并将该数组从设备发送到主机) 。


问题是我的NVIDIA显卡只有2GB内存,分配阵列test和test2的内存总量是320 * 600 * 20000 * 4字节这远远超过2GB。


这个内存来自哪里?以及CUDA如何在每个线程中执行计算?


感谢您的时间

答案 0 :(得分:4)
本地/堆栈内存要求的实际大小不是您想象的(对于整个网格,一次全部),但实际上是基于@njuffa here描述的公式。
基本上,本地/堆栈内存需求的大小取决于您运行的设备的最大瞬时容量,而不是网格的大小。
根据njuffa提供的信息,可用的堆栈大小限制(每个线程)是较小的:
对于你的第一个案例:
float test[20000];
float test2[20000];
总数是160KB(每个线程)所以我们在每个线程的最大限制为512KB。第二个限制怎么样?
GTX 650m有2 cc 3.0(kepler)SM(每个Kepler SM有192个核心)。因此,如果所有 GPU内存可用,则上述第二个限制为:
2GB / 2/2048 = 512KB
(凯普勒有2048 max threads per multiprocessor) 所以在这种情况下它是相同的限制。但这假设所有GPU内存都可用。
由于您在评论中建议此配置失败:
float test[40000];
float test2[40000];
即。 320KB,我会得出结论,你的实际可用GPU内存是在这个批量分配尝试的点上方(160/512)* 100%,即高于31%但低于(320/512)* 100%,即低于62.5% 2GB,所以我得出结论,在堆栈帧的批量分配请求时,你可用的GPU内存将小于1.25GB。
您可以尝试通过在内核启动之前调用cudaGetMemInfo
来确定是否是这种情况(尽管我不知道如何在pycuda中执行此操作)。即使你的GPU以2GB开始,如果你从它运行显示器,你很可能从接近1.5GB的数字开始。在内核启动时,此批量分配请求之前发生的动态(例如cudaMalloc
)和/或静态(例如__device__
)分配都将影响可用内存。
这是解释一些具体细节的全部内容。你的问题的一般答案是"魔法"由于GPU不一定为网格中的所有线程分配堆栈帧和本地存储器这一事实而产生。它只需要分配设备的最大瞬时容量所需的内容(即每SM的SMs *最大线程数),这可能是一个明显小于整个网格所需数量的数字。