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

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

6.2. カーネルのベクトル化

より高いスループットを達成するために、カーネルをベクトル化することができます。 カーネルのベクトル化により、Multiple Work-Itemを単一命令複数データ(SIMD)形式で実行することができます。 Intel® FPGA SDK for OpenCL™オフライン・コンパイラーに指示して、カーネル内のスカラー演算(加算や乗算など)をSIMD演算に変換することができます。

カーネルの本体を変更せずに、Work-Itemごとに追加の実行をオフライン・コンパイラーに指示するには、カーネルコードにnum_simd_work_items属性を含めます。次のコードは、ベクトル化係数4を元のカーネルコードに適用します。

__attribute__((num_simd_work_items(4))) __attribute__((reqd_work_group_size(64,1,1))) __kernel void sum (__global const float * restrict a, __global const float * restrict b, __global float * restrict answer) { size_t gid = get_global_id(0); answer[gid] = a[gid] + b[gid]; }

num_simd_work_items属性を使用するには、reqd_work_group_size属性を使用してカーネルの必要なワーク・グループ・サイズを指定する必要があります。reqd_work_group_sizeに指定したワークグループのサイズは、num_simd_work_itemsに割り当てる値で割り切れなければなりません。上記のコード例では、カーネルの作業グループサイズは64であり、ワークグループは固定されています。各ワークグループ内で、Work-Itemは4つのSIMDベクタレーンに均等に分散されます。オフライン・コンパイラーが4つのSIMDベクタレーンを実装した後、各Work-Itemは4倍の作業を実行するようになりました。

オフライン・コンパイラーはコードをベクトル化し、メモリーアクセスを結合する可能性があります。オフライン・コンパイラーはこれらの最適化を自動的に適用するため、カーネルコードまたはホストコードを変更する必要はありません。

カーネルコードを手動でベクトル化できますが、実装するベクトル化の量を反映するように、ホスト・アプリケーションのNDRangeを調整する必要があります。次の例は、カーネル内で動作を手動で複製するときのコードの変更を示しています。

__kernel void sum (__global const float * restrict a, __global const float * restrict b, __global float * restrict answer) { size_t gid = get_global_id(0); answer[gid * 4 + 0] = a[gid * 4 + 0] + b[gid * 4 + 0]; answer[gid * 4 + 1] = a[gid * 4 + 1] + b[gid * 4 + 1]; answer[gid * 4 + 2] = a[gid * 4 + 2] + b[gid * 4 + 2]; answer[gid * 4 + 3] = a[gid * 4 + 3] + b[gid * 4 + 3]; }

この形式では、カーネルは配列abから4つの要素を読み出し、合計を計算し、その結果を配列のanswerに格納します 。 FPGAパイプラインはメモリー内の隣接する場所にデータをロードして格納するため、手動でオフライン・コンパイラーに4つのロードおよびストア動作の各グループを結合させることができます。

重要: 手動最適化を実装した後、各Work-Itemは4倍の作業を処理します。その結果、ホスト・アプリケーションは、元の例の4分の1のNDRangeを使用する必要があります。逆に、オフライン・コンパイラーの自動ベクトル化機能を使用する場合、NDRangeサイズを調整する必要はありません。 num_simd_work_items属性を使用すると、最小限のコード変更でベクトル幅を調整できます。