4.3. 最佳化分頁表存取

分頁表的所有資料結構都會被保存在主記憶體中;OS 就是在這裡建構並更新表格的。在一個行程的創建、或是分頁表的一次修改之後,都會立即通知 CPU。分頁表是用以將每個虛擬位址,使用上述的分頁表走訪來轉成實體位址。更準確地說:每一層至少會有一個目錄會被用在轉換一個虛擬位址的過程中。這需要高達四次記憶體存取(以執行中行程的一個單一存取而言),這很慢。將這些目錄表的項目視為普通的資料、並在 L1d、L2、等等快取它們是辦得到的,但這可能還是太慢了。

從最早期的虛擬記憶體開始,CPU 設計者便已採用了一種不同的最佳化。一個簡單的計算能夠顯示,僅將目錄表的項目保存在 L1d 以及更高層級的快取中會招致可怕的效能。每個獨立的位址計算會需要相符於分頁表深度的若干 L1d 存取。這些存取無法平行化,因為它們都依賴於前一次查詢的結果。單是這樣就會––在一台有著四個分頁表階層的機器上––需要至少 12 個週期。再加上 L1d 錯失的機率,結果是指令管道無法隱藏任何東西。額外的 L1d 存取也需要將寶貴的頻寬偷到快取去。

所以,不只是將目錄表的項目快取起來,而是連實體分頁位址的完整計算結果也會被快取。跟程式碼與資料快取行得通的理由相同,這種快取的位址計算結果是很有效的。由於虛擬位址的分頁偏移量的部分不會參與到實體分頁位址的計算,僅有虛擬位址的剩餘部分會用來作為快取的標籤。視分頁大小而定,這代表數百或數千條的指令或資料物件會共享相同的標籤,因而共享相同的實體位址前綴(prefix)。

儲存計算得來的值的快取被稱為轉譯後備緩衝區(Translation Look-Aside Buffer,TLB)。它通常是個很小的快取,因為它必須非常快。現代的 CPU 提供了多層 TLB 快取,就如同其他快取一樣;更高層的快取更大也更慢。L1TLB 的小容量通常藉由令快取為全關聯式、加上 LRU 逐出策略來彌補。近來,這種快取的大小已經持續成長,並且––在進行中––被轉變為集合關聯式。因此,當一個新的項目必須被加入時,被逐出並取代的項目可能不是最舊的一個。

如同上面所註記的,用來存取 TLB 的標籤為虛擬位址的一部分。若是在快取中有比對到標籤,最終的實體位址就能夠藉由將來自虛擬位址的分頁偏移量加到被快取的值上而計算出來。這是個非常快的過程;它必須如此,因為實體位址必須可用於每條使用獨立位址的指令、以及––在某些情況下––使用實體位址作為鍵值(key)的 L2 查詢。若是 TLB 查詢沒有命中,處理器必須要進行一次分頁表走訪;這可能是非常昂貴的。

透過軟體或硬體預取程式碼或資料時,若是位址在另一個分頁上,能夠暗自預取 TLB 的項目。這對於硬體預取而言是不可能的,因為硬體可能會引發無效的分頁表走訪。程式設計師因而無法仰賴硬體預取來預取 TLB 項目。必須明確地使用預取指令來達成。TLB––就像是資料與指令快取––能夠出現在多個層級。就如同資料快取一樣,TLB 通常有兩種:指令 TLB(ITLB)以及資料 TLB(DTLB)。像是 L2TLB 這種更高層級的 TLB 通常是統一式的,與其它快取的情況相同。

results matching ""

    No results matching ""