背景
内存用于暂存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中内存访问的性能下降。