張釋文 陳莉君
(西安郵電大學(xué)計(jì)算機(jī)學(xué)院 西安 710121)
近年來,用戶在享受更智能嵌入式Linux設(shè)備帶來的方便與樂趣同時(shí),又不得不面對(duì)系統(tǒng)服務(wù)日漸豐富、啟動(dòng)時(shí)間越來越長(zhǎng)等問題。緩慢的開機(jī)速度嚴(yán)重影響用戶體驗(yàn)[1],因此加快啟動(dòng)速度已經(jīng)成為嵌入式領(lǐng)域待解決的重要問題之一。
目前嵌入式Linux快速啟動(dòng)方法常見的有兩個(gè)方面:
1)優(yōu)化開機(jī)流程。刪除了啟動(dòng)中重復(fù)執(zhí)行的初始化模塊和不常用的兼容性模塊來實(shí)現(xiàn)加速啟動(dòng)。研究主要有:RC(RunlevelControl,運(yùn)行級(jí)別控制)腳本優(yōu)化,如并行服務(wù)啟動(dòng)、使用busybox等[2]。然而對(duì)嵌入式系統(tǒng)來講,刪除了一些模塊之后系統(tǒng)可能不再具有兼容性。另一方面,啟動(dòng)流程中能刪除的模塊有限,優(yōu)化不明顯。
2)休眠技術(shù)。休眠快速啟動(dòng)(Suspend in DisK,SDK)利用掛起/恢復(fù)(Suspend/Resume)技術(shù)[2]把操作系統(tǒng)和應(yīng)用程序完成啟動(dòng)的寄存器和內(nèi)存信息制作成鏡像文件,SDK方法制作鏡像文件是主要的技術(shù)難點(diǎn)。索尼、松下等非營(yíng)利行消費(fèi)電子論壇CELF和Tripeaks公司已開發(fā)出一些基礎(chǔ)技術(shù),目前安卓和Windows 8系統(tǒng)采用此快速啟動(dòng)方法。
近幾年,對(duì)于基于休眠快速啟動(dòng)的研究著眼兩個(gè)問題:減小休眠鏡像大小和縮短關(guān)機(jī)時(shí)間。隨著休眠鏡像尺寸增大,載入鏡像需要時(shí)間變長(zhǎng)。經(jīng)過測(cè)試當(dāng)鏡像文件超過400M時(shí),快速啟動(dòng)反而增加了啟動(dòng)時(shí)間[3]。文獻(xiàn)[4~5]提出減少鏡像存儲(chǔ)干凈頁面(NotRestore Clean page,NRC)的優(yōu)化,產(chǎn)生鏡像時(shí)調(diào)用內(nèi)核模塊大量分配頁面引發(fā)系統(tǒng)換出干凈頁面。和SDK方法相比,NRC方法能減少鏡像至60%左右,縮短了25%的啟動(dòng)時(shí)間和40%的關(guān)機(jī)時(shí)間,該方法不侵入系統(tǒng),然而延長(zhǎng)了關(guān)機(jī)時(shí)間引入不安全因素;文獻(xiàn)[6]提出保存部分內(nèi)存頁面(Only Restore Kernel,ORK)的優(yōu)化,創(chuàng)建鏡像只保存內(nèi)核空間內(nèi)存頁面放棄用戶空間來縮減鏡像文件大小,ORK方法使鏡像縮小至60.5%,但是快速啟動(dòng)結(jié)束之后一段時(shí)間內(nèi)系統(tǒng)響應(yīng)時(shí)間變長(zhǎng)。文獻(xiàn)[3,5]提出鏡像文件一次產(chǎn)生多次同步(Image only Create Once,ICO)的優(yōu)化來縮短關(guān)機(jī)時(shí)間,安裝系統(tǒng)時(shí)候創(chuàng)建鏡像,每次快速啟動(dòng)都使用同一鏡像文件,啟動(dòng)結(jié)束后掃描整個(gè)外存以同步系統(tǒng)狀態(tài)。ICO方法關(guān)機(jī)時(shí)間優(yōu)化非常明顯,然而系統(tǒng)使用一段時(shí)間后和鏡像記錄狀態(tài)差別越來越大,掃描外存需要時(shí)間越來越長(zhǎng),導(dǎo)致啟動(dòng)時(shí)間增加。
針對(duì)延長(zhǎng)關(guān)機(jī)時(shí)間和鏡像加載時(shí)間過長(zhǎng)題,本文分析研究了基于休眠的快速啟動(dòng)方法,提出一種開機(jī)創(chuàng)建快照(Create Image After Boot,CIAB)的優(yōu)化方法,以期縮短關(guān)機(jī)時(shí)間且減小鏡像尺寸。
SDK快速啟動(dòng)是利用Linux電源管理的掛起/恢復(fù)技術(shù)實(shí)現(xiàn)的,該技術(shù)分為兩部分:關(guān)機(jī)前通過掛起技術(shù)將系統(tǒng)當(dāng)前的CPU、內(nèi)存頁面、外部設(shè)備狀態(tài)等,按照一定格式制作成鏡像保存在外部Flash中;下次開機(jī)的時(shí)候利用恢復(fù)技術(shù)按照鏡像文件內(nèi)容恢復(fù)到上次關(guān)機(jī)狀態(tài)。掛起和恢復(fù)函數(shù)執(zhí)行流程如圖1所示。
圖1 恢復(fù)和掛起操作流程圖
內(nèi)核加載器載入并解壓縮內(nèi)核,內(nèi)核執(zhí)行完一些架構(gòu)初始化操作之后,跳轉(zhuǎn)至快速啟動(dòng)入口檢查鏡像文件是否存在,若不存在執(zhí)行正常啟動(dòng)流程。若存在則載入鏡像文件恢復(fù)系統(tǒng),恢復(fù)過程是掛起過程的對(duì)偶操作。
完成準(zhǔn)備工作,接下來是掛起/恢復(fù)流程中最重要的步驟——鏡像創(chuàng)建。
SDK快速啟動(dòng)方法主要依賴掛起過程中產(chǎn)生的鏡像,在保存狀態(tài)階段需要將系統(tǒng)的運(yùn)行狀態(tài)按照一定格式組織成鏡像文件,鏡像文件的格式如圖2所示。
圖2 鏡像組織結(jié)構(gòu)
鏡像頭存儲(chǔ)了鏡像大小、版本號(hào)等等,用來管理整個(gè)鏡像文件的數(shù)據(jù)存儲(chǔ)在鏡像元數(shù)據(jù)中,包括:鏡像文件起始內(nèi)存地址、鏡像文件起始?jí)K號(hào)和位圖索引等等。詳細(xì)結(jié)構(gòu)如圖3所示。
圖3 鏡像數(shù)據(jù)結(jié)構(gòu)
swsusp_info是鏡像頭,鏡像文件中最重要的數(shù)據(jù)結(jié)構(gòu)。swsusp_header表示整個(gè)鏡像文件的開始,其中最重要的結(jié)構(gòu)式指向位圖索引的image。內(nèi)核寫鏡像時(shí),先初始化swsusp_info,swsusp_header,接著循環(huán)申請(qǐng)內(nèi)存存儲(chǔ)鏡像內(nèi)容、寫入外存、修改swap_map_page直到整個(gè)鏡像寫入完成,最后在swsusp_info中記錄大小和版本號(hào)等信息。
讀鏡像是根據(jù)用戶設(shè)置的位置,去外存上先讀出swsusp_info和swsusp_header得到索引位圖,根據(jù)位圖依次讀出鏡像塊,并恢復(fù)到內(nèi)存。
SDK快速啟動(dòng)修改了原本的Linux關(guān)機(jī)流程,在執(zhí)行正常關(guān)機(jī)流程中添加了產(chǎn)生和保存鏡像操作??焖賳?dòng)關(guān)機(jī)流程和正常的關(guān)機(jī)流程對(duì)比如圖4所示。
圖4 關(guān)機(jī)流程對(duì)比圖
SDK快速啟動(dòng)在正常關(guān)機(jī)流程上增加的邏輯有:掛起喚醒設(shè)備、讀寫磁盤等這些相對(duì)耗時(shí)的操作。通過研究SDK方法延長(zhǎng)了40%的關(guān)機(jī)時(shí)間[4]。目前嵌入式設(shè)備常常出現(xiàn)電量耗盡關(guān)機(jī)的使用場(chǎng)景,此種情況下系統(tǒng)來不及保存鏡像指示快速啟動(dòng)失敗。綜上,該問題亟待解決。
基于休眠的快速啟動(dòng)技術(shù)的啟動(dòng)時(shí)間可形式化表示為如下:
其中tb表示內(nèi)核加載器進(jìn)行像CPU、時(shí)鐘等基本初始化的時(shí)間,是讀取休眠鏡像前的準(zhǔn)備工作;td表示從外存讀取休眠鏡像的時(shí)間;tr表示執(zhí)行恢復(fù)系統(tǒng)函數(shù)根據(jù)鏡像恢復(fù)系統(tǒng)的時(shí)間,主要包括恢復(fù)處理器、內(nèi)存、外部設(shè)備狀態(tài)、進(jìn)程狀態(tài)的時(shí)間。
由式(2)看出休眠鏡像讀取時(shí)間和休眠鏡像大小成正比,2.2節(jié)介紹了休眠鏡像的組織結(jié)構(gòu),內(nèi)存數(shù)據(jù)分為內(nèi)核空間和用戶空間。內(nèi)核空間主要有內(nèi)核代碼、內(nèi)核數(shù)據(jù)結(jié)構(gòu)、高速緩存、文件系統(tǒng)數(shù)據(jù)等組成。用戶空間保存了各個(gè)用戶進(jìn)程的地址空間。保存了內(nèi)存全部頁面,包括高速緩存和用戶進(jìn)程數(shù)據(jù)等這些并不重要的頁面,致使休眠鏡像臃腫過大。
本文提出的快速啟動(dòng)優(yōu)化方法:快照在開機(jī)之后產(chǎn)生,系統(tǒng)運(yùn)行過程中更新鏡像文件,在不延長(zhǎng)關(guān)機(jī)或者開機(jī)時(shí)間前提下,任意時(shí)刻外存上存儲(chǔ)了一個(gè)和關(guān)機(jī)前系統(tǒng)狀態(tài)盡可能相同的鏡像文件。
CIAB方法產(chǎn)生的鏡像文件中存儲(chǔ)的并不是關(guān)機(jī)之前系統(tǒng)狀態(tài),使用此鏡像文件恢復(fù)系統(tǒng)將導(dǎo)致快速啟動(dòng)和正常啟動(dòng)進(jìn)入的系統(tǒng)的不一致問題。不一致問題有用戶掛載新文件系統(tǒng)導(dǎo)致的文件系統(tǒng)的不一致和用戶新修改了系統(tǒng)設(shè)置導(dǎo)致的設(shè)置不一致。
CIAB方法不一致問題整體設(shè)計(jì)如圖5所示。
圖5 CIAB方法設(shè)計(jì)圖
系統(tǒng)設(shè)置數(shù)據(jù)和文件系統(tǒng)元數(shù)據(jù)都存儲(chǔ)在鏡像圖5所示位置中,對(duì)于系統(tǒng)設(shè)置,快速啟動(dòng)成功后創(chuàng)建守護(hù)進(jìn)程同步。對(duì)于文件系統(tǒng)元數(shù)據(jù),系統(tǒng)運(yùn)行過程中創(chuàng)建守護(hù)進(jìn)程,定時(shí)同步鏡像保存文件系統(tǒng)元數(shù)據(jù)。
正常啟動(dòng)過程中的掛載文件系統(tǒng),實(shí)際上是讀取外存設(shè)備上的文件系統(tǒng)元數(shù)據(jù)至內(nèi)存,比如說超級(jí)塊、根索引節(jié)點(diǎn)等等,虛擬文件系統(tǒng)用這些數(shù)據(jù)創(chuàng)建file_system_type用以管理文件系統(tǒng)。內(nèi)核用鏈表結(jié)構(gòu)管理全部的file_system_type,表頭由file_systems變量指定,此鏈表是需要同步的數(shù)據(jù)。
CIAB方法創(chuàng)建休眠鏡像結(jié)束時(shí),修改hibernate.c/hibernate函數(shù)正常退出模塊,再次調(diào)用內(nèi)核函數(shù)swap_write_pages在鏡像文件之后記錄file systems,塊號(hào)記錄在fastboot_block變量中。修改之后鏡像結(jié)構(gòu)如圖6所示。
圖6 修改之后的鏡像文件
創(chuàng)建守護(hù)進(jìn)程定時(shí)讀取file_systems鏈表,詳細(xì)流程如圖7所示。
圖7 同步文件系統(tǒng)流程圖
休眠鏡像創(chuàng)建完成后,申請(qǐng)內(nèi)存空間存儲(chǔ)file systems鏈表節(jié)點(diǎn),調(diào)用函數(shù)把該頁寫入swap,此時(shí)鏡像內(nèi)容修改完成。接下來修改鏡像頭存儲(chǔ)的鏡像大小、鏡像元數(shù)據(jù)記錄的位圖信息,設(shè)置鏡像不壓縮標(biāo)志,最后文件系統(tǒng)同步進(jìn)程完成全部工作進(jìn)入睡眠。
只有在用戶掛載了新的文件系統(tǒng)的情況下,file systems鏈表才有變化,因此同步文件系統(tǒng)頻率不高。
用戶在交互使用應(yīng)用過程中會(huì)根據(jù)自己的需要調(diào)整應(yīng)用的設(shè)置,這保證了不同的用戶能夠按照自己的需求定義不同的設(shè)置,快速啟動(dòng)鏡像文件并未保存用戶的最新設(shè)置,因此帶來系統(tǒng)設(shè)置不一致問題。這些交互設(shè)置包括桌面設(shè)置、網(wǎng)絡(luò)設(shè)置等。
系統(tǒng)常用配置常存儲(chǔ)在/etc下,比如桌面壁紙和app icon設(shè)置存儲(chǔ)在/etc/desktop文件中,網(wǎng)絡(luò)設(shè)置位于/etc/networking等等。專用的嵌入式設(shè)備要求一些特殊配制,像智能車載電腦要求記錄用戶播放列表位置等。
CIAB方法解決系統(tǒng)設(shè)置不一致問題詳細(xì)流程如圖8所示。
Bootloader載入鏡像文件,內(nèi)核執(zhí)行完基本初始化操作,調(diào)用函數(shù)hibernate.c/load_image_and_restore按照鏡像文件恢復(fù)系統(tǒng)。讀取/etc/desktop/config、/etc/networking/config和/etc/fastboot_config.xm l,根據(jù)配置文件修改系統(tǒng),同步完成后顯示用戶登錄界面,之后掛起系統(tǒng)創(chuàng)建下次啟動(dòng)使用的鏡像文件。
圖8 同步系統(tǒng)設(shè)置流程圖
本文研究基于快照的嵌入式Linux的快速啟動(dòng),在ARM體系結(jié)構(gòu)下,選用FriendlyARM mini2440硬件平臺(tái)、Ubuntu for ARM操作系統(tǒng)加上qq、小企鵝、紙牌游戲、照相機(jī)和瀏覽器等軟件。使用printk得到優(yōu)化前后的啟動(dòng)時(shí)間和關(guān)機(jī)時(shí)間,分別對(duì)SDK方法、CIAB方法、NRC方法、ORK方法和ICO方法進(jìn)行對(duì)比。
圖9 快速啟動(dòng)開關(guān)機(jī)時(shí)間對(duì)比圖
從圖9看出,各個(gè)快速啟動(dòng)方法和正常開機(jī)時(shí)間相比節(jié)省都超過60%,其中ICO方法啟動(dòng)結(jié)束之后需要掃描外存同步系統(tǒng)數(shù)據(jù),和SDK等快速啟動(dòng)方法相比,花費(fèi)時(shí)間最長(zhǎng),隨著用戶的使用,掃描硬盤耗時(shí)必將越來越高。NRC方法不保存干凈內(nèi)存頁面、ORK只保存內(nèi)核空間內(nèi)存頁面和本文提出的CIAB方法開機(jī)之后內(nèi)存處于干凈狀態(tài)下創(chuàng)建鏡像,均優(yōu)化了鏡像大小,相較于SDK方法啟動(dòng)時(shí)間略有縮短。
關(guān)機(jī)時(shí)間對(duì)比圖中,SDK、NRC和ORK方法關(guān)機(jī)之前創(chuàng)建休眠文件,關(guān)機(jī)時(shí)間比正常關(guān)機(jī)延長(zhǎng)了65%左右。SDK方法休眠鏡像保存全部?jī)?nèi)存頁面,花費(fèi)的關(guān)機(jī)時(shí)間最長(zhǎng)。NRC方法通過關(guān)機(jī)之前申請(qǐng)大量?jī)?nèi)存迫使內(nèi)核回收干凈頁面來減少鏡像存儲(chǔ)內(nèi)存頁面數(shù)量,而ORK方法通過虛擬地址選擇,ORK比NRC關(guān)機(jī)時(shí)間更短。CIAB和ICO方法并為修改原本的關(guān)機(jī)邏輯,關(guān)機(jī)時(shí)間和正常關(guān)機(jī)相同。
綜上,CIAB方法開機(jī)之后大量用戶進(jìn)程運(yùn)行之前創(chuàng)建鏡像,和各個(gè)基于休眠的快速啟動(dòng)方案相比,在縮短關(guān)機(jī)時(shí)間和減小鏡像文件大小方面優(yōu)化顯著。
本文通過分析Linux掛起/恢復(fù)技術(shù),利用現(xiàn)有的SDK快速啟動(dòng)方法,提出一種CIAB快速啟動(dòng)優(yōu)化方法,這種方法在縮短SDK關(guān)機(jī)時(shí)間方面優(yōu)化顯著。這對(duì)研究嵌入式Linux啟動(dòng)過程和加快嵌入式Linux啟動(dòng)速度方面有重要的研究和借鑒意義。然而由于鏡像文件中僅僅保存了內(nèi)存中的基本系統(tǒng)數(shù)據(jù),下一步工作將著力于解決CIAB方法會(huì)導(dǎo)致啟動(dòng)結(jié)束后系統(tǒng)的響應(yīng)時(shí)間變長(zhǎng)問題。