Board logo

标题: 嵌入式Linux系统中的快速启动技术研究 02 [打印本页]

作者: samwalton    时间: 2013-10-11 19:30     标题: 嵌入式Linux系统中的快速启动技术研究 02

2.3 用户空间阶段
  传统Linux的初始化脚本是由bash执行的,在内核引导后启动init进程(/sbin/init)。它使用一个ASCII文件(/etc/inittab)来改变运行级别,这个文件中又会调用RCSript,由RCSript查找/etc/rc.d/rc5.d/并启动相应链接指向的系统服务。
  消费电子类Linux系统需要启用图形界面等必要的服务,未经优化的系统在这个过程中会默认启动很多根本用不到或者当前用不到的系统服务,这一部分会花去较大的时间开销。最简单的优化办法就是根据实际需要,通过改写服务配置文件定制系统服务。另外,init脚本的执行是串行的,在脚本量大时会导致引导过程非常,因此可以考虑并行运行各种服务以加快启动的速度。现在已经出现了一些初始化程序来替代init进程,下面介绍initng和upstart。
  initng(init nextgerneration)能够并行启动服务从而快速完成初始化工作。initng认为满足了依赖关系的服务就可以启动。在从外存加载一个脚本或等待硬件设备启动的同时,可以运行另一个脚本来启动别的服务,使系统在CPU 和 I/O 之间实现较好的平衡。作为一个基于依赖关系的解决方案,initng使用自己的初始化脚本集,它们对服务和守护进程的依赖性进行了编码。如果某个服务依赖(使用 need关键字定义)于其他服务,则要保证启动时它所依赖的所有服务均可用。无依赖关系的服务立即并行启动,具有依赖关系的服务则要等待以安全启动。
  upstart与 initng的区别在于: upstart基于事件,任务/服务的启动/停止都取决于它所等待的事件是否发生。upstart对事件的定义非常灵活,分为3类:edge (simple) events, level (value) events和temporal events。使用start/stop、事件名以及它所期待的值(可选)组成条目对触发事件进行描述。事件依赖有两种办法:一种是任务自身导致事件发生,不管任务何时启动/结束都会有事件发生,对于启动时要执行的基本任务,这种办法比较有效;而对于较复杂的依赖关系,则可使用任务的Shell脚本工具。
  2.4 预读取和预链接
  预读取(Readahead)可以将文件(程序和库文件)在使用之前预先加载到RAM缓存中,这样就不用在使用时为读取这个文件而访问I/O。如果知道下一步操作要访问哪些文件,就可以提前将它们全部
  部分读取到缓冲区,从而加快执行速度。嵌入式系统很多场合下对于下一步操作都是可预测的,比如系统启动时总是以同样的顺序访问同样的可执行/数据文件,文件块的访问往往是顺序的,应用程序启动时总是访问同样的程序文件段、共享库、资源或者输入文件。这样使用预读取有很强的针对性,从而提高程序执行速度。
  ELF(Excutable and Linkable File)是目前Linux中的标准二进制格式,其启动需要以下步骤:将共享库映射到虚拟地址空间;解析符号引用;初始化每个ELF文件。由于共享库是位置无关的,要在运行时完成部分重定位处理和符号查找的工作,才能跳到程序的入口点,因此在带来灵活性的同时,也造成ELF文件的启动速度缓慢,尤其是解析符号引用要消耗大量的时间,对于使用多个共享库的大型程序更是如此。但在很多嵌入式系统中,可执行文件和共享库极少变化,而且每次程序运行时链接工作完全相同。
  预链接(Prelink)利用这一点,修改ELF共享库和二进制文件,将链接信息加入到可执行文件中以简化动态链接重定位,从而使程序启动加快。预链接首先搜集要预链接的ELF二进制文件及其所依赖的共享库,为每个库分配唯一的虚拟空间位置,并将共享库重新链接到这个基准位置(动态链接器要加载这个库时,只要虚拟空间地址未被占用,它就会将库映射到指定位置);然后预链接解析二进制或者库中的所有重定位,并将重定位信息存放到ELF对象,还要将所有依赖库的列表及校验和添加到二进制文件或库中。对于二进制文件,还需列出所有的冲突(在共享库的自然搜索范围内对符号的解析不相同)。在运行时,动态链接器先检查是否所有依赖的库都已经映射到指定的位置,而且库文件没有变化,只考虑冲突而不用处理每个库的重定位,这样大大提高了程序启动的速度。使用时要注意的是,若共享库发生了改变,则使用它的所有程序都要重新链接,否则程序仍要进行耗时的正常重定位。
  3 XIP和文件系统优化
  3.1 代码执行方式
  嵌入式系统中代码的执行方式主要有3种:
  ① 完全映射(fully shadowed)。嵌入式系统程序运行时,将所有的代码从非易失存储器(Flash、ROM等)复制到RAM中运行。
  ② 按需分页(demand paging)。只复制部分代码到RAM中。这种方法对RAM中的页进行导入/导出管理,如果访问位于虚存中但不在物理RAM中会产生页错误,这时才将代码和数据映射到RAM中。
  ③ eXecute In Place (XIP)。在系统启动时,不将代码复制到RAM,而是直接在非易失性存储位置执行。RAM中只存放需要不断变化的数据部分,如图1所示。如果非易失性存储器的读取速度与RAM相近,则XIP可以节省复制和解压的时间。NOR Flash和ROM的读取速度比较快(约100 ns),适合XIP;而NAND Flash的读操作是基于扇区的,速度相对很慢(μs级),因此不宜实现XIP。

  图1 完全映射和XIP的比较






欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0