写点什么

怎样在 1 秒内启动 Linux

  • 2015-12-02
  • 本文字数:1925 字

    阅读完需:约 6 分钟

尽可能快的启动系统,对于自动化设备是非常重要的。系统能够在用户无法感知的时间内启动,也就意味着在不需要工作时,可以完全切断电源,而不是挂起进入休眠状态。本文基于 Atmel AT91 系列片上系统和 NAND 闪存,经过一系列的优化,将 Linux 系统启动时间,从最初的 11 秒,降低到最终的 656 毫秒。

背景知识

系统从上电到完全启动,需要经过许多过程。一个简化的启动流程大概包含:

  1. 硬件重置
  2. 启动引导程序(bootloader)
  3. 操作系统初始化
  4. 应用程序执行

其中硬件非常关键,但是硬件一般难以更改。后续的优化,主要针对引导程序、Linux 内核和应用程序展开。

引导程序优化

引导程序主要完成对 CPU 的基础设置,处理 ARM 标记(ATAGS,ARM TAGS)或设备树(device trees),切换存储管理单元(MMU,Memory Management Unit)等工作。

重要通知:接下来 InfoQ 将会选择性地将部分优秀内容首发在微信公众号中,欢迎关注 InfoQ 微信公众号第一时间阅读精品内容。

对于 U-Boot,常用的优化方式有:

  • 删除不不要的功能:如网络加载等,如果不需要,那么直接移除这些代码吧;
  • 关闭不需要的功能
    • 关闭内核镜像验证
    • 关闭引导程序输出
    • 关闭启动延迟
  • 将通用功能的引导程序修改成一个优化后的初始程序加载器(Initial Program Loader,IPL),对于 U-Boot,可以通过 SPL(Second Program Loader,第二阶段程序加载器)来实现。

内核优化

Linux 内核被设计的非常灵活,可以针对需要的功能做各种配置优化。因此,优化内核对于系统启动速度是至关重要的。

首先,移除一切不要的驱动,尽可能的减少内核加载的内容,能够大大缩短系统启动时间。其次,还有很多内核选择可能需要进一步尝试,比如内核压缩方式,对于嵌入式系统来说,LZO 压缩方式,通常会是一个不错的选择。最后,还可以通过定制一些启动参数,达到加快启动的目的。例如可以通过“lpj=”参数,预设每个循环需要的节拍数(loops per jiffy,lpj)的值,避免系统在启动时自动推算。这样在基于 ARMv5 的系统中,可以节省 100ms 以上的时间。

对于内核启动的优化,可以通过 bootgraph.pl 脚本(位于内核源码的 script/bootgraph.pl )来绘制内核启动耗时图表,用以分析启动最耗时的地方。这个脚本使用非常简单,直接将 dmesg 的输出作为其输入,即可生成 svg 图表:

dmesg | perl scripts/bootgraph.pl > output.svg生成的图表如下图,

图中每一个色段表示一个功能的初始化耗时。可以简单的关闭不需要的功能,或者针对功能进行特定的优化。

除了内核本身之外,内核所在的文件系统也对系统启动有着非常大的影响。对于使用闪存芯片作为存储的系统来说, UbiFS 是一个很好的选择。它能够容忍意外断电,有着出色的挂载速度,以确保系统快速启动。

应用程序优化

内核完成系统启动之后,接来下就是执行应用程序。对于应用程序的优化,主要有两部分,一部分是由应用程序来接管启动的 INIT 进程,另一部分是优化应用程序的链接方式。

标准的 SystemV INIT 程序,需要执行一堆启动脚本。对于嵌入式系统来说,大部分是没有意义的。另一部分(比如挂载文件系统),可以由应用程序自己来实现。然后,可以在内核启动参数中通过“init=”参数,将 INIT 进程直接指定为应用程序。

应用依赖的动态链接库,会按照以下顺序查找:

  1. LD_PRELOAD 环境变量指定的路径(一般对应文件 /etc/ld.so.preload);
  2. ELF .dynamic 节中 DT_RPATH 入口指定的路径,若 DT_RUNPATH 入口不存在的话;
  3. 环境变量 LD_LIBRARY_PATH 指定的路径,但如果可执行文件有 setuid/setgid 权限,则忽略这个路径;编译时指定–library-path 会覆盖这个路径;
  4. ELF .dynamic 节中 DT_RUNPATH 入口指定的路径;
  5. ldconfig 缓存中的路径(一般对应 /etc/ld.so.cache 文件),若编译时使用了 -z nodeflib 的链接选项,则此步跳过;
  6. /lib,然后 /usr/lib 路径 ,若使用了 -z nodeflib 链接选项,则此步亦跳过;

因此,尽可能的将应用程序依赖的动态链接库放到优先查找的路径,可以加快链接速度。对于交叉编译环境特别需要注意,主机上的动态链接库位置和目标系统上的位置可能不一致,这会增加应用程序执行时动态链接库的加载时间。

总结

基于上面提到的三个优化点,可以将系统的启动时间,从最初的 11s 降低到 656ms(数据参考 Jan Altenberg 在都柏林举行的嵌入式 Linux 会议上的演讲稿)。从硬件到引导程序再到内核最后到应用程序,每个启动步骤都有自己可优化的地方,经过一些简单的优化,就可以减少系统的启动时间。


感谢魏星对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群(已满),InfoQ 读者交流群(#2))。

2015-12-02 18:004869

评论

发布
暂无评论
发现更多内容

【软件开发】直播带货App如何开发

青山一叶秋

依赖 jar 没有传递,导致找不到类文件而启动失败了

程序员小航

Java maven

工业企业能耗在线监测系统开发建设

a13823115807

前端需要的免费在线api接口

德育处主任

JavaScript ajax 前端 Postman API

元宇宙时代的业务、场景、技术机遇探索

融云 RongCloud

卧槽!Spring中竟然有12种定义Bean的方法?

北游学Java

Java、 SP【ring

微服务架构 | 如何利用好日志链路追踪做性能分析?

李尚智

Java 链路追踪 微服务治理 性能调试 微服务调用链

2021年12月国产数据库排行榜: openGauss节节攀升拿下榜眼,GaussDB与TDSQL你争我夺各进一位

墨天轮

数据库 opengauss TiDB 国产数据库

一张图看懂融云直播 SDK

融云 RongCloud

Aeron 是如何实现的?—— Ipc 异常情况处理

BUG侦探

Aeron ipc

你怎么总是能写出两三千行的controller类?

CRMEB

Flutter流畅度优化神器-开源组件keframe详解

贝壳大前端技术团队

flutter 性能 滑动优化

人工成本上升+设备停机率高,制造企业该如何破而后立?

优秀

低代码 制造业

【修复升级】腾讯容器安全首个发布开源 Log4j2 漏洞缓解工具

腾讯安全云鼎实验室

可视化神器背后的奥秘

百度开发者中心

大数据 百度开发者沙龙

你想知道的Kotlin version

Changing Lin

12月日更

解决远程办公安全隐患,就用行云管家!

行云管家

远程办公 IT运维

行云管家荣获第二届国际科创节“2021年度高成长性企业奖”!

行云管家

云计算 混合云 IT运维

【HZERO微服务平台6】源码分析之数据权限、sql拦截

qiaoxingxing

签约计划第二季

华为云消息队列服务荣获首个双擎可信云稳定性最高级认证

华为云开发者联盟

开源 安全 消息队列 可信云 DMS Kafka版

进程ID及进程间的关系

mazhen

Linux Shell Linux Kenel

记录一次win10更新版本后IIS无法启动的解决办法

为自己带盐

28天写作 12月日更

斗罗大陆真3D手游实力上线,带你感受魂兽猎杀的超燃时刻

华为云开发者联盟

数据库 华为云数据库 rds for mysql 3D手游 PITR

CSS之选择器(六)::before和::after

Augus

CSS 12月日更

iOS内卷面试题-你以为你够卷了,面试官更卷!

iOSer

ios 内卷 iOS面试

Flutter for Web 在贝壳容灾降级中的应用

贝壳大前端技术团队

flutter 容灾 降级 flutter for web

30个类手写Spring核心原理之MVC映射功能(4)

Tom弹架构

Java spring 源码

30个类手写Spring核心原理之AOP代码织入(5)

Tom弹架构

Java spring 源码

架构设计之MQ选型

无心水

RocketMQ MQ RabbitMQ Kakfa Activemq

潮玩盲盒系统开发元气部落盲盒app开发

风行无疆

重磅!中国红十字基金会固生堂中医惠民专项基金成立

E科讯

怎样在1秒内启动Linux_Linux_金灵杰_InfoQ精选文章