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

39次阅读

共计 3618 个字符,预计需要花费 10 分钟才能阅读完成。

编者按:将物理设施通过 vfio 透传给虚拟机是虚拟化罕用的技术,但当为虚拟机调配比拟大的内存时,虚拟机的启动工夫会显著变慢,可能由十几秒缩短至数分钟,重大影响用户应用体验。本文整顿自龙蜥大讲堂 51 期,浪潮信息操作系统研发工程师参加技术分享,介绍了设施透传虚拟机启动慢的起因及优化办法,以下为此次分享内容:

技术背景:大内存虚拟机设施透传启动提早

虚拟机设施透传时存在问题,比方将网卡或者 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 命令实现。

前面应用到了 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 映射操作。

应用程序执行 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,上面就从代码角度来看哪个函数还能够进行优化。

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 就能够。

测试后果

测试环境为虚拟机调配了 512G 的内存,做了网卡的设施透传,虚拟机的启动工夫计算方法为从 qemu 过程启动开始到呈现 grub 界面为止,还有就是内存预清零在最现实的状况下,即以后零碎上所有的 free page 曾经清零结束。

最终的测试后果:默认状况下(即开启通明大页),如果只开启大块内存 pin,启动工夫从 80 秒升高至 60 秒,如果再开启内存页预清零,启动工夫将升高至 12 秒。再看下虚拟机内存应用大页内存的状况下的测试后果,在应用 2M 或 1G 大页时开启大块内存 pin 性能时,虚拟机的启动工夫根本从 36 秒升高至 18 秒,就算在开启内存页预清零,启动工夫也没有变动,因为内存预清零不能作用于规范大页。

  • 虚拟机调配 512G 内存。
  • 工夫计算方法:time virsh start testvm,工夫为从 qemu 启动到呈现 grub 界面为止。
  • 内存预清零在最现实状况下,即以后零碎上所有 free page 曾经清零结束。

原文链接

本文为阿里云原创内容,未经容许不得转载。

正文完
 0