oprofile

Android上oprofile使用說明

1.目的

本文介紹了oprofile的功能並基於Android 2.1介紹了使用oprofile的基本方法和步驟。本文的讀者爲軟件開發人員和白盒測試人員。

2.oprofile簡介

Oprofile是用於Linux的若干種評測和性能監控工具中的一種,它可以工作在不同的體系結構上,包括IA32、IA64、AMDAthlon系列及ARM等。Oprofile包含在Linux2.5和更高版本的內核中,也包含在大多數較新的Linux發行版本中,在Android中已經集成了Oprofile。

oprofile以很低的開銷對系統中所有運行的代碼(包括kernel、kernel模塊、庫、應用程序)進行函數級別的性能分析(function-level profiling),跟蹤佔用CPU高的函數的調用信息,從而判斷程序中哪些地方存在需要優化的性能瓶頸。

oprofile支持兩種採樣(sampling)方式:基於事件的採樣(event based)和基於時間的採樣(time based)。

基於事件的採樣是oprofile只記錄特定事件(比如L2 cachemiss)的發生次數,當達到用戶設定的定值時oprofile就記錄一下(採一個樣)。這種方式需要CPU內部有性能計數器(performance counter)。

基於時間的採樣是oprofile藉助OS時鐘中斷的機制,每個時鐘中斷oprofile都會記錄一次(採一次樣),又分爲RTC模式(RTC mode,適用於2.2/2.4內核)和定時器中斷模式(timer interrupt mode,適用於2.6以上內核)。引入定時器採樣模式的目的在於,提供對沒有性能計數器的CPU的支持,其精度相對於基於事件的採樣要低,並且因爲要藉助OS時鐘中斷的支持,對禁用中斷的代碼oprofile不能對其進行分析。

高通QSD8K處理器具備性能計數器,但當前發佈的軟件版本只支持定時器模式。

在Android上,oprofile分爲target端和host端兩部分。target端運行在設備上,主要包括一個內核模塊(oprofile.ko)和一個用戶空間的守護進程(oprofiled),前者負責訪問性能計數器或者註冊基於時間採樣的函數(使用register_timer_hook註冊之,使時鐘中斷處理程序最後執行profile_tick時可以訪問之),並採樣置於內核的緩衝區內;後者在後臺運行,負責從內核空間收集數據,寫入文件。host端運行在PC上,包括一組後處理工具用於從原始採樣數據生成可讀的分析報告。

3.oprofile使用方法

本節基於Android 2.1 (Eclair)介紹oprofile的使用方法,在Android 1.6 (Donut)和Android 2.2 (Froyo)上的使用方法與之相似。

在使用oprofile之前,首先必須確保燒到手機上的系統具有root權限,否則無法使用oprofile,並確保/data下有足夠的可用空間用於保存採樣數據(一般幾十MB足夠)。依次按照如下步驟操作。

3.1步驟一:安裝target

Android源代碼中已經包含了移植好的oprofile源代碼,kernel缺省配置選項也已經enable了對oprofile的支持。在將oprofile的target端安裝到手機之前,請首先在eng模式下編譯源代碼,然後按照如下步驟將所需文件複製到手機上:

1.內核模塊oprofile.ko:

在PC上運行:

sourcebuild/envsetup.sh

choosecombo

adb push$ANDROID_PRODUCT_OUT/obj/KERNEL_OBJ/arch/arm/oprofile/oprofile.ko/data

2.守護進程oprofiled和控制程序opcontrol:

如果手機上燒的system.img是eng模式編出來的,裏面已經包含了oprofiled和opcontrol(在/system/xbin/),這一步可以跳過;如果是user模式編出來的system.img則不包含這兩個文件,請運行:

adbpush $ANDROID_PRODUCT_OUT/system/xbin/oprofiled/system/xbin

adb push$ANDROID_PRODUCT_OUT/system/xbin/opcontrol /system/xbin

3. elf內核映像文件:

如果要對內核進行profiling,需要將壓縮的elf內核映像文件vmlinux複製到手機上,運行:

adb push$ANDROID_PRODUCT_OUT/obj/KERNEL_OBJ/arch/arm/boot/compressed/vmlinux/data

該vmlinux必須與手機上實際運行的內核一致。

3.2步驟二:計算內核虛擬地址範圍

要對內核進行profiling,需要計算內核開始和結束地址:

運行:

adb pull /proc/kallsyms .

在文件kallsyms中查找_text,其數值即爲kernel start地址;查找_etext,其數值即爲kernel end地址。

3.3步驟三:將CPU設置在保持最高頻率運行

爲確保oprofile採樣結果的準確性和一致性,在採樣開始之前需將CPU設置在保持最高頻率運行,爲此在adb shell中運行:

mkdir /data/debug

mount -t debugfs debugfs /data/debug

echo 1 >/data/debug/nohlt

echo performance >/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

3.4步驟四:配置oprofile

在adb shell中運行:

insmod /data/oprofile.ko timer=1

opcontrol --setup

oprofiled --session-dir=/data/oprofile--vmlinux=/data/vmlinux --kernel-range=start,end--events=CPU_CYCLES:255:0:50000:0:1:1 --separate-lib=1--separate-kernel=1

說明:

其中--kernel-range中的start和end即爲上述步驟二中獲得的kernel start地址和kernel end地址。

3.5步驟五:開始採樣

運行需要進行profiling的應用程序或場景,然後在adb shell中運行:

opcontrol --start

此時oprofile已開始採樣,可在adb shell中運行:

opcontrol --status

隨時查看oprofile運行狀態和已採集的樣本數。

3.6步驟六:停止採樣

當採集的樣本數足夠多的時候(根據經驗一般數千即可),在adb shell中運行:

opcontrol --stop

3.7步驟七:上傳數據和生成分析結果

在PC上運行:

source build/envsetup.sh

choosecombo

cp $ANDROID_PRODUCT_OUT/obj/KERNEL_OBJ/vmlinux$ANDROID_PRODUCT_OUT/symbols

python$ANDROID_BUILD_TOP/external/oprofile/opimport_pull~/oprofile-result

此時手機上的採樣數據經轉換後存在PC上~/oprofile-result中,運行以下命令顯示分析結果報告:

cd ~/oprofile-result

$OPROFILE_EVENTS_DIR/bin/opreport--session-dir=. -p $ANDROID_PRODUCT_OUT/symbols -d -l

(注:在Android 2.1(Eclair)中執行上面的命令出錯,需將opreport換成自己編譯的0.9.4版本的opreport,編譯步驟參見本文附錄。)

注意:執行以上步驟時若遇到如下出錯信息:

opreport: error while loading shared libraries:libbfd-2.18.0.20080103.so: cannot open shared object file: No suchfile or directory

可運行如下命令予以解決:

ln -s /usr/lib/libbfd.so/usr/lib/libbfd-2.18.0.20080103.so

3.8重新運行oprofile

上述步驟一至七完成了一次完整的oprofile採樣和分析過程,若要再次運行oprofile,需復位oprofile並清理上一次的採樣數據,在adb shell中運行:

opcontrol --shutdown

rm/data/oprofile

umount/data/debug

rm -rf/data/debug

然後重新執行上述步驟三至七進行下一次的採集和分析。

4.簡化oprofile使用步驟的腳本

從上文的介紹可以看到oprofile的使用比較複雜,爲簡化使用步驟,特編寫若干腳本,只需按照如下步驟運行這些腳本即完成oprofile的各項操作:

1.工作環境準備:①在eng模式下編譯源代碼;②爲使用oprofile創建一個工作目錄(例如~/oprofile),將下面附的壓縮包oprofile_cmd.zip解開到該目錄下,並進入到該目錄下;③按照前文3.2節的方法獲取kernel start地址和end地址填入op.sh;④確保燒到手機上的系統具有root權限,且所編譯的內核源代碼與手機上實際運行的內核一致;⑤確保運行過choosecombo;

2.安裝target端:用數據線連接手機和PC,在PC上的oprofile工作目錄下運行:

./prepare.sh

(注:若系統是Android 1.6 (Donut),則運行./prepare.sh donut)

3.採樣:運行需要進行profiling的應用程序或場景,然後在adb shell中運行:

cd/data

shop.sh

此時可運行opcontrol --status查看oprofile運行狀態和已採集的樣本數,當採集的樣本數足夠多的時候(根據經驗一般數千即可),在adb shell中運行:

opcontrol --stop

4.上傳數據:在PC上的oprofile工作目錄下運行:

./import.sh

5.顯示分析結果:在PC上的oprofile工作目錄下運行:

./report.sh

6.重新運行oprofile:在adbshell中運行:

cd/data

shopclean.sh

然後重新執行上述步驟3至5。

5.oprofile分析結果實例

下面是在Android2.1 (Eclair)上對一個運行alphaanimation的應用程序進行oprofile分析的結果:

CPU: CPU with timer interrupt, speed 0 MHz(estimated)

Profiling through timerinterrupt

TIMER:0|

samples|%|

------------------

1769 98.4418 app_process

TIMER:0|

samples|%|

------------------

1299 73.4313 libskia.so

386 21.8202 vmlinux

39 2.2046libdvm.so

17 0.9610libc.so

9 0.5088libui.so

4 0.2261libbinder.so

4 0.2261libsurfaceflinger.so

4 0.2261libutils.so

3 0.1696libandroid_runtime.so

1 0.0565libGLES_android.so

1 0.0565gralloc.qsd8k.so

1 0.0565libm.so

1 0.0565libstdc++.so

13 0.7234rild

TIMER:0|

samples|%|

------------------

9 69.2308 vmlinux

4 30.7692 linker

6 0.3339vmlinux

4 0.2226cnd

TIMER:0|

samples|%|

------------------

2 50.0000 linker

1 25.0000 cnd

1 25.0000 vmlinux

2 0.1113adbd

TIMER:0|

samples|%|

------------------

2 100.000 vmlinux

1 0.0556init

TIMER:0|

samples|%|

------------------

1 100.000 vmlinux

1 0.0556port-bridge

TIMER:0|

samples|%|

------------------

1 100.000 vmlinux

1 0.0556opcontrol

TIMER:0|

samples|%|

------------------

1 100.000 vmlinux

samples %p_w_picpath nameapp namesymbol name

55430.8292libskia.soapp_processS32A_Opaque_BlitRow32_neon

45625.3756libskia.soapp_processS32A_D565_Blend_neon(unsigned short*, unsigned int const*, int,unsigned int, int, int)

1287.1230vmlinuxapp_process__memzero

1136.2883libskia.soapp_processmemset_128_loop

784.3406libskia.soapp_processmemset_128_loop

653.6171vmlinuxapp_process_spin_unlock_irqrestore

201.1130vmlinuxapp_processget_page_from_freelist

181.0017libskia.soapp_processSprite_D32_S32::blitRect(int, int, int, int)

170.9460vmlinuxapp_processv7wbi_flush_user_tlb_range

160.8904vmlinuxapp_processfree_hot_cold_page

150.8347libskia.soapp_processSprite_D16_S32_BlitRowProc::blitRect(int,int, int, int)

130.7234vmlinuxapp_process_spin_unlock_irq

120.6678libdvm.soapp_processdalvik_inst

120.6678libskia.soapp_processSkDraw::drawPaint(SkPaint const&)const

110.6121vmlinuxapp_process__dabt_usr

110.6121vmlinuxapp_processv7_dma_flush_range

100.5565libskia.soapp_processS32A_D565_Opaque_Dither(unsigned short*, unsigned int const*, int,unsigned int, int, int)

...

從以上結果可以看出,在運行alpha animation的過程中,在oprofile採樣數據中2D圖形庫libskia.so佔了最高的比例,達73.4313%,具體是libskia.so中的函數S32A_Opaque_BlitRow32_neon和S32A_D565_Blend_neon分別佔了最高的前二名,說明在這一過程中最影響性能的瓶頸是在skia庫中的這幾個函數。

附錄關於在Android1.6 (Donut)上使用oprofile的注意事項

Android 1.6(Donut)中自帶的opimport和opreport(位於$OPROFILE_EVENTS_DIR/bin/)是64位的,只能在安裝了64位Linux系統的PC上運行,要在32位系統的PC上運行,解決方法是自己編譯0.9.4版本的opimport和opreport(因Android 1.6 (Donut)中自帶的oprofile是0.9.4版本的)。0.9.4版本oprofile源代碼附在下面:(略)

編譯步驟如下:

sourcebuild/envsetup.sh

choosecombo

tar-zxvf oprofile-0.9.4.tar.gz

cdoprofile-0.9.4

./configure--with-linux=$ANDROID_PRODUCT_OUT/obj/KERNEL_OBJ

make

makeinstall

或者採用Android2.1 (Eclair)以上版本中自帶的opimport和opreport(版本爲0.9.5)也可以。

此外Android 1.6(Donut)中的腳本$ANDROID_BUILD_TOP/external/oprofile/opimport_pull有問題,可替換成Android 2.1(Eclair)以上版本中的此文件。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章