劉宇帥 蘇 宇 王金波 吳晨陽
1. 中國科學院大學,北京 100049 2.中國科學院空間應用工程與技術中心,北京 100094
為了適應更為復雜的空間環(huán)境并完成繁雜的空間任務,近些年來航天領域的嵌入式軟件系統(tǒng)從應用規(guī)模、復雜度及重要性程度都保持持續(xù)上升態(tài)勢。相較于UC/OS難以滿足復雜的多接口通信需求,VxWorks價格昂貴且不公開源碼的問題,Linux以其穩(wěn)定、開源以及容易移植等優(yōu)勢,逐漸應用在國外航空航天領域。2014年1月,日本宇宙航空研究開發(fā)機構JAXA將太陽觀測衛(wèi)星“日出”(SOLAR-B),以及觀測衛(wèi)星GEOTAIL的衛(wèi)星管制功能轉移至Linux平臺上;Space X已將Linux廣泛應用于航天器中,且好奇號火星探測器部分控制已由Linux實現(xiàn)。而國內在該領域的研究和應用尚屬空白。
隨著我國載人航天工程邁入載人空間站階段,載荷種類、數(shù)量和復雜度均成倍增長,在未來航天器的建設中,需要利用實時操作系統(tǒng)在機制上給予保障,以保證系統(tǒng)的穩(wěn)定、可靠與高質量,并提高軟件的開發(fā)效率。Linux作為一個通用操作系統(tǒng),雖然有許多優(yōu)越的特性[1],但其實時性能有限[2],切換時間的不確定性對系統(tǒng)安全性造成嚴重威脅,甚至有可能造成災難性事故,如1996年阿麗亞娜V運載火箭失事。優(yōu)先級反轉對系統(tǒng)有致命危害,會導致任務錯亂、邏輯錯亂,造成任務調度時時間的不確定性,甚至有可能致使系統(tǒng)崩潰。例如火星探路者號(Mars Pathfinder),曾由于優(yōu)先級反轉,導致內部執(zhí)行邏輯出現(xiàn)bug,系統(tǒng)無故重啟。因此,針對空間站下一階段有效載荷多線程、高并發(fā)的特點,提出采用基于Preempt RT補丁的Linux系統(tǒng)作為有效載荷的控制系統(tǒng),為保證在空間站階段操作系統(tǒng)的穩(wěn)定性和可靠性要求,將與空間站密切相關的任務切換時間、優(yōu)先級反轉作為重點進行分析研究。
標準Linux是一款優(yōu)秀的分時操作系統(tǒng),追求的是高的系統(tǒng)吞吐率和公平性[3],但實時性不佳,主要體現(xiàn)在以下幾個方面:
1)內核不完全可搶占,相比2.4版本的內核,2.6版本開始引入了內核搶占機制,但內核對關鍵代碼進行保護,仍然有相當一部分區(qū)域禁止搶占,大大增加任務切換時間的不確定性;
2)時鐘顆粒度粗糙,2.6版本內核時鐘精度可達1000Hz,但過度提高內核時鐘精度又會犧牲系統(tǒng)的吞吐率;
3)關中斷問題,內核在接收到外部中斷進入中斷處理程序后,會暫時關閉系統(tǒng)中斷;
4)優(yōu)先級翻轉問題,標準Linux內核并未對優(yōu)先級翻轉問題采取保護措施,導致低優(yōu)先級任務搶占高優(yōu)先級任務,造成不可預知的后果。
以上特性對于有實時性要求的系統(tǒng)來說是不可容忍的,有可能給空間站系統(tǒng)帶來巨大的不確定性。因此非常有必要提升Linux的實時性能。
標準的Linux 并未提供實時的操作系統(tǒng)內核[4],但其開源特性讓我們可以通過改造實現(xiàn)實時性需求。目前主要有以下2種方式:①直接對標準的Linux內核進行修改,增強其實施性能;②采用雙內核方案,對標準的Linux內核進行外部實時性擴展,以內核可加載模塊的方式實現(xiàn)一個實時微內核,將所有實時任務都交由實時內核來處理[5]。與對Linux內核進行外部實時擴展相比,對內核修改使其應用程序的開發(fā)與標準毫無區(qū)別,可以充分利用Linux內的各種系統(tǒng)調用,更適合在現(xiàn)有平臺上進行Linux實時性的測試和研發(fā)。綜上,本文提出對標準Linux內核實時化的優(yōu)化方案:重寫實時互斥鎖、改變優(yōu)先級調度策略、增加可搶占點及為提高中斷響應使其線程化等方面進行優(yōu)化,如圖1所示。因此,本文通過選取Preempt RT補丁的方案來提升Linux內核實時性。
圖1 Linux內核優(yōu)化示意圖
實時搶占補丁(Realtime Preemption Patch,Preempt RT)由Ingo Molnar 和 Thomas Gleixner更新維護[6],并且由開源自動化實驗室(OSADL)測試其穩(wěn)定性。核心思想是提高內核本身的可搶占性,即讓盡可能多的代碼能夠被搶占。其實現(xiàn)方法和原有的增加實施搶占方法不同,它是在原有低延遲補丁和搶占補丁的基礎上加入中斷線程化、高精度時鐘、優(yōu)先級繼承等新特性,將Linux內核修改成完全可搶占式內核,使其具有硬實時能力[7]。實時搶占補丁最小化了內核中不可搶占部分的代碼,同時也最小化了為支持搶占性所必須要修改的代碼量[8]。
可搶占內核的實現(xiàn)對Linux具有非比尋常的意義。首先,這是將Linux應用于實時系統(tǒng)所必需的。嚴苛的響應時間限制是實時系統(tǒng)的特性之一,設備發(fā)生中斷后會喚醒實時進程,該進程需要在規(guī)定時間內調度執(zhí)行。但現(xiàn)有內核是不可搶占的,無法實現(xiàn)該要求,且內核中的響應時間不可控。在實際運行過程中,當較長的系統(tǒng)調用被執(zhí)行時,實時進程只有在當前內核運行進程完全退出時才能執(zhí)行,現(xiàn)有環(huán)境條件下的延遲時間達到100ms的數(shù)量級,對于有高實時響應要求的系統(tǒng)來說是不能容忍的。因此可搶占內核不僅對Linux實現(xiàn)實時性意義非凡,也改善了Linux對某些低延遲應用不能有效支持的問題。
補丁引入了一組正交機制,減少內核延遲并使內核更具確定性。其中一些機制(例如高分辨率計時器和優(yōu)先級繼承)已經(jīng)被合并到了主線內核[9]。補丁對內核的提升是多方面的,本文將與空間站密切相關的任務切換時間、優(yōu)先級反轉作為重點進行分析。
2.2.1 上下文切換時間
進程運行過程中CPU所包含的信息,包括寄存器值、進程狀態(tài)和堆棧內容被稱為該進程的上下文。當進程被其他進程搶占發(fā)生中斷時,系統(tǒng)會將CPU中包含的信息保存,并將搶占了CPU活動進程的上下文信息加載入CPU,整個過程稱為上下文切換。而當被搶占進程重新獲得CPU等資源再次執(zhí)行時,它能恢復自己的上下文信息并從中斷時刻重新開始執(zhí)行,其實質就是被中斷運行的進程與準備運行的進程實現(xiàn)在CPU中上下文的切換。切換時間就是計算從保存被搶占進程的上下文、到恢復某一原先被搶占進程中被保存的上下文信息、最后將控制傳遞給這個新恢復的進程整個過程的時間就是切換時間。
標準Linux內核采用spin_lock(自旋鎖)保護臨界資源,spin_lock的一個特點是進入臨界區(qū)時禁用搶占;而Preempt-rt補丁通過采用rt_mutex代替?zhèn)鹘y(tǒng)的禁用搶占的spin_lock,并定義了新的數(shù)據(jù)類型:spin_lock_t,即凡是使用了該數(shù)據(jù)類型的spin_lock不會禁用內核搶占。因此內核中不可搶占區(qū)域進一步減少,增加了內核的搶占點,降低了上下文切換時間不確定性。
2.2.2 優(yōu)先級反轉
優(yōu)先級反轉指具有較低優(yōu)先級任務占有較高優(yōu)先級任務所需的共享資源,高優(yōu)先任務因資源無法獲得而被迫掛起,直至較低優(yōu)先級任務釋放該資源為止。由于低優(yōu)先級得到CPU時間短,若該時刻有優(yōu)先級處于高低優(yōu)先級之間的任務就緒,且不用該共享資源,則該中優(yōu)先級任務將獲得CPU時間。
如圖2所示,假設此時系統(tǒng)中有A,B,C三個線程,優(yōu)先級依次降低,其中線程A和線程C在運行過程中都需同一共享資源。程序開始執(zhí)行,線程C獲得資源開始運行,線程A由于優(yōu)先級最高在T1時刻搶占CPU并運行。線程A需要的資源正被線程C占用,因此在T2時刻讓出CPU,與此同時優(yōu)先級較高的線程B獲得調度搶占了CPU,直至T3時刻運行完成讓出CPU。線程B運行結束后線程C繼續(xù)執(zhí)行。T4時刻,線程C運行結束釋放共享資源,線程A獲得資源最后運行。由此發(fā)現(xiàn),線程A雖然具有最高優(yōu)先級卻最后才得到運行。
圖2 優(yōu)先級翻轉示意圖
Linux進程調度采用動態(tài)優(yōu)先級調度方式。系統(tǒng)會根據(jù)每個進程的優(yōu)先級和它所采用的調度策略[10]計算權值,并以此進行調度,簡單而有效。
優(yōu)先級反轉解決方案主要有:(1)設置優(yōu)先級的上限,為臨界區(qū)設定某個高優(yōu)先級,進入該臨界區(qū)的每個進程,如果優(yōu)先級低于設定的上線,就會獲得這一優(yōu)先級;(2)優(yōu)先級繼承,如果較高優(yōu)先級進程正在等待某一較低優(yōu)先級進程正在占用的資源時,則低優(yōu)先級進程優(yōu)先級會提升到和高優(yōu)先級進程一樣的優(yōu)先級,在釋放共享資源后,進程優(yōu)先級能恢復到原有優(yōu)先級狀態(tài);(3)采用中斷禁止,以禁止中斷的方法保護臨界區(qū)。在該方法下系統(tǒng)只存在2種優(yōu)先級:1)可搶占優(yōu)先級,是進程一般運行過程中所擁有的優(yōu)先級;2)中斷禁止優(yōu)先級,在臨界區(qū)運行時擁有的優(yōu)先級。
Preempt RT補丁中采用優(yōu)先級繼承協(xié)議的方法解決此問題。Preempt RT補丁為實現(xiàn)優(yōu)先級繼承,在內核中增加了名為rt_mutex的互斥鎖。在具有補丁Preempt RT的Linux內核中,自旋鎖和互斥體將轉換為實時互斥體。旋轉鎖轉換為實時自旋鎖,使用rt_mutex實現(xiàn)互斥[11]。
rt_mutex是互斥鎖結構,包含3個元素。
struct rt_mutex {
raw_spinlock_t wait_lock; /* 保護自旋鎖 */
struct plist_head wait_list; /* 等待所有waiter鏈表 */
struct task_struct *owner; /* 獲得鎖的task,沒有為NULL */
}
rt_mutex_waiter結構是作為task在rt_mutex上掛起時的連接件而存在的,其實它邏輯上應該是task_struct的一部分。rt_mutex waiter的數(shù)據(jù)結構如下,用于記錄等待互斥鎖的結構:
struct rt_mutex_waiter {
struct plist_node list_entry;/* 用于將此結構連接到對應的互斥鎖上 */
struct plist_node pi_list_entry;/*連接到互斥鎖所有者上等待鏈表 */
struct task_struct *task; /* 此waiter所屬的task,等待此mutex的task */
struct rt_mutex *lock;/* 此waiter等待的mutex */
};
pi_waiters是進程描述符 task_struct中用來鏈入等待該進程持有的資源的等待者中優(yōu)先級最高的rt_mutex_waiter。task通過pi_waiters遍歷到在它持有的每個rt_mutex上掛起的最高優(yōu)先級的task(稱作top waiter)。整個遍歷方式都由plist提供,與其相應的不同task優(yōu)先級將作為掛起的rt_mutex_waiter排序的依據(jù)。這樣,一個task能繼承到的優(yōu)先級就是通過pi_waiters取到的第一個rt_mutex_waiter所對應的task的優(yōu)先級。rt_mutex則通過wait_list遍歷在它身上掛起的rt_mutex_waiter,從而遍歷到掛起的task。在此需要注意的是rt_mutex.wait_list中進程優(yōu)先級的變化會引起top waiter優(yōu)先級的改變,此時需要將原來的top waiter從task_struct的pi_waiters里面移出,再把新的top waiter加進去,為確保這一流程有序實現(xiàn),rt_mutex.wait_list也應該是一個優(yōu)先級已經(jīng)排序的plist。綜上所述,preempt RT通過優(yōu)先級的繼承解決了優(yōu)先級反轉的問題。
實時操作系統(tǒng)是一個按照時序方式調度和執(zhí)行任務、保證任務時間需求和管理系統(tǒng)資源的系統(tǒng)程序,其主要特點是響應及時和可靠性高[12]。因此,在闡述了Linux內核實時性能差的問題,并對Preempt RT進行分析后,下面對基于Preempt RT補丁的Linux的實時性從任務切換時間、優(yōu)先級反轉方面的問題進行測試驗證。
接口隨著嵌入式系統(tǒng)越來越復雜,功能越來越強大,在設計中既需要非常靈活的FPGA,又需要處理器去做一些控制,以及配合操作系統(tǒng)使用。因此本次實驗基于Xilinx公司ZYNQ7000系列ZC7045處理器。
ZYNQ-7000是第一代可擴展處理平臺(Extensible Processing Platform,EPP),同時具有軟件、硬件和IO均可編程的特性。傳統(tǒng)模式中,F(xiàn)PGA和ARM之間的通信經(jīng)常成為系統(tǒng)的瓶頸。在ZYNQ7000平臺系列中,將FPGA和ARM集成在一個芯片內部,兩者之間的通信使用AXI_HP、AXI_GP、AXI_ACP三種接口通信,帶寬可達吉比特,解決了二者通信帶寬不足的問題。
3.2.1 測試設計
創(chuàng)建兩個或多個進程,某個進程在執(zhí)行過程中被其他進程搶占或自動掛起而讓出CPU,同時新進程開始執(zhí)行,進而完成進程間的切換,通過多次循環(huán)切換來統(tǒng)計進程間切換時間。在本設計中以父子進程之間通過管道通信完成上下文切換為例。
在進程中創(chuàng)建子進程,同時創(chuàng)建2個管道并在管道中存放定量數(shù)據(jù),管道A被用于子進程的讀操作和父進程的寫操作,管道B被用于父進程的讀操作和子進程寫操作。
程序運行時,子進程循環(huán)先讀取管道A中數(shù)據(jù)并將其寫入管道B中,當沒有數(shù)據(jù)讀入時被阻塞,而后跳轉入父進程。父進程循環(huán)讀取管道B數(shù)據(jù)并寫入管道A,當沒有數(shù)據(jù)讀入時被阻塞再次跳轉回子進程,這就完成一組父子進程切換。在最初進入子進程時和最后退出父進程時分別獲取時間。在父子進程執(zhí)行過程中為確保不被其他進程搶占CPU,在其執(zhí)行時優(yōu)先級設置為最高。將上述過程進行5000次循環(huán)獲取10000次上下文切換的平均時間,測試流程如圖3所示。
圖3 上下文切換測試流程圖
3.2.2 實驗結果及分析
首先在標準Linux內核中進行測試,得到的結果如圖4所示;再將標準內核打入PREEMPT RT補丁,重新配置內核,選擇Fully Preemptible Kernel (RT)選項,編譯內核并將其移植到ZC7045處理器平臺測試,結果如圖5所示,在程序執(zhí)行過程中,增加CPU的負載壓力,結果如圖6所示:
圖4 標準內核上下文切換時間測試結果
圖5 補丁內核無負載切換時間
圖6 補丁內核有負載切換時間
將上述實驗數(shù)據(jù)進行對比分析可得:對比圖4和5不難看出,Preempt RT補丁可以使內核上下文切換10000次的平均時間范圍更加集中,補丁內核的切換時間平均值為15.9μs,方差為0.88,均小于標準內核16.6μs的平均時間和1.36的方差,Preempt RT補丁內核在一定程度上提高了內核的穩(wěn)定性;同時對比圖5和6,在系統(tǒng)負載增加時,上下文切換的平均值的最大值略有增加,但基本滿足軟實時系統(tǒng)的要求。
運用相關工具對切換時間進行上萬次實驗,結果如表1所示,補丁內核的最大值為167μs,滿足航天領域期望的最大值不超過200μs的要求,而標準內核峰值達到500μs以上,甚至達到9166μs,切換時間極不穩(wěn)定。
表1 切換時間/μs
3.3.1 測試設計
通過程序捕獲優(yōu)先級反轉:模擬優(yōu)先級反轉的過程,在程序中設置標記位,分別標記高中低3個進程占用資源的情況和是否開始運行,中優(yōu)先級進程運行時進行標記置1,在高優(yōu)先級進程執(zhí)行時,通過對標識位判定確定是否發(fā)生優(yōu)先級反轉,如果標記中優(yōu)先級進程已經(jīng)執(zhí)行,則表明發(fā)生反轉,反之,則表明通過優(yōu)先級繼承解決了反轉問題。
實現(xiàn)方案:模擬優(yōu)先級反轉的過程,在程序運行過程中通過捕獲優(yōu)先級反轉判斷是否發(fā)生反轉,程序流程圖如圖7所示:
圖7 優(yōu)先級反轉程序流程圖
3.3.2 測試及結果分析
通過5000次試驗可知,在Preempt RT補丁內核上未捕捉到優(yōu)先級反轉,而標準內核則全部捕捉到優(yōu)先級翻轉,由此得出,Preempt RT補丁解決了優(yōu)先級反轉的問題。
分析研究了Linux操作系統(tǒng)在實時性方面的問題,并通過增加PREEMPT RT搶占補丁提高其實時性能,在基于ZYNQ-7000處理器的平臺上對其進行了測試。實驗結果顯示實時可搶占補丁對Linux的實時性具有較好的提升,達到軟實時操作系統(tǒng)的性能要求。綜上, 基于PREEMPT RT補丁內核滿足載人航天應用領域中對非硬實時嵌入式操作系統(tǒng)的要求,大大降低了載人航天工程的成本和開發(fā)難度,同時加快了我國載人航天技術向民用方向發(fā)展的步伐。
參 考 文 獻
[1] Fayyad-Kazan H, Perneel L, Timmerman M. Linux PREEMPT-RT v2.6.33 Versus v3.6.6:Better or Worse for Real-time Applications?[J]. Acm Sigbed Review, 2014, 11(1):26-31.
[2] 祁磊. 基于ARM的嵌入式系統(tǒng)內核移植及實時性研究[D].蘭州:蘭州交通大學, 2016.
[3] 蘇宇, 張濤, 孫黎. 基于Xenomai的實時Linux系統(tǒng)的研究[J]. 計算機技術與發(fā)展, 2013(10):1-5. (Su Yu,Zhang Tao,Sun Li. Research on Real-time Linux System Based on Xenomai[J]. Computer Technology and Development, 2013(10):1-5.)
[4] 介龍梅, 徐有軍, 邵國強. 嵌入式Linux內核實時性測試研究[J]. 智能計算機與應用, 2016, 6(3):105-107.(Jie Longmei,Xu Youjun,Shao Guoqiang. The Research on the Real-time Performance Test of Embedded Linux Kernel[J].Intelligent Computer and Applications, 2016, 6(3):105-107.)
[5] 劉勝, 王麗芳, 蔣澤軍. 基于多核 PC 的 Linux 系統(tǒng)實時性改造[J]. 微電子學與計算機, 2013(8):120-123. (Liu Sheng,Wang Lifang,Jiang Zejun. Resconstruct Real-time of Linux Based on Multicore Computer[J]. Microelectronics & Computer, 2013(8):120-123.)
[6] Fayyad-Kazan H, Perneel L, Timmerman M. Linux PREEMPT-RT vs. Commercial RTOSs: How Big is The Performance Gap?[J]. Gstf Journal on Computing, 2014.
[7] 張曉龍, 郭銳鋒, 陶耀東,等. Linux實時搶占補丁研究及實時性能測試[J]. 計算機工程, 2014, 40(10):304-307.(Zhang Xiaolong, Guo Ruifeng,Tao Yaodong,Liu Sheng. Research of Linux Real-time Preemption Patch and Real-time Performance Measure[J]. Computer Engineering, 2014, 40(10):304-307.)
[8] 董艷雪, 韓衛(wèi)光. 基于多核ARM的Linux操作系統(tǒng)的實時性研究[J]. 小型微型計算機系統(tǒng), 2017, 38(6):1262-1266.(Dong Yanxue,Han Weiguang. Real-time Research of Linux System Based on the Multi-core ARM Platform[J]. Journal of Chinese Computer Systems, 2017, 38(6):1262-1266.)
[9] Scordino C, Scordino C, Abeni L, et al. Deadline Scheduling in the Linux Kernel[J]. Software—practice & Experience, 2016, 46(6):821-839.
[10] Oliveira D B, Oliveira R S. Timing Analysis of the PREEMPT RT Linux Kernel[J]. Software Practice & Experience, 2016, 46(6):789-819.
[11] 黃芳. 基于ARM和RTAI的嵌入式實時平臺的設計與實現(xiàn)[D]. 沈陽:中國科學院研究生院(沈陽計算技術研究所), 2014.
[12] 鄭祥. 淺析Linux進程調度策略[J]. 科技致富向導, 2013(12):22.