在我读过的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
答案 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数组工作示例。