読者です 読者をやめる 読者になる 読者になる

FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://sites.google.com/site/fpgadevelopindex/

行列積演算のHLS設計高速化検討(2. Pipeline Directiveの検討)

msyksphinz.hatenablog.com

前回、基本的な演算性能の測定方法を確立した。まずは、PIPELINEディレクティブを挿入することで、どの程度高速化されるか試行してみよう。

とりあえず、前回のパイプライン挿入無しの場合の計測結果が間違えていた。修正済。

パイプラインを挿入しない場合、ループがそのまま回路に直るので、 64\times 64\times 64\times 10=2,621,440 サイクルとなるはずだ。

最内ループからパイプライン化の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番目のループにパイプラインディレクティブを挿入し、同様にサイクル数を測定する。

f:id:msyksphinz:20160913020048p:plain

  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)で動作しているのだし、そういう意味では実測値はもっと大きくなって良いと思うのだけれども。 実際にどうなっているのか、調査する必要があるなあ。