OpenCL:从主机并行写入设备缓冲区?

时间:2018-12-03 19:50:51

标签: c++ buffer opencl

我有一个很大的cl_mem缓冲区(浮点数为1亿)。我正在尝试减少用主机数据填充数据所花费的时间(我必须多次将数据从主机传递到设备,并且目前每次都重新初始化缓冲区)。

与其一遍又一遍地使用clCreateBuffer / CL_MEM_COPY_HOST_PTR初始化,似乎更有效的方法是初始化一次缓冲区,然后在以后每次使用多线程方法更新其数据(因此,多个CPU线程各自更新以下子集)数据)。

这种方法可行吗?我研究了clEnqueueWriteBuffer,虽然它允许更新缓冲区的一个子集,但似乎仍然可以通过命令队列顺序地对其进行多次调用。我需要多个命令队列吗?这种方法有可能吗?

1 个答案:

答案 0 :(得分:0)

从您的问题尚不清楚,每次初始化/更新是否相同,或者两次运行之间是否需要更新整个缓冲区。显然,最快速的方法是消除重复的工作,并且不要多次复制相同的数据。

您的测量结果是否表明您不受CPU和设备之间的接口的限制?因为如果您每次需要复制N MB,设备通过B MB / s接口连接到CPU /系统内存,并且复制时间不超过N / B秒,那么多线程就无济于事你。

如果您受到某些CPU计算的顺序性质以及随后复制到缓冲区的限制,则可以使用clEnqueueWriteBuffer()的异步变体开始复制第一个数据块,同时计算下一个数据块,依此类推。请注意,clEnqueueWriteBuffer() / CL_MEM_COPY_HOST_PTR通常利用设备的DMA引擎,该引擎通常不需要主机CPU的大量干预,因此可以与计算完全并行运行。 (主机内存带宽当然总是共享的。)

如果这对于您而言太麻烦了,那么使用clEnqueueMapBuffer将缓冲区映射到主机应用程序的地址空间可能会很有用。这允许任意数量的线程同时访问它的任意区域。但是请注意,这并不是灵丹妙药,除非您的OpenCL实现明确指定了实践中的实现方式,否则可能会使您实际上情况变得更糟,因为它可能最终会复制更多 比以前更重要。

如果您的设备内核实际上并没有最终读取所有缓冲区(并且您只是事先不知道它将需要哪些部分),或者有可能如果它们仅精确地读取了全部缓冲区,那么和可预测的模式,但是您的主机代码需要读写很多或写入随机位置,则可以尝试使用CL_MEM_USE_HOST_PTR创建的缓冲区。这并非在所有实现中都是零复制的,但其目的是使设备直接访问主机内存。再次受到设备上行链路接口带宽的限制,并且延迟通常比设备内存差很多,但是如果您的设备实际上不需要读取所有内容,则可以更快,因为您不必推送整个缓冲区沿着管道。

最后,如果您的CPU正在以某种方式预处理/解压缩数据,则可以尝试将其卸载到设备上。