Linux 启动优化实战-2.41 秒启动应用!

系统启动是一个大问题,前段时间有同学也问了我这个问题,不仅仅是Linux,Android 下面的启动优化也可以借助bootchar来分析。下面正文是老吴的实操过程。

哦,对了,上篇文章有同学问文章的封面,这里贴出来,再顺便多送两张,原图出处晓宇姐姐的-芯片之家

0fece24581f1f5febe660e1cf477dfc0.png

e8524d099a82f2ec93696d00428b5c35.png

03c95cacf3f1110e008f6b309494873d.png

目标系统

硬件:

Beagle Bone Black (Cortex A8)

USB 摄像头 + LCD

软件

Linux 5.1 + Buildroot rootfs

FFmpeg,用于采集视频并解码到 LCD。

d63b600acedcac9beb80447ecf0a2a08.png

点击查看大图

当前启动时间

从上电到 LCD 显示第一帧图像:9.45 秒

1、优化编译器

ARM vs Thumb2

比较基于 ARM 或者 Thumb2 指令集编译出来的系统和应用。

ARM:rootfs 为 3.79 MB,ffmpeg 为 227 KB。

Thumb2:3.10 MB (-18 %),183 KB (-19 %)。

性能方面:Thumb2 的性能明显略有提升 (约小于 5 %)。

虽然性能有所提升,但是我个人还是会选择 ARM 指令集。

musl vs uClibc

Buildroot 里有 3 种 C库可以选择:glibc、musl、uClibc,这里我们只比较后面 2 种比较小巧的库。

musl:680 KB (统计 /lib 目录)。

uClibc:570 KB (-16 %)。

uClibc 节省了 110 KB,我们选择 uClibc。

2、优化应用程序

我们可以通过 ./configure 对 FFmpeg 的功能组件进行选择。

另外,还可以用 strace 和 perf 命令调试以优化 FFmpeg 的内部d代码。

优化后的结果:

文件系统:从 16.11 MB 缩小到 3.54 MB (-78 %)。

程序的加载和运行时间:缩短 150 ms。

整体启动时间:缩短 350 ms。

在空间的优化很大,但是在启动时间上的优化很小,这是因为 Linux 运行程序时只加载程序的必要部分。

3、优化 Init 和根文件系统

思路:

使用 bootchartd 分析系统启动并裁剪不必要的服务。

将 /etc/init.d/ 下的启动脚本合并为一个。

不挂载 /proc 和 /sys。

裁剪 BusyBox,文件系统越小,内核挂载可能会越快。

将 Init 程序替换成我们的应用程序。

静态编译应用程序。

裁剪掉不常用的文件,找出长时间不访问的文件:

$ find / -atime -1000 -type f

优化后的结果:

文件系统:裁剪 Busybox 后,从 3.54 MB 缩小到 2.33 MB (-34 %)。

启动时间:基本没改变,大概是因为文件系统本身就足够小了。

使用 initramfs 作为 rootfs:

一般情况下,Linux 系统会先挂载 initramfs,init ramfs 很小且位于内存中,再由 initramfs 负责负载根文件系统。

当我们将 Buildroot rootfs 裁剪得很小时,就可以考虑直接将其作为 initramfs 使用。

这样有什么好处呢?

initramfs 可以和 Kernel 拼接在一起,Bootloader 负责将 Kernel+initramfs 加载到内存中,内核不再需要访问磁盘。

内核不再需要 block/storage 和 filesystem 相关的功能,体积会变得更小,加载时间和初始化时间都会变小。

注意,需要关闭 initramfs 的压缩(CONFIG_INITRAMFS_COMPRESSION_NONE)。

优化后的结果:

即便禁用了 CONFIG_BLOCK 和 CONFIG_MMC 后,总启动时间仍多了 20ms。这可能是因为 Kernel + initramfs 拼在一起之后,内核变大了许多,而内核镜像是需要解压,解压的时间增多了。

4、优化内核

评估方法:

在启动参数里添加 initcall_debug,能得到更多内核 log:

[ 3.750000] calling ov2640_i2c_driver_init+0x0/0x10 @ 1
[ 3.760000] initcall ov2640_i2c_driver_init+0x0/0x10 returned 0 after 544 usecs
[ 3.760000] calling at91sam9x5_video_init+0x0/0x14 @ 1
[ 3.760000] at91sam9x5-video f0030340.lcdheo1: video device registered @ 0xe0d3e340, irq = 24
[ 3.770000] initcall at91sam9x5_video_init+0x0/0x14 returned 0 after 10388 usecs
[ 3.770000] calling gspca_init+0x0/0x18 @ 1
[ 3.770000] gspca_main: v2.14.0 registered
[ 3.770000] initcall gspca_init+0x0/0x18 returned 0 after 3966 usecs
...

另外,可以用 scripts/bootgraph.pl 将 dmesg 的信息转换成图片:

$ scripts/bootgraph.pl boot.log > boot.svg

3611f0853d26157ac5070a8b0306ff0e.png

点击查看大图

接下来,找出消耗时间最多的环节,进行优化。

裁掉 tracing

在 Kernel hacking 里关闭 Tracers 相关的功能。

启动时间:缩短 550ms。

内核大小:缩小 217KB。

裁掉一些用不上的硬件功能

omap8250_platform_driver_init() // (660 ms)
cpsw_driver_init()  // (112 ms)
am335x_child_init() // (82 ms)
...

预设 loops per jiffy

在每次启动时,内核都会校准 delay loop 的值,用于 udelay() 函数。

这会测量 loops per jiffy (lpj) 的值。我们只需要启动一次内核,在log 查找 lpj 值:

Calibrating delay loop... 996.14 BogoMIPS (lpj=4980736)

然后将 lpj=4980736 填写到启动参数中,即可:

Calibrating delay loop (skipped) preset value.. 996.14 BogoMIPS (lpj=4980736)

大约缩短了 82 ms。

禁用 CONFIG_SMP

SMP 的初始化很慢。它通常在默认配置中是启用的,即使是一个单核 CPU。

如果我们的平台是单核的,可以禁用 SMP。

关闭后,内核缩小:-188 KB (-4.6 %),启动时间缩短 126ms.

禁用 log

启动参数里添加 quiet,启动时间缩短 577 ms。

禁用 CONFIG_PRINTK 和 CONFIG_BUG 后,内核缩小 118 KB (-5.8 %) 。

禁用 CONFIG_KALLSYMS 后,内核缩小 107 KB (-5.7 %) 。

合计,启动时间缩短 767 ms。

开启 CONFIG_EMBEDDED 和 CONFIG_EXPERT

这会让系统调用变得更精简,内核会变得没那么通用,但是能保持你的应用程序能运行就足够了。

内核缩小 51 KB。

启动时间缩短 34 ms。

选择 SLAB memory allocators

一般是 SLAB、SLOB、SLUB 三选一。

SLAB:默认选择,最通用、最传统、最可靠。

SLOB:更简洁,代码量更少,更节省空间,适合嵌入式系统,使能后,内核缩小 5 KB,但是启动时间增加 1.43 S!

SLUB:更合适大型系统,使能后,启动时间增加 2 ms。

因此,我们仍使用 SLAB。

内核压缩方式

不同压缩方式的特点如下:

2d98cdf107716f48599ead14fedceed8.png

实测效果:

afc80e797a93673fa397b8272deaf73f.png

看起来,gzip 和 lzo 表现更好。测试的效果应该是和 CPU/磁盘 的性能相关的。

内核编译参数

使能 CONFIG_CC_OPTIMIZE_FOR_SIZE,该选项可能是用 gcc -Os 代替 gcc -O2。

2a98fcb611435b5f62ed7b85e70fcba0.png

点击查看大图

注意,这只是在 BeagleBone Black + Linux 5.1 上的测试结果,不同平台之间有差异。

禁用 /proc 等伪文件系统

要考虑应用的兼容性。

ffmpeg 依赖 /proc ,所以只能关闭一些 proc 相关的选项:CONFIG_PROC_SYSCTL、CONFIG_PROC_PAGE_MONITOR CONFIG_CONFIGFS_FS,启动时间没有变化。

关闭 sysfs, 启动时间缩短 35 ms。

拼接 DTB

启用 CONFIG_ARM_APPENDED_DTB:

$ cat arch/arm/boot/zImage arch/arm/boot/dts/am335x-boneblack-lcd4.dtb > zImage$ setenv bootcmd 'fatload mmc 0:1 81000000 zImage; bootz 81000000'

启动时间缩短 26 ms。

5、优化 Bootloader

这里我们采用最好的方案:使用 Uboot Falcon mode。

Falcon mode 只执行 Uboot 的第一阶段:SPL,然后跳过 Stage 2,执行加载 Kernel。

启动时间缩短 250 ms。

总结

到此,启动优化基本完成,最终效果如下:

[0.000000 0.000000]
[0.000785 0.000785] U-Boot SPL 2019.01 (Oct 27 2019 - 08:04:06 +0100)
[0.057822 0.057822] Trying to boot from MMC1
[0.378878 0.321056] fdt_root: FDT_ERR_BADMAGIC
[0.775306 0.396428] Waiting for /dev/video0 to be ready...
[1.966367 1.191061] Starting ffmpeg
...
[2.412284 0.004277] First frame decoded

从上电到 LCD 显示第一帧图像,总时间为 2.41 秒。

最有效果的步骤如下

3bd3b3abe3cf6c20036a41b8424482e1.png

点击查看大图

仍值得优化的空间

系统花了 1.2 秒等待 USB 摄像头的枚举,这里是否有办法加速?

是否可以关闭 tty 和终端登录?

最后,关于优化启动时间,有一些原则可以遵循

请不要过早地进行优化。

从一些影响面最小的点开始优化。

从 rootfs 、kernel、bootloader 自上而下进行优化。

重点关注短板。

感谢阅读,欢迎转发哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/464178.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

腾达fh307没有显示服务器名,腾达(Tenda)FH307路由器上网设置 | 192路由网

本文介绍了腾达(Tenda)FH307路由器的安装、上网设置方法,同时分别介绍了“ADSL(PPPOE)拨号”、“动态IP”、“静态IP”三种上网方式的区别,以及在腾达(Tenda)FH307路由器上的详细设置。腾达(Tenda)FH307无线路由器一台新购买的腾达FH307路由器实现上网&a…

记得重用layout

2019独角兽企业重金招聘Python工程师标准>>> 这样的布局&#xff1a; <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android" android:layout_width"…

sql2000-2 4/19

SQL2000客戶的上次問題後來H盤自動毀掉了昨天換了顆新硬碟,當資料庫挂上之後,H一直又提示錯誤,後來還是將資料庫路徑設為I傍晚時分親眼目睹了H所有資料被自動刪除的過程,待服務器重新啟動後H無法存取萬幸的是早一步將資料庫路徑作了更動在還原資料庫的過程中用克隆的BAK還原一直…

五一加班

前几年五一放假&#xff0c;我们会去小云家&#xff0c;五一也是荔枝成熟的时候&#xff0c;有一年吃上刚从树上摘的荔枝&#xff0c;现在还能记起那种味道&#xff0c;也是那次之后&#xff0c;想奢入简很难了&#xff0c;荔枝也一定要吃新鲜的了。今年一直还没看到荔枝的影子…

win10系统能做域服务器吗,Win10 LTSC 加入 Windows Server 2019 域服务器

前面的文章已经创建了域服务器、创建了域组织单位、用户组、用户&#xff0c;下面是如何把一台 Win10 LTSC 系统的电脑加入到Windows Server 2019 域服务器&#xff1b;0x01 加域准备修改计算机名、修改IP地址DNS指向 Windows Server 2019 域控制器&#xff1b;注意&#xff1a…

离职就打低绩效,这样对吗?

应该不止听见一个人说过&#xff0c;担心离职遇到各种不爽的事情&#xff0c;比如卡你的离职时间&#xff0c;比如让你背很低的绩效&#xff0c;比如你今年的年终奖就没有了&#xff0c;再比如&#xff0c;你和原来玩得好的同事突然就没话说了。我记得很清楚的事情是&#xff0…

+ 网页制作效果常用代码

控制横向和纵向滚动条的显隐&#xff1f;<body style"overflow-y:hidden"> 去掉x轴<body style"overflow-x:hidden"> 去掉y轴<body scroll"no">不显表格变色<TD οnmοuseοver"this.style.backgroundColor#FFFFFF&qu…

PID算法原理介绍

先来彻底搞懂PID到底是啥&#xff1f;PID&#xff0c;就是“比例&#xff08;proportional&#xff09;、积分&#xff08;integral&#xff09;、微分&#xff08;differential&#xff09;”&#xff0c;是一种很常见的控制算法。在工程实际中&#xff0c;应用最为广泛的调节…

打败opencv ,哦,是快了3倍

大家好&#xff0c;本文转自我一个读者朋友Homio的文章&#xff0c;推荐给大家&#xff0c;希望对做这方便的同学有所帮助。程序员&#xff0c;哦&#xff01;不&#xff01;软件工程师们都对opencv很熟悉&#xff0c;它在工作学习研究中起到了不可或缺的作用。但是它臃肿的身躯…

数据库中使用自增量字段与Guid字段作主键的性能对比(补充篇)-----转

我在发表过“据库中使用自增量字段与Guid字段主键的性能对比”这篇文章后&#xff0c;得到博客园各园友的很多评价&#xff0c;大家对我的测试方法也提出一些改进的方法。让我吃惊的是一园友提出&#xff1a;把guid和id的测试顺序颠倒一下&#xff0c;看下结果。今天就再测试一…

DEVC++出新版本了

昨天发了一篇文章C语言能判断一个变量是int还是float吗&#xff1f;然后有同学问我在Windows下是怎么写C代码的我是没有安装包的&#xff0c;只不过这个同学关系跟我不错&#xff0c;所以我就去找了下安装包&#xff0c;不找不知道&#xff0c;找了才发现&#xff0c;原来这个更…

小鹏汽车面试经验分享

大家周一好&#xff0c;这篇文章转自我的朋友李纳克斯&#xff0c;在做工作的同事&#xff0c;去面试也能增长自己的技术面和技术深度。推荐给大家&#xff0c;希望对大家有所帮助。某个下午&#xff0c;小鹏汽车的HR在招聘软件上撩我&#xff0c;于是我决定去聊聊看。接触下来…

(Bezier)贝塞尔曲在路径规划的运用,机器运动控制常用

前言之前被安排了活&#xff0c;一个局部区域机器运动控制的工作&#xff0c;大致是一个机器位于一个极限区域时候&#xff0c;机器要进入一个特殊的机制&#xff0c;使得机器可以安全的走出来。其中用到了bezier曲线进行优化路径&#xff0c;今天写一下&#xff0c;正好也给大…

当然可以不努力

我刚开始觉得他说的不对&#xff0c;现在越看越觉得他说的有道理。我们这一代人&#xff0c;太容易被别人影响&#xff0c;小的时候&#xff0c;觉得要赶上别人家的孩子&#xff0c;所以就努力读书&#xff0c;努力干家务。长大了一些&#xff0c;要用功的工作&#xff0c;用功…

遇到问题了 .net项目发布到iis6,没有权限访问!?

系统环境&#xff1a;windows2003 sp1 iis6 .net 2 framework已经允许了asp.net 2.0的支持在vs2005中把自己的web项目发布到iis6中的虚拟目录&#xff0c; 可是无法访问呀您无权查看该网页 您可能没有权限用您提供的凭据查看此目录或网页。 如果您确信能够查看该目录或网页&am…

嵌入式界的顶流开源项目,RetroPie 是怎么设计的?

RetroPie 是啥&#xff1f;一个用于将树梅派等板子转变为游戏机的开源项目。树梅派上运行 RetroPieGithub:https://github.com/RetroPie/RetroPie-Setup第一感觉&#xff0c;基于 Shell&#xff0c;有啥牛逼的。但仔细想想&#xff0c;一个简单的项目能获得 9.4K 的 Star&#…

java线程池,信号量使用demo

直接上代码 package org.jimmy.threadtest20181121;import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit;public class TestThread20181128 {public Semaphore semaphore new Semaphore(2, true)…

Spring JDBC最佳实践(2)

2019独角兽企业重金招聘Python工程师标准>>> 使用DataSourceUtils进行Connection的管理 由上节代码可知&#xff0c;JdbcTemplate在获取Connection的时候&#xff0c;并不是直接调用DataSource的getConnection(),而是调用了如下的代码&#xff1a; Connection con …

我所感受到的上海

大家好&#xff0c;文章转自张老师的公众号&#xff0c;文章的我不是小编本人&#xff0c;小编现居深圳&#xff0c;刚接受了一场大雨的洗礼。前两天公众号抽奖的书籍已经发货&#xff0c;中奖的朋友们注意查收。当格蠹园里的大灰反复犹豫到底应该在哪里生产的时候&#xff0c;…

设计模式学习笔记五——Prototype模式

动机&#xff1a;使用原型实例指定创建对象的种类&#xff0c;然后通过拷贝这些原型来创建新的对象。某些结构复杂对象面临着剧烈变化&#xff0c;但拥有比较稳定一致的接口&#xff0c;如何隔离出这些易变对象&#xff0c;使客户程序不随之改变&#xff1f;场景&#xff1a;Th…