前回、基本的な演算性能の測定方法を確立した。まずは、PIPELINEディレクティブを挿入することで、どの程度高速化されるか試行してみよう。
とりあえず、前回のパイプライン挿入無しの場合の計測結果が間違えていた。修正済。
パイプラインを挿入しない場合、ループがそのまま回路に直るので、 サイクルとなるはずだ。
最内ループからパイプライン化のDirectiveを挿入する
void matrix_mul (const float matrix_a[MATRIX_LENGTH][MATRIX_LENGTH], const float matrix_b[MATRIX_LENGTH][MATRIX_LENGTH], float matrix_c[MATRIX_LENGTH][MATRIX_LENGTH]) { for (int j = 0; j < MATRIX_LENGTH; j++) { for (int i = 0; i < MATRIX_LENGTH; i++) { matrix_c[j][i] = 0; for (int k = 0; k < MATRIX_LENGTH; k++) { matrix_c[j][i] += matrix_a[j][k] * matrix_b[k][i]; } } } return; }
最内ループにパイプラインディレクティブを挿入してみる。
void matrix_mul (const float matrix_a[MATRIX_LENGTH][MATRIX_LENGTH], const float matrix_b[MATRIX_LENGTH][MATRIX_LENGTH], float matrix_c[MATRIX_LENGTH][MATRIX_LENGTH]) { for (int j = 0; j < MATRIX_LENGTH; j++) { for (int i = 0; i < MATRIX_LENGTH; i++) { matrix_c[j][i] = 0; matrix_hls_label1:for (int k = 0; k < MATRIX_LENGTH; k++) { matrix_c[j][i] += matrix_a[j][k] * matrix_b[k][i]; } } } return; }
ラベルが挿入され、Vivado HLS側でパイプラインディレクティブが挿入される。
これで一度Synthesisを行い、Vivado側に戻って再合成およびサイクル数測定、結果を回収。さらに、2番目のループにパイプラインディレクティブを挿入し、同様にサイクル数を測定する。
for (int j = 0; j < MATRIX_LENGTH; j++) { label_hls_label2:for (int i = 0; i < MATRIX_LENGTH; i++) { matrix_c[j][i] = 0; matrix_hls_label1:for (int k = 0; k < MATRIX_LENGTH; k++) { matrix_c[j][i] += matrix_a[j][k] * matrix_b[k][i]; } } }
サイクル数は以下のようになった。
種類 | Vivado HLSサイクル数見積 | (実測)サイクル数(20回実行) | サイクル数(平均) |
---|---|---|---|
パイプライン化無し | 2629762 | 5486812 | 274340.6 |
最内ループ パイプライン | 1343488 | 2807102 | 140355.1 |
最内ループ 2番目ループ パイプライン | 262407 | 554837 | 27741.85 |
最内ループ 2番目ループ 最外ループ パイプライン | 取得忘れ | 計測未 | - |
3ループ分パイプラインしたものは、およそ1時間程度合成しているが、まだ完了しない。だいたいZynq のLUTを80%程度使ってしまっているので、使いものにならないのだけれども。
ってかあれ?サイクル数の見積りと実際のサイクル数が、桁が全然違うなあ。そもそも実測値はARM(800MHz)で動作しているのだし、そういう意味では実測値はもっと大きくなって良いと思うのだけれども。 実際にどうなっているのか、調査する必要があるなあ。