c++ - 调用内核后使用 queue.flush() 和 queue.finish() 的正确方法是什么?

标签 c++ kernel opencl

我正在为我的项目使用 opencl 1.2 c++ 包装器。我想知道调用内核的正确方法是什么。在我的例子中,我有 2 个设备,数据应该同时发送给它们。

我将我的数据分成两个 block ,两个设备都应该能够分别对它们执行计算。它们没有互连,也不需要知道其他设备中发生了什么。

当数据被发送到两个设备时,我想在我的程序继续之前等待内核完成。因为我将使用从两个内核返回的结果。所以我不想在内核返回之前开始读取数据。

我有两种方法。在我的案例中,哪一个在编程上是正确的:

方法一:

for (int i = 0; i < numberOfDevices; i++) {
  // Enqueue the kernel.
  kernelGA(cl::EnqueueArgs(queue[iter],
                         arguments etc...);
  queue[i].flush();
}

// Wait for the kernels to return.
for (int i = 0; i < numberOfDevices; i++) {
  queue[i].finish();
}

方法二:

for (int i = 0; i < numberOfDevices; i++) {
  // Enqueue the kernel.
  kernelGA(cl::EnqueueArgs(queue[iter],
                     arguments etc...);
}

for (int i = 0; i < numberOfDevices; i++) {
  queue[i].flush();
}

// Wait for the kernels to return.
for (int i = 0; i < numberOfDevices; i++) {
  queue[i].finish();
}

或者它们都不正确并且有更好的方法来等待我的内核返回?

最佳答案

假设每个设备都在自己的内存中计算:

我会选择你的 method-1 的多线程 (for) 循环版本。因为 opencl 不强制供应商进行异步排队。例如,Nvidia 对某些驱动程序和硬件进行同步排队,而 amd 具有异步排队。

当每个设备由一个单独的线程驱动时,它们应该在同步读取部分结果之前将 Write+Compute 一起入队(第二个线程循环)

拥有多个线程也有利于自旋等待类型同步 (clfinish),因为多个自旋等待循环是并行工作的。这应该可以节省一毫秒的时间。

Flush 帮助 amd 等供应商尽早开始排队。

要使所有设备的输入和输出正确,只需要两个完成命令就足够了。一个在写入+计算之后,然后一个在读取(结果)之后。因此每个设备都获得相同的时间步数据并在相同的时间步产生结果。如果队列类型是有序的,则 Write 和 Compute 不需要在它们之间完成,因为它是一个一个地计算的。此外,这不需要阻塞读取操作。

琐碎的完成命令总是会降低性能。

注意:我已经使用所有这些编写了一个负载均衡器,并且当使用基于事件的同步而不是完成时,它的性能更好。 Finish 比基于事件的完成更容易,但同步时间更长。

此外,单队列并不总是将 GPU 推向极限。每个设备至少使用 4 个队列可确保在我的 amd 系统上隐藏写入和计算的延迟。有时甚至 16 个队列也能提供更多帮助。但对于 io 瓶颈情况可能需要更多。

例子:

 thread1
      Write 
      Compute
      Synchronization with other thread

  Thread2
      Write
      Compute
      Synchronization with other thread




   Thread 1
         Read
         Synchronization with other thread

   Thread2
         Read
         Synchronization with other thread

琐碎的同步会降低性能,因为驱动程序不知道您的意图,他们会保持原样。因此,您应该消除不必要的完成命令,并尽可能将阻塞写入转换为非阻塞写入。

零同步也是错误的,因为 opencl 不会强制供应商在几次入队后开始计算。它可能会在几分钟甚至几秒钟内无限增长到千兆字节的内存。

关于c++ - 调用内核后使用 queue.flush() 和 queue.finish() 的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42096778/

相关文章:

Julia 的 OpenCL BLAS

c++ - 使用 C 对串行 AT 命令的响应较慢,但使用 minicom 响应速度较快

c++ - std::string::reserve 和字符串结尾 0

c - 具有内存映射 I/O 的 C 指针的奇怪行为

linux - iwlist() 命令如何扫描无线网络?

cuda - 在 opencl 中 CPU 作为主机,intel HD 4000 作为设备 1,离散 GPU 作为设备 2

c++ - boost::pool_allocator 需要八个静态库?

c++ - 类中的常量?

linux - Linux内核重新配置和重建后如何更新rootfs?

cpu - 只能用 OpenCL 写吗?