诸如数据库分析等应用所含的数据集大小远超加速器件上可用的全局器件存储器中可存储的量。此类应用要求以块的形式来传输和处理完整的数据。将数据传输与计算加以重叠的技巧对于为这类应用实现高性能而言,显得至关重要。
在 GitHub 的 Vitis 加速示例的主机类别下的重叠示例的 vadd
内核中可找到相应的示例。此示例演示了在应用中重叠主机 (CPU) 与 FPGA 计算的技巧。在此示例中,内核对 2 个阵列的处理方式是将其添加到一起并写入输出。从主机角度来看,在此示例中执行 4 项任务:
- 写入缓冲器 a (
Wa
) - 写入缓冲器 b (
Wb
) - 执行
vadd
内核 - 读取缓冲器 c (
Rc
)
如果使用简单的按顺序执行命令队列(无数据传输最优化),整个执行时间线轨迹应如下所示:
如果使用无序命令队列,则数据传输和内核执行可以重叠,如下图所示。在此示例的主机代码中,针对所有缓冲器使用双重缓冲,以便在内核处理一组缓冲器的同时,主机可以在另一组缓冲器上运行。
OpenCL
event
对象提供了一种简单的方法,可用于设置复杂的操作依赖关系并同步主机线程和器件操作。事件均为 OpenCL 对象,可追踪操作状态。事件对象是由存储器对象上的内核执行命令 read
、write
和 copy
命令或者使用 clCreateUserEvent
创建的用户事件来创建的。
您可通过查询这些命令返回的事件来确保操作完成。下图中的箭头演示了如何设置事件触发以实现最优性能。
在此示例中,主机代码 (
host.cpp
) 通过一个循环来对这 4 项任务进行排队,以便处理整个数据集。它还会设置不同任务之间的事件同步,以确保满足每项任务的数据相依赖关系。通过将不同存储器对象值传递给 clEnqueueMigrateMemObjects
API 即可设置双重缓冲。事件同步可通过让每个 API 调用等待其他事件以及在 API 完成时触发其自己的事件来予以实现。
以下“Timeline Trace”(时间线轨迹)视图清晰展示了数据传输时间被完全隐藏,而计算单元 vadd_1
则持续运行的过程。