您的位置:首页 > 移动开发 > Android开发

Android-5.1-bootchart

2016-07-24 23:50 661 查看


1.Bootchart介绍

Bootchart是对GNU / Linux的启动过程的性能分析和可视化工具。在开机过程中会收集资源利用和处理信息,最后这些信息会呈现在一个PNG,SVG或EPS编码图上(官网英文介绍地址:http://www.bootchart.org/).


2.Bootchar调试

Bootchart代码已在Android的源代码中,需要我们修改对应的配置来启用bootchart.

system/core/init/Android.mk中,添加如下信息,打开BOOTCHART功能:

 LOCAL_PATH:= $(call my-dir)

 include $(CLEAR_VARS)

+INIT_BOOTCHART := true

system/core/init/bootchart.h中定义BOOTCHART:

 #ifndef BOOTCHART

-#define  BOOTCHART  0

+#define  BOOTCHART  1

 #endif

touch system/core/init/bootchart.c (更新文件)

mmm system/core/init/                   (重新编译init模块)

编译提示信息:target Symbolic: init (out/target/product/cht_cr_mrd/symbols/init)表示已经生成init程序,重新打包boot.img,烧录boot.img.

烧录完成后,系统开机,写入bootchart采集时间:

adb shell "echo 120 > /data/bootchart-start"

然后重启系统.(以上操作可以阅读官方文档:system/core/init/README.BOOTCHART)

这时候问题来了,/data/bootchart目录下本该有很多记录数据的文件,但居然没有产生!

log上提示”audit: type=1400 audit(1325552984.022:5): avc:  denied"权限问题,开始怀疑selinux问题导致,把main函数里的selinux_initialize()注释掉,即关闭selinux,但问题依旧。.

于是就开始跟踪分析bootchart代码,在init.c里

queue_builtin_action(bootchart_init_action, "bootchart_init");添加action正常.

有调用bootchart_init_action函数,此函数有执行,添加打印后发现此函数里bootchart_count的值居然为0!,代码如下

#if BOOTCHART

static int bootchart_init_action(int nargs, char **args)

{

    bootchart_count = bootchart_init();

ERROR("bootchart_init_action:bootchart_count %d\n",bootchart_count);

    if (bootchart_count < 0) {

        ERROR("bootcharting init failure\n");

    } else if (bootchart_count > 0) {

        ERROR("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS);

    } else {

        ERROR("bootcharting ignored\n");

    }

    return 0;

}

#endif

于是就继续跟代码到bootchart_init函数里.找到创建/data/bootchart目录的代码:

do {ret=mkdir(LOG_ROOT,0755);}while (ret < 0 && errno == EINTR);

添加打印,这里ret返回值为0,即创建/data/bootchart目录是成功的!,那为什么没有目录呢?冷静下来思考,怀疑是创建后被删除了?但是按照bootchart的设计,这个目录是用来保存数据,需要用户获取的,bootchart本身不会去删除的.所以在/data路径下手动创建此目录,重启后,该目录是存在的,排除了删除的可能.跟踪发现其他文件open返回值也是正常的,当时很奇怪.折腾了一整天,后来查看系统启动过程信息,分析发现在bootchart运行之后/data分区才挂载上来导致的!!!!!即bootchart_init里open/mkdir方式创建的这些目录和文件,全部被之后挂载的分区覆盖了!所以在不修改挂载前提下,就修改bootchart文件路径吧,山不过来,我就过去~找到问题点,修改就容易了,已知/dev目录在bootchart调用之前,是一定会先创建的.所以修改方法,就是把使用的路径从/data修改到/dev即可,修改如下:

--- a/system/core/init/bootchart.c

+++ b/system/core/init/bootchart.c

@@ -36,15 +36,17 @@

 

 #define VERSION         "0.8"

 #define SAMPLE_PERIOD   0.2

-#define LOG_ROOT        "/data/bootchart"

+#define LOG_ROOT        "/dev/bootchart"

 #define LOG_STAT        LOG_ROOT"/proc_stat.log"

 #define LOG_PROCS       LOG_ROOT"/proc_ps.log"

要注意启动bootchart需要读取LOG_STARTFILE文件的值(默认为/data/bootchart-start)来确定启动采样,目前data分区挂载的问题,无法使用,需要修改.尝试在/dev/下创建bootchart-start节点,并写入值,但是失败了,因为/dev目录下的文件在重启后是重新生成的,重启前创建的文件都不存在了,此方法不行. 于是就是去修改启动bootchart的条件的代码.一种方式是通过修改/proc/cmdline的androidboot.bootchart=值,另外一种就是直接修改修改bootchart_init函数里代码,本文采取后者:

proc_read( "/proc/cmdline", cmdline, sizeof(cmdline) );

s = strstr(cmdline, KERNEL_OPTION);

+//force to 180s

+timeout = 180;

重新编译,烧录.测试图表生成,打包bootchart图表源文件

adb shell

cd /dev/bootchart
busybox tar -czf bootchart.tgz header proc_stat.log proc_ps.log proc_diskstats.log kernel_pacct


exit

adb pull /dev/bootchart/bootchart.tgz ./


3.生成bootchart性能分析图

ubuntu上安装bootchart工具:

sudo apt-get install bootchart

运行bootchart解析所获取到的数据:

enhuiou@enhuiou-OptiPlex-3020:~/bootchart$ bootchart bootchart.tgz 

parsing 'bootchart.tgz'

parsing 'header'

parsing 'proc_stat.log'

parsing 'proc_ps.log'

Traceback (most recent call last):

  File "/usr/bin/bootchart", line 23, in <module>

    sys.exit(main())

  File "/usr/lib/pymodules/python2.7/pybootchartgui/main.py", line 111, in main

    options.crop_after, options.annotate)

  File "/usr/lib/pymodules/python2.7/pybootchartgui/parsing.py", line 248, in parse

    state = parse_paths(writer, ParserState(), paths)

  File "/usr/lib/pymodules/python2.7/pybootchartgui/parsing.py", line 237, in parse_paths

    state = _do_parse(writer, state, name, tf.extractfile(name))

  File "/usr/lib/pymodules/python2.7/pybootchartgui/parsing.py", line 201, in _do_parse

    state.ps_stats = _parse_proc_ps_log(writer, file)

  File "/usr/lib/pymodules/python2.7/pybootchartgui/parsing.py", line 88, in _parse_proc_ps_log

    userCpuLoad, sysCpuLoad = process.calc_load(userCpu, sysCpu, time - ltime)

  File "/usr/lib/pymodules/python2.7/pybootchartgui/samples.py", line 83, in calc_load

    userCpuLoad = float(userCpu - self.last_user_cpu_time) / interval

ZeroDivisionError: float division by zero

MD,报错了...

错误信息看,是存在除0的异常,查看这部分代码,interval存在为0的情况,所以在/usr/lib/pymodules/python2.7/pybootchartgui/samples.py报错的这行,添加如下代码在

if interval == 0:

   interval = 1

再次编译,会报同样除0的问题,修改方法与上面一样.

编译后生成png图片,打开如下所示:



这里有个问题,我们设置的是180s,实际上只采集了90秒左右,采集时间怎么少了90秒?

查看init.c代码里,发现for循环中,在执行的command是非常多的,每次循环的间隔并不是固定的200ms,而每次循环都会执行--bootchart_count操作,即bootchart希望每次执行的间隔是200ms,但init循环任务中处理的多个command,时间都不固定(即代码中"poll(ufds, fd_count, timeout);的timeout不固定"),所以这里的采集总时间就跟设定的所不同了.

图标上标示信息还是挺全的,如果还是不清楚,可以先阅读官网(http://www.bootchart.org/)samples栏的示例分析.


4.总结

在开机优化方面,可以通过以下几点来减少开机时间:

1.bootchart生成数据图表,查看是否存在长期占用资源的情况.

2.存储器从nand flash换为EMMC,并且多片改为单片,EMMC驱动设置为高速模式.

3.减少POWER按键开机检测时间,这个需要设置PMU的相关寄存器来实现,如AXP288,按键检测(36H寄存器),最长3s,最小128ms.

4.去除kernel中不需要的模块.

5.将内核打印等级设置为最高(8),查看内核执行过程中占用时间大的任务,分析解决(如有超时响应的任务,占用时间较长,要解决掉),当然正式版本打印信息是关闭的.

6.删除不需要的APK,减少开机预加载时间.

7.去除init.rc中不需要的服务.

8.清除systemserver.java中不需要的服务.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bootchart 开机加速