使用 OpenCL 或其他 GPGPU 框架在现代 x86 硬件上的 CPU 和 GPU 之间共享数据

Pau*_*zak 5 gpgpu opencl

CPU 和 GPU 硬件的逐步统一,正如 AMD Kaveri 与 hUMA(异构统一内存访问)和英特尔第 4 代 CPU 所证明的那样,应该允许 CPU 和 GPU 之间的无复制数据共享。我想知道,最新的 OpenCL(或其他 GPGPU 框架)实现是否允许在 CPU 和 GPU 上运行的代码之间实现大型数据结构的真正无复制共享(无显式或隐式数据复制)。

jpr*_*ice 5

从 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, ...);
Run Code Online (Sandbox Code Playgroud)

这将创建一个设备缓冲区,从主机向其中写入一些数据,然后使用该缓冲区在设备上运行内核。由于缓冲区的分配方式,如果设备和主机具有统一的内存系统,则不应导致内存传输。


上述方法仅限于简单、扁平的数据结构(一维数组)。如果您对使用更复杂的东西(例如链表、树或任何其他基于指针的数据结构)感兴趣,则需要利用OpenCL 2.0中的共享虚拟内存 (SVM)功能。在撰写本文时,AMD 和 Intel 都发布了一些对 OpenCL 2.0 功能的预览支持,但我不能保证他们的 SVM 实现。

SVM 方法的工作流程与上面列出的代码有些相似。简而言之,您将使用 分配一个缓冲区clSVMAlloc,它将返回一个在主机和设备上均有效的指针。当您希望从主机访问缓冲区并将其传递给设备时,您将使用clEnqueueSVMMapclEnqueueSVMUnmap来同步数据clSetKernelArgSVMPointer。SVM 和CL_MEM_ALLOC_HOST_PTRSVM之间的关键区别在于,SVM 指针也可以包含在传递给设备的另一个缓冲区内(例如,在结构内或由另一个指针指向)。这使您可以构建可在主机和设备之间共享的复杂的基于指针的数据结构。