2

我对在 AMD GPU(夏威夷核心或 Radeon R9 390)上使用 OpenCL 的一些性能感到有点不知所措。

操作如下:

  • 将内存对象 #1 发送到 GPU
  • 执行内核#1
  • 将内存对象 #2 发送到 GPU
  • 执行内核#2
  • 将内存对象 #3 发送到 GPU
  • 执行内核#3

依赖是:

  • 内存对象 #1 上的内核 #1
  • 内存对象 #2 上的内核 #2 以及内核 #1 的输出内存
  • 内存对象 #3 上的内核 #3 以及内核 #1 和 #2 的输出内存

内存传输和内核执行在两个独立的命令队列中执行。命令依赖由 OpenCL 中定义的 GPU 事件完成。

整个操作现在循环,只是为了使用相同的输入数据进行性能分析。

CodeXL 时间线

正如您在时间线中看到的,主机在 GPU 上等待很长时间才能完成 clWaitForEvents(),而 GPU 大部分时间都处于空闲状态。您还可以看到重复的操作。为方便起见,我还提供了所有已发布 OpenCL 命令的列表。

CodeXL 命令

我现在的问题是:

  1. 为什么GPU闲置这么多?在我的脑海中,我可以轻松地将所有“蓝色”项目组合在一起并立即开始操作。内存传输为 6 GB/s,这是预期的速率。

  2. 为什么内核执行得这么晚?为什么内核 #2 和内核 #3 执行之间存在差距?

  3. 为什么内存传输和内核不并行执行?我使用 2 个命令队列,只有 1 个队列,性能更差。

只需将所有命令放在我的脑海中(当然要保持依赖关系,所以第一个绿色必须在第一个蓝色之后开始),我可以将性能提高三倍。我不知道为什么GPU如此缓慢。有没有人有一些见识?


一些数字运算

  • 内存传输 #1 为 253 µs
  • 内存传输 #2 为 120 µs
  • 内存传输#3 为 143 µs - 由于未知原因,它总是太高,它应该是 #2 的 1/2 或在 70-80 µs 范围内

  • 内核 #1 为 74 µs

  • 内核 #2 为 95 µs
  • 内核 #3 为 107 µs

因为内核 #1 比内存传输 #2 快,内核 #2 比内存传输 #3 快,所以总时间应该是:

  • 253 µs + 120 µs + 143 µs + 107 µs = 623 µs

但 clWaitForEvents 是

  • 1758 µs - 或大约 3 倍

是的,有一些损失,我可以接受 10% (60 µs),但 300% 太多了。

4

1 回答 1

2

正如@DarkZeros 所说,您需要通过使用多个命令队列在时间线上重叠它们来隐藏内核队列开销。

为什么GPU闲置这么多?

因为您正在使用 2 个命令队列,并且它们正在串行运行(可能)带有使它们等待更长时间的事件。

如果一切都是串行的,您应该使用单个队列。如果您可以添加双缓冲或类似技术来推进计算,您应该让两个队列重叠操作。

为什么内核执行得这么晚?

宽洞由主机端延迟组成,例如排队命令、向设备刷新命令、主机端算法和设备端事件控制逻辑。也许事件可以小到 20-30 微秒,但主机-设备交互不止于此。

如果您摆脱事件并使用单个队列,驱动程序甚至可以添加早期计算技术来填补这些空白,甚至在您将这些命令排入队列之前(可能),就像 CPU 进行早期分支(预测)一样。

为什么内存传输和内核不并行执行?

没有强制执行,但驱动程序还可以检查内核和副本之间的依赖关系并保持数据完整,他们可以暂停一些操作,直到其他一些操作完成(也许)。

您确定内核和缓冲区副本是完全独立的吗?

另一个原因可能是两个队列没有太多选择重叠。如果两个队列都有两种类型的操作,它们将有更多的重叠选项,例如内核+内核、复制+复制,而不仅仅是内核+复制。


如果程序有太多的小内核,你可以尝试 OpenCL 2.0 动态并行,它使设备调用内核本身比主机端排队更快。

也许您可以添加更高级别的并行性,例如图像级并行性(如果您进行图像处理)以保持 gpu 忙碌。同时处理 5-10 个图像,这应确保独立的内核/缓冲区执行,除非所有图像都在同一个缓冲区中。如果这不起作用,那么您可以启动 5-10 个相同程序的进程(进程级并行性)。但是有太多的上下文可能会受到驱动程序的限制,因此图像级别的并行性必须更好。

R9 390 必须能够处理 8-16 个命令队列。

1758 微秒

有时即使是空内核也会等待 500-100 µs。很可能您应该排队 1000 个周期,最后等待一次。如果每个循环在用户单击按钮后工作,那么用户就不会注意到 1.7 毫秒的延迟。


  • 使用许多队列。
  • 摆脱队列之间的事件(如果有的话)。
  • 让每个队列做各种工作。
  • 在主机端的单个等待事件之前进行多次迭代。
  • 如果存在 OpenCL 2.0,也可以尝试设备端入队,但这仅适用于内核执行,不适用于与主机之间的副本。
于 2017-07-13T16:18:10.453 回答