从版本 1.0 开始,OpenCL 就可以通过以下方式在主机和设备之间共享数据而无需任何内存传输:CL_MEM_ALLOC_HOST_PTR
旗帜。该标志为设备分配一个缓冲区,但确保它位于主机也可以访问的内存中。这些“零拷贝”传输的工作流程通常采用以下形式:
// Allocate a device buffer using host-accessible memory
d_buffer = clCreateBuffer(context, CL_MEM_ALLOC_HOST_PTR, size, NULL, &err);
// Get a host-pointer for the buffer
h_buffer = clEnqueueMapBuffer(queue, d_buffer, CL_TRUE, CL_MAP_WRITE,
0, size, 0, NULL, &err);
// Write data into h_buffer from the host
...
// Unmap the memory buffer
clEnqueueUnmapMemObject(queue, d_buffer, h_buffer, 0, NULL, NULL);
// Do stuff with the buffer on the device
clSetKernelArg(kernel, 0, sizeof(cl_mem), &d_buffer);
clEnqueueNDRangeKernel(queue, kernel, ...);
这将创建一个设备缓冲区,从主机向其中写入一些数据,然后在设备上使用该缓冲区运行内核。由于缓冲区的分配方式,如果设备和主机具有统一的内存系统,则不应导致内存传输。
上述方法仅限于简单、平面的数据结构(一维数组)。如果您有兴趣使用更复杂的东西,例如链表、树或任何其他基于指针的数据结构,您将需要利用共享虚拟内存 (SVM)OpenCL 2.0 中的功能。在撰写本文时,AMD 和 Intel 都发布了对 OpenCL 2.0 功能的一些预览支持,但我不能保证他们的 SVM 实现。
SVM 方法的工作流程与上面列出的代码有些相似。简而言之,您将使用分配一个缓冲区clSVMAlloc
,它将返回一个在主机和设备上都有效的指针。你将使用clEnqueueSVMMap
and clEnqueueSVMUnmap
当您希望从主机访问缓冲区时同步数据,以及clSetKernelArgSVMPointer
将其传递给设备。 SVM 和 SVM 之间的关键区别CL_MEM_ALLOC_HOST_PTR
SVM 指针也可以包含在传递给设备的另一个缓冲区内(例如,在结构内或由另一个指针指向)。这允许您构建可以在主机和设备之间共享的复杂的基于指针的数据结构。