蜗窝科技

kernel启动优化

printk · · 阅读 22920 · 2015年4月存档

抛砖引玉,手有余香

由于老衲技术水平有限,以下梦话可能会有很多漏洞,希望各位大拿发现bug后,以强大的知识理论碾压老衲,让贫僧能在痛苦中疯狂成长。

—————————————————->\n

由于老衲最近在做车载linux kernel优化,特别是对启动时间的优化,从一开始的漫无目的,到现在的算是了解的过程,下了很大功夫。

特别是优化到最后2s以内,每10ms的优化太让人吐血了。杂话不多说,开整。

工欲善其事,必先利其器。

要调整启动时间,肯定得需要一个比较精确的时间戳,常用的有直接在kernel的menuconfig中选中printk_time,这样每条log前面都会打出相应的时间。这个就可以直接在menuconfig中配置,比较方便。但是精度不太高,因为选中printk_time也会影响启动时间。

这里推荐使用ckermit,直接嵌套minicom,配置完了之后可以将log重定向到一个文件中,在文件中对每条log就有详细的时间戳。

ubuntu系统直接sudo apt-get install ckemit

vim ~/.kermrc

set line /dev/ttyUSB0 #配置dbug串口
set speed 115200 #配置dbug uart速率
set carrier-watch off #
set handshake none
set flow-control none # 配置硬件流控
robust
set file type bin
set file name lit
set rec pack 1000
set send pack 10000
set windows 5
set protocol xmodem
set protocol zmodem
set session-log TIMESTAMPED-TEXT # 配置log重定向格式
log session #将log写入文件session中,此文件位于~/session
connect #自动链接串口,如果不写这条命令,需在进入ckermit 命令行后输入 c 或 connect

:wq! #保存退出

执行 sudo kermit

进入ckermit并自动链接串口,ps:如果想从串口退出 按下 “Ctrl + " 并输入 “q”

工具配置好后,放下,开始分析从哪优化

三军未动,粮草先行

kernel启动分为三部分

uboot引导 -> kernel载入启动 -> 挂载文件系统(跑初始化脚本)

1.uboot启动

对uboot不是很了解,希望有懂的大拿能协助我完成这部分内容。对这部分只是有点想法

首先,去除万恶的bootdelay,这部分最低也是1s。其次,去除不必要的在uboot部分启动的驱动,加入MMU(别问我为什么,关于加MMU这部分是另一位大神告诉我的,据说很有用,此处也希望各位大拿协助),跳过kernel的头部信息0-4k,直接从kernel的主启动部分down入内存。

首先要了解uboot是如何将kernel down入到内存中,根据硬件不同,uboot的配置也不同,但是优化点大同小异,本人使用的硬件平台如下

norflash:16m 放置uboot与kernel

emmc:4g 放置文件系统

Arm Cortex-A9架构的freescale imx6系列

所以在我的板子上,uboot需要将uImage从norflash中down入ram中。

那么,优化点来了。。。

拷贝数据肯定要用到memcpy,memset,特别是uImage还是比较大的(我裁剪完有2.9M),能将memcpy与memset的运行速度优化了,会直接减少启动时间,这里是用汇编写了一个memcpy 与 memset,众所周知,汇编的执行效率要大于C。此处大概优化几毫秒(这个地方是从2s 优化到 1.3s的过程中考虑到的。。)

2.kernel启动

首先uImage会有一个解压缩的过程,在编译的时候,会对uImage配置一个压缩算法,常用的有bz2,gzip,lzop,(貌似现在已经不支持bz2了)那么通过对比这几种压缩算法,找出一款最适合自己的。。。

Alogrithm % remaining MB/s Encoding MB/s Decoding

gzip 13.4 21 %2

lzop 20.5 135 410

bz2 XX XX XX

由于历史悠久,老衲已经忘却了bz2的压缩信息,不过确是与gzip差不多

那么由此看出,最适合老衲的就是lzop,因为空间大小完全不用考虑,很足够,但是解压速率是gzip的四倍不到,已经很快了。

其次就是lpj 熟悉的人一看见他就有种跳过的冲动,这货就是kernel启动时,check一下子,没什么用,只要前期都ok了,这部分就是skip用的

关于lpj的值,可以通过打log去判断,每一个硬件环境,lpj的值基本不同。

以上都是小点,little point, 其实占用时间最长的 就是 启动kernel时 加载各个模块,跑各个probe所占用的时间

这部分分为三部:

1)内核裁剪,将用不着的模块干掉。

2)优化所需build-in的启动时间

这里需要详细说一下,有个技巧,就是在kernel目录下的 init/main.c中 do_initcalls函数中

static void __init do_initcalls(void)
{
initcall_t *fn;
for (fn = __early_initcall_end; fn < __initcall_end; fn++){
// printk("==========================now will call : %p\n”,fn);
do_one_initcall(*fn);
}
}
将printk那行打开即可。

这里会调到所有注册在module_init段中的函数

换句话说就是你需要编译的module都会在这调用。那么就会很方便的 查看出哪个模块占用多少时间。从而去针对性的优化。

其他的 都是一些简单的,比如说优化log等级,优化开机logo,将无用模块搬入文件系统启动。(类似于延时启动)

3.文件系统优化

水太深,老衲用的还是比较旧的

由于各个文件系统不同,启动sequence也不一样。业内公认启动最快的是systemd,因为这货竟然是并发启动。

由于板子不同,需求不同,所以每个不同的系统的优化肯定有很多不同之处

希望大家多多讨论,将我没有 涉及到的,或者优化的不对的地方翻出来,一起研究研究。

以上。

继续讨论

新讨论请用 GitHub 账号在下方发言——评论会保存在本仓库的 Discussions 里,与站点同寿; 再下方的「历史评论」是原站的只读存档。

评论(22 条,只读存档)

以下为原站的历史评论(只读存档);继续讨论请用上方的评论区。

  • wowo

    发布的这篇文章没有“允许评论”,我帮你打开了,顺便分享一下我的一些经验: 1. 关于时间戳,依赖打印,总是不精确的。可以在启动的第一时间,start一个硬件timer,在后续的时间点中,通过timer的计时,精确获取耗时信息。 2. 到底要统计哪些过程的耗时,是需要经过仔细思考设计的。其实几个点就够了,目的性要强。 3. 最重要的,是要找出关键步骤的耗时(可能你已经找出来,但没有给大家贴下来哦)。 4. 关于u-boot,还是要搞清楚的,实在不行,就不用它了呗,自己写个。 5. kernel在norflash中,可以考虑加载和解压,哪个更耗时。说不定使用Image会更快(说不定)。
    • printk

      @wowo:大哥,我还没写完怎么就发出去了。。。。。。还有一部分那
      • wowo

        @printk:哈哈,是不是Linuxer直接给你审核通过了?
        • linuxer

          @wowo:这位骚年,没有编辑完成就不要点击发布哦,看你提交要求审核都一个星期了,不给你发布总觉得会打击年轻人的积极性,因此,我就稍微编辑了一下,然后审核通过了,^_^
          • printk

            @linuxer:可能是公司网不好,点错了把 - -
      • wowo

        @printk:没事,可以接着编辑。
        • printk

          @wowo:编辑完了,直接审核把~~~~~~
  • tastier

    大师,我也是做车载平台的(车联网),还在读研,大师方便透露自己的公司吗? 我们用的CPU是AMD Geode LX800,在车载方面,和大师用的A9哪个性能更好?
    • printk

      @tastier:你那个是属于低功耗的,低性能的,基于X86架构的片子,定位应该属于中低端市场把。。。。单纯比性能没什么意义,在车载方面,不需要太花哨的性能值,稳定与低功耗在短时间内,还是一直在统领车载市场的。毕竟安卓系统进入车载后,如果发生类似于安卓手机这种越用越卡,经常死机的情况的话,那就太危险了。 我们单位是一个老牌车载导航日企,名字不方便透露,抱歉!
      • tastier

        @printk:您现在的工作地点在哪?我以后也想进类似企业,谢谢
        • printk

          @tastier:大连,工作如娶老婆,不一定要找最好的,但是要找最合适的
  • Jacky

    我司的芯片,6Q.
  • von81

    @printk:可以给个你优化的例子吗?具体哪些点,耗时多少,做了哪些优化,优化后耗时多少。 还有个疑问:把kernel读出来 vs 解压kernel, 更大的kernel读出来的时间肯定更长,优化这个时间 vs 优化解压的时间,哪个更好,要对比一下吧? 就uboot来说,我感觉主要有两个功能,一个是把kernel拷贝到内存,另一个是调试。 在发布的时候,其实调试功能是不需要的,仅需要第一个功能。 firstboot也是可以把kernel拷贝到内存的,这样发布的时候就可以不要uboot了。 ps: 1、firstboot是指把uboot拷贝到内存的这个boot,imx6中可能不是这个名字。 2、建议楼主说明你优化的kernel和uboot版本。 kernel 3.0以上版本,大多用了设备树,uboot具有调试设备树的功能,所以uboot有可能悄悄改了设备树,如果不要uboot,需要确定uboot是如何改了设备树。 3、uboot一般是读取固定大小的kernel和文件系统进内存。例如kernel是2.9M,uboot可能固定读4M,不会去管真正的kernel是多大,建议楼主确认下你的uboot是否是这样。 还有两个记不清楚的地方,说出来供楼主参考。 我以前粗略看过kernel的汇编部分,记得在汇编里好像会把真正的kernel搬运到新的内存地址,这个地方应该也可以优化。 读内核时,开启dma,应该可以读的更快吧
  • littlekernel

    上次在网上搜资料的时候,看到这个网站上的文章,这个网站上所有的文章都是贵司内部工程师发出的吗? @wowo
    • linuxer

      @littlekernel:不是不是,蜗窝科技不是一个公司,就是一个技术交流的网站而已。主要发表文章的是两个人,wowo和linuxer,还有其他的热心网友而已。
      • tigger

        @linuxer:two pioneers will change the world!!
        • linuxer

          @tigger:过奖过奖,个人爱好而已,和热爱听音乐,看电影是一样的^_^
  • freshwater

    1.3s,比suspend to dram启动还要快?
  • song

    今天意外发现了这个网站,真是太好了! 更意外的是通过其他文章的评论里wowo的链接看到这篇文章后,我才发现原来之前来过这里,只是当时错过了~ 以后常来,向大家学习!
    • wowo

      @song:呵呵,有缘总会相见,很惭愧工作忙,能写的东西有限…… 欢迎常来,共同切磋~~
  • bsp

    优化经验之一: 在bootloader中打开cache(L1&L2),然后memcpy(uImage); 之后clean + invalid + disable所有cache,关闭mmu,进入kernel。 优化经验之二: 如果使用串口打印系统启动日志,串口波特率又过低(9600),是相对影响系统启动时间的。 可以提高打印日志的级别(启动参数加quiet),减少串口信息的输出,再试验。
  • passerby

    在ARM中DCACHE是与MMU绑定的,如果没有使能MMU则不能使用DCACHE。而CACHE对于CPU的性能有很大的影响,所以在UBOOT中使用了MMU会提高CPU的计算速度,使CPU的运行速度加快,从而使启动时间变慢。wowo里有篇文章就讲了使用cache和不使用cache时,CPU性能的巨大差距。