前言 Linux基金會(huì)在4月3日公布了Linux開發(fā)年報(bào),向我們展示了linux kernel作為世上最大開源合作項(xiàng)目之一的魅力。自2005年以來,共有800家公司7800名開發(fā)人員參與Linux kernel開發(fā),最近一年也有200家公司共1000名開發(fā)人員參與。目前在Linus Torvalds的監(jiān)督之下,Linux核心約2到3個(gè)月發(fā)布一個(gè)新的穩(wěn)定版本,每次更新大約包含8000到12000項(xiàng)修改,平均每小時(shí)有提交6.88次修改。內(nèi)核所有文件代碼已超過1500萬行,大約以每年10%的代碼量在增長(zhǎng)。 規(guī)模組織如此巨大,開發(fā)又活躍,且對(duì)質(zhì)量有非常高要求的項(xiàng)目,不禁好奇它是如何做好質(zhì)量保證的,于是查閱了網(wǎng)上較多資料,探索Linux kernel的質(zhì)量保證之道。 名詞解釋
Linux Kernel和GNU/Linux。Linux kernel作為系統(tǒng)的最底層,是負(fù)責(zé)管理硬件、執(zhí)行任務(wù)調(diào)度、維護(hù)整體安全和完整性的系統(tǒng)軟件。一個(gè)內(nèi)核不是一套完整的操作系統(tǒng),人們將 Linux 內(nèi)核和 GNU 系統(tǒng)組成完整的自由系統(tǒng):基于 Linux 的 GNU 系統(tǒng)(或簡(jiǎn)稱為 GNU/Linux 系統(tǒng))。咱們平時(shí)所說的Linux系統(tǒng)多是指GNU/Linux。 Patch。升級(jí)內(nèi)核時(shí),不必要每次都下載或提交整個(gè)的源碼文件,而是使用patch,或者叫做補(bǔ)丁或升級(jí)包。很多不同版本的內(nèi)核源代碼是以一組補(bǔ)丁(補(bǔ)丁集)甚至是若干獨(dú)立補(bǔ)丁的形式存在的。這些補(bǔ)丁應(yīng)該應(yīng)用在特定版本的內(nèi)核樹上。 內(nèi)核樹。樹的意思是“包含內(nèi)核源代碼的目錄的內(nèi)容”。另外一層意思是“內(nèi)核源碼的開發(fā)分支”。不同的分支命名也不一樣,比較流行的分支(樹)有-next樹(前身是Andrew Morton維護(hù)的-mm樹),-rt 樹(實(shí)時(shí)樹,包含把linux轉(zhuǎn)換為實(shí)時(shí)系統(tǒng)的補(bǔ)?。?。 -next 樹,由Stephen Rothwell維護(hù),是一些其他樹以及各種獨(dú)立的實(shí)驗(yàn)性補(bǔ)丁,它集合了主線和多種內(nèi)核子系統(tǒng)(子系統(tǒng)樹)維護(hù)人所使用的樹,子系統(tǒng)樹中含有被認(rèn)為是實(shí)驗(yàn)性的和還沒準(zhǔn)備好合并到主線中的各種補(bǔ)丁。換句話說,-next樹的每個(gè)版本都是帶有額外修改和一些bug的主線的未來快照。Bug盡可能在這些補(bǔ)丁合并到主線之前得到修正。 開發(fā)流程 要了解測(cè)試,先得看看整個(gè)項(xiàng)目的開發(fā)過程。 Linux kernel開發(fā)流程是基于一個(gè)松散的、定時(shí)發(fā)布的滾動(dòng)模型,每2-3個(gè)月發(fā)布一個(gè)新穩(wěn)定版本。2-3個(gè)月被認(rèn)為是一個(gè)合適的時(shí)間周期,能加快開發(fā)速度的同時(shí),也減少發(fā)行商需要處理的外部修改,更短則導(dǎo)致測(cè)試時(shí)間太少,新內(nèi)核測(cè)試不充分;更長(zhǎng)則導(dǎo)致發(fā)布版本之間會(huì)堆積太多工作。此模型從2005年正式確認(rèn),盡早將新功能融入內(nèi)核主線,將發(fā)布給用戶的延期降至最低。 在準(zhǔn)備提交Linux kernel代碼前,開發(fā)者將升級(jí)拆分為一個(gè)個(gè)小的互相獨(dú)立的單元,叫做補(bǔ)?。╬atch)。每個(gè)補(bǔ)丁通常只做一件事情,并且應(yīng)當(dāng)保證系統(tǒng)在打上此補(bǔ)丁之后是依然能正常編譯和工作的。這導(dǎo)致每個(gè)補(bǔ)丁都可以做代碼質(zhì)量和正確性評(píng)審,同時(shí)也導(dǎo)致每個(gè)版本提交的補(bǔ)丁數(shù)較大。 提交的補(bǔ)丁并不是直接進(jìn)入到內(nèi)核主線,參考圖一的代碼流動(dòng)過程,只有一個(gè)人能將補(bǔ)丁放入到內(nèi)核主線:Linus Torvalds。但是隨著越來越多的補(bǔ)丁加入到內(nèi)核,大約只有2%的補(bǔ)丁是Linux直接選入的。內(nèi)核代碼從邏輯上是拆分成一系列的子系統(tǒng)集合。每個(gè)子系統(tǒng)負(fù)責(zé)內(nèi)核的一部分(比如網(wǎng)絡(luò)、SCSI驅(qū)動(dòng)、特定架構(gòu)支持、內(nèi)存管理、視頻設(shè)備等),并且擁有指定的維護(hù)者,維護(hù)者對(duì)該子系統(tǒng)的代碼總體負(fù)責(zé)。當(dāng)前有過超過100個(gè)子系統(tǒng)。補(bǔ)丁先是進(jìn)入到一個(gè)子系統(tǒng)樹,子系統(tǒng)維護(hù)者接受修改時(shí),補(bǔ)丁就會(huì)附加“由誰(shuí)簽收通過” 的一行簽字。該信息表明此補(bǔ)丁可以合入到內(nèi)核。 
圖一 代碼流動(dòng)過程 Linux-next樹本意是在Linus合并代碼前將各子系統(tǒng)的代碼整合到一起,并進(jìn)行測(cè)試,挑選出可能存在的沖突和跨子系統(tǒng)問題。 實(shí)際例子 一個(gè)新版本2.6.20的發(fā)布過程如下圖二。在每一個(gè)版本開始時(shí),Linus會(huì)打開合并窗口(merge window),從那時(shí)起,被認(rèn)為是可靠穩(wěn)定的代碼會(huì)被合并到內(nèi)核主線,新的功能或驅(qū)動(dòng)等得以加入進(jìn)來,合并窗口會(huì)開啟兩周,然后Linus會(huì)宣布窗口關(guān)閉,并發(fā)布第一個(gè)rc版本,如下圖2.6.20-rc1。此-rc1版本的發(fā)布意味著新功能的加入已經(jīng)完成,以后再加入的補(bǔ)丁只能是修復(fù)問題,以確保此版本的穩(wěn)定,但也有即少數(shù)包含新功能的補(bǔ)丁會(huì)被認(rèn)為是不友好的。問題修復(fù)的代碼不斷進(jìn)入主線,Linus接下來大約每周發(fā)布一個(gè)新的rc版本,通常會(huì)在6-9個(gè)rc版本后認(rèn)為此版本已經(jīng)穩(wěn)定并且最終發(fā)布2.6.20版本,再進(jìn)入下一個(gè)三位版本的迭代。發(fā)布之后,此2.6.x版本就移交給穩(wěn)定組(stable team),穩(wěn)定組時(shí)而會(huì)再發(fā)布2.6.x.y版本,每個(gè)四位版本的發(fā)布會(huì)有兩個(gè)條件:(1)修復(fù)重大的bug;(2)該補(bǔ)丁也已被融入到下個(gè)三位版本開發(fā)的主線中了。穩(wěn)定組通常維護(hù)一個(gè)穩(wěn)定版本6個(gè)月左右,之后就由使用該版內(nèi)核的發(fā)行版發(fā)行商負(fù)責(zé)。
 圖二 一個(gè)版本的發(fā)布過程 測(cè)試 對(duì)Linux kernel測(cè)試面臨的挑戰(zhàn)巨大:如前面的數(shù)據(jù)所顯示,(1)其快速活躍的開發(fā);(2)經(jīng)常性的版本發(fā)布,每次發(fā)布都包含大量修改,以及內(nèi)核本身支持配置的靈活性、可擴(kuò)展性,待測(cè)點(diǎn)太多(3)需要覆蓋各種平臺(tái),Linux已支持二十多種平臺(tái)體系,是支持平臺(tái)最廣的系統(tǒng);(4)過時(shí)的case需要維護(hù)以及大量遺留代碼。 與松散的開發(fā)流程相對(duì)應(yīng),沒有看到正式的測(cè)試流程,開源軟件很大一部分的測(cè)試執(zhí)行是依靠用戶實(shí)際運(yùn)行使用。如下圖三所示。
 圖三 開源測(cè)試的大體流程 測(cè)試項(xiàng)目簡(jiǎn)介 Linux kernel與測(cè)試相關(guān)較出名的開源項(xiàng)目有: LTP:Linux Test Project http://ltp./。 Autotest:http://autotest.github.com/ CrackerJack Project:http://ossipedia.ipa./crackerjack/index.html。 LTP是一個(gè)聯(lián)合項(xiàng)目主要驗(yàn)證Linux系統(tǒng)的可靠性、健壯性和穩(wěn)定性,最先由SGI?啟動(dòng),并由IBM?負(fù)責(zé)維護(hù)。2012年4月發(fā)布的最新穩(wěn)定版本已擁有3000+的case(case增長(zhǎng)并不多,06年時(shí)就有2900+的case),用于測(cè)試Linux kernel以及相關(guān)功能。使用的編程語(yǔ)言主要是ANSI-C(占94%),以及Bash腳本(占5%),還有Perl(占0.62%)。它也有一套使用ANSI-C和Bash寫case的模板。 Autotest是后啟之秀,最早被用于Linux kernel自動(dòng)化測(cè)試的框架,使用python語(yǔ)言,現(xiàn)在也被多個(gè)其它項(xiàng)目所應(yīng)用。新case能較容易添加,ANSI-C或者Bash寫的case也能較方便地融入此框架。針對(duì)Linux kernel的測(cè)試項(xiàng)目地址是http://test.,用于交流、共享和分析測(cè)試數(shù)據(jù)。Autotest框架分服務(wù)端和客戶端,在監(jiān)聽到有新版本發(fā)布(三位版本、四位版本、-rc版本、-git版本)時(shí),會(huì)自動(dòng)觸發(fā)執(zhí)行自動(dòng)化,執(zhí)行過程見下圖四。
 圖四 Autotest自動(dòng)化執(zhí)行流程 CrackerJack 是一個(gè)主要負(fù)責(zé)linux kernel兼容性測(cè)試的項(xiàng)目,找出不同內(nèi)核版本系統(tǒng)調(diào)用的diff情況,已支持317個(gè)系統(tǒng)調(diào)用。它也是使用Autotest框架執(zhí)行,diff結(jié)果是個(gè)矩陣可見下圖五或者網(wǎng)址http://ossipedia.ipa./crackerjack/compare_results.html。Diff比較是智能的,并非單獨(dú)地比較輸出結(jié)果,比如time時(shí)間調(diào)用每次系統(tǒng)返回都是不一樣的,比較時(shí)就是檢查兩次調(diào)用之間的時(shí)間差。
 圖五 CrackerJack diff結(jié)果 測(cè)試方式 測(cè)試手段是多樣的:?jiǎn)螠y(cè)、集成測(cè)試、功能測(cè)試、性能測(cè)試、壓力測(cè)試、回歸測(cè)試等,但沒有一種手段在任意時(shí)候都合適。質(zhì)量保證是多方面的,除了要求開發(fā)者寫出高質(zhì)量代碼外,靜態(tài)代碼檢查、還要有頻繁且嚴(yán)格的code review,下面列舉一些針對(duì)Linux kernel特點(diǎn)的測(cè)試。 1. 開發(fā)者測(cè)試。鼓勵(lì)開發(fā)者寫單元測(cè)試,但很多時(shí)候有太多的依賴假設(shè),單測(cè)等是很難的,比如要測(cè)試U盤在讀寫過程中被拔掉,再插上的情況,只有實(shí)際運(yùn)行執(zhí)行才能驗(yàn)證程序是否正確。無論開發(fā)人員使用何種方式,都需要保證負(fù)責(zé)的代碼是經(jīng)過測(cè)試了的。不需要在所有版本上運(yùn)行,但需要確保代碼質(zhì)量,不能假定的字節(jié)序、字節(jié)長(zhǎng)度,都應(yīng)該使用標(biāo)準(zhǔn)接口。有些時(shí)候是修復(fù)別人報(bào)的bug,而開發(fā)人員又沒有復(fù)現(xiàn)該bug的環(huán)境,此時(shí)修改也需要由bug提交者確認(rèn)在其環(huán)境測(cè)試通過或者在其它能復(fù)現(xiàn)該bug的環(huán)境驗(yàn)證通過。對(duì)修改代碼的質(zhì)量保證方法還包括交由其它人評(píng)審?fù)ㄟ^或測(cè)試通過。編譯器的報(bào)警也是需要修復(fù)的。 2. 社區(qū)測(cè)試。社區(qū)開發(fā)模式,也強(qiáng)調(diào)社區(qū)測(cè)試,鼓勵(lì)大家在做好數(shù)據(jù)備份前提下使用最新發(fā)布的版本,類似軟件正式發(fā)布前的試用版本,以確保在不同的機(jī)器不同的平臺(tái)上能實(shí)際正常運(yùn)行。對(duì)此類版本的使用是有風(fēng)險(xiǎn)的,有可能導(dǎo)致系統(tǒng)崩潰。通常在系統(tǒng)安裝后,啟動(dòng)時(shí)也會(huì)比較小心,逐項(xiàng)加載啟動(dòng),以檢查每步都是正常的。還會(huì)做一些非常規(guī)的操作,也就是異常測(cè)試。 3. 配置測(cè)試。Linux kernel的配置也較復(fù)雜,以支持較好的靈活性和可擴(kuò)展性,測(cè)試需要盡量地覆蓋不同的配置組合條件。有的做法是隨機(jī)配置,再編譯運(yùn)行啟動(dòng),7*24小時(shí)重復(fù)不間斷地做,以找出可能存在的問題。做的過程中也有優(yōu)化,比如關(guān)閉一些不必要的選項(xiàng),減少編譯的時(shí)間。 有些配置項(xiàng)是有助于測(cè)試執(zhí)行時(shí)監(jiān)控問題和分析問題的,比如打印出debug日志,或者在出錯(cuò)時(shí)打印盡可能多的信息,kernel在某些設(shè)置下自身也會(huì)做一些運(yùn)行過程中的檢查,如CONFIG_DETECT_SOFTLOCKUP能檢查出內(nèi)核部分是否在內(nèi)核模式中循環(huán)超過60秒的bug,這類配置通常會(huì)在測(cè)試時(shí)打開。 4. 硬件測(cè)試。驗(yàn)證kernel對(duì)不同平臺(tái)的支持時(shí),會(huì)使用些不常用的硬件,以及不常用的硬件組合,不同的體系架構(gòu)。 5. 對(duì)待變化。由于Linux kernel經(jīng)常變化,不可能每次變動(dòng)都同等對(duì)待。針對(duì)-rc候選發(fā)布版本,需要嚴(yán)格地測(cè)試,因?yàn)樗鼈円坏┍徽J(rèn)為是穩(wěn)定的之后就會(huì)正式發(fā)布,并很可能由發(fā)行商選中到發(fā)行版中。而針對(duì)-next樹或者以前的-mm樹,因?yàn)樗鼈兲菀鬃兓?,沒有時(shí)間和資源運(yùn)行全量測(cè)試,通常只執(zhí)行最基本的測(cè)試。 6. 工具。Linux測(cè)試工具眾多,可見http://ltp./tooltable.php,覆蓋率、安全性、調(diào)試、網(wǎng)絡(luò)、性能等方方面面工具都應(yīng)有盡有。 7. 性能測(cè)試。Linux kernel對(duì)性能要求也比較高,性能測(cè)試通常要注意的幾點(diǎn):(1)最好是利用benchmark,以取得可信數(shù)據(jù);(2)避免I/O緩存因素,緩存對(duì)性能影響較大;(3)確保測(cè)量環(huán)境的穩(wěn)定性,特別是比較前后版本時(shí)。Autotest中也包含性能測(cè)試自動(dòng)化,一次升級(jí)導(dǎo)致的性能問題和修復(fù)如下圖六所示,2.6.14-rc2-mm1版本與2.6.14-rc1-mm1版本相比執(zhí)行時(shí)間由101增加到了111,性能降低了10%,直到2.6.16-rc1-mm4版本才修復(fù)。
 圖六 Autotest性能測(cè)試執(zhí)行結(jié)果圖 8. 可測(cè)性。Linux kernel在可測(cè)性方面也有較好支持。 (1)內(nèi)核模塊化。啟動(dòng)內(nèi)核模塊支持后,內(nèi)核的某些部分就可以在需要的時(shí)候才裝載到內(nèi)存中,使內(nèi)核變得更小,運(yùn)行更快。模塊化的內(nèi)核部分可以在系統(tǒng)運(yùn)行期間裝載或者卸載。 (2)內(nèi)核hacking 選項(xiàng),編譯一個(gè)測(cè)試用的內(nèi)核,有助有內(nèi)核特定功能的調(diào)試,也需要注意有部分選項(xiàng)會(huì)導(dǎo)致性能降低。 (3)Magic SysRq鍵,神奇的鍵盤快捷鍵,可以利用快捷鍵直接向內(nèi)核傳遞特定的指定。 (4)多種信息收集方式,內(nèi)核的bug不一定是導(dǎo)致系統(tǒng)崩潰,一些嚴(yán)重的錯(cuò)誤通過日志等表現(xiàn)出來,信息收集就變得猶為重要了??梢酝ㄟ^Syslog, console, dmesg等方式dump和顯示日志,除此之外,還可以通過串口和網(wǎng)絡(luò)控制臺(tái)遠(yuǎn)程收集信息。 (5)kexec快速重啟系統(tǒng),使用 kexec可以直接重新啟動(dòng)到另一個(gè)內(nèi)核,不再必須通過固件和引導(dǎo)裝載程序階段,能為測(cè)試節(jié)省大量時(shí)間。 (6)使用biselect追查問題,當(dāng)發(fā)現(xiàn)一個(gè)bug卻不知道是由哪個(gè)補(bǔ)丁引入時(shí),使用二分查找,代碼管理系統(tǒng)git以及補(bǔ)丁管理工具quilt都支持二分查找。 9. 覆蓋率。關(guān)于Linux kernel的測(cè)試覆蓋率,沒有看到最新的統(tǒng)計(jì),不過以前數(shù)據(jù)多是在20%左右的分支覆蓋率。 雖然說自動(dòng)化測(cè)試越來越重要,但是將內(nèi)核部分測(cè)試自動(dòng)化卻是非常困難的,自動(dòng)化只涵蓋了一少部分功能,性能的自動(dòng)化看起來做得更多些。質(zhì)量更多還是由開發(fā)人員以及社區(qū)測(cè)試來保證。另外一方面看,Linux kernel本身的架構(gòu)應(yīng)該也有較高的容錯(cuò)性和可擴(kuò)展性,以支持如此大量又頻繁的修改。 說明 寫本文時(shí),我還并沒有實(shí)際參與過Linux kernel的開發(fā)或測(cè)試,只是對(duì)其有興趣,于是在網(wǎng)上查閱了大量文檔,有些信息可能已經(jīng)過時(shí)或者與實(shí)際情況不符,僅供參考。 引用說明 網(wǎng)上鏈接 Crackerjack Project http://ossipedia.ipa./crackerjack/index.html Linux命名爭(zhēng)議 http://en./wiki/GNU/Linux_naming_controversy Linux Test Project,測(cè)試Linux kernel以及相關(guān)功能 http://ltp./ Linux測(cè)試工具 http://ltp./tooltable.php Linux 維基百科 http://en./wiki/Linux Linux Kernel維基百科 http://en./wiki/Linux_kernel 開發(fā)流程 http:///en/developers/process Autotest項(xiàng)目http://autotest.github.com/ Greg Kroah Hartman on the Linux Kernel視頻http://www./watch?v=L2SED6sewRw http:///questions/3177338/how-is-linux-kernel-tested kernel官網(wǎng) http://www./ Linux kernel郵件列表FQA http://ftp./pub/linux/docs/lkml/ Pdf電子書 《Best Practices in Linux Kernel Testing》 《Linux Kernel Tester’s Guide》version 0.3,中文版《Linux 內(nèi)核測(cè)試指南》 《How to Participate in the Linux Community》2008.8 《Linux Kernel Development:How Fast it is Going, Who is Doing It, What They are Doing, and Who is Sponsoring It》2012.3
|