在 CUDA 中,我们可以通过主机内存的设备端指针实现从主机内存到设备共享内存的内核托管数据传输。喜欢这个:
int *a,*b,*c; // host pointers
int *dev_a, *dev_b, *dev_c; // device pointers to host memory
…
cudaHostGetDevicePointer(&dev_a, a, 0); // mem. copy to device not need now, but ptrs needed instead
cudaHostGetDevicePointer(&dev_b, b, 0);
cudaHostGetDevicePointer(&dev_c ,c, 0);
…
//kernel launch
add<<<B,T>>>(dev_a,dev_b,dev_c);
// dev_a, dev_b, dev_c are passed into kernel for kernel accessing host memory directly.
在上面的例子中,内核代码可以通过dev_a
、dev_b
和dev_c
访问主机内存。内核可以利用这些指针将数据从主机直接移动到共享内存,而无需通过全局内存中继它们。
但似乎在 OpenCL 中这是一项不可能完成的任务?(OpenCL 中的本地内存与 CUDA 中的共享内存相对应)
您可以在 OpenCL 中找到完全相同的 API。
它在 CUDA 上的工作原理:
根据此演示文稿和官方文档。
关于cudaHostGetDevicePointer
的金钱报价:
传回由 分配的映射主机内存的设备指针 cudaHostAlloc 或由 cudaHostTRegister 注册。
CUDA 与 cudaHostGetDevicePointer
的 CUDA cudaHostAlloc
的工作方式与 OpenCL 中MapBuffer
CL_MEM_ALLOC_HOST_PTR
完全相同。基本上,如果它是一个独立的GPU,结果将缓存在设备中,如果它是一个与主机共享内存的独立GPU,它将直接使用内存。因此,CUDA 中没有使用离散 GPU 的实际"零复制"操作。
函数cudaHostGetDevicePointer
不接受原始的错位指针,就像 OpenCL 中的限制一样。从 API 用户的角度来看,这两种方法是完全相同的方法,允许实现进行几乎相同的优化。
使用离散 GPU,您获得的指针指向 GPU 可以通过 DMA 直接传输内容的区域。否则,驱动程序将获取指针,将数据复制到 DMA 区域,然后启动传输。
但是,在 OpenCL2.0 中,这显然是可能的,具体取决于设备的功能。通过最精细的粒度共享,您可以使用随机错误定位的主机指针,甚至可以对主机使用原子,因此您甚至可以在主机运行时从主机动态控制内核。
http://www.khronos.org/registry/cl/specs/opencl-2.0.pdf
有关共享虚拟内存规范,请参阅第 162 页。请注意,当你编写内核时,即使从内核的角度来看,这些仍然只是__global指针。