【发布时间】:2012-03-07 17:28:22
【问题描述】:
我正在做一个项目,我需要我的 CUDA 设备对包含指针的结构进行计算。
typedef struct StructA {
int* arr;
} StructA;
当我为结构分配内存然后将其复制到设备时,它只会复制结构而不是指针的内容。现在我正在通过首先分配指针来解决这个问题,然后将主机结构设置为使用该新指针(位于 GPU 上)。以下代码示例使用上面的结构描述了这种方法:
#define N 10
int main() {
int h_arr[N] = {1,2,3,4,5,6,7,8,9,10};
StructA *h_a = (StructA*)malloc(sizeof(StructA));
StructA *d_a;
int *d_arr;
// 1. Allocate device struct.
cudaMalloc((void**) &d_a, sizeof(StructA));
// 2. Allocate device pointer.
cudaMalloc((void**) &(d_arr), sizeof(int)*N);
// 3. Copy pointer content from host to device.
cudaMemcpy(d_arr, h_arr, sizeof(int)*N, cudaMemcpyHostToDevice);
// 4. Point to device pointer in host struct.
h_a->arr = d_arr;
// 5. Copy struct from host to device.
cudaMemcpy(d_a, h_a, sizeof(StructA), cudaMemcpyHostToDevice);
// 6. Call kernel.
kernel<<<N,1>>>(d_a);
// 7. Copy struct from device to host.
cudaMemcpy(h_a, d_a, sizeof(StructA), cudaMemcpyDeviceToHost);
// 8. Copy pointer from device to host.
cudaMemcpy(h_arr, d_arr, sizeof(int)*N, cudaMemcpyDeviceToHost);
// 9. Point to host pointer in host struct.
h_a->arr = h_arr;
}
我的问题是:这样可以吗?
这似乎是一项非常艰巨的工作,我提醒您这是一个非常简单的结构。如果我的结构体包含大量指针或本身带有指针的结构体,分配和复制的代码将相当冗长和混乱。
【问题讨论】:
-
第 7 步和第 9 步是多余的,否则就是这样。正如下面的答案所说,最好避免在 GPU 上使用基于指针的复杂数据结构。 GPU 上的性能更差,而且 API 确实不是为它设计的。
-
我可以看到第7步是多余的,但是为什么第9步呢?
-
h_a是(或应该是)主机内存中保存的设备结构的“图像”。分配它以在主机内存中保存指针可能是不良做法/错误/设备内存泄漏的某种组合,具体取决于您的真实意图。将d_a的内容复制回h_a后,您“绕了一圈”,又回到了起点。 -
但为了将结构正确复制到设备,我必须将
h_a的指针设置为d_arr(步骤4)。因此,当我将数据复制回来时,我还必须将h_a中的指针设置为我刚刚复制到的数组。我同意在上面的示例中第 7 步是多余的,因为结构中没有其他信息,但如果有该步骤就不会是多余的。或者我完全错了吗? -
感谢 tahatmat,为我们提供了这种跨主机和设备内存来回复制结构的模式。但是我认为值得一提的是第二种方式,这似乎更一致,有助于避免实施第 9 步。函数 cudaMemcpy() 的具体特性实际上允许以这种方式取消引用主机代码中的设备指针:您跳过第 4 步并在复制之后在第 5 步将 h_a 复制到 d_a,您手动将每个设备指针地址复制到 d_a,如下所示:cudaMemcpy(&(d_a->arr), &(d_arr), sizeof(int*), cudaMemcpyHostToDevice)。同样,“d_a->arr”是合法的
标签: pointers struct cuda device host