如何在OpenCL中使用固定内存/映射内存

kri*_*isg 18 memory gpu data-transfer gpgpu opencl

为了减少我的应用程序从主机到设备的传输时间,我想使用固定内存.NVIDIA的最佳实践指南建议使用以下代码映射缓冲区并写入数据:

cDataIn = (unsigned char*)clEnqueueMapBuffer(cqCommandQue, cmPinnedBufIn, CL_TRUE,CL_MAP_WRITE, 0, memSize, 0, NULL, NULL, NULL);

for(unsigned int i = 0; i < memSize; i++) 
{ 
    cDataIn[i] = (unsigned char)(i & 0xff); 
}

clEnqueueWriteBuffer(cqCommandQue, cmDevBufIn, CL_FALSE, 0, 
szBuffBytes, cDataIn, 0, NULL, NULL);
Run Code Online (Sandbox Code Playgroud)

英特尔的优化指南建议使用对clEnqueueMapBuffer和clEnqueueUnmapBuffer的调用,而不是调用clEnqueueReadBuffer或clEnqueueWriteBuffer.

使用固定内存/映射内存的正确方法是什么?是否有必要使用enqueueWriteBuffer写入数据或者enqueueMapBuffer是否足够?

另外,CL_MEM_ALLOC_HOST_PTR和CL_MEM_USE_HOST_PTR之间有什么区别?

Dar*_*ros 14

这是一个很有趣的话题,很少有人详细介绍.我将尝试准确定义它的工作原理.

固定存储器指的是存储器以及存在于存储器中的存储器,因此在这两个存储器之间可以进行DMA写入.提高复制性能.这就是为什么它需要CL_MEM_ALLOC_HOST_PTR缓冲区创建参数.

另一方面,CL_MEM_USE_HOST_PTR将采用主机指针来创建缓冲区,规范还不清楚这是否可以是固定内存.但一般来说,它不应该是以这种方式创建的固定内存,因为主机指针尚未被OpenCL API保留,并且不清楚它驻留在内存中的何处.


关于地图/阅读问题.两者都可以.他们将提供相同的表现.这两种技术之间的区别在于:

  • 对于Map/Unmap:您需要在写入/读取之前进行映射,然后取消映射.这样就可以确保数据的一致性.这些是API调用,需要时间来完成以及异步.好处是,你不需要保存任何其他东西而不是缓冲对象.
  • 对于Map +读/写:在创建内存区时,您需要执行Map并保存指针值.然后,在破坏缓冲区时,您需要首先取消映射然后销毁它.你需要一直保持buffer+Mapped_Buffer.好处是你现在可以只clEnqueueRead/Write使用那个映射指针.API将等待固定数据保持一致,然后考虑完成.它更容易使用,因为它就像一次性执行map + unmap.

读/写模式更易于使用,特别适用于重复读取,但不像手动地图选项那样通用,因为您不能写read only地图,也不能读write only地图.但是对于一般用途,读取的变量永远不会被写入,反之亦然.


我的理解是英特尔建议,指的是"使用Map,而不是普通的读/写",而不是"当你使用Map时,不要使用Map/Write over Writeped".

您是否通过英特尔硬件检查此nVIDIA推荐?我认为它应该有效,但是我不知道该操作是否确实是最佳的(如在AMD或nVIDIA HW中).

  • 确实很奇怪,您需要同时使用clEnqueueWriteBuffer()和Map / Unmap。由于执行Map并更改主机指针时,实际上是在更改CPU和GPU数据。取消映射后,数据将在CPU和GPU端之间同步。我不理解您是否需要在MAP + change cDataIn和UNMAP之间执行clEnqueueWriteBuffer。很奇怪... (2认同)