インテルのみ表示可能 — GUID: ewa1397066666833
Ixiasoft
1.3. シングル・ワーク・アイテム・カーネル対NDRangeカーネル
インテル® FPGA SDK for OpenCL™ ホストはSingle Work-Itemとしてカーネルを実行できます。これはNDRangeサイズが(1,1,1)のカーネルを起動するのと同じです。
OpenCL仕様バージョン1.0では、この動作モードがタスク・パラレル・プログラミングとして記述されています。 タスクとは、Single Work-Itemを含む1つのワークグループで実行されるカーネルのことです。
一般に、ホストはMultiple Work-Itemを並行して起動します。しかし、このデータ並列プログラミング・モデルは、並列Work-Item間で細かいデータを共有する必要がある場合には適していません。このような場合、カーネルをSingle Work-Itemとして表現することで、スループットを最大化することができます。 NDRangeカーネルとは異なり、Single Work-Itemカーネルは、Cプログラミングに似た自然なシーケンシャル・モデルに従います。特に、Work-Item間でデータを分割する必要はありません。
FPGA上でのハイスループットのWork-Itemベースのカーネル実行を確実にするために、 Intel® FPGA SDK for OpenCL™オフライン・コンパイラーは、ある時点で複数のパイプライン・ステージを並列に処理する必要があります。この並列性は、ループの反復をパイプライン化することによって実現されます。
Single Work-Itemでの累積を示す次の簡単なコード例を検討してください。
1 kernel void accum_swg (global int* a, global int* c, int size, int k_size) { 2 int sum[1024]; 3 for (int k = 0; k < k_size; ++k) { 4 for (int i = 0; i < size; ++i) { 5 int j = k * size + i; 6 sum[k] += a[j]; 7 } 8 } 9 for (int k = 0; k < k_size; ++k) { 10 c[k] = sum[k]; 11 } 12 }


次の図は、iの各反復がどのようにブロックに入るかを示しています。
外部ループを観測すると、IIの値が1であるということは、スレッドの各反復がすべてのクロックサイクルに入ることもできることを意味します。この例では、k_sizeが20でサイズが4であると見なされます。これは、外側のループ反復0~7がそれをストールさせることなく入り込むことができるので、最初の8クロックサイクルにあてはまります。スレッド0が内部ループに入ると、それは4回の反復で終了します。スレッド1〜8は内部ループに入ることができず、スレッド0によって4サイクル停止します。スレッド0の反復が完了すると、スレッド1は内部ループに入ります。その結果、スレッド9は、クロックサイクル13で外側ループに入ります。スレッド9から20は、 サイズの値である4クロックサイクルごとにループに入ります。この例では、外部ループの動的開始間隔が静的に予測される開始間隔1よりも大きく、内部ループのトリップ数の関数であることがわかります。

- 次の関数のいずれかを使用すると、カーネルがNDRangeとして解釈されます。
- get_local_id()
- get_global_id()
- get_group_id()
- get_local_linear_id()
- barrier
- reqd_work_group_size属性が( 1,1,1)以外の値に指定されている場合、カーネルはNDRangeとして解釈されます。それ以外の場合、カーネルは Single Work-Itemカーネルとして解釈されます。
NDRangeで書かれた同じ累算例を検討してください。
kernel void accum_ndr (global int* a, global int* c, int size) { int k = get_global_id(0); int sum[1024]; for (int i = 0; i < size; ++i) { int j = k * size + i; sum[k] += a[j]; } c[k] = sum[k]; }


制限
OpenCLタスク並列プログラミング・モデルは、 Single Work-Itemの実行におけるバリアの概念をサポートしていません。バリア( barrier)をカーネル内のメモリーフェンス( mem_fence )に置き換えます。