”
Vivado HLS 2014.4 で合成したラプラシアンフィルタIPの高速化12(性能が最大になる設定を探る5)”の続き。
今回は、ラプラシアンフィルタIP のAXI Master が接続されているAXI Interconnect (axi_mem_intercon_1) の設定は、Slave Interface タブの Enable Register Slice を Auto に、Enable Data FIFO を 512 deep に設定した。
今回の設定を下の表にまとめておく。
項目 | 値 |
---|
Vivado HLS 2014.4 のクロック周期制約 | 8 ns |
Vivado HLS 2014.4 のTiming Summary Estimated | 7 ns |
AXI Interconnect (axi_mem_intercon_1) の設定のSlave Interface タブの Enable Register Slice | Auto |
AXI Interconnect (axi_mem_intercon_1) の設定のSlave Interface タブのEnable Data FIFO | 512 deep (packet mode) |
ラプラシアンフィルタIPやaxi_mem_intercon_1へ供給するFCLK_FCLK3の周波数 | 130MHz, 100MHz |
ラプラシアンフィルタIP のAXI Master が接続されているAXI Interconnect (axi_mem_intercon_1) の Slave Interface タブの設定を下に示す。

最初に、FCLK_CLK3 を 130 MHz に設定した。

論理合成、インプリメント、ビットストリームの生成を行った。Summary を下に示す。

AXI Interconnect (axi_mem_intercon_1) の設定が none, none の場合よりも、FFで 2 %, LUT で 4 %, BRAM で 5 % 増えている。
ZYBO 実機で、ラプラシアンフィルタ全体の処理時間を測定した結果、64.2 ms となった。ラプラシアンフィルタのみの処理時間は、49.0 ms だった。
Enable Data FIFO を 32 deep にした時よりも、両方共、約 100 ns 遅い。
次に、FCLK_CLK3 を 100 MHz に設定する。

論理合成、インプリメント、ビットストリームの生成を行った。Summary を下に示す。

130 MHz の時と同様に、AXI Interconnect (axi_mem_intercon_1) の設定が none, none の場合よりも、FFで 2 %, LUT で 4 %, BRAM で 5 % 増えている。
ZYBO 実機で、ラプラシアンフィルタ全体の処理時間を測定した結果、79.1 ms となった。ラプラシアンフィルタのみの処理時間は、63.7 ms だった。
Enable Data FIFO を 32 deep にした時よりも、両方共 約 300 ns 遅い
AXI Master が接続されているAXI Interconnect (axi_mem_intercon_1) の設定のうちのSlave Interface タブの Enable Data FIFO を 32 deep に設定しても、512 deep に設定も大した違いは無いと思う。
- 2015年04月13日 04:32 |
- Vivado HLS
-
| トラックバック:0
-
| コメント:6
twitterもSNSも手を出していないので、のんびりと眺めさせてもらっていますので
遅れましたが、この度はご愁傷様でした。
いつ、何が起きてもおかしくはない歳になりましたが、新しい事を勉強するのは
やめたくないものです。
ここから、本題
今のソースのように一旦バッファにデータを溜め込んで演算する方式だとFIFOの
深さを変更しても、パイプライン化しても、データの転送完了フラグがフィルタ
処理の開始トリガがとなるので、フィルタの処理時間が全てのファクターになる
ようですね。
下のような、画素データを読み出しながらフィルタ処理をして書き出す方法で
ないと、プログラムのコード=実行時間となりパラメータを振って高速化するの
は難しいかなと感じます(ソースは適当に書いたので動作補償なしです ^^;)
高位合成と言っても、データの流れや重なりを分析するところまではまだまだ
無理そうだけど面白い時代になったものです。これが20年早ければw
for (y=0; y<VERTICAL_PIXEL_WIDTH-1; y++){
cam_fb_addr = (int*)(cam_fb+offset_cam_addr+((y+1)*(HORIZONTAL_PIXEL_WIDTH)));
lap_fb_addr = (int *)(lap_fb+offset_lap_addr+(y*(HORIZONTAL_PIXEL_WIDTH)));
sum0 = 0;
sum1 = 0;
cen0 = 0;
cen1 = 0;
for (x=0; x<HORIZONTAL_PIXEL_WIDTH-1; x++){
px_data = (const int*)cam_fb_addr++ ; // 1画素の読み出し
py_data = conv_rgb2y(px_data); // 1byte幅のデータ
pb_data = line_buf[x] ; // バッファからの読み出し
// モノクロデータをバッファに詰める
if (y==0) pb_data = py_data; // 1ライン目はバッファクリア
else if pb_data = pb_data<<8 | py_data ; // 2ライン目以降はYデータを詰めていく
line_buf[x] = bp_data ; // バッファに書き込み
cen0 = cen1;
cen1 = cen2;
cen2 = bp_data>>8 & 0xff ; // 中心データを読み出し
sum0 = sum1 ; // フィルタのサム値を算出
sum1 = sum2 ;
sum2 = (bp_data>>16) & 0xff + (bp_data>>8) & 0xff + bp_data & 0xff ;
// ラプラシアンフィルタ処理
rap_val = cen1*8 + cen1 - (sum0 + sum1 + sum2 ) ;
if (rap_val<0) rap_val = 0;
else if (rap_val>255) rap_val = 255;
(const int*)lap_fb_addr++ = (rap_val<<16)+(rap_val<<8)+rap_val;
}
}
- 2015/04/14(火) 11:11:32 |
- URL |
- おる #mQop/nM.
- [ 編集 ]
おるさん、こんにちは。
Vivado HLSのユーザーズガイドによるとmemcpy()関数を使わないとシングル転送になると書いてあるんです。それでバースト転送になるようにmemcpy()を使っています。ここでブロックされちゃうので、完全なパイプラインにならないんです。
http://japan.xilinx.com/support/documentation/sw_manuals_j/xilinx2014_4/ug902-vivado-high-level-synthesis.pdf の154ページです。
なお、性能を向上する方法についてはわかっていまして、DMAエンジンとAXI-Streamを使えば良さそうです。
今のところは、あくまでソフトウェアとしても動くメモリベースのCソースをハードウェアにしてどこまで速くできるのか?をテストしています。
- 2015/04/14(火) 12:29:42 |
- URL |
- marsee #f1oWVgn2
- [ 編集 ]
こんにちは。
読んでみましたがメモリアクセスではAXIバスのところで制約が多くて、そこを回避するにはDMAが必要というのは理解できました。
先読みのキャッシュくらいあれば、バスアクセスの効率は上がりそうですが。
メモリベースでの高速化として残されているのは、配列をFIFOと見立ててアクセスするか、「配列とメモリの障害」を回避するくらいしか手段が残されていないのですね。
- 2015/04/16(木) 10:13:50 |
- URL |
- おる #mQop/nM.
- [ 編集 ]
ここまでしてしまうと、Cソースと言えるのか謎になってしまいますが、メモリベースで最速にできそうなソースに修正してみました。
int x,y;
int sum0,sum1,sum2; // フィルタの-1部分の加算値
int cen0,cen1; // 中心データのシフト用
int py_data,pb_data,rap_val; // 一時データ
int line_buf[HORIZONTAL_PIXEL_WIDTH]; // 画像データの読み出し用バッファ(32bit-SinglePort)
int sum_buf[HORIZONTAL_PIXEL_WIDTH]; // 前2ライン分のYデータ格納用バッファ(16bit-DualPort)
int lap_buf[HORIZONTAL_PIXEL_WIDTH]; // フィルタ結果の格納用バッファ(32bit-SinglePort)
for (y=0; y<VERTICAL_PIXEL_WIDTH-1; y++){
cam_fb_addr = (int*)(cam_fb+offset_cam_addr+(y*HORIZONTAL_PIXEL_WIDTH));
memcpy(&line_buf[0], (const int*)cam_fb_addr, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
sum0 = 0;
sum1 = 0;
cen1 = 0;
for (x=0; x<HORIZONTAL_PIXEL_WIDTH-1; x++){
py_data = conv_rgb2y(line_buf[x]); // 輝度Yデータ
pb_data = sum_buf[x] ; // バッファからの前ラインの読み出し
// モノクロデータをバッファに詰める
if (y==0) pb_data = 0; // 1ライン目はバッファクリア
cen0 = cen1;
cen1 = pb_data & 0xff ; // 中心データをシフト
sum0 = sum1 ; // フィルタのサム値を算出
sum1 = sum2 ;
sum2 = ((pb_data>>8) & 0xff) + (pb_data & 0xff) + (py_data & 0xff) ;
pb_data = pb_data<<8 + py_data ; //
sum_buf[x] = pb_data ; // 過去のデータを保存
// ラプラシアンフィルタ処理
rap_val = cen0*8 + cen0 - (sum0 + sum1 + sum2 ) ;
if (rap_val<0) rap_val = 0;
else if (rap_val>255) rap_val = 255;
lap_buf[x] = (rap_val<<16)+(rap_val<<8)+rap_val;
}
lap_fb_addr = (int *)(lap_fb+offset_lap_addr+(y*(HORIZONTAL_PIXEL_WIDTH)));
memcpy(lap_fb_addr, (const int*)lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
}
- 2015/04/16(木) 11:32:56 |
- URL |
- おる #mQop/nM.
- [ 編集 ]
おるさん、いつもコメントありがとうございます。
メモリベースのCソースコードによる高位合成は、tu1987さんのコードが最速だと思います。ある程度、高速化のめどが立ったので、これからAXI-Streamによる実装に移ろうと思います。
- 2015/04/16(木) 22:22:38 |
- URL |
- marsee #f1oWVgn2
- [ 編集 ]
こちらこそ、ありがとうございます。
おかげさまでメモリベースの処理といえども、データフローまで考慮すれば高位合成が
かなりのところまで最適化してくれるというのがよくわかりました。
おまけに、今日の記事もそうですが手動で行っていた最適化がツールで自動に出来るのが
わかりすごいことだと感心してます。
次世代の高位合成はデータ構造から流れまでを解析して合成できるようになるのでしょうかね。
ストリーミングの方も楽しみに読ませていただきます。
- 2015/04/22(水) 17:23:03 |
- URL |
- おる #mQop/nM.
- [ 編集 ]