四.Gprof在Zynq-7000開發板上的實驗:
Hardware: ZC706 evaluation board(其他開發板亦可,只是細節上會略有不同)
Software: Xilinx 14.7 Linux pre-built
Tool chain: PetaLinux 2013.04 tool chain
為了簡單起見,筆者沒有重新編譯Linux,而是使用的Xilinx 14.7 Linux pre-built。
在Linux Host上下載libjpeg后執行以下命令即可完成編譯:
cd
tar zxvf /path/to/jpegsrc.v9.tar.gz
cd jpeg-9
./configure --prefix=/home/wave/xilinx/libjpeg/jpeg-bin --host=arm-xilinx-linux-gnueabi
Note: 參數--prefix指明編譯結果的安裝位置,參數--host指明交叉編譯工具鏈的前綴。在使用PetaLinux 2013.04 tool chain之前需要先到其目錄下source settings.sh
這里需要編輯Makefile,在CFLAGS和LDFLAGS中增加-pg選項。
make
make install
這時編譯完成后的可執行程序cjpeg和djpeg使用到了.so文件,不適合用gprof。關于這一點可以用ldd命令確認。所以還需要用以下命令手工編譯出statically linked binary,拷貝到libjpeg安裝目錄下的bin目錄下,方便后期的profiling。這些命令可以通過觀察libjpeg的make過程得到。
arm-xilinx-linux-gnueabi-gcc -std=gnu99 -g -O2 -pg -o djpeg-s djpeg.c wrppm.c wrgif.c wrtarga.c wrrle.c wrbmp.c rdcolmap.c cdjpeg.c ../jpeg-bin/lib/libjpeg.a
arm-xilinx-linux-gnueabi-gcc -std=gnu99 -g -O2 -pg -o cjpeg-s cjpeg.c rdppm.c rdgif.c rdtarga.c rdrle.c rdbmp.c rdswitch.c cdjpeg.c ../jpeg-bin/lib/libjpeg.a
然后將jpeg-bin下的所有內容打包,和Xilinx 14.7 Linux pre-built image files,以及數據文件park-2880x1800.jpg拷貝到SD卡中,從SD卡啟動ZC706開發板。
在開發板的console上,執行以下命令
mount /dev/mmcblk0p1 /mnt
mkdir work
cd work
tar zxvf /mnt/jpeg-bin.tar.gz
cd jpeg-bin/bin
cp /mnt/park-2880x1800.jpg .
export LD_LIBRARY_PATH=/home/root/work/jpeg-bin/lib
time ./djpeg-s -bmp park-2880x1800.jpg > result.bmp
mv gmon.out gmon-ds.out
time ./cjpeg-s ./result.bmp > ./result.jpg
mv gmon.out gmon-cs.out
對于djpeg-s和cjpeg-s,執行時間如下所示。我們可以看到這兩個應用程序的主要執行時間實在用戶空間的,還是比較適合用gprof來做profiling的。
real 0m4.258s
user 0m4.200s
sys 0m0.050s
real 0m4.289s
user 0m4.230s
sys 0m0.050s
然后我們可以把執行結果拷貝到SD卡中,準備拿到Linux Host上進行分析。
cp result.* /mnt
cp gmon*.out /mnt
umount /mnt
在Linux Host上,我們可以通過以下命令看到profiling的結果:
gprof -b djpeg-s gmon-ds.out >report-ds.txt
gprof -b cjpeg-s gmon-cs.out >report-cs.txt
關于JPEG解碼Profiling結果的主要部分如下:
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
20.95 0.31 0.31 1800 0.17 0.17 ycc_rgb_convert
19.60 0.60 0.29 40680 0.01 0.01 jpeg_idct_16x16
17.57 0.86 0.26 20340 0.01 0.02 decode_mcu
14.87 1.08 0.22 81000 0.00 0.00 jpeg_idct_islow
13.51 1.28 0.20 finish_output_bmp
6.08 1.37 0.09 1175224 0.00 0.00 jpeg_fill_bit_buffer
5.41 1.45 0.08 put_pixel_rows
2.03 1.48 0.03 127506 0.00 0.00 jpeg_huff_decode
關于JPEG編碼Profiling結果的主要部分如下:
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
24.63 0.50 0.50 preload_image
21.18 0.93 0.43 20340 0.02 0.02 encode_mcu_huff
13.79 1.21 0.28 40680 0.01 0.01 jpeg_fdct_16x16
12.81 1.47 0.26 81180 0.00 0.01 forward_DCT
8.87 1.65 0.18 81000 0.00 0.00 jpeg_fdct_islow
8.37 1.82 0.17 1800 0.09 0.09 rgb_ycc_convert
5.42 1.93 0.11 1 110.00 110.00 get_24bit_row
3.45 2.00 0.07 __divsi3
0.49 2.01 0.01 113 0.09 10.27 compress_data
0.49 2.02 0.01 __aeabi_uidivmod
0.49 2.03 0.01 jpeg_fdct_ifast
怎么樣?是不是很容易?
如果反復profiling幾次,就會注意到profiling結果里面的順序會有所變化。主要原因還是采樣的時間太短,只有4.2秒,如果延長profiling的時間,得到的結果會更加逼近真實值。
五.關于sprof:
sprof主要用于Gprof的補充,分析程序的共享庫(需要-g編譯)。一般的使用步驟:
1. export LD_PROFILE_OUTPUT=${PWD}
2. export LD_PROFILE=abc.so.A.B
3. export LD_LIBRARY_PATH=/path/to/lib/
4. 執行使用該so的主程序
5. 執行sprof so_file_name.so so_file_name.so.profile
注意:在實際執行時發現LD_PROFILE指向的文件名后有可能需要加上實際的數字才可以。
在本次實驗中,在生成profiling report的時候會發生錯誤:
sprof libjpeg.so.9 libjpeg.so.9.profile
Inconsistency detected by ld.so: dl-open.c: 611: _dl_open: Assertion `_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT' failed!
按照Google Search Result的說法,在老版本的glibc里面會有這個問題,新版本有可能已經解決了。不過因為oprofile完全可以profiling shared library,所以只是簡單的嘗試了一下,沒有繼續深入研究這個話題。上面的經驗或許會對有興趣的開發者有所借鑒。
六.小結:
盡管gprof有各種這樣那樣的限制和不足,如果能夠合理規避,對于代碼執行時間大部分是在用戶空間的計算密集型的應用程序,gprof還是非常方便好用的。
評論
查看更多