歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> linux kernel測試初探

linux kernel測試初探

日期:2017/2/27 16:03:04   编辑:Linux教程
前言
Linux基金會在4月3日公布了Linux開發年報,向我們展示了linux kernel作為世上最大開源合作項目之一的魅力。自2005年以來,共有800家公司7800名開發人員參與Linux kernel開發,最近一年也有200家公司共1000名開發人員參與。目前在Linus Torvalds的監督之下,Linux核心約2到3個月發布一個新的穩定版本,每次更新大約包含8000到12000項修改,平均每小時有提交6.88次修改。內核所有文件代碼已超過1500萬行,大約以每年10%的代碼量在增長。
規模組織如此巨大,開發又活躍,且對質量有非常高要求的項目,不禁好奇它是如何做好質量保證的,於是查閱了網上較多資料,探索Linux kernel的質量保證之道。

名詞解釋
Linux Kernel和GNU/Linux。Linux kernel作為系統的最底層,是負責管理硬件、執行任務調度、維護整體安全和完整性的系統軟件。一個內核不是一套完整的操作系統,人們將 Linux 內核和 GNU 系統組成完整的自由系統:基於 Linux 的 GNU 系統(或簡稱為 GNU/Linux 系統)。咱們平時所說的Linux系統多是指GNU/Linux。
Patch。升級內核時,不必要每次都下載或提交整個的源碼文件,而是使用patch,或者叫做補丁或升級包。很多不同版本的內核源代碼是以一組補丁(補丁集)甚至是若干獨立補丁的形式存在的。這些補丁應該應用在特定版本的內核樹上。
內核樹。樹的意思是“包含內核源代碼的目錄的內容”。另外一層意思是“內核源碼的開發分支”。不同的分支命名也不一樣,比較流行的分支(樹)有-next樹(前身是Andrew Morton維護的-mm樹),-rt 樹(實時樹,包含把linux轉換為實時系統的補丁)。
-next 樹,由Stephen Rothwell維護,是一些其他樹以及各種獨立的實驗性補丁,它集合了主線和多種內核子系統(子系統樹)維護人所使用的樹,子系統樹中含有被認為是實驗性的和還沒准備好合並到主線中的各種補丁。換句話說,-next樹的每個版本都是帶有額外修改和一些bug的主線的未來快照。Bug盡可能在這些補丁合並到主線之前得到修正。

開發流程
要了解測試,先得看看整個項目的開發過程。
Linux kernel開發流程是基於一個松散的、定時發布的滾動模型,每2-3個月發布一個新穩定版本。2-3個月被認為是一個合適的時間周期,能加快開發速度的同時,也減少發行商需要處理的外部修改,更短則導致測試時間太少,新內核測試不充分;更長則導致發布版本之間會堆積太多工作。此模型從2005年正式確認,盡早將新功能融入內核主線,將發布給用戶的延期降至最低。
在准備提交Linux kernel代碼前,開發者將升級拆分為一個個小的互相獨立的單元,叫做補丁(patch)。每個補丁通常只做一件事情,並且應當保證系統在打上此補丁之後是依然能正常編譯和工作的。這導致每個補丁都可以做代碼質量和正確性評審,同時也導致每個版本提交的補丁數較大。
提交的補丁並不是直接進入到內核主線,參考圖一的代碼流動過程,只有一個人能將補丁放入到內核主線:Linus Torvalds。但是隨著越來越多的補丁加入到內核,大約只有2%的補丁是Linux直接選入的。內核代碼從邏輯上是拆分成一系列的子系統集合。每個子系統負責內核的一部分(比如網絡、SCSI驅動、特定架構支持、內存管理、視頻設備等),並且擁有指定的維護者,維護者對該子系統的代碼總體負責。當前有過超過100個子系統。補丁先是進入到一個子系統樹,子系統維護者接受修改時,補丁就會附加“由誰簽收通過” 的一行簽字。該信息表明此補丁可以合入到內核。

圖一 代碼流動過程
Linux-next樹本意是在Linus合並代碼前將各子系統的代碼整合到一起,並進行測試,挑選出可能存在的沖突和跨子系統問題。

實際例子
一個新版本2.6.20的發布過程如下圖二。在每一個版本開始時,Linus會打開合並窗口(merge window),從那時起,被認為是可靠穩定的代碼會被合並到內核主線,新的功能或驅動等得以加入進來,合並窗口會開啟兩周,然後Linus會宣布窗口關閉,並發布第一個rc版本,如下圖2.6.20-rc1。此-rc1版本的發布意味著新功能的加入已經完成,以後再加入的補丁只能是修復問題,以確保此版本的穩定,但也有即少數包含新功能的補丁會被認為是不友好的。問題修復的代碼不斷進入主線,Linus接下來大約每周發布一個新的rc版本,通常會在6-9個rc版本後認為此版本已經穩定並且最終發布2.6.20版本,再進入下一個三位版本的迭代。發布之後,此2.6.x版本就移交給穩定組(stable team),穩定組時而會再發布2.6.x.y版本,每個四位版本的發布會有兩個條件:(1)修復重大的bug;(2)該補丁也已被融入到下個三位版本開發的主線中了。穩定組通常維護一個穩定版本6個月左右,之後就由使用該版內核的發行版發行商負責。

圖二 一個版本的發布過程

測試
對Linux kernel測試面臨的挑戰巨大:如前面的數據所顯示,(1)其快速活躍的開發;(2)經常性的版本發布,每次發布都包含大量修改,以及內核本身支持配置的靈活性、可擴展性,待測點太多(3)需要覆蓋各種平台,Linux已支持二十多種平台體系,是支持平台最廣的系統;(4)過時的case需要維護以及大量遺留代碼。
與松散的開發流程相對應,沒有看到正式的測試流程,開源軟件很大一部分的測試執行是依靠用戶實際運行使用。如下圖三所示。

圖三 開源測試的大體流程

測試項目簡介
Linux kernel與測試相關較出名的開源項目有:
LTP:Linux Test Project http://ltp.sourceforge.net/。
Autotest:http://autotest.github.com/
CrackerJack Project:http://ossipedia.ipa.go.jp/crackerjack/index.html。
LTP是一個聯合項目主要驗證Linux系統的可靠性、健壯性和穩定性,最先由SGI™啟動,並由IBM®負責維護。2012年4月發布的最新穩定版本已擁有3000+的case(case增長並不多,06年時就有2900+的case),用於測試Linux kernel以及相關功能。使用的編程語言主要是ANSI-C(占94%),以及Bash腳本(占5%),還有Perl(占0.62%)。它也有一套使用ANSI-C和Bash寫case的模板。
Autotest是後啟之秀,最早被用於Linux kernel自動化測試的框架,使用python語言,現在也被多個其它項目所應用。新case能較容易添加,ANSI-C或者Bash寫的case也能較方便地融入此框架。針對Linux kernel的測試項目地址是http://test.kernel.org,用於交流、共享和分析測試數據。Autotest框架分服務端和客戶端,在監聽到有新版本發布(三位版本、四位版本、-rc版本、-git版本)時,會自動觸發執行自動化,執行過程見下圖四。

圖四 Autotest自動化執行流程
CrackerJack 是一個主要負責linux kernel兼容性測試的項目,找出不同內核版本系統調用的diff情況,已支持317個系統調用。它也是使用Autotest框架執行,diff結果是個矩陣可見下圖五或者網址http://ossipedia.ipa.go.jp/crackerjack/compare_results.html。Diff比較是智能的,並非單獨地比較輸出結果,比如time時間調用每次系統返回都是不一樣的,比較時就是檢查兩次調用之間的時間差。

圖五 CrackerJack diff結果

測試方式
測試手段是多樣的:單測、集成測試、功能測試、性能測試、壓力測試、回歸測試等,但沒有一種手段在任意時候都合適。質量保證是多方面的,除了要求開發者寫 出高質量代碼外,靜態代碼檢查、還要有頻繁且嚴格的code review,下面列舉一些針對Linux kernel特點的測試。
1. 開發者測試。鼓勵開發者寫單元測試,但很多時候有太多的依賴假設,單測等是很難的,比如要測試U盤在讀寫過程中被拔掉,再插上的情況,只有實際運行執行才 能驗證程序是否正確。無論開發人員使用何種方式,都需要保證負責的代碼是經過測試了的。不需要在所有版本上運行,但需要確保代碼質量,不能假定的字節序、 字節長度,都應該使用標准接口。有些時候是修復別人報的bug,而開發人員又沒有復現該bug的環境,此時修改也需要由bug提交者確認在其環境測試通過 或者在其它能復現該bug的環境驗證通過。對修改代碼的質量保證方法還包括交由其它人評審通過或測試通過。編譯器的報警也是需要修復的。

2. 社區測試。社區開發模式,也強調社區測試,鼓勵大家在做好數據備份前提下使用最新發布的版本,類似軟件正式發布前的試用版本,以確保在不同的機器不同的平 台上能實際正常運行。對此類版本的使用是有風險的,有可能導致系統崩潰。通常在系統安裝後,啟動時也會比較小心,逐項加載啟動,以檢查每步都是正常的。還 會做一些非常規的操作,也就是異常測試。

3. 配置測試。Linux kernel的配置也較復雜,以支持較好的靈活性和可擴展性,測試需要盡量地覆蓋不同的配置組合條件。有的做法是隨機配置,再編譯運行啟動,7*24小時 重復不間斷地做,以找出可能存在的問題。做的過程中也有優化,比如關閉一些不必要的選項,減少編譯的時間。
有些配置項是有助於測試執行時監控問題和分析問題的,比如打印出debug日志,或者在出錯時打印盡可能多的信息,kernel在某些設置下自身也會做一 些運行過程中的檢查,如CONFIG_DETECT_SOFTLOCKUP能檢查出內核部分是否在內核模式中循環超過60秒的bug,這類配置通常會在測 試時打開。

4. 硬件測試。驗證kernel對不同平台的支持時,會使用些不常用的硬件,以及不常用的硬件組合,不同的體系架構。

5. 對待變化。由於Linux kernel經常變化,不可能每次變動都同等對待。針對-rc候選發布版本,需要嚴格地測試,因為它們一旦被認為是穩定的之後就會正式發布,並很可能由發 行商選中到發行版中。而針對-next樹或者以前的-mm樹,因為它們太容易變化了,沒有時間和資源運行全量測試,通常只執行最基本的測試。

6. 工具。Linux測試工具眾多,可見http://ltp.sourceforge.net/tooltable.php,覆蓋率、安全性、調試、網絡、性能等方方面面工具都應有盡有。

7. 性能測試。Linux kernel對性能要求也比較高,性能測試通常要注意的幾點:
(1)最好是利用benchmark,以取得可信數據;
(2)避免I/O緩存因素,緩存對性 能影響較大;
(3)確保測量環境的穩定性,特別是比較前後版本時。Autotest中也包含性能測試自動化,一次升級導致的性能問題和修復如下圖六所 示,2.6.14-rc2-mm1版本與2.6.14-rc1-mm1版本相比執行時間由101增加到了111,性能降低了10%,直到2.6.16- rc1-mm4版本才修復。

圖六 Autotest性能測試執行結果圖

8. 可測性。Linux kernel在可測性方面也有較好支持。
(1)內核模塊化。啟動內核模塊支持後,內核的某些部分就可以在需要的時候才裝載到內存中,使內核變得更小,運行更快。模塊化的內核部分可以在系統運行期間裝載或者卸載。
(2)內核hacking 選項,編譯一個測試用的內核,有助有內核特定功能的調試,也需要注意有部分選項會導致性能降低。
(3)Magic SysRq鍵,神奇的鍵盤快捷鍵,可以利用快捷鍵直接向內核傳遞特定的指定。
(4)多種信息收集方式,內核的bug不一定是導致系統崩潰,一些嚴重的錯誤通過日志等表現出來,信息收集就變得猶為重要了。可以通過Syslog, console, dmesg等方式dump和顯示日志,除此之外,還可以通過串口和網絡控制台遠程收集信息。
(5)kexec快速重啟系統,使用 kexec可以直接重新啟動到另一個內核,不再必須通過固件和引導裝載程序階段,能為測試節省大量時間。
(6)使用biselect追查問題,當發現一個bug卻不知道是由哪個補丁引入時,使用二分查找,代碼管理系統git以及補丁管理工具quilt都支持二分查找。

9. 覆蓋率。關於Linux kernel的測試覆蓋率,沒有看到最新的統計,不過以前數據多是在20%左右的分支覆蓋率。

雖然說自動化測試越來越重要,但是將內核部分測試自動化卻是非常困難的,自動化只涵蓋了一少部分功能,性能的自動化看起來做得更多些。質量更多還是由開發人員以及社區測試來保證。另外一方面看,Linux kernel本身的架構應該也有較高的容錯性和可擴展性,以支持如此大量又頻繁的修改。
Copyright © Linux教程網 All Rights Reserved