Vivado-HLSで行列積の回路を設計した場合と、普通にARM Cortex-A9上で動作する行列積のプログラムでどれくらいの速度差になるのか調査してみることにした。
今回使用するのは48×48の行列データで、ころ2つのデータの行列積を計算するものとする。
for (j = 0; j < MATRIX_LENGTH; j++) { for (i = 0; i < MATRIX_LENGTH; i++) { matrix_c[j][i] = 0; for (k = 0; k < MATRIX_LENGTH; k++) { matrix_c[j][i] += matrix_a[j][k] * matrix_b[k][i]; } } }
Vivado-HLSでは、最内ループにPIPELINEディレクティブを挿入したものを用意し、これを論理合成を行ってFPGAに実装を行った。 そしてこれを20回呼び出し、そのときに経過する時間を計測する。
for (trial_count = 0; trial_count < 20; trial_count++) { XMatrix_mul_Write_matrix_a_Words(p_matrix_mul, 0, (int *)matrix_a, XMATRIX_MUL_SLV0_DEPTH_MATRIX_A); XMatrix_mul_Write_matrix_b_Words(p_matrix_mul, 0, (int *)matrix_b, XMATRIX_MUL_SLV0_DEPTH_MATRIX_B); XMatrix_mul_Start (p_matrix_mul); while (!XMatrix_mul_IsDone (p_matrix_mul)); XMatrix_mul_Read_matrix_c_Words (p_matrix_mul, 0, (int *)matrix_c, XMATRIX_MUL_SLV0_DEPTH_MATRIX_C); }
一方で、C言語で記述した、ARM上で動作するプログラムは以下になる。これを-O3
オプションでコンパイルし、実験を行う。
for (trial_count = 0; trial_count < 20; trial_count++) { cpp_matrix_mul (matrix_a, matrix_b, matrix_c); }
計測は前回紹介したサイクルカウンタを用いて行なう。計測結果は以下のようになった。
サイクル数 | |
---|---|
Vivado-HLSで生成した回路 | 1203350 |
ARM Cortex-A9で実行したプログラム | 179649 |
あれ、ずいぶんとCortex-A9の方が速い。。。
しかし、この結果は驚くには足らないものなのかもしれない。Cortex-A9、つまりPS側は動作周波数800MHz、一方でFPGA側、ロジック側は100MHzで動作している。 動作周波数で既にこの程度差が付いているのならば、時間経過としておよそ7倍に収まった、というのは、Vivado-HLSのパイプライン化の効果が殆ど出ていないということになる。
また、良く考えてみると、PL側の論理にはデータ転送の時間が入っている。一方でARM側は、ポインタ参照なのでこの必要はない。 とりあえず、データは時間0でダウンロード&アップロードできるとして、計測してみよう。
for (trial_count = 0; trial_count < 20; trial_count++) { XMatrix_mul_Start (p_matrix_mul); while (!XMatrix_mul_IsDone (p_matrix_mul)); }
サイクル数 | |
---|---|
Vivado-HLSで生成した回路 | 1195316 |
ARM Cortex-A9で実行したプログラム | 179649 |
あれ、やっぱり殆ど変わっていない。やはりメインプログラムの部分で十分に遅いのか。
これ、単純な計算、というかハードウェア化した結果オリジナルよりも8倍速くなるようなアルゴリズムにしか効果が無いなあ。 どういう特徴があるのか、もう少し調べてみたい。