CUDA双指针内存拷贝

5
我将我的示例代码编写如下。
int ** d_ptr;
cudaMalloc( (void**)&d_ptr, sizeof(int*)*N );

int* tmp_ptr[N];
for(int i=0; i<N; i++)
    cudaMalloc( (void**)&tmp_ptr[i], sizeof(int)*SIZE );
cudaMemcpy(d_ptr, tmp_ptr, sizeof(tmp_ptr), cudaMemcpyHostToDevice);

这段代码运行良好,但是在内核启动后,我无法接收到结果。

int* Mtx_on_GPU[N];
cudaMemcpy(Mtx_on_GPU, d_ptr, sizeof(int)*N*SIZE, cudaMemcpyDeviceToHost);

此时,出现了段错误(segment-fault-error)。但是我不知道哪里出错了。

int* Mtx_on_GPU[N];
for(int i=0; i<N; i++)
    cudaMemcpy(Mtx_on_GPU[i], d_ptr[i], sizeof(int)*SIZE, cudaMemcpyDeviceToHost);

这段代码也存在相同的错误。

我认为我的代码肯定有些错误,但是我整天都找不到它。

给我一些建议。

1个回答

11

在最后一行

cudaMemcpy(Mtx_on_GPU[i], d_ptr[i], sizeof(int)*SIZE, cudaMemcpyDeviceToHost);

你正在尝试将数据从设备复制到主机(注意:我假设您已为Mtx_on_GPU指针分配了主机内存!)。

然而,这些指针存储在设备内存中,因此您无法直接从主机端访问它们。该行代码应该是:

cudaMemcpy(Mtx_on_GPU[i], temp_ptr[i], sizeof(int)*SIZE, cudaMemcpyDeviceToHost);
这在使用“过于繁琐”的变量名称时可能会更清晰:
int ** devicePointersStoredInDeviceMemory;
cudaMalloc( (void**)&devicePointersStoredInDeviceMemory, sizeof(int*)*N);

int* devicePointersStoredInHostMemory[N];
for(int i=0; i<N; i++)
    cudaMalloc( (void**)&devicePointersStoredInHostMemory[i], sizeof(int)*SIZE );

cudaMemcpy(
    devicePointersStoredInDeviceMemory, 
    devicePointersStoredInHostMemory,
    sizeof(int*)*N, cudaMemcpyHostToDevice);

// Invoke kernel here, passing "devicePointersStoredInDeviceMemory"
// as an argument
...

int* hostPointersStoredInHostMemory[N];
for(int i=0; i<N; i++) {
    int* hostPointer = hostPointersStoredInHostMemory[i]; 
    // (allocate memory for hostPointer here!)

    int* devicePointer = devicePointersStoredInHostMemory[i];

    cudaMemcpy(hostPointer, devicePointer, sizeof(int)*SIZE, cudaMemcpyDeviceToHost);
}

回应评论所说的内容:

d_ptr 是 "指针数组"。但是这个数组的内存是使用 cudaMalloc 分配的,这意味着它位于设备上。相比之下,使用 int* Mtx_on_GPU[N];主机内存中 "分配"了 N 个指针。你也可以使用 malloc 来指定数组大小。当你比较下面的分配时,可能会更清楚。

int** pointersStoredInDeviceMemory;
cudaMalloc((void**)&pointersStoredInDeviceMemory, sizeof(int*)*N);

int** pointersStoredInHostMemory;
pointersStoredInHostMemory = (void**)malloc(N * sizeof(int*));

// This is not possible, because the array was allocated with cudaMalloc:
int *pointerA = pointersStoredInDeviceMemory[0];

// This is possible because the array was allocated with malloc:    
int *pointerB = pointersStoredInHostMemory[0];

跟踪指针所存储的内存类型以及指针所指向的内存类型可能有点令人费解,但幸运的是,它很少超过2次间接引用。


哦,天啊。它明显运行良好。谢谢!但我有一些疑问。d_ptr和tmp_ptr都使用cudaMalloc,为什么我可以访问tmp_ptr,而无法访问d_ptr? - Umbrella
@Umbrella 我添加了一个编辑,现在可能更清晰了。 - Marco13
非常清晰明了。做得好! - BillD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接