Intel® FPGA SDK for OpenCL™: ベスト・プラクティス・ガイド

ID 683521
日付 12/08/2017
Public
ドキュメント目次

3.1.1. チャネルとパイプの特性

OpenCL™カーネルプログラムにチャネルまたはパイプを実装するには、それぞれの インテル® FPGA SDK for OpenCL™ 特性を考慮してください。

基本動作

チャネルのデフォルト動作はブロックしています。パイプのデフォルト動作はノンブロッキングです。

複数のOpenCLカーネルの同時実行

複数のOpenCLカーネルを同時に実行することができます。同時実行をイネーブルするには、複数のコマンドキューをインスタンス化するようにホストコードを変更します。同時に実行される各カーネルは、別々のコマンド・キューに関連付けられます。

重要:

パイプ固有の考慮事項:

インテル® FPGA SDK for OpenCL™ プログラミング・ガイド他のOpenCL SDKとの互換性の確保に記載されているOpenCLパイプの変更により、SDKでカーネルを実行することができます。ただし、カーネルのスループットを最大化するわけではありません。 OpenCL仕様バージョン2.0では、カーネルが空のパイプからの読み出しを行わないように、パイプ読み出しの前にパイプ書き込みを行う必要があります。その結果、カーネルは同時に実行できません。 インテル® FPGA SDK for OpenCL™ 同時実行をサポートするため、ホスト・アプリケーションとカーネルプログラムを変更してこの機能を使用することができます。この変更により、アプリケーションのスループットが向上します。ただし、カーネルを別のSDKに移植することはできません。この制限にもかかわらず、変更は最小限であり、両方のタイプのコードを維持するために多大な努力を必要としません。

パイプを含むカーネルの同時実行をイネーブルするには、カーネルコードのdepthの属性をblocking属性(つまり、 __attribute __((blocking))に置き換えます。 blockingの属性はread_pipewrite_pipe関数呼び出しにブロッキング動作を紹介します。コールサイトは、パイプの他端が準備完了になるまで、カーネルの実行をブロックします。

blockingの属性とdepthの属性の両方をカーネルに追加すると、パイプが空のときだけread_pipe呼び出しがブロックされ、パイプがいっぱいになったときにwrite_pipe呼び出しがブロックされます。ブロック動作により、カーネル間の暗黙的な同期が行われ、カーネル同士が互いにロックステップで実行されます。

暗黙のカーネル同期

チャネルをブロックするか、パイプの呼び出しをブロックすることで、カーネルを暗黙的に同期させます。次の例を検討してください。

表 5.  カーネル同期のためのチャネルとパイプコールのブロック
ブロッキング・チャネルコールを持つカーネル ブロッキング・パイプ・コールを持つカーネル
channel int c0; __kernel void producer (__global int * in_buf) { for (int i = 0; i < 10; i++) { write_channel_intel (c0, in_buf[i]); } } __kernel void consumer (__global int * ret_buf) { for (int i = 0; i < 10; i++) { ret_buf[i] = read_channel_intel(c0); } }
__kernel void producer (__global int * in_buf, write_only pipe int __attribute__ ((blocking)) c0) { for (int i = 0; i < 10; i++) { write_pipe (c0, &in_buf[i]); } } __kernel void consumer (__global int * ret_buf, read_only pipe int __attribute__ ((blocking)) c0) { for (int i = 0; i < 10; i++) { int x; read_pipe (c0, &x); ret_buf[i] = x; } }

producerカーネルがデータを書き、 consumerカーネルが各ループ反復中にデータを読み込むように、カーネルを同期させることができます。 producerwrite_channel_intelまたはwrite_pipe呼び出しがread_channel_intelまたはread_pipeコールで任意のデータを書き込まない場合、producerが有効なデータを送信するまで(またはその逆)、consumerread_channel_intelまたはread_pipeコールをブロックと待機します。

呼び出し間のデータの永続性

write_channel_intelコールがデータをチャネルに書き込んだり、 write_pipe呼び出しがパイプにデータを書き込んだ後も、データはワークグループおよびNDRange呼び出し間で永続的です。Work-Itemがチャネルまたはパイプに書き込むデータは、別のWork-Itemがそこから読み出されるまでそのチャネルまたはパイプに残ります。さらに、チャネルまたはパイプ内のデータの順序は、そのチャネルまたはパイプへの書き込み動作の順序と等価であり、順序は書き込み動作を実行するWork-Itemとは独立しています。

たとえば、複数のWork-Itemがチャネルまたはパイプに同時にアクセスしようとすると、Single Work-ItemだけがそのWork-Itemにアクセスできます。 write_channel_intelコールまたはwrite_pipeコールは、 DATAXという特定のWork-Itemデータをそれぞれチャネルまたはパイプに書き込みます。同様に、チャンネルまたはパイプにアクセスするための最初のWork-Itemは、そこからDATAXを読み出します。読み書き動作のこの順番は、チャネルとパイプをカーネル間でデータを共有するための有効な方法にします。

課された作業アイテムの注文

SDKは、チャネルまたはパイプの読み書き動作の一貫性を維持するためのWork-Itemの順序を強制します。