OpenCL:如何在主机和设备缓冲区之间实现并行写入?

3
我有一个很大的cl_mem缓冲区(100百万个浮点数)。 我试图减少从主机填充数据所需的时间(我必须多次从主机传递数据到设备,目前我每次都重新初始化缓冲区)。
与其一遍又一遍地使用clCreateBuffer / CL_MEM_COPY_HOST_PTR进行初始化,似乎更有效的方法是初始化缓冲区一次,然后每次更新其数据时采用多线程方法(因此多个CPU线程同时更新子集的数据)。
这种方法可行吗? 我已经研究了clEnqueueWriteBuffer,虽然它允许更新缓冲区的子集,但似乎仍然会由命令队列按顺序执行多个调用。 我需要多个命令队列吗? 这种方法可行吗?
1个回答

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以某种方式对数据进行预处理/解包,则可以尝试将其转移到设备上。


数据在每次迭代中都不同,因此我不能简单地放弃常量更新。我不确定如何计算传输到设备的理论速度限制,但它是一个PCI-E 3.0连接到NVidia 1080ti GPU...所以我只是假设我能够从中挤出更多的性能,因为它相当强大,但你可能是对的,我已经达到了极限。我将在计算过程中尝试更多连续的异步复制(您的第三段)...但总体而言,我更想知道是否可以同时进行多个副本以并行传输数据... - Tyson
@Tyson 如果您使用了完整的16条PCIe 3.0通道,那么您的理论极限略低于16GB/s。在具有多个PCIe x16插槽的消费者或小型工作站系统上,如果占用了2个插槽,则通常只会获得8条通道,这将使最大带宽减半。 - pmdj
你认为进一步追求我试图实现的优化(并行传输)会有好处吗?或者在你看来,对于一个浮点向量进行同步的clCreateBuffer调用已经是最快的方式了(忽略像随着数据计算而进行的连续调用clEqueueWriteBuffer这样的优化)。换句话说,如果你有一个1亿个浮点数的数组,并且必须将其一次性传输到GPU上,你是否认为单个clCreateBuffer调用是绝对最快的方式,无论你使用多少CPU核心? - Tyson
1
我可能会尝试两种方法:(1)使用clEqueueWriteBuffer()的异步变体,尝试通过在此期间在CPU上执行其他任务来隐藏上传时间;(2)使用或不使用CL_MEM_ALLOC_HOST_PTR分配内存,使用clEnqueueMapBuffer()映射内存,并直接将其用作在CPU上生成/加载100百万个浮点数的目标数组。在使用内核之前不要忘记取消映射。版本(2)几乎肯定会在具有统一内存的集成GPU上击败任何其他东西(测试CL_DEVICE_HOST_UNIFIED_MEMORY)。 - pmdj
1
你的1080Ti没有UMA,因此在很大程度上,最好的工作方式将取决于其他所有因素:内存访问模式,100M浮点数来自哪里(生成/加载它们所需的时间是否与VRAM上传相当或更长?) - pmdj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接