Opencl 建议在实现零拷贝时使用clEnqueueMapBuffer和clenqueuenmapmeobject的方法

Opencl 建议在实现零拷贝时使用clEnqueueMapBuffer和clenqueuenmapmeobject的方法,opencl,Opencl,我正在使用opencl进行深度学习,张量的输出大小是固定的 在cuda中,我可以通过cudaMallocHost使用零拷贝,这可以在初始化中调用。我可以从主机读取张量的输出,而无需显式调用cudaMemcpy 它非常有效,因为在整个程序执行过程中只调用了一次。我不需要每次转发后都给Cudamalochost打电话 当我尝试在opencl中实现零拷贝时,在一些实现中,当你想读取张量的输出时,每次转发之后,他们都会调用ClenqueueEmapBuffer和clEnqueueUnmapMemObje

我正在使用opencl进行深度学习,张量的输出大小是固定的

在cuda中,我可以通过cudaMallocHost使用零拷贝,这可以在初始化中调用。我可以从主机读取张量的输出,而无需显式调用cudaMemcpy

它非常有效,因为在整个程序执行过程中只调用了一次。我不需要每次转发后都给Cudamalochost打电话

当我尝试在opencl中实现零拷贝时,在一些实现中,当你想读取张量的输出时,每次转发之后,他们都会调用ClenqueueEmapBuffer和clEnqueueUnmapMemObject

下面是示例()

但是我发现,clEnqueueMapBuffer的开销是不可忽略的,有时延迟相当大


这真的是建议的方法吗?我可以在程序的生命周期内只调用一次ClenqueueEmapBuffer,并在程序结束时调用一次ClenqueuenmapMemObject吗?这样做有什么问题吗?

如果您的OpenCL实现支持共享虚拟内存(在2.0中引入),那么该功能允许您执行类似的操作,以及更多操作

对于OpenCL 1.x,除非您的OpenCL实现做出了超出标准的任何保证(我希望它通过扩展来实现),否则您必须在内核获得对缓冲区的写访问权之前取消对缓冲区的映射,同样,在对缓冲区进行写映射时,您也不能允许内核读取缓冲区

下文对此进行了解释:

在设备上执行的内核对映射为写入的内存区域的读写未定义

设备上执行的内核写入内存对象映射区域的行为未定义

在1.2版中,对其进行了扩展,但要点相同:

如果内存对象当前映射为写入,则应用程序必须确保 对象在从该对象读取或写入的任何排队内核或命令之前取消映射 内存对象或其任何关联内存对象(子缓冲区或1D图像缓冲区对象) 或其父对象(如果内存对象是子缓冲区或1D图像缓冲区对象)开始 执行;否则,行为是未定义的

如果内存对象当前映射为读取,则应用程序必须确保 对象在写入此内存对象的任何排队内核或命令之前取消映射 或其任何关联的内存对象(子缓冲区或1D图像缓冲区对象)或其父对象 对象(如果内存对象是子缓冲区或1D图像缓冲区对象)开始执行; 否则,行为是未定义的

如果发现映射/取消映射的开销很高,那么在OpenCL实现中可能没有达到零拷贝代码路径,并且驱动程序实际上是在复制内存内容。如果有疑问,请咨询您的实现供应商,了解他们建议您如何在OpenCL中实现零拷贝缓冲区。标准不保证零拷贝缓冲区。

我创建了一个gist()来验证未定义的行为,但是在没有取消映射操作的情况下,一切都可以工作。你知道原因吗?你不能“验证”未定义的行为。未定义的行为意味着你无法预测将会发生什么。这包括它在某些情况下似乎“正确”工作,但在其他情况下会微妙地中断。此外,例如,GPU驱动程序更新可能会改变行为。