针对任何性能问题,我觉得第一步都先需要做如下三个确认:
性能问题中,超过 90% 都是和 APP 相关的,所以先来聊聊这方面的主要工具 systrace, 此篇文章主要讲讲调试方式,如果想了解怎么分析,可以看看我的第二篇文章 APP 启动,触摸事件和 UI 绘制的简单分析示例 和官方文档。
比较常用的方式是通过 Google 提供的 Python 脚本抓取 systrace, 我们可以在 SDK 或者 Android 源码中找到这个脚本,使用方式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
systrace.py gfx rs input view sched am wm camera dalvik freq idle load sync workq power mmc disk sm audio hal video app res binder_driver binder_lock -b 20480 -t 10 -o trace.html # -b trace buffer 大小,单位为 kb,建议 20M,太小会信息不足,太大会因内存不足而抓取不了 # -t 持续时间,单位为秒,时间必须覆盖问题现场,但是也不能太长,不然内存不足 # -o Systrace 输出的文件路径 # 需要抓取的 tags,一般情况下,我们可以全选。不同的 Android SDK 其 tags 有所不同, 可以通过如下方式查看。 systrace.py --list-categories gfx - Graphics input - Input view - View System wm - Window Manager am - Activity Manager hal - Hardware Modules res - Resource Loading dalvik - Dalvik VM power - Power Management sched - CPU Scheduling freq - CPU Frequency idle - CPU Idle ... |
有些性能问题只有在不连接 USB 的时候才能重现问题,我们就需要利用 atrace 来获取离线的 systrace。
确认如下先决条件是否满足:
1 2 |
a. adb root and adb remount is available b. /system/bin/atrace is available |
抓取 systrace
1 2 3 |
adb root && adb remount adb shell atrace -z -b 40960 gfx input view wm am hal res dalvik rs sched freq idle load disk mmc -t 15 > /data/local/tmp/trace_output & |
重连 USB 确认 atrace 进程是否结束。
1 |
adb shell ps -t | grep atrace |
atrace 如已完成,取出 dump。
1 |
adb pull /data/local/tmp/trace_output |
将 dump 转换为 systrace。
1 |
systrace.py --from-file trace_output -o output.html |
当我们需要深入剖析某一个进程的耗时时,我们可以通过 traceview 跟踪的程序的性能,查看每个方法执行的时间。
1 2 3 4 5 6 7 8 9 |
# |
当遇到 APP 启动问题时,我们可以使用 profiling 来帮助我们定位问题,首先我们需要在其 activity 中添加 profiling 的代码,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Debug.startMethodTracing("MainActivity Trace" ); //trace begin } @Override protected void onStart() { super.onStart(); Debug.stopMethodTracing(); //trace end } } |
然后,我们就可以通过如下指令去获取 trace 帮助我们分析:
1 2 3 4 |
adb shell am start -n |
使系统运行于 performance 模式,查看一下问题是否存在。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
adb shell root adb shell setenforce 0 adb shell stop thermal-engine adb shell rmmod core_ctl # CPU 性能模式 adb shell "echo 1 > /sys/devices/system/cpu/cpu1/online" adb shell "echo 1 > /sys/devices/system/cpu/cpu2/online" adb shell "echo 1 > /sys/devices/system/cpu/cpu3/online" ... adb shell "echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor" adb shell "echo performance > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor" adb shell "echo performance > /sys/devices/system/cpu/cpu2/cpufreq/scaling_governor" adb shell "echo performance > /sys/devices/system/cpu/cpu3/cpufreq/scaling_governor" ... # GPU 性能模式 adb shell "echo 1 > /sys/class/kgsl/kgsl-3d0/force_rail_on" adb shell "echo 1 > /sys/class/kgsl/kgsl-3d0/force_clk_on" adb shell "echo 1 > /sys/class/kgsl/kgsl-3d0/force_bus_on" adb shell "echo 10000000 > /sys/class/kgsl/kgsl-3d0/idle_timer" adb shell "echo performance > /sys/class/kgsl/kgsl-3d0/devfreq/governor" adb shell "echo 0 > /sys/class/kgsl/kgsl-3d0/bus_split" # DDR 性能模式 adb shell "echo 1 > /sys/kernel/debug/msm-bus-dbg/shell-client/mas" adb shell "echo 512 > /sys/kernel/debug/msm-bus-dbg/shell-client/slv" adb shell "echo 0 > /sys/kernel/debug/msm-bus-dbg/shell-client/ab" adb shell "echo 16 * DDR max frequency > /sys/kernel/debug/msm-bus-dbg/shell-client/ib" adb shell "echo 1 > /sys/kernel/debug/msm-bus-dbg/shell-client/update_request" |
写在“死马当活马医”的最前面,在使用如下这些方式时,记得多和对比机对比。
获取 thermal-engine 的调试日志,查看是否有限制动作。
1 2 3 |
adb shell stop thermal-engine adb shell thermal-engine --debug & adb shell logcat -v time -s ThermalEngine > |
Perfd 是 QCOM 开发的一个和性能相关的后台程序。默认情况下会开机自启动,其对机器性能至关重要,所以我们需要确保其已启动。
1 2 |
adb shell ps |grep perfd root 4326 1 8704 844 futex_wait 7fa7af1984 S /system/vendor/bin/perfd |
我们也可以打开 perfd 的调试日志,然后抓取 logcat 和 systrace, 以便获取更多的调试信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 方法一: adb pull /system/build.prop echo "debug.trace.perf=1" >> build.prop adb push build.prop /system/ adb shell chmod 0644 /system/build.prop adb shell sync adb shell reboot # 方法二: adb shell root adb shell setenforce 0 adb shell setprop debug.trace.perf 1 adb shell stop perfd adb shell start perfd |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ adb shell getprop | grep "pm.dexopt" [pm.dexopt.ab-ota]: [speed-profile] [pm.dexopt.bg-dexopt]: [speed-profile] [pm.dexopt.boot]: [verify] [pm.dexopt.first-boot]: [quicken] [pm.dexopt.inactive]: [verify] [pm.dexopt.install]: [quicken] [pm.dexopt.shared]: [speed] # pm.dexopt.install # 从性能上来说 verify < quicken < speed-profile < speed # 编译和安装速度 verify > quicken > speed-profile > speed |
dexopt 宏: odex 开关
可以通过调整堆内存的初始大小(dalvik.vm.heapstartsize)来优化性能,不过此方案需谨慎。
1 2 3 4 5 6 |
# device/qcom/msmxxx/msmxxx.mk PRODUCT_PROPERTY_OVERRIDES += \ dalvik.vm.dex2oat-filter=interpret-only \ dalvik.vm.image-dex2oat-filter=speed\ dalvik.vm.heapminfree=4m \ dalvik.vm.heapstartsize=16m |
我比较喜欢结合如下两条命令进行分析,主要查看是否有异常进程,比如长时间暂用 CPU。
1 2 |
adb shell top -m 5 while true; do adb shell dumpsys cpuinfo; sleep 1; done | tee cpu_usage.txt |
我主要使用如下内存和 IO 的工具,一般还需要结合 top、ps
等工具来一起定位导致内存泄漏的进程。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
adb shell dumpsys meminfo free vmstat iostat pmap PID adb shell pull /d/ion # 可以检查heaps来确定cached ION memory. adb shell cat /d/kgsl/proc/*/mem > kgsl_mem.txt # 可以用例看每个processgfx所用的memory. adb shel cat /proc/meminfo adb shell cat /proc/zoneinfo # 获得更准确的memoryinfo adb shell cat /d/shrinker # 查看可以 free的memory 大小及其优先级. adb shell cat /sys/class/kgsl/kgsl/page_alloc # kgsl /1024/1024 gfx 分配的size adb shell cat /sys/kernel/debug/ion/heaps/system # ION total /1024/1024 |
一般和系统相关的性能问题,我也会对比一下 event。
1 |
adb logcat -b events |
遇到 Camera 相关的问题,一般需要通过如下方式增加 trace。
1 2 3 4 |
1. adb root 2. adb shell "echo 1 > /d/tracing/events/camera/enable" 3. adb shell "echo 1 > /d/tracing/tracing_on" 4. 在对应界面添加 Trace.beginSection 和 Trace.endSection标签 |
如上是我试验过的一些调试方法,如下两篇高通文档中,有更多针对常见问题的调试方式和解决方案。
80-np885-1_c_graphics_power_and_performance_overview.pdf
[80-p0584-1_b_common-performance-issues-debugging-guide.pdf](http://sorry-it-is-prietary/80-p0584-1_b_common performance issues debugging guide.pdf)
提供一份获取主要性能信息的脚本源码,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
#================================================================= # Script of capturing CPU, procrank, memory and top information with time interval. mkdir PerfLogs cd PerfLogs rm ./*.txt echo "Start..." while : do echo "Perf" MYDATE=`date +%y-%m-%d_%H:%M:%S` echo $MYDATE # Print current CPU frequency # Modify below lines based on CPU core number. echo "" echo "${MYDATE}" >> cpuinfo_cur_freq.txt & echo "cpu0 cur freq:`cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq`" >> cpuinfo_cur_freq.txt & echo "cpu1 cur freq:`cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq`" >> cpuinfo_cur_freq.txt & echo "cpu2 cur freq:`cat /sys/devices/system/cpu/cpu2/cpufreq/scaling_cur_freq`" >> cpuinfo_cur_freq.txt & echo "cpu3 cur freq:`cat /sys/devices/system/cpu/cpu3/cpufreq/scaling_cur_freq`" >> cpuinfo_cur_freq.txt & echo "cpu4 cur freq:`cat /sys/devices/system/cpu/cpu4/cpufreq/scaling_cur_freq`" >> cpuinfo_cur_freq.txt & echo "cpu5 cur freq:`cat /sys/devices/system/cpu/cpu5/cpufreq/scaling_cur_freq`" >> cpuinfo_cur_freq.txt & echo "cpu6 cur freq:`cat /sys/devices/system/cpu/cpu6/cpufreq/scaling_cur_freq`" >> cpuinfo_cur_freq.txt & echo "cpu7 cur freq:`cat /sys/devices/system/cpu/cpu7/cpufreq/scaling_cur_freq`" >> cpuinfo_cur_freq.txt & echo "${MYDATE}" >> procrank.txt & procrank >> procrank.txt & echo "${MYDATE}" >> proc_meminfo.txt & cat /proc/meminfo >> proc_meminfo.txt & echo "${MYDATE}" >> meminfo.txt & dumpsys meminfo >> meminfo.txt & echo "${MYDATE}" >> top.txt & top -t -m 8 -n 1 >> top.txt & sleep 60 #60 seconds, you can modify the time interval. done |