林玉哲, 蔣金虎, 張為華
1(復(fù)旦大學(xué) 軟件學(xué)院, 上海 200438)
2(復(fù)旦大學(xué) 上海市數(shù)據(jù)科學(xué)重點實驗室, 上海 200438)
操作系統(tǒng)在現(xiàn)代生活中的應(yīng)用越來越廣泛, 其發(fā)展主要面對著來自兩方面的壓力: 一是多樣化的硬件,二是復(fù)雜多樣的上層應(yīng)用. 操作系統(tǒng), 對上, 需要能為不同的應(yīng)用提供相對應(yīng)的系統(tǒng)服務(wù), 對下, 需要能夠支持各種硬件, 發(fā)揮出它們的性能, 這些都給操作系統(tǒng)的擴展性, 靈活性, 性能提出了不同程度的挑戰(zhàn). 從擴展性的角度來說, 操作系統(tǒng)需要能夠支持不同種類的物理核心, 從靈活性的角度來說, 操作系統(tǒng)需要能夠針對不同的應(yīng)用提供合適的系統(tǒng)服務(wù), 從性能角度說, 操作系統(tǒng)的性能直接影響到用戶的使用, 因此操作系統(tǒng)必須在保證一定程度性能的前提下完成各種功能.
針對這些問題, 多內(nèi)核(multikernel)操作系統(tǒng)是一種可行的設(shè)計理念. 多內(nèi)核操作系統(tǒng)是一種在底層硬件上運行多個內(nèi)核, 每個內(nèi)核(kernel)各自維護一組內(nèi)核數(shù)據(jù)的操作系統(tǒng)設(shè)計方案. 在諸如Linux 等單內(nèi)核操作系統(tǒng)中, 盡管每個核心(core)都運行自己的執(zhí)行流, 但是它們操作的是同一組內(nèi)核數(shù)據(jù), 因此稱之為單內(nèi)核. 相較而言, 多內(nèi)核操作系統(tǒng)則是分布式地運行了多個內(nèi)核, 機器中的一部分核心運行其中一個內(nèi)核, 維護該內(nèi)核的內(nèi)核數(shù)據(jù). 內(nèi)核之間不直接共享內(nèi)核數(shù)據(jù),而是通過其他的方式進行必要的同步.
多內(nèi)核操作系統(tǒng)相比一般的單內(nèi)核操作系統(tǒng)有著諸多的優(yōu)勢. 首先, 多內(nèi)核操作系統(tǒng)可以為不同的核心選擇不同的內(nèi)核, 所以可以更容易地針對不同體系結(jié)構(gòu)的核心進行擴展. 其次, 在特定的場景下, 分布式的設(shè)計也可以作為虛擬機的代替方案, 將整組機器中某一個核心, 分配給一個新的內(nèi)核, 作為一個單獨的操作系統(tǒng)或客戶機進行使用. 最后, 多內(nèi)核操作系統(tǒng)中內(nèi)核之間盡量少地保留共享數(shù)據(jù), 因此避免了在多核心之間進行頻繁的數(shù)據(jù)同步, 避免了復(fù)雜的鎖的設(shè)計, 在特定的情況下可以獲得更高的性能.
與此同時, 多內(nèi)核操作系統(tǒng)的設(shè)計也存在諸多的策略與考慮. 其中包括, 設(shè)計多內(nèi)核操作系統(tǒng)的整體架構(gòu), 界定和規(guī)范一個內(nèi)核中的數(shù)據(jù), 配置每個內(nèi)核所負責的物理資源, 設(shè)計內(nèi)核與內(nèi)核之間必要的通信與同步規(guī)則, 以及對新的硬件設(shè)備進行熱啟動和支持.
本文接下來首先對多內(nèi)核操作系統(tǒng)進行介紹, 說明其出現(xiàn)的背景與應(yīng)用場景. 然后介紹多內(nèi)核操作系統(tǒng)設(shè)計上的考慮和難點. 接著, 本文將對現(xiàn)有的多內(nèi)核操作系統(tǒng)進行分析. 而后對多內(nèi)核操作系統(tǒng)與相關(guān)技術(shù)進行比對分析其優(yōu)劣所在. 最后對多內(nèi)核操作系統(tǒng)的研究和未來做總結(jié).
現(xiàn)代計算機硬件技術(shù)發(fā)展飛速, 多核以及異構(gòu)架構(gòu)的硬件日新月異. 相對地, 其上運行的軟件卻很難完美地跟上硬件更新的速度. 因此軟件設(shè)計中適配性和可擴展性是十分重要的. 操作系統(tǒng)作為軟件極為重要的一環(huán)也是如此. 操作系統(tǒng)的更新與擴展主要面臨來自于兩方面的壓力: 越來越復(fù)雜的硬件與越來越復(fù)雜的應(yīng)用場景.
從硬件的角度來說, 多核/眾核體系結(jié)構(gòu)逐漸流行起來, 隨著核心數(shù)目的增加, 操作系統(tǒng)中核心間數(shù)據(jù)同步的問題也越來越嚴重. 由于不同核心共同維護同一組內(nèi)核數(shù)據(jù), 操作系統(tǒng)的設(shè)計者往往需要利用鎖等方法對數(shù)據(jù)進行同步與保護, 這往往會帶來很高的性能開銷. 除了多核/眾核架構(gòu)下數(shù)據(jù)同步的問題, 硬件的多樣性也會增加操作系統(tǒng)設(shè)計上的難度. 在不同的硬件上, 不同配置或設(shè)計策略的內(nèi)核會產(chǎn)生不同的性能. 例如, 在一些ARM 架構(gòu)[1]的硬件上, 同時存在多種不同性能的核心. 針對這些核心的不同, 在調(diào)度算法上面,設(shè)計者會傾向于讓計算能力更強的核心來負載需求高性能的任務(wù), 而讓計算能力稍弱的核心負責一些輕量型的任務(wù). 對于一般的操作系統(tǒng)來說, 為了達到這樣的目的, 需要在自身的代碼里對各種硬件進行判斷, 這樣會增加內(nèi)核的復(fù)雜度, 使內(nèi)核的擴展越來越復(fù)雜.
從應(yīng)用場景的角度來說, 不同的應(yīng)用場景需要操作系統(tǒng)提供不同程度的系統(tǒng)服務(wù). 如, 一些實時性任務(wù)會要求對任務(wù)時間進行精確的控制, 這要求操作系統(tǒng)不但能夠支持普通的應(yīng)用, 同時還需要為這些實時性任務(wù)提供更加高效且實時性的服務(wù). 再比如, 數(shù)據(jù)中心廠商需要將眾多硬件以不同的方式分配給不同的用戶,這就需要服務(wù)器的操作系統(tǒng)或管理系統(tǒng)能夠利用諸如虛擬化等技術(shù)為不同的用戶提供不同操作系統(tǒng)的客戶虛擬機.
多內(nèi)核操作系統(tǒng)的研究從某種角度上來說就是為了更好地解決以上這些問題. 多內(nèi)核操作系統(tǒng)一般應(yīng)用于多核/眾核的硬件系統(tǒng). 一般的單內(nèi)核操作系統(tǒng), 所有核心上的執(zhí)行流維護的都是同一組內(nèi)核的數(shù)據(jù). 為了正確地維護這些數(shù)據(jù), 以及并行執(zhí)行某些系統(tǒng)服務(wù),會利用鎖等機制來對數(shù)據(jù)進行同步, 這種同步會帶來額外的性能開銷. 另外, 面對不同物理硬件, 單內(nèi)核操作系統(tǒng)雖然可以針對不同的核心進行專門的優(yōu)化, 但隨著硬件種類的增多, 系統(tǒng)會變得越來越臃腫. 相較而言, 多內(nèi)核操作系統(tǒng)允許在一組機器中運行多個內(nèi)核,選擇其中的某一個或某幾個核心作為一組來運行一個特定的內(nèi)核, 維護一組特定的內(nèi)核數(shù)據(jù), 而其他的核心以類似的方式負責另外的幾個內(nèi)核, 維護另外幾組內(nèi)核的內(nèi)核數(shù)據(jù). 在這樣一種分布式的設(shè)計中, 由于每個內(nèi)核是各自獨立的, 因此可以大大減少不同內(nèi)核間數(shù)據(jù)的同步, 并且可以為不同硬件上的內(nèi)核專門準備獨有的策略, 在進行擴展的時候也不會影響到其他內(nèi)核的內(nèi)部邏輯. 因此多內(nèi)核操作系統(tǒng)擁有相比單內(nèi)核操作系統(tǒng)更好的擴展性.
除擴展性以外, 多內(nèi)核操作系統(tǒng)在應(yīng)用上也具有很高的靈活性. 多內(nèi)核操作系統(tǒng)可以作為實時操作系統(tǒng)的一種解決方案, 諸如RT Linux[2-5], Xenomai[6,7]等操作系統(tǒng)選擇一種近似于多內(nèi)核操作系統(tǒng)的雙內(nèi)核模式, 一個Linux 內(nèi)核用于一般的任務(wù), 一個實時性內(nèi)核用于實時性任務(wù). 除了用于實時性操作系統(tǒng), 多內(nèi)核操作系統(tǒng)也可以作為虛擬化技術(shù)的一種替代方案. 虛擬化技術(shù)[8-13]是一類利用硬件或軟件模擬計算機 硬件系統(tǒng)的技術(shù), 用戶可以將其模擬的硬件系統(tǒng)作為一個獨立的機器進行使用. 相對的, 多內(nèi)核操作系統(tǒng)中的一個內(nèi)核由于具有較高的獨立性, 因此也可以被客戶視為一個單獨的機器. 相比于虛擬化技術(shù), 多內(nèi)核操作系統(tǒng)中用戶的內(nèi)核直接運行在真實存在的硬件上, 而不是模擬出的硬件環(huán)境上, 并且多內(nèi)核操作系統(tǒng)也避免了虛擬化技術(shù)中必要的中間層的設(shè)計, 減少了整體性能的損耗. 多內(nèi)核操作系統(tǒng)在啟動, 遷移和更新上也擁有很大的靈活性. 經(jīng)過設(shè)計的多內(nèi)核操作系統(tǒng)允許內(nèi)核進行動態(tài)啟動, 遷移和更新. 系統(tǒng)可以選擇在不影響其他核心的前提下將一個核心上的內(nèi)核遷移到新的核心上, 可以選擇將空余核心分配給一個新的內(nèi)核, 也可以對其上運行的內(nèi)核進行更新. 在某個內(nèi)核出現(xiàn)錯誤的時候, 可以避免影響到其他的內(nèi)核而只對出現(xiàn)錯誤的內(nèi)核進行重啟或替換的操作.
除了靈活性和擴展性, 多內(nèi)核操作系統(tǒng)根據(jù)設(shè)計的不同也可以增加整個系統(tǒng)運行的性能. 在單內(nèi)核系統(tǒng)中, 因為要并行處理同一組內(nèi)核數(shù)據(jù), 往往會涉及到數(shù)據(jù)的同步問題. 一般來說, 由于存儲層次的不同, 核心之間, 共享緩存層次越高, 數(shù)據(jù)同步代價就越小, 而共享緩存層次較低甚至只能直接通過內(nèi)存進行同步數(shù)據(jù)的兩個核心, 數(shù)據(jù)同步開銷的代價就很大. 多內(nèi)核操作系統(tǒng)可以選擇讓擁有更高層次共享緩存的核心負責處理一個內(nèi)核, 擁有較低甚至沒有共享緩存的核心負責不同的內(nèi)核, 通過這樣的方式, 就可以盡量減少受緩存一致性影響較大的核心之間的交互, 從而規(guī)避開銷過大的數(shù)據(jù)同步.
多內(nèi)核操作系統(tǒng)的設(shè)計涉及到諸多方面, 接下來本文會從幾個方面討論多內(nèi)核操作系統(tǒng)設(shè)計上的考慮和策略. 多內(nèi)核操作系統(tǒng)的設(shè)計包括幾個方面, 首先,設(shè)計與規(guī)劃每一個內(nèi)核的數(shù)據(jù), 其次, 確定物理硬件的資源分配與管理的方式, 接著, 考慮不同內(nèi)核上的核心之間, 同一個內(nèi)核上的核心之間, 以及運行在這些核心之上的用戶線程應(yīng)當以什么樣的方式進行通信, 最后應(yīng)當討論內(nèi)核的熱啟動, 遷移, 和更新.
單內(nèi)核操作系統(tǒng)和多內(nèi)核操作系統(tǒng), 一個很重要的區(qū)別在于運行在核心上的各個執(zhí)行流, 處理和維護的是否是同一組內(nèi)核數(shù)據(jù). 內(nèi)核的數(shù)據(jù)一般包括核心的數(shù)據(jù)流自身運行需要的數(shù)據(jù), 如每個核心擁有的棧,用于維護整個內(nèi)核運行或為用戶提供服務(wù)的數(shù)據(jù), 如頁表, 文件表等. 單內(nèi)核操作系統(tǒng)的內(nèi)核數(shù)據(jù)只有一組,而多內(nèi)核操作系統(tǒng)則是其中的每一個內(nèi)核都單獨維護一組數(shù)據(jù). 盡管如此, 多內(nèi)核操作系統(tǒng)中一個內(nèi)核維護的內(nèi)核數(shù)據(jù)與單內(nèi)核操作系統(tǒng)維護的數(shù)據(jù)沒有什么本質(zhì)上的不同. 圖1 和圖2 分別展示了單內(nèi)核操作系統(tǒng)和多內(nèi)核系統(tǒng)在物理硬件, 內(nèi)核數(shù)據(jù)以及其上運行的應(yīng)用的結(jié)構(gòu). 在單內(nèi)核操作系統(tǒng)中, 所有物理核心維護同一組內(nèi)核數(shù)據(jù), 這些核心的執(zhí)行流為同一個內(nèi)核服務(wù), 這個內(nèi)核則利用這唯一的一組內(nèi)核數(shù)據(jù)為其上運行的不同線程服務(wù). 在多內(nèi)核系統(tǒng)中, 核心被分成多個組, 每個組的核心維護一組內(nèi)核數(shù)據(jù), 形成一個內(nèi)核,這個內(nèi)核為其上運行的線程提供服務(wù). 不同組之間, 內(nèi)核之間或其上運行的線程之間, 使用額外的設(shè)計來保證互相之間能夠進行一定程度的通信.
圖1 單內(nèi)核操作系統(tǒng)架構(gòu)
圖2 多內(nèi)核操作系統(tǒng)架構(gòu)
一般來說, 不論是單內(nèi)核操作系統(tǒng)亦或是多內(nèi)核操作系統(tǒng), 在其中的一個內(nèi)核中, 各個核心上執(zhí)行流使用同一個內(nèi)核頁表, 擁有同一個地址空間, 因此也維護同一組內(nèi)核數(shù)據(jù). 在面對自然而然會出現(xiàn)的數(shù)據(jù)同步問題時, 內(nèi)核會使用鎖來進行保護, 對這方面的優(yōu)化有很多, 包括但不局限于對于各種鎖的使用以及將數(shù)據(jù)進行一定程度的分布式處理[14]. 但是總體上來說, 各個核心維護的依然是同一組數(shù)據(jù). 這樣做的結(jié)果, 就是在一個內(nèi)核上運行的用戶態(tài)的程序, 他們所能夠看到的內(nèi)核狀態(tài)應(yīng)當是一致的.
盡管多內(nèi)核操作系統(tǒng)上不同內(nèi)核在使用時可以被用戶視為完全獨立, 互不影響. 但是多內(nèi)核操作系統(tǒng)依然要保障不同內(nèi)核之間通信的功能. 首先, 幾個內(nèi)核很可能要共同使用同一組硬件, 諸如內(nèi)存, 中斷等, 那么它們之間就必須有某種程度上的同步, 使得他們能夠共同使用這些硬件或是對這些硬件的使用權(quán)利進行協(xié)商. 一般的處理方案是, 維護一組專門的數(shù)據(jù), 然后設(shè)計專門的通信方案來進行同步和更新. 例如, 可以選擇每個內(nèi)核保存一個副本, 然后通過設(shè)計一個共享的消息管道來進行同步, 或是選擇將數(shù)據(jù)保存在一個共享的空間, 然后通過鎖來訪問和更新. 盡管這樣的一段數(shù)據(jù)的維護是必要的, 但是多內(nèi)核操作系統(tǒng)中, 這一部分被設(shè)計得盡可能的少, 以保證內(nèi)核之間的獨立性.
多內(nèi)核操作系統(tǒng)的內(nèi)核雖然是獨立的, 但它們依然共同使用同一臺機器上的硬件. 盡管理論上使用者可以按照自身意愿對內(nèi)核進行配置和資源分配, 但是為了整個系統(tǒng)的性能與穩(wěn)定, 依然需要一套專門的指導(dǎo)性方案.
首先需要考慮的是內(nèi)核及其中數(shù)據(jù)的配置方式.在一個內(nèi)核的內(nèi)部, 數(shù)據(jù)往往是通過鎖來進行維護并在不同的核心之間同步的. 同步所需要的時間往往會影響到系統(tǒng)的性能, 常見的鎖的方案包括大鎖和細粒度鎖, 前者使用一個全局的鎖來維護所有共享的數(shù)據(jù),后者則會使用更細粒度的鎖來進行維護. 從時間效率上說, 細粒度鎖能達到更好的并行性, 但是設(shè)計相對復(fù)雜. 大鎖設(shè)計上簡單, 但是其相當于讓不同的核心串行執(zhí)行, 并行性較差. 多內(nèi)核, 作為第3 種方案, 選擇每一個內(nèi)核維護一組內(nèi)核數(shù)據(jù), 不同內(nèi)核數(shù)據(jù)之間只在少數(shù)時間的時候通過諸如消息隊列等方式進行同步, 既擁有良好的并行性, 設(shè)計上也不會過于復(fù)雜, 因此是一種相對合理的方案. 所以, 一個多內(nèi)核操作系統(tǒng)應(yīng)該是這樣的: 其上的核心被劃分到幾個內(nèi)核之中, 內(nèi)核內(nèi)部的核心通過大鎖或細粒度維護數(shù)據(jù), 內(nèi)核之間的數(shù)據(jù)則只在需要的時候通過消息進行同步.
Peters 等人的研究[15]指出, 對于一些特定的內(nèi)核運行時間較少的內(nèi)核, 如微內(nèi)核[16,17]等, 大鎖相比于細粒度鎖會擁有更好的性能. 其原因在于鎖本身帶來的代價甚至超出了并行帶來的收益. 對于多內(nèi)核操作系統(tǒng)來說, 其中一個內(nèi)核對于大鎖或者細粒度鎖的選擇可以是隨意的, 微內(nèi)核可以選擇大鎖, 而對并行性有更高要求的則可以選擇細粒度鎖.
確定了內(nèi)核數(shù)據(jù)的配置方式后, 需要確定的是, 內(nèi)核到物理核心的分配問題. 現(xiàn)代的多核硬件中, 往往會有不同層次的緩存, 對這些緩存的合理使用可以直接加快系統(tǒng)的運行速度. 在一個內(nèi)核中, 當其中一個核心向內(nèi)存中更新數(shù)據(jù), 會通過緩存一層層寫回到內(nèi)存, 此時, 如果另一個核心和這個核心沒有共享緩存的話, 想要獲得更新后的數(shù)據(jù)就需要再從內(nèi)存中將其讀到自己的緩存中, 這會產(chǎn)生很大的開銷. 而如果兩個核心之間存在共享緩存, 那么就可以在數(shù)據(jù)真正寫回到內(nèi)存之前就通過共享緩存將其獲取. 因此, 擁有共享緩存的核心能夠在相對少的執(zhí)行時間中完成數(shù)據(jù)的同步. 因此,一個內(nèi)核中核心數(shù)目的上限應(yīng)當盡量由擁有共享緩存的核心數(shù)目來決定, 即, 有共享緩存的核心負責同一個內(nèi)核, 沒有共享緩存的核心負責不同內(nèi)核.
至于一個內(nèi)核核心數(shù)目的下限, 存在這樣的方案:每一個核心都為一個單獨的內(nèi)核服務(wù). 在這種方案中,每一個核心對應(yīng)一個內(nèi)核, 那么核心維護數(shù)據(jù)的時候就不再需要鎖. 從某種角度來說, 這種方案并行度很高而且避免了鎖和數(shù)據(jù)同步的代價. 但是, 在實際使用中,有大量的用戶應(yīng)用是有多核運行的需求的, 單核心內(nèi)核的模式會導(dǎo)致這類的應(yīng)用頻繁地使用多內(nèi)核提供的跨內(nèi)核通信的功能, 從而增加用戶使用系統(tǒng)服務(wù)的復(fù)雜程度并增加內(nèi)核間進行數(shù)據(jù)同步的次數(shù).
對于其他的硬件, 諸如內(nèi)存, 硬盤, 中斷控制器等,只要各個內(nèi)核之間可以事前商定這些資源的使用, 多內(nèi)核操作系統(tǒng)一般來說可以給予內(nèi)核較大的自由.
多內(nèi)核操作系統(tǒng)中的通信涉及到多個方面. 根據(jù)使用者可以分為內(nèi)核層的通信和用戶層的通信.
內(nèi)核層的通信是指內(nèi)核在維護內(nèi)核數(shù)據(jù)時所做的通信. 具體來說, 內(nèi)核層的通信包括內(nèi)核內(nèi)的通信與內(nèi)核間的通信. 內(nèi)核內(nèi)的通信指的是同一個內(nèi)核中不同核心之間的通信, 這種通信理論上不能稱之為通信, 僅是在需要時用鎖等方式實現(xiàn)的一種數(shù)據(jù)的共享. 內(nèi)核間的通信是指在不同內(nèi)核之中的兩個核心的通信, 這種通信一般用于處理一些內(nèi)核之間需要共享的數(shù)據(jù).一種簡單的方案是通過為兩個內(nèi)核設(shè)置相同的頁表項,從而設(shè)置一段共享的地址空間, 然后把這些共享的數(shù)據(jù)直接放到這個區(qū)間中, 通過鎖的方式進行讀取和更新, 或是在這段共享的區(qū)間中設(shè)計一個消息通道, 通過這種方式來進行消息通信. 總之, 內(nèi)核層的通信只是為了滿足在內(nèi)核層進行一定程度的數(shù)據(jù)共享, 這種通信本質(zhì)上只是一種代碼上實現(xiàn), 而不會體現(xiàn)成一組面向用戶的規(guī)范的接口.
多內(nèi)核操作系統(tǒng)不僅需要支持在其中某一個內(nèi)核上運行的用戶程序, 也需要支持同時運行在幾個內(nèi)核上運行的用戶程序, 這就需要為用戶提供一整套的用戶層的通信方式. 用戶層的通信一般是基于內(nèi)核提供給用戶的接口來完成. 以不共享地址空間的兩個線程為例, 這樣的兩個線程由于不共享地址空間, 因此無法直接訪問對方的數(shù)據(jù). 因此需要調(diào)用一定的系統(tǒng)調(diào)用來進行通信. 此時, 分為兩種情況, 兩個線程在同一個內(nèi)核上或在不同內(nèi)核上.
如果這兩個線程在同一個內(nèi)核上, 那么其本質(zhì)等于單內(nèi)核操作系統(tǒng)中兩個用戶線程的通信. 這里有兩個常見的方案: (1)為兩個線程申請一段共享的用戶地址空間, 如Linux 提供的共享內(nèi)存的接口, 通過創(chuàng)建和修改頁表項來實現(xiàn). (2) 使用內(nèi)核提供的進程間通信(inner-process communication, IPC)的接口. 進程間通信的實現(xiàn)方式有很多相關(guān)研究, 如seL4[16]的進程間通信,為每個線程準備了一段獨有的IPC 緩存, 通信時將數(shù)據(jù)從一邊的緩存移動到另一邊. 除此之外seL4 還專門對同核心上的兩個線程之間的進程間通信進行了諸多優(yōu)化, 如利用寄存器代替內(nèi)存來進行信息傳遞.
不同內(nèi)核上的兩個線程的通信也是類似的. 對于不同內(nèi)核的兩個線程之間的通信大體上也是這兩種方案: 一是通過創(chuàng)建和修改頁表項來為兩個線程準備一段共享的地址空間, 二是為用戶線程準備一套完整的進程間通信的接口. 與同內(nèi)核上的兩個線程通信不同的是, 內(nèi)核提供的這些功能需要能夠做到跨內(nèi)核. 如果要為兩個不同內(nèi)核的線程提供相同的地址空間, 首先要求兩個內(nèi)核都擁有分配該實際物理空間的權(quán)限, 然后兩個內(nèi)核各自將對應(yīng)的物理地址寫入到自己負責的用戶頁表的頁表項中. 如果是要為兩個不同內(nèi)核上的線程提供進程間通信的接口, 可行的方案是由這兩個內(nèi)核約定一段共享區(qū)間, 然后將其實現(xiàn)為一個消息隊列, 從而提供通信的功能.
對于多內(nèi)核操作系統(tǒng)來說, 其內(nèi)部的一個內(nèi)核可以是現(xiàn)有的各種內(nèi)核設(shè)計之一. 只要該內(nèi)核能夠遵循整個系統(tǒng)約定好的規(guī)范, 按照約定好的范圍使用各種硬件資源, 那么它理論上就能夠作為多內(nèi)核操作系統(tǒng)的一部分, 多內(nèi)核操作系統(tǒng)就能夠依照這些規(guī)范對它們進行啟動, 遷移和更新.
在一般的單內(nèi)核操作系統(tǒng)的啟動中, 以運行在Intel 架構(gòu)上的為例, 在機器通電之后, 會遵循諸如多重處理器規(guī)范等[18]選擇一個核心作為BSP (bootstrap processor)進行啟動. 之后, BSP 會執(zhí)行BIOS 等引導(dǎo)程序(bootloader), 遵循諸如multiboot 的規(guī)范, 將執(zhí)行流跳轉(zhuǎn)到支持這些規(guī)范的內(nèi)核代碼處. 接下來, 由BSP 運行內(nèi)核代碼進行更進一步的內(nèi)核啟動, 包括但不限于設(shè)置頁表, 尋址模式等. 在時機成熟時, 它們會向其他尚未啟動的核心, 這些核心被稱之為AP (application processor), 發(fā)送處理器間中端(interprocessor interrupt),使其他的核心的執(zhí)行流跳轉(zhuǎn)到它們需要跳轉(zhuǎn)到的位置,使這些AP 能夠參與到內(nèi)核的啟動之中.
多內(nèi)核操作系統(tǒng)啟動的第一步和一般的多核機器上單內(nèi)核操作系統(tǒng)的啟動是類似的. 具體來說, 多內(nèi)核操作系統(tǒng)啟動的第一個內(nèi)核與單內(nèi)核操作系統(tǒng)啟動整個系統(tǒng)是類似的. 兩者都是先啟動一個BSP, 然后啟動其他的AP. 區(qū)別在于, 多內(nèi)核操作系統(tǒng)啟動的AP 只包括屬于這個內(nèi)核的核心. 在這樣一個初始的內(nèi)核啟動后, 它將負責啟動其他的內(nèi)核. 為了方便表述, 本文稱第一個啟動的內(nèi)核為主內(nèi)核, 其他的內(nèi)核為子內(nèi)核. 在這里, 多內(nèi)核操作系統(tǒng)往往會自己定義好一組規(guī)范, 定義諸多子內(nèi)核運行所必須的內(nèi)容, 如子內(nèi)核可以使用的核心, 可以使用的內(nèi)存, 可以使用的其他硬件資源以及必要的用于交互的共享空間. 主內(nèi)核啟動子內(nèi)核的過程與BSP 啟動AP 是類似的, 依然以Intel 架構(gòu)為例,主內(nèi)核中的一個核心, 向子內(nèi)核中的BSP 發(fā)送一個處理器間中端, 使得子內(nèi)核的BSP 跳轉(zhuǎn)到自己內(nèi)核的入口, 而規(guī)范定義好的數(shù)據(jù)的地址則可以作為一個參數(shù)傳遞給子內(nèi)核的BSP. 主內(nèi)核和子內(nèi)核在啟動之后本質(zhì)上并沒有什么不同, 理論上, 只要事先約定好權(quán)限,啟動新的子內(nèi)核的可以是任何一個內(nèi)核. 因此, 啟動一個新的子內(nèi)核, 這樣一個行為完全可以設(shè)計成為一個系統(tǒng)調(diào)用, 交由用戶程序來決定使用.
多內(nèi)核操作系統(tǒng)中內(nèi)核的遷移可能分為兩種情況:(1)將一個內(nèi)核關(guān)閉, 然后將其上的任務(wù)遷移到其他的正在運行的內(nèi)核上. (2)將一個內(nèi)核連帶其上的任務(wù)遷移到其他的物理核心上. 這兩種情況, 都可以劃歸為,關(guān)閉一個內(nèi)核, 將其上的任務(wù)遷移到一個新的內(nèi)核上,只不過對于前者來說, 這個新的內(nèi)核是一個已經(jīng)存在了的內(nèi)核, 對于后者來說, 這個新的內(nèi)核是一個與原來內(nèi)核完全一致的內(nèi)核. 對于一個內(nèi)核來說, 關(guān)鍵的幾項,一是內(nèi)核維護的內(nèi)核數(shù)據(jù), 二是內(nèi)核所使用的硬件資源. 當系統(tǒng)對內(nèi)核進行遷移時, 本質(zhì)上是將內(nèi)核維護的內(nèi)核數(shù)據(jù)和使用的硬件資源, 通過數(shù)據(jù)拷貝或是傳遞指針的方式, 交給一個新的內(nèi)核來維護, 至于這個新的內(nèi)核, 是否使用原來的核心, 是否使用原來內(nèi)核的代碼,都可以交由用戶或操作系統(tǒng)自行決定.
內(nèi)核的更新本質(zhì)上就是對內(nèi)核遷移的一種擴展,即首先將一個內(nèi)核上的數(shù)據(jù)遷移到其他內(nèi)核, 或是單純將其存儲起來, 然后對原來的內(nèi)核在內(nèi)存中的代碼進行更新, 然后將內(nèi)核數(shù)據(jù)遷移回來.
在本節(jié)中, 本文將對現(xiàn)有的多內(nèi)核操作系統(tǒng)以及一些相關(guān)技術(shù)進行介紹和討論. 現(xiàn)有的多內(nèi)核操作系統(tǒng)的相關(guān)研究主要集中在, 多內(nèi)核針對異構(gòu)架構(gòu)的設(shè)計, 多內(nèi)核的遷移管理配置等方面, 除此之外, 還有一些將多內(nèi)核系統(tǒng)的思想用于更廣泛場景的研究.
Barrelfish[19-22]設(shè)計了一套相對完整的多內(nèi)核操作系統(tǒng). 該設(shè)計初衷主要為面向異構(gòu)的硬件, 諸如一個同時包含多個不同種類核心的機器. 在Barrelish 的設(shè)計中,每一個物理的核心負責一個內(nèi)核. 如圖3 所示, Barrelfish將操作系統(tǒng)相關(guān)的職責分為兩個部分, 位于內(nèi)核空間的特權(quán)模式(privileged-mode) 的CPU 驅(qū)動(CPU driver), 位于用戶空間的用戶模式(user-mode)的管程(monitor), 前者相當于一般語境下的內(nèi)核, 后者則類似于根線程.
圖3 Barrelfish 架構(gòu)圖[19]
在數(shù)據(jù)上, Barrelfish 使用了seL4 等微內(nèi)核的設(shè)計策略, 把系統(tǒng)資源分為一個個的內(nèi)核對象, 并把這些對象的引用(在微內(nèi)核里稱作capability)以樹的方式進行維護. 這樣的一組內(nèi)存數(shù)據(jù), 被稱作OS node. 內(nèi)核間的內(nèi)核數(shù)據(jù)各自獨立而不共享. 這些內(nèi)核對象包含進程控制塊, 頁表等各種和用戶息息相關(guān)的數(shù)據(jù). 另外,由于使用的是微內(nèi)核的設(shè)計策略, 很多原本是操作系統(tǒng)負責的任務(wù)都變成了用戶進程完成的任務(wù). 例如, 用戶需要自己調(diào)用系統(tǒng)去申請一個內(nèi)存對象作為一個頁表, 而內(nèi)核會將這個頁表的capability 返回給用戶讓用戶去使用. 這種內(nèi)核的設(shè)計簡化了內(nèi)核本身, 使得內(nèi)核在維護自身的數(shù)據(jù)時更加容易, 也為之后內(nèi)核遷移的設(shè)計做下鋪墊.
在通信方面, Barrelfish 中, 通信的雙方是用戶態(tài)的兩個線程. 具體來說, 如果是同一個內(nèi)核上的兩個用戶線程的通信, 則他們會通過一般的微內(nèi)核的IPC 進行,如果這兩個線程在不同的內(nèi)核上, 它們會建立一段共享內(nèi)存以作為跨內(nèi)核通信的通道. Barrelfish 將這種跨內(nèi)核的通信稱為URPC. 為了能夠提供完整的URPC功能, 需要底層CPU 驅(qū)動提供一些必要的功能, 如發(fā)送IPI 的功能, 即由一個核心向另一個核心發(fā)送處理器間中斷.
Barrelfish 允許動態(tài)地啟動一個新的內(nèi)核, 他們設(shè)計了一組boot driver, 專門用于啟動新的內(nèi)核. 首先Barrelfish 要求有一個已經(jīng)啟動的主內(nèi)核, boot driver運行在這個主內(nèi)核上. 啟動一個新的目標內(nèi)核的順序如下: 首先, 利用機器自身的機制(如ACPI)檢測新的核心, 然后, boot driver 為這個新的核心選擇一個合適的內(nèi)核, 按照核心啟動的協(xié)議對核心進行啟動, 將內(nèi)核的代碼加載到相應(yīng)的位置, 并將目標核心的執(zhí)行流跳轉(zhuǎn)到內(nèi)核入口, 然后目標核心就可以繼續(xù)自己內(nèi)核的初始化等諸多事項.
Barrelfish 同時也設(shè)計了一整套的內(nèi)核更新與遷移的算法, 其主要方式為, 將待更新內(nèi)核的OS node 轉(zhuǎn)交給其他的內(nèi)核, 然后待目標內(nèi)核更新完畢后, 將OS node 轉(zhuǎn)移回來.
總體而言, Barrelfish 是多內(nèi)核操作系統(tǒng)的一次很好的嘗試. 在各個方面都提出了很多值得借鑒的方法.
LegoOS[23]是Purdue University 開發(fā)的一種名為Splitkernel 的操作系統(tǒng), 這種設(shè)計與一般多內(nèi)核設(shè)計類似, 但是LegoOS 能夠適應(yīng)更廣泛的應(yīng)用場景. LegoOS的研究認為, 多內(nèi)核操作系統(tǒng)針對的是單內(nèi)存的多核心機器, 雖然其中的每個內(nèi)核可以被配置于不同的物理核心上, 但是這些內(nèi)核依然使用的是同一組內(nèi)存. 而LegoOS 擴展了使用的場景, 使它能夠適應(yīng)于更大型的服務(wù)器.
一般來說, 一個服務(wù)器系統(tǒng)包含的機器組包括多種核心, 多個不同種類的內(nèi)存, 以及多個不同種類的硬件存儲, 這些硬件往往通過網(wǎng)絡(luò)的方式連接起來.LegoOS 將這些硬件資源分為3 種組件: 核心, 內(nèi)存, 硬盤. 在這樣的情況下, 每一個內(nèi)核的結(jié)點可以選擇運行在任意的幾個組件之上, 而任意一個組件也可以同時為幾個內(nèi)核進行服務(wù). 相比一般的多內(nèi)核有著更多的擴展性. 為了實現(xiàn)這種分布式服務(wù)器上的多內(nèi)核系統(tǒng),LegoOS 還有專門負責管理所有資源組件的全局的管理器. 相比一般的多內(nèi)核, LegoOS 可以適用于不共享內(nèi)存的機器組, 前者內(nèi)核間的通信方式可以通過共同使用的內(nèi)存, 但是后者就只能通過網(wǎng)絡(luò)傳輸來進行通信. 因此LegoOS 使用了諸如RDMA 等相關(guān)技術(shù)來對網(wǎng)絡(luò)通信進行優(yōu)化.
實時操作系統(tǒng)是一種能夠快速接受和處理任務(wù)并能在規(guī)定時間內(nèi)產(chǎn)生處理結(jié)果的一類操作系統(tǒng), 其主要特點為擁有高實時性與可靠性. RT Linux 與Xenomai就是兩個典型的面向?qū)崟r的操作系統(tǒng), 且兩者都使用了“雙內(nèi)核”的設(shè)計思路.
RT Linux[2-5]是一種基于Linux 的實時操作系統(tǒng),如圖4 所示, 在RT Linux 中, 存在一個直接運行在硬件上的RT Linux 內(nèi)核. 該內(nèi)核為面向?qū)崟r應(yīng)用的內(nèi)核,直接負責管理硬件以及為實時應(yīng)用提供服務(wù). 在RT Linux 內(nèi)核中, 存在有調(diào)度器, 其負責調(diào)度實時應(yīng)用和一般的Linux 內(nèi)核, 而一般的Linux 內(nèi)核則負責管理運行非實時性的任務(wù). 在運行時, 實時應(yīng)用可以直接使用硬件的中斷并與硬件進行IO 交互, 一般的應(yīng)用則需要首先通過Linux 內(nèi)核, Linux 內(nèi)核再通過RT Linux 內(nèi)核來與硬件進行IO 交互. 在RT Linux 系統(tǒng)中, 盡管存在這兩個內(nèi)核, 但是一般性的Linux 內(nèi)核更類似于RT Linux 上運行的一個額外的應(yīng)用, 與其他的實時性任務(wù)共同參與調(diào)度. 這樣的設(shè)計保證了RT Linux 能夠通過調(diào)度提高實時性應(yīng)用的優(yōu)先級, 從而使系統(tǒng)能夠為實時任務(wù)提供精確的時間控制以及服務(wù).
圖4 RT Linux 架構(gòu)
Xenomai[6,7]是一種實現(xiàn)了雙內(nèi)核機制的實時操作系統(tǒng), 與RT Linux 不同的是, 其中的用于一般應(yīng)用的Linux 內(nèi)核與用于實時任務(wù)的內(nèi)核都處在同一個級別,參與調(diào)度. 如圖5 所示, Xenomai 使用了i-pipe 的技術(shù),i-pipe 負責中斷的分發(fā)與傳遞. 通過設(shè)計中斷的分發(fā)與傳遞規(guī)則來保證不同內(nèi)核的優(yōu)先級的不同. 舉例來說,當一個優(yōu)先級高的實時內(nèi)核注冊了一個中斷時, i-pipe會立刻進行處理, 而遇到一個優(yōu)先級低的Linux 內(nèi)核的中斷時, 它會等到實時內(nèi)核使用完物理硬件之后才觸發(fā)中斷運行Linux 的內(nèi)核.
圖5 Xenomai 架構(gòu)圖
RT Linux 和Xenomai 等實時操作系統(tǒng)與Barrelfish等系統(tǒng)有比較大的區(qū)別, 首先, RT Linux 和Xenomai都僅支持雙內(nèi)核, 并不等同于一般意義上的多內(nèi)核操作系統(tǒng). 其次由于實時操作系統(tǒng)主要面向于實時應(yīng)用,因此實時內(nèi)核的部分一般占有主要的地位. 當實時應(yīng)用需要的時候, 物理核心就會被實時內(nèi)核所搶占,Linux 內(nèi)核就會被調(diào)度出去, 換成實時內(nèi)核或應(yīng)用來運行. 相較而言, Barrelfish 盡管也支持內(nèi)核在物理核心間的轉(zhuǎn)移, 但是其中各個內(nèi)核依然是相對平等的.
除去上文提到的多內(nèi)核操作系統(tǒng)和與多內(nèi)核操作系統(tǒng)相近的雙內(nèi)核操作系統(tǒng), 還有一些操作系統(tǒng)相關(guān)研究, 雖然這些研究本身并不是多內(nèi)核操作系統(tǒng), 但是這些研究有的為多內(nèi)核操作系統(tǒng)的發(fā)展提供了思路,有的為多內(nèi)核操作系統(tǒng)提供了可行的技術(shù).
Corey[14]是一項針對Linux 系統(tǒng)的研究, 該研究分析了操作系統(tǒng)數(shù)據(jù)同步存在的瓶頸, 并針對該問題進行了解決. Corey 提出了分布式的設(shè)計, 將內(nèi)核數(shù)據(jù)分為共享部分和非共享部分, 以此來減少同步帶來的開銷. 該理念也是多內(nèi)核操作系統(tǒng)采用的方法的核心, 區(qū)別在于多內(nèi)核操作系統(tǒng)是一種更極端的方式, 它幾乎完全摒棄了共享數(shù)據(jù)的部分.
Theseus[24]是基于Rust 語言實現(xiàn)的操作系統(tǒng), 其利用Rust 語言的特性, 將內(nèi)核數(shù)據(jù)分成一個個極小的組件, 每一個組件被對應(yīng)到Rust 的crate, 一種獨立的編程單元. Rust 在編譯時就可以對內(nèi)核數(shù)據(jù)的每個組件對應(yīng)的內(nèi)存進行追蹤和保護. 將內(nèi)核數(shù)據(jù)組件化是一種非常有效的方式, 該思路往往也會被應(yīng)用到多內(nèi)核操作系統(tǒng)中, 組件化的內(nèi)核數(shù)據(jù)將更容易進行動態(tài)地加載與遷移.
PTask[25]是一種針對GPU 異構(gòu)架構(gòu)的研究. PTask對操作系統(tǒng)進行了擴展. 使其能夠?qū)PU 也納入操作系統(tǒng)的控制范疇中. 在此之前, GPU 僅僅是一個外部設(shè)備, 用戶通過IO 與GPU 通信. PTask 將GPU 變成了操作系統(tǒng)的一部分, 相當于一個特殊的核心, 加入到了調(diào)度之中. 多內(nèi)核操作系統(tǒng)也有類似的設(shè)計理念, 即將各種物理核心都作為一種可分配的資源提供給各個內(nèi)核,而GPU 與CPU 同樣, 也是可分配的核心資源之一.
多內(nèi)核操作系統(tǒng)與虛擬化技術(shù)都是能夠在某種層面上解決多核/眾核, 異構(gòu)架構(gòu)上擴展性, 性能穩(wěn)定性,以及資源分配的設(shè)計. 但是兩者還是有著明顯的不同.
如表1 所示, (1)多內(nèi)核操作系統(tǒng)中的每個內(nèi)核真實運行在單獨的一部分的硬件上, 相對而言, 虛擬化技術(shù)中一個客戶操作系統(tǒng)可能運行在一組被模擬出來的硬件上, 而模擬的硬件一般都會帶來一定程度的性能損耗. (2) 多內(nèi)核操作系統(tǒng)中的內(nèi)核由于直接運行在硬件之上, 因此不支持跨平臺執(zhí)行. 相較而言,虛擬化技術(shù)允許跨平臺執(zhí)行, 如一些虛擬化技術(shù)允許ARM 架構(gòu)的程序運行在x86 宿主機上, 而多內(nèi)核操作系統(tǒng)中, ARM 的程序只能在ARM 的核心上執(zhí)行.(3) 多內(nèi)核操作系統(tǒng)盡管需要一定程度的內(nèi)核管理, 但是這種管理的功能一般交由其中一個內(nèi)核來進行, 相比而言, 虛擬化技術(shù)一般需要一層中間的管理層來負責不同虛擬機之間的切換和使用. (4) 在內(nèi)存隔離方面, 一些虛擬化技術(shù)使用了輔助頁表的方式為客戶提供一個完整的虛擬地址空間, 但是這個空間映射到真實物理地址時可能并非連續(xù), 這樣的設(shè)計會導(dǎo)致緩存的性能降低. 而多內(nèi)核操作系統(tǒng)會將真實的連續(xù)的物理內(nèi)存直接分配給某個內(nèi)核, 因此不會增加緩存的開銷.
表1 多內(nèi)核操作系統(tǒng)與虛擬化技術(shù)的比較
從這些比較可以看出, 多內(nèi)核操作系統(tǒng)對于虛擬化技術(shù)互有優(yōu)劣, 在技術(shù)選擇時, 多內(nèi)核操作系統(tǒng)可以作為替代虛擬化技術(shù)的技術(shù)選擇.
多內(nèi)核操作系統(tǒng)是面對多核異構(gòu)系統(tǒng)的一種實現(xiàn)方式, 它從某種程度上解決了異構(gòu)系統(tǒng)不同硬件的適配問題. 相比單內(nèi)核操作系統(tǒng), 多內(nèi)核操作系統(tǒng)擁有更高的靈活性, 適應(yīng)性, 容錯性. 如果設(shè)計的足夠合理, 能夠正確地使用各項資源, 相比單內(nèi)核操作系統(tǒng), 也會有相近甚至較好的性能.
從未來發(fā)展的角度考慮, 為了讓多內(nèi)核操作系統(tǒng)能夠適用于更多硬件以及更多現(xiàn)有軟件, 需要為現(xiàn)有的單內(nèi)核進行多內(nèi)核化的改進. 然而現(xiàn)有的單內(nèi)核設(shè)計各有不同的宗旨, 提供的API 也各有差異. 為了讓不同硬件, 不同的內(nèi)核, 使用不同API 的軟件都集合在一套多內(nèi)核系統(tǒng)里, 一套專門的權(quán)威的多內(nèi)核系統(tǒng)的規(guī)范是必要的, 而這樣的過程很可能是漫長而充滿挑戰(zhàn)的.
總而言之, 多內(nèi)核操作系統(tǒng)還有很多路要走, 雖然研究不乏少數(shù), 但是依舊還有發(fā)展的空間.