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

148
Intel ® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus ® Prime 開発デザインスイートの更新情報: 17.1 更新情報 フィードバック UG-OCL003 | 2017.12.08 最新版をウェブからダウンロード: PDF | HTML

Transcript of Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド...

Page 2: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

目次

1. はじめに.............................................................................................................................51.1. FPGA 概要............................................................................................................. 51.2. パイプライン........................................................................................................... 71.3. シングル・ワーク・アイテム・カーネル対 NDRange カーネル.....................................................91.4. マルチ・スレッド・ホスト・アプリケーション........................................................................ 15

2. カーネルの report.html ファイルのレビュー............................................................................. 172.1. High Level Design レポートの概要.............................................................................172.2. Report Summary のレビュー 、 ............................................................................... 192.3. ループ情報のレビュー...............................................................................................20

2.3.1. OpenCL のデザイン例のループ解析レポート........................................................222.3.2. メモリー・アクセス・パターンの例の変更...............................................................232.3.3. loop_coalesce を使用してネストループによって消費されるエリアの削減.................27

2.4. エリア情報の確認....................................................................................................282.4.1. ソース別エリア分析..................................................................................... 292.4.2. システムのエリア分析...................................................................................30

2.5. メモリー・レプリケーションとストールに関する情報の確認..................................................... 312.5.1. System Viewer の機能................................................................................312.5.2. Kernel Memory Viewer の特長 ...................................................................33

2.6. HTML レポートの情報に基づいた OpenCL のデザイン例の 適化...........................................352.7. HTML レポート:エリア・レポート・メッセージ.....................................................................41

2.7.1. ボード・インターフェイスのエリア・レポート・メッセージ............................................. 422.7.2. 機能オーバヘッドのエリア・レポート・メッセージ..................................................... 422.7.3. 州のエリア・レポートメッセージ........................................................................ 422.7.4. フィードバックのためのエリア・レポート・メッセージ................................................. 422.7.5. 定数メモリーのエリア・レポート・メッセージ.......................................................... 422.7.6. プライベート変数ストレージのエリア・レポート・メッセージ.........................................43

2.8. HTML レポート:カーネルデザインの概念........................................................................ 442.8.1. Kernels .................................................................................................452.8.2. Global Memory Interconnect .....................................................................452.8.3. ローカルメモリー ....................................................................................... 462.8.4. Nested Loops ......................................................................................... 522.8.5. Single Work-Item カーネルのループ...............................................................592.8.6. チャネル ..................................................................................................662.8.7. ロード・ストア・ユニット..................................................................................66

3. OpenCL カーネルデザインのベスト・プラクティス......................................................................... 713.1. データを経由して転送する インテル FPGA SDK for OpenCL チャネルまたは OpenCL パイプ........ 71

3.1.1. チャネルとパイプの特性.................................................................................723.1.2. チャネルおよびパイプの実行順序......................................................................743.1.3. チャネルまたはパイプのバッファー推論の 適化.................................................... 753.1.4. チャネルとパイプのベスト・プラクティス............................................................... 75

3.2. ループのアンロール................................................................................................. 763.3. 浮動小数点演算の 適化...........................................................................................78

3.3.1. 浮動小数点表現と固定小数点表現.................................................................... 80

目次

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

2

Page 3: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

3.4. アラインメントされたメモリーの割り当て........................................................................ 803.5. 構造体をパディング付きまたはパディングなしで整列する......................................................813.6. ベクトル型要素の類似構造の維持.................................................................................833.7. ポインター・エイリアシングの回避................................................................................. 833.8. 高価な機能の回避................................................................................................... 843.9. Work-ItemID 依存の後方分岐の回避........................................................................... 85

4. パフォーマンスのボトルネックを特定するためのカーネルのプロファイリング..........................................864.1. Intel FPGA Dynamic Profiler for OpenCL のベスト・プラクティス.......................................874.2. Intel FPGA Dynamic Profiler for OpenCL GUI...........................................................87

4.2.1. ソース・コード・タブ.......................................................................................874.2.2. カーネル実行タブ........................................................................................894.2.3. Autorun Captures タブ...............................................................................90

4.3. プロファイリング情報の解釈....................................................................................... 914.3.1. ストール、占有、帯域幅.................................................................................. 914.3.2. アクティビティー......................................................................................... 934.3.3. キャッシュヒット..........................................................................................944.3.4. OpenCL のデザインシナリオ例のプロファイラ解析................................................. 944.3.5. 自動プロファイラーデータ.............................................................................. 98

4.4. Intel FPGA Dynamic Profiler for OpenCL の制限........................................................ 98

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略........................................... 1005.1. 適化レポートのフィードバックに基づくて Single Work-Item カーネル依存関係のアドレッシング. 100

5.1.1. ループ実行依存関係の削除...........................................................................1015.1.2. Relaxing Loop Carried の依存関係...............................................................1045.1.3. Loop Carried 依存関係の簡素化................................................................... 1065.1.4. ループで運ばれた依存関係のローカルメモリーへの転送.........................................1095.1.5. シフトレジスターの推測によるループキャリー依存関係の削除.................................. 110

5.2. メモリー配列へのアクセスによるループキャリー依存関係の削除............................................1125.3. Single Work-Item カーネルの良いデザイン方法............................................................ 113

6. NDRange カーネルのデータ処理効率を向上させるための戦略.......................................................1176.1. 大ワーク・グループ・サイズまたは必要なワーク・グループ・サイズの指定..................................1176.2. カーネルのベクトル化............................................................................................. 119

6.2.1. スタティック・メモリー統合............................................................................ 1206.3. 複数のコンピューティング・ユニット............................................................................. 122

6.3.1. コンピューティング・ユニット複製対カーネル SIMD ベクトル化................................. 1236.4. コンピューティング・ユニット複製とカーネル SIMD ベクトル化の組み合わせ............................. 1246.5. リソース駆動型 適化.............................................................................................1266.6. HTML レポートのカーネルプロパティとループアンロールステータスの確認...............................127

7. メモリーアクセス効率向上のための戦略................................................................................... 1287.1. メモリーアクセスの 適化に関する一般的なガイドライン....................................................1287.2. グローバル・メモリー・アクセスの 適化.........................................................................129

7.2.1. 連続メモリー・アクセス................................................................................ 1307.2.2. グローバルメモリーの手動分割...................................................................... 131

7.3. 定数、ローカルまたはプライベート・メモリーを使用したカーネル計算の実行.............................. 1327.3.1. キャッシュ・メモリー....................................................................................1327.3.2. ローカルメモリーへのデータの事前ロード..........................................................133

目次

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

3

Page 4: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

7.3.3. プライベート・メモリーに変数と配列の格納.........................................................1347.4. ローカルメモリーのバンキングによるカーネル・パフォーマンスの向上..................................... 135

7.4.1. アレイインデックスに基づくローカル・メモリー・バンクの幾何学的構成の 適化.............. 1377.5. メモリー・レプリケーションファクタの制御によるローカルメモリーへのアクセスの 適化............... 1387.6. ループパイプラインのメモリー依存性の 小化................................................................ 140

8. FPGA エリアの最適化のための戦略....................................................................................... 1418.1. コンパイルに関する考慮事項.....................................................................................1418.2. ボードバリアントの選択に関する考慮事項..................................................................... 1418.3. メモリーアクセスに関する考慮事項............................................................................. 1428.4. 算術演算の考慮事項...............................................................................................1438.5. データ型の選択に関する考慮事項............................................................................... 143

A. 追加情報........................................................................................................................ 145A.1. 改訂履歴............................................................................................................ 145

目次

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

4

Page 5: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

1. はじめに

インテル® FPGA SDK for OpenCL™ のベスト・プラクティス・ガイドでは、FPGA SoftwareDevelopment Kit (SDK) for OpenCL(1)の機能を使用して、 インテル FPGA 製品用に OpenCL アプリケーションを 適化するためのガイダンスを提供しています(2)。

OpenCL Specification version 1.0、Khronos Group™による OpenCL Specification version1.0 で説明されているように、OpenCL の概念とアプリケーション・プログラミング・インターフェイス(API)に精通していることを前提としています。 また、OpenCL アプリケーションの作成経験があることを前提としています。

FPGA 用の OpenCL アプリケーションの 高のパフォーマンスを実現するには、基礎となるハードウェアの詳細に慣れてください。 さらに、OpenCL アプリケーションを FPGA に変換してマッピングするコンパイラーの 適化についても理解してください。

OpenCL Specification version 1.0 の詳細については、Khronos Group ウェブサイトの OpenCLReference Pages を参照してください。 OpenCL API とプログラミング言語の詳細については、OpenCL Specification version 1.0 を参照してください。

関連情報• OpenCL のリファレンス・ページ

• OpenCL の仕様バージョン 1.0

1.1. FPGA 概要

フィールド・プログラマブル・ゲート・アレイ(FPGA)は、集積回路であり、無限の数の機能を実行するために繰り返し構成できます。

FPGA はいくつかの小さなコンピューティング・ユニットで構成されています。次の図に示すように、コンピューティング・ユニットをプログラミングして接続することで、カスタムデータパスをファブリックに直接組み込むことができます。データフローはアーキテクチャに直接プログラミングされています。

(1) インテル FPGA SDK for OpenCL は公開されている Khronos 仕様に基づいており、Khronos 適合性テストプロセスに合格しています。 現在の適合ステータスは www.khronos.org/conformance にあります。

(2) OpenCL および OpenCL のロゴは Apple Inc.の商標であり、Khronos Group™の許可を得て使用しています。

UG-OCL003 | 2017.12.08

フィードバック

Intel Corporation.無断での引用、転載を禁じます。Intel、インテル、Intel ロゴ、Altera、ARRIA、CYCLONE、ENPIRION、MAX、NIOS、QUARTUS および STRATIX の名称およびロゴは、アメリカ合衆国および/ またはその他の国における Intel Corporationの商標です。インテルは FPGA 製品および半導体製品の性能がインテルの標準保証に準拠することを保証しますが、インテル製品およびサービスは、予告なく変更される場合があります。インテルが書面にて明示的に同意する場合を除き、インテルはここに記載されたアプリケーション、または、いかなる情報、製品、またはサービスの使用によって生じるいっさいの責任を負いません。インテル製品の顧客は、製品またはサービスを購入する前、および、公開済みの情報を信頼する前には、デバイスの仕様を 新のバージョンにしておくことをお勧めします。*その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

ISO9001:2015登録済

Page 6: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -1: FPGA アーキテクチャ

FPGA では、ビットマスキング、シフト、加算などの低レベルの動作がすべて設定可能です。また、これらの動作を任意の順序でアセンブルできます。計算パイプラインを実装するために、FPGA はルックアップ・テーブル(LUT)、レジスター、オンチップメモリー、および算術ハードウェア(例えば、デジタル信号プロセッサー(DSP)ブロック)の組み合わせを再構成可能な接続のネットワークを介して統合します。その結果、FPGA は高度なプログラマビリティを実現します。 LUT は、さまざまなロジック機能を実装します。例えば、LUT をリプログラミングすることにより、ビット単位の AND 論理関数からビット単位のXOR 論理関数に演算を変更することができます。

アルゴリズムを高速化するために FPGA を使用することの主な利点は、幅広く異機種でユニークなパイプライン実装をサポートすることです。この特性は、対称型マルチプロセッサー、DSP、およびグラフィックス処理ユニット(GPU)などの多くの異なるタイプの処理ユニットとは対照的です。これらのタイプのデバイスでは、同じ汎用コンピューティング・ハードウェアを複数回複製することによって並列性が実現されます。しかし、FPGA では、アルゴリズムが実行するロジックのみを複製することで並列処理を実現できます。

1. はじめにUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

6

Page 7: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

プロセッサーは、各クロックサイクルで実行できる作業量を制限する命令セットを実装します。たとえば、ほとんどのプロセッサーには、次の C コードを実行できる専用命令がありません。

E = (((A + B) ^ C) & D) >> 2;

この C コード例のための専用の命令がないと、CPU、DSP、または GPU は、動作を実行するために複数の命令を実行する必要があります。対照的に、FPGA は、ソフトウェア・アルゴリズムに必要な命令セットを実装できるハードウェア・プラットフォームと考えることができます。上記のコード例を 1 クロックサイクルで実行する一連の動作を実行するように FPGA をコンフィグレーションすることができます。 FPGA実装は、特殊な追加ハードウェアとビット単位の XOR および AND 演算を実行する LUT を接続します。その後、デバイスはプログラマブルな接続を使用して、ハードウェア・リソースを消費することなく 2 ビット右シフトを実行します。この動作の結果は、複雑なパイプラインを形成する後続の動作の一部になります。

1.2. パイプライン

パイプライン・アーキテクチャでは、入力データは一連のステージを通過します。各ステージは、メモリー動作や計算などの 終結果に貢献する動作を実行します。

マイクロプロセッサー、デジタル信号プロセッサー(DSP)、ハードウェア・アクセラレーター、およびデジタル・ハードウェアの他の高性能実装のデザインは、パイプライン・アーキテクチャを含むことが多いです。

たとえば、以下の図は、多段パイプラインとしての次のコード例を表しています。 

for (i = 0; i < 1024; i++){ y[i] = (a[i] + b[i] + c[i] + d[i] + e[i] + f[i] + g[i] + h[i]) >> 3;}

図 -2: 多段パイプライン図の例 

Add AddAddAddAddAddAdd Shiftby 3

a[i]

y[i]

h[i]g[i]f[i]e[i]d[i]c[i]b[i]

Pipeline Stage1 8765432

For i = 0...1023

パイプライン・アーキテクチャでは、各算術演算はパイプラインに一度に 1 つずつ渡されます。したがって、上の図に示すように、飽和パイプラインは、算術演算を同時に並列に計算する 8 つのステージから構成されています。さらに、多数のループ反復のために、パイプライン・ステージは、後続の各ループ反復に対してこれらの算術命令を同時に実行し続けます。

インテル FPGA SDK for OpenCL のパイプライン・アプローチ

新しいパイプラインがデザインに基づいて構築されます。その結果、高度に構成可能な FPGA の性質に対応することができます。

次の OpenCL コードの断片を検討してください。

C = (A >> 5) + B;F = (D – E) << 3;G = C + F;

1. はじめにUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

7

Page 8: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

FPGA 全体を同時に実行する複雑なパイプライン構造をインスタンス化するように FPGA を設定することができます。この場合、SDK は、下の図に示すように、コードをパイプライン型加算器に入力する 2 つの独立したパイプライン・エンティティとして実装しています。

図 -3: SDK のパイプライン・アプローチの例

Subtraction Shift Right by 5

Shift Left by 3 Addition

Addition

D E A B

F C

G

Intel® FPGA SDK for OpenCL オフライン・コンパイラー多数の Work-Item 内の動作を並行して実行できるようにすることで、計算を高速化するカスタム・パイプライン構造を提供します。オフライン・コンパイラーは、以下に示すように、クロックサイクルごとに変数 C 、 F 、および G の値を計算するカスタム・パイプラインを作成できます。ランプアップの後、パイプラインは 1 サイクルあたり Single Work-Itemのスループットを維持します。

図 -4: クロックサイクル当たり 3 つの動作を持つ FPGA パイプライン

543210

G

C

F

Time in Clock Cycles

(A0 >> 5) + B0 (A1 >> 5) + B1 (A2 >> 5) + B2 (A3 >> 5) + B3 (A4 >> 5) + B4 (A5 >> 5) + B5

(D0 - E0) << 3 (D1 - E1) << 3 (D2 - E2) << 3 (D3 - E3) << 3 (D4 - E4) << 3 (D5 - E5) << 3

C0 + F0 C1 + F1 C2 + F2 C3 + F3 C4 + F4

1. はじめにUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

8

Page 9: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

従来のプロセッサーは、共有レジスターのセットが限られています。 終的に、プロセッサーは、記憶されたデータをメモリーに書き出して、より多くのデータがレジスターを占めるようにしなければなりません。オフライン・コンパイラーは、パイプライン内のすべてのアクティブな Work-Items のデータを格納するのに十分なレジスターを生成することによって、データをライブ」に保ちます。次のコード例および図は、OpenCL パイプラインのライブ変数 C を示しています。

size_t index = get_global_id(0);

C = A[index] + B[index];E[index] = C – D[index];

図 -5: ライブ変数 C を持つ FPGA パイプラインLoad

A[index]Load

B[index]

LoadD[index]

StoreE[index]

C

+

-

Clock Cycle 0

Index = 0 LoadA[index]

LoadB[index]

LoadD[index]

StoreE[index]

C

+

-

Clock Cycle 1

Index = 1

Index = 0

LoadA[index]

LoadB[index]

LoadD[index]

StoreE[index]

C

+

-

Clock Cycle 2

Index = 2

Index = 0

Index = 1

1.3. シングル・ワーク・アイテム・カーネル対 NDRange カーネル

インテル は、可能であれば、OpenCL カーネルをシングル・ワーク・アイテムとして構成することを推奨します。ただし、カーネル・プログラムにループとメモリーの依存関係がない場合、カーネルが MultipleWork-Items を効率的に並列に実行できるため、アプリケーションを 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 ベースのカーネル実行を確実にするために、 IntelFPGA SDK for OpenCL オフライン・コンパイラーは、ある時点で複数のパイプライン・ステージを並列に処理する必要があります。この並列性は、ループの反復をパイプライン化することによって実現されます。

1. はじめにUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

9

Page 10: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

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 }

各ループ反復の間に、グローバルメモリー a からのデータ値は、 sum [k]に蓄積されます。この例では、4 行目の内側ループは、開始インターバル値が 1 で、レイテンシーが 11 です。外側ループも 1 以上の開始インターバル値を持ち、レイテンシーは 8 です。

注意: 新しいループ反復の開始頻度は開始間隔(II)と呼ばれます。 II は、パイプラインが次のループ反復を処理する前に待機しなければならないハードウェア・クロック・サイクルの数を指します。 適にアンロールされたループは、1 つのループ反復がクロックサイクルごとに処理されるため、II の値が 1 です。

図 -6: ループ解析レポート

1. はじめにUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

10

Page 12: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -8: 内部ループ accum_swg.B2実行

L = 11

3

2

1

0Location of loop iterations in the hardware pipeline after first four iterations have been launched.

Legend

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

1. はじめにUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

12

Page 13: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -9: Single Work-Item の実行

重要: • 次の関数のいずれかを使用すると、カーネルが 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];}

1. はじめにUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

13

Page 15: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

制限

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

関連情報• Multiple Work-Item Ordering for Channels

• Single Work-Item カーネルのループ (59 ページ)

• Nested Loops (52 ページ)

1.4. マルチ・スレッド・ホスト・アプリケーション

パラレルで独立したデータパスがあり、ホストがカーネル実行の間にデータを処理するときは、マルチ・スレッド・ホスト・アプリケーションの使用を検討してください。

図 -12: パイプライン・ループでマルチスレッド実行の起動頻度の比較

Cloc

k Cy

cles

i0i1

i5i4

i3i2

Loop Pipelining

Cloc

k Cy

cles

t0t1

t5t4

t3t2

Parallel Threads

パラレル・スレッドは、クロックサイクルごとに 1 つのスレッドでパイプライン方式で起動されます。この場合、ループ・パイプラインでパイプラインの並列処理とループ反復間の状態情報の通信が可能になります。ループの依存関係は、1 クロックサイクルで解決されないことがあります。

以下の図は、シングル・スレッド・ホスト・アプリケーションが、カーネル実行間で並列の独立したデータパスをどのように処理するかを示しています。

図 -13: シングル・スレッド・ホスト・アプリケーションによるカーネルの実行

Kernel 1

Kernel 4Kernel 3

Poll forcompletion

Poll forcompletion

Hostprocessing

Kernel 2Host

processingHost

processing

Hostprocessing

Dataset 1

Dataset 2

Main Program

シングル・スレッドのホスト・アプリケーションでは、 OpenCL ホスト関数呼び出しの周りに外部同期機構を構築する必要があります。スレッドセーフな実行環境でマルチ・スレッド・ホスト・アプリケーションを使用すると、ホストコードを簡素化できます。さらに、ホスト内の複数のデータセットを同時に処理することで、カーネルの実行を高速化することができます。

1. はじめにUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

15

Page 16: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

次の図は、マルチ・スレッド・ホスト・アプリケーションがカーネル実行間で並列の独立したデータ・パスをどのように処理するかを示しています。

図 -14: スレッドセーフなランタイム環境におけるマルチ・スレッド・ホスト・アプリケーションによるカーネルの実行

MainProgram

Dataset 1

Kernel 1Host

processing Kernel 2Host

processing

Dataset 1

Kernel 3Host

processing Kernel 4Host

processing

Thread 1

Thread 2

関連情報Multiple Host Threads

1. はじめにUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

16

Page 17: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

2. カーネルの report.html ファイルのレビュー

<your_kernel_filename>/reports/report.html ファイルには、エリアやメモリーの使用法、ループ構造、カーネル・パイプライン情報などのカーネル解析データがあります。

2.1. High Level Design レポートの概要

High Level Design レポート (report.html) は、レポートメニュー、Analysis ペイン、SourceCode ぺイン、および Details ペインの 4 つの主要セクションに分かれています。

Report menu

Analysis pane Source code pane

Details pane

レポートメニュー

View reports のプルダウンメニューから、レポートを選択してカーネル デザインの特定部分の分析を表示します。

UG-OCL003 | 2017.12.08

フィードバック

Intel Corporation.無断での引用、転載を禁じます。Intel、インテル、Intel ロゴ、Altera、ARRIA、CYCLONE、ENPIRION、MAX、NIOS、QUARTUS および STRATIX の名称およびロゴは、アメリカ合衆国および/ またはその他の国における Intel Corporationの商標です。インテルは FPGA 製品および半導体製品の性能がインテルの標準保証に準拠することを保証しますが、インテル製品およびサービスは、予告なく変更される場合があります。インテルが書面にて明示的に同意する場合を除き、インテルはここに記載されたアプリケーション、または、いかなる情報、製品、またはサービスの使用によって生じるいっさいの責任を負いません。インテル製品の顧客は、製品またはサービスを購入する前、および、公開済みの情報を信頼する前には、デバイスの仕様を 新のバージョンにしておくことをお勧めします。*その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

ISO9001:2015登録済

Page 18: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

Analysis ペイン

Analysis ペインは、View reports のプルダウンメニューで選択したレポートの詳細情報を表示します。

Source Code ペイン

Source Code ペインは、カーネル デザイン内のすべてのソースファイルにおけるコードを表示します。

カーネル デザイン内の異なるソースファイル間を選択するには、Source Code ペイン上でプルダウンメニューをクリックします。Source Code ペインを折りたたむには、オプションが 2 つあります。

• Source Code ペインのプルダウンメニュー横の X アイコンをクリックします。

• レポートメニューの右側にある垂直の省略記号のアイコンをクリックし、Show/Hide sourcecode を選択します。

あらかじめ Source Code ペインを折りたたんだ状態で展開する場合は、レポートメニューにある垂直の省略記号のアイコンをクリックし、Show/Hide source code を選択します。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

18

Page 19: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

Details ペイン

ループ分析またはエリアレポートに表示される各ラインは、使用可能な場合、Detail カラムレポートのコメントを詳しく述べる追加情報を表示します。Details ペインを閉じるために Details ペインを折りたたむには、オプションが 2 つあります。

• Detail Code ペインのプルダウンメニュー横の X アイコンをクリックします。

• レポートメニューの左側にある垂直の省略記号のアイコンをクリックし、Show/Hide detailsを選択します。

2.2. Report Summary のレビュー 、

Report Summary は、デザイン内の各カーネル の要約を含んだデザインのコンパイル結果のおおまかな概要と、デザイン内の各カーネル が使用する見積られたリソースの要約を提供します。

Report Summary は、Info、Kernel Summary 、Estimated Resource Usage、および CompileWarnings の 4 つ のセクションに分かれています。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

19

Page 20: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

Info

Info セクションは、次の項目を含んだコンパイルの一般情報を表示します。

• プロジェクトの名前

• ターゲット FPGA ファミリー、デバイス、およびボード

• インテル Quartus® Prime のバージョン

• AOC のバージョン

• デザインをコンパイルするために使用されたコマンド

• レポートが生成された日付と時間

Kernel Summary

Kernel Summary ではデザインの各カーネルと、次の項目を含んだ各カーネルのいくつかの情報をリストします。

• カーネルが NDRange か Single Work-Item kernel か

• autorun 属性が使用されているかどうか

• カーネルで要求されるワークグループ・サイズ

• 計算ユニットの数

リストでカーネルを選択すると、Details ペインはカーネルに関する追加情報を表示します。

• カーネルのベクトル化

• 大グローバルワーク・ディメンション

• ワークグループの 大のサイズ

Estimated Resource Usage

Estimated Resource Usage セクションは、すべてのチャネルで使用される見積られたリソース、グローバル・インターコネクトの見積られたリソース、定数キャッシュ、およびボード・インターフェイスと同様に、デザインの各カーネルで使用される見積られるリソースの要約を表示します。

Compile Warnings

Compile Warnings セクションは、コンパイラーがコンパイル時に生成した警告のうちのいくつかを表示します。

2.3. ループ情報のレビュー

High Level Design レポート ( <your_kernel_filename>/reports/report.html)ファイルには、デザインのすべてのループとそれらのアンロールステータスに関する情報が含まれています。このループ分析レポートは、 Intel FPGA SDK for OpenCL オフライン・コンパイラーがカーネルのスループットを 大化できるかどうかを調べるのに役立ちます。

さらに、ループ分析レポートは、次のプラグマの 1 つもしくは 1 つ以上のループを展開する場所を判断するのにも役立ちます。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

20

Page 21: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

• #pragma unroll

#pragma unroll について詳しくは、Intel FPGA SDK for OpenCL Programming Guideの「Unrolling a Loop」を参照してください。

• #pragma loop_coalesce

#pragma loop_coalesce について詳しくは、Intel FPGA SDK for OpenCLProgramming Guide の「Coalescing Nested Loops」を参照してください。

• #pragma ii

#pragma ii について詳しくは、Intel FPGA SDK for OpenCL Programming Guide の「Specifying a loop initiation interval (II)」を参照してください。

1. View reports > Loop Analysis をクリックします。

2. Analysis ペインで Show fully unrolled loops を選択し、デザイン内のすべてのループの情報を取得します。

3. デザインのスループットを向上させるためのアクションを特定するには、下のフローチャートを参照します。

ループ

完全に展開された?

部分的に展開された?

パイプライン された?

YES

NO

NO

NO

YESYES

YES

II=1? ループのパイプラインはオプションです。

シリアル実行情報は Details ペインを参照

Bottleneckまたは Details カラムで詳細を参照

Details カラムに「Unrolled by #pragma unroll」または 「Auto-unrolled」 が表示されます。ループ構造はオプションです。

大スループットは達成されます。

#pragma unroll の値が正しいかを確認

NO

注意:

II はループのイニシエーション・インターバルを指し、新しいループ反復処理までの開始時間を示します。II の値 = 1 が理想的であり、すなわち、 パイプラインはクロックサイクルごとに新しいループ反復処理が可能なため、パイプラインが 大の効率で機能していることを意味します。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

21

Page 22: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

2.3.1. OpenCL のデザイン例のループ解析レポート

4 つのループを含む OpenCL カーネルの例のループ解析レポート。

1 // ND-Range kernel with unrolled loops 2 __attribute((reqd_work_group_size(1024,1,1))) 3 kernel void t (global int * out, int N) { 4 int i = get_global_id(0); 5 int j = 1; 6 for (int k = 0; k < 4; k++) { 7 #pragma unroll 8 for (int n = 0; n < 4; n++) { 9 j += out[k+n];10 }11 }12 out[i] = j;1314 int m = 0;15 #pragma unroll 116 for (int k = 0; k < N; k++) {17 m += out[k/3];18 }19 #pragma unroll20 for (int k = 0; k < 6; k++) {21 m += out[k];22 }23 #pragma unroll 224 for (int k = 0; k < 6; k++) {25 m += out[k];26 }27 out[2] = m;28 }

このデザイン例のループ分析レポートは、コードで定義されているさまざまな種類のループのアンロール戦略を強調しています。

図 -15: 4 つのループを持つ OpenCL デザイン例のループ解析レポート

Intel FPGA SDK for OpenCL オフライン・コンパイラーはソースコードに基づいて以下のループ・アンローリング戦略を実行します。

• 初のループ(ライン 6)を完全に展開します。

• #pragma unroll の仕様のため、 初のループ内(ライン 8)で内側のループを完全に展開します。

• #pragma unroll 1 仕様のため、2 番目の外部ループ Block2(ライン 16)をアンロールしません。

• #pragma unroll の仕様のため、3 番目の外部ループ(ライン 20)を完全に展開します。

• #pragma unroll 2 の仕様のため、4 番目の外部ループ Block4(ライン 24)を 2 回展開します。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

22

Page 23: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

2.3.2. メモリー・アクセス・パターンの例の変更

以下は、単純な OpenCL カーネルのコード例です。

kernel void big_lmem_4r_4w_nosplit (global int* restrict in, global int* restrict out) { local int lmem[4][1024]; int gi = get_global_id(0); int gs = get_global_size(0); int li = get_local_id(0); int ls = get_local_size(0); int res = in[gi]; #pragma unroll for (int i = 0; i < 4; i++) { lmem[i][(li*i) % ls] = res; res >>= 1; }

// Global memory barrier barrier(CLK_GLOBAL_MEM_FENCE);

res = 0; #pragma unroll for (int i = 0; i < 4; i++) { res ^= lmem[i][((ls-li)*i) % ls]; } out[gi] = res;}

この例のシステム・ビューア・レポートは、ストール可能なロードおよびストアを強調表示します。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

23

Page 25: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -17: 実施例のエリア・リポート

Double pump uses more logic (ALUTs/FFs) but provides more ports

Expected to have four banks, but the compiler banked on lowest dimen-

図 -18: 例のカーネル・メモリー・ビューア

Load and store getting arbitrated

Arbitration (stallable)

Both banks Bank 0 Only Bank 1 Only

ロードとストアの動作の間の 初のバンクでは、アービトレーションが高い 2 つのメモリーバンクしか作成されないことに注意してください。次に、次のコード例に示すように、バンク・インデックスを第 2 次元に切り替えます。

kernel void big_lmem_4r_4w_nosplit (global int* restrict in, global int* restrict out) { local int lmem[1024][4];

int gi = get_global_id(0); int gs = get_global_size(0); int li = get_local_id(0); int ls = get_local_size(0); int res = in[gi]; #pragma unroll for (int i = 0; i < 4; i++) { lmem[(li*i) % ls][i] = res; res >>= 1;

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

25

Page 26: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

} // Global memory barrier barrier(CLK_GLOBAL_MEM_FENCE); res = 0; #pragma unroll for (int i = 0; i < 4; i++) { res ^= lmem[((ls-li)*i) % ls][i]; } out[gi] = res;}

カーネル・メモリー・ビューアでは、4 つのメモリーバンクが別々のロード・ストア・ユニットで作成されていることがわかります。すべてのロードストア命令はストールフリーです。

図 -19: バンク・インデックスを変更した後の例のカーネル・メモリー・ビューア

Four memory banks created with separate load store units

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

26

Page 27: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -20: バンク・インデックスを変更した後の例のエリア・レポートBefore changing

After changing

2.3.3. loop_coalesceを使用してネストループによって消費されるエリアの削減

ループが 3 つ以上の深さにネストされると、より多くのエリアが消費されます。

ネストされたループのレイテンシーを削減する方法を説明するために orig と lc_test カーネルを使用する次の例を検討してください。

orig カーネルはネストされたループを 4 の深さまでがあります。ネストされたループは、次のレポートに示すように、変数が保持されているためにエリアを消費する余分なブロック(ブロック 2,3,4,6,7,8)を作成しました。

図 -21: Loop Coalescing の前後の Area Report および System Viewer

Latency 4

Latency 4

Latency 4

Latency 15

Kernel orig - before Kernel orig - before Kernel lc_test - after

All four variables are carried only for 15 cyclessince Block 1 has a latency of 15

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

27

Page 28: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

ループの合体により、 lc_test のレイテンシーが短縮されていることがわかります。 orig カーネルのブロック 5 と lc_test カーネルのブロック 12 は、 も内側のループです。

図 -22: lc_testと origカーネルのエリアレポートKernel lc_test -- after

Kernel lc_test -- afterKernel orig -- before

関連情報Coalescing Nested Loops

2.4. エリア情報の確認

<your_kernel_filename>/reports/report.html ファイルには、OpenCL システムのエリア使用に関する情報が含まれています。ソースコード(つまり、コードライン)またはシステムによってエリア使用量情報を表示することができます。

地域レポートには、以下の目的があります。

• OpenCL システム全体の詳細なエリア内訳を提供します。内訳はソースコードに関連しています。

• 生成されたハードウェアを洞察し、潜在的な非効率性を解決するための提案を提供します。 

次の図に示すように、エリアレポートは 3 つの階層レベルに分かれています。

• システムエリア :

• これは、すべてのカーネル、チャネル、インターコネクト、ボードロジックで使用されます。

• カーネルエリア :

• オーバーヘッド(例えば、ディスパッチ・ロジック)を含めて、特定のカーネルによって使用されます。

• 基本ブロックエリア :

• これは、カーネル内の特定の基本ブロックによって使用されます。基本的なブロックエリアは、ソースコードのブランチのないセクション(ループ本体など)を表します。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

28

Page 29: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -23: エリアレポートの階層

注意: エリア使用量データは Intel FPGA SDK for OpenCL オフライン・コンパイラーが生成する見積もりです。 これらの見積もりは、 終的なエリア使用結果とは異なる場合があります。

• レポート・メニューの View reports...のプルダウン・メニューで Area analysis by sourceまたは Area analysis of system を選択します。

2.4.1. ソース別エリア分析

ソースレポートによるエリア分析では、ソースコードの各行がエリアの使用にどのように影響するかを近似して示しています。このビューでは、エリア情報が階層的に表示されます。

4 つのループを含む OpenCL カーネルの例:

1 // ND-Range kernel with unrolled loops 2 __attribute ((reqd_work_group_size(1024,1,1))) 3 kernel void t (global int * out, int N) { 4 int i = get_global_id(0); 5 int j = 1; 6 for (int k = 0; k < 4; k++) { 7 #pragma unroll 8 for (int n = 0; n < 4; n++) { 9 j += out[k+n];10 }11 }12 out[i] = j;1314 int m = 0;15 #pragma unroll 116 for (int k = 0; k < N; k++) {17 m += out[k/3];18 }19 #pragma unroll20 for (int k = 0; k < 6; k++) {21 m += out[k];22 }23 #pragma unroll 224 for (int k = 0; k < 6; k++) {25 m += out[k];26 }27 out[2] = m;28 }

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

29

Page 30: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

以下のエリアレポートには、カーネルシステム、ボード・インターフェイス、およびグローバル・インターコネクトのエリア使用量がリストされています。これらの要素はシステムレベルの IP で、デザインがターゲットとするカスタム・プラットフォームまたはリファレンス・プラットフォームに依存します。カーネル t はカーネルシステムの階層内にあり、ソースコードが始まる場所です。このレポートは、カーネル t の下でソースコード内で宣言されたすべての変数を指定し、残りのエリア情報を行番号でソートします。

図 -24: 例示的なエリアレポートのソースビュー

この例では、コードライン j + = out [k + n]のコードライン(9 行目)では、 Intel FPGA SDKfor OpenCL オフライン・コンパイラー追加を実行してグローバルメモリーからデータをロードするのに必要なエリアに基づいて推定エリア使用量を計算します。コードライン out [i] = j (12 行目)の場合、オフライン・コンパイラーはポインター値を計算するために必要なエリアに基づいて推定エリア使用量を計算し、グローバルメモリーに格納し直します。

2.4.2. システムのエリア分析

システムレポートのエリア分析は、FPGA に実装されているハードウェアに も近い OpenCL システムのエリア内訳を示しています。

4 つのループを含む OpenCL カーネルの例:

1 // ND-Range kernel with unrolled loops 2 __attribute((reqd_work_group_size(1024,1,1))) 3 kernel void t (global int * out, int N) { 4 int i = get_global_id(0); 5 int j = 1; 6 for (int k = 0; k < 4; k++) { 7 #pragma unroll 8 for (int n = 0; n < 4; n++) { 9 j += out[k+n];10 }11 }12 out[i] = j;1314 int m = 0;15 #pragma unroll 1

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

30

Page 31: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

16 for (int k = 0; k < N; k++) {17 m += out[k/3];18 }19 #pragma unroll20 for (int k = 0; k < 6; k++) {21 m += out[k];22 }23 #pragma unroll 224 for (int k = 0; k < 6; k++) {25 m += out[k];26 }27 out[2] = m;28 }

図 -25: 地域レポートの例

システムビューでは、カーネルは論理ブロックに分割されています。ブロックに関連付けられているコードラインのエリア使用情報を表示するには、そのブロックのレポートエントリーを展開するだけです。この例では、コードライン out [i] = j (12 行目)のエリア情報が Block1 の下で使用可能です。システムビューでのライン 12 の推定エリア使用量は、ソースビューでの見積もりと同じです。

2.5. メモリー・レプリケーションとストールに関する情報の確認

<your_kernel_filename>/reports/report.html ファイルには、カーネルと異なるメモリー、カーネル間に接続されたチャネル、およびループ間の情報の読み出しと格納を含むストール・ポイント・グラフがあります。

システムビューアには、OpenCL システムの抽象ネットリストが表示されます。システムビューアでOpenCL デザインのグラフィカルな表示を確認すると、メモリーの複製を確認し、停止可能なロードおよびストア命令を識別できます。

1. レポートメニューの View reports...のプルダウンメニューで System viewer を選択します。

2.5.1. System Viewer の機能

システムビューアは、 OpenCL システムのインタラクティブなグラフィカル・レポートで、ロードとストアのサイズとタイプ、ストール、レイテンシーなどの情報を確認できます。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

31

Page 32: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

次の方法でシステムビューアと対話できます。

• マウスホイールを使用して、システムビューア内で拡大または縮小します。

• 赤い論理ブロックに関連付けられているデザインの部分を確認します。たとえば、High InitiationInterval (II)値を持つパイプライン・ループを持つロジックブロックは、High II 値がデザインのスループットに影響を及ぼす可能性があるため、赤で強調表示されます。

• ブロック内の任意のノードにカーソルを合わせると、そのノードの情報がツールチップと詳細ペインに表示されます。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

32

Page 33: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

• 非表示にする接続のタイプをオフにして、システムビューアに含める接続のタイプを選択します。デフォルトでは、 Control と Memory の両方がシステムビューアでチェックされます。 Controlとは、ブロックとループの間の接続を指します。Memory とは、グローバルメモリーまたはローカルメモリーとの接続を指します。デザインに読み出しチャンネルまたは書き込みチャンネルとの接続がある場合、システムビューアに Channels オプションもあります。

Both control and memory connections shown Only control connections shown Only memory connections shown

2.5.2. Kernel Memory Viewer の特長

多くのアルゴリズムでは、データ移動がボトルネックになることがよくあります。High Level Design レポート (report.html) 内の Kernel memory viewer は、 Intel FPGA SDK for OpenCL オフライン・コンパイラーが カーネルのメモリーシステム上のデータ接続をどのように解釈するかを示しています。 kernel memory viewer を使用すると、 カーネルデザインのデータ移動のボトルネックの特定に役立ちます。

更に、メモリーアクセスの一部のパターンは LSU ( ロードストアー・ユニット ) で望まない調停を引き起こし、 カーネルのスループット性能に影響を与える可能性があります。 Kernel memory viewer を使用すると、LSU で望ましくない調停が発生する可能性のある位置を見つけることができます。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

33

Page 34: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

Kernel Memory Viewer には次のペインがあります。

MemoryList

Memory List ペインは、 カーネルの階層、その カーネル内のメモリー、および対応するメモリーバンクを表示します。

リストにあるメモリー名をクリックすると、 Kernel memory viewer ペイン内のメモリーがグラフィック表示されます。また、メモリーを宣言したコード内のラインは、SourceCode ペインでハイライトで表示されます。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

34

Page 35: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

メモリーバンクでのチェックボックスをクリアーすると、そのバンクが Kernel MemoryViewer ペインに表示され、複雑なメモリーデザインを表示する際に特定のメモリーバンクに焦点を当てるのに役立ちます。デフォルトでは、 カーネルメモリー内のすべてのバンクが選択され、 Kernel Memory Viewer ペインで表示されます。

KernelMemoryViewer

Kernel Memory Viewer ペインは、メモリーシステム内のバンク上のロジックポートを特定するためにロードとストアー間の接続を表示します。次のノードのタイプは KernelMemory Viewer ペイン内で表示される可能性があり、 kernel メモリーシステムによります。

• Memory node: メモリー

• Bank node: メモリー内のバンク。Memory List ペインで選択されているバンクのみ表示されます。Memory List ペイン内でのバンクの選択は複雑なメモリーデザインの表示に役立ちます。

• Port node: バンクでのロジックポート。次の 3 種類のポートがあります。

— R: 読み取り専用ポート

— W: 書き込み専用ポート

— RW: 読み取りおよび書き込みを有するポート

• LSU node: メモリーに接続されるストアー (ST) またはロード (LD) ノード

• Arbitration node: アービトレーション (ARB) ノードは LSU が共有ポートノードへのアクセスを競合していることを示します。

• Port-sharing node: ポートシェアリング (SHARE) ノードは LSU が共有ポートノードへの排他的なアクセスを持つことを示しているため、ロードストアー・ユニットにはストールがありません。

任意のノードにカーソルを置くと、そのノードの属性が表示されます。

LSU ノードにカーソルを置くと、LSU ノードから LSU が接続するすべてのポートまでのパスがハイライトで表示されます。

ポートノードにカーソルを置くと、ポートノードからポートノードに格納されているすべての LSU までのパスがハイライトで表示されます。

ノードを選択するためにクリックし、Details ペインにノード属性を表示します。

Details Details ペインは Kernel Memory Viewer ペインで選択されたノードの属性を表示します。例えば、 カーネル内のメモリーを選択する際、 ペインはソースコードで指定した任意のユーザー定義の属性と同様に、メモリーバンクの幅や深さなどの情報を表示します。

Details ペインの内容は Kernel Memory Viewer ペイン内で異なるノードを選択するまで保持されます。

2.6. HTML レポートの情報に基づいた OpenCL のデザイン例の最適化

HTML レポートの情報を活用して OpenCL カーネルを 適化する方法に関するガイド。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

35

Page 36: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

行列の正方形 AxA を実行する OpenCL のデザイン例:

// performs matrix square A*A// A is a square len*len matrix

kernel void matrix_square (global float* restrict A, unsigned len, global float* restrict out) { for(unsigned oi = 0; oi < len*len; oi++) { float sum = 0; int row = oi % len; for (int col = 0; col < len; col++) { unsigned i = (row * len) + col; // 0, 1, 2, 3, 4,... unsigned j = (col * len) + row; // 0, 3, 6, 9, 1,... sum += A[i] * A[j]; } out[oi] = sum; }}

カーネル matrix_square のエリアレポートのシステムビューは、 ブロック 3 のフリップフロップ(FF)と RAM の推定使用量が高いことを示しています。システムビューアの Block3 をさらに調べると、Block3 のレイテンシー値も高いことがわかります。

図 -26: 最適化されていないカーネル matrix_square のエリアレポートとシステムビューアの結果

これらのパフォーマンスのボトルネックの原因は、システムがループ内からグローバルメモリーからデータをロードしているためです。したがって、次の変更されたコードに示すように、データをローカルメモリーにプリロードすることが、 初に行う 適化のステップです。

kernel void matrix_square_v1 (global float* restrict A, unsigned len, global float* restrict out){ // 1. preload the data into local memory // - suppose we know the max size is 4X4

local int cache_a[16];for(unsigned k = 0; k < len*len; k++) { cache_a[k] = A[k];}

for(unsigned oi = 0; oi < len*len; oi++) {

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

36

Page 37: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

float sum = 0; int row = oi % len; for(int col = 0; col < len; col++) { unsigned i = (row * len) + col; // 0, 1, 2, 3, 4,... unsigned j = (col * len) + row; // 0, 3, 6, 9, 1,... sum += cache_a[i] * cache_a[j]; } out[oi] = sum; }}

図 -27: 修正されたカーネル matrix_square_v1 のエリアレポートとシステムビューアの結果

エリアレポートとシステムビューアの結果に示されているように、ローカルメモリーにデータをプリロードすると、RAM の使用量が 3 分の 1 に減少し、レイテンシー値が 255 から 97 に低下します。

matrix_square_v1 のエリアレポートをさらに調べると、以下のエリアレポートの行 30 であるコードライン int row = oi%len は、法計算のために異常に大きなエリアが使用されます。

図 -28: 修正カーネル matrix_square_v1 のエリアレポートのソースビュー

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

37

Page 38: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

モジュラス計算を削除して列カウンターに置き換えると、修正されたカーネル matrix_square_v2に示すように、適応ルックアップテーブル(ALUT)および FF 使用量を 50%削減できます。

kernel void matrix_square_v2 (global float* restrict A, unsigned len, global float* restrict out){ // 1. preload the data into local memory // - suppose we know the max size is 4X4 // 2. remove the modulus computation

local int cache_a[16]; for (unsigned k = 0; k < len*len; k++) { cache_a[k] = A[k]; }

unsigned row = 0; unsigned ci = 0; for (unsigned oi = 0; oi < len*len; oi++) { float sum = 0;

// keep a column counter to know when to increment rowif (ci == len) { ci = 0; row += 1;}ci += 1;

for (int col = 0; col < len; col++) { unsigned i = (row * len) + col; // 0, 1, 2, 3, 4,... unsigned j = (col * len) + row; // 0, 3, 6, 9, 1,... sum += cache_a[i] * cache_a[j]; } out[oi] = sum; }}

図 -29: 修正されたカーネル matrix_square_v1 と matrix_square_v2 間のエリア使用の比較

matrix_square_v2 のエリアレポートをさらに調べると、インデックス i と j の計算(つまり、符号なし i =(row * len)+ col および符号なし j =(col * len)+ row)では ALUT と FF の使用量の見積もりが非常に異なることがわかります。さらに、エリアレポートは、これらの 2 つの計算がデジタル信号処理(DSP)ブロックを使用していることも示しています。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

38

Page 39: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -30: 異なるインデックス計算の異なるエリアの使用を示す修正カーネル matrix_square_v2 のエリアレポート

インデックス計算のために DSP と RAM ブロックの使用を 適化する方法は、乗算計算を削除して、下記の修正されたカーネル matrix_square_v3 に示すように、加算を追跡するだけです。

kernel void matrix_square_v3 (global float* restrict A, unsigned len, global float* restrict out) { // 1. preload the data into local memory // - suppose we know the max size is 4X4 // 2. remove the modulus computation // 3. remove DSP and RAM blocks for index calculation helps reduce the latency

local int cache_a[16]; for (unsigned k = 0; k < len*len; k++) { cache_a[k] = A[k]; }

unsigned row_i = 0; unsigned row_j = 0; unsigned ci = 0; for (unsigned oi = 0; oi < len*len; oi++) { float sum = 0; unsigned i, j;

// keep a column counter to know when to increment row if (ci == len) { ci = 0; row_i += len; row_j += 1; } ci += 1;

i = row_i; // initialize i and jj = row_j;for (int col = 0; col < len; col++) {i += 1; // 0, 1, 2, 3, 0,...j += len; // 0, 3, 6, 9, 1,... sum += cache_a[i] * cache_a[j]; } out[oi] = sum; }}

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

39

Page 40: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

乗算ステップを削除することで、下記のエリアレポートに示すように、DSP 使用率を 50%削減できます。さらに、この修正はレイテンシーを短縮するのに役立ちます。

図 -31: 修正されたカーネル matrix_square_v2 と matrix_square_v3 間のエリア使用の比較

レイテンシーをさらに削減するために、修正されたカーネル matrix_square_v3 のループ分析レポートを確認することができます。以下に示すように、解析ペインと詳細ペインでは、 sum + =cache_a [i] * cache_a [j]のループに依存する依存関係があるため、Block27 に II ボトルネックが発生しています。

図 -32: 修正されたカーネルのループ解析 matrix_square_v3

ループで運ばれる依存関係を解決するには、修正されたカーネル matrix_square_v4 で強調表示されているコードに示すように、計算の乗算部分と加算部分を分けることができます。

kernel void matrix_square_v4 (global float* restrict A, unsigned len, global float* restrict out){ // 1. preload the data into local memory // - suppose we know the max size is 4X4 // 2. remove the modulus computation // 3. remove DSP and RAM blocks for index calculation helps reduce the latency // 4. remove loop-carried dependency 'sum' to improve throughput by trading off area

local int cache_a[16]; for (unsigned k = 0; k < len*len; k++) { cache_a[k] = A[k]; }

unsigned row_i = 0; unsigned row_j = 0; unsigned ci = 0; for (unsigned oi = 0; oi < len*len; oi++) { float sum = 0; unsigned i, j;

float prod[4]; // make register

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

40

Page 41: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

#pragma unroll for (unsigned k = 0; k < 4; k++) { prod[k] = 0; }

// keep a column counter to know when to increment row if (ci == len) { ci = 0; row_i += len; row_j += 1; } ci += 1;

i = row_i; // initialize i and j j = row_j; for (int col = 0; col < len; col++) { i += 1; // 0, 1, 2, 3, 0,... j += len; // 0, 3, 6, 9, 1,... prod[col] = cache_a[i] * cache_a[j]; }

sum = prod[0];#pragma unrollfor (unsigned k = 1; k < 4; k++) { sum += prod[k];}

out[oi] = sum; }}

以下のエリアレポートおよびシステムビューアの結果に示されているように、計算ステップを分割することで、エリア使用量の増加を犠牲にしてより高いスループットを達成できます。この変更により、ループのII 値が 1 に減少し、レイテンシーが 30 から 24 に減少します。

図 -33: 修正されたカーネル matrix_square_v4 のエリアレポートとシステムビューアの結果

2.7. HTML レポート:エリア・レポート・メッセージ

OpenCL アプリケーションをコンパイルした後は、 Intel FPGA SDK for OpenCL オフライン・コンパイラーが生成するエリアレポートをレビューします。アプリケーションのリソース使用状況を要約するだけでなく、デザインを変更して効率を向上させる方法の提案もあります。

ボード・インターフェイスのエリア・レポート・メッセージ (42 ページ)

機能オーバヘッドのエリア・レポート・メッセージ (42 ページ)

州のエリア・レポートメッセージ (42 ページ)

フィードバックのためのエリア・レポート・メッセージ (42 ページ)

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

41

Page 42: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

定数メモリーのエリア・レポート・メッセージ (42 ページ)

プライベート変数ストレージのエリア・レポート・メッセージ (43 ページ)

2.7.1. ボード・インターフェイスのエリア・レポート・メッセージ

エリアレポートは、 Intel FPGA SDK for OpenCL オフライン・コンパイラーカスタム・プラットフォームまたはボード・インターフェイス用に生成されます。ボード・インターフェイスは、 PCIe®などの外部インターフェイスとの通信を容易にするデバイスの静的エリアです。カスタム・プラットフォームは、ボード・インターフェイスのサイズを指定します。

表 1. エリア・レポートメッセージに関する追加情報

メッセージ 説明

プラットフォーム・インターフェイス・ロジック。 —

2.7.2. 機能オーバヘッドのエリア・レポート・メッセージ

エリアレポートは、 Intel FPGA SDK for OpenCL オフライン・コンパイラーディスパッチカーネルなどのタスク用に生成されます。

表 2. エリア・レポート・メッセージに関する追加情報

メッセージ 説明

カーネルのディスパッチ・ロジック max_global_work_dim(0)カーネル属性を含むカーネルにはオーバーヘッドはありません。その結果、この行は対応するエリアレポートには存在しません。

2.7.3. 州のエリア・レポートメッセージ

エリアレポートは、デザインがライブ値と制御ロジックに使用するリソースの量を示します。

State の報告された面積消費量を減らすには、次のようにデザインを変更します。

• ローカル変数のサイズの低減

• ローカル変数の範囲を可能な限りローカライズして範囲の低減

• カーネル内のネストされたループの数を減らす

2.7.4. フィードバックのためのエリア・レポート・メッセージ

エリアレポートには、デザインがループに依存する依存関係に使用するリソースが指定されています。

フィードバックの下で報告されたエリアの消費量を減らすには、デザイン内のループ実行変数の数とサイズを低減します。

2.7.5. 定数メモリーのエリア・レポート・メッセージ

エリアレポートは、定数キャッシュメモリーのサイズを指定します。また、データ複製や読み出し動作の回数などの情報も提供します。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

42

Page 43: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

表 3. エリア・レポートメッセージに関する追加情報

メッセージ 説明

<N>バイトの定数キャッシュはすべてのカーネルからアクセス可能で、カーネル呼び出し間で永続的です。 キャッシュ内のデータは、<Y>の読み出しをサポートするために<X>回複製されます。 ヒット、ミスに対して 適化されたキャッシュは、大きなペナルティを発生します。キャッシュ内のデータ量が少ない場合、値をカーネル引数として渡すことを検討してください。キャッシュの有効性を評価するために、キャッシュに対するアクセスのストールをチェックするには、Intel FPGA DynamicProfiler for OpenCL を使用します。実際のキャッシュヒット率のプロファイリングは現在サポートされていません。

2.7.6. プライベート変数ストレージのエリア・レポート・メッセージ

エリアレポートは、 OpenCL デザインに基づいたプライベート・メモリーの実装に関する情報を提供します。Single Work-Item カーネルの場合、 Intel FPGA SDK for OpenCL オフライン・コンパイラー変数のタイプに応じて、プライベート・メモリーを別々に実装します。オフライン・コンパイラーは、さまざまな構成(たとえば、プレーンレジスター、シフトレジスター、バレルシフタ)のレジスターにスカラーと小さな配列を実装します。オフライン・コンパイラーはブロック RAM に大きな配列を実装します。

表 4. エリア・レポート・メッセージに関する追加情報

メッセージ 説明

オンチップブロック RAM を用いたプライベート・メモリーの実現

オンチップのブロック RAM に実装されたプライベート・メモリー。 ブロック RAM 実装は、NDRange カーネルのローカルメモリーと同様のシステムを作成します。

オンチップブロック ROM を用いたプライベート・メモリーの実現

— オンチップブロック ROM を使用するたびに、オフライン・コンパイラーは同じ ROM の別のインスタンスを作成します。オフライン・コンパイラーがオンチップブロック ROM に実装するプライベート変数の明示的な注釈はありません。

レジスターを用いたプライベート・メモリーの実装

次のサイズのレジスターを使用して実装されています。- <X> registers of width <Y> and depth <Z> [(depth wasincreased by a factor of <N> due to a loop initiation intervalof <M>.)]- ...

オフライン・コンパイラーがプライベート変数をレジスターに実装することを報告します。オフライン・コンパイラーは、多くのレジスターにプライベート変数を実装することがあります。このメッセージは、特定の幅と深さを持つレジスターのリストを提供します。

シフトレジスターを用いたプライベート・メモリーの実装

<N>またはより少ないタップポイントを持つシフトレジスターとして実装されています。これは非常に効率的なストレージタイプです。次のサイズのレジスターを使用して実装されています。- <X> register(s) of width <Y> and depth <Z>- ...

オフライン・コンパイラーがシフトレジスターにプライベート変数を実装することを報告します。このメッセージは、シフトレジスターの特定の幅と深さのリストを提供します。オフライン・コンパイラーは、タップポイントに応じて、単一の配列を複数の小さなシフトレジスターに分割することがあります。注意: オフライン・コンパイラーはタップポイントの数を過大評価する

可能性があります。

レジスター付きバレルシフタを用いたプライベート・メモリーの実装

動的インデックス作成によるレジスター付きバレルシフタとして実装されています。これは高オーバーヘッド・ストレージ・タイプです。可能であれば、コンパイル時の既知の索引付けに変更します。この変数にアクセスするためのエリアコストは、アクセスが発生する行に表示されます。次のサイズのレジスターを使用して実装されています。

オフライン・コンパイラーは、ダイナミック・インデックスのためにレジスターを持つバレルシフターにプライベート変数を実装することを報告します。レポートのこの行には、プライベート変数の全エリア使用量が指定されていません。レポートには、変数にアクセスする行に関する追加のエリア使用情報が表示されます。

continued...

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

43

Page 44: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

メッセージ 説明

- <X> registers of width <Y> and depth <Z> [(depth wasincreased by a factor of <N> due to a loop initiation intervalof <M>.)]- ...

注意: • エリアレポートは、実装によっては、プライベート・メモリーを宣言または使用するコードラインにメモリー情報を注釈します。

• オフライン・コンパイラーがオンチップブロック RAM にプライベート・メモリーを実装すると、エリアレポートは、関連するローカルメモリー固有のメッセージをプライベート・メモリーシステムに表示します。

2.8. HTML レポート:カーネルデザインの概念

どのように インテル FPGA SDK for OpenCL カーネル、グローバルメモリー相互接続、ローカルメモリー、ループ、チャネルなどの OpenCL デザインコンポーネントを実装することで、OpenCL のデザインを 適化することができます。

図 -34: OpenCL デザイン例の生成

Kernels (45 ページ)

Global Memory Interconnect (45 ページ)

ローカルメモリー (46 ページ)

Nested Loops (52 ページ)

Single Work-Item カーネルのループ (59 ページ)

チャネル (66 ページ)

ロード・ストア・ユニット (66 ページ)

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

44

Page 45: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

2.8.1. Kernels

Intel FPGA SDK for OpenCL Offline Compiler は、get_global_id()やget_local_id()などのビルトインのワークアイテム関数を使用しないカーネルを単一のワークアイテムカーネルとしてコンパイルします。それ以外の場合、オフライン・コンパイラーはカーネルをNDRange カーネルとしてコンパイルします。

組み込みの Work-Item 関数の詳細については、OpenCL Specification version 1.0 の 6.11.1:Work-Item Functions のいセクションを参照してください。

単一の Work-Item カーネルの場合、オフライン・コンパイラーはカーネル内のすべてのループをパイプライン化して、複数のループ反復を同時に実行できるようにします。コンパイラーがループの一部を効果的にパイプライン化できない場合、またはループをパイプライン化できない場合、カーネルのパフォーマンスが低下する可能性があります。

オフライン・コンパイラーは、NDRange カーネルでループをパイプライン化できません。ただし、これらのループは複数の Work-Item を同時に受け入れることができます。カーネルには複数のループがあり、それぞれにネストされたループがあります。外側のループごとにネストされたループの反復の総数を表にすると、カーネルのスループットは、通常、テーブル化した 大の反復の合計値だけ減少します。

効率的に NDRange カーネルを実行するには、通常、多数のスレッドが必要です。

2.8.2. Global Memory Interconnect

高性能コンピューティングでは、読み書きアクセスのメモリー帯域幅を 大限に活用することが不可欠です。 OpenCL システムには、さまざまな種類のグローバルメモリーインターコネクトが存在します。メモリー相互接続は、 ロード・ストア・ユニット ( LSU )と呼ばれることもあります。

GPU とは異なり、FPGA はアプリケーションに 適なカスタム LSU を構築できます。結果として、アプリケーションに理想的な LSU タイプを選択する OpenCL コードを書く能力が、デザインのパフォーマンスを大幅に向上させるのに役立つかもしれません。

デザインの HTML エリアレポートを見直すと、システムレベルのグローバル・インターコネクトエントリーの値は、グローバル・メモリー・インターコネクトのサイズを表します。

図 -35: OpenCL デザインにおけるグローバル・メモリー・インターコネクトのサイズを示す HTML エリアレポート

HTML レポートでは、メモリー・システム・ビューアは、グローバルメモリー相互接続を負荷(LD)、ストア(ST)、および接続(灰色線)として示しています。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

45

Page 46: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -36: OpenCL デザインにおけるグローバルメモリー相互接続のシステムビューア結果

Intel FPGA SDK for OpenCL Offline Compiler は、デザインのメモリー・アクセス・パターンに基づいて、OpenCL システム用の適切なタイプの LSU を選択します。例示的な LSU タイプには、連続アクセス(または連続アクセス)およびバースト・インターリーブ・アクセスが含まれています。 ページ 131 そしてページ 130 連続したメモリーアクセスとバースト・インターリーブされたメモリーアクセスとの間のアクセスパターンの違いをそれぞれ示しています。

2.8.3. ローカルメモリー

ローカルメモリーは複雑なシステムです。異なるレベルのキャッシュがある一般的な GPU アーキテクチャとは異なり、FPGA はローカルメモリーを FPGA 内部の専用メモリーブロックに実装します。

ローカルメモリー特性• ポート - ローカルメモリーの各バンクには、デザインが同時にアクセスできる書き込みポートと読

み出しポートがあります。

• ダブルポンピング - ダブルポンピング機能により、各ローカル・メモリー・バンクは 大 3 つのリードポートをサポートします。詳細については、 ダブルポンピングのセクションを参照してください。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

46

Page 47: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

ローカルメモリーは複雑なシステムです。異なるレベルのキャッシュがある一般的な GPU アーキテクチャとは異なり、FPGA はローカルメモリーを FPGA 内部の専用メモリーブロックに実装します。

図 -37: 1 つまたは複数の M20K ブロックにおけるローカルメモリーの実装

M20K

M20K

M20K

Local Memory

Read port 0

Write port

lmem

Bank 0

カーネルのコードでは、 local 型の変数としてローカルメモリーを宣言します。

local int lmem[1024];

Intel FPGA SDK for OpenCL Offline Compiler は、幅、深さ、バンク、レプリケーション、相互接続などのローカルメモリープロパティをカスタマイズします。オフライン・コンパイラーは、コードに基づいてアクセスパターンを分析し、アクセス競合を 小限に抑えるためにローカルメモリーを 適化します。

下の図は、サイズ、幅、深さ、バンク、およびレプリケーションの基本的なローカルメモリープロパティを示しています。

図 -38: 複製のないローカルメモリーの例と 2 回複製された 2 つのバンク

Depth=1024

Width=32

Local Memory Size=4096 bytes

Bank 0

Local Memory Size=8192 bytes

Depth=1024

Width=32

Bank 0

Bank 1 Width=32

Local Memory Size=8192 bytes

Bank 0Depth=1024

Bank 0Copy 1

HTML レポートでは、ローカルメモリーの全体的な状態は 適であると報告されていますが、複製されており、潜在的に非効率的です。

高効率カーネルをデザインするための鍵は、決してストールしないメモリーアクセスを持つことです。この場合、データパス内のすべての同時メモリーアクセスサイトは、競合することなくメモリーにアクセスすることが保証されています。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

47

Page 48: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

複雑なカーネルでは、オフライン・コンパイラーは、メモリーアクセスに競合があるかどうかを推測するのに十分な情報がない可能性があります。その結果、オフライン・コンパイラーはローカルメモリーロードストアユニット(LSU)を推論してメモリーアクセスを調停します。しかし、LSU を推論することは非効率を引き起こすかもしれない。詳細については、 ローカルメモリー LSU を参照してください。

図 -39: 複雑なローカル・メモリー・システム

Kernel Pipeline Local MemoryInterconnect

M20K

M20KM20KM20KM20KM20Kport 0

port 1

オフライン・コンパイラーは、指定した正確なサイズのローカルメモリーを実装するとは限りません。FPGA RAM ブロックは特定のディメンションを持つため、オフライン・コンパイラーはサポートされている次の RAM ブロック・ディメンションに切り上げるローカルメモリーサイズを実装します。 RAM ブロックの詳細については、デバイス固有の情報を参照してください。

ローカル・メモリー・バンク

ローカル・メモリー・バンクは、デフォルトで 小次元でのみ機能します。複数のバンクを有することにより、同時書込みが可能になる。次の図は、次のローカル変数宣言の実装を示しています。

local int lmem[1024][4];

図 -40: Implementation of lmem[1024][4]

Depth=1024

Width=32

lmem

Bank 0

Bank 3

Bank 2

Bank 1

Read port 0Write port 0

Read port 3

Read port 2

Read port 1

Write port 3

Write port 2

Write port 1

Local Memory Size=16384 bytes

ループ内の各ローカルメモリーアクセスには、別々のアドレスがあります。次のコード例では、オフライン・コンパイラーは 4 つの別々のバンクを作成するために lmem を推論できます。ループは lmem [][]への 4 つの同時アクセスを可能にし、 適な構成を実現します。

kernel void bank_arb_consecutive_multidim (global int* restrict in, global int* restrict out) {

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

48

Page 49: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

local int lmem[1024][BANK_SIZE];

int gi = get_global_id(0); int gs = get_global_size(0); int li = get_local_id(0); int ls = get_local_size(0);

int res = in[gi];

#pragma unroll for (int i = 0; i < BANK_SIZE; i++) { lmem[((li+i) & 0x7f)][i] = res + i; res >> 1; }

int rdata = 0; barrier(CLK_GLOBAL_MEM_FENCE);

#pragma unroll for (int i = 0; i < BANK_SIZE; i++) { rdata ^= lmem[((li+i) & 0x7f)][i]; }

out[gi] = rdata;

return;}

下位次元でバンクしたくない場合、 bank_bits 属性を指定して、メモリーアドレスからバンク選択ビットとして使用するビットを指定します。 bank_bits 属性を使用すると、メモリーデータを複数のバンクに分割し、どのアドレスビットを使用してバンクを選択するかを指定できます。指定されたbank_bits 属性は、どのメモリーバンクにどのデータ要素が含まれているかを意味します。

local int [4] [128] __attribute __((bank_bits(8,7)、bankwidth(4)));

次の例では、 も低い 2 つの次元の代わりに 7 番目と 8 番目のビットでバンキングが行われます。

#define BANK_SIZE 4kernel void bank_arb_consecutive_multidim_origin (global int* restrict in, global int* restrict out) {

local int a[BANK_SIZE][128] __attribute__((bank_bits(8,7),bankwidth(4)));

int gi = get_global_id(0); int li = get_local_id(0);

int res = in[gi];

#pragma unroll for (int i = 0; i < BANK_SIZE; i++) { a[i][((li+i) & 0x7f)] = res + i; res >> 1; }

int rdata = 0; barrier(CLK_GLOBAL_MEM_FENCE);

#pragma unroll for (int i = 0; i < BANK_SIZE; i++) { rdata ^= a[i][((li+i) & 0x7f)]; }

out[gi] = rdata;

return;}

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

49

Page 50: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

結果のメモリーのビューは、 初の例の初期ビューと同じです。しかし、バンク・オンに間違ったビットを指定すると、メモリーアービトレーション・ロジックが変化します。

メモリーの次のビューは、メモリーを次のように指定した結果です。

local int a[4][128] __attribute__((bank_bits(4,3),bankwidth(4)));

コンパイラーがローカルメモリーへのアクセスを別々のアドレスに推論できない場合、ローカルメモリーの相互接続を使用してアクセスを調停し、パフォーマンスを低下させます。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

50

Page 51: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

ローカルメモリー複製

ローカルメモリーの複製により、同時に読み出し動作が実行されます。オフライン・コンパイラーは、効率的なローカルメモリーアクセスのためにデザインを 適化して、全体的なパフォーマンスを 大化します。メモリー・レプリケーションは、場合によっては非効率なハードウェアにつながりますが、メモリー・レプリケーションは必ずしも RAM の使用を増加させるとは限りません。

オフライン・コンパイラーが 3 つ以上のワークグループが同時にローカルメモリーから読み出していることを認識すると、ローカルメモリーをレプリケートします。ローカルメモリーの複製がデザインエリアを大幅に増やす場合、カーネル内の障壁の数を減らすか、または max_work_group_size 値を大きくして複製のファクタを下げることを検討してください。

ダブルポンピング

デフォルトでは、各ローカル・メモリー・バンクには 1 つの読み出しポートと 1 つの書き込みポートがあります。ダブルポンピング機能により、各ローカル・メモリー・バンクは 大 3 つの読み出しポートをサポートすることができます。

図 -41: ローカルメモリーにおけるダブルポンピングのハードウェア・アーキテクチャ

CLK

2X CLK

Read port 0

Write portRead port 2Read port 1

Local Memory

Bank 0

M20K

LegendMultiplexers implementedby core logic

lmem

ダブルポンピングを可能にする基本的なメカニズムは、M20K ハードウェアにあります。 初のクロックサイクル中、M20K ブロックはダブルクロックになります。次に、第 2 のクロックサイクルの間、ポートは多重化されて 2 つの読み出しポートがさらに形成されます。

ダブルポンピング機能をイネーブルすると、オフライン・コンパイラーはエリア対 大周波数を交換します。オフライン・コンパイラーは、ヒューリスティック・アルゴリズムを使用して 適なメモリー構成を決定します。

ダブルポンピングの利点:• 1 つの読み出しポートから 3 つの読み出しポートに増加する

• RAM 使用量を節約する

ダブルポンピングの短所:• 冗長ロジックを実装する

• 大周波数を下げる可能性がある

次のコード例は、8 つの読み出しポートと 1 つの書き込みポートを持つローカルメモリーの実装を示しています。オフライン・コンパイラーは、ダブルポンピングを可能にし、ローカルメモリーを 3 回複製して、 大 9 つの読み出しポートをサポートできるメモリー構成を実装します。

#define NUM_WRITES 1#define NUM_READS 8#define NUM_BARRIERS 1

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

51

Page 52: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

local int lmem[1024]; int li = get_local_id(0);

int res = in[gi]; #pragma unroll for (int i = 0; i < NUM_WRITES; i++) { lmem[li - i] = res; res >>= 1; } // successive barriers are not optimized away #pragma unroll for (int i = 0; i < NUM_BARRIERS; i++) { barrier(CLK_GLOBAL_MEM_FENCE); } res = 0; #pragma unroll for (int i = 0; i < NUM_READS; i++) { res ^= lmem[li - i]; }

図 -42: Intel FPGA SDK for OpenCL Offline Compiler の 8 個のリードポートと 1 個のライトポートを持つ lmem []の実装

Bank 0Copy 1

Read port 0Read port 1Read port 2

Read port 3Read port 4Read port 5Read port 6Read port 7Read port 8Write port

Bank 0 Bank 0Copy 1

Bank 0Copy 2

lmem

Local Memory

2.8.4. Nested Loops

Intel FPGA SDK for OpenCL オフライン・コンパイラーループ反復の順序付けのためにパイプライン実行を推測しません。その結果、内部ループの反復回数は、異なるループ反復で異なる可能性があるため、外部ループ反復は、その後の内部ループに対して順序が乱れる可能性があります。

アウトオブオーダーのアウターループ反復の問題を解決するには、アウターループ反復間で変化しない上限と下限を持つ内側ループをデザインします。

Single Work-Item の実行

FPGA 上でのハイスループットの Work-Item ベースのカーネル実行を確実にするために、 IntelFPGA SDK for OpenCL オフライン・コンパイラーはある時点で複数のパイプライン・ステージを並列に処理する必要があります。この並列性は、ループの反復をパイプライン化することによって実現されます。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

52

Page 53: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

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 }

各ループ反復の間に、グローバルメモリー a からのデータ値は、 合計[k]に蓄積されます。この例では、4 行目の内側ループの開始インターバル値は 1 で、レイテンシーは 11 です。外側ループも 1 以上の開始インターバル値を持ち、レイテンシーは 8 です。

注意: 新しいループの繰り返しは開始間隔(II)と呼ばれます。 II は、パイプラインが次のループ反復を処理する前に待機しなければならないハードウェア・クロック・サイクルの数を指す。 適にアンロールされたループは、1 つのループ反復がクロックサイクルごとに処理されるため、II の値が 1 です。

図 -43: ループ解析レポート

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

53

Page 55: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -45: Inner Loop accum_swg.B2 Execution

L = 11

3

2

1

0Location of loop iterations in the hardware pipeline after first four iterations have been launched.

Legend

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

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

55

Page 56: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -46: Single Work-Item の実行

非線形実行

ループ構造は線形実行をサポートしていません。次のコード例は、外部ループ i に 2 つの分岐する内部ループが含まれていることを示しています。外側ループの各反復は、1 つの内側ループまたは非直線的実行パターンである他方を実行することができます。

__kernel void structure (__global unsigned* restrict output1, __global unsigned* restrict output2, int N) { for (unsigned i = 0; i < N; i++) { if ((i & 3) == 0) { for (unsigned j = 0; j < N; j++) { output1[i+j] = i * j; } } else { for (unsigned j = 0; j < N; j++) { output2[i+j] = i * j; } } }}

アウトオブオーダーのループ反復

内側ループの反復回数は、外側ループの反復ごとに異なります。次のコード例を検討してください。

__kernel void order( __global unsigned* restrict input, __global unsigned* restrict output int N ) { unsigned sum = 0; for (unsigned i = 0; i < N; i++) { for (unsigned j = 0; j < i; j++) { sum += input[i+j]; }

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

56

Page 57: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

} output[0] = sum;}

この例は、 i = 0 の場合、内側のループ j がゼロ回反復することを示しています。 i = 1 の場合、 jは 1 回反復します。内部ループの反復回数が変わるため、オフライン・コンパイラーはパイプライン処理を推測できません。

シリアルリージョン

内部ループアクセスが外部ループ依存関係を引き起こすと、ネストされたループ内で直列エリアが発生することがあります。内部ループは、データまたはメモリーの依存性のために、外部ループの反復で直列エリアになります。

定常状態では、外側ループの II =内側ループの II *内側ループのトリップ数となります。 II が 1 より大きい内部ループと、直列実行エリアがない外部ループの場合、スレッドを外部ループからインターリーブすることは可能です。

次の式を検討してみましょう。

kernel void serially_execute (global int * restrict A, global int * restrict B, global int * restrict result, unsigned N) { int sum = 0; for (unsigned i = 0; i < N; i++) { int res; for (int j = 0; j < N; j++) { sum += A[i*N+j]; } sum += B[i]; } *result = sum;}

この例では、外側ループの依存関係は、内側ループの逐次実行をもたらしました。パフォーマンスの主な違いは、内側ループの定常状態 II =内側ループ*(内側ループのトリップ数-1)+レイテンシーです。この例では、内部ループの II は 4 のレイテンシーを持ち、II は外部ループの II であり、レイテンシーは 7です。N が大きい場合(レイテンシーと比較して 400 など)、外部ループ II からの影響はほとんどありません。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

57

Page 59: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -48: シリアル実行

2.8.5. Single Work-Item カーネルのループ

Intel FPGA SDK for OpenCL オフライン・コンパイラーデータ処理のパフォーマンスを 大限にするためにカーネルを 適化するアルゴリズムを実装しています。

単一の Work-Item カーネル内のループのデータパスは、飛行中に複数の反復を含むことができます。この動作は、NDRange カーネルのループに Multiple Work-Item が含まれている点で、NDRangeカーネル内のループとは異なります。 適にアンロールされたループとは、クロックサイクルごとに起動されるループの繰り返しです。クロックサイクルごとに 1 回のループ反復を開始すると、パイプラインの効率が 大化され、 高のパフォーマンスが得られます。下の図に示すように、クロックサイクルごとに1 つのループを起動することで、カーネルの処理速度が向上します。

図 -49: パイプライン化されていないループとパイプライン化されたループの間のループ反復の起動頻度の比較

Cloc

k Cy

cles

i0

i1

i2 Cloc

k Cy

cles

i0i1

i5i4

i3i2

Non-Pipelined Loop Pipelined Loop

新しいループ反復の開始頻度は開始間隔(II)と呼ばれます。 II は、パイプラインが次のループ反復を処理する前に待機しなければならないハードウェアクロックサイクルの数を示します。 適にアンロールされたループは、1 つのループ反復がクロックサイクルごとに処理されるため、II の値が 1 です。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

59

Page 60: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

HTML レポートでは、 適に展開されていないループのループ分析で、オフライン・コンパイラーがループを正常にパイプライン処理したことが示されます。

次の式を検討してみましょう。

kernel void simple_loop (unsigned N, global unsigned* restrict b, global unsigned* restrict c, global unsigned* restrict out){ for (unsigned i = 1; i < N; i++) { c[i] = c[i-1] + b[i]; } out[0] = c[N-1];}

図 -50: カーネルのハードウェア表現 simple_loop

Load

i=2

i=1

i=0

Store

この図は、オフライン・コンパイラーが並列実行とループパイプライニングを使用して simple_loopを効率的に実行する方法を示しています。この simple_loop カーネルのループ解析レポートは、for.body ループの場合、 Pipelined 列は Yes を示し、 II 列は 1 を示します。

クリティカルパスと最大周波数のトレードオフ

可能であれば、オフライン・コンパイラーは与えられたループに対して II の値 1 を達成しようと試みます。いくつかのケースでは、オフライン・コンパイラーは、ターゲット fmax が低下して 1 になるように努力するかもしれません。

次の式を検討してみましょう。

kernel void nd (global int *dst, int N) { int res = N; #pragma unroll 9 for (int i = 0; i < N; i++) { res += 1; res ^= i; } dst[0] = res;}

次の論理図は、カーネル ND の実際の、より複雑なハードウェア実装の簡略化した表現です。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

60

Page 61: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -51: カーネルにおけるループの論理図

11

. . .unroll_inst_0

unroll_inst_1

unroll_inst_8

i

XORXOR

XORres_next

res

. . .i+1 i+8

1

図 -52: カーネルの実際のハードウェア実装

unroll_inst_0 unroll_inst_1 unroll_inst_2

加算演算と XOR ゲートによるフィードバックは、オフライン・コンパイラーが目標周波数を達成する能力を制限するクリティカルパスです。結果として得られる HTML レポートは、クリティカルパスを構成するコントリビュータの内訳をパーセンテージで表したものです。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

61

Page 62: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -53: カーネルのループ解析レポートの詳細ペイン"9%: Add Operation (fmax_report.cl:5)"行は、フィードバックごとに 1 回で 9 回繰り返されます。

ループの起動間隔に影響を与えるループキャリー依存関係

ループがパイプライン化されているにもかかわらず、II の値が 1 にならない場合があります。これらのケースは、通常、データ依存性またはループ内のメモリー依存性によって発生します。

データ依存とは、ループ反復で以前の反復に依存する変数を使用する状況を指します。この場合、ループはパイプライン化できますが、その II 値は 1 より大きくなります。次の例を検討してください。

1 // An example that shows data dependency 2 // choose(n, k) = n! / (k! * (n-k)!) 3 4 kernel void choose( unsigned n, unsigned k, 5 global unsigned* restrict result ) 6 { 7 unsigned product = 1; 8 unsigned j = 1; 910 for( unsigned i = k; i <= n; i++ ) {11 product *= i;12 if( j <= n-k ) {13 product /= j;14 }15 j++;16 }1718 *result = product;19 }

すべてのループ反復において、カーネル choose における product 変数の値は、インデックス i の現在の値に前回の反復からの product の値を掛けて計算されます。その結果、現在の反復が処理を終了するまで、ループの新しい反復を開始することはできません。下の図は、システムビューアに表示されるカーネル choose の論理ビューを示しています 。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

62

Page 63: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -54: カーネルの論理ビュー

カーネル選択のループ分析レポートは、ブロック 1 の II 値が 13 であることを示します。さらに、詳細ペインでは、高 II 値が製品へのデータ依存によって発生し、クリティカルパスへの 大貢献者は整数 13行目の除算演算。

図 -55: カーネル choose のループ分析レポート

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

63

Page 64: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -56: カーネル choose のループ分析レポートの詳細ペインの情報

メモリー依存とは、前のループ反復からのメモリーアクセスが完了するまで、ループ反復におけるメモリーアクセスが進まない状況を指す。次の例を検討してください。

1 kernel void mirror_content( unsigned max_i,2 global int* restrict out)3 {4 for (int i = 1; i < max_i; i++) {5 out[max_i*2-i] = out[i];6 }7 }

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

64

Page 66: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

関連情報シングル・ワーク・アイテム・カーネル対 NDRange カーネル (9 ページ)

2.8.6. チャネル

Intel FPGA SDK for OpenCL のチャネルインプリメンテーションは、あるカーネルから別のカーネルにデータを渡してパフォーマンスを向上させる柔軟な方法を提供します。

カーネルコードでチャネルを宣言するときは、宣言の前にキーワード channel を付けてください 。

例:channel long16 myCh __attribute__((depth(16)));

HTML レポートでは、エリアレポートによってチャネルエリアがソースコードの宣言行にマップされます。チャネルおよびチャネルアレイは、その幅および深さとともに報告されます。

実装されたチャネル深度は、チャネル宣言で指定した深度と異なる場合があります。 OpenCL オフライン・コンパイラー用インテル FPGA SDK は、シフトレジスターまたは RAM ブロックにチャネルを実装できます。オフライン・コンパイラーは、チャネル深度に基づいてチャネル実装のタイプを決定します。

2.8.7. ロード・ストア・ユニット

Intel FPGA SDK for OpenCL オフライン・コンパイラーさまざまな種類のロードストアユニット(LSU)を生成します。 LSU の種類によっては、コンパイラーがメモリー・アクセス・パターンやその他のメモリー属性に応じて LSU の動作やプロパティを変更することがあります。

ロードストアのユニットタイプまたは修飾子を明示的に選択することはできませんが、コード内のメモリー・アクセス・パターン、使用可能なメモリーのタイプ、およびメモリーアクセスがローカルメモリーかグローバルメモリーかを変更することによって、コンパイラーがインスタンス化する LSU のタイプに影響を与えることができます 。

ロード・ストア・ユニットのタイプ

コンパイラーは、推論されたメモリー・アクセス・パターン、ターゲットプラットフォームで使用可能なメモリーの種類、およびメモリーアクセスがローカルメモリーかグローバルメモリーかに基づいて、いくつかの異なる種類のロード・ストア・ユニット(LSU)を生成できます。 Intel FPGA SDK for OpenCL オフライン・コンパイラーは、次のタイプの LSU を生成できます。

• バースト合体のロード・ストア・ユニット (67 ページ)

• ロード・ストア・ユニットのプリフェッチ (67 ページ)

• ストリーミングロードストアユニット (67 ページ)

• セミストリーミングロードストアユニット (68 ページ)

• ローカル・パイプラインロードストアユニット (68 ページ)

• Global Infrequent Load-Store Units (68 ページ)

• コンスタント・パイプライン・ロード・ストア・ユニット (69 ページ)

• 原子パイプライン式ロード・ストア・ユニット (69 ページ)

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

66

Page 67: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

バースト合体のロード・ストア・ユニット

バースト合体 LSU は、コンパイラーによってインスタンス化されるデフォルトの LSU タイプです。可能な限り大きなバーストが生成されるまで要求をバッファーします。バースト合体 LSU は大域メモリーへの効率的なアクセスを提供できますが、相当量の FPGA リソースが必要です。

kernel void burst_coalesced (global int * restrict in, global int * restrict out) { int i = get_global_id(0); int value = in[i/2]; // Burst-coalesced LSU out[i] = value;}

メモリー・アクセス・パターンやその他の属性によっては、次の方法でバースト合体 LSU を変更することがあります。

• キャッシュ (69 ページ)

• ライト・アクノリッジ(ライト・アクノリッジ) (70 ページ)

• 非整列 (70 ページ)

ロード・ストア・ユニットのプリフェッチ

先読み LSU は、先行するアドレスに基づいて FIFO に有効なデータを完全に保持し、連続した読み出しを仮定するために、バーストがメモリーから大きなブロックを読み出す FIFO(時には名前付きパイプと呼ばれる)をインスタンス化します。不連続リードはサポートされていますが、FIFO をフラッシュして再充填する際に不利益が生じます。

kernel void prefetching (global int * restrict in, global int * restrict out, int N) { int res = 1; for (int i = 0; i < N; i++) { int v = in[i]; // Prefetching LSU res ^= v; } out[0] = res;}

ストリーミングロードストアユニット

ストリーミング LSU は、FIFO が有効なデータでいっぱいになるように、大きなブロックをメモリーからFFIFO をインスタンス化します。このデータブロックは、メモリーアクセスが順序通りであり、アドレスがベースアドレスからの単純なオフセットとして計算できる場合にのみ使用できます。

kernel void streaming (global int * restrict in, global int * restrict out) { int i = get_global_id(0); int idx = out[i]; // Streaming LSU int cached_value = in[idx]; out[i] = cached_value; // Streaming LSU}

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

67

Page 68: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

セミストリーミングロードストアユニット

セミストリーミング LSU は、読み出し専用キャッシュをインスタンス化します。キャッシュにはエリアのオーバーヘッドがありますが、グローバルメモリー内の同じデータ位置に繰り返しアクセスする場合、パフォーマンスが向上します。カーネル内のストアによってデータが上書きされないようにする必要があります。これは、キャッシュの一貫性を損なうためです。 LSU キャッシュは、関連するカーネルが開始されるたびにフラッシュされます。

#define N 16kernel void semi_streaming (global int * restrict in, global int * restrict out) { #pragma unroll 1 for (int i = 0; i < N; i++) { int value = in[i]; // Semi-streaming LSU out[i] = value; }}

ローカル・パイプラインロードストアユニット

ローカル・パイプライン化された LSU は、ローカルメモリーにアクセスするために使用されるパイプライン化された LSU です。リクエストは受信するとすぐに提出されます。メモリーアクセスはパイプライン化されているので、一度に複数のリクエストを飛行することができます。 LSU とローカルメモリーとの間にアービトレーションがない場合、ローカル・パイプライン化されたノーストール LSU が作成されます。

__attribute((reqd_work_group_size(1024,1,1)))kernel void local_pipelined (global int* restrict in, global int* restrict out) { local int lmem[1024]; int gi = get_global_id(0); int li = get_local_id(0);

int res = in[gi]; for (int i = 0; i < 4; i++) { lmem[li - i] = res; // Local-pipelined LSU res >>= 1; }

barrier(CLK_GLOBAL_MEM_FENCE);

res = 0; for (int i = 0; i < 4; i++) { res ^= lmem[li - i]; // Local-pipelined LSU }

out[gi] = res;}

コンパイラーは、ローカル・パイプライン化された LSU を次のように変更する可能性があります。

• Never-stall (70 ページ)

Global Infrequent Load-Store Units

グローバルな頻度の低い LSU は、まれであることが証明できるグローバル・メモリー・アクセスに使用されるパイプライン型の LSU です。グローバルなまれな LSU は、ループに含まれていないメモリー動作に対してのみインスタンス化され、NDRange カーネル内の単一のスレッドに対してのみアクティブです。

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

68

Page 69: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

パイプライン化された LSU は他の LSU タイプよりも小さいため、コンパイラーはパイプライン化されたLSU としてグローバルなまれな LSU を実装します。パイプライン化された LSU のスループットは低下する可能性がありますが、メモリーアクセスがまれであるため、このスループットのトレードオフは許容されます。

kernel void global_infrequent (global int * restrict in, global int * restrict out, int N) { int a = 0; if (get_global_id(0) == 0) a = in[0]; // Global Infrequent LSU for (int i = 0; i < N; i++) { out[i] = in[i] + a; }}

コンスタント・パイプライン・ロード・ストア・ユニット

一定のパイプライン化された LSU は、主に定数キャッシュからの読み出しに使用されるパイプライン化された LSU です。一定のパイプライン化された LSU は、バースト合体 LSU より少ない面積を消費する。一定パイプライン化された LSU のスループットは、リードが定数キャッシュ内でヒットしたかどうかによって大きく異なります。キャッシュミスは高価です。

kernel void constant_pipelined (constant int *src, global int *dst) { int i = get_global_id(0); dst[i] = src[i]; // Constant pipelined LSU}

インスタンス ID について詳しくは、キャッシュ・メモリー (132 ページ)を参照してください。

原子パイプライン式ロード・ストア・ユニット

アトミックパイプライン化された LSU は、すべてのアトミック動作に使用されます。アトミック動作を使用すると、カーネルのパフォーマンスが大幅に低下する可能

kernel void atomic_pipelined (global int* restrict out) { atomic_add(&out[0], 1); // Atomic LSU}

ロードストアユニット修飾子

カーネルのメモリー・アクセス・パターンに応じて、コンパイラーはいくつかの LSU を変更します。

キャッシュ

バースト合体 LSU にはキャッシュが含まれることがあります。キャッシュは、メモリー・アクセス・パターンがデータ依存であるか、または繰り返しているように見える場合に作成されます。ロードで同じデータが必要な場合でも、キャッシュを他のロードと共有することはできません。キャッシュはカーネル開始時にフラッシュされ、キャッシュなしで同等の LSU より多くのハードウェア・リソースを消費します。キャッシュは、アクセスパターンを簡素化するか、ポインターを揮発性としてマークすることによって無効にすることができます。

kernel void cached (global int * restrict in, global int * restrict out) { int i = get_global_id(0); int idx = out[i]; int cached_value = in[idx]; // Burst-coalesced cached LSU out[i] = cached_value;}

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

69

Page 70: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

ライト・アクノリッジ(ライト・アクノリッジ)

バースト集約されたストア LSU は、データの依存関係が存在する場合、書き込み確認信号を必要とすることがあります。ライトアクノリッジ信号を有する LSU は、追加のハードウェア資源を必要とする。複数のライトアクノリッジ LSU が同じメモリーにアクセスすると、スループットが低下する可能性があります。

kernel void write_ack (global int * restrict in, global int * restrict out, int N) { for (int i = 0; i < N; i++) { if (i < 2) out[i] = 0; // Burst-coalesced write-ack LSU out[i] = in[i]; }}

非整列

バースト合体 LSU が外部メモリー・ワード・サイズにアラインメントされていないメモリーにアクセスできる場合、アラインメントされていない LSU が作成されます。アラインメントされていない LSU を実装するには、追加のハードウェア・リソースが必要です。アラインメントされていない多くの要求を受信すると、アラインメントされていない LSU のスループットが低下する可能性があります。

kernel void non_aligned (global int * restrict in, global int * restrict out) { int i = get_global_id(0); // three loads are statically coalesced into one, creating a Burst-coalesced non-aligned LSU int a1 = in[3*i+0]; int a2 = in[3*i+1]; int a3 = in[3*i+2]; // three stores statically coalesced into one out[3*i+0] = a3; out[3*i+1] = a2; out[3*i+2] = a1;}

Never-stall

ローカル・パイプライン化された LSU がアービトレーションせずにローカルメモリーに接続されている場合、メモリーへのすべてのアクセスがコンパイラーに知られている一定数のサイクルになるため、ストールしない LSU が作成されます。

次の例では、96 ビット幅のメモリーアクセスの一部は 2 つのメモリーワードにまたがるため、メモリーから 2 つのフルラインのデータを読み出す必要があります。

__attribute((reqd_work_group_size(1024,1,1)))kernel void never_stall (global int* restrict in, global int* restrict out, int N) { local int lmem[1024]; int gi = get_global_id(0); int li = get_local_id(0);

lmem[li] = in[gi]; // Local-pipelined never-stall LSU barrier(CLK_GLOBAL_MEM_FENCE); out[gi] = lmem[li] ^ lmem[li + 1];}

2. カーネルの report.html ファイルのレビューUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

70

Page 71: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

3. OpenCL カーネルデザインのベスト・プラクティス

Intel FPGA SDK for OpenCL オフライン・コンパイラー技術を使用すると、固定ハードウェア・アーキテクチャに 適に適合するようにカーネルを変更する必要はありません。代わりに、オフライン・コンパイラーは、ハードウェア・アーキテクチャをカーネル要件に合わせて自動的にカスタマイズします。

一般に、 初に単一のコンピューティング・ユニットをターゲットとするカーネルを 適化する必要があります。このコンピューティング・ユニットを 適化した後、ハードウェアをスケーリングして FPGA の残りの部分を満たすようにパフォーマンスを上げてください。カーネルのハードウェア・フットプリントは、ハードウェアのコンパイルに要する時間と相関します。したがって、より小さなフットプリント(つまり、単一の計算単位)で実行できる 適化が増えるほど、一定の時間内に実行できるハードウェアの数が増えます。

データ処理とメモリーアクセスの 適化に加えて、カーネルの作成時には、必要に応じて次のデザイン方法を実装することを検討してください。

データを経由して転送する インテル FPGA SDK for OpenCL チャネルまたは OpenCL パイプ (71ページ)

ループのアンロール (76 ページ)

浮動小数点演算の 適化 (78 ページ)

アラインメントされたメモリーの割り当て (80 ページ)

構造体をパディング付きまたはパディングなしで整列する (81 ページ)

ベクトル型要素の類似構造の維持 (83 ページ)

ポインター・エイリアシングの回避 (83 ページ)

高価な機能の回避 (84 ページ)

Work-ItemID 依存の後方分岐の回避 (85 ページ)

3.1. データを経由して転送する インテル FPGA SDK for OpenCL チャネルまたはOpenCL パイプ

カーネル間のデータ転送効率を高めるには、 インテル FPGA SDK for OpenCL カーネルプログラムのチャンネル拡張を実装します。チャネルの機能を活用したいが、他の SDK を使用してカーネルプログラムを実行できるようにするには、OpenCL パイプを実装します。

時には、FPGA からグローバルメモリーへの帯域幅は、カーネル間のデータ転送効率を制限します。理論上の 大 FPGA 対グローバルメモリー帯域幅は、対象のカスタム・プラットフォームおよびボードで使用可能なグローバルメモリーバンクの数によって異なります。ボードの理論上の 大帯域幅を決定するには、ボードベンダのマニュアルを参照してください。

実際には、カーネルは使用可能な 大グローバルメモリー帯域幅の 100%使用を達成していません。使用率は、アルゴリズムのアクセスパターンによって異なります。

UG-OCL003 | 2017.12.08

フィードバック

Intel Corporation.無断での引用、転載を禁じます。Intel、インテル、Intel ロゴ、Altera、ARRIA、CYCLONE、ENPIRION、MAX、NIOS、QUARTUS および STRATIX の名称およびロゴは、アメリカ合衆国および/ またはその他の国における Intel Corporationの商標です。インテルは FPGA 製品および半導体製品の性能がインテルの標準保証に準拠することを保証しますが、インテル製品およびサービスは、予告なく変更される場合があります。インテルが書面にて明示的に同意する場合を除き、インテルはここに記載されたアプリケーション、または、いかなる情報、製品、またはサービスの使用によって生じるいっさいの責任を負いません。インテル製品の顧客は、製品またはサービスを購入する前、および、公開済みの情報を信頼する前には、デバイスの仕様を 新のバージョンにしておくことをお勧めします。*その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

ISO9001:2015登録済

Page 72: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

グローバルメモリー帯域幅が OpenCL カーネルのパフォーマンス制約条件である場合、まずアルゴリズムを複数の小さなカーネルに分解してみてください。次に、下の図に示すように、SDK カーネル間のデータ転送用のチャネルまたは OpenCL パイプを実装してグローバル・メモリー・アクセスの一部を削除します。

図 -59: チャネルまたはパイプの実装結果としてのグローバル・メモリー・アクセス・パターンの違い

Global Memory

Kernel 1 Kernel 4Kernel 2 Kernel 3Write

ReadRead

ReadRead

WriteWriteWrite

Global Memory

Kernel 1 Kernel 4Kernel 2 Kernel 3

Read

Write

Channel/Pipe Channel/Pipe

Global Memory Access Pattern Before Intel FPGA SDK for OpenCL Channels or Pipes Implementation

Global Memory Access Pattern After Intel FPGA SDK for OpenCL Channels or Pipes Implementation

Channel/Pipe

チャネルの使用方法の詳細については インテル FPGA SDK for OpenCL プログラミング・ガイドのインテル FPGA SDK for OpenCL チャネル拡張の実装のセクションを参照してください。

パイプの使用方法の詳細については、 インテル FPGA SDK for OpenCL プログラミング・ガイドのOpenCL パイプの実装のセクションを参照してください。

関連情報• Implementing Intel FPGA SDK for OpenCL Channels Extension

• Implementing OpenCL Pipes

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

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

基本動作

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

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

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

3. OpenCL カーネルデザインのベスト・プラクティスUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

72

Page 73: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

重要: パイプ固有の考慮事項:

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

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

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

暗黙のカーネル同期

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

表 5. カーネル同期のためのチャネルとパイプコールのブロック

ブロッキング・チャネルコールを持つカーネル ブロッキング・パイプ・コールを持つカーネル

channel int c0;

__kernelvoid producer (__global int * in_buf) { for (int i = 0; i < 10; i++) { write_channel_intel (c0, in_buf[i]); } }

__kernelvoid consumer (__global int * ret_buf) { for (int i = 0; i < 10; i++) { ret_buf[i] = read_channel_intel(c0); }}

__kernelvoid 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]); }}

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

3. OpenCL カーネルデザインのベスト・プラクティスUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

73

Page 74: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

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

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

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

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

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

関連情報Ensuring Compatibility with Other OpenCL SDKs

3.1.2. チャネルおよびパイプの実行順序

カーネルプログラムの各チャネルまたはパイプ呼び出しは、FPGA パイプラインで実行される命令に変換されます。 チャネルコールまたはパイプ呼び出しの実行は、有効な Work-Item がパイプラインを通じて実行される場合に発生します。ただし、チャネルまたはパイプ呼び出しの間に制御またはデータ依存がない場合でも、それらの実行はカーネル・パイプラインで完全な命令レベルの並列性を達成できないことがあります。

次のコードの例を検討してみましょう。

表 6. 2 つのリードチャネルまたはパイプ呼び出しを持つカーネル

2 つのリードチャネルコールを持つカーネル 2 つのパイプ呼び出しを読み込んだカーネル

__kernel voidconsumer (__global uint*restrict dst) { for (int i = 0; i < 5; i++) { dst[2*i] = read_channel_intel(c0); dst[2*i+2] = read_channel_intel(c1); }}

__kernel voidconsumer (__global uint*restrict dst, read_only pipe uint __attribute__((blocking)) c0, read_only pipe uint __attribute__((blocking)) c1){ for (int i = 0; i < 5; i++) { read_pipe (c0, &dst[2*i]); read_pipe (c1, &dst[2*i+2]); }}

左側のコード例は、2 つの読み出しチャネル呼び出しを行います。右側のコード例は、2 つの読み出しパイプ呼び出しを行います。ほとんどの場合、カーネルはこれらのチャネル呼び出しまたはパイプ呼び出しを並列に実行します。ただし、チャネルおよびパイプ・コールの実行が順不同で行われる可能性があります。アウト・オブ・シーケンス実行は、C1 からの読み出し動作が発生し、C0 からの読み出し動作の前に完了することができることを意味します。

3. OpenCL カーネルデザインのベスト・プラクティスUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

74

Page 75: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

3.1.3. チャネルまたはパイプのバッファー推論の最適化

バッファーされたチャネルまたはパイプの手動による追加に加えて、 Intel FPGA SDK for OpenCLオフライン・コンパイラーは可能な限りバッファーサイズを調整してカーネルのスループットを向上させます。

コンパイル時に、オフライン・コンパイラーは、相互作用するチャネルまたはパイプ間のスケジューリングの不一致を計算します。これらの不一致は、読み出しと書き込みの動作の不均衡を引き起こす可能性があります。オフライン・コンパイラーは、不均衡を修正するためにバッファー推論 適化を自動的に実行します。

次の例を検討してみましょう。

表 7. チャネルとパイプのバッファー推論の最適化

チャンネル付きカーネル パイプ付きカーネル

__kernel void producer ( __global const uint * restrict src, const uint iterations){ for(int i = 0; i < iteration; i++) { write_channel_intel(c0,src[2*i]); write_channel_intel(c1,src[2*i+1]); }}

__kernel void consumer ( __global uint * restrict dst, const uint iterations){ for(int i = 0; i < iterations; i++) { dst[2*i] = read_channel_intel(c0); dst[2*i+1] = read_channel_intel(c1); }}

__kernel void producer ( __global const uint * restrict src, const uint iterations, write_only pipe uint __attribute__((blocking)) c0, write_only pipe uint __attribute__((blocking)) c1){ for(int i = 0; i < iteration; i++) { write_pipe(c0,&src[2*i]); write_pipe(c1,&src[2*i+1]); }}

__kernel void consumer ( __global uint * restrict dst, const uint iterations, read_only pipe uint __attribute__((blocking)) c0, read_only pipe uint __attribute__((blocking)) c1){ for(int i = 0; i < iterations; i++) { read_pipe(c0,&dst[2*i]); read_pipe(c1,&dst[2*i+1]); }}

オフライン・コンパイラーは、カーネル間のチャネルまたはパイプがサイクルを形成できない場合、バッファー推論の 適化を実行します。カーネル間の cycl は、カーネルから、書き込みチャネルまたは書き込みパイプ呼び出しを経由して元のカーネルに戻るパスです。この例では、カーネル producer のライトチャネルまたはライトパイプコールが 10 サイクル離れてスケジュールされ、リードチャネルまたはリードパイプコールが 15 サイクル離れてスケジュールされているとします。C1 への読み出し動作が発生する前に、5 つの余分な書き込み動作が発生するかもしれないのであり、読み出しが一時的に不一致が存在すると C1 に書き込み動作を。この不均衡を修正するために、オフライン・コンパイラーは、ストールを避けるために c1 に 5 サイクルのバッファーサイズを割り当てます。追加のバッファー容量は、producer カーネルの c1 書き込み動作と consumer カーネルの c1 読み出し動作を切り離します。

3.1.4. チャネルとパイプのベスト・プラクティス

チャネルとパイプをデザインする際には、次のベスト・プラクティスを考慮してください。

3. OpenCL カーネルデザインのベスト・プラクティスUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

75

Page 76: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

• マルチ・スレッド・カーネルよりもシングル・スレッド・カーネルを使用してください。

• デザインモデルがフィード・フォワード・データパス、例えばバックツーバックループまたは離散処理ステップでどのように表現できるかを検討します。デザインをチャネルで接続された複数のカーネルに分割する必要があるかどうかを判断します。

• カーネルの同じポイントでデータ全体が使用されている場合のみ、チャネル上のデータを集約します。

• カーネルあたりのチャネル数を妥当なものに保つようにしてください。

• データを待っているループ構造を使用している場合、非ブロッキング・チャネルまたはパイプを使用しないでください。非ブロッキング・チャネルは、ブロッキング・チャネルより多くのリソースを消費します。

3.2. ループのアンロール

Intel FPGA SDK for OpenCL オフライン・コンパイラー OpenCL カーネル記述をハードウェア・リソースに変換します。 OpenCL カーネルにループ反復が含まれている場合、ループを展開してパフォーマンスを向上させてください。ループ展開は、ハードウェア・リソース消費の増加を犠牲にしてオフライン・コンパイラーが実行する反復回数を減少させます。

各 Work-Item が配列内の 4 つの要素の累積を計算する責任がある並列アプリケーション用のOpenCL コードを検討してください。

__kernel void example ( __global const int * restrict x, __global int * restrict sum ) { int accum = 0;

for (size_t i = 0; i < 4; i++) { accum += x[i + get_global_id(0) * 4]; }

sum[get_global_id(0)] = accum;}

このカーネルでは、以下の 3 つの主要な動作が行われています。

• 入力 x からのロード動作

• 累積

• オペレーションを出力 sum に格納する

オフライン・コンパイラーは、OpenCL カーネルコードのデータフローセマンティクスに従って、これらの動作をパイプラインに配置します。たとえば、オフライン・コンパイラーは、ループ終了条件に応じて、パイプラインの 後からパイプラインの先頭に結果を転送することによってループを実装します。

OpenCL カーネルは、クロックサイクルごとに各 Work-Item の 1 回のループ反復を実行します。十分なハードウェア・リソースがあれば、ループを展開することでカーネルのパフォーマンスを向上させることができ、カーネルが実行する反復回数が減ります。ループをアンロールするには、次のコード例に示すように、 #pragma unroll ディレクティブをメインループに追加します。ループをアンロールすると、オフライン・コンパイラーが作成するコンピューティング・ユニットの構造が大幅に変更されることに注意してください。

__kernel void example ( __global const int * restrict x, __global int * restrict sum ) { int accum = 0;

#pragma unroll for (size_t i = 0; i < 4; i++) { accum += x[i + get_global_id(0) * 4];

3. OpenCL カーネルデザインのベスト・プラクティスUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

76

Page 77: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

}

sum[get_global_id(0)] = accum;}

この例では、 #pragma unroll ディレクティブにより、オフライン・コンパイラーはループの 4 つの繰り返しを完全に展開します。アンロールを達成するために、オフライン・コンパイラーは、加算演算の数を 3 倍にし、4 倍のデータをロードすることによってパイプラインを拡張します。ループが除去されると、コンピューティング・ユニットはフィードフォワード構造を前提します。結果として、コンピューティング・ユニットは、初期ロード動作および加算の完了後にクロックサイクルごとに sum 要素を記憶することができる。オフライン・コンパイラーは、4 つのロード動作を統合することによってこのカーネルをさらに適化し、コンピューティング・ユニットが 1 つのロード動作で結果を計算するために必要なすべての入力データをロードできるようにします。

注意: ネストされたループ構造は使用しないでください。代わりに、可能であれば#pragma unroll ディレクティブを追加して大きな単一ループを実装するか、内部ループを展開してください。

ループをアンロールし、グローバルメモリーからロード動作を統合することにより、ハードウェアによるカーネルのインプリメンテーションでクロックサイクルごとに多くの動作を実行できます。一般に、OpenCL カーネルのパフォーマンスを向上させるために使用する方法は、次の結果を達成する必要があります。

• 並列動作の数を増やす

• 実装のメモリー帯域幅を増やす

• カーネルがハードウェアで実行できるクロックサイクルあたりの動作数を増やす

オフライン・コンパイラーは、以下の状況で完全にループを展開することができない場合があります。

• 非常に多数の反復を伴うデータ依存ループの完全なアンローリングを指定します。したがって、カーネルのハードウェア実装が FPGA に適合しない可能性があります。

• 完全な展開を指定し、ループの境界は定数ではありません。

• ループは、複雑な制御フローで構成されます(たとえば、コンパイル時に不明な複雑な配列インデックスまたは終了条件を含むループ)。

上記の 後の 2 つのケースでは、オフライン・コンパイラーは次の警告を発行します。

ループのフルアンロールが要求されますが、ループの境界を特定できません。ループはアンロールされません。

これらの状況でループのアンロールをイネーブルするには、 #pragma unroll <N> ディレクティブ(<N>はアンロール係数である)を指定します。アンロール係数は、オフライン・コンパイラーがアンロールする回数を制限します。たとえば、カーネル内のループが展開されないようにするには、そのループに#pragma unroll 1 ディレクティブを追加します。

適切に構成されたループを構築するためのヒントについては、Good Design Practices for SingleWork-Item Kernel を参照してください。

関連情報Single Work-Item カーネルの良いデザイン方法 (113 ページ)

3. OpenCL カーネルデザインのベスト・プラクティスUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

77

Page 78: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

3.3. 浮動小数点演算の最適化

浮動小数点演算の場合、 Intel FPGA SDK for OpenCL オフライン・コンパイラーハードウェアでより効率的なパイプライン構造を作成し、ハードウェア全体の使用を削減する 適化を実行します。これらの

適化は、浮動小数点結果の小さな違いを引き起こす可能性があります。

ツリーのバランス

動作規則の順序は OpenCL 言語で適用されます。次の例では、オフライン・コンパイラーは も内側の括弧内の演算から始まる厳密な順序で乗算と加算を実行します。

result = (((A * B) + C) + (D * E)) + (F * G);

デフォルトでは、オフライン・コンパイラーは、そのような計算のためにロングブレインに似た実装を作成します。

図 -60: デフォルトの浮動小数点実装

+

+

+

A

G

DC

B

E

Result

F

長くて不均衡な動作は、より高価なハードウェアにつながります。より効率的なハードウェア実装は、以下に示すようにバランスの取れたツリーです 。

3. OpenCL カーネルデザインのベスト・プラクティスUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

78

Page 79: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -61: 平衡化されたツリー浮動小数点実装

++

+

A D

C

E FB G

Result

バランスの取れたツリーの実装では、オフライン・コンパイラーは、長いブレインの浮動小数点加算器をツリーパイプライン構造に変換します。オフライン・コンパイラーは、浮動小数点演算の結果が異なるため、浮動小数点演算のツリー・バランシングを自動的に実行しません。その結果、この 適化は IEEE 標準 754-2008 と矛盾します。

オフライン・コンパイラーで平衡ツリーを使用して浮動小数点演算を 適化し、プログラムが浮動小数点結果の小さな違いを許容できるようにするには、次のように-fp-relaxed オプションを aoc コマンドに含めます。

aoc -fp-relaxed <your_kernel_filename>.cl

丸め動作

浮動小数点演算の平衡化ツリーの実装には、複数回の丸め演算が含まれます。これらの丸め処理では、一部のアプリケーションでは相当量のハードウェア・リソースが必要になる場合があります。オフライン・コンパイラーは、IEEE Standard 754-2008 で要求される結果に違反するため、丸め処理の回数を自動的に減らすことはありません。

aoc コマンドの-fpc オプションを使用して浮動小数点演算を実装するために必要なハードウェアの量を減らすことができます。プログラムで浮動小数点結果の小さな違いを許容できる場合、次のコマンドを呼び出します。

aoc -fpc <your_kernel_filename>.cl

-fpc オプションを指定すると、オフライン・コンパイラーは次のタスクを実行します。

• 可能であれば、浮動小数点丸め演算と変換を削除してください。

可能であれば、 -fpc 引数は、浮動小数点演算のツリーの 後で、浮動小数点演算を 1 回だけ丸めるようにオフライン・コンパイラーに指示します。

• 精度を維持するために追加の仮数ビットを持ちます。

オフライン・コンパイラーは、浮動小数点演算を介して追加の精度ビットを持ち、浮動小数点演算のツリーの 後でこれらの精度ビットを削除します。

3. OpenCL カーネルデザインのベスト・プラクティスUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

79

Page 80: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

このタイプの 適化は、融合された浮動小数点演算を実行するハードウェアをもたらし、多くの新しいハードウェア処理システムの機能です。複数の浮動小数点演算を融合すると、丸めステップの数が 小限に抑えられ、より正確な結果が得られます。この 適化の一例は、新しいプロセッサーアーキテクチャで使用可能な FMAC(fused multiply-accumulate)命令です。オフライン・コンパイラーは、カーネル内の浮動小数点演算子の多くの組み合わせに対して、融合した浮動小数点数学機能を提供できます。

3.3.1. 浮動小数点表現と固定小数点表現

FPGA には、浮動小数点演算を実装するための相当量のロジックが含まれています。ただし、可能であれば、データの固定小数点表現を使用して、使用可能なハードウェア・リソースの量を増やすことができます。固定小数点演算を実装するために必要なハードウェアは、通常、同等の浮動小数点演算よりも小さくなります。その結果、固定小数点演算を浮動小数点演算よりも FPGA に適合させることができます。

OpenCL 標準は固定小数点表現をサポートしていません。整数データ型を使用して固定小数点表現を実装する必要があります。ハードウェア開発者は、通常、固定小数点データ表現を使用してハードウェアを節約し、計算を実行するために必要なデータ解決のみを保持します。OpenCL 標準ではこれらのデータ解像度のみがサポートされているため、8,16,32、または 64 ビットのスカラデータ型を使用する必要があります。ただし、ハードウェアのコンパイルツールでハードウェア・リソースを節約するための 適化を実行できるように、ソースコードに適切なマスキング動作を組み込むことができます。

たとえば、アルゴリズムで 17 ビットのデータの固定小数点表現を使用する場合、値を格納するために32 ビットのデータ型を使用する必要があります。その後、 Intel FPGA SDK for OpenCL オフライン・コンパイラー 2 つの 17 ビット固定小数点値を一緒に追加するには、オフライン・コンパイラーが余分な上位 15 ビットの加算を処理するために余分なハードウェアを作成する必要があります。この追加のハードウェアが存在しないようにするには、スタティックビットマスクを使用して、ハードウェアのコンパイル中に不要なビットを無視するようにハードウェアのコンパイルツールに指示します。以下のコードはこのマスキング動作を実装しています。

__kernel fixed_point_add (__global const unsigned int * restrict a, __global const unsigned int * restrict b, __global unsigned int * restrict result){ size_t gid = get_global_id(0);

unsigned int temp; temp = 0x3_FFFF & ((0x1_FFFF & a[gid]) + ((0x1_FFFF & b[gid]));

result[gid] = temp & 0x3_FFFF;}

このコード例では、入力 a と b の上位 15 ビットがマスクされて一緒に加算されます。 2 つの 17 ビット値を加算した結果は 18 ビットの分解能を超えることができないため、オフライン・コンパイラーは追加のマスクを適用して結果の上位 14 ビットをマスクします。 終的なハードウェアの実装は、完全な32 ビットの追加ではなく、17 ビットの追加です。この例のロジックの節約は、FPGA で使用可能なハードウェア・リソースの数に比べて比較的少ないです。しかし、これらの小さな節約は、頻繁に適用されると、FPGA 全体でより大きなハードウェア節約に蓄積されます。

3.4. アラインメントされたメモリーの割り当て

FPGA との間でデータを転送するために使用されるホスト側のメモリーを割り当てる場合、メモリーは少なくとも 64 バイトに揃えられている必要があります。

ホスト側のメモリーを整列させることで、FPGA とのダイレクトメモリーアクセス(DMA)転送が可能になり、バッファー転送効率が向上します。

3. OpenCL カーネルデザインのベスト・プラクティスUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

80

Page 81: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

注意: ホスト側メモリーの使用方法によっては、 インテル はより厳密なアラインメントを割り当てることを推奨します。たとえば、割り当てられたメモリーを使用して CL_MEM_USE_HOST_PTR フラグを使用してバッファーを作成する場合、カーネル内のバッファーにアクセスするために使用されるデータ型に合わせてメモリーを適切に配置する必要があります。ホスト側メモリーの位置合わせ要件の詳細については、OpenCL 仕様バージョン 1.2 のセクション C.3 を参照してください。

アラインメントされたメモリー割り当てを設定するには、ホストプログラムに次のソースコードを追加します。

• Windows の場合

#define AOCL_ALIGNMENT 64#include <malloc.h>void *ptr = _aligned_malloc (size, AOCL_ALIGNMENT);

整列メモリーブロックを解放するには、関数呼び出し_aligned_free(ptr);を含めます。

• Linux の場合

#define AOCL_ALIGNMENT 64#include <stdlib.h>void *ptr = NULL;posix_memalign (&ptr, AOCL_ALIGNMENT, size);

整列メモリーブロックを解放するには、関数呼び出し free(ptr);を含めます。

関連情報OpenCL の仕様バージョン 1.2

3.5. 構造体をパディング付きまたはパディングなしで整列する

適切に整列された構造体は、 Intel FPGA SDK for OpenCL オフライン・コンパイラーが も効率的なハードウェアを生成します。適切な struct の整列とは、整列を struct のサイズで均等に分割することを意味します。

重要: データ構造の 4 バイト整列を確認してください。 struct の整列が 4 バイトより小さいと、ハードウェアが大きくなり、遅くなります。整列の増加に伴い、ハードウェア効率が向上します。次の例では、Pixel_s 構造体は 1 バイトに整列していますが、 Pixel 構造体は 4 バイトの not_used 整数が存在するために 4 バイト整列されています。

重要:

typedef struct { char r,g,b,alpha;} Pixel_s;

typedef union { Pixel_s p; int not_used;} Pixel;

また、次のコード例に示すように、 aligned 属性を使用して 4 バイトのアラインメントを強制することもできます。

typedef struct {char r、g、b、alpha; } __attribute __((aligned(4)))ピクセル;

3. OpenCL カーネルデザインのベスト・プラクティスUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

81

Page 82: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

オフライン・コンパイラーは、次のすべての基準を満たすために構造体のアラインメントを必要とするISO C 標準に準拠しています。

• アラインメントは、すべての構造体メンバーのアラインメント間の 小公倍数の整数倍でなければなりません。

• このマクロの値は、2 の累乗である必要があります。

カーネルコードに aligned( N )属性を含めることで、 struct の整列を設定することができます。整列属性なしで、オフライン・コンパイラーは、 struct のサイズに基づいて、 struct のアレイ内の各 struct のアラインメントを決定します。次の例を検討してください。

__kernel void test (struct mystruct* A, struct mystruct* B){ A[get_global_id(0)] = B[get_global_id(0)];}

mystruct のサイズが 101 バイトの場合、各ロードまたはストアのアクセスは 1 バイトで整列されます。 mystruct のサイズが 128 バイトの場合、各ロードまたはストアのアクセスは 128 バイトに整列され、 も効率的なハードウェアが生成されます。

構造体のフィールドは、struct の中に整列されていない場合、オフラインのコンパイラーはそれらを整列するためにパディングを挿入します。 struct フィールド間にパディングを挿入すると、次のようにハードウェアの効率に影響します。

• 構造体のサイズを増やす

• アラインメントに影響する可能性がある

オフライン・コンパイラーがパディングを挿入しないようにするには、カーネルコードに packed 属性を含めます。前述の ISO C 標準は、パックされた struct またはアンパックされた struct のアラインメントを決定するときに適用されます。次の例を検討してください。

struct mystruct1{ char a; int b;};

mystruct1 のサイズは 8 バイトです。したがって、 struct は 8 バイトに整列され、カーネル内で効率的にアクセスされます。ここで別の例を検討してください。

struct mystruct2{ char a; int b; int c;};

mystruct2 のサイズは 12 バイトで、 struct は 4 バイトに整列しています。struct フィールドはパディングされており、struct はアラインメントされていないため、カーネル内のアクセスは非効率的です。

以下に packed 属性を含む struct の例を示します。

struct __attribute__((packed)) mystruct3{ char a;

3. OpenCL カーネルデザインのベスト・プラクティスUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

82

Page 83: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

int b; int c;};

mystruct4 のサイズは 16 バイトです。 mystruct4 が整列され、 struct フィールドの間にパディングがないため、このカーネルのアクセスは mystruct3 のアクセスよりも効率的です 。

構造体に aligned( N )属性と packed 属性の両方を含めるには、次の例を考えてください。

struct __attribute__((packed)) __attribute__((aligned(16))) mystruct5{ char a; int b; int c;};

mystruct5 のサイズは 9 バイトです。 aligned(16)属性のため、 struct は配列内の 16 バイト整列アドレスに格納されます。 mystruct5 は 16 バイトで整列されており、パディングもないため、このカーネルでのアクセスは効率的です。

struct の整列と aligned( N )および packed 属性の詳細については、以下の文書を参照してください。

• OpenCL 仕様バージョン 1.2.1 のセクション 6.11.1

• インテル FPGA SDK for OpenCL プログラミング・ガイドのデータ構造の挿入のディセーブル

• Struct アラインメントの指定のセクションの インテル FPGA SDK for OpenCL プログラミング・ガイド

関連情報• OpenCL の仕様バージョン 1.2

• Disabling Insertion of Data Structure Padding

• Specifying the Alignment of a Struct

3.6. ベクトル型要素の類似構造の維持

ベクトル型の 1 つの要素を更新する場合、ベクトルのすべての要素を更新します。

次のコード例は、ベクトル要素を更新するシナリオを示しています。

__kernel void update (__global const float4 * restrict in, __global const float4 * restrict out){ size_t gid = get_global_id(0);

out[gid].x = process(in[gid].x); out[gid].y = process(in[gid].y); out[gid].z = process(in[gid].z); out[gid].w = 0; //Update w even if that variable is not required.}

3.7. ポインター・エイリアシングの回避

可能であれば、ポインター引数に restrict キーワードを挿入します。ポインター引数に restrictキーワードを含めると、 Intel FPGA SDK for OpenCL オフライン・コンパイラー競合しないロード動作とストア動作との間の不要なメモリー依存関係を作成することがなくなります。

3. OpenCL カーネルデザインのベスト・プラクティスUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

83

Page 84: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

restrict キーワードは、オフライン・コンパイラーに、ポインターが別のポインターのエイリアスではないことを通知します。たとえば、カーネルに大域メモリー A と B が重複しない 2 つのポインターがある場合、カーネルを次のように宣言します。

__kernel void myKernel (__global int * restrict A, __global int * restrict B)

警告: 他のポインターの別名を指すポインターに restrict キーワードを挿入すると、結果が正しくない可能性があります。

3.8. 高価な機能の回避

一部の機能は FPGA で実装するのに費用がかかります。高価な機能は、カーネルのパフォーマンスを低下させるか、実装するために大量のハードウェアを必要とする可能性があります。

以下の機能は高価です。

• 整数除算とモジュロ(剰余)演算子

• 加算、乗算、絶対値、および比較を除くほとんどの浮動小数点演算子 

注意: 浮動小数点演算の 適化の詳細については、「浮動小数点演算の 適化のセクションを参照してください。

• アトミック関数

対照的に、安価な機能はカーネルの性能にはほとんど影響を与えず、その実装は 小のハードウェアしか消費しません。

以下の機能は安価です。

• AND、NAND、OR、NOR、XOR、および XNOR などの 2 進論理演算

• 1 つの定数引数による論理演算

• 定数でシフト

• 整数の乗算と 2 の累乗である定数による除算

高価な関数がワークグループ内のすべての Work-Item に対して新しいデータを生成する場合、それをカーネルでコード化することは有益です。これに対して、以下のコード例は、NDRange の各 Work-Item で実行される高価な浮動小数点演算(除算)のケースを示しています。

__kernel void myKernel (__global const float * restrict a, __global float * restrict b, const float c, const float d){ size_t gid = get_global_id(0); //inefficient since each work-item must calculate c divided by d b[gid] = a[gid] * (c / d); }

この計算の結果は常に同じです。このような冗長かつハードウェアのリソース集約的な動作を回避するには、ホスト・アプリケーションで計算を実行し、使用する NDRange 内のすべての Work-Item の引数として結果をカーネルに渡します。変更されたコードを以下に示します。

__kernel void myKernel (__global const float * restrict a, __global float * restrict b, const float c_divided_by_d){ size_t gid = get_global_id(0);

3. OpenCL カーネルデザインのベスト・プラクティスUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

84

Page 85: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

/*host calculates c divided by d once and passes it into kernel to avoid redundant expensive calculations*/ b[gid] = a[gid] * c_divided_by_d; }

Intel FPGA SDK for OpenCL オフライン・コンパイラーは、NDRange 全体で Work-Item に依存しない動作を 1 つの動作に統合します。次に、すべての Work-Item にわたって結果を共有します。 初のコード例では、オフライン・コンパイラーは、 c による d の除算がすべての Work-Item にわたって一定であるため、すべての Work-Item で共有される 1 つの除算ブロックを作成します。この 適化は冗長ハードウェアの量を 小限に抑えるのに役立ちますしかし、整数除算の実装には、相当量のハードウェア・リソースが必要です。したがって、除算演算をホスト・プロセッサーにオフロードし、結果を引数としてカーネルに渡してハードウェア・リソースを節約することが有益です。

関連情報浮動小数点演算の 適化 (78 ページ)

3.9. Work-ItemID 依存の後方分岐の回避

Intel FPGA SDK for OpenCL オフライン・コンパイラーは、特定の機能ユニットがいつアクティブになるかを示す単一のビットに条件文を畳ませます。オフライン・コンパイラーは、ループ構造に関係しない単純な制御フローを完全に排除し、フラットな制御構造とより効率的なハードウェアの使用をもたらします。オフライン・コンパイラーは、条件文などの前方分岐を効率的に含むカーネルを効率的にコンパイルします。パフォーマンスを低下させるため、Work-ItemID に依存する後方分岐(ループ内で発生する分岐)をカーネルに含めないでください。

例えば、次のコードは、そのような get_global_id 又は get_local_id などの Work-ItemIDを含む分岐示します。

for (size_t i = 0; i < get_global_id(0); i++){ // statements}

3. OpenCL カーネルデザインのベスト・プラクティスUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

85

Page 86: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

4. パフォーマンスのボトルネックを特定するためのカーネルのプロファイリング

Intel FPGA Dynamic Profiler for OpenCL は、OpenCL カーネルのパフォーマンスを評価するのに役立つデータを生成します。 Intel FPGA Dynamic Profiler for OpenCL はパフォーマンス・カウンターを備えたカーネル・パイプラインを計測します。これらのカウンターは、カーネルのパフォーマンスデータを収集します。このデータは、プロファイラ GUI で確認できます。

次の OpenCL カーネルプログラムを検討してください。

__kernel void add (__global int * a, __global int * b, __global int * c){ int gid = get_global_id(0); c[gid] = a[gid]+b[gid];}

下の図に示すように、Profiler 計測器は、カーネルプログラム用に生成されたパイプライン全体で、デイジーチェインでパフォーマンス・カウンターを接続します。ホストは、これらのカウンターによって収集されたデータを読み出します。たとえば、 PCI Express® ( PCIe )ベースのシステムでは、ホストは PCIe制御レジスターアクセス(CRA)または制御およびステータスレジスター(CSR)ポートを介してデータを読み出します。

図 -62: Intel FPGA Dynamic Profiler for OpenCL: パフォーマンス・カウンターの定数

+

Load Load

Store

+

Load Load

Store

CRATo Host CRA

To Host

Work-Item の実行停止は、 インテル FPGA SDK for OpenCL パイプラインのさまざまな段階で発生する可能性があります。大量のメモリーアクセスまたはロードおよびストア動作を伴うアプリケーションは、メモリー転送の完了を可能にするために頻繁に停止することがあります。Profiler は、カーネル・パイプライン内の大部分の停止を引き起こすロードおよびストア動作またはチャネルアクセスを識別するのに役立ちます。

UG-OCL003 | 2017.12.08

フィードバック

Intel Corporation.無断での引用、転載を禁じます。Intel、インテル、Intel ロゴ、Altera、ARRIA、CYCLONE、ENPIRION、MAX、NIOS、QUARTUS および STRATIX の名称およびロゴは、アメリカ合衆国および/ またはその他の国における Intel Corporationの商標です。インテルは FPGA 製品および半導体製品の性能がインテルの標準保証に準拠することを保証しますが、インテル製品およびサービスは、予告なく変更される場合があります。インテルが書面にて明示的に同意する場合を除き、インテルはここに記載されたアプリケーション、または、いかなる情報、製品、またはサービスの使用によって生じるいっさいの責任を負いません。インテル製品の顧客は、製品またはサービスを購入する前、および、公開済みの情報を信頼する前には、デバイスの仕様を 新のバージョンにしておくことをお勧めします。*その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

ISO9001:2015登録済

Page 87: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

Intel FPGA Dynamic Profiler for OpenCL の使用方法については、 インテル FPGA SDK forOpenCL プログラミング・ガイドの「OpenCL カーネルのプロファイリングのセクションを参照してください。

関連情報OpenCL カーネルのエミュレーション

4.1. Intel FPGA Dynamic Profiler for OpenCL のベスト・プラクティス

インテル は、OpenCL カーネルをプロファイリングするときの Intel FPGA Dynamic Profiler forOpenCL のベスト・プラクティスに従うことを推奨します。

• パフォーマンス・カウンターをカーネルに挿入するには、開発中に aoc コマンドに-profileIntel FPGA SDK for OpenCL オフライン・コンパイラーコマンドオプションを含めます。

• Profiler を使用せずにカーネルの fmax とパフォーマンスを定期的にチェックしてください。

• プロファイラーのオーバーヘッドを減らすには、ローカルフォルダーからホスト・アプリケーションを実行します。リモートまたは NAS フォルダからホストを実行しないでください。

• カーネルの実行時間が 20 ms より長いことを確認してください。そうしないと、Profiler のオーバーヘッドが引き継がれます。

• すべてのロードおよびストア動作とチャネルがデータフローでどのように接続されているかを理解します。

4.2. Intel FPGA Dynamic Profiler for OpenCL GUI

Intel FPGA Dynamic Profiler for OpenCL GUI は、メモリーおよびチャネルまたはパイプアクセスから収集された統計情報を表示します。

表 8. Intel FPGA Dynamic Profiler for OpenCL GUI の要約見出し

見出し 変更内容

ボード カーネルのエミュレーションと実行中に Intel FPGA SDK forOpenCL オフライン・コンパイラーが使用するアクセラレータボードの名前。

Global Memory BW (DDR) 各メモリータイプ(DDR など)で使用可能な理論上のグローバルメモリー帯域幅の 大値。

要約見出ししのすぐ下に、使用可能なタブをクリックすると詳しいプロファイル情報を表示できます。

重要: 以下のセクションでは、 SDK のチャンネル拡張に関する情報は、OpenCL パイプにも適用されます。

ソース・コード・タブ (87 ページ)

カーネル実行タブ (89 ページ)

Autorun Captures タブ (90 ページ)

4.2.1. ソース・コード・タブ

Intel FPGA Dynamic Profiler for OpenCL GUI での Source Code ドタブには、ソースコード情報とメモリーおよびチャネルアクセスに関する詳細な統計情報が含まれています。

4. パフォーマンスのボトルネックを特定するためのカーネルのプロファイリングUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

87

Page 88: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -63: Intel FPGA Dynamic Profiler for OpenCL GUI での Source Code タブ

ソ Source Code タブには、カーネルコードの特定の行に関する詳細情報が表示されます。

表 9. Source Code タブで使用できる情報の種類

カラム 変更内容 アクセスタイプ

属性 メモリータイプ(ローカルまたはグローバル)、対応するメモリーシステム(DDR またはクワッドデータレート(QDR))、読み出しまたは書き込みアクセスなどのメモリーまたはチャネル属性情報。

すべてのメモリーアクセスとチャネルアクセス

ストールの割合 メモリーまたはチャネル・アクセスがパイプライン・ストールの原因となっている時間の割合です。これは、メモリーまたはチャネルアクセスがアクセス要求を満たす能力の尺度です。

すべてのメモリーアクセスとチャネルアクセス

占有の割合 有効な Work-Item がメモリーまたはチャネル命令を実行するときのプロファイリングされた時間フレーム全体の割合。

すべてのメモリーアクセスとチャネルアクセス

帯域幅 メモリーアクセスが使用する平均メモリー帯域幅とその全体的な効率。グローバル・メモリー・アクセスごとに、グローバル・メモリー・システムからデータを取得するために FPGA リソースが割り当てられます。しかし、カーネルプログラムが使用するデータ量は、取得したデータ量より少なくなる可能性があります。全体的な効率は、カーネルプログラムが使用する、グローバル・メモリー・システムから取得した総バイト数の割合です。

グローバル・メモリー・アクセス

1 行のソースコードが複数のメモリー動作またはチャネル動作を指示する場合、プロファイル統計情報はドロップダウンリストボックスに表示され、関連情報を表示するように選択できます。

図 -64: [ソースコード]タブ:複数のメモリーまたはチャネル動作のドロップダウンリスト

4.2.1.1. ツール・オプション

カーネルソースコードに関する追加情報を入手するには、コード内のチャネルアクセス上にマウスを置いてツールチップをアクティブにします。

4. パフォーマンスのボトルネックを特定するためのカーネルのプロファイリングUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

88

Page 89: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -65: Intel FPGA Dynamic Profiler for OpenCL GUI:ソースコードタブツールヒント

注意: カーネルが複数のメモリー動作を実装するハードウェア・リソースを統合するメモリー 適化を実行する場合、メモリー動作ごとに統計データを使用できないことがあります。統計データの 1 つのセットは、ハードウェアの統合ポイントにマップされます。

表 10. Source Code タブのツールヒントが提供する情報の種類

カラム ツールヒント 変更内容 メッセージの例 アクセスタイプ

属性 キャッシュヒット

キャッシュを使用するメモリーアクセスの数。キャッシュヒット率が高いと、メモリー帯域幅の使用率が低下します。

キャッシュヒット=30%

グローバルメモリー

アラインメントされていないアクセス

アラインメントされていないメモリーアクセスの割合。アラインされていないアクセス率が高いということは、非効率的なメモリーアクセスを意味します。効率を向上させるために、カーネルコードのアクセスパターンを変更することを検討してください。

アラインメントされていないアクセス=20%

グローバルメモリー

静的に融合 ロードまたはストア・メモリー動作が静的に結合されているかどうかを示す。一般に、スタティック・メモリー統合は、連続するメモリーアドレスにアクセスする複数のメモリーアクセスを単一のワイドアクセスにマージします。

融合 グローバルまたはローカルメモリー

占有の割合

アクティビティー

述語チャネルまたはメモリー命令が有効になっている時間の割合(条件付き実行が true の場合)。

注意: アクティビティーの割合は、命令の占有率よりも小さい可能性があります。

アクティビティー=20%

グローバルまたはローカルメモリー、およびチャネル

帯域幅

バースト・サイズ

メモリー動作の平均バーストサイズ。メモリーシステムがバーストモード(例えば内蔵 RAM)をサポートしていない場合、バースト情報は使用できません。

平均バーストサイズ= 7.6( 大バースト=16)

グローバルメモリー

4.2.2. カーネル実行タブ

Kernel Execution タブ Intel FPGA Dynamic Profiler for OpenCL GUI は、カーネルプログラム全体の実行プロセスをグラフィカルに表示します。これは、各カーネルの実行時間を示し、異なるカーネル実行間の相互作用についての洞察を提供します。

たとえば、低速のネットワーク・ディスク・アクセスでネットワーク・ディレクトリーからホスト・アプリケーションを実行すると、ランタイムがプロファイル出力データをディスクに格納している間に、GUI はカーネル起動間の遅延を表示できます。

注意: カーネルの実行とホスト・アプリケーション全体の実行時間の増加を防ぐため、ローカルディスクからホスト・アプリケーションを実行してください。

4. パフォーマンスのボトルネックを特定するためのカーネルのプロファイリングUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

89

Page 90: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -66: Intel FPGA Dynamic Profiler for OpenCL GUI での Kernel Execution タブ

水平の棒グラフは、カーネルの実行時間を表します。 初のエントリー(fft1d)に示されている 2 つのバーの組み合わせは、合計時間を表します。 2 番目と 後のエントリーは、時間間隔を占めるカーネルの実行を示します。これらのバーは、 output_kernel と input_kernel の同時実行を表し、カーネルがメモリー帯域幅などの共通リソースを共有していることを示します。

ヒント: 特定の実行時間のプロファイル・データを調べることができます。上の例では、fft1d の左側のバーをダブルクリックすると、その特定のカーネル実行イベントのプロファイル・データを表示する別のウィンドウが開きます。

Kernel Execution タブには、ホストとデバイス間のメモリー転送に関する情報も表示されます。

図 -67: カーネル実行タブ:ホストデバイスのメモリー転送情報

注意: 拡大または縮小して拡大率を調整すると、時間スケールの粒度が微妙に変化することがあります。

メモリー転送情報の表示をイネーブルするには、環境変数 ACL_PROFILE_TIMER を値 1 に設定し、ホスト・アプリケーションを実行します。 ACL_PROFILE_TIMER 環境変数を設定すると、メモリー転送の記録が可能になります。この情報は profile.mon ファイルに格納され、Intel FPGA DynamicProfiler for OpenCL GUI によって解析されます。

4.2.3. Autorun Captures タブ

自動実行の統計データを表示するには、 Intel FPGA Dynamic Profiler for OpenCL は、エンキューされたカーネルのデータを表示する方法と同様です。自動実行およびエンキューされたカーネルの統計データは、いずれも、単一の profile.mon ファイルに格納されます。

自動実行プロファイル・データは、エンキューされたプロファイル・データと同様に表示されます。ただし、自動実行カーネルは実行時タブが実行時表示になっていないため、自動実行カーネルは継続的に実行されます。

注意: 自動実行カーネルを複数回プロファイルすると、 Intel FPGA Dynamic Profiler for OpenCL はすべてのプロファイル・インスタンスの平均です。

4. パフォーマンスのボトルネックを特定するためのカーネルのプロファイリングUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

90

Page 91: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

autorun カーネルを少なくとも 1 回プロファイルすると、Autorun Captures タブが Intel FPGADynamic Profiler for OpenCL GUI に表示されます。このタブには、デバイスとカーネルによって構成されたすべての自動実行プロファイルキャプチャのテーブルが表示されます。特定のキャプチャの自動実行カーネルのプロファイル・データを表示するには、関連するボタンを選択すると、新しいプロファイラ・ウィンドウが開き、自動平均キャプチャのデータのみが表示されます(全体の平均ではなく)。

次の図には、4 つの自動実行キャプチャインスタンスがあります。デバイス 0 の streamer 自動実行カーネルで 0.03ms で行われたキャプチャから自動プロファイル・データを表示するには、Device 0 のストリーマー・ロウの 0.03ms ボタンを選択します。

図 -68: Autorun Captures タブ

Profiler Captures ボタンには、キャプチャが開始された時間が表示されます。この時間は、ホストプログラムの開始に関連します。

注意: キャプチャ時間は Kernel Execution タブのタイムラインとは相関しません。このタイムラインは、ホストプログラムではなく、 初にエンキューされたカーネルの開始時間を基準にしています。

4.3. プロファイリング情報の解釈

プロファイリング情報は、不十分なカーネル・パフォーマンスにつながる貧弱なメモリーまたはチャネルの動作を識別するのに役立ちます。

次に、Profiler レポートに記録される Intel FPGA Dynamic Profiler for OpenCL メトリックについて説明します。

重要: インテル FPGA SDK for OpenCL のチャンネル拡張に関する情報は、OpenCL パイプにも適用されます。

ストール、占有、帯域幅 (91 ページ)

アクティビティー (93 ページ)

キャッシュヒット (94 ページ)

OpenCL のデザインシナリオ例のプロファイラ解析 (94 ページ)

自動プロファイラーデータ (98 ページ)

4.3.1. ストール、占有、帯域幅

カーネルコードの特定の行については、Intel FPGA Dynamic Profiler for OpenCL GUI でのSource Code でタブは、ストール率、占有率、平均メモリー帯域幅が表示されます。

失速、占有、帯域幅の定義については、 表 9 (88 ページ) を参照してください。

4. パフォーマンスのボトルネックを特定するためのカーネルのプロファイリングUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

91

Page 92: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

インテル FPGA SDK for OpenCL は、Work-Item がパイプライン・ステージを順に(パイプライン -パラレルに)横断するパイプライン・アーキテクチャを生成します。パイプライン・ステージが空になるとすぐに、Work-Item がステージに入り、ステージを占有します。パイプラインの並列性は、パイプライン化されたループの反復にも適用されます。

図 -69: パフォーマンス・カウンターで計測されたカーネル・パイプラインの簡略化された表現

Load-Store Unit

Upstreamkernel pipeline

Downstreamkernel pipeline

ctr ctr

ctrtotal_count

ivalid_count

ostall_count

1

ivalid ostall

ovalid istall data

Upstream kernel pipelinewill set ivalid=0 if ostall=1

Global memoryinterconnect

32

data512

req

waitreq

以下は、Profiler がストール、占有、および帯域幅を計算することを説明する簡略化された式です。

Stall =ostall_counttotal_count

x 100%

ivalid_counttotal_count x 100%Occupancy =

Bandwidth = data_width x ivalid_count

kernel_timex 100%

注意: 帯域幅式の ivalid_count には、ロードストアユニットへの predicate=true 入力も含まれます。

理想的なカーネル・パイプライン条件:

• 失速率は 0%に等しい

• 占有率は 100%

• 帯域幅はボードの帯域幅に等しい

4. パフォーマンスのボトルネックを特定するためのカーネルのプロファイリングUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

92

Page 93: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

カーネル・パイプラインの特定の場所では、ストール率と占有率の合計が 100%にほぼ等しい場合、プロファイラはその場所をストールソースとして識別します。ストール率が低い場合、プロファイラはその場所をストールの犠牲者として識別します。

Profiler は、オフライン・コンパイラーがカーネルから効率的なパイプラインを生成した場合(作業項目または反復がパイプライン・ステージを通過して停止することなく)、高い占有率を報告します。

すべての LSU が同じ回数アクセスされた場合、同じ占有値を持ちます。

• Work-Item が連続してパイプラインに入ることができない場合、パイプラインにバブルを挿入します。

• ループパイプライニングでは、反復間に存在する泡のために、ループに依存する依存関係もパイプラインに泡を形成します。

• LSU が他の LSU よりも頻繁にアクセスされない場合(LSU が他の LSU を含むループの外にある場合など)、この LSU の占有値は他の LSU よりも低くなります。

占有率に関する同じルールがチャネルに適用されます。

関連情報ソース・コード・タブ (87 ページ)

4.3.1.1. チャンネルの停止

チャネルは、2 つのカーネル間、またはカーネルと I/O チャネル間のポイントツーポイント通信リンクを提供します。 I/O チャネルが停止すると、I/O チャネルがカーネルに追いついていないことを意味します。

たとえば、カーネルにイーサネット I/O に対するチャネル読み出し呼び出しがあり、Profiler がストールを識別した場合、書込みチャネルは、イーサネット I/O へのデータ書込みがカーネルの読み出し速度と同じ速度で行われていないことを意味します。

カーネル間チャネルの場合、チャネルの読み出し側と書き込み側の間に不均衡がある場合、または読み出しと書き込みのカーネルが同時に実行されていない場合にストールが発生します。

たとえば、読み出しが書き込みを実行するカーネルと同時に起動されないか、または読み出し操作が書き込み操作よりもはるかに遅い場合、Profiler は書き込みカーネル内の write_channel_intel呼び出しの停止を識別します。

関連情報データを経由して転送する インテル FPGA SDK for OpenCL チャネルまたは OpenCL パイプ (71ページ)

4.3.2. アクティビティー

Activity は、述語命令が有効になっている時間の割合、つまり LSU がそのデータを受け取る時間の割合を測定します。

Intel FPGA Dynamic Profiler for OpenCL GUI での Source Cod タブは、占有率(Occupancy%)カラムのツールチップが Activity の割合を指定する場合があります。Activity は、以下に説明するように、アクティビティーが述語に関連する点で占有とは異なります。

各 LSU には、ivalid 信号の他に述語信号があります。 ivalid シグナルは、上流のロジックが有効なデータを LSU に提供していることを示します。述語信号は、LSU が受信するデータに作用するべきであることを示します。Work-Item またはループ反復は、述語であってもメモリー命令を占有することができま

4. パフォーマンスのボトルネックを特定するためのカーネルのプロファイリングUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

93

Page 94: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

す。分岐ステートメントにループが含まれていない場合、オフライン・コンパイラーは分岐を変換して制御フローを 小限に抑え、より効率的なハードウェアを実現します。変換の一部として、メモリーおよびチャネル命令を述語化し、出力結果をマルチプレクサ論理によって選択する必要があります。

次の式を検討してみましょう。

int addr = compute_address();int x = 0;if (some_rare_condition) x = src[addr];

オフライン・コンパイラーは、コードを次のように変更します。

int addr = compute_address();int x = 0;x = src[addr] if some_rare_condition;

この場合、 src []はクロックサイクルごとに有効なアドレスを受け取ります。パイプラインに SRC[]自体は生成されないストールを想定すると、[] SRC 用 ivalid 信号は、ほとんどの時間を高くなります。実際には、 src []は述語信号 some_rare_condition が真の場合にのみロードを実行します。したがって、この負荷動作では、占有率は高くなりますが、活動は低くなります。

ツールヒントで使用可能なアクティビティーの割合は、述語アクセスを考慮しないため、低いアクティビティーの割合に基づいて述語命令を識別できます。活動率が低いにもかかわらず、これらの指示には高い占有率があるかもしれません。

関連情報ツール・オプション (88 ページ)

4.3.3. キャッシュヒット

キャッシュヒット率は、プライベート・キャッシュの有効性を測定します。

Intel FPGA Dynamic Profiler for OpenCL GUI での Source Code タブは、 Attributes カラムのツールヒントがキャッシュヒット率を指定することがあります。一部のグローバル負荷ユニットでは、 Intel FPGA SDK for OpenCL オフライン・コンパイラーはプライベート・キャッシュをインスタンス化することがあります。この場合、オフライン・コンパイラーはこのキャッシュの有効性を測定するために追加のハードウェアカウンターを作成します。このプライベート・キャッシュの詳細は、HTML エリアレポートで確認できます。

4.3.4. OpenCL のデザインシナリオ例のプロファイラ解析

OpenCL のデザインシナリオの例と問題点を理解することで、デザインの Profiler メトリクスを活用してパフォーマンスを 適化することができます。

4.3.4.1. ハイストール率

高いストール率は、メモリー帯域幅またはチャネルバッファー空間の競合のために、メモリーまたはチャネル命令がアクセス要求を満たすことができないことを意味します。

帯域幅の使用が非効率的である場合、また、アプリケーションの実行中に大量のデータ転送が必要な場合、メモリー命令が頻繁に停止します。非効率的なメモリーアクセスは、帯域幅の 適使用に至りません。そのような場合、カーネルのメモリーアクセスを分析して、改善が可能かどうかを確認してください。

4. パフォーマンスのボトルネックを特定するためのカーネルのプロファイリングUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

94

Page 95: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

チャネルへの読み出しアクセスと書き込みアクセスとの間に強い不均衡が存在する場合、チャネル命令はストールします。不均衡は、チャネル読み出しまたは異なる速度で動作する書き込みによって引き起こされる可能性があります。

たとえば、書き込みチャネル呼び出しのストール率が高いと判明した場合、読み出しチャネル呼び出しの占有率および活動度が低いかどうかを確認します。そうである場合、読み出しチャネル呼び出しを制御するカーネルの実行速度は、書き込みチャネル呼び出しを制御するカーネルにとって遅すぎるため、パフォーマンスのボトルネックにつながります。

メモリーまたはチャネルアクセスがパーセンテージの高いパイプラインストールを引き起こしている場合、メモリーまたはチャネルを指示するソースコードのラインは赤で強調表示されます。ストール率が20%以上になると、ストールの識別が高くなります。ストール率が高いほど、赤いハイライトが暗くなります。高失速率の値を簡単にトラバースするには、[ソースコード]タブの右下隅に右矢印と左矢印があります。

図 -70: 高い失速率の識別

関連情報• データを経由して転送する インテル FPGA SDK for OpenCL チャネルまたは OpenCL パイプ

(71 ページ)

• ソース・コード・タブ (87 ページ)

4. パフォーマンスのボトルネックを特定するためのカーネルのプロファイリングUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

95

Page 96: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

4.3.4.2. 低い占有率

占有率が低いということは、Work-Item がロードおよびストア動作またはチャネルをまれにアクセスしていることを意味します。この動作は、ロードおよびストア動作、またはクリティカルでないループにあるチャネルで発生します。しかし、メモリーまたはチャネル命令がカーネルコードの重要な部分にあり、占有率または活動率が低い場合、ハードウェアで Work-Item またはループ反復が発行されていないため、パフォーマンスのボトルネックが存在することを意味します。

次の式を検討してみましょう。

__kernel void proc (__global int * a, ...) { for (int i = 0; i < N; i++) { for (int j = 0; j < 1000; j++) { write_channel_intel (c0, data0); } for (int k = 0; k < 3; k++) { write_channel_intel (c1, data1); } }}

すべてのループがパイプライン化されていると仮定すると、トリップカウントが 1000 の 初の内部ループがクリティカルループです。トリップカウントが 3 の 2 番目の内部ループは頻繁に実行されません。その結果、チャネル c0 の占有率およびアクティビティーパーセンテージが高く、チャネル c1 の占有率およびアクティビティーの割合が低いことが期待できます。

また、小さなワーク・グループ・サイズを定義すると、占有率が低くなる可能性があり、カーネルが十分なWork-Item を受け取らない可能性があります。これは問題があります。なぜなら、一般にカーネルの実行中にパイプラインが空であり、パフォーマンスが低下するからです。

4.3.4.3. 低帯域幅効率

有用なデータを得るために過剰な帯域幅が必要な場合、帯域幅の効率が悪くなります。通常、過剰な帯域幅使用は、メモリーアクセスが不十分な場合(例えば、ランダムアクセス)に発生し、合併の機会が不十分になります。

メモリーアクセスを確認して、メモリーサイトへのアクセスが連続するメモリーエリアをアドレス指定するように書き換えることができるかどうかを確認します。

関連情報• メモリーアクセス効率向上のための戦略 (128 ページ)

• ソース・コード・タブ (87 ページ)

4.3.4.4. 高い失業率と高い占有率

ロードおよびストア動作またはチャネルのストール率が高いチャネルは、カーネルのパイプラインストールの原因です。

注意: 理想的なカーネル・パイプライン条件は、ストールの割合が 0%で、占有率が 100%です。

通常、ストール率と占有率の合計はほぼ 100%になります。ロードおよびストア動作またはチャネルの失速率が高い場合、ロードおよびストア動作またはチャネルがすべてのサイクルを実行できるが、ストールが発生していることを意味します。

4. パフォーマンスのボトルネックを特定するためのカーネルのプロファイリングUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

96

Page 97: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

グローバルロードおよびストア動作をストールするためのソリューションは以下の通りです。

• ローカルメモリーを使用してデータをキャッシュします。

• データを読み出す回数を減らします。

• グローバル・メモリー・アクセスを改善します。

— より多くのグローバル・メモリー・フレンドリーなアドレッシング(例えば、ストライド・アクセスからシーケンシャル・アクセスへの変更)のアクセス・パターンを変更してください。

— カーネルを-no-interleaving=default Intel FPGA SDK for OpenCL オフライン・コンパイラーコマンドオプションでコンパイルし、読み出しバッファーと書き込みバッファーを別々の DDR バンクに分けます。

— より少ないが広いグローバル・メモリー・アクセスがあります。

• より多くの帯域幅を持つアクセラレーター・ボードを取得します(たとえば、2 つの DDR の代わりに3 つの DDR を持つボード)。

ローカルロードおよびストア動作をストールするためのソリューションは以下の通りです。

• HTML エリアレポートを確認してローカルメモリーの構成を確認し、構成を変更してストールフリーにします。

チャネルをストールするためのソリューションは以下の通りです。

• チャンネルの反対側のストールを修正します。たとえば、チャネルの読み出しが停止した場合、チャネルへのライターがチャネルにデータを書き込む速度が十分でなく、調整が必要であることを意味します。

• デザインにチャンネルループがある場合、チャンネルの深さを指定します。

4.3.4.5. ノーストール、低占有率、低帯域幅効率

ループに依存する依存関係は、LSU またはチャネルの占有率が低く、帯域幅が狭くなる原因となるボトルネックとなります。

注意: 理想的なカーネル・パイプライン条件は、ストール・パーセンテージが 0%、占有率が 100%、ボードの使用可能帯域幅に等しい帯域幅を持ちます。

図 -71: OpenCL カーネルとプロファイラ解析の例

この例では、dst[]は、 FACTOR2 ループの 20 回の反復と FACTOR1 ループの回 4 回の繰り返しが実行されます。したがって、FACTOR2 ループがボトルネックの原因となります。

ループボトルネックを解決するソリューションは以下の通りです。

• FACTOR1 をアンロールし、 FACTOR2 は均等にループします。 FACTOR1 ループをさらに展開するだけでは、ボトルネックは解消されません

• カーネルをベクトル化し、各ループ反復中に Multiple Work-Item を実行できるようにする

4. パフォーマンスのボトルネックを特定するためのカーネルのプロファイリングUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

97

Page 98: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

関連情報カーネルのベクトル化 (119 ページ)

4.3.4.6. ノー・ストール、高占有率、低帯域幅効率

カーネルデザインの構造によって、アクセラレーター・ボードが提供できるすべての使用可能な帯域幅を使用できなくなる可能性があります。

注意: 理想的なカーネル・パイプライン条件は、ストール・パーセンテージが 0%、占有率が 100%、ボードの使用可能帯域幅に等しい帯域幅を持ちます。

図 -72: OpenCL カーネルとプロファイラ解析の例

この例では、アクセラレーター・ボードは 25600 MB/s の帯域幅を提供できます。しかし、vector_add カーネルは、使用可能な帯域幅の 14%を要求しています(2 リード+ 1 ライト)。x 4 バイト x 294 MHz = 12 バイト/サイクル x 294 MHz = 3528 MB/s。帯域幅を増やすには、各クロックサイクルで実行されるタスクの数を増やします。

低帯域幅のソリューションは以下の通りです。

• カーネルを自動的または手動でベクトル化して wider 要求を作成する

• も内側のループをアンロールして、クロックサイクルごとにさらに多くの要求を実行する

• タスクの一部を別のカーネルに委譲する

4.3.4.7. 高失速率と低占有率

グローバルストア動作で高い失速率(たとえば 30%)と非常に低い占有率(たとえば 0.01%)が発生する場合があります。このようなストア動作が 10000 サイクルの計算ごとに 1 回行われる場合、このストアの効率は懸念の原因ではありません。

4.3.5. 自動プロファイラーデータ

エンキューされたカーネルと同様に、自動実行プロファイラの統計データを表示するには、 次の aoclコマンドを使用して Intel FPGA Dynamic Profiler for OpenCL GUI を実行します。

aocl report <filename>.aocx profile.mon <filename>.source

関連情報Autorun Captures タブ (90 ページ)

4.4. Intel FPGA Dynamic Profiler for OpenCL の制限

Intel FPGA Dynamic Profiler for OpenCL はいくつかの制限があります。

4. パフォーマンスのボトルネックを特定するためのカーネルのプロファイリングUG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

98

Page 99: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

• Profiler は、実行中のカーネルから 1 組のプロファイル・データのみを抽出することができます。

Profiler がカーネルの実行が完了した後でプロファイル・データを収集する場合、 profile.monファイルを複数回生成するようにホスト API を呼び出すことができます。

カーネルの実行時にプロファイル・データを収集する方法の詳細については、 インテル FPGASDK for OpenCL プログラミング・ガイドのカーネル実行部の間に収集プロファイル・データのセクションを参照してください。

• プロファイル・データは、OpenCL プログラムまたは複数のデバイスで永続的ではありません。

プロファイル・データは、単一の OpenCL プログラムと単一のデバイスのみで要求できます。ホストが新しいカーネルプログラムを FPGA の内部と外部に交換すると、Profiler はプロファイル・データを保存しません。

• パフォーマンス・カウンターを使用して Verilog コードをインスツルメント化すると、ハードウェアリソースの使用率(つまり FPGA エリアの使用率)が増加し、通常はパフォーマンスが低下します。

パフォーマンス・カウンターを使用した Verilog コードのインストルメントについては、 インテルFPGA SDK for OpenCL プログラミング・ガイドの「パフォーマンス・カウンターを使用したカーネル・パイプラインのインストルメントのセクションを参照してください。

関連情報• Collecting Profile Data During Kernel Execution

• Instrumenting the Kernel Pipeline with Performance Counters (-profile)

4. パフォーマンスのボトルネックを特定するためのカーネルのプロファイリングUG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

99

Page 100: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略

適化レポートのフィードバックに基づくて Single Work-Item カーネル依存関係のアドレッシング(100 ページ)

メモリー配列へのアクセスによるループキャリー依存関係の削除 (112 ページ)

Single Work-Item カーネルの良いデザイン方法 (113 ページ)

5.1. 最適化レポートのフィードバックに基づくて Single Work-Item カーネル依存関係のアドレッシング

多くの場合、 OpenCL アプリケーションを Single Work-Item カーネルとしてデザインするだけで、追加の 適化手順を実行せずにパフォーマンスを 大化することができます。Single Work-Item カーネルのパフォーマンスをさらに向上させるために、 適化レポートが識別する依存関係に対処することによって 適化することができます。

次のフローチャートは、デザインを反復し、Single Work-Item カーネルを 適化するために取ることができるアプローチの概要を示しています。使用方法については、 インテル FPGA SDK for OpenCLEmulator と Profiler については、 インテル FPGA SDK for OpenCL プログラミング・ガイドのOpenCL カーネルのエミュレートとデバッグと OpenCL カーネルの プロファイリングを参照してください。 Intel FPGA Dynamic Profiler for OpenCL GUI およびプロファイリング情報について詳しくは、 パフォーマンス・ボトルネックを特定するためのカーネルのプロファイルを参照してください。

インテル は除去、緩和、単純化、およびローカルメモリーへの転送の順に、単一の Work-Item カーネルループ搬送依存関係に対処するための以下の 適化オプションを推奨しています。

UG-OCL003 | 2017.12.08

フィードバック

Intel Corporation.無断での引用、転載を禁じます。Intel、インテル、Intel ロゴ、Altera、ARRIA、CYCLONE、ENPIRION、MAX、NIOS、QUARTUS および STRATIX の名称およびロゴは、アメリカ合衆国および/ またはその他の国における Intel Corporationの商標です。インテルは FPGA 製品および半導体製品の性能がインテルの標準保証に準拠することを保証しますが、インテル製品およびサービスは、予告なく変更される場合があります。インテルが書面にて明示的に同意する場合を除き、インテルはここに記載されたアプリケーション、または、いかなる情報、製品、またはサービスの使用によって生じるいっさいの責任を負いません。インテル製品の顧客は、製品またはサービスを購入する前、および、公開済みの情報を信頼する前には、デバイスの仕様を 新のバージョンにしておくことをお勧めします。*その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

ISO9001:2015登録済

Page 101: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -73: Single Work-Item カーネルの最適化ワークフロー

Develop kernel as single work-item

Generate optimization report to identify pipeline stalls

aoc -c myKernel.cl

Minimize pipeline stalls by:1. Removing dependency2. Relaxing dependency3. Simplifying dependency4. Accepting modifications

Pipeline stallsidentified?

Generate the .aocx file

aoc [-v] myKernel.cl -report

Measure kernel performance(e.g. modify host code to track time before

and after clEnqueueTask() API call)

Performancetarget met?

Optimizationcompletes

YES NO

YES

myKernel.aocx

Emulate kernel aoc -march=emulator myKernel.cl

Profile kernelaoc -profile myKernel.cl

aocl report myKernel.aocx profile.mon [myKernel.source]

Restructuredesign

NO

Emulationsuccessful?

Loop Analysis in the HTML report

myKernel.aoco

NO

YES

Estimated Resource Usage Summary in the HTML report

Resource usageacceptable?

Use available resources to:1. Execute certain pipleinesections in parallel2. Unroll loops

NOYES Free on-chipresources available?

NO

Restructuredesign

YES

Review HTML report<your_kernel_filename>/reports/report.html

1. ループ実行依存関係の削除 (101 ページ)

2. Relaxing Loop Carried の依存関係 (104 ページ)

3. Loop Carried 依存関係の簡素化 (106 ページ)

4. ループで運ばれた依存関係のローカルメモリーへの転送 (109 ページ)

5. シフトレジスターの推測によるループキャリー依存関係の削除 (110 ページ)

関連情報• Emulating and Debugging Your OpenCL Kernel

• OpenCL カーネルのエミュレーション

• パフォーマンスのボトルネックを特定するためのカーネルのプロファイリング (86 ページ)

5.1.1. ループ実行依存関係の削除

適化レポートからのフィードバックに基づいて、より単純なメモリー・アクセス・パターンを実装することにより、ループで運ばれる依存関係を削除できます。

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

101

Page 102: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

以下の項目について検討します。

1 #define N 128 2 3 __kernel void unoptimized (__global int * restrict A, 4 __global int * restrict B, 5 __global int* restrict result) 6 { 7 int sum = 0; 8 9 for (unsigned i = 0; i < N; i++) {10 for (unsigned j = 0; j < N; j++) {11 sum += A[i*N+j];12 }13 sum += B[i];14 }15 16 * result = sum;17 }

unoptimized カーネルの 適化レポートは、次のようになります。

===================================================================================Kernel: unoptimized===================================================================================The kernel is compiled for single work-item execution.

Loop Report:

+ Loop "Block1" (file k.cl line 9) | Pipelined with successive iterations launched every 2 cycles due to: | | Pipeline structure: every terminating loop with subloops has iterations | launched at least 2 cycles apart. | Having successive iterations launched every two cycles should still lead to | good performance if the inner loop is pipelined well and has sufficiently | high number of iterations. | | Iterations executed serially across the region listed below. | Only a single loop iteration will execute inside the listed region. | This will cause performance degradation unless the region is pipelined well | (can process an iteration every cycle). | | Loop "Block2" (file k.cl line 10) | due to: | Data dependency on variable sum (file k.cl line 7) | | |-+ Loop "Block2" (file k.cl line 10) Pipelined well. Successive iterations are launched every cycle.

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

102

Page 103: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

• レポートの 初のロウは、 Intel FPGA SDK for OpenCL オフライン・コンパイラーは外部ループのパイプライン実行を正常に推定し、新しいループ反復が他のサイクルごとに起動します。

• due to Pipeline structure というメッセージは、オフライン・コンパイラーが外側ループ反復を 2 サイクルごとに起動させるパイプライン構造を作成することを示します。この動作は、カーネルコードの構造の結果ではありません。

注意: 単一の Work-Item カーネルを構成する方法の推奨事項については、単一の Work-Itemカーネルのための良いデザイン方法のセクションを参照してください。

• レポートの 初の行の残りのメッセージは、変数 sum に対するデータ依存のために、ループがサブループ全体で一度に 1 回の繰り返しを実行することを示しています。このデータ依存関係は、各外部ループ反復が、内部ループが実行を開始する前に前の反復からの sum の値が必要であるために存在します。

• レポートの 2 番目のロウは、内部ループがパイプライン形式で実行され、パフォーマンス制限のあるループに依存する依存関係がないことを通知します。

外側のループの反復がサブループ渡って連続的に実行されないように、このカーネルのパフォーマンスを 適化するには、変数 sum のデータの依存関係を削除します。 2 つのループで sum を含む計算を切り離すには、次のタスクを実行します。

1. 内部ループでのみ使用するローカル変数( sum2 など )を定義します。

2. ステップ 1 のローカル変数を使用して、 A [i * N + j]の累積値を内部ループの繰り返しとして格納します。

3. 外部ループでは、 B [i]の累積値とローカル変数に格納されている値を格納する変数 sum を格納します。

以下は、再構成されたカーネル optimized です。

1 #define N 128 2 3 __kernel void optimized (__global int * restrict A, 4 __global int * restrict B, 5 __global int * restrict result) 6 { 7 int sum = 0; 8 9 for (unsigned i = 0; i < N; i++) {10 // Step 1: Definition11 int sum2 = 0;12 13 // Step 2: Accumulation of array A values for one outer loop iteration14 for (unsigned j = 0; j < N; j++) {15 sum2 += A[i*N+j];16 }17 18 // Step 3: Addition of array B value for an outer loop iteration19 sum += sum2;20 sum += B[i];21 }22 23 * result = sum;24 }

以下のような 適化レポートは、変数 sum に対するループキャリー依存関係の削除に成功したことを示しています。

===================================================================================Kernel: optimized

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

103

Page 104: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

===================================================================================The kernel is compiled for single work-item execution.

Loop Report:

+ Loop "Block1" (file optimized.cl line 9) | Pipelined with successive iterations launched every 2 cycles due to: | | Pipeline structure: every terminating loop with subloops has iterations | launched at least 2 cycles apart. | Having successive iterations launched every two cycles should still lead to | good performance if the inner loop is pipelined well and has sufficiently | high number of iterations. | | |-+ Loop "Block2" (file optimized.cl line 14) Pipelined well. Successive iterations are launched every cycle.

===================================================================================

適化レポートに次のメッセージだけが表示されたら、ループキャリー依存関係の問題はすべて解決しました。

• Pipelined execution inferred∸ も内側のループ用。

• Pipelined execution inferred. Successive iterations launchedevery 2 cycles due to: Pipeline structure∸他のすべてのループ用。

関連情報Single Work-Item カーネルの良いデザイン方法 (113 ページ)

5.1.2. Relaxing Loop Carried の依存関係

適化レポートからのフィードバックに基づいて、依存距離を増やすことでループに依存する依存関係を緩和することができます。ループキャリー値の生成とその使用の間に発生するループ反復回数を増やすことによって依存距離を増加させます。

次の式を検討してみましょう。

1 #define N 128 2 3 __kernel void unoptimized (__global float * restrict A, 4 __global float * restrict result) 5 { 6 float mul = 1.0f; 7 8 for (unsigned i = 0; i < N; i++) 9 mul *= A[i];10 11 * result = mul;12 }

===================================================================================Kernel: unoptimized===================================================================================The kernel is compiled for single work-item execution.

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

104

Page 105: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

Loop Report:

+ Loop "Block1" (file unoptimized.cl line 8) Pipelined with successive iterations launched every 6 cycles due to:

Data dependency on variable mul (file unoptimized.cl line 9) Largest Critical Path Contributor: 100%: Fmul Operation (file unoptimized.cl line 9)

===================================================================================

上記の 適化レポートでは、 Intel FPGA SDK for OpenCL オフライン・コンパイラーがループのパイプライン実行を首尾よく推測します。しかし、変数 mul に対するループキャリーの依存関係は、6 サイクルごとにループ反復を開始させます。この場合、ライン 9 上の浮動小数点乗算演算(すなわち、 mul *= A [i] )は、変数 mul の計算に対する 大の遅延に寄与します。

ループ運搬のデータ依存性を緩和するために、代わりにすべての M の繰り返しを、乗算結果を格納する変数の M コピー上で動作し、一つのコピーを使用するために単一の変数を使用します。

1. 変数 mul の複数のコピーを宣言します(たとえば、 mul_copies という配列内 )。

2. mul_copies のすべてのコピーを初期化します。

3. 乗算演算では、配列の 後のコピーを使用します。

4. シフト演算を実行して、配列の 後の値をシフトレジスターの先頭に戻します。

5. すべてのコピーを mul に削減し、 終値を result に書き込みます。

以下は再構築されたカーネルです。

1 #define N 128 2 #define M 8 3 4 __kernel void optimized (__global float * restrict A, 5 __global float * restrict result) 6 { 7 float mul = 1.0f; 8 9 // Step 1: Declare multiple copies of variable mul10 float mul_copies[M];11 12 // Step 2: Initialize all copies13 for (unsigned i = 0; i < M; i++)14 mul_copies[i] = 1.0f;15 16 for (unsigned i = 0; i < N; i++) {17 // Step 3: Perform multiplication on the last copy18 float cur = mul_copies[M-1] * A[i];19 20 // Step 4a: Shift copies21 #pragma unroll 22 for (unsigned j = M-1; j > 0; j--)23 mul_copies[j] = mul_copies[j-1];24 25 // Step 4b: Insert updated copy at the beginning26 mul_copies[0] = cur;27 }28 29 // Step 5: Perform reduction on copies30 #pragma unroll 31 for (unsigned i = 0; i < M; i++)32 mul *= mul_copies[i];

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

105

Page 106: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

33 34 * result = mul;35 }

以下のような 適化レポートは、変数 mul に対するループキャリー依存関係の緩和に成功したことを示しています。

===================================================================================Kernel: optimized===================================================================================The kernel is compiled for single work-item execution.

Loop Report:

+ Fully unrolled loop (file optimized2.cl line 13) Loop was automatically and fully unrolled. Add "#pragma unroll 1" to prevent automatic unrolling.

+ Loop "Block1" (file optimized2.cl line 16) | Pipelined well. Successive iterations are launched every cycle. | | |-+ Fully unrolled loop (file optimized2.cl line 22) Loop was fully unrolled due to "#pragma unroll" annotation.

+ Fully unrolled loop (file optimized2.cl line 31) Loop was fully unrolled due to "#pragma unroll" annotation.

5.1.3. Loop Carried 依存関係の簡素化

カーネルでループに依存する依存関係を削除したり緩めることができない場合、依存関係を単純化して単一の work-item カーネルのパフォーマンスを向上させることができます。

次の式を検討してみましょう。

1 #define N 128 2 #define NUM_CH 3 3 4 channel uchar CH_DATA_IN[NUM_CH]; 5 channel uchar CH_DATA_OUT; 6 7 __kernel void unoptimized() 8 { 9 unsigned storage = 0;10 unsigned num_bytes = 0;11 12 for (unsigned i = 0; i < N; i++) {13 14 #pragma unroll15 for (unsigned j = 0; j < NUM_CH; j++) {16 if (num_bytes < NUM_CH) {17 bool valid = false;18 uchar data_in = read_channel_nb_intel(CH_DATA_IN[j], &valid);19 if (valid) {20 storage <<= 8;21 storage |= data_in;22 num_bytes++;23 }24 }25 }26

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

106

Page 107: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

27 if (num_bytes >= 1) {28 num_bytes -= 1;29 uchar data_out = storage >> (num_bytes*8);30 write_channel_intel(CH_DATA_OUT, data_out);31 }32 }33 }

このカーネルは、3 つの入力チャンネルから 1 バイトのデータをノンブロッキング形式で読み込みます。次に、データを一度に 1 バイトずつ出力チャネルに書き込みます。変数 storage を使用して 大 4 バイトのデータを格納し、変数 num_bytes を使用して、格納されているバイト数を追跡します。 storageに使用可能なスペースがある場合、カーネルはチャネルの 1 つから 1 バイトのデータを読み出し、storage の 下位バイトに格納します。

次の 適化レポートは、変数 num_bytes にループで運ばれる依存関係があることを示しています。

===================================================================================Kernel: unoptimized===================================================================================The kernel is compiled for single work-item execution.

Loop Report:

+ Loop "Block1" (file unoptimized3.cl line 12) | Pipelined with successive iterations launched every 7 cycles due to: | | Data dependency on variable num_bytes (file unoptimized3.cl line 10) | Largest Critical Path Contributors: | 16%: Integer Compare Operation (file unoptimized3.cl line 16) | 16%: Integer Compare Operation (file unoptimized3.cl line 16) | 16%: Integer Compare Operation (file unoptimized3.cl line 16) | 7%: Integer Compare Operation (file unoptimized3.cl line 27) | 6%: Add Operation (file unoptimized3.cl line 10, line 22, line 28) | 6%: Add Operation (file unoptimized3.cl line 10, line 22, line 28) | 6%: Add Operation (file unoptimized3.cl line 10, line 22, line 28) | 3%: Non-Blocking Channel Read Operation (file unoptimized3.cl line 18) | 3%: Non-Blocking Channel Read Operation (file unoptimized3.cl line 18) | 3%: Non-Blocking Channel Read Operation (file unoptimized3.cl line 18) | | |-+ Fully unrolled loop (file unoptimized3.cl line 15) Loop was fully unrolled due to "#pragma unroll" annotation.

num_bytes の計算パスは次のとおりです。

1. 16 行目の比較( (num_bytes <NUM_CH)の場合 )

2. 19 行目の比較のために、18 行目の非ブロッキング・チャネル読み出し操作で valid 変数の計算( uchar data_in = read_channel_nb_intel(CH_DATA_IN [j]、&valid) )。

3. 22 行目への追加( num_bytes ++ )。

4. 27 行目の比較( if(num_bytes> = 1) )。

5. 28 行目の減算( num_bytes - = 1 )。

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

107

Page 108: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

14 行目の unroll プラグマのために、 Intel FPGA SDK for OpenCL オフライン・コンパイラーは、ループをアンロールし、ループ本体の比較と追加を 3 回繰り返します。 適化レポートは、比較がnum_bytes の計算パスで も高価な演算であり、その後に 22 行目の加算が続くことを示しています。

num_bytes に対するループキャリーの依存関係を単純化するには、アプリケーションを再構築して次のタスクを実行することを検討してください 。

1. カーネルは、 storage に使用可能な十分なスペースがある場合にのみチャネルから読み出すことを確認し、すべてのチャネルの操作がデータを返す読み出すた場合に(つまり、 storage 内の空きスペースの少なくとも 3 つのバイトがある)。この条件を設定すると、比較回数を減らすことで変数 num_bytes の計算パスが簡単になります。

2. より簡単に 3 バイトのスペースしきい値を満たすために、 storage のサイズを 4 バイトから 8 バイトに増やします。

Below is the restructured kernel optimized:

1 #define N 128 2 #define NUM_CH 3 3 4 channel uchar CH_DATA_IN[NUM_CH]; 5 channel uchar CH_DATA_OUT; 6 7 __kernel void optimized() 8 { 9 // Change storage to 64 bits10 ulong storage = 0;11 unsigned num_bytes = 0;12 13 for (unsigned i = 0; i < N; i++) {14 15 // Ensure that we have enough space if we read from ALL channels16 if (num_bytes <= (8-NUM_CH)) {17 #pragma unroll18 for (unsigned j = 0; j < NUM_CH; j++) {19 bool valid = false;20 uchar data_in = read_channel_nb_intel(CH_DATA_IN[j], &valid);21 if (valid) {22 storage <<= 8;23 storage |= data_in;24 num_bytes++;25 }26 }27 }28 29 if (num_bytes >= 1) {30 num_bytes -= 1;31 uchar data_out = storage >> (num_bytes*8);32 write_channel_intel(CH_DATA_OUT, data_out);33 }34 }35 }

An optimization report similar to the one below indicates the successful simplificationof the loop-carried dependency on the variable num_bytes:

===================================================================================Kernel: optimized===================================================================================The kernel is compiled for single work-item execution.

Loop Report:

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

108

Page 109: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

+ Loop "Block1" (file optimized3.cl line 13) | Pipelined well. Successive iterations are launched every cycle. | | |-+ Fully unrolled loop (file optimized3.cl line 18) Loop was fully unrolled due to "#pragma unroll" annotation.

5.1.4. ループで運ばれた依存関係のローカルメモリーへの転送

削除できないループキャリー依存関係の場合は、グローバルメモリーからローカルメモリーへのループキャリー依存関係を持つ配列を移動して II を改善します。

次の式を検討してみましょう。

1 #define N 12823 __kernel void unoptimized( __global int* restrict A )4 {5 for (unsigned i = 0; i < N; i++)6 A[N-i] = A[i];7 }

===================================================================================Kernel: unoptimized===================================================================================The kernel is compiled for single work-item execution.

Loop Report:

+ Loop "Block1" (file unoptimized4.cl line 5) Pipelined with successive iterations launched every 324 cycles due to:

Memory dependency on Load Operation from: (file unoptimized4.cl line 6) Store Operation (file unoptimized4.cl line 6) Largest Critical Path Contributors: 49%: Load Operation (file unoptimized4.cl line 6) 49%: Store Operation (file unoptimized4.cl line 6)

グローバル・メモリー・アクセスには長いレイテンシーがあります。この例では、配列 A [i]に対するループ搬送依存性は長いレイテンシーを引き起こす。このレイテンシーは、 適化レポートの II が 324 に反映されています。ループで運ばれた依存関係をグローバルメモリーからローカルメモリーに転送してII 値を減らすには、次のタスクを実行します。

1. ループ実行された依存関係を持つ配列をローカルメモリーにコピーします。この例では、配列A[i]はローカルメモリーの配列 B [i]になります。

2. 配列 B [i]に対してループで実行される依存関係を持つループを実行します。

3. 配列をグローバルメモリーにコピーし直します。

配列 A [i]をローカルメモリに転送すると、配列 B [i]になります。ループに依存する依存関係は、B [i]になります。ローカルメモリーはグローバルメモリーよりもはるかに低いレイテンシーを持つため、II 値が向上します。

以下は、再構成されたカーネル 適化です。

1 #define N 128 2 3 __kernel void optimized( __global int* restrict A )

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

109

Page 110: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

4 { 5 int B[N]; 6 7 for (unsigned i = 0; i < N; i++) 8 B[i] = A[i]; 910 for (unsigned i = 0; i < N; i++)11 B[N-i] = B[i];1213 for (unsigned i = 0; i < N; i++)14 A[i] = B[i];15 }

下記のような 適化レポートは、324 から 2 への II の減少の成功を示しています。

===================================================================================Kernel: optimized===================================================================================The kernel is compiled for single work-item execution.

Loop Report:

+ Loop "Block1" (file optimized4.cl line 7) Pipelined well. Successive iterations are launched every cycle.

+ Loop "Block2" (file optimized4.cl line 10) Pipelined with successive iterations launched every 2 cycles due to:

Memory dependency on Load Operation from: (file optimized4.cl line 11) Store Operation (file optimized4.cl line 11) Largest Critical Path Contributors: 65%: Load Operation (file optimized4.cl line 11) 34%: Store Operation (file optimized4.cl line 11)

+ Loop "Block3" (file optimized4.cl line 13) Pipelined well. Successive iterations are launched every cycle.

5.1.5. シフトレジスターの推測によるループキャリー依存関係の削除

Intel FPGA SDK for OpenCL オフライン・コンパイラーで倍精度浮動小数点演算を効率的に実行する 1 つの作業項目カーネルを処理できるようにするには、シフトレジスターを推論してループ実行依存関係を削除します。

以下の項目について検討します。

1 __kernel void double_add_1 (__global double *arr, 2 int N, 3 __global double *result) 4 { 5 double temp_sum = 0; 6 7 for (int i = 0; i < N; ++i) 8 { 9 temp_sum += arr[i];10 }11 12 *result = temp_sum;13 }

unoptimized カーネルの Optimization レポートは、次のようになります。

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

110

Page 111: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

===================================================================================Kernel: double_add_1===================================================================================The kernel is compiled for single work-item execution.

Loop Report:

+ Loop "Block1" (file unoptimized5.cl line 7) Pipelined with successive iterations launched every 11 cycles due to:

Data dependency on variable temp_sum (file unoptimized5.cl line 9) Largest Critical Path Contributor: 97%: Fadd Operation (file unoptimized5.cl line 9)

適化されていないカーネルは、倍精度浮動小数点配列 arr [i]の要素を合計する累算器です。各ループ反復に対して、オフライン・コンパイラーは加算の結果を計算するために 11 サイクルを要し、それを変数 temp_sum に格納します 。各ループの反復では、以前のループ反復からの temp_sum の値が必要です。これにより、 temp_sum にデータ依存関係が作成されます 。

• データの依存関係を削除するには、配列 arr [i]をシフトレジスターとして推定します。

以下は、再構成されたカーネル optimized です:

1 //Shift register size must be statically determinable 2 #define II_CYCLES 12 3 4 __kernel void double_add_2 (__global double *arr, 5 int N, 6 __global double *result) 7 { 8 //Create shift register with II_CYCLE+1 elements 9 double shift_reg[II_CYCLES+1];10 11 //Initialize all elements of the register to 012 for (int i = 0; i < II_CYCLES + 1; i++)13 {14 shift_reg[i] = 0;15 }16 17 //Iterate through every element of input array18 for(int i = 0; i < N; ++i)19 {20 //Load ith element into end of shift register21 //if N > II_CYCLE, add to shift_reg[0] to preserve values22 shift_reg[II_CYCLES] = shift_reg[0] + arr[i];23 24 #pragma unroll25 //Shift every element of shift register26 for(int j = 0; j < II_CYCLES; ++j)27 {28 shift_reg[j] = shift_reg[j + 1];29 }30 }31 32 //Sum every element of shift register33 double temp_sum = 0;34 35 #pragma unroll 36 for(int i = 0; i < II_CYCLES; ++i)37 {38 temp_sum += shift_reg[i];39 }

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

111

Page 112: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

4041 *result = temp_sum;42 }

次の Optimization レポートは、シフトレジスター shift_reg [II_CYCLES]の推論が変数temp_sum のデータ依存性を正常に削除することを示しています。

===================================================================================Kernel: double_add_2===================================================================================The kernel is compiled for single work-item execution.

Loop Report:

+ Fully unrolled loop (file optimized5.cl line 12) Loop was automatically and fully unrolled. Add "#pragma unroll 1" to prevent automatic unrolling.

+ Loop "Block1" (file optimized5.cl line 18) | Pipelined well. Successive iterations are launched every cycle. | | |-+ Fully unrolled loop (file optimized5.cl line 26) Loop was fully unrolled due to "#pragma unroll" annotation.

+ Fully unrolled loop (file optimized5.cl line 36) Loop was fully unrolled due to "#pragma unroll" annotation.

5.2. メモリー配列へのアクセスによるループキャリー依存関係の削除

単一の Work-Item カーネルに ivdep プラグマを含めて、メモリー配列へのアクセスがループに依存する依存関係を引き起こさないことを宣言します。

コンパイル中に、 Intel FPGA SDK for OpenCL オフライン・コンパイラーは、ロードおよびストア命令が依存関係の制約内で動作することを保証するハードウェアを作成します。依存関係制約の一例は、従属するロード命令およびストア命令が順番に実行されなければならないことです。 ivdep プラグマが存在すると、オフライン・コンパイラーは、カーネルコード内のプラグマ宣言の直後にあるループ内のロード命令とストア命令の間にこの余分なハードウェアを取り除くよう指示します。余分なハードウェアを削除すると、ロジック使用率が低下し、単一の Work-Item カーネルで II 値が低下する可能性があります。

• ループ内にあるメモリー配列へのすべてのアクセスがループキャリー依存関係を引き起こさない場合、カーネルコードのループの前に#pragma ivdep 行を追加します。

Example kernel code:

// no loop-carried dependencies for A and B array accesses#pragma ivdepfor (int i = 0; i < N; i++) {

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

112

Page 113: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

A[i] = A[i - X[i]]; B[i] = B[i - Y[i]];}

• ループ内の特定のメモリー配列へのアクセスがループに依存する依存関係を引き起こさないように指定するには、カーネルコードのループの前に#pragma ivdep array( array_name )という行を追加します。

ivdep プラグマで指定された配列は、ローカルまたはプライベートのメモリー配列、またはグローバル、ローカル、またはプライベートのメモリーストレージを指すポインター変数でなければなりません。指定された配列がポインターの場合、 ivdep プラグマは指定されたポインターで別名を持つ可能性があるすべての配列にも適用されます。

ivdep プラグマで指定された配列は、構造体の配列またはポインターメンバーでもあります。

カーネルコードの例 :

// No loop-carried dependencies for A array accesses// The offline compiler will insert hardware that reinforces dependency constraints for B#pragma ivdep array(A)for (int i = 0; i < N; i++) { A[i] = A[i - X[i]]; B[i] = B[i - Y[i]];}

// No loop-carried dependencies for array A inside struct#pragma ivdep array(S.A)for (int i = 0; i < N; i++) { S.A[i] = S.A[i - X[i]];}

// No loop-carried dependencies for array A inside the struct pointed by S#pragma ivdep array(S->X[2][3].A)for (int i = 0; i < N; i++) { S->X[2][3].A[i] = S.A[i - X[i]];}

// No loop-carried dependencies for A and B because ptr aliases// with both arraysint *ptr = select ? A : B;#pragma ivdep array(ptr)for (int i = 0; i < N; i++) { A[i] = A[i - X[i]]; B[i] = B[i - Y[i]];}

// No loop-carried dependencies for A because ptr only aliases with Aint *ptr = &A[10];#pragma ivdep array(ptr)for (int i = 0; i < N; i++) { A[i] = A[i - X[i]]; B[i] = B[i - Y[i]];}

5.3. Single Work-Item カーネルの良いデザイン方法

OpenCL カーネルにループ構造が含まれている場合は、 インテル で推奨されるのガイドラインに従って、 Intel FPGA SDK for OpenCL オフライン・コンパイラーが効果的に解析できるようにカーネルを構築してください。適切に構造化されたループは、ループ内でパイプライン並列処理を実行するようにオフライン・コンパイラーに指示する場合に特に重要です。

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

113

Page 114: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

ポインター・エイリアシングの回避

可能であれば、ポインター引数に restrict キーワードを挿入します。ポインター引数に restrictキーワードを含めることにより、オフライン・コンパイラーは、競合しない読み出し動作と書き込み動作の間に不要なメモリー依存関係を作成することを防止します。各反復があるアレイからデータを読み出し、同じ物理メモリー内の別のアレイにデータを書き込むループを検討してください。これらのポインター引数に restrict キーワードを含めることなく、オフライン・コンパイラーは 2 つの配列間の依存関係を想定し、その結果としてパイプラインの並列性を少なくします。

「整形式ループの構築

「正常に形成されたループは、整数境界と比較され、反復ごとに 1 の単純な誘導インクリメントを有する出口条件がありますカーネルに "整形式"ループを含めると、オフライン・コンパイラーがこれらのループを効率的に解析できるため、パフォーマンスが向上します。

次の例は、「整形式ループです。

for (i = 0; i < N; i++) { //statements}

重要: 「整形式ネストループは、カーネルのパフォーマンスを 大化するのにも役立ちます。

次の例は、「整形式ネストループ構造です。

for (i = 0; i < N; i++) { //statements for(j = 0; j < M; j++) { //statements }}

ループ運搬依存関係の最小化

以下のループ構造は、各ループ反復が以前の反復によって書き込まれたデータを読み込むため、ループに依存する依存関係を作成します。その結果、前の反復からの書き込み動作が完了するまで、各読み出し動作を続行できません。ループに依存する依存関係が存在すると、オフライン・コンパイラーが達成できるパイプラインの並列性が低下し、カーネルのパフォーマンスが低下します。

for (int i = 0; i < N; i++) { A[i] = A[i - 1] + i;}

オフライン・コンパイラーは、ループで静的なメモリー依存分析を実行して、ループが達成できる並列度を判断します。場合によっては、オフライン・コンパイラーが 2 つの配列アクセス間の依存関係を想定し、その結果としてパイプラインの並列性が低下することがあります。オフライン・コンパイラーは、未知の変数のためにコンパイル時に依存関係を解決できない場合、または配列アクセスが複雑なアドレッシングを伴う場合、ループに依存する依存関係を前提としています。

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

114

Page 115: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

可能な場合、ループに依存する依存関係を 小限に抑えるため、以下のガイドラインに従ってください。

• ポインター演算を回避します。

カーネルが算術演算から導出されたポインター値を逆参照することによって配列にアクセスするとき、コンパイラーの出力は 適ではない。たとえば、次の方法で配列にアクセスしないでください。

for (int i = 0; i < N; i++) { int t = *(A++); *A = t;}

• 単純な配列インデックスを導入します。

オフライン・コンパイラーがそれらを効率的に解析できないため、次のタイプの複雑な配列インデックスは回避してください。コンパイラー出力が 適ではない場合があります。

— 配列インデックスの非定数。

たとえば、 A [K + i] ( i はループインデックス変数、 K は未知変数)。

— 同じ添字の場所に複数の索引変数があります。

たとえば、 A [i + 2×j] ( i と j はダブルネストループのループインデックス変数)です。

注意: オフライン・コンパイラーは、インデックス変数が異なる下付き文字であるため、効率的に配列インデックス A [i] [j]を解析できます。

— 非線形インデックス付け。

たとえば、 A [i&C]は i がループインデックス変数、 C が定数または非定数変数です。

• 可能であれば、カーネル内の一定の境界を持つループを使用してください。

一定の境界を持つループにより、オフライン・コンパイラーは範囲分析を効果的に実行できます。

複雑なループ終了条件の回避

オフライン・コンパイラーは、終了条件を評価して、後続のループ反復がループパイプラインに入るかどうかを判断します。オフライン・コンパイラーが終了条件を評価するためにメモリーアクセスまたは複雑な動作を必要とすることがあります。このような場合、後続の反復は、評価が完了するまで開始できず、全体的なループのパフォーマンスが低下します。

ネステッド・ループから単一のループへの変換

パフォーマンスを 大にするには、ネステッド・ループを可能な限り単一のフォームに結合します。ネステッド・ループを単一のループに再構成することは、ループ反復間のハードウェア・フットプリントおよび計算オーバーヘッドを低減します。

次のコード例は、ネストされたループの単一ループへの変換を示しています。

ネストループ 変換シングルループ

for (i = 0; i < N; i++) { //statements for (j = 0; j < M; j++) { //statements } //statements}

for (i = 0; i < N*M; i++) { //statements}

可能な限り最も深いスコープ内の変数の宣言

変数の実装に必要なハードウェア・リソースを減らすには、変数をループで使用する前に宣言します。変数を使用しないループ全体で変数データを保存する必要がないため、できるだけ深いスコープで変数を宣言すると、データの依存関係やハードウェアの使用が 小限に抑えられます。

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

115

Page 116: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

次の式を検討してみましょう。

int a[N];for (int i = 0; i < m; ++i) { int b[N]; for (int j = 0; j < n; ++j) { // statements }}

配列 a は、配列 b よりも多くのリソースを実装する必要があります。ハードウェアの使用を減らすには、外側ループの反復によってデータを維持する必要がない限り、配列 a を内側ループの外側に宣言します。

ヒント: 可能な限り も深いスコープで変数のすべての値を上書きすると、変数を表示するのに必要なリソースも少なくなります。

5. Single Work-Item カーネル・パフォーマンスを向上させるための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

116

Page 117: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

6. 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] = a[gid] + b[gid];}

このカーネルは、配列 a と b を一度に 1 つずつ追加します。各 Work-Item は、2 つの要素(各配列から1 つずつ)を追加し、和を配列の回答に格納する役割を担います 。 適化がなければ、カーネルはWork-Item ごとに 1 回の追加を実行します。OpenCL カーネルのパフォーマンスを 大にするには、適用可能な 適化手法を実装して、データ処理効率を向上させることを検討してください。

1. 大ワーク・グループ・サイズまたは必要なワーク・グループ・サイズの指定 (117 ページ)

2. カーネルのベクトル化 (119 ページ)

3. 複数のコンピューティング・ユニット (122 ページ)

4. コンピューティング・ユニット複製とカーネル SIMD ベクトル化の組み合わせ (124 ページ)

5. リソース駆動型 適化 (126 ページ)

6. HTML レポートのカーネルプロパティとループアンロールステータスの確認 (127 ページ)

6.1. 最大ワーク・グループ・サイズまたは必要なワーク・グループ・サイズの指定

可能であれば 、カーネルの max_work_group_size 属性または reqd_work_group_size属性を指定します。これらの属性により、 Intel FPGA SDK for OpenCL オフライン・コンパイラーは余分なロジックなしでカーネルをハードウェア・リソースに一致させるための積極的な 適化を実行します。

オフライン・コンパイラーは、コンパイル時および実行時に課される特定の制約に応じて、カーネルのデフォルトのワーク・グループ・サイズを想定しています。

UG-OCL003 | 2017.12.08

フィードバック

Intel Corporation.無断での引用、転載を禁じます。Intel、インテル、Intel ロゴ、Altera、ARRIA、CYCLONE、ENPIRION、MAX、NIOS、QUARTUS および STRATIX の名称およびロゴは、アメリカ合衆国および/ またはその他の国における Intel Corporationの商標です。インテルは FPGA 製品および半導体製品の性能がインテルの標準保証に準拠することを保証しますが、インテル製品およびサービスは、予告なく変更される場合があります。インテルが書面にて明示的に同意する場合を除き、インテルはここに記載されたアプリケーション、または、いかなる情報、製品、またはサービスの使用によって生じるいっさいの責任を負いません。インテル製品の顧客は、製品またはサービスを購入する前、および、公開済みの情報を信頼する前には、デバイスの仕様を 新のバージョンにしておくことをお勧めします。*その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

ISO9001:2015登録済

Page 118: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

オフライン・コンパイラーは、コンパイル時に次の制約を課します。

• reqd_work_group_size 属性に値を指定すると、作業グループのサイズはこの値と一致する必要があります。

• max_work_group_size 属性に値を指定すると、ワーク・グループ・サイズはこの値を超えてはなりません。

• reqd_work_group_size と max_work_group_size の値を指定せず、カーネルに障壁がある場合、オフライン・コンパイラーのデフォルトの作業グループサイズは 256 です。

• 両方の属性に値を指定せず、カーネルにバリアが含まれていない場合、オフライン・コンパイラーはコンパイル時にワーク・グループ・サイズに制約を課すことはありません。

ヒント: clGetKernelWorkGroupInfo API コールの CL_KERNEL_WORK_GROUP_SIZE およびCL_KERNEL_COMPILE_WORK_GROUP_SIZE クエリを使用して、オフライン・コンパイラーがコンパイル時に特定のカーネルに課すワーク・グループ・サイズの制約を判断します。

OpenCL 標準では、実行時に次の制約が課されます。

• 各ディメンションのワーク・グループ・サイズは、各ディメンションの要求された NDRange サイズに均等に分割する必要があります。

• ワーク・グループ・サイズは、 clGetDeviceInfo API コールのCL_DEVICE_MAX_WORK_GROUP_SIZE およびCL_DEVICE_MAX_WORK_ITEM_SIZES クエリで指定されたデバイス制約を超えてはなりません。

注意: 要求された NDRange カーネルの実行に指定したワーク・グループ・サイズが上記のすべての制約を満たしていない場合、 clEnqueueNDRangeKernel API 呼び出しはエラーCL_INVALID_WORK_GROUP_SIZE で失敗します。

reqd_work_group_size 属性と max_work_group_size 属性の両方に値を指定しない場合、ランタイムはデフォルトのワーク・グループ・サイズを次のように決定します。

• カーネルに障壁が含まれているかローカルの Work-Item ID を参照している場合、またはホストコードで clGetKernelWorkGroupInfo および clGetDeviceInfo API 呼び出しを使用してワーク・グループ・サイズを照会すると、実行時はワーク・グループ・サイズから Work-Item にデフォルトで実行します。

• カーネルに障壁がないか、ローカル Work-ItemID を参照していない場合、またはホストコードがワーク・グループ・サイズを照会しない場合、デフォルトのワーク・グループ・サイズはグローバルNDRange サイズです。

NDRange カーネル(つまり、Single Work-Item カーネルではない)をキューイングするときは、次の条件で明示的なワーク・グループ・サイズを指定します。

• カーネルがメモリーバリア、ローカルメモリー、またはローカル Work-ItemID を使用している場合。

• ホストプログラムが作業グループのサイズを照会する場合。

カーネルでメモリーバリアが使用されている場合、次のいずれかの作業を実行して、ハードウェア・リソースを 小限に抑えます。

• reqd_work_group_size 属性の値を指定します。

• max_work_group_size 属性には、すべてのランタイム作業グループサイズ要求に対応する小の作業グループサイズを割り当てます。

6. NDRange カーネルのデータ処理効率を向上させるための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

118

Page 119: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

注意: NDRange カーネルの 後にメモリーバリアを含めると、コンパイルが失敗します。

実行時にデフォルトより小さいワーク・グループ・サイズを指定すると、ハードウェアが過剰に消費される可能性があります。したがって、デフォルト以外のワーク・グループ・サイズが必要な場合、max_work_group_size 属性を指定して 大ワーク・グループ・サイズを設定します。すべてのカーネル呼び出しでワーク・グループ・サイズが一定のままである場合、 reqd_work_group_size 属性を含めることによって、必要なワーク・グループ・サイズを指定します。reqd_work_group_size 属性は、指定したワークグループごとの Work-Item の数を管理するために、正確なハードウェア量を割り当てるようにオフライン・コンパイラーに指示します。この割り振りにより、ハードウェア・リソースが節約され、カーネルコンピューティング・ユニットの実装効率が向上します。 reqd_work_group_size属性を指定することにより、オフライン・コンパイラーが未知のサイズの作業グループをサポートするために追加のハードウェアを実装するのを防ぐこともできます。

たとえば、次のコードでは、ワークグループの固定サイズを 64 個の Work-Item に割り当てることができます。

__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];}

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 倍の作業を実行するようになりました。

6. NDRange カーネルのデータ処理効率を向上させるための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

119

Page 120: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

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

カーネルコードを手動でベクトル化できますが、実装するベクトル化の量を反映するように、ホスト・アプリケーションの 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];}

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

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

6.2.1. スタティック・メモリー統合

静的メモリー統合は、カーネルが非プライベート・メモリーにアクセスする回数を減らそうとする IntelFPGA SDK for OpenCL オフライン・コンパイラー 適化ステップです。

次の図は、カーネルのパフォーマンスがスタティック・メモリー統合から利益を得られる一般的なケースを示しています。

6. NDRange カーネルのデータ処理効率を向上させるための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

120

Page 121: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -74: スタティック・メモリー統合

__kernel void summation(__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];}

__kernel void summation(__global const float4 * restrict a, __global const float4 * restrict b, __global float4 * restrict answer){ size_t gid = get_global_id(0);

answer[gid] = a[gid] + b[gid];}

Original Kernel

With CoalescingMemory

次のベクトル化されたカーネルを検討してください。

__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];}

OpenCL カーネルは、メモリー内の連続した場所にアクセスする 4 つのロード動作を実行します。競合する場所に 4 回のメモリーアクセスを実行する代わりに、オフライン・コンパイラーは 4 つの負荷を単一のより広いベクトル負荷に統合します。この 適化により、メモリーシステムへのアクセス回数が減少し、メモリー・アクセス・パターンが改善される可能性があります。

オフライン・コンパイラーは、カーネルをベクトル化する際にスタティック・メモリーの結合を自動的に実行しますが、効率的なメモリーアクセスを確保するために、可能な場合はいつでも、広いベクトルロードとストアを OpenCL コードに使用する必要があります。スタティック・メモリー統合を手動で実装するには、コンパイル時に順次アクセスパターンを識別できるようにコードを記述する必要があります。上の図に示されている元のカーネルコードは、スタティック・メモリー結合から恩恵を受けることができます。これは、バッファー a と b のすべてのインデックスが、コンパイル時に判明しているオフセットで増分するためです。これとは対照的に、次のコードでは、スタティック・メモリーの結合を行うことはできません。

__kernel void test (__global float * restrict a, __global float * restrict b, __global float * restrict answer; __global int * restrict offsets){ size_t gid = get_global_id(0);

answer[gid*4 + 0] = a[gid*4 + 0 + offsets[gid]] + b[gid*4 + 0]; answer[gid*4 + 1] = a[gid*4 + 1 + offsets[gid]] + b[gid*4 + 1];

6. NDRange カーネルのデータ処理効率を向上させるための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

121

Page 122: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

answer[gid*4 + 2] = a[gid*4 + 2 + offsets[gid]] + b[gid*4 + 2]; answer[gid*4 + 3] = a[gid*4 + 3 + offsets[gid]] + b[gid*4 + 3];}

値のオフセット[gid]はコンパイル時には不明です。その結果、オフライン・コンパイラーは静的に読み出しをバッファーにアクセスを合体することはできません。

6.3. 複数のコンピューティング・ユニット

より高いスループットを達成するために、 Intel FPGA SDK for OpenCL オフライン・コンパイラーはカーネルごとに複数のコンピューティング・ユニットを生成できます。オフライン・コンパイラーは、各計算単位を一意のパイプラインとして実装します。一般に、各カーネルコンピューティング・ユニットは複数のワークグループを同時に実行することができます。

全体のカーネルスループットを向上させるために、FPGA のハードウェア・スケジューラーはワークグループを追加の使用可能なコンピューティング・ユニットにディスパッチします。コンピューティング・ユニットは、フル・キャパシティーに達していない限り、ワークグループ割り当てに使用できます。

各作業グループは、実行を完了するのに同じ時間がかかるものとします。オフライン・コンパイラーが 2つのコンピューティング・ユニットを実装する場合、各コンピューティング・ユニットは作業グループの半分を実行します。ハードウェア・スケジューラーがワークグループをディスパッチするため、このプロセスを独自のコードで管理する必要はありません。

オフライン・コンパイラーは、カーネルの 適な計算単位数を自動的に決定しません。カーネル実装のコンピューティング・ユニットの数を増やすには、以下のコードサンプルに示すように、num_compute_units 属性を使用してオフライン・コンパイラーが作成するコンピューティング・ユニットの数を指定する必要があります。

__attribute__((num_compute_units(2)))__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];}

コンピューティング・ユニットの数を増やすと、スループットが向上します。ただし、以下の図に示すように、コンピューティング・ユニット間のグローバルメモリー帯域幅が増加するという犠牲を払って実行します。また、ハードウェア・リソースの使用率も向上します。

6. NDRange カーネルのデータ処理効率を向上させるための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

122

Page 123: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -75: 複数の計算単位によるデータフロー

Global Memory

Sum KernelCompute Unit #1

Loads

Stores

Sum KernelCompute Unit #2

Loads

Stores

6.3.1. コンピューティング・ユニット複製対カーネル SIMD ベクトル化

ほとんどの場合、 num_simd_work_items 属性を実装して、 num_compute_units 属性を使用する前にデータ処理の効率を上げる必要があります。

num_compute_units 属性と num_simd_work_items 属性の両方は、 Intel FPGA SDKfor OpenCL オフライン・コンパイラーがカーネルを実装するために使用するハードウェアの量を増やすことによってスループットを向上させます。num_compute_units 属性は、ワークグループのスケジュールを設定できるコンピューティング・ユニットの数を変更し、カーネルがグローバルメモリーにアクセスする回数も変更します。対照的に、 num_simd_work_items 属性は、コンピューティング・ユニットが単一のワークグループで並列に実行できる作業量を変更します。num_simd_work_items 属性は、各 SIMD ベクタレーンでコントロールロジックを共有することによって、コンピューティング・ユニットのデータパスのみを複製します。

通常、num_simd_work_items 属性を使用すると、num_compute_units 属性を使用して同じ目標を達成するより効率的なハードウェアにつながります。num_simd_work_items 属性を使用すると、オフライン・コンパイラーでメモリーアクセスを結合することもできます。

6. NDRange カーネルのデータ処理効率を向上させるための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

123

Page 124: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -76: コンピューティング・ユニット複製対カーネル SIMD ベクトル化

Global Memory Global Memory

LD

LD

LD

LD

LDST

ST

ST

ST

ST

Kernel ComputeUnit #1

Kernel ComputeUnit #4

Kernel ComputeUnit #3

Kernel ComputeUnit #2

x4 SIMD KernelCompute Unit

Four Compute Units(num_compute_units(4))

Compute Unit with Four SIMD Lanes(num_simd_work_items(4))

大域メモリーと競合する複数のコンピューティング・ユニッは、望ましくないメモリー・アクセス・パターンにつながる可能性があります。num_simd_work_items が num_compute_units 属性の代わりに属性を導入することにより、望ましくないメモリー・アクセス・パターンを変更することができます。また、num_simd_work_items は、潜在的に属性 num_compute_units がオファーを属性同等のカーネル演算ユニットの重複と同じ演算スループットを提供しています。

次のような状況では、 num_simd_work_items 属性をカーネルに実装することはできません。

• num_simd_work_items に指定する値は、 2,4,8 または 16 ではありません。

• reqd_work_group_size の値は num_simd_work_items で割り切れません。

たとえば、50 が 4 で割り切れないため、次の宣言は正しくありません。

__attribute__((num_simd_work_items(4)))__attribute__((reqd_work_group_size(50,0,0)))

• 複雑な制御フローを持つカーネル。別の Work-Item は、(例えば、制御パスがget_global_ID または get_local_ID に依存)異なる制御経路をたどるするカーネルをベクトル化することはできません。

カーネルコンパイル時に、オフライン・コンパイラーは、ベクトル化 適化の実装が成功したかどうかを通知するメッセージを発行します。報告されたベクトル化係数が num_simd_work_items 属性に指定した値と一致すると、カーネルのベクトル化は成功します。

6.4. コンピューティング・ユニット複製とカーネル SIMD ベクトル化の組み合わせ

複製またはベクトル化された OpenCL カーネルが FPGA に収まらない場合、コンピューティング・ユニットを複製してカーネルをベクトル化することによって、カーネルを変更できます。カーネルのコンピューティング・ユニット数を変更するには、nnum_compute_units 属性を含めます。そして、カーネルのベクトル化を使用するには、num_simd_work_items 属性を含めます。

6. NDRange カーネルのデータ処理効率を向上させるための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

124

Page 125: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

num_simd_work_items 属性が 16 に設定されたカーネルが FPGA に収まらないケースを検討してください。より狭い SIMD カーネルコンピューティング・ユニットを複製することによってカーネルを修正すると、カーネルが適合するかもしれません。コンピューティング・ユニットの数と SIMD 幅の 適なバランスを決定するには、いくつかの実験が必要になるかもしれません。たとえば、4 レーン幅の SIMDカーネルコンピューティング・ユニットを 3 回複製すると、8 レーン幅の SIMD カーネルコンピューティング・ユニットを 2 回複製するよりもスループットが向上する可能性があります。

次のコード例は、 OpenCL コードで num_compute_units および num_simd_work_items属性を組み合わせる方法を示しています。

__attribute__((num_simd_work_items(4)))__attribute__((num_compute_units(3)))__attribute__((reqd_work_group_size(8,8,1)))__kernel void matrixMult(__global float * restrict C, __global float * restrict A,. . .

下の図は、上記のカーネルのデータフローを示しています。 num_compute_units は、3 つの複製コンピューティング・ユニットを実装します。 num_simd_work_items は、4 つの SIMD ベクタレーンを実装しています。

図 -77: コンピューティング・ユニット複製とカーネル SIMD ベクトル化を組み合わせることによるスループットの最適化

Global Memory

LD

LD

LD

ST

ST

ST

x4 SIMD KernelCompute Unit #1

x4 SIMD KernelCompute Unit #3

x4 SIMD KernelCompute Unit #2

注意: また、リソース駆動型オプティマイザで、 num_compute_units と num_simd_work_items の適な組合せを自動的に判別できるようにすることもできます。

重要: より小さなデザインよりも FPGA 全体を満たすハードウェアデザインをコンパイルする方が時間がかかります。カーネル 適化を調整するときは、カーネルを再コンパイルする前に、SIMD ベクタレーンの数を増やしてコンピューティング・ユニットを削除してください。

6. NDRange カーネルのデータ処理効率を向上させるための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

125

Page 126: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

6.5. リソース駆動型最適化

Intel FPGA SDK for OpenCL オフライン・コンパイラーは、様々な値のカーネル属性を組み合わせる効果を自動的に分析し、リソース駆動型の 適化を実行します。

コンパイル中、オフライン・コンパイラーは、さまざまな組み合わせの num_compute_units およびnum_simd_work_items カーネル属性の複数の値を調べ、一連のヒューリスティックを適用してベースデザインを段階的に改善します。オフライン・コンパイラーは、この 1 組の値を実装して、毎秒実行される Work-Item に関してカーネルのパフォーマンスを 大化します。

分析の結果に基づいて、オフライン・コンパイラーは、Work-Item が頻繁に実行するコードブロックを適化します。これらのコードブロックの場合、コンパイラーは追加のハードウェア・リソースを使用して

より高いスループットで実装を実現します。Work-Item が頻繁に実行されないコードブロックの場合、コンパイラーは同じハードウェアを再使用して複数の動作を実装しようとします。

発生するハードウェア共有の量は、 sharing degree と呼ばれます。これは、同じ計算単位内で実行される Work-Item によって動作が共有される回数です。Work-Item が頻繁に実行されないコードブロックは、より高い共有度につながる可能性があります。

オフライン・コンパイラーは、カーネル宣言で指定したカーネル属性またはプラグマの値は変更しません。オフライン・コンパイラーは、不特定の属性とプラグマのみを変更します。

最適化動作

リソース駆動型 適化の例を次に示します。

• カーネルが FPGA に適合しない場合にのみ、頻繁に実行されないコードブロックのリソース共有を試みます。

オフライン・コンパイラーが FPGA 内で 適化されたカーネルを識別した後、 適化を適用してパフォーマンスを向上させます。

• マルチカーネルデザインでは、 初に 小限のパフォーマンスでカーネルを改善します。

カーネルの 適化が行われる順序は、1 秒あたりの Work-Item 数に基づいています。これらのカーネルをそれ以上 適化できない場合、以降のカーネルはスループットの見積もりの順に改善されます。リソース駆動型 適化の間、オフライン・コンパイラーは一連の高性能候補を保持し、それぞれに増分 適化を適用しようとします。これらの 適化は一般的により効率的なハードウェア実装をもたらすので、ループアンローリングおよび SIMD ベクトル化は、コンピューティング・ユニット複製よりも好ましい 適化戦略です。

• リソース駆動型 適化の間、オフライン・コンパイラーは、所定の 適化ステップのセットを反復します。

多くの場合、オフライン・コンパイラーは 適化範囲を事前に推定します。たとえば、使用可能なメモリー帯域幅に基づいてコンピューティング・ユニットの 大数を決定します。オフライン・コンパイラーが 適化を実行できない場合、そのステップをスキップして他の 適化を試みます。

制限

静的 適化にはいくつかの固有の制限があります。制御フロー分析は、コンパイル時に未知である、ホストから渡されたカーネル引数の値を仮定します。たとえば、オフライン・コンパイラーでは、境界が未知のループが 1024 回反復すると想定しています。これらの前提に基づいて、オフライン・コンパイラーは、作業アイテムが予測よりも頻繁に実行されるコードブロックに向けて 適化を誘導することがあります。境界が未知のループの場合、 unroll プラグマを使用してコード内のアンロール係数を指定することによって、アンローリングの量を上書きできます。ループをアンロールする必要がない場合、アンロール係数を 1 に指定して、ループをアンローリングしないことを指定できます。

6. NDRange カーネルのデータ処理効率を向上させるための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

126

Page 127: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

もう 1 つの制限要因は、ハードウェアのコンパイルが行われる前にすべての 適化が行われることです。性能予測は、ハードウェアコンパイラーが達成する 大動作周波数を正確に捕捉しないことがあります。同様に、リソース駆動型 適化で使用される推定リソース使用率は、実際のハードウェア・リソース使用率を反映しない場合があります。

共有とベクトル化の量には範囲の制限もあります。現在、 大共有度は 8 であり、SIMD ベクタレーンの大数は 16 です。

6.6. HTML レポートのカーネルプロパティとループアンロールステータスの確認

NDRange カーネルをコンパイルすると、 Intel FPGA SDK for OpenCL オフライン・コンパイラーは<your_kernel_filename>/reports/report.html ファイルを生成して、選択されたカーネル・プロパティーとループアンロール・ステータスに関する情報を提供します。

関連情報カーネルの report.html ファイルのレビュー (17 ページ)

6. NDRange カーネルのデータ処理効率を向上させるための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

127

Page 128: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

7. メモリーアクセス効率向上のための戦略

メモリーアクセス効率は、しばしば OpenCL カーネルの全体的なパフォーマンスを左右します。OpenCL コードを開発する際には、グローバル・メモリー・アクセスの回数を 小限に抑えることが有効です。 OpenCL 仕様バージョン 1.0 では、 global メモリー、 constant メモリー、 local メモリー、および private メモリーの 4 種類のメモリータイプが記述されています。

相互接続トポロジーは、共有されたグローバル、定数、およびローカル・メモリー・システムをそれらの基礎となるメモリーに接続します。相互接続はメモリーポートへのアクセスアービトレーションを含みます。

メモリーアクセスは、共有メモリーリソース(つまり、グローバル、ローカル、および定数メモリー)を競合します。 OpenCL カーネルが多数のメモリーアクセスを実行する場合、 Intel FPGA SDK forOpenCL オフライン・コンパイラーはメモリーアクセス要求を処理するための複雑なアービトレーション・ロジックを生成する必要があります。複雑なアービトレーションロジックにより、 大動作周波数(fmax )が低下し、カーネルの性能が低下する可能性があります。

以下のセクションでは、メモリーアクセスの 適化について詳しく説明します。要約すると、グローバル・メモリー・アクセスを 小限にすることは、以下の理由から有益である。

• 一般に、OpenCL カーネルのパフォーマンスが向上すると、グローバルメモリー帯域幅要件が増加します。

• グローバルメモリーの 大帯域幅は、 大ローカルメモリー帯域幅よりもずっと小さくなります。

• FPGA の 大計算帯域幅は、グローバルメモリー帯域幅よりもはるかに大きくなります。

注意: 可能であれば、ローカル、プライベート、または定数メモリーを使用して、カーネルのメモリー帯域幅を増やしてください。

1. メモリーアクセスの 適化に関する一般的なガイドライン (128 ページ)

2. グローバル・メモリー・アクセスの 適化 (129 ページ)

3. 定数、ローカルまたはプライベート・メモリーを使用したカーネル計算の実行 (132 ページ)

4. ローカルメモリーのバンキングによるカーネル・パフォーマンスの向上 (135 ページ)

5. メモリー・レプリケーションファクタの制御によるローカルメモリーへのアクセスの 適化 (138ページ)

6. ループパイプラインのメモリー依存性の 小化 (140 ページ)

7.1. メモリーアクセスの最適化に関する一般的なガイドライン

OpenCL カーネルのメモリーアクセスを 適化すると、カーネル全体のパフォーマンスが向上します。

可能であれば、メモリーアクセスを 適化するための以下の手法を実装することを検討してください。

UG-OCL003 | 2017.12.08

フィードバック

Intel Corporation.無断での引用、転載を禁じます。Intel、インテル、Intel ロゴ、Altera、ARRIA、CYCLONE、ENPIRION、MAX、NIOS、QUARTUS および STRATIX の名称およびロゴは、アメリカ合衆国および/ またはその他の国における Intel Corporationの商標です。インテルは FPGA 製品および半導体製品の性能がインテルの標準保証に準拠することを保証しますが、インテル製品およびサービスは、予告なく変更される場合があります。インテルが書面にて明示的に同意する場合を除き、インテルはここに記載されたアプリケーション、または、いかなる情報、製品、またはサービスの使用によって生じるいっさいの責任を負いません。インテル製品の顧客は、製品またはサービスを購入する前、および、公開済みの情報を信頼する前には、デバイスの仕様を 新のバージョンにしておくことをお勧めします。*その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

ISO9001:2015登録済

Page 129: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

• OpenCL プログラムに一対のカーネルがある場合、一方はデータを生成し、もう一方はそのデータを消費します。両方の機能を実行する単一のカーネルにそれらを変換します。また、元の 2 つのカーネルの関数を論理的に分離するヘルパー関数を実装します。

FPGA の実装は、別々の小さなカーネルに比べて大きなカーネルを優先します。カーネル統一により、他のカーネルで同じデータをフェッチする前に、あるカーネルの結果をグローバルメモリーに一時的に書き込む必要がなくなります。

• Intel FPGA SDK for OpenCL オフライン・コンパイラーは、FPGA のローカルメモリーを GPU とは非常に異なる方法で実装しています。 OpenCL カーネルに GPU 固有のローカル・メモリー・バンクの競合を避けるコードが含まれている場合、オフライン・コンパイラーは可能な限り自動的にローカル・メモリー・バンクの競合を回避するハードウェアを生成するため、そのコードを削除します。

7.2. グローバル・メモリー・アクセスの最適化

Intel FPGA SDK for OpenCL オフライン・コンパイラーはグローバルメモリーとして SDRAM を使用します。デフォルトでは、オフライン・コンパイラーはグローバルメモリーをバースト・インターリーブ構成で構成します。 オフライン・コンパイラーは、グローバルメモリーを各外部メモリーバンクにインターリーブします。

ほとんどの場合、デフォルトのバースト・インターリーブ構成により、メモリーバンク間のロードバランシングが 適化されます。ただし、ロードバランシングを改善するために、2 つのインターリーブされていない(および連続した)メモリーエリアとして手動でバンクを分割することが必要な場合もあります。

下の図は、バースト・インターリーブのメモリー・パーティションとインターリーブされていないメモリー・パーティションのメモリー・マッピング・パターンの違いを示しています。

7. メモリーアクセス効率向上のための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

129

Page 130: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -78: グローバル・メモリー・パーティション

0x7FFF_FFFFAddress

0x7FFF_FC000x7FFF_FBFF

0x7FFF_F800

0x0000_0FFF

0x0000_0C000x0000_0BFF

0x0000_08000x0000_07FF

0x0000_04000x0000_03FF

0x0000_0000

Bank 2

Bank 1

Bank 2

Bank 1

Bank 2

Bank 1

Bank 2

Bank 1

Address0x7FFF_FFFF

0x4000_00000x3FFF_FFFF

0x0000_0000

Burst-Interleaved Separate Partitions

7.2.1. 連続メモリー・アクセス

連続したメモリーアクセスの 適化は、カーネルにおけるグローバルロードおよびストア動作のアクセスパターンを静的に分析します。カーネル呼び出し全体で発生する順次ロードまたはストア動作の場合、 Intel FPGA SDK for OpenCL オフライン・コンパイラーグローバルメモリー内の連続した位置にカーネルがアクセスするように指示します。

次の式を検討してみましょう。

__kernel void sum ( __global const float * restrict a, __global const float * restrict b, __global float * restrict c ){ size_t gid = get_global_id(0);

c[gid] = a[gid] + b[gid];}

アレイ a からのロード動作は、Work-Item のグローバル ID の直接関数であるインデックスを使用します。配列インデックスを Work-Item のグローバル ID に基づいて設定することにより、オフライン・コンパイラーは連続したロード動作を指示できます。これらのロード動作は、入力配列から順番にデータを検索し、必要に応じてパイプラインに読み取ったデータを送ります。次に、連続ストア動作は、計算パイプラインを出る結果の要素をグローバルメモリー内のシーケンシャルな場所に格納します。

7. メモリーアクセス効率向上のための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

130

Page 131: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

ヒント: オフライン・コンパイラーがロード動作に対してより積極的な 適化を実行できるように、読み出し専用グローバルバッファーに const 修飾子を使用します。

次の図は、連続したメモリーアクセス 適化の例を示しています。

図 -79: フラッシュメモリー・アクセス

GlobalMemory

VectorAdditionPipeline

ConsecutiveLoad

ConsecutiveLoad

ConsecutiveStore

a[N-1] a[3] a[2] a[1] a[0]a[5] a[4]a[N-2]

b[N-1] b[3] b[2] b[1] b[0]b[5] b[4]b[N-2]

c[0] c[1] c[3] c[N-2] c[N-1]c[4] c[5]c[2]

連続したロードおよびストア動作は、アクセス速度の向上およびハードウェア・リソースの必要性の低減につながるため、メモリーアクセス効率を向上させます。データは、パイプラインの計算部分に同時に出入りし、計算とメモリーアクセスの間に重複が可能です。可能な場合、グローバルメモリーにアクセスするロードおよびストア動作の連続するメモリー位置をインデックスする Work-ItemID を使用します。グローバルメモリーへの順次アクセスは、理想的なアクセスパターンを提供するため、メモリー効率を向上させます。

7.2.2. グローバルメモリーの手動分割

メモリーを手動で分割して、各バッファーが異なるメモリーバンクを占めるようにすることができます。

グローバルメモリーのデフォルトのバースト・インターリーブ構成では、メモリーアクセスが別のメモリーバンクよりも 1 つの外部メモリーバンクを優先しないようにすることで、負荷の不均衡を防ぎます。ただし、データを手動で分割することで、バッファーグループ全体のメモリー帯域幅を制御することができます。

• Intel FPGA SDK for OpenCL オフライン・コンパイラーは、異なるメモリータイプ間でバースト・インターリーブすることはできません。特定のメモリータイプの各バンクを非インターリーブバンクとして設定するには、OpenCL カーネルを -no-interleaving=<global_memory_type> フラグでコンパイルします。

カーネルが同じサイズの 2 つのバッファーをメモリーにアクセスする場合、負荷間の動的スケジューリングに関係なく、両方のメモリーバンクに同時にデータを分散できます。この 適化手順は、見かけ上のメモリー帯域幅を増加させる可能性があります。

カーネルが異種グローバル・メモリー・タイプにアクセスする場合、aoc コマンドには、手動でパーティション化する各メモリー・タイプの -no-interleaving=<global_memory_type> オプションを組み込みます。

7. メモリーアクセス効率向上のための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

131

Page 132: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

-no-interleaving=<global_memory_type> オプションの使用方法の詳細については、 インテル FPGA SDK for OpenCL プログラミング・ガイドのグローバルメモリー(-no-interleaving=<global_memory_type>)のバーストインターリーブのディセーブルのセクションを参照してください。

関連情報Disabling Burst-Interleaving of Global Memory (-no-interleaving=<global_memory_type>)

7.2.2.1. 異種メモリーバッファー

カーネルは、DDR、QDR、および内蔵 RAM などの複数のグローバル・メモリー・タイプを含む FPGA ボード上で実行できます。

FPGA ボードが異機種グローバル・メモリー・タイプを提供している場合、様々な効率で異なるメモリー・アクセスを処理することに注意してください。

例:

• 長いシーケンシャルアクセスには DDR SDRAM を使用してください。

• ランダムアクセスには QDR SDRAM を使用してください。

• ランダムな低レイテンシーアクセスには内蔵 RAM を使用してください。

グローバルメモリーにバッファーを割り当てる方法と、異機種バッファーを使用するようにホスト・アプリケーションを変更する方法については、 インテル FPGA SDK for OpenCL プログラミング・ガイドのグローバルメモリーのバッファーエリアの指定およびグローバルメモリーの手動パーティショニングのための OpenCL バッファーの割り当てを参照してください。

関連情報• Partitioning Buffers Across Different Memory Types (Heterogeneous Memory)

• Allocating OpenCL Buffer for Manual Partitioning of Global Memory

7.3. 定数、ローカルまたはプライベート・メモリーを使用したカーネル計算の実行

メモリーアクセス効率を 適化するには、 OpenCL カーネルの計算を定数メモリー、ローカルメモリー、またはプライベート・メモリーで実行することによって、グローバル・メモリー・アクセスの数を 小限に抑えます。

グローバル・メモリー・アクセスを 小限に抑えるには、まずグローバルメモリーから定数、ローカル、またはプライベート・メモリーへの計算グループからデータをプリロードする必要があります。プリロードされたデータに対してカーネル計算を実行し、その結果をグローバルメモリーに書き戻します。

7.3.1. キャッシュ・メモリー

コンスタント・メモリーはグローバルメモリー上にありますが、カーネルは実行時にすべてのワークグループが共有するオンチップキャッシュにロードします。たとえば、すべてのワークグループが使用する読み出し専用データがあり、定数バッファーのデータサイズが定数キャッシュに収まる場合、データを定数メモリーに割り当てます。定数キャッシュは、カーネルのいくつかの呼び出しで一定の高帯域幅のテーブル検索に も適しています。定数キャッシュは、高いキャッシュヒット性能のために 適化されています。

7. メモリーアクセス効率向上のための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

132

Page 133: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

デフォルトでは、定数キャッシュサイズは 16 KB です。定数キャッシュサイズを指定するには、-const-cache-bytes = <N>aoc コマンドのオプション<N>バイト単位の一定のキャッシュサイズです。

長いメモリーレイテンシーを許容するための余分なハードウェアを持つグローバル・メモリー・アクセスとは異なり、定数キャッシュはキャッシュミスに対して大きなパフォーマンス上の不利益を被ります。OpenCL カーネルコードの__constant 引数がキャッシュに収まらない場合、代わりに__globalconst 引数を使用するとパフォーマンスが向上する可能性があります。ホスト・アプリケーションが定数キャッシュに既にロードされている定数メモリーに書き込む場合、キャッシュされたデータは定数キャッシュから破棄されます(つまり、無効化される)。

-const-cache-bytes=<N> のオプションについて詳しくは インテル FPGA SDK forOpenCL プログラミング・ガイドの定数メモリーキャッシュサイズの設定 (-const-cache-bytes=<N>)のセクションを参照してください。

関連情報Configuring Constant Memory Cache Size (-const-cache-bytes=<N>)

7.3.2. ローカルメモリーへのデータの事前ロード

ローカルメモリーはグローバルメモリーよりもかなり小さいですが、スループットが大幅に向上し、レイテンシーが大幅に減少します。グローバル・メモリー・アクセスとは異なり、カーネルはパフォーマンス上のペナルティーなしにランダムにローカルメモリーにアクセスできます。 カーネルコードを構造化するときは、グローバルメモリーに順番にアクセスし、そのデータをオンチップローカルメモリーにバッファーリングしてからカーネルが計算に使用します。

Intel FPGA SDK for OpenCL オフライン・コンパイラーは、FPGA のオンチップメモリーブロックにOpenCL ローカルメモリーを実装しています。オンチップメモリーブロックには 2 つの読み出しポートと書き込みポートがあり、OpenCL カーネルの動作周波数の 2 倍の動作周波数でクロックすることができます。このクロック周波数を 2 倍にすることで、メモリーを二重ポンプ」にすることができ、同じメモリーから 2 倍の帯域幅が得られます。その結果、各オンチップメモリーブロックは 大 4 つの同時アクセスをサポートします。

理想的には、各バンクへのアクセスは、バンクのオンチップメモリーブロックにわたって均一に分散される。 1 クロックサイクルでオンチップメモリーブロックへの同時アクセスは 4 回しかできないため、アクセスを分散することでバンクの競合を回避できます。

このバンキング設定は通常有効です。ただし、オフライン・コンパイラーは、多数のバンクに対応するために複雑なメモリーシステムを作成する必要があります。多数のバンクが調停ネットワークを複雑にし、システム全体のパフォーマンスを低下させる可能性があります。

オフライン・コンパイラーは FPGA のオンチップメモリーブロックにあるローカルメモリーを実装するため、オフライン・コンパイラーはコンパイル時にローカル・メモリー・システムのサイズを選択する必要があります。オフライン・コンパイラーがローカル・メモリー・システムのサイズを決定する方法は、OpenCLコードで使用されるローカルデータ型によって異なります。

7. メモリーアクセス効率向上のための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

133

Page 134: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

ローカルメモリーアクセスの最適化

ローカルメモリーアクセスの効率を 適化するには、次のガイドラインを考慮してください。

• ループアンローリングなどの特定の 適化手法を実装すると、より多くの同時メモリーアクセスが発生する可能性があります。

注意: メモリーアクセスの数を増やすと、メモリーシステムが複雑になり、パフォーマンスが低下する可能性があります。

• 可能であれば、カーネル内の固有のローカルメモリーアクセス数を 4 以下に制限することで、ローカルメモリーサブシステムを単純化してください。

ローカル・メモリー・システムへのメモリーアクセスが 4 つ以下の場合、 大のローカルメモリーパフォーマンスを達成します。特定のメモリーシステムへのアクセス回数が 4 より大きい場合、オフライン・コンパイラーは、メモリーシステムのオンチップメモリーブロックをバンク構成に配置します。

• 関数スコープのローカルデータがある場合、オフライン・コンパイラーは、コンパイル時に関数本体内で定義したローカルデータの静的なサイズを指定します。ローカルメモリーを定義するには、オフライン・コンパイラーにメモリーを必要なサイズに設定し、2 の累乗に も近い値に切り上げます。

• __local カーネル引数を指すポインターの場合、ホストは clSetKernelArg 呼び出しによって実行時に動的にメモリーサイズを割り当てます。ただし、オフライン・コンパイラーはコンパイル時にこれらの物理メモリーサイズを設定する必要があります。

デフォルトでは、 __local カーネル引数のポインターは 16 KB です。割り当てサイズは、ポインター宣言に local_mem_size 属性を含めることで指定できます。

注意:

clSetKernelArg 呼び出しは、コンパイル時に物理的に割り振られたデータサイズよりも小さいデータサイズを要求できますが、決してそれより大きいサイズにはなりません。

• ローカルメモリーにアクセスする場合、可能な限り単純なアドレス計算を使用し、必須ではないポインター演算を避けてください。

インテル は、オフライン・コンパイラーが静的コード解析を通じてアクセスパターンをより確実に保証できるようにすることにより、FPGA リソースの使用率を削減し、ローカルメモリー効率を向上させるために、このコーディング・スタイルを推奨しています。複雑なアドレス計算とポインター演算を使用すると、オフライン・コンパイラーがデータの異なる部分を表す独立したメモリーシステムを作成するのを防ぐことができ、エリア使用量が増加し、実行時パフォーマンスが低下します。

• 可能であれば、メモリーへのポインターの格納は避けてください。記憶されたポインターは、しばしばポインターがメモリーから引き出されたときに、アクセスされたデータセットを静的なコンパイラー分析が決定することを防止します。メモリーへのポインターの格納は、ほとんど常に 適ではないエリアとパフォーマンスの結果につながります。

local_mem_size 属性の使用法については、 インテル FPGA SDK for OpenCL プログラミング・ガイドのローカルメモリーのポインターサイズの指定を参照してください。

関連情報Programming Strategies for Optimizing Local Memory Efficiency

7.3.3. プライベート・メモリーに変数と配列の格納

Intel FPGA SDK for OpenCL オフライン・コンパイラーは、FPGA レジスターまたはブロック RAM を使用してプライベート・メモリーを実装します。オフライン・コンパイラーは、プライベート・メモリーアクセスを分析し、アクセスをレジスターするようにそれらを促進します。 float、int、char などのスカラー変数は主にプロモートされます。アクセスがコンパイル時定数である場合、集計データ型がプロモートされま

7. メモリーアクセス効率向上のための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

134

Page 135: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

す。通常、プライベート・メモリーは、単一変数または小さな配列を格納するのに便利です。レジスターはFPGA のハードウェア・リソースが豊富であり、可能な限り他のメモリータイプではなくプライベート・メモリーを使用する方がほぼ常に優れています。カーネルはプライベート・メモリーに並行してアクセスすることができ、他のメモリータイプ(すなわち、グローバルメモリー、ローカルメモリー、定数メモリー)より多くの帯域幅を提供することができます。

レジスターを使用したプライベート・メモリーの実装の詳細については、 インテル FPGA SDK forOpenCL プログラミング・ガイドのレジスターの推論のセクションを参照してください。

関連情報Inferring a Register

7.4. ローカルメモリーのバンキングによるカーネル・パフォーマンスの向上

numbanks( N )および bankwidth( M )の高度なカーネル属性を指定すると、並列メモリーアクセス用にローカル・メモリー・バンクを構成できます。これらの高度なカーネル属性によって記述されたバンキングジオメトリは、カーネルがローカル・メモリー・システムのどの要素を並列にアクセスできるかを決定します。

次のコード例は、単一のバンクに実装された 8 x 4 ローカル・メモリー・システムを示しています。その結果、システム内の 2 つの要素に並列にアクセスすることはできません。

local int lmem[8][4];

#pragma unrollfor(int i = 0; i<4; i+=2) { lmem[i][x] = …; }

図 -80: 8 x 4 ローカル・メモリー・システムへのシリアルアクセス

0,1

2,32,22,12,0

1,31,21,11,0

0,30,20,0

3,33,23,13,0

4,34,24,14,0

5,35,25,15,0

6,36,26,16,0

7,37,27,17,0

local int lmem[8][4]

serial access

7. メモリーアクセス効率向上のための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

135

Page 136: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

パフォーマンスを向上させるために、 numbanks( N )と bankwidth( M )をコードに追加して、メモリーバンクの数とバンク幅をバイト単位で定義することができます。次のコードは、それぞれ 16 バイト幅の 8 つのメモリーバンクを実装しています。このメモリーバンク構成により、8×4 アレイのパラレルメモリーアクセスが可能になります。

local int __attribute__((numbanks(8), bankwidth(16))) lmem[8][4]; #pragma unrollfor (int i = 0; i < 4; i+=2) { lmem[i][x & 0x3] = …; }

注意: パラレルアクセスをイネーブルするには、下位の配列インデックスの動的アクセスをマスクする必要があります。下位の配列インデックスに動的アクセスをマスクすると、 Intel FPGA SDK for OpenCL オフライン・コンパイラー x はインデックスの下限を超えません。

図 -81: 16 バイト幅の 8 つのメモリーバンクを備えた 8×4 ローカル・メモリー・システムへの並列アクセス

0,1

2,32,22,12,0

1,31,21,11,0

0,30,20,0

3,33,23,13,0

4,34,24,14,0

5,35,25,15,0

6,36,26,16,0

7,37,27,17,0

local int lmem[8][4]

parallel access Bank 0

Bank 1

Bank 2

Bank 3

Bank 4

Bank 5

Bank 6

Bank 7

numbanks( N )および bankwidth( M )カーネル属性に異なる値を指定することで、パラレル・アクセス・パターンを変更できます。次のコードは、それぞれ 4 バイト幅の 4 つのメモリーバンクを実装しています。このメモリーバンク構成は、8×4 アレイ全体にわたる並列メモリーアクセスをイネーブルします。

local int __attribute__((numbanks(4), bankwidth(4))) lmem[8][4];

#pragma unrollfor (int i = 0; i < 4; i+=2) { lmem[x][i] = …; }

7. メモリーアクセス効率向上のための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

136

Page 137: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

図 -82: 4 つの 4 バイト幅のメモリーバンクを備えた 8×4 ローカル・メモリー・システムへの並列アクセス

0,1

2,32,22,12,0

1,31,21,11,0

0,30,20,0

3,33,23,13,0

4,34,24,14,0

5,35,25,15,0

6,36,26,16,0

7,37,27,17,0

local int lmem[8][4]

Bank 0

Bank 1

Bank 2

Bank 3

parallelaccess

7.4.1. アレイインデックスに基づくローカル・メモリー・バンクの幾何学的構成の最適化

デフォルトでは、 Intel FPGA SDK for OpenCL オフライン・コンパイラーは、ローカル・メモリー・システムを自動的にバンキングすることでパフォーマンスを向上させる可能性があります。 インテル FPGASDK for OpenCL は、ローカル・メモリー・システムのバンキングジオメトリをカスタマイズできる高度な機能が含まれています。 ローカル・メモリー・バンクのジオメトリを設定するには、OpenCL カーネルに numbanks( N )および bankwidth( M )カーネル属性を含めます。

次のコード例は、 numbanks および bankwidth に割り当てた値に基づいて、バンクのジオメトリがどのように変化するかを示しています。

表 11. 2×4 ローカル・メモリー・システムのバンクジオメトリに対するバンク数とバンク数の影響この表の 初と 後の行は、2D 配列の上下のインデックスにメモリーをバンクする方法を示しています。

コードの例 バンクの幾何学

local int__attribute__((numbanks(2), bankwidth(16))) lmem[2][4];

0,0 0,1 0,2 0,3

1,0 1,1 1,2 1,3

lmem

Bank 0

Bank 1

continued...

7. メモリーアクセス効率向上のための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

137

Page 138: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

コードの例 バンクの幾何学

local int __attribute__((numbanks(2), bankwidth(8))) lmem[2][4];

0,0 0,1 0,2 0,3

1,0 1,1 1,2 1,3

lmem

Bank 0

Bank 1

local int __attribute__((numbanks(2), bankwidth(4))) lmem[2][4];

0,0 0,1 0,2 0,3

1,0 1,1 1,2 1,3

lmem

Bank 0

Bank 1

local int __attribute__((numbanks(4), bankwidth(8))) lmem[2][4]; 0,0 0,1 0,2 0,3

1,0 1,1 1,2 1,3

lmem

Bank 0

Bank 1

Bank 2

Bank 3

local int__attribute__((numbanks(4), bankwidth(4))) lmem[2][4]; 0,0 0,1 0,2 0,3

1,0 1,1 1,2 1,3

lmem

Bank 0

Bank 1

Bank 2

Bank 3

関連情報Kernel Attributes for Configuring Local Memory System

7.5. メモリー・レプリケーションファクタの制御によるローカルメモリーへのアクセスの最適化

メモリー複製率は、デザインがローカル・メモリー・システムを実装するために使用する M20K メモリーブロックの数です。 メモリー複製因子を制御するには、お使いの OpenCL カーネル™の singlepumpまたは doublepump カーネル属性が含まれます。 singlepump と doublepump のカーネル属性は インテル FPGA SDK for OpenCL の高度な機能一部です。

インテル M20K メモリーブロックには 2 つの physical ポートがあります。各 M20K ブロックで使用できる論理ポートの数は、ポンピングの程度によって異なります。ポンピングは、他のデザインと比較してM20K ブロックのクロック周波数の尺度です。

7. メモリーアクセス効率向上のための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

138

Page 139: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

カーネルがローカル・メモリー・システム lmem のための 3 つの読み出しポートと 1 つの書き込みポートを指定するデザイン例を検討してください。以下のコード例に示すように、ローカル変数宣言のsinglepump カーネル属性を含めて、M20K ブロックは残りのデザインと同じ頻度で実行されます。

int __attribute__((memory, numbanks(1), bankwidth(64), singlepump, numreadports(3), numwriteports(1))) lmem[16];

図 -83: シングルポンプ M20K メモリーブロックへのアクセス

M20K

M20K

M20K

read_0

read_1

read_2

write

lmem

各シングルポンプ M20K ブロックには 2 つの logica ポートがあります。ローカル・メモリー・システムの各書き込みポートは、デザインがメモリーシステムを実装するために使用するすべての M20K ブロックに接続する必要があります。ローカル・メモリー・システムの各読み出しポートは、1 つの M20K ブロックに接続する必要があります。これらの接続の制約のため、 lmem に指定されたポート数を実装するには、3 つの M20K ブロックが必要です 。

ローカル変数宣言に doublepump カーネル属性を含める場合、残りのデザインと同じ頻度で M20Kメモリーブロックを実行するように指定します。

int __attribute__((memory, numbanks(1), bankwidth(64), doublepump, numreadports(3), numwriteports(1))) lmem[16];

図 -84: ダブルポンピングされた M20K メモリーブロックへのアクセス

M20K

read_0read_1read_2write

lmem

7. メモリーアクセス効率向上のための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

139

Page 140: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

各ダブルポンプ M20K ブロックには 4 つの論理ポートがあります。そのため、3 つの読み出しポートと1 つの書き込みポートをすべて lmem に実装するには、1 つの M20K ブロックが必要です 。

注意: • メモリーをダブルポンピングすると、リソースのオーバーヘッドが増加します。実際に M20K を節約したり、パフォーマンスを向上させたり、その両方を達成した場合にのみ、 doublepump カーネル属性を使用してください。

• ストアはすべてのレプリケートに接続されている必要があり、競合に遭ってはいけません。したがって、ストアが 3 つ以上ある場合、メモリーは複製されません。ローカルメモリー・レプリケーションは、単一のストアでうまく動作します。

• メモリーシステム全体が複製されるため、潜在的に大きな M20K メモリーブロックが観察されることがあります。

関連情報Kernel Attributes for Configuring Local Memory System

7.6. ループパイプラインのメモリー依存性の最小化

インテル FPGA SDK for OpenCL Offline Compiler は、同じスレッドからのメモリーアクセスがプログラムの命令に従うことを保証します。 NDRange カーネルをコンパイルするときは、障壁を使用して同じワークグループ内のスレッド間でメモリーアクセスを同期させます。

ループの依存関係は、メモリーアクセスに関連するレイテンシーのために Single Work-Item カーネルにボトルネックを招く可能性があります。オフライン・コンパイラーは、依存メモリー動作が完了するまでメモリー動作を延期します。これは、ループ開始間隔(II)に影響を与える可能性があります。オフライン・コンパイラーは、 適化レポートのメモリー依存性を示します。

ループパイプライニングのメモリー依存性の影響を 小限に抑えるには:

• オフライン・コンパイラーが誤った依存関係を想定していないことを確認します。

スタティック・メモリー依存分析が依存関係が存在しないことを証明できない場合、オフライン・コンパイラーは依存関係が存在するとみなし、依存関係を強制するようにカーネル実行を変更します。メモリーシステムがストールフリーであれば、依存関係の影響は小さくなります。

— ロード・ストア・ユニットに対するデータ依存性を伴う読出し動作後の書込みは、わずか 2 クロック・サイクル(II = 2)が必要です。他のストールフリーのシナリオでは、 大 7 クロックサイクルかかることがあります。

— 読み出し後書き込み(制御依存)動作は、オフライン・コンパイラーによって完全に解決できます。

• 依存関係がないと確信できる場合、カーネルコードのループの前に#pragma ivdep 行を追加してスタティック・メモリー依存解析を無効にします。

7. メモリーアクセス効率向上のための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

140

Page 141: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

8. FPGA エリアの最適化のための戦略

OpenCL カーネルが異なるサイズの FPGA 上で実行可能な場合、エリアの使用は重要なデザイン上の考慮事項です。 OpenCL アプリケーションをデザインするときは、 インテル は、ハードウェアエリアの使用を 適化するための特定のデザイン戦略を実行することを推奨します。

カーネルのパフォーマンスを 適化するには、通常、追加の FPGA リソースが必要です。これとは対照的に、エリアの 適化はパフォーマンスの低下を招くことがあります。カーネル 適化の間、 インテル は、

適なサイズとパフォーマンスのトレードオフを生成するカーネル・プログラミング戦略を決定するために、FPGA ボード上で複数のバージョンのカーネルを実行することを推奨します。

8.1. コンパイルに関する考慮事項

カーネルのコンパイル中にエリアの使用状況を分析するように Intel FPGA SDK for OpenCL オフライン・コンパイラーに指示することができます。

1. 画面上の推定資源使用量の要約を確認するには、 aoc コマンドに-report フラグを含めてカーネルをコンパイルします。カーネル固有のエリア使用量の情報を確認するには、<your_kernel_filename> /reports/report.html ファイル。

2. 可能であれば、 aoc コマンドの-fpc または-fp-relaxed オプションを使用して OpenCL カーネルをコンパイルし、浮動小数点計算を実行します。

-report 、 -fp-relaxed および-fpc オプションの詳細な使用方法については、 見積もりリソース使用量の要約を表示する(-report)」 、 浮動小数点演算の順序を緩和する(-fp-relaxed)」 、および浮動小数点数を減らす動作(-fpc)のセクション インテル FPGA SDK for OpenCL プログラミング・ガイド

浮動小数点演算の詳細については、浮動小数点演算の 適化を参照してください。

関連情報• HTML レポート:エリア・レポート・メッセージ (41 ページ)

• Displaying the Estimated Resource Usage Summary On-Screen (-report)

• Relaxing the Order of Floating-Point Operations (-fp-relaxed)

• Reducing Floating-Point Rounding Operations (-fpc)

• 浮動小数点演算の 適化 (78 ページ)

8.2. ボードバリアントの選択に関する考慮事項

カスタム・プラットフォームで必要な外部接続リソースのみを提供するボードバリアントをターゲットにします。

UG-OCL003 | 2017.12.08

フィードバック

Intel Corporation.無断での引用、転載を禁じます。Intel、インテル、Intel ロゴ、Altera、ARRIA、CYCLONE、ENPIRION、MAX、NIOS、QUARTUS および STRATIX の名称およびロゴは、アメリカ合衆国および/ またはその他の国における Intel Corporationの商標です。インテルは FPGA 製品および半導体製品の性能がインテルの標準保証に準拠することを保証しますが、インテル製品およびサービスは、予告なく変更される場合があります。インテルが書面にて明示的に同意する場合を除き、インテルはここに記載されたアプリケーション、または、いかなる情報、製品、またはサービスの使用によって生じるいっさいの責任を負いません。インテル製品の顧客は、製品またはサービスを購入する前、および、公開済みの情報を信頼する前には、デバイスの仕様を 新のバージョンにしておくことをお勧めします。*その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

ISO9001:2015登録済

Page 142: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

たとえば、カーネルに 1 つの外部メモリーバンクが必要な場合、単一の外部メモリーバンクのみをサポートするボードバリアントをターゲットにします。複数の外部メモリーバンクを持つボードをターゲットにすると、カーネルのエリア使用量が不必要に増加します。

カスタム・プラットフォームでニーズに合ったボード・バリエーションが提供されない場合、ボード・バリエーションの作成を検討してください。詳細については、 カスタム・プラットフォームツールキットユーザーガイドを参照してください。

関連情報Intel FPGA SDK for OpenCL カスタム・プラットフォーム・ツールキットのユーザーガイド

8.3. メモリーアクセスに関する考慮事項

インテル メモリーアクセス効率を向上させ、 OpenCL カーネルのエリア使用を削減するカーネル・プログラミング戦略を推奨しています。

1. 外部メモリーへのアクセスポイントの数を 小限に抑えます。

可能であれば、ある場所から入力を読み出し、内部的にデータを処理し、出力を別の場所に書き込むようにカーネルを構造化します。

2. ローカルまたはグローバル・メモリー・アクセスに頼るのではなく、可能であればシフトレジスター推論を使ってカーネルを Single Work-Item として構造化してください。

3. 外部メモリーにデータを書き込むカーネルと外部メモリーからデータを読み込むカーネルを作成する代わりに、直接データ転送のためにカーネル間に インテル FPGA SDK for OpenCL チャネル拡張を実装します。

4. OpenCL アプリケーションは、多くの独立した定数データアクセスが含まれている場合、代わりに__global const の__constant 使用して対応するポインターを宣言します。 __globalconst を使用する宣言は、ロードまたはストア動作ごとにプライベート・キャッシュを作成します。一方、 __constant を使用した宣言では、単一の定数キャッシュがチップ上にのみ作成されます。

注意:

カーネルが Cyclone® V デバイス(たとえば、Cyclone V SoC)をターゲットにしている場合、 __constant ポインターカーネル引数を宣言すると、FPGA のパフォーマンスが低下する可能性があります。

5. カーネルが少数の定数引数を渡した場合、それらをグローバルメモリーへのポインターではなく値として渡します。

例えば、代わり* COEF __constant INT を通過した後、10 にインデックス 0 を有するCOEF を間接参照の値(INT16 の COEF)として COEF を渡します。 coef が__constant ポインターの唯一の引数だった場合、それを値として渡すと、定数キャッシュとそれに対応するロードとストア動作が完全に削除されます。

6. パイプライン・ループ内で大規模なシフトレジスターを条件付きでシフトすると、効率の悪いハードウェアが作成されます。たとえば、 if(K> 5)条件が存在する場合 、次のカーネルはより多くのリソースを消費します。

#define SHIFT_REG_LEN 1024__kernel void bad_shift_reg (__global int * restrict src, __global int * restrict dst, int K){ float shift_reg[SHIFT_REG_LEN]; int sum = 0; for (unsigned i = 0; i < K; i++)

8. FPGA エリアの最適化のための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

142

Page 143: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

{ sum += shift_reg[0]; shift_reg[SHIFT_REG_LEN-1] = src[i];

// This condition will cause sever area bloat. if (K > 5) { #pragma unroll for (int m = 0; m < SHIFT_REG_LEN-1 ; m++) { shift_reg[m] = shift_reg[m + 1]; } } dst[i] = sum; }}

注意:

条件付きでシフトレジスターにアクセスしても、ハードウェアの効率は低下しません。 カーネルに大きなシフトレジスターの条件付きシフトを実装する必要がある場合は、ローカルメモリーを使用するようにコードを変更することを検討してください。

8.4. 算術演算の考慮事項

過剰な FPGA エリアの使用を避けるために、 OpenCL アプリケーションに適切な算術演算を選択してください。

1. 必要なときにだけ浮動小数点演算を導入します。

2. Intel FPGA SDK for OpenCL オフライン・コンパイラーは、浮動小数点定数はデータ型を 2 倍にするようにデフォルト設定されています。 f 指定を定数に追加して、単精度浮動小数点演算にします。

例えば、算術演算 sin(1.0)は、倍精度浮動小数点サイン関数を表します。算術演算 sin(1.0f)は、単精度浮動小数点正弦関数を表します。

3. 複雑な関数に対して完全精度の結果を必要としない場合、より簡単な算術演算を計算して結果を近似します。以下のシナリオ例を検討してください。

a. 関数 pow(x、n)を計算する代わりに、 n が小さい値の場合、ハードウェア・リソースと面積が大幅に少なくて済むので、繰り返し二乗演算を実行して結果を近似します。

b. 近似を使用して結果を計算すると、エリアの使用量が過剰になることがあるため、元のエリアと近似されたエリアの使用を認識していることを確認してください。たとえば、 sqrt 関数はリソースを消費しません。大まかな近似以外に、実行時にホストが計算しなければならない算術演算で sqrt 関数を置き換えると、エリアの使用量が大きくなる可能性があります。

c. 少数の入力値で作業する場合、代わりに LUT を使用することを検討してください。

4. コンパイル時にオフライン・コンパイラーが計算する定数(たとえば log(PI/2.0) )を使用してカーネルが複雑な算術演算を実行する場合、代わりにホスト上で算術演算を実行し、ランタイムでその結果を引数としてカーネルに渡します。

8.5. データ型の選択に関する考慮事項

適切なデータ型を選択して、 OpenCL アプリケーションによる FPGA エリアの使用を 適化します。

1. アプリケーションに 適なデータ型を選択します。

たとえば、データ型 short が十分な場合、変数を float として定義しないでください。

2. 算術式の両側が同じデータ型に属していることを確認してください。

8. FPGA エリアの最適化のための戦略UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

143

Page 144: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

算術式の一方の側が浮動小数点値で、もう一方の側が整数である例を検討してください。一致しないデータ型は、 Intel FPGA SDK for OpenCL オフライン・コンパイラーが暗黙的な変換演算子を作成します。変換演算子は、多数存在する場合は高価になります。

3. パディングがデータ構造内に存在する場合、パディングを使用します。

たとえば、 float4 と同じサイズの float3 データ型のみが必要な場合、データ型を float4に変更して、余分なディメンションを使用して関連のない値を使用することができます。

8. FPGA エリアの最適化のための戦略UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

144

Page 145: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

A. 追加情報

デモンストレーションとトレーニング・オプションについて詳しくは、 インテル FPGA SDK forOpenCL 製品ページを参照してください。

関連情報Intel FPGA SDK for OpenCL FPGA のプラットフォーム・ページ

A.1. 改訂履歴

表 12. 改訂履歴:スタート・ガイド

日付 バージョン 変更内容

2017 年 12 月 2017.12.08 • 以下の新しいトピックが追加されました:— Autorun Captures タブ (90 ページ)— 自動プロファイラーデータ (98 ページ)

2017 年 11 月 2017.11.06 • すべてのトピックを個々の章に移動。• トピックのタイトルの一部をタスクベースのタイトルに変更。• Fmax のすべての出現箇所を fmax に変更。• ストール、占有、帯域幅 (91 ページ)に新しい短い説明を追加。• ページ 15 への説明とともに、並列スレッドとループ・パイプライン処理の比較を示す新しい画像

を追加。• FPGA 概要 (5 ページ)での説明とともに FPGA アーキテクチャを追加た。• ループパイプラインのメモリー依存性の 小化 (140 ページ)を追加。• エリア情報の確認 (28 ページ)にエリアレポート階層の詳細を追加。• チャネルとパイプのベスト・プラクティス (75 ページ)を追加。• アラインメントされたメモリーの割り当て (80 ページ)を更新。• loop_coalesce を使用してネストループによって消費されるエリアの削減 (27 ページ)を追

加。• メモリー・アクセス・パターンの例の変更 (23 ページ)を追加。• イメージページ 101 を更新。• 以下のトピックでは、aoc コマンドに対して単一ダッシュと-option=<value>の規則を実

装。— ページ 101— 浮動小数点演算の 適化 (78 ページ)— グローバルメモリーの手動分割 (131 ページ)— キャッシュ・メモリー (132 ページ)— コンパイルに関する考慮事項 (141 ページ)— 高い失業率と高い占有率 (96 ページ)

• シングル・ワーク・アイテム・カーネル対 NDRange カーネル (9 ページ)では、— デザインのための単一作業項目カーネルを作成するための基準を削除。— 新しいサンプルコードと関連説明を追加。— 単一作業項目の実行に関するサブトピックを削除し、その内容をこのトピックとマージ。

continued...

UG-OCL003 | 2017.12.08

フィードバック

Intel Corporation.無断での引用、転載を禁じます。Intel、インテル、Intel ロゴ、Altera、ARRIA、CYCLONE、ENPIRION、MAX、NIOS、QUARTUS および STRATIX の名称およびロゴは、アメリカ合衆国および/ またはその他の国における Intel Corporationの商標です。インテルは FPGA 製品および半導体製品の性能がインテルの標準保証に準拠することを保証しますが、インテル製品およびサービスは、予告なく変更される場合があります。インテルが書面にて明示的に同意する場合を除き、インテルはここに記載されたアプリケーション、または、いかなる情報、製品、またはサービスの使用によって生じるいっさいの責任を負いません。インテル製品の顧客は、製品またはサービスを購入する前、および、公開済みの情報を信頼する前には、デバイスの仕様を 新のバージョンにしておくことをお勧めします。*その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

ISO9001:2015登録済

Page 146: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

日付 バージョン 変更内容

2017 年 5 月 2017.05.08 • コード例の一部の関数を次のように書き換え。— read_channel_altera から read_channel_intel に— write_channel_altera から write_channel_intel に— read_channel_nb_altera から read_channel_nb_intel に— write_channel_nb_altera から write_channel_nb_intel に

• ロード・ストア・ユニット (66 ページ)を追加。• Report Summary のレビュー 、 (19 ページ)を追加。• Kernel Memory Viewer の特長 (33 ページ)を追加。

2016 年 12 月 2016.12.02 微細な編集上の更新。

2016 年 10 月 2016.10.31 • Altera SDK for OpenCL を インテル FPGA SDK for OpenCL に変更 。• Altera Offline Compiler を Intel FPGA SDK for OpenCL オフライン・コンパイラーに変

更 。• Align a Struct with or without Padding では、構造体宣言に関する属性の配置を修正する

ようにコードスニペットを修正。• トピック Review Your Kernel's report.html File を追加し、HTML GUI を説明するサブト

ピック、GUI が提供するさまざまなレポート、および HTML レポートの情報を活用して OpenCLデザイン例を 適化する方法についてのチュートリアルを追加しました。

•• カーネルのサブトピック、グローバルメモリーインターコネクト、ローカルメモリー、ネストルー

プ、単一作業項目カーネル内のループ、およびチャネルが含まれるトピック HTML Report:Kernel Design Concepts を追加。

• 情報が HTML レポートの一部になったため、Optimization Report セクションと関連するサブセクションを削除しました。

2016 年 5 月 2016.05.02 • ivdep プラグマを紹介するために、トピック Removing Loop-Carried DependenciesCaused by Accesses to Memory Arrays を追加。

• Strategies for Improving Memory Access Efficiency の下で、numbanks とbankwidth カーネル属性を使用してローカルメモリシステムのジオメトリを設定する方法を説明するために、以下のトピックを追加。— Improve Kernel Performance by Banking the Local Memory— Optimize the Geometric Configuration of Local Memory Banks Based on

Array Index• Strategies for Improving Memory Access Efficiency の下に、singlepump および

doublepump カーネル属性の使用法を説明するためのトピック Optimize Accesses toLocal Memory by Controlling the Memory Replication Factor を追加。

•• 拡張 適化レポートのメッセージを含むために Addressing Single Work-Item Kernel

Dependencies Based on Optimization Report Feedback の下のサブセクションを更新。

• リソース使用量を確認するために拡張エリアレポートにアクセスする手順を含むために図Optimization Work Flow for a Single Work-Item Kernel を更新。

• Strategies for Improving NDRange Kernel Data Processing Efficiency の下に、Review Kernel Properties and Loop Unroll Status in the Optimization Report セクションを追加。

2015 年 11 月 2015.11.02 • トピック Multi-Threaded Host Application を追加。• Specify a Maximum Work-Group Size or a Required Work-Group Size のメモリー

バリアに関する注意書きを追加しました。continued...

A. 追加情報UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

146

Page 147: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

日付 バージョン 変更内容

2015 年 5 月 15.0.0 • Memory Access Considerations では、Cyclone V デバイスをターゲットとするカーネルで__constant ポインタ引数を宣言するときに発生する可能性があるパフォーマンス低下に関する注意書きを追加。

• Good Design Practices for Single Work-Item Kernel では、Initialize Data Prior toUsage in a Loop セクションを削除し、Declare Variables in the Deepest ScopePossible セクションを追加。

• Removing Loop-Carried Dependency by Inferring Shift Registers を追加。このトピックでは、単一の作業項目カーネルで、シフトレジスターとして倍精度浮動小数点配列を推論することで、ループキャリー依存関係を除去する方法について説明します。

•• Data Type Considerations から Data Type Selection Considerations に変更。

2014 年 12 月 14.1.0 • .レポートメッセージと 適化レポートのレイアウトを更新するために Optimization ReportMessages セクションの情報フローを再編成。

• 失敗した 適以下のパイプライン実行の理由を詳述する新しい 適化レポートメッセージが含まれています。

• Added the Optimization Report Messages for Simplified Analysis of a ComplexDesign subsection under Optimization Report Messages to describe new reportmessage for simplified kernel analysis. 単純化されたカーネル分析のための新しいレポートメッセージを記述するために Optimization Report Messages の下に OptimizationReport Messages for Simplified Analysis of a Complex Design サブセクションを追加。

• Using Feedback from the Optimization Report to Address Single Work-ItemKernels Dependencies を Addressing Single Work-Item Kernel DependenciesBased on Optimization Report Feedback に変更。

• ループ運搬依存関係を解決するための新しい戦略を説明するために Addressing SingleWork-Item Kernel Dependencies Based on Optimization Report Feedback の下にTransferring Loop-Carried Dependency to Local Memory サブセクションを追加。

2014 年 6 月 14.0.0 • 文書の名前を インテル FPGA SDK for OpenCL ベスト・プラクティス・ガイドに変更。• インフォメーション・フローの再編。• Good Design Practices から Good OpenCL Kernel Design Practices に変更。• Transfer data via offline compilerL Channels にチャンネル情報を追加。• Profile Your Kernel to Identify Performance Bottlenecks にプロファイラー情報を追

加。• Single Work-Item Kernel Versus NDRange Kernel セクションを追加。• Single Work-Item Execution セクションを変更。• Performance Warning Messages セクションを削除。• Single Work-Item Kernel Programming Considerations から Good Design

Practices for Single Work-Item Kernel に変更。

2013 年 12 月 13.1.1 • Specify a Maximum Work-Group Size or a Required Work-Group Size セクションを変更。

• Heterogeneous Memory Buffers セクションを追加。• Single Work-Item Execution セクションを変更。• Performance Warning Messages セクションを追加。• Single Work-Item Kernel Programming Considerations セクションを変更。

2013 年 11 月 13.1.0 • インフォメーション・フローの再編。• インテル FPGA SDK for OpenCL Compilation Flow セクションを変更。• Pipelines; inserted the figure Example Multistage Pipeline Diagram セクションを変

更continued...

A. 追加情報UG-OCL003 | 2017.12.08

フィードバック Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド

147

Page 148: Intel FPGA SDK for OpenCL...Intel® FPGA SDK for OpenCL ベスト・プラクティス・ガイド インテル ® Quartus Prime開発デザインスイートの更新情報: 17.1

日付 バージョン 変更内容

• 次の図を削除。— Instruction Flow through a Five-Stage Pipeline Processor.— Vector Addition Kernel Compiled to an FPGA.— Effect of Kernel Vectorization on Array Summation.— Data Flow Implementation of a Four-Element Accumulation Kernel.— Data Flow Implementation of a Four-Element Accumulation Kernel with Loop

Unrolled.— Complete Loop Unrolling.— Unrolling Two Loop Iterations.— Memory Master Interconnect.— Local Memory Read and Write Ports.— Local Memory Configuration.

• Good Design Practices セクションを変更。• 次のセクションを削除。

— Predicated Execution.— Throughput Analysis.— Case Studies.

• Optimizing Data Processing Efficiency から Optimization of Data ProcessingEfficiency に変更。

• Replicating Compute Units versus Kernel SIMD Vectorization から Compute UnitReplication versus Kernel SIMD Vectorization に変更。

• Using num_compute_units and num_simd_work_items Together からCombination of Compute Unit Replication and Kernel SIMD Vectorization に変更。

• Memory Streaming から Contiguous Memory Accesses に変更。

2013 年 6 月 13.0 SP1.0 • 複雑な出口パスを含む OpenCL カーネル・ソース・コードのサポート状況を更新。• Store と Global Memory 間のデータフローを修正するために、図 Effect of Kernel

Vectorization on Array Summation を更新。• Loop Unrolling セクションの unroll プラグマ・ディレクティブの内容を更新。• Local Memory セクションを変更。• Loop Unrolling with Vectorization セクションを削除。• 図 Optimizing Local Memory Bandwidth を削除。

2013 年 5 月 13.0.1 • 用語を更新。 たとえば、パイプラインは計算単位に置き換えられます。 ベクターレーンは SIMDベクターレーンに置き換えられます。

• Good Design Practices の下に以下のセクションを追加。— Preprocessor Macros.— Floating-Point versus Fixed-Point Representations.— Recommended Optimization Methodology.— Sequence of Optimization Techniques.

• コードの一部を更新。• 図 Data Flow with Multiple Compute Units を変更。• 図 Compute Unit Replication versus Kernel SIMD Vectorization を変更。• 図 Optimizing Throughput Using Compute Unit Replication and SIMD

Vectorization を変更。• 図 Memory Streaming を変更。• 図 Local Memories Transferring Data Blocks within Matrices A and B を追加。• 情報の流れを整理。 図、表、および例の数を更新。• 新しいカーネル属性に関する情報を追加。 max_share_resources および

num_share_resources

2013 年 5 月 13.0.0 • パイプラインの説明を更新。• ケーススタディのコード例と結果の表を更新。• 図を更新。

2012 年 11 月 12.1.0 初版。

A. 追加情報UG-OCL003 | 2017.12.08

Intel FPGA SDK for OpenCL: ベスト・プラクティス・ガイド フィードバック

148