【问题标题】:OpenCL: parrallel write from host to device buffer?OpenCL:从主机到设备缓冲区的并行写入?
【发布时间】:2019-05-05 04:03:08
【问题描述】:

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

与其一遍又一遍地使用 clCreateBuffer/CL_MEM_COPY_HOST_PTR 进行初始化,似乎将缓冲区初始化一次,然后每次使用多线程方法更新其数据(因此多个 CPU 线程每次更新数据)。

这样的方法可行吗?我研究了 clEnqueueWriteBuffer,虽然它允许更新缓冲区的子集,但似乎对它的多次调用仍将由命令队列按顺序执行。我需要多个命令队列吗?这种方法甚至可能吗?

【问题讨论】:

    标签: c++ buffer opencl


    【解决方案1】:

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

    您的测量结果是否表明您不受 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 以某种方式对数据进行预处理/解包,您可以尝试将其卸载到设备上。

    【讨论】:

    • 每次迭代的数据都不一样,所以我不能简单地放弃不断更新。我不完全确定如何计算传输到设备的理论速度限制,但它是与 NVidia 1080ti GPU 的 PCI-E 3.0 连接……所以我只是假设我能够多榨一点果汁退出它,因为它相当强大,但你可能是对的,我已经到了极限。我将在计算期间对连续的异步副本进行更多实验(您的第 3 段)...但总体而言,我更想知道我是否可以同时进行多个副本以并行传输数据...
    • @Tyson 如果您使用 PCIe 3.0 的全部 16 条通道,那么您的理论限制略低于 16GB/s。在具有多个 PCIe x16 插槽的消费类或小型工作站系统上,如果占用 2 个插槽,通常只能获得 8 个通道,这会使最大带宽减半。
    • 那么您会看到进一步追求我想要实现的优化(并行传输)的好处吗?或者在您看来,在浮点向量上同步 clCreateBuffer 调用的速度与事情的速度一样快(忽略优化,如在计算数据时对 clEqueueWriteBuffer 进行渐进式调用)。换句话说,如果给你一个 1 亿浮点数组并且必须将它放到 GPU 上一次,你会认为单次调用 clCreateBuffer 是绝对最快的方法,而不管你使用多少 CPU 内核?跨度>
    • 我可能会同时尝试两个:(1)clEqueueWriteBuffer() 的异步变体,同时尝试通过在 CPU 上执行其他操作来隐藏上传时间; (2) 分配内存 (a) 或 (b) 不使用 CL_MEM_ALLOC_HOST_PTR,使用 clEnqueueMapBuffer() 映射内存并直接将其用作目标数组,用于在 CPU 上生成/加载 1 亿个浮点数。在将缓冲区与内核一起使用之前,不要忘记取消映射。版本 (2) 几乎肯定会在具有统一内存的集成 GPU 上击败其他任何东西(测试 CL_DEVICE_HOST_UNIFIED_MEMORY)。
    • 您的 1080Ti 没有 UMA,因此在很大程度上,最有效的方法取决于其他一切:内存访问模式,100M 浮点数来自何处(生成/加载它们是否需要一定数量与 VRAM 上传相比或更长的时间?)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-17
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 2021-07-29
    • 1970-01-01
    相关资源
    最近更新 更多