在内核中使用2d数组

时间:2016-01-30 16:24:41

标签: cuda gpgpu

在我读过的CUDA例子中,当数组在全局存储器中时,我不会在内核代码中直接使用2D数组符号[] [],这与它在共享存储器中的情况不同,例如:矩阵乘法。这背后有任何与性能相关的原因吗?

另外,我在旧线程中读到以下代码不正确

int **d_array;
cudaMalloc(  (void**)&d_array , 5 * sizeof(int*) );  

for(int i = 0 ; i < 5 ; i++) 
{ 
cudaMalloc((void **)&d_array[i],10 * sizeof(int));
}

根据作者的说法,&#34;一旦主线程在设备上分配内存,主线程就会失去对它的访问权限,也就是说,它只能在内核中访问。因此,当您尝试在数组的第二维上调用cudaMalloc时,它会抛出一个&#34;访问冲突写入位置&#34; 。例外&#34;

我不明白作者的真正含义;实际上,我发现上面的代码是正确的

感谢您的帮助

SS

1 个答案:

答案 0 :(得分:2)

  

这背后有与性能相关的原因吗?

是的,双引号数组通常需要额外的指针查找,即额外的内存读取,才能访问引用的数据。通过使用“模拟”2D访问:

int val = d[i*columns+j];

而不是:

int val = d[i][j];

然后只需要一次内存读访问。直接计算正确的索引,而不是要求读取行指针。与内存带宽相比,GPU通常具有大量计算能力。

  

我不明白作者的真正含义;实际上,我发现上面的代码是正确的

代码实际上是错误的。

此操作:

cudaMalloc(  (void**)&d_array , 5 * sizeof(int*) );

在设备上创建一个连续分配,长度等于5个指针存储,并获取该分配的起始地址,并将其存储在与d_array关联的主机内存位置。这就是cudaMalloc的作用:它创建所请求长度的设备分配,并在提供的主机内存变量中存储该分配的起始设备地址

所以让我们解构一下这里要求的内容:

cudaMalloc((void **)&d_array[i],10 * sizeof(int));

这就是说,创建一个长度为10*sizeof(int)的设备分配,并将其起始地址存储在d_array[i]位置。但与d_array[i] 关联的位置在设备上,而不是主机上,并且需要取消引用 d_array指针才能实际访问它,在那里存放东西。

cudaMalloc不会这样做。您不能要求将设备分配的起始地址存储在设备存储器中。您只能要求将设备分配的起始地址存储在主机内存中。

&d_array

是指向主机内存的指针。

&d_array[i]

是指向设备内存的指针。

现在在cuda tag info link中引用了规范的2D数组工作示例。