转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就行了。祝各位好运!

更多相关文章

  1. getSystemService获得系统服务列表
  2. Android(安卓)5.1源码编译环境搭建
  3. Android版网络办公系统应用客户端+服务端
  4. Andriod编译内核模块*.ko
  5. Android温故之-Activity
  6. 基于ubuntu16.04多用户编译android N(android 7.1)系统提示ninja
  7. android图书管理系统+javaweb后台服务器代码
  8. UBI文件系统
  9. Android(安卓)Notification使用系统通知栏布局出现的图标问题

随机推荐

  1. Android画板
  2. Android(安卓)开发艺术探索笔记之十 -- A
  3. Android从零开始-Android工程的目录结构
  4. 错误ava.lang.RuntimeException: Unable
  5. 升级Android内置apk版本
  6. Android开发环境配置简介
  7. 用于替代 Android(安卓)自带 Dialog 和 P
  8. Android(安卓)最全面试题汇总(问题+答案+
  9. 深入理解Android(安卓)WebView
  10. adb devices找不到设备