背景
內存用於暫存CPU將要執行的指令和數據,所有程序的運行都必須先載入到內存中才可以,內存的大小及其訪問速度也直接影響整個系統性能。在平台虛擬化技術中,Guest的運行也需要依賴內存。和運行在真實物理硬件上的操作系統一樣,在Guest操作系統看來,Guest可用的內存空間也是一個從零地址開始的連續的物理內存空間。為了達到這個目的,Hypervisor(即KVM)引入了一層新的地址空間,即Guest物理地址空間,這個地址空間不是真正的硬件上的地址空間,它們之間還有一層映射。所以,在虛擬化環境下,內存使用就需要兩層的地址轉換,即Guest應用程序可見的Guest虛擬地址(Guest Virtual Address,GVA)到客戶機物理地址(Guest Physical Address,GPA)的轉換,再從Guest物理地址(GPA)到宿主機物理地址(Host Physical Address,HPA)的轉換。其中,前一個轉換由Guest操作系統來完成,而后一個轉換由Hypervisor來負責。為了解決這兩次地址轉換,Intel先后使用了不同的技術手段。
影子頁表
影子頁表(Shadow Page Tables)是從軟件上維護了從GVA到HPA之間的映射,每一份Guest操作系統的頁表也對應一份影子頁表。有了影子頁表,在普通的內存訪問時都可實現從GVA到HPA的直接轉換,從而避免了上面前面提到的兩次地址轉換。Hypervisor將影子頁表載入到物理上的內存管理單元(Memory Management Unit,MMU)中進行地址翻譯。GVA、GPA、HPA之間的轉換,以及影子頁表的作用如下圖。
盡管影子頁表提供了在物理MMU硬件中能使用的頁表,但是其缺點也是比較明顯的。
技術復雜
影子頁表實現非常復雜,導致其開發、調試和維護都比較困難。
物理內存開銷大
由於需要為每個客戶機進程對應的頁表的都維護一個影子頁表,因此影子頁表的內存開銷非常大。
EPT
EPT(Extended Page Tables,擴展頁表),屬於Intel的第二代硬件虛擬化技術,它是針對內存管理單元(MMU)的虛擬化擴展。相對於影子頁表,EPT降低了內存虛擬化的難度(,也提升了內存虛擬化的性能。從基於Intel的Nehalem架構的平台開始,EPT就作為CPU的一個特性加入到CPU硬件中去了。
Intel在CPU中使用EPT技術,AMD也提供的類似技術叫做NPT,即Nested Page Tables。都是直接在硬件上支持GVA-->GPA-->HPA的兩次地址轉換,從而降低內存虛擬化實現的復雜度,也進一步提升了內存虛擬化的性能。Intel EPT技術的基本原理如下圖
CR3(控制寄存器3)將客戶機程序所見的客戶機虛擬地址(GVA)轉化為客戶機物理地址(GPA),然后在通過EPT將客戶機物理地址(GPA)轉化為宿主機物理地址(HPA)。這兩次轉換地址轉換都是由CPU硬件來自動完成的,其轉換效率非常高。
在使用EPT的情況下,客戶機內部的Page Fault、INVLPG(使TLB]項目失效)指令、CR3寄存器的訪問等都不會引起VM-Exit,因此大大減少了VM-Exit的數量,從而提高了性能。
EPT只需要維護一張EPT頁表,而不需要像“影子頁表”那樣為每個客戶機進程的頁表維護一張影子頁表,從而也減少了內存的開銷。
VPID
TLB(Translation Lookaside Buffer)轉換檢測緩沖區是一個內存管理單元,用於改進虛擬地址到物理地址轉換速度的緩存。
VPID(VirtualProcessor Identifiers,虛擬處理器標識),是在硬件上對TLB資源管理的優化,通過在硬件上為每個TLB項增加一個標識,用於不同的虛擬處理器的地址空間,從而能夠區分開Hypervisor和不同處理器的TLB。
硬件區分了不同的TLB項分別屬於不同虛擬處理器,因此可以避免每次進行VM-Entry和VM-Exit時都讓TLB全部失效,提高了VM切換的效率。
由於有了這些在VM切換后仍然繼續存在的TLB項,硬件減少了一些不必要的頁表訪問,減少了內存訪問次數,從而提高了Hypervisor和客戶機的運行速度。
VPID也會對客戶機的實時遷移(Live Migration)有很好的效率提升,會節省實時遷移的開銷,會提升實時遷移的速度,降低遷移的延遲(Latency)。
VPID與EPT是一起加入到CPU中的特性,也是Intel公司在2009年推出Nehalem系列處理器上新增的與虛擬化相關的重要功能。
Host上常看CPU對EPT、VPID支持情況
我Host上有8顆邏輯CPU

[root@localhost ~]# grep "ept vpid" /proc/cpuinfo -o ept vpid ept vpid ept vpid ept vpid ept vpid ept vpid ept vpid ept vpid
KVM虛擬化下如何開關EPT、VPID
在加載kvm_intel模塊時,可以通過設置ept和vpid參數的值來打開或關閉EPT和VPID。
當然,如果kvm_intel模塊已經處於加載狀態,則需要先卸載這個模塊,在重新加載之時加入所需的參數設置。

[root@localhost ~]# cat /sys/module/kvm_intel/parameters/ept Y [root@localhost ~]# cat /sys/module/kvm_intel/parameters/vpid Y
一般不要手動關閉EPT和VPID功能,否則會導致Guest中內存訪問的性能下降。