0

我试图了解 CL_MEM_USE_HOST_PTR 和 CL_MEM_COPY_HOST_PTR 的工作原理。基本上当使用 CL_MEM_USE_HOST_PTR 时,比如说在创建 2D 图像时,这不会将任何内容复制到设备,而是 GPU 将参考主机上的映射内存(clEnqueueMapBuffer 映射它),进行处理,我们可以将结果写入其他位置.

另一方面,如果我使用 CL_MEM_COPY_HOST_PTR,它将创建设备上主机 ptr 指向的数据的副本(我猜它会创建一个单独的副本,而不仅仅是缓存)。现在将对复制到设备的数据进行处理,然后将结果再次复制到主机。我希望我理解正确。

所以我的问题是......只是出于我的好奇心,我想这样做。我将使用 CL_MEM_USE_HOST_PTR 现在即使设备可以访问主机内存,我希望 GPU 内核在设备本身上创建一个单独的副本(不使用 COPY_HOST_PTR,因为这再次在主机本身中完成)然后执行处理这些数据。如何才能做到这一点??

4

3 回答 3

1

使用 CL_MEM_READ_WRITE 创建要复制到的缓冲区,但不要在主机上对其进行初始化。我最近不得不为连续整数初始化一个新缓冲区

cl_mem _offsetBuffer;
_offsetBuffer = clCreateBuffer(_context, CL_MEM_READ_WRITE, (size_t)(count * sizeof(cl_int)), NULL, &errorCode);

上面的 clCreateBuffer 除了为您提供内存对象的句柄外,不会对主机的内存做任何事情。然后我使用内核来分配顺序值,因为事实证明显卡上的内存速度比在 cpu 上分配值要快得多。

__kernel void initOffsetBuffer(__global int* offsetBuffer, const int offsetBufferLength, const int startValue){
    int gid = get_global_id(0);
    int gs = get_global_size(0);
    int i;
    for(i=gid;i<offsetBufferLength;i+=gs){
        offsetBuffer[i] = i+startValue;
    }
}

此时主机内存中仍然没有缓冲区的副本。我需要使用 clEnqueueReadBuffer 将其复制到主机。

您可以轻松地将此代码修改为复制内核,而不仅仅是直接赋值。

__kernel void copyBuffer(__global const int* srcBuffer, __global int* dstBuffer, const int bufferLength){
    int gid = get_global_id(0);
    int gs = get_global_size(0);
    int i;
    for(i=gid;i<bufferLength;i+=gs){
        dstBuffer[i] = srcBuffer[i];
    }
}
于 2012-07-08T16:10:02.110 回答
1

OpenCL 缓冲区通常在主机内存中具有其“位”的副本(这是在 OpenCL 规范中调用缓冲区内容的方式)。这是必要的,因为设备内存是有限的,并且这些位通常仅在内核使用时才传输到设备。

当您使用 USE_HOST_PTR 创建缓冲区时,您允许 OpenCL 运行时将 host_ptr 位置用于此主机内存副本。当内核将使用缓冲区时,这些位将被复制到设备中。执行后,您需要确保这些位同步回您的主机内存。这是通过调用 来完成的clEnqueueMapBuffer,该函数返回的指针将在您的主机内存区域内。

当您使用 COPY_HOST_PTR 创建缓冲区时,运行时会分配缓冲区的新主机内存副本,并将您的位复制到其中。通常,此时不会向设备发送任何内容。

于 2012-07-08T18:18:39.837 回答
0

CL_MEM_HOST_PTR - 实际上 cl_mem 对象将在设备上分配内存并复制主机指针指定的数据。对设备端缓冲区对象的任何修改对主机端都是不可见的。

CL_MEM_USE_HOST_PTR - cl_mem 对象使用host_ptr 提供的内存,因此设备可以直接修改分配在主机上的数据,这样我们不涉及任何数据传输。

于 2014-06-17T13:45:24.297 回答