写点什么

怎样在 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:005134

评论

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

娄底携手浪潮,打造了智慧城市建设的“娄底样板”

Kubernetes Pod篇:带你轻松玩转Pod

xcbeyond

Kubernetes pod 28天写作 Kubernetes从入门到精通 服务编排

计算机网络学习第一课

落曦

第二周作业

Geek_6a8931

红帽架构师:为什么KubeEdge是2020年我最喜欢的开源项目?

华为云原生团队

开源 云原生 边缘计算 边缘技术

使用 async_hooks 模块进行请求追踪

智联大前端

node.js 大前端 koa async_hooks

架构师训练营-大作业:物流系统架构设计

晴空万里

架构师训练营第2期

【年度重磅】2020华为云社区年度技术精选合集,700页+免费下载!

华为云开发者联盟

数据库 AI 云原生 物联网 华为云

八大案例带你了解图数据库如何洞察数据间关联价值

NebulaGraph

图数据库 图数据库实战

转角遇上Volcano,看HPC如何应用在气象行业

华为云开发者联盟

容器 云原生 HPC Volcano 批量计算

云原生架构下复杂工作负载混合调度的思考与实践

星环科技

云计算

不可忽视的PHP数据精度损失问题

架构精进之路

php 七日更 28天写作

面试官常问的垃圾回收器,这次全搞懂

Silently9527

Java JVM 垃圾回收 GC

智能building 之智慧城市

张老蔫

28天写作

开发的必杀技:Git 的分支管理

华为云开发者联盟

git Linux 分支

区块链养成宠物游戏开发动物世界app系统搭建方案

v16629866266

【并发编程的艺术】内存语义分析:volatile、锁与CAS

程序员架构进阶

Java 架构 Java内存模型 28天写作

2021分享三面阿里:Java面试核心手册+Java电子书+技术笔记+学习视频

比伯

Java 编程 架构 面试 程序人生

Android Styling System

Changing Lin

android

30+岁、没转管理、加不动班,我的竞争力从哪里来?

博文视点Broadview

【图文并茂,点赞收藏哦!】重学巩固你的Vuejs知识体系

我是哪吒

程序员 面试 Vue 大前端 Web

数据库覆盖式数据导入方法:部分和完全

华为云开发者联盟

数据库 sql 数据 DWS 覆盖式导入

毫不留情地揭开负载均衡的真面目~

田维常

负载均衡

从定义到AST及其遍历方式,一文带你搞懂Antlr4

华为云开发者联盟

Java AST 语言 antlr4 语法分析器

Elasticsearch和Kibana变更开源许可协议;Facebook利用AI增强为视障人士描述照片能力

京东科技开发者

云计算

屏幕共享功能的应用

anyRTC开发者

android 音视频 WebRTC 在线教育 视频会议

甲方日常 90

句子

工作 随笔杂谈 日常

《Java 面经手册》PDF,全书5章29节,417页11.5万字,完稿&发版!

小傅哥

Java 面试 小傅哥 PDF 面经手册

并发条件队列之Condition 精讲

伯阳

AQS 多线程 lock Condition 条件队列

趋势预测:2021年五大流行的编程语言

禅道项目管理

Java php python 爬虫 趋势

2021年1月国产数据库排行榜:OceanBase重回前三,TDSQL增长趋势最强劲!

墨天轮

数据库

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