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

news2025/2/3 22:49:50

编者按:将物理设备通过 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 已经清零完毕。

原文链接

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/103648.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小林coding阅读笔记:计算机网络基础篇-TCP\IP模型

前言 参考/导流: 小林coding - 2.1 TCP/IP 网络模型有哪几层?学习意义 学习分层设计思想构建网络层次以及各层协议作用知识体系为网络编程奠定理论基础,对于RPC框架or分布式系统通信都是极为重要的一节,是提升整个系统效率的关键…

ubunt配置samba服务器,匿名访问

1. 环境 ubuntu14.04 2. 安装samba服务器 sudo apt-get install samba 3. 配置samba文件 vim /etc/samba/smb.conf 在最后添加如下内容 [muchx]comment Shared Folder with username and passwordpath /home/muchx/sharepublic yeswritable yesvalid users muchxcre…

二、基于kubeadm安装kubernetes1.25集群第一篇

1、概述 Kubeadm 是一个提供了 kubeadm init 和 kubeadm join 的工具, 作为创建 Kubernetes 集群的 “快捷途径” 的最佳实践。 kubeadm 通过执行必要的操作来启动和运行最小可用集群。 按照设计,它只关注启动引导,而非配置机器。同样的&…

虹科分享 | 硬件加密U盘 | 管理密码安全的四大工具

随着网络攻击变得越来越突出,密码安全变得越来越重要。为了为每个帐户创建安全密码,许多人正在转向密码管理工具来帮助防止敏感数据的泄露。 考虑到这一点,以下是一些顶级密码管理工具。 领先的密码管理工具 Keeper密码管理器和数字保险库 …

kali linux手动编译网卡驱动(以mt7612u为例)

〇、linux常用命令 《Linux入门与基础》课程教案_小王小王指定辉煌的博客-CSDN博客_linux入门与基础教案 linux常用命令笔记(二)_小王小王指定辉煌的博客-CSDN博客 一、下载源码 查看系统版本号 uname -r uname -a cat /proc/version 或/lib/module…

手撕红黑树的构建与验证

上篇文章我们介绍了AVL树的构建与适用场景,我们知道了AVL树虽然查找效率很高,但是不适合频繁插入或删除的场景。为了解决这个问题又诞生了新的数据结构:红黑树 那么本篇文章就着重介绍红黑树的性质与如何构建。 1.红黑树的性质 1.结点颜色非黑…

邓俊辉 《数据结构》笔记1 绪论

邓俊辉 《数据结构》笔记1 绪论 CSDN转图床总是崩,如果全写完再上传一次要调好多,感觉很麻烦,所以写一点更新一点,会持续更新 提前发出来还有个好处就是push自己更新不会咕咕咕,哈哈 参考资料 MOOC 数据结构上MOOC 数…

【计算机考研408】磁盘的初始化过程

该图是磁盘物理图 关于磁盘存储器,[柱面号盘面号扇区号]⇔外存块号 注:柱面是相对位置相同的磁道所构成的面 磁盘初始化 低级初始化(也称物理格式化) (1)分扇区 (2)用特殊数据结构…

linux后台自定义后台服务service(以filebeat举例)

文章目录一、配置攥写1)安装filebeat和配置相关修改2)常用命令二、启动顺序1)命令循序2)systemctl添加自定义系统服务(服务填写指南)3)linux的systemctl命令详解及使用教程三、遇到的坑点和报错…

谁再要你自学网络安全,请给他一大B兜

前言 作为一名6年网安工程师老菜鸟来说,我实在想不通,开发岗位那么多,为什么要来学网安? 在这里必须给那些准备入坑的同学泼几盆冷水!零基础自学网络安全?劝你还是别做梦了! 基础确实很简单&#xff0c…

2023火爆共享购商业模式概念、框架、基础制度

各位企业家及创业者朋友们,你们好。我是微三云(陈志坤),在你打开这个文章的时候,先不要急,因为任何一个能够长久、安稳、盈利的平台,背后肯定有一位看准宏观方向且耐心的人。这是一个极具颠覆性…

算法图论篇

文章目录一、DFS1.排列数字(全排列)2.n皇后3.树的重心二、BFS1.走迷宫2.八数码3.图中点的层次三、拓扑排序1.有向图的拓扑序列四、最短路1.Dijkstra2. bellman-ford3.spfa4.floyd五、求最小生成树1.Prim算法2.Kruskal算法六、二分图1.染色法判定二分图2.…

UWB汽车钥匙介绍

汽车钥匙经历了机械钥匙、遥控钥匙、PEPS、数字钥匙四个阶段,而数字钥匙又分为BLE/NFC/UWB三种技术路线。 由于UWB安全性、定位精度、作用范围明显好于BLE和NFC,因此成为汽车数字钥匙的最优技术。 PEPS与数字钥匙: PEPS是指无钥匙进入/无钥匙启动系统&a…

【爬虫】JS调试解决反爬问题系列2

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ 🐴作者:秋无之地 🐴简介:CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作,主要擅长领域有:爬虫、后端、大数据…

ubuntu arm架构各版本源整理

目录 一、x86机构 1、ubuntu 20.04 2、ubuntu 18.04 3、ubuntu 21.10 4、ubuntu 22.04 二、arm机构 1、ubuntu 20.04 2、ubuntu 18.04 3、ubuntu 21.10 4、ubuntu 22.04 三、出现的问题 1、换成国内源后报https证书问题 2、如果选择国内开源站 ​3、提示the publi…

C语言重点解剖操作符要点速记

1.在多层嵌套的时候,每一次}结束加一个注释,标记清楚结束的是哪一个。 2.大部分注释都换成了空格。 in/* */t a; 等价于 in t a;替换成一个空格。 3.# define(中间可以有空格),但是不建议。 4.全局变量,常量定义等建议加上注释…

基于昇思MindSpore Quantum,实现量子虚时演化算法

01、关于昇思MindSpore项目介绍 1.项目名称 基于昇思MindSpore Quantum,实现量子虚时演化算法 2.项目链接 https://summer-ospp.ac.cn/#/org/prodetail/221cb0176 3.项目描述 在本次项目中,我们将运用MindSpore Quantum框架在量子线路上完成虚时演…

【Django】第一课 银行账户管理系统开发

概念 django服务器开发框架是一款基于Python编程语言用于web服务器开发的框架,采用的是MTV架构模式进行分层架构。 项目的搭建 1.打开pycharm开发软件,打开开发软件的内置dos窗口操作命令行 在这里指定项目存放的磁盘路径,并使用创建djang…

算法刷题日志——dp

文章目录[打家劫舍 III](https://leetcode.cn/problems/house-robber-iii/description/)卖股票的最佳时机[买卖股票的最佳时机 II](https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/)[买卖股票的最佳时机 III](https://leetcode.cn/problems/best-time-to-bu…

RK3588平台开发系列讲解(系统篇)A/B System的介绍

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、简介二、配置2.1、uboot配置2.2、system bootctrl参考沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍RK3588平台的A/B System。 一、简介 A/B System指的是存在两套可以正常工作的系统,分别存…