openACC:将3D阵列复制到设备时耗尽设备内存

时间:2018-02-07 05:53:49

标签: c openacc

我是使用openACC的新手,我正在试图弄清楚当我使用nvidia-smi数据指令(特别是在C中)时发生了什么。

我有一个3D数组,我正在尝试将其复制到设备上进行一些计算。我遇到的问题是,当我执行复制时,设备内存不足,即使按照我的估计,阵列应该只有~40 MB(20000 x 128 x 2浮点数组)。我正在使用GTX 950,在运行时有超过1 GB的可用内存(使用pgcc -acc -Minfo -o copytest copytest.c检查)。

这是我用来测试的代码。我编译了它 #include <stdlib.h> #include <stdio.h> #include <string.h> float ***create_test_array( int nsamples, int nchan, int npol ) { int s, ch; // Loop variables float ***array; array = (float ***)malloc( nsamples * sizeof(float **) ); for (s = 0; s < nsamples; s++) { array[s] = (float **)malloc( nchan * sizeof(float *) ); for (ch = 0; ch < nchan; ch++) array[s][ch] = (float *)malloc( npol * sizeof(float) ); } return array; } void test_copy( int nsamples, int nchan, int npol, float ***arr) { #pragma acc data pcopyin(arr[0:nsamples][0:nchan][0:npol]) #pragma acc kernels for (int pol = 0; pol < npol; pol++) { for (int ch = 0; ch < nchan; ch++) { for (int s = 0; s < nsamples; s++) { arr[s][ch][pol] = 0.0; } } } } void main() { int nsamples = 10000; int nchan = 128; int npol = 2; float ***test_array = create_test_array( 2*nsamples, nchan, npol ); test_copy( 2*nsamples, nchan, npol, test_array ); }

{{1}}

非常感谢任何见解。

1 个答案:

答案 0 :(得分:0)

这实际上是GPU的非常糟糕的数据布局。问题是编译器必须匹配GPU上的结构,因此需要创建一个指针数组,然后为每个指针创建第二个数组或指针,并将指针“附加”到它的父节点。 “attach”意味着它将在父数组中的适当位置填充设备指针,但必须启动内核才能执行此操作。更糟糕的是,它需要再次遍历结构以创建第三维并再次附加指针。第三个维度也用于对齐,这是额外内存的来源。这会导致很多额外开销,并会严重影响您的表现。

此外,由于主机和设备之间的数据传输只能在连续的块上进行,因此运行时必须遍历结构并一次只复制2个元素。再次,导致高开销。

如果你可以交换“nsamples”和“npol”维度,你仍然会有一些开销,但是128 + 2x128附件远远少于20000 + 20000x128。

或者,您可以使用CUDA Unified Memory(-ta = tesla:managed)让CUDA运行时为您执行数据移动。编译器不再需要创建GPU数据结构,也不需要附加指针。

第三个选项是线性化数组(即使其成为一维数组),然后在循环中计算索引。