题目有点大,其实kernel的启动性能调整和android基本没什么关系,我想应该适用所有使用linux的嵌入式设备
时间测量
说到性能调整,第一件该干的的事就是看下时间到底消耗在哪里。俗话说的好:知己知彼,百战百胜;过度优化,万恶之首
因此手头上要有称心如意的时间测试工具,方法。其实我是不太喜欢工具的,工具这东西可遇不可求,而且不如写代码顺手。
1. PRINTK_TIME
在内核编译选项中打开CONFIG_PRINTK_TIME,重新编译内核后,系统启动后就可以看到每一条printk前都有一个时间戳了,这样就有个大概的轮廓,哪
个驱动消耗了更多的时间,当然这个信息对我们性能调整来说粒度太粗了
2. initcall_debug宏
上面的PRINTK_TIME只是在printk附加上当时的系统时间,对于那些没有printk信息输出的驱动来说是无法提供启动时间信息的,initcall_debug派上了用场,打开这个宏后,每个驱动的初始化起始时间和结束时间都打印出来了。有了这个时间,基本就可以确定哪些部分需要优化了。我的做法是只关注耗时10000us以上的驱动。
3. ktime_t
调用ktime_get 获取时间,我最喜欢的时间测量方法,对于可疑的耗时函数,可如下测试
ktime_t start, end;
start = ktime_get()
candidate_func(arg...)
end = ktime_get()
printk(KERN_ALERT "%s: start time=%d.%d, end time=%d.%d\n", __func__, start.tv.sec, start.tv.nsec, end.tv.sec, end.tv.nsec);
可以很准确的计算candidate_func的时间,当然如果candidate_func中引发了调度,时间就没那么准确了。
4 printk
尽量去掉printk对时间测量的影响,可以调整kernel/printk.c中的DEFAULT_CONSOLE_LOGLEVEL宏,把级别较低的信息去掉
性能优化方法
1. hard code lpj,在uboot启动参数增加 lpj=3997696. 其中的3997696替换为你的机器启动信息获取的值,这个一般能节省200ms
2. 裁剪内核,这块比较大,要单独开一篇来介绍,裁剪的好处有两点:第一减少kernel的尺寸,这也就相应的减少了加载kernel image的时间,第二也减少了不必要的初始化
3. 代码调整:
根据时间测试,找到耗时瓶颈,看看是否能进行优化。
4. 优化设备IO驱动,提高数据的读写速度,kernel启动完成到android launcher完成,几乎无处不涉及到文件的读写,IO速度对启动时间的影响重大,代码是人写的,所以平台特定的IO代码绝对有优化的空间
性能优化结果
最终优化后的结果是kernel从启动到init.rc大概需要0.5秒左右,当然具体优化到什么程度,和kernel需要加载的驱动是密切相关的。