张释文 陈莉君
(西安邮电大学计算机学院 西安 710121)
近年来,用户在享受更智能嵌入式Linux设备带来的方便与乐趣同时,又不得不面对系统服务日渐丰富、启动时间越来越长等问题。缓慢的开机速度严重影响用户体验[1],因此加快启动速度已经成为嵌入式领域待解决的重要问题之一。
目前嵌入式Linux快速启动方法常见的有两个方面:
1)优化开机流程。删除了启动中重复执行的初始化模块和不常用的兼容性模块来实现加速启动。研究主要有:RC(RunlevelControl,运行级别控制)脚本优化,如并行服务启动、使用busybox等[2]。然而对嵌入式系统来讲,删除了一些模块之后系统可能不再具有兼容性。另一方面,启动流程中能删除的模块有限,优化不明显。
2)休眠技术。休眠快速启动(Suspend in DisK,SDK)利用挂起/恢复(Suspend/Resume)技术[2]把操作系统和应用程序完成启动的寄存器和内存信息制作成镜像文件,SDK方法制作镜像文件是主要的技术难点。索尼、松下等非营利行消费电子论坛CELF和Tripeaks公司已开发出一些基础技术,目前安卓和Windows 8系统采用此快速启动方法。
近几年,对于基于休眠快速启动的研究着眼两个问题:减小休眠镜像大小和缩短关机时间。随着休眠镜像尺寸增大,载入镜像需要时间变长。经过测试当镜像文件超过400M时,快速启动反而增加了启动时间[3]。文献[4~5]提出减少镜像存储干净页面(NotRestore Clean page,NRC)的优化,产生镜像时调用内核模块大量分配页面引发系统换出干净页面。和SDK方法相比,NRC方法能减少镜像至60%左右,缩短了25%的启动时间和40%的关机时间,该方法不侵入系统,然而延长了关机时间引入不安全因素;文献[6]提出保存部分内存页面(Only Restore Kernel,ORK)的优化,创建镜像只保存内核空间内存页面放弃用户空间来缩减镜像文件大小,ORK方法使镜像缩小至60.5%,但是快速启动结束之后一段时间内系统响应时间变长。文献[3,5]提出镜像文件一次产生多次同步(Image only Create Once,ICO)的优化来缩短关机时间,安装系统时候创建镜像,每次快速启动都使用同一镜像文件,启动结束后扫描整个外存以同步系统状态。ICO方法关机时间优化非常明显,然而系统使用一段时间后和镜像记录状态差别越来越大,扫描外存需要时间越来越长,导致启动时间增加。
针对延长关机时间和镜像加载时间过长题,本文分析研究了基于休眠的快速启动方法,提出一种开机创建快照(Create Image After Boot,CIAB)的优化方法,以期缩短关机时间且减小镜像尺寸。
SDK快速启动是利用Linux电源管理的挂起/恢复技术实现的,该技术分为两部分:关机前通过挂起技术将系统当前的CPU、内存页面、外部设备状态等,按照一定格式制作成镜像保存在外部Flash中;下次开机的时候利用恢复技术按照镜像文件内容恢复到上次关机状态。挂起和恢复函数执行流程如图1所示。
图1 恢复和挂起操作流程图
内核加载器载入并解压缩内核,内核执行完一些架构初始化操作之后,跳转至快速启动入口检查镜像文件是否存在,若不存在执行正常启动流程。若存在则载入镜像文件恢复系统,恢复过程是挂起过程的对偶操作。
完成准备工作,接下来是挂起/恢复流程中最重要的步骤——镜像创建。
SDK快速启动方法主要依赖挂起过程中产生的镜像,在保存状态阶段需要将系统的运行状态按照一定格式组织成镜像文件,镜像文件的格式如图2所示。
图2 镜像组织结构
镜像头存储了镜像大小、版本号等等,用来管理整个镜像文件的数据存储在镜像元数据中,包括:镜像文件起始内存地址、镜像文件起始块号和位图索引等等。详细结构如图3所示。
图3 镜像数据结构
swsusp_info是镜像头,镜像文件中最重要的数据结构。swsusp_header表示整个镜像文件的开始,其中最重要的结构式指向位图索引的image。内核写镜像时,先初始化swsusp_info,swsusp_header,接着循环申请内存存储镜像内容、写入外存、修改swap_map_page直到整个镜像写入完成,最后在swsusp_info中记录大小和版本号等信息。
读镜像是根据用户设置的位置,去外存上先读出swsusp_info和swsusp_header得到索引位图,根据位图依次读出镜像块,并恢复到内存。
SDK快速启动修改了原本的Linux关机流程,在执行正常关机流程中添加了产生和保存镜像操作。快速启动关机流程和正常的关机流程对比如图4所示。
图4 关机流程对比图
SDK快速启动在正常关机流程上增加的逻辑有:挂起唤醒设备、读写磁盘等这些相对耗时的操作。通过研究SDK方法延长了40%的关机时间[4]。目前嵌入式设备常常出现电量耗尽关机的使用场景,此种情况下系统来不及保存镜像指示快速启动失败。综上,该问题亟待解决。
基于休眠的快速启动技术的启动时间可形式化表示为如下:
其中tb表示内核加载器进行像CPU、时钟等基本初始化的时间,是读取休眠镜像前的准备工作;td表示从外存读取休眠镜像的时间;tr表示执行恢复系统函数根据镜像恢复系统的时间,主要包括恢复处理器、内存、外部设备状态、进程状态的时间。
由式(2)看出休眠镜像读取时间和休眠镜像大小成正比,2.2节介绍了休眠镜像的组织结构,内存数据分为内核空间和用户空间。内核空间主要有内核代码、内核数据结构、高速缓存、文件系统数据等组成。用户空间保存了各个用户进程的地址空间。保存了内存全部页面,包括高速缓存和用户进程数据等这些并不重要的页面,致使休眠镜像臃肿过大。
本文提出的快速启动优化方法:快照在开机之后产生,系统运行过程中更新镜像文件,在不延长关机或者开机时间前提下,任意时刻外存上存储了一个和关机前系统状态尽可能相同的镜像文件。
CIAB方法产生的镜像文件中存储的并不是关机之前系统状态,使用此镜像文件恢复系统将导致快速启动和正常启动进入的系统的不一致问题。不一致问题有用户挂载新文件系统导致的文件系统的不一致和用户新修改了系统设置导致的设置不一致。
CIAB方法不一致问题整体设计如图5所示。
图5 CIAB方法设计图
系统设置数据和文件系统元数据都存储在镜像图5所示位置中,对于系统设置,快速启动成功后创建守护进程同步。对于文件系统元数据,系统运行过程中创建守护进程,定时同步镜像保存文件系统元数据。
正常启动过程中的挂载文件系统,实际上是读取外存设备上的文件系统元数据至内存,比如说超级块、根索引节点等等,虚拟文件系统用这些数据创建file_system_type用以管理文件系统。内核用链表结构管理全部的file_system_type,表头由file_systems变量指定,此链表是需要同步的数据。
CIAB方法创建休眠镜像结束时,修改hibernate.c/hibernate函数正常退出模块,再次调用内核函数swap_write_pages在镜像文件之后记录file systems,块号记录在fastboot_block变量中。修改之后镜像结构如图6所示。
图6 修改之后的镜像文件
创建守护进程定时读取file_systems链表,详细流程如图7所示。
图7 同步文件系统流程图
休眠镜像创建完成后,申请内存空间存储file systems链表节点,调用函数把该页写入swap,此时镜像内容修改完成。接下来修改镜像头存储的镜像大小、镜像元数据记录的位图信息,设置镜像不压缩标志,最后文件系统同步进程完成全部工作进入睡眠。
只有在用户挂载了新的文件系统的情况下,file systems链表才有变化,因此同步文件系统频率不高。
用户在交互使用应用过程中会根据自己的需要调整应用的设置,这保证了不同的用户能够按照自己的需求定义不同的设置,快速启动镜像文件并未保存用户的最新设置,因此带来系统设置不一致问题。这些交互设置包括桌面设置、网络设置等。
系统常用配置常存储在/etc下,比如桌面壁纸和app icon设置存储在/etc/desktop文件中,网络设置位于/etc/networking等等。专用的嵌入式设备要求一些特殊配制,像智能车载电脑要求记录用户播放列表位置等。
CIAB方法解决系统设置不一致问题详细流程如图8所示。
Bootloader载入镜像文件,内核执行完基本初始化操作,调用函数hibernate.c/load_image_and_restore按照镜像文件恢复系统。读取/etc/desktop/config、/etc/networking/config和/etc/fastboot_config.xm l,根据配置文件修改系统,同步完成后显示用户登录界面,之后挂起系统创建下次启动使用的镜像文件。
图8 同步系统设置流程图
本文研究基于快照的嵌入式Linux的快速启动,在ARM体系结构下,选用FriendlyARM mini2440硬件平台、Ubuntu for ARM操作系统加上qq、小企鹅、纸牌游戏、照相机和浏览器等软件。使用printk得到优化前后的启动时间和关机时间,分别对SDK方法、CIAB方法、NRC方法、ORK方法和ICO方法进行对比。
图9 快速启动开关机时间对比图
从图9看出,各个快速启动方法和正常开机时间相比节省都超过60%,其中ICO方法启动结束之后需要扫描外存同步系统数据,和SDK等快速启动方法相比,花费时间最长,随着用户的使用,扫描硬盘耗时必将越来越高。NRC方法不保存干净内存页面、ORK只保存内核空间内存页面和本文提出的CIAB方法开机之后内存处于干净状态下创建镜像,均优化了镜像大小,相较于SDK方法启动时间略有缩短。
关机时间对比图中,SDK、NRC和ORK方法关机之前创建休眠文件,关机时间比正常关机延长了65%左右。SDK方法休眠镜像保存全部内存页面,花费的关机时间最长。NRC方法通过关机之前申请大量内存迫使内核回收干净页面来减少镜像存储内存页面数量,而ORK方法通过虚拟地址选择,ORK比NRC关机时间更短。CIAB和ICO方法并为修改原本的关机逻辑,关机时间和正常关机相同。
综上,CIAB方法开机之后大量用户进程运行之前创建镜像,和各个基于休眠的快速启动方案相比,在缩短关机时间和减小镜像文件大小方面优化显著。
本文通过分析Linux挂起/恢复技术,利用现有的SDK快速启动方法,提出一种CIAB快速启动优化方法,这种方法在缩短SDK关机时间方面优化显著。这对研究嵌入式Linux启动过程和加快嵌入式Linux启动速度方面有重要的研究和借鉴意义。然而由于镜像文件中仅仅保存了内存中的基本系统数据,下一步工作将着力于解决CIAB方法会导致启动结束后系统的响应时间变长问题。