4.3.1. 使用 TLB 的預警
TLB 是個處理器核心的全域(global)資源。所有執行在處理器核心的執行緒與行程都使用相同的 TLB。由於虛擬到實體位址的轉譯是看設置的是哪一個分頁表樹而定的,因此若是分頁表被更改了,CPU 就不能盲目地重複使用快取的項目。每個行程有個不同的分頁表樹(但同個行程中的執行緒並非如此)。假如有的話,系統核心與 VMM(虛擬機器監視器)亦是如此。一個行程的位址空間佈局也是可能改變的。有兩種處理這個問題的方式:
- 每當分頁表樹被更改都沖出 TLB。
- 擴充 TLB 項目的標籤,以額外且唯一地識別它們所指涉到的分頁表樹。
在第一種情況中,每當情境切換(context switch)都會沖出 TLB。由於––在大多 OS 中––從一個執行緒/行程切換到另一個時,需要執行一些系統核心的程式碼,TLB 沖出會被限制在離開(有時候是進入)系統核心位址空間時。在虛擬化的系統上,當系統核心必須呼叫 VMM、並在返回的途中時,這也會發生。若是系統核心和/或 VMM 不必使用虛擬位址、或是能夠重複使用與發出系統/VMM 呼叫的行程或系統核心相同的虛擬位址(即,位址空間被重疊了),TLB 只須在––離開系統核心或 VMM 後––處理器恢復一個不同的行程或系統核心的執行時沖出。
沖出 TLB 有效但昂貴。舉例來說,在執行一個系統呼叫時,系統核心程式可能會被限制在數千行觸及––或許––少數的新分頁(或者一個大分頁,如同在某些架構上的 Linux 的情況)的指令。這個操作僅會取代與被觸及的分頁一樣多的 TLB 項目。以 Intel 的 Core2 架構、附加它的 128 ITLB 與 256 DTLB 的項目而言,一次完整的沖出可能意味著被不必要地沖出的項目(分別)會超過 100 與 200 個。當系統呼叫返回(return)到相同的行程時,所有那些被沖出的 TLB 項目都能夠被再次用到,但它們將會被丟掉。對於在系統核心或 VMM 中經常用到的程式碼亦是如此。儘管系統核心以及 VMM 的分頁表通常不會改變,因此 TLB 項目––理論上––能夠被保存相當長的一段時間,但在每次進入系統核心時,TLB 也必須從零開始填入。這也解釋了為何現今處理器中的 TLB 快取並沒有更大的原因:程式的執行時間非常可能不會長到足以填入這所有的項目。
這個事實––當然––不會逃出 CPU 架構師的掌心。最佳化快取沖出的一個可能性是,單獨令 TLB 項目失效。舉例來說,若是系統核心與資料落在一個特殊的位址範圍,那麼僅有落在這個位址範圍的分頁必須從 TLB 逐出。這只需要比對標籤,因而不怎麼昂貴。這個方法在位址空間的一部分––例如,透過一次 munmap
呼叫––被更改的情況下也是有用的。
一個好得多的解法是擴充用來 TLB 存取的標籤。若是––除了虛擬位址的部分以外––為每個分頁表樹(即,一個行程的位址空間)加上一個唯一的識別子(identifier),TLB 根本就不必完全沖出。系統核心、VMM、以及獨立的行程全都能夠擁有唯一的識別子。採用這個方案的唯一議題是,可用於 TLB 標籤的位元數量會被嚴重地限制,而位址空間的數量則否。這表示是有必要重複使用某些識別子的。當這種情況發生時,TLB 必須被部分沖出(如果可能的話)。所有帶著被重複使用的識別子的項目都必須被沖出,但這––但願如此––是個非常小的集合。
當多個行程執行在系統中時,這種擴充的 TLB 標記在虛擬化的範圍之外是有優勢的。假如每個可執行行程的記憶體使用(是故 TLB 項目的使用)受限了,有個好機會是,當一個行程再次被排程時,它最近使用的 TLB 項目仍然在 TLB 中。但還有兩個額外的優點:
- 特殊的位址空間––像是那些被系統核心或 VMM 所用到的––通常只會被進入一段很短的時間;後續的控制經常是返回到啟動這次進入的位址空間。沒有標籤的話,便會執行一或兩次 TLB 沖出。有標籤的話,呼叫位址空間的快取轉譯會被保留,而且––由於系統核心與 VMM 位址空間根本不常更改 TLB 項目––來自前一次系統呼叫的轉譯等仍然可以被使用。
- 當在兩條相同行程的執行緒之間切換時,根本不需要 TLB 沖出。不過,沒有擴充的 TLB 標籤的話,進入系統核心就會銷毀第一條執行緒的項目。
某些處理器已經––一段時間了––實作了這些擴充標籤。AMD 以 Pacifica 虛擬化擴充引入了一種 1 位元的標籤擴充。這個 1 位元位址空間 ID(Address Space ID,ASID)是––在虛擬化的情境中––用以從客戶域(guest domain)的位址空間區別出 VMM 的位址空間。這使得 OS 得以避免在每次進入 VMM(舉例來說,處理一個分頁錯誤〔page fault〕)時沖出客戶端的 TLB 項目、或者在返回客戶端時沖出 VMM 的 TLB 項目。這個架構未來將會允許使用更多的位元。其它主流處理器可能也會遵循這套方法並支援這個功能。