FC2カウンター FPGAの部屋 Zynq
FC2ブログ

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

FPGAの部屋

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

ikwzm さんの fclkcfg による Zynq のPS の fclk の設定2

ikwzm さんの fclkcfg による Zynq のPS の fclk の設定”の続き。

前回は、ZYBO_BOOT つまり、ブート用のFAT32 フォーマットのMicro SD カードのパーティションで、uEnv.txt (u-boot の設定ファイル)を編集して、各 fclk の Clock Source を設定した。そのため、デバイスツリーで fclk を設定したときに正しい値を設定することができた。
今回は、新しく ikwzm さんにバージョンアップして頂いた新しい fclkcfg (fclkcfg-4.14.34-armv7-fpga_1.1.0-1_armhf.deb)を使用して、デバイスツリーから Clock Source を変更することができるかどうか?を確かめる。

最初に今までの uEnv.txt に戻した。
ZYBOt_22_180819.png

リブートして、
sudo dtbocfg.rb -i --dts devicetree.dts wl_tracing_cnn
すると、以前同様に、ずれたクロック周波数が設定される。
ZYBOt_23_180819.png

ZYBOt_24_180819.png

ずれたクロック周波数が設定されているということを覚えておいて欲しい。

ikwzm/FPGA-SoC-Linux を git clone して比べてみると、fclkcfg-4.14.34-armv7-fpga_1.1.0-1_armhf.deb が新しくなっていたけれど、dtbocfg-4.14.34-armv7-fpga_0.0.6-1_armhf.deb と udmabuf-4.14.34-armv7-fpga_1.2.3-1_armhf.deb も新しくなっていた。
ZYBOt_25_180819.png

この3つを ZYBOt の ~/debian ディレクトリに SFTP した。
ZYBOt_26_180819.png


sudo dpkg -i dtbocfg-4.14.34-armv7-fpga_0.0.6-1_armhf.deb
ZYBOt_27_180819.png

sudo dpkg -i fclkcfg-4.14.34-armv7-fpga_1.1.0-1_armhf.deb
sudo dpkg -i udmabuf-4.14.34-armv7-fpga_1.2.3-1_armhf.deb

ZYBOt_28_180819.png

FPGA Clock Configuration Device Driver を見ながら devicetree.dts を変更した。
"armpll" は <&clkc 0>、"ddrpll" は <&clkc 1>、"iopll" は <&clkc 2> だそうだ。
ZYBOt_29_180819.png

/dts-v1/;/plugin/;
/ {
    fragment@0 {
        target-path = "/amba/fpga-region0";
        #address-cells = <0x1>;
        #size-cells = <0x1>;

        __overlay__ {
            #address-cells = <0x1>;
            #size-cells = <0x1>;

            firmware-name = "ZYBO_0_wrapper.bin";

            mt9d111_axi_iic@41600000 {
                compatible = "generic-uio";
                reg = < 0x41600000 0x10000>;
            };
            dmaw4gabor_0@43cb0000 {
                compatible = "generic-uio";
                reg = < 0x43cb0000 0x10000 >;
            };
            axis_switch_0@43c10000 {
                compatible = "generic-uio";
                reg = < 0x43c10000 0x10000 >;
            };
            axis_switch_1@43c20000 {
                compatible = "generic-uio";
                reg = < 0x43c20000 0x10000 >;
            };
            lap_filter_axis_0@43c30000 {
                compatible = "generic-uio";
                reg = < 0x43c30000 0x10000>;
            };    
            mt9d111_inf_axis_0@43C40000 {
                compatible = "generic-uio";
                reg = < 0x43C40000 0x10000>;
            };
            bitmap_disp_cntrler_axi_master_0@43c00000 {
                compatible = "generic-uio";
                reg = < 0x43c00000 0x10000>;
            };
            bitmap_disp_cntrler_axi_master_1@43c50000 {
                compatible = "generic-uio";
                reg = < 0x43c50000 0x10000>;
            };
            axi_gpio_0@41200000 {
                compatible = "generic-uio";
                reg = < 0x41200000 0x10000>;
            };
            frame_buffer_bmdc@17800000 {
                compatible = "generic-uio";
                reg = < 0x17800000 0x1000000>;
            };
            pwm_0@43c60000 {
                compatible = "generic-uio";
                reg = < 0x43c60000 0x10000>;
            };
            pwm_1@43c70000 {
                compatible = "generic-uio";
                reg = < 0x43c70000 0x10000>;
            };
            motor_monitor_0@43c80000 {
                compatible = "generic-uio";
                reg = < 0x43c80000 0x10000>;
            };
            motor_monitor_1@43c90000 {
                compatible = "generic-uio";
                reg = < 0x43c90000 0x10000>;
            };
            dmar4resize_gray_0@43ca0000 {
                compatible = "generic-uio";
                reg = < 0x43ca0000 0x10000>;
            };
            rgb2hsv_0@43cc0000 {
                compatible = "generic-uio";
                reg = < 0x43cc0000 0x10000>;
            };
            ultrasoninc_sensor_inf_0@43cd0000 {
                compatible = "generic-uio";
                reg = < 0x43cd0000 0x10000>;
            };
            resize_gray_0@43ce0000 {
                compatible = "generic-uio";
                reg = < 0x43ce0000 0x10000>;
            };
            curve_conv_nn2_axis3_0@43cf0000 {
                compatible = "generic-uio";
                reg = < 0x43cf0000 0x10000>;
            };

            pow2-udmabuf0 {
                compatible  = "ikwzm,udmabuf-0.10.a";
                device-name = "udmabuf0";
                size = <0x00600000>;
            };

            fclk0 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <&clkc 15>, <&clkc 2>;
                insert-rate    = "100000000";
                insert-enable = <1>;
            };
            fclk1 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <&clkc 16>, <&clkc 2>;
                insert-rate    = "40000000";
                insert-enable = <1>;
            };
            fclk2 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <&clkc 17>, <&clkc 2>;
                insert-rate    = "72000000";
                insert-enable = <1>;
            };
            fclk3 {
                compatible    = "ikwzm,fclkcfg-0.10.a";
                clocks        = <&clkc 18>, <&clkc 0>;
                insert-rate    = "65000000";
                insert-enable = <1>;
            };
        };
    } ;
} ;


最初は fclk* のところの &clkc がエラーになってしまっていたのだが、ikwzm さんに教えてもらって、devicetree.dts の最初の「/dts-v1/;」を「/dts-v1/;/plugin/;」に変更したら、&clkc が通るようになった。
ikwzm さんによると

「大元のデバイスツリーを作るときに dtc に -@ か --symbols を付けるとシンボル情報を含んだ dtb が出来ます。/plugin/; はそのシンボル情報を使うことを意味します。昔は dtc に -@ が無かったので出来なかったのですが。」

だそうだ。いつもありがとうございます。

さて、
sudo dtbocfg.rb -i --dts devicetree.dts wl_tracing_cnn
を行った。
ZYBOt_30_180819.png

シリアル・コンソールを見ると、正常な周波数が設定されている。成功だ。
ZYBOt_31_180819.png

なお、
sudo dtbocfg.rb -r wl_tracing_cnn
で、デバイスツリーに書かれたデバイス・ドライバが外れて、もう一度、sudo dtbocfg.rb -i できるようになる。

つまり、Debian が起動中にいろいろなハードウェアを取替えて試すことができる。とっても便利だと思う。

(追加)
cd /sys/devices/soc0/amba/amba\:fpga-region0/
ls

すると、デバイスツリーに書いたデバイスが見える。
ZYBOt_16_180818.png

cd /sys/class
ls

すると、fclkcfg, udamebuf, uio が見える。
ZYBOt_17_180818.png
  1. 2018年08月19日 08:31 |
  2. Zynq
  3. | トラックバック:0
  4. | コメント:0

ikwzm さんの fclkcfg による Zynq のPS の fclk の設定

白線追従用CNNを使用したZYBOtの白線追従走行1(準備編)”の続き。

前回は、デバイスツリー・ソース・ファイルを書いて、ビットストリームのFPGAへのロードやUIO の設定、udmabuf のロード、fclk の設定を行ったが、fclk の設定値が想定していた値と違ってしまった。
これは、ikwzm さんにお聞きしたところ、fclk1 などのClock Source が違っていたからということだった。Clock Source には、ARMPLL、DDRPLL、IOPLL の3種類あるが、どれを選ぶかで、周波数の設定値に対して、実際の値の偏差が発生するかどうか?が決まる。
このfclkcfg のバージョンでは、デバイスツリーのロード時にClock Source を変更することはできないので、u-boot 時にClock Source を変更するということだ。なお、現在のfclkcfg (fclkcfg-4.14.34-armv7-fpga_1.1.0-1_armhf.deb)では、デバイスツリーにClock Source を書くことができるので、後でやってみよう。

さて、ZYBO に挿入するMicro SD カードのZYBO_BOOT パーティションの uEnv.tst の fpga_set_cmd を以下の様に書き換えた。

fpga_set_cmd=run slcr_unlock_cmd && mw.l 0xF8000170 0x00100A00 && mw.l 0xF8000180 0x00100A00 && mw.l 0xF8000190 0x00100A00 && mw.l 0xF80001A0 0x00100A20 && run slcr_lock_cmd


U-Boot から Zynq の PLクロックとリセット信号を制御する”を参照すると、最初の fclk0 の値の設定は、”0xF8000170 0x00100A00”で、DIVISOR1 が 1 で、DIVISOR0 が 10 で、Clock Source はIOPLL ということを示す。デバイスツリーでDIVISOR の倍率は変更できるので、全部の fclk がDIVISOR1 が 1 で、DIVISOR0 が 10 だが、最後の fclk3 だけは Clock Source が ARMPLL になっている。
ZYBOt_18_180818.png

ZYBOt_19_180818.png

これでZYBOt のDebian をブートして、~/zybot/wl_tracing_cnn ディレクトリに行って、
sudo dtbocfg.rb -i --dts devicetree.dts wl_tracing_cnn
でデバイスツリーで示されるドライバをロードした。
ZYBOt_20_180818.png

シリアル・コンソールを見ると、設定通りの周波数が出ている。成功だ。
ZYBOt_21_180818.png
  1. 2018年08月19日 05:12 |
  2. Zynq
  3. | トラックバック:0
  4. | コメント:0

新しいラプラシアンフィルタのソフトウェア実装

OpenMPを使ったラプラシアンフィルタの動作がおかしいという現象があった。ブログのコメント欄でも教えてもらったのだが、OpenMPのプラグマを書いた for 文のどの順に実行されるかわからない?ということで、元のラプラシアンフィルタをよりシンプルにしてみた。
laplacian_filter.c ~ laplacian_filter4.c までは、ラプラシアンフィルタ処理によって、画像の周りの1ピクセルのみ 0 にしていたが、今回は上と右の 2 ピクセルを 0 にしている。下にその図を示す。ブルーの画面がラプラシアンフィルタの出力画像で、黒い部分が 0 を出力している部分とする。
OpenMP_23_150720.png

ラプラシアンフィルタは3 ピクセル x 3 ラインのデータを元に真ん中の画像を出力しているので、今回のソフトウェアの方が if 文が少なくなる。
実際のラプラシアンフィルタのソフトウェアはGitHubにあげておいたので、marsee101/laplacian_filters を見て欲しい。
laplacian_filter5.c は laplacian_filter.c に対応する実装で、順に番号付けされていて、 laplacian_filter8.c は、 laplacian_filter4.c に対応する実装となっている。

下に gcc-4.8 で laplacian_filter5.c の性能を比較した時のスクリプトを示す。

gcc laplacian_filter5.c -o laplacian_filter5
gcc -O1 laplacian_filter5.c -o laplacian_filter5_O1
gcc -O2 laplacian_filter5.c -o laplacian_filter5_O2
gcc -O3 laplacian_filter5.c -o laplacian_filter5_O3
gcc -Os laplacian_filter5.c -o laplacian_filter5_Os
gcc -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math laplacian_filter5.c -o laplacian_filter5_n
gcc -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O1 laplacian_filter5.c -o laplacian_filter5_n1
gcc -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O2 laplacian_filter5.c -o laplacian_filter5_n2
gcc -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O3 laplacian_filter5.c -o laplacian_filter5_n3
gcc -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -Os laplacian_filter5.c -o laplacian_filter5_ns
./laplacian_filter5
./laplacian_filter5_O1
./laplacian_filter5_O2
./laplacian_filter5_O3
./laplacian_filter5_Os
./laplacian_filter5_n
./laplacian_filter5_n1
./laplacian_filter5_n2
./laplacian_filter5_n3
./laplacian_filter5_ns
objdump -S -d laplacian_filter5 | grep "vmov" -c
objdump -S -d laplacian_filter5_O1 | grep "vmov" -c
objdump -S -d laplacian_filter5_O2 | grep "vmov" -c
objdump -S -d laplacian_filter5_O3 | grep "vmov" -c
objdump -S -d laplacian_filter5_Os | grep "vmov" -c
objdump -S -d laplacian_filter5_n | grep "vmov" -c
objdump -S -d laplacian_filter5_n1 | grep "vmov" -c
objdump -S -d laplacian_filter5_n2 | grep "vmov" -c
objdump -S -d laplacian_filter5_n3 | grep "vmov" -c
objdump -S -d laplacian_filter5_ns | grep "vmov" -c


laplacian_filter5.c を他のラプラシアンフィルタの実装に切り替えながら性能を測定した。

laplacian_filter5.c の結果を示す。
OpenMP_24_150720.png

laplacian_filter6.c の結果を示す。
OpenMP_25_150720.png

laplacian_filter7.c の結果を示す。
OpenMP_26_150720.png

laplacian_filter8.c の結果を示す。
OpenMP_27_150720.png

次に、OpenMP を使った時の各ラプラシアンフィルタ処理時間を測定した。
下に gcc-4.8 の -fopenmp オプションを付けた時の性能を比較するためのスクリプトを示す。

gcc -fopenmp laplacian_filter5.c -o laplacian_filter5_mp
gcc -fopenmp -O1 laplacian_filter5.c -o laplacian_filter5_mpO1
gcc -fopenmp -O2 laplacian_filter5.c -o laplacian_filter5_mpO2
gcc -fopenmp -O3 laplacian_filter5.c -o laplacian_filter5_mpO3
gcc -fopenmp -Os laplacian_filter5.c -o laplacian_filter5_mpOs
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math laplacian_filter5.c -o laplacian_filter5_mpn
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O1 laplacian_filter5.c -o laplacian_filter5_mpn1
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O2 laplacian_filter5.c -o laplacian_filter5_mpn2
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O3 laplacian_filter5.c -o laplacian_filter5_mpn3
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -Os laplacian_filter5.c -o laplacian_filter5_mpns
./laplacian_filter5_mp
./laplacian_filter5_mpO1
./laplacian_filter5_mpO2
./laplacian_filter5_mpO3
./laplacian_filter5_mpOs
./laplacian_filter5_mpn
./laplacian_filter5_mpn1
./laplacian_filter5_mpn2
./laplacian_filter5_mpn3
./laplacian_filter5_mpns
objdump -S -d laplacian_filter5_mp | grep "vmov" -c
objdump -S -d laplacian_filter5_mpO1 | grep "vmov" -c
objdump -S -d laplacian_filter5_mpO2 | grep "vmov" -c
objdump -S -d laplacian_filter5_mpO3 | grep "vmov" -c
objdump -S -d laplacian_filter5_mpOs | grep "vmov" -c
objdump -S -d laplacian_filter5_mpn | grep "vmov" -c
objdump -S -d laplacian_filter5_mpn1 | grep "vmov" -c
objdump -S -d laplacian_filter5_mpn2 | grep "vmov" -c
objdump -S -d laplacian_filter5_mpn3 | grep "vmov" -c
objdump -S -d laplacian_filter5_mpns | grep "vmov" -c


OpenMP を使った時の新しく作ったラプラシアンフィルタの性能を測定した。
laplacian_filter5.c に OpenMP用のプラグマを入れた。
OpenMP_32_150720.png

laplacian_filter5.c の結果を示す。
OpenMP_28_150720.png

laplacian_filter5.c のラプラシアンフィルタ結果を示す。今回は正常だ。
OpenMP_36_150720.jpg

laplacian_filter6.c に OpenMP用のプラグマを入れた。
OpenMP_33_150720.png

laplacian_filter6.c の結果を示す。
OpenMP_29_150720.png

laplacian_filter6.c のラプラシアンフィルタ結果を示す。今回は正常だ。
OpenMP_37_150720.jpg

laplacian_filter7.c に OpenMP用のプラグマを入れた。
OpenMP_34_150720.png

laplacian_filter7.c の結果を示す。
OpenMP_30_150720.png

laplacian_filter7.c のラプラシアンフィルタ結果を示す。今回は正常だ。
OpenMP_38_150720.jpg

laplacian_filter8.c に OpenMP用のプラグマを入れた。
OpenMP_35_150720.png

laplacian_filter8.c の結果を示す。
OpenMP_31_150720.png

laplacian_filter8.c のラプラシアンフィルタ結果を示す。今回も真ん中に線が入ってしまった。
OpenMP_39_150720.jpg

gcc-4.8 の各最適化オプションとNEON命令を追加した時、gcc-4.8 の OpenMPで 2 スレッドにした場合の性能を表にした。表中で同じ色の背景は出力位置は違っても同じ実装であることを示す。
最初にgcc-4.8 の各最適化オプションとNEON命令を追加した時の表を示す。
OpenMP_40_150720.png

gcc-4.8 の OpenMPで 2 スレッドにした場合の性能の表を示す。
OpenMP_41_150720.png

gcc-4.8 の OpenMP、-O3、laplacian_filter8.c で最速値 72.5 ms が計測できた。まだ、laplacian_filter8.c は結果がおかしいが最速値を計測することができた。一方、ラプラシアンフィルタの実行に関しては、1 core 使用した時と、2 core 使用した時では、あまり速度差が無いと言える。
  1. 2015年07月20日 07:56 |
  2. Zynq
  3. | トラックバック:0
  4. | コメント:0

OpenMPでのラプラシアンフィルタの実行速度3

OpenMPでのラプラシアンフィルタの実行速度2”の続き。

前回は、laplacian_fiter1 と laplacian_fiter2 のOpenMP を使うようにコンパイルして、実行した結果をブログに書いた。今回は、laplacian_fiter3 と laplacian_fiter4 をやってみた。

laplacian_fiter3.c を下に示すように、Cソースコードを修正した。
OpenMP_20_150717.png

2つ目の for ループの前に、

#ifdef _OPENMP
#pragma omp parallel for private(lap_fil_val, a, b, cam_fb_addr, lap_fb_addr)
#endif

を置いた。

このCソースコードを以下のコマンドで、コンパイル、実行、NEON命令の有無を調査した。

gcc -fopenmp laplacian_filter3.c -o laplacian_filter3_mp
gcc -fopenmp -O1 laplacian_filter3.c -o laplacian_filter3_mpO1
gcc -fopenmp -O2 laplacian_filter3.c -o laplacian_filter3_mpO2
gcc -fopenmp -O3 laplacian_filter3.c -o laplacian_filter3_mpO3
gcc -fopenmp -Os laplacian_filter3.c -o laplacian_filter3_mpOs
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math laplacian_filter3.c -o laplacian_filter3_mpn
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O1 laplacian_filter3.c -o laplacian_filter3_mpn1
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O2 laplacian_filter3.c -o laplacian_filter3_mpn2
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O3 laplacian_filter3.c -o laplacian_filter3_mpn3
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -Os laplacian_filter3.c -o laplacian_filter3_mpns
./laplacian_filter3_mp
./laplacian_filter3_mpO1
./laplacian_filter3_mpO2
./laplacian_filter3_mpO3
./laplacian_filter3_mpOs
./laplacian_filter3_mpn
./laplacian_filter3_mpn1
./laplacian_filter3_mpn2
./laplacian_filter3_mpn3
./laplacian_filter3_mpns
objdump -S -d laplacian_filter3_mp | grep "vmov" -c
objdump -S -d laplacian_filter3_mpO1 | grep "vmov" -c
objdump -S -d laplacian_filter3_mpO2 | grep "vmov" -c
objdump -S -d laplacian_filter3_mpO3 | grep "vmov" -c
objdump -S -d laplacian_filter3_mpOs | grep "vmov" -c
objdump -S -d laplacian_filter3_mpn | grep "vmov" -c
objdump -S -d laplacian_filter3_mpn1 | grep "vmov" -c
objdump -S -d laplacian_filter3_mpn2 | grep "vmov" -c
objdump -S -d laplacian_filter3_mpn3 | grep "vmov" -c
objdump -S -d laplacian_filter3_mpns | grep "vmov" -c

を実行した。
結果を示す。
OpenMP_12_150717.png

laplacian_fiter2.c の時と同様に、ラプラシアンフィルタの画像的には、左側はそれなりだが、右側が強調されている気がする。
OpenMP_17_150717.jpg


laplacian_fiter4.c を下に示すように、Cソースコードを修正した。
OpenMP_21_150717.png

filter_line() 関数の for () 文の前に、

#ifdef _OPENMP
#pragma omp parallel for private(lap_fil_val, current, next, prev)
#endif

を置いた。

このCソースコードを以下のコマンドで、コンパイル、実行、NEON命令の有無を調査した。

gcc -fopenmp laplacian_filter4.c -o laplacian_filter4_mp
gcc -fopenmp -O1 laplacian_filter4.c -o laplacian_filter4_mpO1
gcc -fopenmp -O2 laplacian_filter4.c -o laplacian_filter4_mpO2
gcc -fopenmp -O3 laplacian_filter4.c -o laplacian_filter4_mpO3
gcc -fopenmp -Os laplacian_filter4.c -o laplacian_filter4_mpOs
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math laplacian_filter4.c -o laplacian_filter4_mpn
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O1 laplacian_filter4.c -o laplacian_filter4_mpn1
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O2 laplacian_filter4.c -o laplacian_filter4_mpn2
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O3 laplacian_filter4.c -o laplacian_filter4_mpn3
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -Os laplacian_filter4.c -o laplacian_filter4_mpns
./laplacian_filter4_mp
./laplacian_filter4_mpO1
./laplacian_filter4_mpO2
./laplacian_filter4_mpO3
./laplacian_filter4_mpOs
./laplacian_filter4_mpn
./laplacian_filter4_mpn1
./laplacian_filter4_mpn2
./laplacian_filter4_mpn3
./laplacian_filter4_mpns
objdump -S -d laplacian_filter4_mp | grep "vmov" -c
objdump -S -d laplacian_filter4_mpO1 | grep "vmov" -c
objdump -S -d laplacian_filter4_mpO2 | grep "vmov" -c
objdump -S -d laplacian_filter4_mpO3 | grep "vmov" -c
objdump -S -d laplacian_filter4_mpOs | grep "vmov" -c
objdump -S -d laplacian_filter4_mpn | grep "vmov" -c
objdump -S -d laplacian_filter4_mpn1 | grep "vmov" -c
objdump -S -d laplacian_filter4_mpn2 | grep "vmov" -c
objdump -S -d laplacian_filter4_mpn3 | grep "vmov" -c
objdump -S -d laplacian_filter4_mpns | grep "vmov" -c

を実行した。
結果を示す。
OpenMP_13_150717.png

ラプラシアンフィルタ処理後の画像は、真ん中に縦に線が入ってしまった。それ以外は普通だ。
OpenMP_18_150717.jpg

OpenMP を使用したラプラシアンフィルタのみの各最適化オプションでの実行時間を表にまとめたので、下に示す。使用したコンパイラは gcc-4.8 だ。
OpenMP_22_150717.png

OpenMP を使用しない gcc の各最適化オプションのラプラシアンフィルタのみの処理時間の表を下に示す。
NEON_48_150714.png

上の2つの表を比較してみると、-O無しの場合は OpenMP が明らかに速いが、それ以外の場合はあまり速くなっていないことが分かる。
  1. 2015年07月18日 04:31 |
  2. Zynq
  3. | トラックバック:0
  4. | コメント:0

OpenMPでのラプラシアンフィルタの実行速度2

OpenMPでのラプラシアンフィルタの実行速度”の続き。

Vengineer さんからツイッターで、”forループ内のローカル変数をプラグマ内で定義しないと、おかしくなりますよ”とのアドバイスを頂いた。調べてみると、”#pragma omp parallel for”の後に”private(list)”を付ける必要があるようだ。
C言語による OpenMP 入門 ”の12ページ、”5.1 private(list) ”を参照すると、各スレッドで独自の変数値を持つためには、private 指示子が必要なようだ。

最初に laplacian_filter.c だが、以下の図の様にCソースコードを修正した。
OpenMP_14_150717.png

2つ目の for ループの前に、

#ifdef _OPENMP
#pragma omp parallel for private(lap_fil_val, fl, sl, tl, a, b)
#endif

を置いた。

このCソースコードを以下のコマンドで、コンパイル、実行、NEON命令の有無を調査した。

gcc -fopenmp laplacian_filter.c -o laplacian_filter1_mp
gcc -fopenmp -O1 laplacian_filter.c -o laplacian_filter1_mpO1
gcc -fopenmp -O2 laplacian_filter.c -o laplacian_filter1_mpO2
gcc -fopenmp -O3 laplacian_filter.c -o laplacian_filter1_mpO3
gcc -fopenmp -Os laplacian_filter.c -o laplacian_filter1_mpOs
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math laplacian_filter.c -o laplacian_filter1_mpn
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O1 laplacian_filter.c -o laplacian_filter1_mpn1
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O2 laplacian_filter.c -o laplacian_filter1_mpn2
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O3 laplacian_filter.c -o laplacian_filter1_mpn3
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -Os laplacian_filter.c -o laplacian_filter1_mpns
./laplacian_filter1_mp
./laplacian_filter1_mpO1
./laplacian_filter1_mpO2
./laplacian_filter1_mpO3
./laplacian_filter1_mpOs
./laplacian_filter1_mpn
./laplacian_filter1_mpn1
./laplacian_filter1_mpn2
./laplacian_filter1_mpn3
./laplacian_filter1_mpns
objdump -S -d laplacian_filter1_mp | grep "vmov" -c
objdump -S -d laplacian_filter1_mpO1 | grep "vmov" -c
objdump -S -d laplacian_filter1_mpO2 | grep "vmov" -c
objdump -S -d laplacian_filter1_mpO3 | grep "vmov" -c
objdump -S -d laplacian_filter1_mpOs | grep "vmov" -c
objdump -S -d laplacian_filter1_mpn | grep "vmov" -c
objdump -S -d laplacian_filter1_mpn1 | grep "vmov" -c
objdump -S -d laplacian_filter1_mpn2 | grep "vmov" -c
objdump -S -d laplacian_filter1_mpn3 | grep "vmov" -c
objdump -S -d laplacian_filter1_mpns | grep "vmov" -c

を実行した。
結果を示す。
OpenMP_10_150717.png

ラプラシアンフィルタ処理後の画面はやはり、前回と同じで、最初に........が余計に出ている。
OpenMP_15_150717.jpg


次に、laplacian_filter2.c をOpenMP を使用するように gcc でオプション付けてコンパイルした。以下の様にCソースコードを修正した。
OpenMP_19_150717.png

同様に、2つ目の for ループの前に、

#ifdef _OPENMP
#pragma omp parallel for private(lap_fil_val, a, b, cam_fb_addr, lap_fb_addr)
#endif

を置いた。

このCソースコードを以下のコマンドで、コンパイル、実行、NEON命令の有無を調査した

。gcc -fopenmp laplacian_filter2.c -o laplacian_filter2_mp
gcc -fopenmp -O1 laplacian_filter2.c -o laplacian_filter2_mpO1
gcc -fopenmp -O2 laplacian_filter2.c -o laplacian_filter2_mpO2
gcc -fopenmp -O3 laplacian_filter2.c -o laplacian_filter2_mpO3
gcc -fopenmp -Os laplacian_filter2.c -o laplacian_filter2_mpOs
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math laplacian_filter2.c -o laplacian_filter2_mpn
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O1 laplacian_filter2.c -o laplacian_filter2_mpn1
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O2 laplacian_filter2.c -o laplacian_filter2_mpn2
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -O3 laplacian_filter2.c -o laplacian_filter2_mpn3
gcc -fopenmp -mcpu=cortex-a9 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -ffast-math -Os laplacian_filter2.c -o laplacian_filter2_mpns
./laplacian_filter2_mp
./laplacian_filter2_mpO1
./laplacian_filter2_mpO2
./laplacian_filter2_mpO3
./laplacian_filter2_mpOs
./laplacian_filter2_mpn
./laplacian_filter2_mpn1
./laplacian_filter2_mpn2
./laplacian_filter2_mpn3
./laplacian_filter2_mpns
objdump -S -d laplacian_filter2_mp | grep "vmov" -c
objdump -S -d laplacian_filter2_mpO1 | grep "vmov" -c
objdump -S -d laplacian_filter2_mpO2 | grep "vmov" -c
objdump -S -d laplacian_filter2_mpO3 | grep "vmov" -c
objdump -S -d laplacian_filter2_mpOs | grep "vmov" -c
objdump -S -d laplacian_filter2_mpn | grep "vmov" -c
objdump -S -d laplacian_filter2_mpn1 | grep "vmov" -c
objdump -S -d laplacian_filter2_mpn2 | grep "vmov" -c
objdump -S -d laplacian_filter2_mpn3 | grep "vmov" -c
objdump -S -d laplacian_filter2_mpns | grep "vmov" -c

を実行した。
結果を示す。
OpenMP_11_150717.png

ラプラシアンフィルタの画像的には、左側はそれなりだが、右側が強調されている気がする。
OpenMP_16_150717.jpg
  1. 2015年07月17日 05:25 |
  2. Zynq
  3. | トラックバック:0
  4. | コメント:3

OpenMPでのラプラシアンフィルタの実行速度

今まで、NEON命令を使ってラプラシアンフィルタの実行速度を測ってきたが、今回はOpenMPを使って、高速化してみよう。
OpenMPとは複数のプロセッサを使ったマルチスレッディングを行うための API だそうだ。

参考にしたWebサイトは”OpenMP”と”gccのOpenMP実現について”だ。

まずは、”gccのOpenMP実現について”のhello.c をコンパイルして実行してみた。
ちなみに、”#incluce”だけではコンパイル・エラーだったので、”#incluede ”に変更した。

後は、同様に、gcc -fopenmp hello.c でコンパイルして、./a.out で実行した。
OpenMP_1_150716.png

Zynq は、Dual Core のCortex-A9 使用していて、2つのプロセッサなので、2プロセッサ使えるようだ。

次に laplacian_filter.c の 最初の for 文の前に”OpenMP”を参考にして、
#ifdef _OPENMP
#pragma omp parallel for
#endif

を入れてみた。
OpenMP_2_150716.png

gcc-4.8 で下のコマンドでコンパイルを行った。
gcc -fopenmp laplacian_filter.c -o laplacian_filter1_mp
コンパイルが正常に終了した。./laplacian_filter1_mp で動作させた。
OpenMP_3_150716.png

ラプラシアンフィルタ処理結果がおかしい。
OpenMP_7_150716.jpg

ラプラシアンフィルタのみの処理時間は、変動が大きいので、5回の平均を取った。その結果は、約 262 ms だった。
通常のlaplacian_filter1 のラプラシアンフィルタのみの処理時間は、425 ms なので、425 ms / 262 ms ≒ 1.62 倍速くなっているが、結果がおかしいのではしょうがない。

次に、laplacian_filter.c の次の for 文の前に
#ifdef _OPENMP
#pragma omp parallel for
#endif

を入れてみた。
OpenMP_4_150716.png

これで同様に、gcc -fopenmp laplacian_filter.c -o laplacian_filter1_mp
コンパイルが正常に終了した。./laplacian_filter1_mp で動作させた。
OpenMP_5_150716.png

今度は、ラプラシアンフィルタのみの処理時間は、約 243 ms だった。これも通常のラプラシアンフィルタのみの処理時間と比べてみよう。 425 ms / 243 ms ≒ 1.75 倍速かった。

今回のラプラシアンフィルタの処理画像は、最初に...... が入っているのが、バグのようだ。
OpenMP_8_150716.jpg

ちなみに、./laplacian_filter1 実行結果、つまり通常にコンパイルしたラプラシアンフィルタの処理画像を示す。
OpenMP_9_150716.jpg
  1. 2015年07月16日 05:28 |
  2. Zynq
  3. | トラックバック:0
  4. | コメント:0

gcc と clang で -Ofast 最適化オプションを付けた場合の実行速度

gcc-4.6, gcc-4.8, clang-3.4 とコンパイル時の最適化オプションによる速度の違いを検証してきた。
今回は、最適化オプションの -Ofast を gcc-4.6, gcc-4.8, clang-3.4 で試してみた。

最初は gcc-4.6 の -Ofast のみから。
NEON_40_150714.png

gcc-4.6 の自動ベクトル化の -Ofast
NEON_41_150714.png

gcc-4.8 の -Ofast のみ。
NEON_42_150714.png

gcc-4.8 の自動ベクトル化の -Ofast
NEON_43_150714.png

clang-3.4 でスクリプトを投入した。そのスクリプトを下に示す。

clang -Ofast laplacian_filter.c -o laplacian_filter1_Of
clang -Ofast laplacian_filter2.c -o laplacian_filter2_Of
clang -Ofast laplacian_filter3.c -o laplacian_filter3_Of
clang -Ofast laplacian_filter4.c -o laplacian_filter4_Of
clang -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=hard -Ofast laplacian_filter.c -o laplacian_filter1_nf
clang -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=hard -Ofast laplacian_filter2.c -o laplacian_filter2_nf
clang -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=hard -Ofast laplacian_filter3.c -o laplacian_filter3_nf
clang -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=hard -Ofast laplacian_filter4.c -o laplacian_filter4_nf
./laplacian_filter1_Of
./laplacian_filter2_Of
./laplacian_filter3_Of
./laplacian_filter4_Of
./laplacian_filter1_nf
./laplacian_filter2_nf
./laplacian_filter3_nf
./laplacian_filter4_nf


その結果を下に示す。
NEON_44_150714.png

gcc-4.6 でコンパイルした実行ファイルがNEON命令を使用しているか?を調べた。値が 0 でない実行ファイルがNEON命令を使用している。
NEON_45_150714.png

gcc-4.8 でコンパイルした実行ファイルがNEON命令を使用しているか?を調べた。値が 0 でない実行ファイルがNEON命令を使用している。
NEON_46_150714.png

clang-3.4 でコンパイルした実行ファイルがNEON命令を使用しているか?を調べた。値が 0 でない実行ファイルがNEON命令を使用している。
NEON_47_150714.png

gcc-4.6 と gcc-4.8 の -Ofast オプションのラプラシアンフィルタのみの処理時間を表に追加した。-Ofast は -O3 とほとんど変わらないようだ。
NEON_48_150714.png

clang-3.4 の -Ofast オプションのラプラシアンフィルタのみの処理時間を表に追加した。-Ofast は やはり -O3 とほとんど変わらないようだ。
NEON_49_150714.png
  1. 2015年07月14日 20:36 |
  2. Zynq
  3. | トラックバック:0
  4. | コメント:0
»