Vitis™ ハードウェア アクセラレーション チュートリアル

xilinx.com の Vitis™ 開発環境を参照

モジュール 4 のコードおよびファイル (モジュール 1 と同じ手順で Vitis、Vitis アナライザー、および Vitis HLS を設定)

このモジュールの内容
1. テンプレート化された関数を使用し、適用されたプログラマブル係数で計算ループを複製
2. Vitis HLS dataflow プラグマを使用
3. フル コンパイルを実行してカードをプログラム

ここをクリックして展開し、dataflow プラグマの詳細をご覧ください。

DATAFLOW プラグマは、タスク レベルのパイプライン処理をイネーブルにして関数およびループをオーバーラップできるようにし、レジスタ トランスファー レベル (RTL) インプリメンテーションでの同時実行性を増加してデザイン全体のスループットを向上します。

C 記述では、すべての演算が順次に実行されます。pragma HLS allocation などのリソースを制限する指示子を指定しない場合は、Vivado 高位合成 (HLS) ではレイテンシを最小限に抑え、同時実行性を向上するように処理されます。ただし、データ依存性のためにこれが制限されることがあります。たとえば、配列にアクセスする関数またはループは、完了する前に配列への読み出し/書き込みアクセスをすべて終了する必要があります。そのため、そのデータを消費する次の関数またはループの演算を開始できません。DATAFLOW データ最適化を使用すると、前の関数またはループがすべての演算を完了する前に、次の関数またはループの演算を開始できるようになります。

DATAFLOW プラグマを指定した場合、HLS ツールで順次関数またはループ間のデータフローが解析され、プロデューサー関数またはループが完了する前にコンシューマー関数またはループの演算を開始できるように、ピンポン RAM または FIFO に基づいてチャネルが作成されます。これにより関数またはループを並列実行でき、レイテンシが削減されて RTL のスループットが向上します。

開始間隔 (II) (関数またはループの開始から次の関数またはループの開始までのサイクル数) が指定されていない場合は、HLS ツールで開始間隔が最小になるようにし、データが使用可能になったらすぐに演算を開始できるようにすることが試みられます。

ヒント: config_dataflow コマンドは、dataflow 最適化で使用されるデフォルトのメモリ チャネルと FIFO の深さを指定します。詳細は、『Vivado Design Suite ユーザー ガイド: 高位合成』 (UG902) の config_dataflow に関する説明を参照してください。DATAFLOW 最適化が機能するようにするには、デザイン内でデータが 1 つのタスクから次のタスクに流れる必要があります。次のコーディング スタイルを使用すると、HLS ツールで DATAFLOW 最適化が実行されなくなります。

  • シングル プロデューサー コンシューマー違反

  • タスクのバイパス

  • タスク間のフィードバック

  • タスクの条件付き実行

  • 複数の exit 条件を持つループ

重要: これらのコーディング スタイルのいずれかが使用されている場合、HLS ツールでメッセージが表示され、DATAFLOW 最適化は実行されません。

STABLE プラグマを使用して DATAFLOW 領域内の変数を安定とマークすると、変数が同時に読み出しまたは書き込みされるのを回避できます。

最後に、DATAFLOW 最適化には階層インプリメンテーションはありません。サブ関数またはループに最適化が有益な可能性のあるタスクが含まれる場合、最適化をそのループまたはサブ関数に適用するか、サブ関数をインライン展開する必要があります。

構文

C ソースの領域、関数、またはループ内に配置します。

#pragma HLS DATAFLOW

次の例では、wr_loop_j ループ内で DATAFLOW 最適化を指定しています。

wr_loop_j: for (int j = 0; j < TILE_PER_ROW; ++j) { #pragma HLS DATAFLOW wr_buf_loop_m: for (int m = 0; m < HEIGHT; ++m) { wr_buf_loop_n: for (int n = 0; n < WIDTH; ++n) { #pragma HLS PIPELINE // should burst WIDTH in WORD beat outFifo >> tile[m][n]; } } wr_loop_m: for (int m = 0; m < HEIGHT; ++m) { wr_loop_n: for (int n = 0; n < WIDTH; ++n) { #pragma HLS PIPELINE outx[HEIGHT*TILE_PER_ROW*WIDTH*i+TILE_PER_ROW*WIDTH*m+WIDTH*j+n] = tile[m][n]; } } }

コレスキー カーネルのコード変更

このモジュール 4 では、アルゴリズムのコードを cholesky_kernel.hpp ヘッダーファイルに移動します。

並列処理と並列計算の数は明示的に指定されるようになっています。これは、NCU (#define NCU 16cholesky_kernel.cpp に設定された定数) で決まります。

NCU は、テンプレート パラメーターとして chol_col_wrapper 関数に渡されます (次を参照)。DATAFLOW プラグマが、chol_col ループを 16 回呼び出すループに適用されます。

template <typename T, int N, int NCU>
void chol_col_wrapper(int n, T dataA[NCU][(N + NCU - 1) / NCU][N], T dataj[NCU][N], T tmp1, int j)
{
#pragma HLS DATAFLOW

Loop_row:
    for (int num = 0; num < NCU; num++)
    {
#pragma HLS unroll factor = NCU
        chol_col<T, N, NCU>(n, dataA[num], dataj[num], tmp1, num, j);
    }
}

DATAFLOW が確実に適用されるように、dataA は複数の NCU 部分に分割されます。

最後に、ループは NCU 係数を使用して展開されます。この係数は、データのチャンクが処理されるたびに、chol_col のコピーが NCU (たとえば 16) 個作成されることを意味します。

デザインの実行

モジュール 1 と同じ手順:

  • ハードウェア エミュレーションを実行します。

  • Vitis アナライザーを実行します。

  • Vitis HLS を実行し、結果をデータフロー ビューアーを確認します。これは、合成サマリ レポートから dataflow が適用される関数 (chol_col_wrapper) を右クリックすると表示できます。このアニメーションを参照して、アクセス方法および複製が適用されたことを確認する方法を確認してください。

結果のサマリ

CPU(*) での実行を含む、すべてのモジュールの実行を比較した実際の結果は、次のようになります。

モジュール CPU モジュール 1 モジュール 2 モジュール 3 モジュール 4 (NCU = 16)
実行時間 (µs) 21461 793950 793732 536784 11698
速度アップ (CPU 基準) 1 0.03x 0.03x 0.04x 1.83x
速度アップ なし 1 1 1.48x 68x

(*): 基準 CPU は、Intel® Xeon® Processor E5-2640 v3 (Nimbix で利用可能) です。

まとめ

これで、この Vitis ハードウェア アクセラレータの入門チュートリアルは終了です。その他の Vitis のデザイン最適化チュートリアルを参照するには、ここをクリックしてください。

Copyright© 2020-2022 Xilinx