Android性能測試工具--Oprofile


轉http://blog.csdn.net/louieuser/article/details/6152175
Android應用的性能如何測試?JAVA層面可以用TraceView,可是用NDK開發出來的是so,TraceView跟蹤不了怎么辦?問了Google大神,答案是OProfile!
Oprofile 是Linux系統下一個低開銷的系統全局的性能監視工具,利用處理器上所包含的專用的性能監視硬件(若沒有性能監視硬件則使用一個基於計時器的代用品)來收集與性能相關的數據樣品。它獲得關於內核以及系統上的可執行文件的信息,例如內存是何時被引用的;L2緩存請求的數量;收到的硬件中斷數量等。
Oprofile的特點如下:
l         無需重新編譯源代碼,如果不進行源代碼及分析,連調試信息(-g option to gcc)也不是必須的。
l         只在內核中插入一個模塊。
l         可以分析運行於系統之上的所有代碼(禁用中斷的代碼除外)
l         系統的額外開銷小,Oprofile會增加1%-8%的系統開銷(取決於采樣頻率)
l         兼容所有2.2,2.4,2.6內核,可以運行在SMP系統之上
l         支持主流CPU架構,包括X86、arm、AVR32、mips、powerpc等
Oprofile要想跑在Andorid上,要滿足下面的條件:
1.內核要支持
2.要將Oprofile移植到Arm平台上
 
下面是移植的全過程:
一、Oprofile移植
用到的交叉編譯工具如下:
arm-2010.09-50-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2
用到的庫如下:
popt-1.14.tar.gz 
binutils-2.21.tar.gz
oprofile-0.9.6.tar.gz
 
$ tar xvfz arm-2010.09-50-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2 -C ~/
修改~/.bashrc,添加
export PATH=${PATH}:/home/louieli/arm-2010.09/bin
 
$ tar zxvf popt-1.14.tar.gz 
$ cd popt-1.14
$ ac_cv_va_copy=yes ./configure --with-kernel-support --host=arm-none-linux-gnueabi --prefix=/home/louieli/work/popt
$ make
$ make install
 
$ tar zxvf binutils-2.21.tar.gz
$ cd binutils-2.21/
$ ./configure --with-kernel-support --host=arm-none-linux-gnueabi --prefix=/home/louieli/work/binutils --enable-shared
$ make LDFLAGS="-all-static"
可能會出現 cc1: warnings being treated as errors,找到出錯文件的Makefile文件,將-Werror去掉
$ make install
 
$ tar zxvf oprofile-0.9.6.tar.gz
$ cd oprofile-0.9.6/
$ ./configure --with-kernel-support --host=arm-none-linux-gnueabi --prefix=/home/louieli/work/oprofile/ --with-extra-libs=/home/louieli/work/popt/lib/ --with-extra-includes=/home/louieli/work/popt/include/ --with-binutils=/home/louieli/work/binutils
$ make LDFLAGS="-all-static -L/home/louieli/work/binutils/lib -Xlinker -R -Xlinker /home/louieli/work/binutils/lib  -L/home/louieli/work/popt/lib/"
$ make install
用file 命令查看,我們需要的oprofile文件都已經變成可以在android上跑的靜態鏈接文件了
install.sh: Bourne-Again shell script text executable
opannotate: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, for GNU/Linux 2.6.16, not stripped
oparchive:  ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, for GNU/Linux 2.6.16, not stripped
opcontrol:  a /system/bin/sh script text executable
opgprof:    ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, for GNU/Linux 2.6.16, not stripped
ophelp:     ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, for GNU/Linux 2.6.16, not stripped
opimport:   ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, for GNU/Linux 2.6.16, not stripped
opjitconv:  ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, for GNU/Linux 2.6.16, not stripped
opreport:   ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, for GNU/Linux 2.6.16, not stripped
oprofiled:  ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, for GNU/Linux 2.6.16, not stripped
 
 
二、編譯linux內核映像
a)准備交叉編譯工具鏈
android代碼樹中有一個prebuilt項目,包含了我們編譯內核所需的交叉編譯工具。
 
b)設定環境變量
$ emacs ~/.bashrc
增加如下兩行:
export PATH=$PATH:~/android/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin
export ARCH=arm
保存后,同步變化:
$ source ~/.bashrc
 
c)獲得合適的內核源代碼
$ cd ~/android
獲得內核源代碼倉庫
$ git clone git://android.git.kernel.org/kernel/common.git kernel
$ cd kernel
$ git branch
顯示
* android-2.6.27
說明你現在在android-2.6.27這個分支上,也是kernel/common.git的默認主分支。
顯示所有head分支:
$ git branch -a
顯示
* android-2.6.27
remotes/origin/HEAD -> origin/android-2.6.27
remotes/origin/android-2.6.25
remotes/origin/android-2.6.27
remotes/origin/android-2.6.29
remotes/origin/android-goldfish-2.6.27
remotes/origin/android-goldfish-2.6.29
我們選取最新的android-goldfish-2.6.29,其中goldfish是android的模擬器模擬的CPU。
$ git checkout -b android-goldfish-2.6.29 origin/android-goldfish-2.6.29
$ git branch
顯示
android-2.6.27
* android-goldfish-2.6.29
我們已經工作在android-goldfish-2.6.29分支上了。
 
d)設定交叉編譯參數
打開kernel目錄下的Makefile文件,把CROSS_COMPILE指向剛才下載的prebuilt中的arm-eabi編譯器
CROSS_COMPILE ?= arm-eabi-
LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,/
$(call ld-option, -Wl$(comma)–build-id,))
這一行注釋掉,並且添加一個空的LDFLAGS_BUILD_ID定義,如下:
LDFLAGS_BUILD_ID =
 
e)編譯內核映像
$ cd ~/android/kernel
$ make goldfish_defconfig
$ make menuconfig
修改內核配置如下
General setup --->
[*] Profiling support (EXPERIMENTAL)
[ ] Activate markers
[*] OProfile system profiling (EXPERIMENTAL) 
這是把OProfile直接編進內核,也可以選擇[M] OProfile system profiling (EXPERIMENTAL)會在arch/arm/oprofile文件夾下生成oprofile.ko,oprofile.ko需要用insmod載入。
$make 
 
f)測試生成的內核映像
$ emulator -avd myavd -kernel ~/android/kernel/arch/arm/boot/zImage
 
三、Oprofile在android模擬器中的使用
1.先看一下opcontrol的參數
# opcontrol
opcontrol: usage:
   -l/--list-events list event types and unit masks
   -?/--help        this message
   -v/--version     show version
   --init           loads the oprofile module and oprofilefs
   --setup          give setup arguments (may be omitted)
   --status         show configuration
   --start-daemon   start daemon without starting profiling
   -s/--start       start data collection
   -d/--dump        flush the collected profiling data
   -t/--stop        stop data collection
   -h/--shutdown    stop data collection and kill daemon
   -V/--verbose[=all,sfile,arcs,samples,module,misc,ext]
                    be verbose in the daemon log
   --reset          clears out data from current session
   --save=name      save data from current session to session_name
   --deinit         unload the oprofile module and oprofilefs
   -e/--event=eventspec
      Choose an event. May be specified multiple times. Of the form
      "default" or "name:count:unitmask:kernel:user", where :
      name:     event name, e.g. CPU_CLK_UNHALTED or RTC_INTERRUPTS
      count:    reset counter value e.g. 100000
      unitmask: hardware unit mask e.g. 0x0f
      kernel:   whether to profile kernel: 0 or 1
      user:     whether to profile userspace: 0 or 1
   -p/--separate=type,[types]
       Separate profiles as follows :
       none:     no profile separation
       library:  separate shared library profiles per-application
       kernel:   same as library, plus kernel profiles
       thread:   per-thread/process profiles
       cpu:      per CPU profiles
       all:      all of the above
   -c/--callgraph=#depth         enable callgraph sample collection with a maximum depth.
                                 Use 0 to disable callgraph profiling.
   --session-dir=dir             place sample database in dir instead of
                                 default location (/var/lib/oprofile)
   -i/--image=name[,names]       list of binaries to profile (default is "all")
   --vmlinux=file                vmlinux kernel image
   --no-vmlinux                  no kernel image (vmlinux) available
   --kernel-range=start,end      kernel range vma address in hexadecimal
   --buffer-size=num             kernel buffer size in sample units
   --buffer-watershed            kernel buffer watershed in sample units (2.6 only=
   --cpu-buffer-size=num         per-cpu buffer size in units (2.6 only)
   --note-table-size             kernel notes buffer size in notes units (2.4 only)
 
   --xen                         Xen image (for Xen only)
   --active-domains=<list>       List of domains in profiling session (for Xen only)
                                 (list contains domain ids separated by commas)
 
 
 
2.使用方法
將我們之前編譯好的oprofile和busybox裝入模擬器
執行oprofile目錄中的install.sh 將oprofile裝入模擬器
adb push busybox /data/busybox
$adb shell  //進入模擬器shell
#chmod 777 /data/busybox
# /data/busybox --install /data/busybox
#export PATH=/data/busybox:$PATH:/data/oprofile
# mount -o remount rw /
# mount -o rw,remount -t yaffs2 /dev/mtdblock3 /system
# touch /etc/mtab
# echo nodev /dev/oprofile oprofilefs rw 0 0>/etc/mtab
# mkdir /dev/oprofile
# mount -t oprofilefs nodev /dev/oprofile    //這一句很重要,沒有這一句會出現下面的錯誤
 
# opcontrol --init      
cat: can't open '/dev/oprofile/cpu_type': No such file or directory
Unable to open cpu_type file for reading
Make sure you have done opcontrol --init
cpu_type 'unset' is not valid
you should upgrade oprofile or force the use of timer mode
 
# opcontrol --init     //初始化,只需運行一次
# opcontrol --setup --callgraph=2 --session-dir=/data/first --no-vmlinux
Using 2.6+ OProfile kernel interface.
Using log file /data/first/samples/oprofiled.log
Daemon started.
Profiler running.
# opcontrol --status
Daemon running: pid 637
Separate options: none
vmlinux file: none
Image filter: none
Call-graph depth: 2
# opcontrol --start     //啟動profiler
Using 2.6+ OProfile kernel interface.
Using log file /var/lib/oprofile/samples/oprofiled.log
Daemon started.
Profiler running.
# /data/test/test     //運行我們的程序 ( 我的測試程序通過這條指令編譯arm-none-linux-gnueabi-gcc -g -o test test.c -static -fno-omit-frame-pointer)
in c
in a
in b
in a
in c
in b
in a
in a
# opcontrol --dump   //收集采樣數據
# opcontrol --stop //停止profiler
Stopping profiling.
#opreport --session-dir=/data/first -l /data/test/test       //查看報告
CPU: CPU with timer interrupt, speed 0 MHz (estimated)
Profiling through timer interrupt
samples  %        symbol name
11291    79.9589  a
1129      7.9952  b
853       6.0406  main
848       6.0052  c
現在我們就可以根據oprofile的輸出對我們的程序進行優化了。
如果有哪位同學也想試一把的話,一定要用linux。這種移植環境很重要,我之前就在測試機(win7+cygwin)上浪費了很多時間。這里有打包好的工具,大家可以下載。其中kernel-qemu就是我們之前編譯好的內核,替換掉Android SDK中的kernel-qemu就行了。祝各位好運!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM