データベース分析のようなアプリケーションでは、アクセラレーション デバイスで使用可能なグローバル デバイス メモリよりも大きなデータ セットが使用され、データ全体をブロック単位で転送して処理する必要があります。これらのアプリケーションで優れたパフォーマンスを達成するには、データ転送と計算をオーバーラップさせる手法が必要となります。
この例は、GitHub の Vitis Accelerated Examples の host カテゴリにある overlap 例からの vadd
カーネルのものです。この例は、アプリケーションでホスト (CPU) と FPGA の計算をオーバーラップさせる手法を示します。カーネルは 2 つの配列をまとめて追加し、出力に書き込んでいます。この例では、ホストで実行する必要のあるタスクは次の 4 つです。
- バッファー a の書き込み (
Wa
) - バッファー b の書き込み (
Wb
) -
vadd
カーネルの実行 - バッファー c の読み出し (
Rc
)
データ転送の最適化をせずに単純な順番どおりのコマンド キューを使用すると、実行タイムライン全体のトレースは次のようになります。
順不同コマンド キューを使用すると、次の図に示すように、データ転送とカーネル実行をオーバーラップできます。この例のホスト コードでは、カーネルが 1 セットのバッファーを処理している間に、ホストでもう 1 つのバッファーのセットを処理できるように、すべてのバッファーにダブル バッファリングが使用されます。
OpenCL
event
オブジェクトを使用すると、複雑な操作依存を簡単に設定して、ホスト スレッドとデバイス動作を同期できます。イベントは、操作のステータスを調べるための OpenCL オブジェクトです。イベント オブジェクトは、read
、write
、およびメモリ オブジェクトの copy
コマンドで作成されるか、clCreateUserEvent
を使用して作成されたユーザー イベントです。
これらのコマンドで返されるイベントをクエリすることにより、操作が完了したかどうかを確認できます。次の図の矢印は、最適なパフォーマンスを達成するために、イベント トリガーをどのように設定できるかを示しています。
例では、ホスト コード (
host.cpp
) は、ループ内の 4 つのタスクをエン キューしてデータ セット全体を処理します。また、各タスクのデータ依存が満たされるように、異なるタスク間のイベント同期を設定します。ダブル バッファリングは、異なるメモリ オブジェクト値を clEnqueueMigrateMemObjects
API に渡すことにより設定します。イベント同期は、各 API 呼び出しがほかのイベントを待ち、その API が終了してからそれ自身のイベントをトリガーするようにすると達成できます。
次に示す [Timeline Trace] ビューでは、計算ユニット vadd_1
が継続的に実行されており、データ転送時間は完全に隠されています。