浪潮信息工程师:带你了解设备透传虚拟机的快速启动技术优化方案 | 龙蜥技术

简介: 一文了解设备透传虚拟机启动慢的原因及优化方法。

编者按:将物理设备通过 vfio 透传给虚拟机是虚拟化常用的技术,但当为虚拟机分配比较大的内存时,虚拟机的启动时间会明显变慢,可能由十几秒延长至数分钟,严重影响用户使用体验。本文整理自龙蜥大讲堂 51 期,浪潮信息操作系统研发工程师参与技术分享,介绍了设备透传虚拟机启动慢的原因及优化方法,以下为此次分享内容:

51期.png

技术背景:大内存虚拟机设备透传启动延迟

虚拟机设备透传时存在问题,比如将网卡或者 GPU 这些 pci 设备通过宿主机的 vfio 透传到虚拟机,并且又为虚拟机分配了比较大的内存时,虚拟机的启动时间会明显变慢。特别是分配了几百 G,甚至上 TB 的内存时,就会有比较明显的启动延迟,可能由十几秒延迟到数分钟。由于只有第一次启动时,也就是 qemu 进程启动时才会影响,所以一般来说用户可以接受这个启动延迟,但如果用户有频繁创建销毁虚拟机的需求时就会有比较差的使用体验。


把设备透传到虚拟机内部之后将会使用虚拟机内部的驱动程序对设备进行操作,这里有一个重要的问题是在虚拟机内部该如何进行 DMA 操作,因为 DMA 是不会经过 CPU 的,所以使用的是物理地址,但虚拟机内部看到的物理地址实际上只是宿主机上 qemu 进程申请的虚拟地址,直接用来做 DMA 肯定是不行的。这里就需要借助 IOMMU 来实现,虚拟机内 DMA 访问的 GPA,经过 iommu 映射到宿主机上的物理地址 HPA2,另外虚拟机内的驱动程序也可以经过 MMU/EPT,把 GVA 映射为 HPA1,最终需要 HPA1 和 HPA2 这两个物理地址是同一个才能让设备正常运行。(如下图)

为了实现 HPA1 等于 HPA2,需要 GPA 到 HPA 的映射是固定的并进行 iommu 表的建立,vfio 是通过 VFIO_IOMMU_MAP_DMA 命令实现。

11.png

后面使用到了 free page reporting 机制,这里介绍下 free page reporting 机制的原理,首先该机制提供了回调函数的注册,每隔 2 秒会遍历每个 zone 中的空闲页并调用回调函数进行处理,但只处理 buddy 中高阶内存页,就是 pageblock_order 阶及以上的内存,在 X86 架构下就是处理 9 阶和 10 阶的内存页,也就是 2M 和 4M 的内存页,这样也是保证能够处理 2M 的透明大页。


另一方面在处理时会保证每个 zone 的水线要比最低水线高 64M,因为如果 zone 的水线本身已经够低了,还从 zone 中申请内存,可能就会触发内存回收,这就会影响一些程序的性能。


通内存预清零加速 qemu 进程的内存初始化过程

下图是一个虚拟机启动时的火焰图,这里的虚拟机启动是指 qemu 进程开始执行到虚拟机内部出现 BIOS 界面为止,不包括虚拟机内部的内核加载、服务运行过程,从火焰图可以看到最耗时的函数是 clear_subpage 函数,根据函数调用关系可以看到是从 qemu 端调用了 ioctl 系统调用,这里就是要将虚拟机内存大小的虚拟内存执行  iommu 映射工作,将虚拟地址映射到指定的物理地址上。这其中就需要先将虚拟地址执行 page fault,并将虚拟机地址和物理地址的关系固定下来,再执行 iommu 映射操作。

12.png

应用程序执行 page fault 时最终都会执行 clear_user_highpage 对内存进行清零操作,这个函数相对来说耗时较长,是虚拟机启动时间慢的重要原因,当然我们可以选择不进行内存清零,但这会把宿主机上的一些敏感信息传递给虚拟机,造成安全影响,所以一般我们需要对内存进行清零。


为了解决内存页清零耗时比较长的问题,我们可以基于 free page reporting 机制实现内存页的预清零,过程比较简单,这里简单说下原理。首先通过 free page reporting 接口注册自己的 hook 函数,然后这个 hook 函数会周期性的被调用,每次调用会将 buddy 中的 2M/4M 空闲页执行清零操作,并在 page 的 flag 上设置清零 flag,最后在应用程序申请的内存触发缺页异常并需要对内存进行清零时,会首先判断该页是否已经设置了清零 flag,如果已设置则跳过耗时较长的清零操作。还有一点就是内存页的清零属于耗时但不紧急的操作,如果当前 CPU 有其它的事情要做,则优先执行别的工作,只有在 CPU 空闲时才执行内存清零。


通过大块内存 pin 降低 qemu 的内存 pin 时间

下图是优化了内存页预清零之后的火焰图,可以看到 clear_user_page 函数的执行时间已经非常短了,总体执行时间比较长的几个函数是 follow_page_mask、handle_mm_fault、find_extern_vma,下面就从代码角度来看哪个函数还可以进行优化。

13.png

vfio_pin_map_dma(…)
{
    while(size)
    {
    npage = vfio_pin_pages_remote(dma,start_vaddr,size,&pfn,limit)
    vfio_iommu_map(iommu,start_vaddr,pfn,npage,true)
    }将物理地址连续的内存执行iommu map
}

IOMMU_MAP_DMA 的 ioctl 进入内核空间会执行到 vfio_pin_map_dma 函数,在这个函数里会对虚拟机内存大小的虚拟内存进行 iommu map 操作,首先调用 vfio_pin_pages_remote 进行内存 pin 操作,这个函数的返回值 npage 是物理地址连续的N个内存页,然后调用 vfio_iommu_map 执行 iommu map 操作,比如对于 500G 内存的虚拟机来说会执行很多次这两个函数。

vfio_pin_pages_remote(…)
{
    for (…)
    {    
    pin_user_pages_remote(NULL, mm, vaddr, 1, flags | FOLL_LONGTERM, page, NULL, NULL);
    pfn = page_to_pfn(page[0]);
    if(pfn != *pfn_base + pinned)
    break;
    }每次只pin一个page,然后判断和上一个page是否物理连续
}

vfio_pin_pages_remote 这个函数会返回物理连续的多个内存页,为了实现这功能,每次调用 pin_user_pages_remote 获取一个页,然后判断和上一个页是否物理连续。

get_user_pages(…)
{
  while(npages)
  {
    if(!vma ||  start >= vma->vm_end)//相邻的两个虚拟内存页是否属于同一个vma
    {
      vma = find_extern_vma(…)
    }
    page = follow_page_mask(vma,start,…);
    if(!page)
      faultin_page(…)
  }
}

前面说的 pin_user_pages_remote 函数执行了很多次,这个函数里主要是调用了 get_user_pages,根据需要 pin 的 page 个数,首先判断相邻的两个虚拟内存页是否属于同一个 vma,如果不是则调用 find_extern_vma 函数获取 vma,这个函数从火焰图来看也是耗时比较长的,下面就是执行 follow_page_mask 获取页表,如果还未分配物理页则调用 page fault。


后面的两个函数执行是无法避免的,现在就看 find_extern_vma 函数,因为虚拟机的物理内存是 qemu mmap 的连续虚拟内存,属于同一个 vma,所以每次如果 pin 多个 page 可以跳过频繁执行的 find_extern_vma。


下面看一下内核社区的优化方案,5.12 内核合入主线,通过修改 vfio 代码实现,commit 说明有 8% 的性能提升。


优化原理是在 pin_user_pages_remote 函数里每次获取 512 个 page,当然这些page可能是不连续的,然后将这 512 个 page 中连续的部分识别出来分别执行iommu,因为我们系统中是开启透明大页的,所以一般来说这 512 个 page 都是物理连续的,只需要执行一次 iommu 就可以。

14.png

14.png

测试结果

测试环境为虚拟机分配了 512G 的内存,做了网卡的设备透传,虚拟机的启动时间计算方法为从 qemu 进程启动开始到出现 grub 界面为止,还有就是内存预清零在最理想的情况下,即当前系统上所有的 free page 已经清零完毕。


最终的测试结果:默认情况下(即开启透明大页),如果只开启大块内存 pin,启动时间从 80 秒降低至 60 秒,如果再开启内存页预清零,启动时间将降低至 12 秒。再看下虚拟机内存使用大页内存的情况下的测试结果,在使用 2M 或 1G 大页时开启大块内存 pin 功能时,虚拟机的启动时间基本从 36 秒降低至 18 秒,就算在开启内存页预清零,启动时间也没有变化,因为内存预清零不能作用于标准大页。

14.png

  • 虚拟机分配 512G 内存。
  • 时间计算方法:time virsh start testvm,时间为从 qemu 启动到出现 grub 界面为止。
  • 内存预清零在最理想情况下,即当前系统上所有 free page 已经清零完毕。


关于直播课件及视频回放获取方式:

【PPT 课件获取】:关注微信公众号(OpenAnolis),回复“龙蜥课件” 即可获取。有任何疑问请随时咨询龙蜥助手—小龙(微信:openanolis_assis)。

【视频回放】:视频回放可前往龙蜥官网 https://openanolis.cn/video 查看。

—— 完 ——

加入龙蜥社群

加入微信群:添加社区助理-龙蜥社区小龙(微信:openanolis_assis),备注【龙蜥】与你同在;加入钉钉群:扫描下方钉钉群二维码。

640 (5).png

相关文章
|
10月前
|
监控 算法 Java
Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
234 27
|
5月前
|
人工智能 安全 虚拟化
企业级Win11纯净部署指南|VMware虚拟机安装+GPT分区优化+绕过限制详解(小白必看)
Windows 11 是微软推出的新一代操作系统,以其直观交互和 AI 技术为核心升级亮点。界面采用圆角设计与居中任务栏布局,支持多窗口贴靠分屏、虚拟桌面功能,大幅提升多任务处理效率。系统深度集成了 Copilot 智能助手,提供语音写作、照片编辑等便捷功能,并通过 DirectStorage 和 DirectX 12 Ultimate 技术优化游戏体验。本文详细介绍 Windows 11 的下载、U盘制作及安装步骤,帮助用户快速上手全新系统。
422 21
|
7月前
|
监控 网络安全 虚拟化
Hyper-V中Win10,虚拟机运行错误处理的方案
当Hyper-V中的Windows 10虚拟机出现运行错误时,可按以下步骤处理:首先进行基本检查与修复,包括检查虚拟机配置、确保Hyper-V服务正常运行及重启相关服务。其次,使用PowerShell命令或DISM工具修复虚拟机配置和系统组件。接着,查看事件查看器中的错误日志,分析问题原因。调整虚拟机资源分配,优化性能。针对特定错误情况,如启动失败或网络问题,采取相应措施解决。若问题仍未解决,考虑克隆、重置或重新安装虚拟机,必要时联系技术支持。操作前请备份重要数据并以管理员身份运行命令。
|
7月前
|
存储 监控 虚拟化
Hyper V上网优化:提升虚拟机网络速度
要优化Hyper-V虚拟机的网络速度,可从以下几方面入手:1. 优化虚拟交换机配置,如选择合适的交换机类型、启用SR-IOV、配置VLAN和QoS策略;2. 调整网络适配器设置,选择适当的适配器类型并启用VRQ等;3. 优化宿主机网络配置,更新网卡固件和驱动,启用硬件加速;4. 使用性能监视工具监控网络流量;5. 其他措施如启用硬件虚拟化、使用外部存储、配置NLB等。通过合理配置,可显著提升网络性能。
|
7月前
|
编解码 虚拟化 Windows
通过Hyper分辨率适配技术,可以解决虚拟机显示器上的分辨率适配难题
Hyper-V的增强会话模式通过RDP协议实现虚拟机与物理显示器的高质量连接,支持更高分辨率、优化图形性能,并提供共享剪贴板、拖放文件等增强功能。启用此模式可解决虚拟机分辨率适配难题,提升显示效果和交互性。需确保操作系统支持RDP,网络稳定,且注意对主机性能的影响。
|
7月前
|
编解码 监控 虚拟化
Hyper分辨率优化技术,怎么使得虚拟机中的图形应用能够以更高的清晰度呈现
Hyper分辨率优化技术通过增强虚拟机的图形处理能力,显著提升图像清晰度和视觉体验,适用于图形设计、视频编辑等场景。该技术依赖于虚拟机的硬件配置、显卡驱动及显示设置,确保高分辨率内容的最佳呈现。使用时需合理设置分辨率,定期更新驱动并监控性能,以实现最佳效果。
|
10月前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
11月前
|
监控 算法 Java
Java虚拟机垃圾回收机制深度剖析与优化策略####
【10月更文挑战第21天】 本文旨在深入探讨Java虚拟机(JVM)中的垃圾回收机制,揭示其工作原理、常见算法及参数调优技巧。通过案例分析,展示如何根据应用特性调整GC策略,以提升Java应用的性能和稳定性,为开发者提供实战中的优化指南。 ####
136 5
|
11月前
|
监控 Java 开发者
Java虚拟机(JVM)深度优化指南####
本文深入探讨了Java虚拟机(JVM)的工作原理及其性能优化策略,旨在帮助开发者通过理解JVM的内部机制来提升Java应用的运行效率。不同于传统的技术教程,本文采用案例分析与实战技巧相结合的方式,为读者揭示JVM调优的艺术。 ####
312 8
|
11月前
|
存储 持续交付 虚拟化