【问题标题】:Proper use of cudaMalloc3D with cudaMemcpy正确使用 cudaMalloc3D 和 cudaMemcpy
【发布时间】:2013-05-10 10:17:57
【问题描述】:

我想在每个维度上发送一个大小为 size 的 3D 数组 src,将其展平为大小为 length = size * size * size 的一维数组,然后发送到内核中,计算结果并将其存储在 dst 中。但是,最后,dst 不正确地包含全 0。这是我的代码:

int size = 256;
int length = size * size * size;
int bytes = length * sizeof(float);

// Allocate source and destination arrays on the host and initialize source array

float *src, *dst;
cudaMallocHost(&src, bytes);
cudaMallocHost(&dst, bytes);
for (int i = 0; i < length; i++) {
    src[i] = i;
}

// Allocate source and destination arrays on the device

struct cudaPitchedPtr srcGPU, dstGPU;
struct cudaExtent extent = make_cudaExtent(size*sizeof(float), size, size);
cudaMalloc3D(&srcGPU, extent);
cudaMalloc3D(&dstGPU, extent);

// Copy to the device, execute kernel, and copy back to the host

cudaMemcpy(srcGPU.ptr, src, bytes, cudaMemcpyHostToDevice);
myKernel<<<numBlocks, blockSize>>>((float *)srcGPU.ptr, (float *)dstGPU.ptr);
cudaMemcpy(dst, dstGPU.ptr, bytes, cudaMemcpyDeviceToHost);

为了清楚起见,我省略了对cudaMallocHost()cudaMalloc()cudaMemcpy() 的错误检查。在任何情况下,这段代码都不会触发错误。

cudaMalloc3D()cudaMemcpy() 的正确用法是什么?

如果我也应该发布内核的最小测试用例,或者是否可以在上面的代码中找到问题,请告诉我。

【问题讨论】:

标签: cuda


【解决方案1】:

编辑:如果使用 CUDA 数组,则范围占用元素数,但如果不使用 CUDA 数组,则有效占用字节数(例如,分配有cudaMalloc 的某些非数组变体的内存)

来自the Runtime API CUDA documentation

extent 字段定义了元素中传输区域的尺寸。如果 CUDA 数组参与复制,则根据该数组的元素定义范围。如果没有 CUDA 数组参与复制,则范围在 unsigned char

的元素中定义

另外,cudaMalloc3D 返回一个 pitched 指针,这意味着它至少具有您提供的范围的尺寸,但出于对齐原因可能更多。在访问设备内存和从设备内存复制数据时,您必须考虑到这一点。有关cudaPitchedPtr 结构的文档,请参阅here

至于使用cudaMalloc3DcudaMemcpy,您可能想看看使用cudaMemcpy3D (documentation here),它可能会让您的生活更轻松一些,以了解您的主机和设备内存的间距考虑到。要使用cudaMemcpy3D,您必须使用适当的信息创建一个cudaMemcpy3DParms 结构。它的成员是:

cudaArray_t dstArray
struct cudaPos dstPos
struct cudaPitchedPtr dstPtr
struct cudaExtent extent
enumcudaMemcpyKind kind
cudaArray_t srcArray
struct cudaPos srcPos
struct cudaPitchedPtr srcPtr

并且您必须指定srcArray srcPtr 之一和dstArray dstPtr 之一。此外,文档建议在使用之前将结构初始化为 0,例如 cudaMemcpy3DParms myParms = {0};

另外,你可能有兴趣看看这个other SO question

【讨论】:

  • 我可以使用 srcGPU 作为 dstPtr,但我应该使用什么作为 srcArray 或 srcPtr?我从 float *src 复制,它既不是 cuda 数组也不是 cuda 倾斜指针。
  • @1'' 我会尝试为您的src 指针创建一个cudaPitchedPtr,步幅与您的宽度相同
  • 好主意,我会试试的。但是,我没有错误检查内核本身,它在当前代码中给出了错误“无效参数”。为什么我不能将 srcPtr.ptr 和 dstPtr.ptr 传递给期望浮点 * 的内核?
  • 自己传递原始指针当然是有效的(尽管您也希望将它们的步幅传递进去)。您的启动参数numBlocks, blockSize 是否可能无效?
  • 啊,很好理解那个,我没有读过整段。我将编辑我的答案,以包含将来提出此问题的任何人的全部报价
猜你喜欢
  • 2022-07-12
  • 2013-11-13
  • 2013-05-12
  • 1970-01-01
  • 1970-01-01
  • 2017-10-09
  • 1970-01-01
  • 2016-09-02
  • 1970-01-01
相关资源
最近更新 更多