王 娜, 李彥峰,2, 孫菲艷, 汪 辰
(1 金陵科技學院 南京軟件研究院, 南京 211169; 2 中國科學院 軟件研究所, 北京 100190)
Linux操作系統以其開源、可移植的優勢,以及穩定和支持多種處理器結構的特點受到諸多嵌入式產品開發者的青睞,成為嵌入式領域發展最快的操作系統。作為一個通用的操作系統,Linux本身也對實時性做了一定的考慮,但是仍有很多不足。
目前針對Linux的實時化改造,業界已推出多種方案。其中的實時搶占補丁(PREEMPT_RT patch)即因其簡潔設計以及與內核主線的一致性,獲得工業控制領域的廣泛關注,并且PREEMPT_RT補丁(以下簡稱PREEMPT_RT)對Linux的實時化改造正在不斷地被吸收融入到Linux主線中,成為Linux實時化改造的主流設計理念。
中斷管理的高效、可靠是系統設計的關鍵部分之一,如果設計不良則可能造成不必要的硬件等待,使得整個任務處理出現延滯。PREEMPT_RT引入了中斷線程化的思路,改善由于中斷處理導致的內核延遲的問題。目前很多研究實驗均已表明中斷線程化可有助于減少內核的搶占延遲,從而整體提升實時任務的處理性能。但中斷線程化對于中斷延時的影響,現有研究結論卻并不一致。一部分研究推證出中斷線程化可以降低中斷延時[1],另外有些研究則指出,中斷線程化會導致中斷延時的增加[2]。綜上論述可知,本文將基于PREEMPT_RT對中斷線程化的實現進行分析,并據此研發提出了一種中斷延遲時間的測試方法,接下來又基于TI AM3358處理器的開發板進行測試驗證,得出了中斷線程化對中斷延遲時間影響的結論,同時還設計提出了實時中斷和非實時中斷的概念,對基于PREEMPT_RT內核的驅動開發具有較強的指導意義。
處理硬件中斷是造成內核響應延遲的一個重要原因。分析原因可知,硬件處理某一個中斷的過程中,其它中斷是被阻塞的。傳統Linux內核處理中斷的過程,從系統檢測到一個中斷開始,一直到中斷的處理程序運行結束,處理中斷的CPU一直處于關中斷的狀態, 整個過程中斷和任務均無法得到響應,造成中斷響應時間、任務調度時間不確定。
針對這一問題,Linux系統引入了中斷上半部、底半部的概念。當運行于中斷底半部程序時,中斷被使能,這在一定程度上就減少了系統關中斷的時間,但就效果改觀而言卻極為有限。首先,系統處理底半部中斷時,仍然不支持高優先級任務的調度,增加了任務調度時間的不確定性。其次,底半部的設計思想語意含糊,在系統中常常作為一種改進建議,而不是強制規范。事實上,一般用戶很難清晰地界定哪部分是中斷服務的上半部分,哪部分是底半部分,因此用戶完全可能將其繞過,就使得中斷編程的隨意性增大,難以達到滿意的綜合設計效率[2]。通過以上分析可知,系統運行中斷的過程中,中斷響應和任務調度的時間均存在較大的不確定性,受到中斷任務本身工作量的干擾,運行時間無法得到保證,因而難以滿足實時性的要求。
PREEMPT_RT延續了中斷上半部、底半部的設計思路,提出了中斷線程化的概念,將中斷事件集合中的絕大部分置于內核線程中進行處理。通過喚醒線程使中斷得以執行,其結果是增強了內核的可搶占性,使得實時任務能夠獲得及時處理。
中斷線程化的核心思想就是將中斷任務盡可能地放到內核線程中去完成,原則上,可以將中斷處理的全部工作均投放至線程中去,但也有例外,譬如對于共享中斷線的一些處理,就必須定制在硬中斷上下文中實現,研究中將這部分的處理稱作快速檢測處理程序,而將中斷過程中除此之外的處理稱作中斷主處理程序。整個中斷處理花費的時間,將主要消耗在中斷主處理程序上,所以中斷主處理程序的運行時間決定了系統關中斷的時間。研究推得偽代碼可參見表1。由表1可知,中斷線程化前的代碼結構中,快速檢測處理程序和中斷主處理程序都是在硬件中斷上下文中被執行的,這個過程中系統處于關中斷狀態。中斷線程化之后,中斷主處理程序執行被放入到內核線程中去處理,硬件中斷上下文中原定執行中斷主處理程序的部分現在卻只需完成喚醒中斷線程這一個動作,大大減少了系統的關中斷時間。
表1中斷線程化前后中斷處理偽代碼
Tab.1Interruptprocessingpseudo-codebeforeandafterthreadedinterrupt

中斷線程化前中斷線程化后on each IRQ reacheddohard_cli();IRQ_handler(); 快速檢測處理程序; 中斷主處理程序;hard_sti();doneon each IRQ reacheddohard_cli();IRQ_handler(); 快速檢測處理程序; 喚醒中斷線程;hard_sti();done……irq_thread: 中斷主處理程序;
中斷線程在內核中的默認設置是實時優先級為50,調度策略為SCHED_FIFO的實時內核線程。這樣一來,在中斷線程的運行過程中,如果有優先級大于50的實時進程進來,中斷線程的處理被掛起,系統轉而去執行實時任務,從而保證了實時任務的及時運行,增加了系統的確定性。
對于被線程化的中斷,系統接收到中斷后,并不是直接進入中斷服務函數,而是通過設置調度標志告知系統,當中斷線程被實際調度,此時才能真正開始執行中斷處理函數。另外,中斷線程的運行還有可能會被更高優先級的實時任務打斷。相應地,對于被線程化的中斷來說,自身的優先級就被降低了。因此,中斷線程化實質上是降低了中斷自身的響應速度,減少了系統的關中斷時間,在提高系統可搶占性的同時,也一并優化了系統的實時性能。
通過原理分析可以看出,中斷線程化使得中斷自身的優先級被降低,考慮到有些中斷的響應必須及時(例如:系統的時鐘中斷),Linux搶占內核對中斷線程化也給出了靈活處理,增加了IRQF_NODALY標志位,用戶在申請某一個中斷時,如果設置了此標志位,則此中斷將被禁止中斷線程化。這樣的設計相當于給中斷賦予了優先級,將系統的中斷分為實時中斷和非實時中斷。具體來說,實時中斷可以通過設置IRQF_NODALY實現,運行在關中斷狀態的中斷上下文; 非實時中斷則可做到中斷線程化,運行在開中斷狀態,并且可以被搶占的進程上下文。
基于中斷線程化的原理分析可知,從系統整體性能來看,中斷線程化減小了系統關中斷時間,增加了內核的可搶占性,從而降低了系統的搶占延遲時間,但是對于被線程化的中斷本身,其處理優先級卻被降低,于無形中就增加了中斷的延遲處理時間。目前,對于Linux內核的搶占延遲時間的測量,已經可以見到較為成熟的測試工具。諸如,rttest包中的cyclictest用于測試系統搶占延遲時間即已得到廣泛應用,但是,對于中斷延遲時間的測試,還沒有一個可以供研究者直接調取的通用測試程序。在此情況下,本文即研發提出了一種簡單方便的方法用來測試中斷延遲時間。對此可做探討論述如下。
中斷延遲時間是指,從中斷被觸發開始到中斷處理函數的第一條指令執行所經歷的時間。本文提出了一種測試中斷延時的方法,選取系統中的一個定時器硬件,通過計算定時器中斷的響應延遲,獲取系統的中斷延時時間。如圖1所示,設置定時器的間隔時間為period,在ts時刻啟動定時器,那么定時器中斷理論上應該在ts+period時刻觸發,事實上,由于中斷延遲的存在,實際的中斷執行時間要遲于理論計算時間,假設在th時刻,中斷處理程序的第一條指令被執行,那么中斷延遲時間ti就可以通過計算得來。計算公式的數學表述如下:
ti=th-ts-period
(1)

圖1 測試原理
首先選取一個定時器硬件,本文選用TI開發板的Dmtimer3硬件作為定時器的中斷觸發源。然后設置此定時器每隔100 us觸發一個中斷,設置中斷到時處理函數。在定時器啟動時獲取中斷觸發時間ts,定時器中斷到來的中斷處理函數的第一句代碼中獲取中斷到來時間th,兩者的差值即為中斷延時時間,此后重新使能定時器,開始下一輪中斷,循環測試。測試程序主要代碼可詳見如下。
//定時器使能函數irq_enalbe
omap_dm_timer_start(timer_ptr);
//獲取定時器啟動時間
do_gettimeofday(&ts);
……
//定時器中斷處理函數
do_gettimeofday(&th);
//計算本次中斷響應延遲時間
diff=timeval_sub(th,ti)-period;
//重新使能定時器,開始下一輪的測試
irq_enable()
實驗基于TI AM3358處理器開發板設計展開,此開發板使用ARM Cortex-A8核心,主頻為800 MHz,內存采用512 M的DDR3內存。實驗使用的非實時測試環境內核原始版本為linux-3.2.0,搶占內核版本在原始版本基礎上打上PREEMPT-3.2.0-rt10補丁。
為了更加直觀地探察中斷線程化對系統的影響以及對中斷自身的影響,使用本文推介的中斷延遲測試方法,設計構建了2類實驗。內容闡釋如下。
(1)對系統影響實驗:設計一個中斷負載,分別在Linux內核和PREEMPT_RT內核上運行負載,統計此時的中斷延時時間,分析中斷線程化對系統關中斷時間的影響。
(2)對中斷自身影響:分別在Linux原生內核和PREEMPT_RT內核下創建定時器中斷,測試中斷延遲時間,分析中斷線程化對中斷自身的影響。
實驗基本原理可描述為:為了驗證中斷線程化對系統關中斷時間的影響,需要在系統中人為創建中斷,因此開發了一個負載程序。負載被設置為一個內核模塊,該內核模塊每隔100 us觸發一次中斷,一次中斷處理的時間大概在50 us左右,當此負載存在的情況下,新增定時器中斷,計算定時器中斷的延遲時間,通過這一指標就可以驗證系統的關中斷時間。
分別在非實時Linux內核和實時搶占內核中進行實驗,將各自運行20 000次,并將實驗結果使用二維點陣圖繪制出來,運行結果如圖2所示。
結果顯示,加中斷負載后,非實時內核的中斷最小延時48 us,最大延時63 us,平均延時54.9 us。實時搶占式內核的中斷最小延時6 us,最大延時35 us,平均延時10.9 us,在中斷延時時間上較非實時內核要占據明顯優勢,進而證實了中斷線程化減少了關中斷的時間,從而可以改善系統的中斷延時時間,增加內核的整體可搶占性。

(a) 非實時內核中斷延時時間

(b) 實時內核中斷延時時間
實驗基本原理可描述為:分別在Linux內核和PREEMPT_RT內核創建定時器中斷,計算中斷延時時間,驗證中斷線程化對中斷自身的影響。
實驗將在Linux內核和PREEMPT_RT內核的2種內核環境下分別運行20 000次,獲取各次的中斷延時時間,并將測試結果使用二維點陣圖繪制出來,結果對比如圖3所示。
結果顯示,經過20 000次測試,非實時Linux內核的中斷延時最小時間為2 us,最大值13 us,平均值5.5 us,標準方差0.5。實時搶占內核中斷延時最小時間6 us,最大值28 us,平均值12.6 us,標準方差1.3。實時搶占Linux內核的中斷延時時間大于普通非實時內核的測試結果。

(a) 非實時內核中斷延時時間

(b) 實時內核中斷延時時間
使用實時搶占內核的系統,在某些使用場景下,如果對中斷延時時間有著嚴格的要求(比如必須在20 us內響應),中斷線程化將無法做到,那么就可以在申請中斷時將其設置為實時中斷,此時就不再會被線程化,而是運行在中斷上下文中。實時搶占內核中的實時中斷的中斷延時時間測試結果如圖4所示。

圖4 實時搶占內核中實時中斷中斷延時
結果顯示,實時搶占內核中若將中斷設置為實時中斷,中斷延時時間可以控制在15 us以內,平均中斷延時5.5 us,與非實時Linux內核的測試結果相當。
本文探討了Linux搶占內核中中斷線程化的實現原理,從原理上分析了中斷線程化對系統整體性能的影響,并提出了一種中斷延時時間測試的方法,將該方法在TI AM3358處理器的平臺運行實現,實驗結果表明,Linux搶占內核中斷線程化可以減少系統關中斷時間,從而提高中斷處理效率。
Linux搶占內核對中斷的處理更加靈活,用戶可以根據自身需要將中斷設置為實時中斷或非實時中斷。其中,實時中斷未被線程化,在中斷上下文中處理,處理的優先級高,及時性強,但缺點是增加系統關中斷時間,而在此期間將無法處理其它的任何中斷或任務。非實時中斷指被線程化的中斷,在進程上下文處理,依賴調度器的調度,處理的優先級相對較低,及時性差,優點是減少系統關中斷時間,可與系統中的其它任務共同競爭資源,其公平性則更加突出。
在研究中,本文進一步設計了實驗仿真來證明上述理論,從而為使用PREEMPT_RT內核的開發人員設計內核驅動提供了重要的參考依據。