FC2カウンター FPGAの部屋 intel HLS の pointer_mm_master を試してみた2
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

intel HLS の pointer_mm_master を試してみた2

intel HLS の pointer_mm_master を試してみた1”の続き。

前回は、intel HLS の F:\intelFPGA_lite\17.1\hls\examples\tutorials\interfaces\pointer_mm_master を試してみた。
ここには、part_1_pointers.cpp、part_2_masters.cpp、part_3_ddr_masters.cpp、part_4_ddr_masters_coalesce.cpp、part_5_ddr_masters_align.cpp の 5 つのAvalon-MM master のサンプルがあった。そして、それぞれの実装の違いをHDLのポート宣言を見ることで確認した。
今回は、それらの転送波形をModelSim で見てみよう。

part_1_pointers.cpp
part_1_pointers.cpp のハードウェア化関数、component void vector_add() コードを引用する。

component void vector_add(int* a,
                          int* b,
                          int* c,
                          int N) {
  for (int i = 0; i < N; ++i) {
    c[i] = a[i] + b[i];
  }
}


ModelSim の全体波形を示す。
Intel_HLS_135_171208.png

done が出るまでの時間は約 17.03 us だった。

1つのトランザクションが見えるように拡大波形を示す。
Intel_HLS_136_171208.png

それぞれ 1 回ずつReadが 2 回、Write が 1 回のアクセルがある。 1 回の転送の周期は、17 ns だった。これを 1000 回やっているので、17 us となり計算は合う。

part_2_masters.cpp
part_2_masters.cpp のハードウェア化関数、component void vector_add() コードを引用する。

component void vector_add(ihc::mm_master<int, ihc::aspace<1>, ihc::awidth<16>, ihc::dwidth<32> >& a,
                          ihc::mm_master<int, ihc::aspace<2>, ihc::awidth<16>, ihc::dwidth<32> >& b,
                          ihc::mm_master<int, ihc::aspace<3>, ihc::awidth<16>, ihc::dwidth<32> >& c,
                          int N) {
  for (int i = 0; i < N; ++i) {
    c[i] = a[i] + b[i];  
  }
}


part_1_pointers.cpp と比べると、32 ビット幅のバスを 3 つにした。つまりスループットが大きくなる要素がそろった。
ModelSim の全体波形を示す。
Intel_HLS_137_171208.png

3つのバスとも、アドレスとデータの幅は 32 ビットだ。
part_2_masters.cpp の done が出るまでに時間は約 1.04 ms となった。part_1_pointers.cpp との性能差は17 倍弱だ。

拡大してみよう。
Intel_HLS_138_171208.png

この実装では、Read と Write はパイプライン実行されている。クロックごとに 1 ns で Write されているので、1 回の転送の周期は 1 ns となる。

part_2_masters.cpp がなぜエラーになるかだが、演算の最初を拡大してみると、最初の演算の答えが avmm_3_rw_writedata に 0000464c と出ているが、まだ avmm_3_rw_write は 1 にアサートされていない。avmm_3_rw_write が 1 にアサートされるのはその 2 クロック後であるので、データが 2 個ずれているようだ。この、avmm_3_rw_write が 1 にアサートされるのを 2 クロック前にずらせれば良さそうだ。

part_3_ddr_masters.cpp
part_3_ddr_masters.cpp のハードウェア化関数、component void vector_add() コードを引用する。

component void vector_add(ihc::mm_master<int, ihc::aspace<1>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::waitrequest<true> >& a, // bank 1
                          ihc::mm_master<int, ihc::aspace<1>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::waitrequest<true> >& b, // bank 1
                          ihc::mm_master<int, ihc::aspace<2>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::waitrequest<true> >& c, // bank 2
                          int N) {
  for (int i = 0; i < N; ++i) {
    c[i] = a[i] + b[i];  
  }
}


データバスの幅が 256 ビットになって、Read が 1 つのバス、Write も 1 つのバスの合計 2 つのバスになった。
ModelSim の全体波形を示す。
Intel_HLS_139_171208.png

まばらにアクセスがあるが、ビット幅が 256 ビット幅なので、done が出るまでの時間は、約 1.63 us だった。part_1_pointers.cpp との性能差は約10.4 倍だった。

拡大してみてみよう。
Intel_HLS_140_171208.png

Write の幅を見ると 8 ns になっているのが分かる。これは、32ビット幅の演算器しか持っていないので、256 ビット幅のデータを満たすには、 256 / 32 = 8 クロック分(1クロックは 1 ns)かかるためだと思われる。

part_4_ddr_masters_coalesce.cpp
part_4_ddr_masters_coalesce.cpp のハードウェア化関数、component void vector_add() コードを引用する。

component void vector_add(ihc::mm_master<int, ihc::aspace<1>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::waitrequest<true> >& a, // bank 1
                          ihc::mm_master<int, ihc::aspace<1>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::waitrequest<true> >& b, // bank 1
                          ihc::mm_master<int, ihc::aspace<2>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::waitrequest<true> >& c, // bank 2
                          int N) {
  #pragma unroll 8
  for (int i = 0; i < N; ++i) {
    c[i] = a[i] + b[i];  
  }
}


part_4_ddr_masters_coalesce.cpp では、#pragma unroll 8 のプラグマが追加されているので、part_3_ddr_masters.cpp での 8 クロックに 1 回のデータ Write が改善されていると思われる。
ModelSim の全体波形を示す。
Intel_HLS_141_171208.png

done が出るまでの時間は、384 ns だった。アクセスがきちんと並んでいて、転送のスループットが大きいのが分かる。part_1_pointers.cpp との性能差は約 44.3 倍だった。

波形を拡大してみよう。
Intel_HLS_142_171208.png

Read のアドレスが飛んでいるので、a[i] をRead しているアドレスと b[i] をRead しているアドレスがあると考えられる。よって、Write の転送は、半分のスループットになっているのが分かる。つまり、2 つデータを読んで 1 つデータを書いているわけだ。

part_5_ddr_masters_align.cpp
part_5_ddr_masters_align.cpp のハードウェア化関数、component void vector_add() コードを引用する。

component void vector_add(ihc::mm_master<int, ihc::aspace<1>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::align<32>, ihc::waitrequest<true> >& a, // bank 1
                          ihc::mm_master<int, ihc::aspace<1>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::align<32>, ihc::waitrequest<true> >& b, // bank 1
                          ihc::mm_master<int, ihc::aspace<2>, ihc::awidth<32>, ihc::dwidth<256>, ihc::latency<0>, ihc::maxburst<8>, ihc::align<32>, ihc::waitrequest<true> >& c, // bank 2
                          int N) {
  #pragma unroll 8
  for (int i = 0; i < N; ++i) {
    c[i] = a[i] + b[i];  
  }
}


part_5_ddr_masters_align.cpp では、part_4_ddr_masters_coalesce.cpp に ihc::align<32> が追加されている。これでデータバスの 256 ビット幅にアラインされているということにしている。

ModelSim の全体波形を示す。
Intel_HLS_143_171208.png

done が出るまでの時間は、380 ns だった。part_4_ddr_masters_coalesce.cpp とほとんど同じようだ。part_1_pointers.cpp との性能差は約 44.8 倍だった。

波形を拡大してみた。
Intel_HLS_144_171208.png

part_4_ddr_masters_coalesce.cpp と同様だ。 ihc::align<32> を付けるとリソース使用量が減るのではないか?と思う。


最後に part_2_masters.cpp のエラーの対処方法を押しててもらったので、やってみよう。

component void vector_add(ihc::mm_master<int, ihc::aspace<1>, ihc::awidth<16>, ihc::dwidth<32>, ihc::latency<0> >& a,
                          ihc::mm_master<int, ihc::aspace<2>, ihc::awidth<16>, ihc::dwidth<32>, ihc::latency<0> >& b,
                          ihc::mm_master<int, ihc::aspace<3>, ihc::awidth<16>, ihc::dwidth<32>, ihc::latency<0> >& c,
                          int N) {
  for (int i = 0; i < N; ++i) {
    c[i] = a[i] + b[i];  
  }
}


このように、ihc::latency<0> を追加して build clean してから build default を行ったところ、PASSED になった。なお、mm_A, mm_B, mm_C の宣言の部分にも ihc::latency<0> を追加している。
Intel_HLS_145_171209.png

ModelSim の波形を示す。
Intel_HLS_146_171209.png

これは、ihc::latency<0> を付加する前に比べてスループットが下がっている。以前は、done が出るまでに時間は約 1.04 ms だったが、今回は、約 1.33 ms になった。

拡大してみた。
Intel_HLS_147_171209.png
  1. 2017年12月08日 05:13 |
  2. intel HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
https://marsee101.blog.fc2.com/tb.php/3997-e67cad11
この記事にトラックバックする(FC2ブログユーザー)