做性能优化绕不开开机启动时间的优化,用户往往都希望自己的机器能够快速的启动,这种强烈的需求覆盖各种电子设备,本篇主要简单的介绍Android设备启动时间的计时工具——bootchart以及简单的优化。
1. bootchart工具的使用
Bootchart是一个用于Linux启动过程性能分析的开源软件工具,以可视化的方式对GUN/Linux的开机启动过程进行性能分析,包括资源的使用(如CPU,磁盘等),各进程的执行时间信息等。根据分析结果,确定系统启动的性能瓶颈,制定相应的优化策略。由于Android系统是基于Linux的,所以我们可以使用Bootchart来分析开机性能。实际上在Android中已经集成了Bootchart这一开源工具供我们使用,只是在Android5.1之前默认是没有编译进系统的,需要我们手动编译进去使用,这里不再赘述在Android5.1以下系统如何使用Bootchart,从Android6.0开始,Google已经在Android系统中默认集成了Bootchart,adb shell
命令进入设备后,可以看到有一个/data/bootchart
目录。因为bootchart本身会影响性能,所以默认没有打开Bootchart开关,/data/bootchart
目录下什么东西都没有。下面介绍在Android O中的使用方法:
adb shell touch /data/bootchart/enabled
重新启动设备,启动后会发现在
/data/bootchart/
目录下生成了如下文件:1
2
3
4
5
6
7adb shell ls -l data/bootchart/
total 4792
-rw-rw-rw- 1 root root 0 2018-03-13 10:58 enabled
-rw-rw-rw- 1 root root 1115 1970-02-02 00:32 header
-rw-rw-rw- 1 root root 180357 2018-03-13 11:18 proc_diskstats.log
-rw-rw-rw- 1 root root 4635657 2018-03-13 11:18 proc_ps.log
-rw-rw-rw- 1 root root 80531 2018-03-13 11:18 proc_stat.log电脑连接手机,执行android源码中的脚本:
./system/core/init/grab-bootchart.sh
,随后就会在执行命令的目录下生成bootchart.png
1.1 grab-bootchart.sh
先来看一下脚本内容:
1 | !/bin/sh |
由于现在使用的开发环境ubuntu为远程主机,无法连接手机,所以直接把/data/bootchart/
目录下生成的文件打包成bootchart.tgz,然后copy到ubuntu机器,直接使用bootchart /tmp/android-bootchart/bootchart.tgz
命令生成bootchart.png。
如果ubuntu机器中的bootchart无法执行,或者没有安装其他工具,可使用如下命令安装:
1 | sudo apt-get install bootchart |
1.2 compare-bootcharts.py
Google还给我们提供了一个比较脚本/system/core/init/compare-bootcharts.py用来比较两次开机的数据。需要将两次打包得到的两个压缩包bootchart.tgz分别保存在base_bootchart_dir和exp_bootchart_dir目录中,然后运行下面的命令来执行脚本:
1 | root@ubuntu:~/work/Ored $ ./system/core/init/compare-bootcharts.py base_bootchart_dir exp_bootchart_dir |
这个脚本中只比较了几个重要的核心进程(init、surfacefliger、bootanimation、zygote64、zygote、system_server、bootanimation)的启动时间。
1.3 bootchart.png
生成的bootchart.png如下图所示:
通过图片中的时间线timeline上各个进程的启动、IO处理等,我们大致可以分析在开机过程中哪个部分比较耗时,我们能够大致清楚了从系统启动到Android启动完成后的主要时间,同时也能够简单的分析出kernel启动时间,zygote启动时间,sysetmserver启动时间,看出哪个部分比较耗时,待查找出后去重点优化,但是这个工具还是不能把Android 启动阶段毕竟清晰的展现出来,这个时候就需要使用到开机events log信息了。
2 系统启动架构图
3. 如何debug
开机时间分为2部分,一个是内核空间,另一个是用户空间,需要关注的有如下几点:
Kernel config:在
kernel/arch/arm64/configs/
目录下有2个配置文件,分别是xxx_defconfig和xx-perf_defconfig;- xxx_defconfig:包含kernel的debug信息,性能差;
- xxx-perf_defconfig:移除了kernel的debug信息,性能好;
抓取log:包含kernel、events和adb log;
- ``` shell
adb wait-for-device root
adb wait-for-device
adb shell dmesg > dmesg.txt // kernel log
adb logcat -b events -d > logcat_events.txt // events log
adb logcat -v time thread -d > logcat.txt // adb log1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- 如果以上log不能获取足够的信息,则抓取Ftrace log,抓取方法参考文档:[点我下载](https://pan.baidu.com/s/1TZa8S4ljTdAUdEIgMVYUKw) ,密码:iegy
#### 4. log分析
##### 4.1 kernel log
**bootloader的时间**
``` powershell
[ 0.350199] KPI: Bootloader start count = 70361
[ 0.350204] KPI: Bootloader end count = 100035
[ 0.350208] KPI: Bootloader display count = 3623140379
[ 0.350212] KPI: Bootloader load kernel count = 5008
[ 0.350217] KPI: Kernel MPM timestamp = 119237
[ 0.350221] KPI: Kernel MPM Clock frequency = 32768
- ``` shell
NHLOS time: A/D=70361/32768=2.15s
LK time: (B-A)/D=(100035-70361)/32768=0.91s
Boot loader :C/D-kmsg(C)=119237/32768-0.35=3.29s
驱动初始化耗时
1 | 01-29 20:39:54.040 0 0 I KPI : Bootloader start count = 70361 |
耗时大概为2.52s,使用如下修改打开调试开关,
1 | // kernel/init/main.c |
打开后可以看到初始化前后的log,从而对比哪个驱动模块耗时长。
Zygote启动前的command耗时
1 | 01-29 20:39:57.799 0 0 I init : init second stage started! // init第二阶段初始化开始 |
耗时大概为5.82s,Init程序里默认对耗时超过50ms的command会打印log进行警告:
1 | 01-29 20:39:59.327 0 0 I init : Command 'wait_for_coldboot_done' action=wait_for_coldboot_done (<Builtin Action>:0) returned 0 took 1472ms. |
Wait_for_coldboot_done由于是冷启动,需要等待sys必要节点创建完成,因此时间会比较长;
mount_all /vendor/etc/fstab.qcom 为需要解析fatab.qcom表内容以及挂载分区;
另外此阶段还有解析rc文件和prop文件,给文件和节点打selinux标签耗时,这部分耗时一般和硬件性能有关(CPU和emmc)。
1 | 01-29 20:39:57.807 0 0 I init : Running restorecon... // 开始给文件和节点打selinux标签 |
4.2 events log
1 | adb logcat -b events | grep boot_progress |
启动阶段 | 时间点(ms) | 花费时间(ms) | 备注 |
---|---|---|---|
boot_progress_start | 10453 | 10453 | Linux kernel启动到Zygote进程启动的时间,包含从kernel启动到Init启动Zygote的时间 |
boot_progress_preload_start | 11684 | 1231 | ART虚拟机启动耗时/Zygote开始启动 |
boot_progress_preload_end | 12545 | 770 | 虚拟机资源装载耗时/Zygote启动结束 |
boot_progress_system_run | 12796 | 251 | System Server进程启动耗时 |
boot_progress_pms_start | 13101 | 305 | Android一些在PMS前需要启动服务的启动耗时,package scan开始 |
boot_progress_pms_system_scan_start | 13255 | 154 | system目录开始scan时间点 |
boot_progress_pms_data_scan_start | 14157 | 902 | data目录开始scan时间点/system目录扫描耗时 |
boot_progress_pms_scan_end | 14164 | 7 | 扫描结束时间点/data目录扫描耗时 |
boot_progress_pms_ready | 14392 | 1291 | PMS启动扫描包耗时(pms_ready~pms_start) |
boot_progress_ams_ready | 15153 | 761 | PMS后的系统服务启动时间 |
boot_progress_enable_screen | 15792 | 639 | AMS启动完成后开始激活屏幕 |
sf_stop_bootanim | 17153 | 1361 | |
wm_boot_animation_done | 17155 | 2 | 从enable_screen到animation_done包含壁纸和keyguard的绘制时间 |
以上数据为优化后的数据,主要涉及到配置源码中/kernel/arch/arm64/config/xxx-perf_defconfig
,关闭不必要的配置,尤其是串口log,以及camera驱动优化,TP优化等待,更多优化后续持续更新。
引用:
http://blog.csdn.net/ljp1205/article/details/78360701
http://blog.csdn.net/whurs/article/details/67062678