导读:嵌入式Linux在应用中每每但愿系统能在尽可能短的时间内启动,以提升用户体验。并且在有的应用场合,对启动时间具备严格的时间要求,尤为在工业或者医疗器械应用领域。此时如何加快Linux的启动,将成为一个挑战,对于大多数应用开发人员而言,因为Linux系统的复杂性,对于如何提升启动速度,每每无从下手。那么阅读完本文,将得到清晰完整的解决思路。linux
1.下降启动时间的通常思路
git
在准备下降系统的启动时间时,思路上应创建如下的切入点:github
最快的代码是未执行的代码。缓存
引导操做本质上的很大一部分工做其实是将代码和数据从存储设备加载到RAM。如所需加载内容越少则意味着加载操做越快。 安全
若是根文件系统越大,则安装时间可能会越长。微信
所以,即便未执行的代码也会延长启动时间。架构
另外在硬件方案设计时尽可能选择读写速度快的存储介质。例如,从SD卡启动实际上比从NAND FLASH启动快。函数
2.启动时间测量方法工具
要下降系统的启动时间,则首先须要选择一个可靠的启动时间的测量方法:性能
在Linux代码中加入对某一个GPIO脚的逻辑电平控制,利用示波器测量GPIO状态。后面将介绍如何在代码中加入对GPIO的控制。
监控串口控制台报文以测量时间,可使用grabserial。
参见https://elinux.org/Grabserial
3. 工具链优化
3.1 从工具链入手
选择使用合适的工具链,应是第一个入手点,由于全部的运行加载固件都是由工具链编译而成。若是还没有进行其余优化,则更改工具链的好处将更加明显,而且更容易度量。
您能够在工具链中进行如下更改,这可能会影响启动时间,性能和大小:
编译器版本:gcc和binutils的版本,最新版本每每能够具备更好的优化功能。
C库:glibc,uClibc,musl。使用uClibc和musl库编译的根文件系统更小
指令集变量:ARM或Thumb2,是否支持硬浮点。
可能会影响代码性能和代码大小(Thumb2编码与ARM相同的指令,但以更紧凑的方式,至少会显着减少大小)。
C库在建立工具链时进行了硬编码,可供选择的C库:
glibc:最标准且功能最全。http://www.gnu.org/software/libc/
uClibc:更小且可配置。已经存在约20年了。http://uclibc-ng.org/
musl:uClibc替代品,虽比较新但很成熟。http://www.musl-libc.org/
能够对glibc/uclibc-ng /musl进行对比测试:
1.静态编译hello.c程序并比较大小
使用gcc 6.3, armel, musl 1.1.16: 7300 字节
使用gcc 6.3, armel, uclibc-ng 1.0.22 : 67204 字节
使用gcc 6.2, armel, glibc: 492792 字节
2. 静态编译BusyBox 1.26.2并比较大小
使用gcc 6.3, armel, musl 1.1.16: 183348 字节
使用gcc 6.3, armel, uclibc-ng 1.0.22 : 210620 字节
使用gcc 6.2, armel, glibc: 755088 字节
3.2 指令集选择
编译rootfs进行测试对比:
用gcc 7.4编译,生成ARM代码:
根文件系统总大小:3.79 MB
用gcc 7.4编译,生成Thumb2代码:
根文件系统总大小:3.10 MB(-18%)
性能方面:Thumb2的性能明显改善(大约少于5%,可是从一次运行到另外一次运行,测量的执行时间略有变化)。
4. 应用软件优化
4.1 测量strace
strace容许跟踪应用程序及其子级进行的全部系统调用。对于开发很是有用:
了解如何在用户空间上花费时间
例如,轻松查找打开尝试(open()),文件访问(read() /write() )和内存分配(mmap2() )。无需访问源代码便可完成!
寻找耗时最长的开销应用
查找在应用程序和脚本中完成的没必要要的工做。例如:屡次打开同一文件,或尝试打开不存在的文件。
局限性:您没法跟踪init进程!
关于strace 参见
http://sourceforge.net/projects/strace/:
在全部GNU / Linux系统上可用,能够由您的交叉编译工具链生成器构建。
更简单的办法:直接拷贝一个现成的静态二进制文件。 参见
https://github.com/bootlin/static-binaries/tree/master/strace
能够查看进程的操做状况:
1. 访问文件,分配内存...
2. 一般足以发现简单的错误。
用法:
1.strace <命令>(开始一个新进程)
2.strace -p <pid>(跟踪现有进程)strace -c <command>(统计进程的系统开销时间)
如查看cat操做:
又如统计进程的调用时间:
4.2 Linux上的性能监测工具oprofile
Oprofile是linux上的性能监测工具:
具备两种工做方式:legacy模式和perf_events模式
legacy模式:
1.精度低,请使用内核驱动程序进行配置
2.使用CONFIG_OPROFILE进行编译配置
3.用户空间工具:opcontrol和oprofiled
perf_events模式:
1.使用硬件性能计数器
2.使用CONFIG_PERF_EVENTS和CONFIG_HW_PERF_EVENTS编译配置
3.用户空间工具:operf
其使用方法:
legacy 模式:
opcontrol --vmlinux=/path/to/vmlinux # optional step
opcontrol --start
/my/command
opcontrol --stop
perf_events 模式
operf --vmlinux=/path/to/vmlinux /my/command
利用opreport获取结果
例如:
4.3 perf工具
Perf 是内置于Linux 内核源码树中的性能剖析(profiling)工具。它基于事件采样原理,以性能事件为基础,支持针对处理器相关性能指标与操做系统相关性能指标的性能剖析。可用于性能瓶颈的查找与热点代码的定位。linux2.6及后续版本都自带该工具,几乎可以处理全部与性能相关的事件
使用硬件性能计数器
使用CONFIG_PERF_EVENTS和CONFIG_HW_PERF_EVENTS进行配置
用户空间工具:性能。它是内核源代码的一部分,所以始终与您的内核同步。
用法:perf record /my/command
经过如下方式得到结果:perf report
例如:
4.4 链接器优化
启动时使用的应用程序组代码:
查找启动期间调用的功能,例如使用
-finstrument-functions gcc选项。
建立一个自定义的连接描述文件,以按调用顺序从新排列这些函数。能够经过将每一个函数放在各自的部分中来实现:
-ffunction-sections gcc选项。
特别对于具备较大MTD读取块的闪存存储特别有用。由于读取整个读取块后,极有可能读取没必要要的数据。
详细信息:http://blogs.linux.ie/caolan/2007/04/24/controlling-symbol-ordering/
经过以下方法,能够找到有望被优化的地方:
1.启动一次应用程序并测量其启动时间。
2.再次启动应用程序并测量其启动时间。因为它的代码应仍在Linux文件缓存中,故其代码加载时间将为零。
从而知道第一次加载应用程序代码(及其库)所花费的时间。连接器优化节省的时间应少于此上限。
而后据此能够决定是否有必要这样对该应用进行连接优化。因为连接优化必须修改应用程序的编译方式,所以此类优化的成本很高。
4.4.1 Prelink 预连接工具
Prelink是Red Hat 开发者 Jakub Jelinek 所设计的工具,正如其名字所示,Prelink利用事先连接代替运行时连接的方法来加速共享库的加载,它不只能够加快起动速度,还能够减小部份内存开销,是各类Linux架构上用于减小程序加载时间、缩短系统启动时间和加快应用程序启动的很受欢迎的一个工具。
预连接减小了启动可执行文件所需的时间
在Android上普遍使用
必须配置为知道哪些库须要进行预连接,并将为每一个可用符号分配一个固定的地址,从而消除了在启动可执行文件时从新定位符号的须要。
请注意安全性,由于可执行代码始终加载在同一地址。
代码以及文档参见
http://people.redhat.com/jakub/prelink/
支持ARM,但自2013年以来未发布。Buildroot也不支持。可是,x86比较容易实现。
后续会发布:
优化嵌入式Linux的启动时间之init脚本启动优化
优化嵌入式Linux的启动时间之文件系统优化
优化嵌入式Linux的启动时间以内核优化
优化嵌入式Linux的启动时间之bootloader优化
优化嵌入式Linux的启动时间之硬件初始化优化
敬请关注!
本文分享自微信公众号 - 嵌入式客栈(embInn)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。