
桔妹导读:GPU虚拟机实例建立速度慢是公有云面临的广泛问题,因为一般状况下建立虚拟机属于低频操做而未引发业界的重视,实际生产中仍是存在对GPU实例建立时间有苛刻要求的业务场景。本文将介绍滴滴云在解决该问题时的思路、方法、并展现最终的优化成果。html
从公有云服务商那里购买过虚拟主机的资深用户,通常会发现这么个规律:建立一台CPU虚拟主机是比较快的,可是要建立一台包含GPU卡的虚拟主机一般须要等比较长的时间,整个建立过程短则数十秒钟,长则数分钟。对于绝大多少的用户来讲,虚拟主机的建立时间长一点对他们影响并不大,由于建立虚拟机属于相对低频操做。可是也会有一些特定的用户因为其业务场景交互性比较强,会对虚拟主机的建立时间有相对苛刻的要求,由于过长的建立时间会致使其业务用户体验不好。本文将从虚拟化的角度来介绍GPU虚拟主机建立时间长背后的缘由,以及相关的优化方法。安全
经过分析Libvirt, QEMU以及Guest 内的相关日志及对应的时间戳,能够获取GPU虚拟主机在建立过程当中的耗时状况,这里咱们主要关心几个关键的时间点: a) Libvirt 开始建立QEMU 进程;b) Libvirt 执行 Resume启动VCPU ; c) Guest kernel 打印第一条日志. 在本文中,咱们把a和 b 之间的时间间隔称为QEMU初始化时间, 把b 和c 之间的时间间隔称为 BIOS执行时间。如下数据是在滴滴云的线上环境中采集到的建立一台包含8个CPU核虚拟机实例的相关数据:性能优化

从上面的数据能够看到,对于规格相同的虚拟机实例,带1块P40卡的GPU实例相比同规格的CPU实例在QEMU初始化及BIOS执行部分的时间都明显要长, 在带4块P40卡以及更大内存规格的场景下,须要的时间会进一步拉长。经过实验咱们发如今主机配置和GPU卡型号肯定的前提下,GPU实例的建立时间长短主要取决于两个因素:虚拟机的内存大小和GPU卡的数量。服务器
为何GPU实例的建立过程要比CPU实例的建立过程耗时长?多消耗的时间到底花在哪里?要搞清楚缘由须要深刻的分析,比较直观的办法就是经过perf采样来生成火焰图,以此来分析虚拟机在建立过程当中的热点函数。下图是在滴滴云环境里抓取到的GPU虚拟机启动过程当中QEMU进程的火焰图。微信

经过对代码调用关系的分析,能够得知热点发生在系统分配内存和对内存页面清零的过程当中,是由QEMU中的vfio_dma_map函数在执行VFIO_IOMMU_MAP_DMA ioctl 系统调用所触发,该调用会Pin住全部分配给VM当作RAM使用的内存。在Pin 内存的过程当中,若是虚拟内存对应的物理页面还没有分配,会先进行物理内存分配并对内存页面内容进行清零。在Linux kernel 中,对分配给应用程序的内存进行清零主要是基于安全方面的考虑,避免Host 内存中的内容泄漏给用户空间的应用程序。这里之因此要将内存Pin 住,目的是为了保证IOMMU IO页表和 host HVA->HPA 映射的一致性,不然Guest 内设备的DMA操做可能会访问到错误的内存页面。多线程
VFIO DMA 映射处理慢能够在必定程度上解释为何内存的大小和GPU卡的数量会影响到GPU实例的建立时间。虚拟机实例内存规格越大,须要映射和Pin住的内存量也就越大,相关处理的耗时和内存量成正比。另外GPU卡上一般会包含一块比较大的MMIO区域,对MMIO的映射也会耗费较多的时间,卡的数量越多,耗时就会越长。相比之下,CPU实例的建立过程没有VFIO DMA 映射的相关处理流程,所以会比较快。app
针对以上的热点,有什么办法能够消除或者缓解呢?已经有业内的同行们提到过这个问题并给出了对应的解决方案,其思路是对分配给VM 用做RAM使用的内存区域作一个标记,在内核中跳过对标记的内存页面进行清零,而将清零的动做留给QEMU来作,在QEMU 中能够利用多线程以及更高效的指令进行清零动做,从而加速Pin内存的过程。该方案的缺陷主要有两点: 一是存在安全性风险,其余应用程序能够利用设定的标记来窥探host 内存中的信息;二是在VM实例的VCPU个数比较少的状况下,优化效果不是很好。分布式
咱们采用了另一种方案,经过修改Host kernel的内存管理部分, 咱们实现了一种对Host 上空闲物理内存提早进行清零的机制,清零动做能够在系统空闲的时候进行,当某个内存页面被清零后,将其对应的 struct page 进行标记,这样在须要对内存进行清零的时候,能够经过检查该标记来判断是否要执行清零动做,若是清零的标记已经被设置,就能够跳过清零的步骤。该方案避免了上述方案中的两个主要问题,同时还有其它方面的好处,主要包括如下几点:a.能够提升缺页异常处理效率,尤为是透明大页的缺页异常处理效率;b. 能够加速须要Pin内存及须要经过mlock 来锁住内存的应用场景,例如使用RDMA, QAT 硬件加速等场合;c. 能够加速内核中其余须要对内存进行清零的场景。相关补丁的RFC版本,咱们已经提交到了Linux kernel 社区。函数
另外一个加速Pin内存的有效方法是采用大页,经过开启透明大页能够显著减小缺页处理的调用次数并加速Pin内存的过程。下图展现了开启透明大页以及启用空闲内存预清零机制对GPU实例创建立时间的影响。性能
以上的数据代表,在开启透明大页以及空闲内存预清零功能后,能够显著的的优化QEMU的初始化时间,可是BIOS部分的耗时依然偏长。经过进一步的分析咱们发现主要的时间消耗仍是在VFIO 映射DMA的处理过程中,主要有几个方面的缘由:a. 映射DMA Pin内存须要逐页查询页表,开销较大;b. QEMU 存在对部分IOVA区域的反复映射及解除映射的操做。因而咱们尝试在这两个方向上进行优化,经过采用批量处理的方法减小查询页表的开销,另外在QEMU中加入VFIO DMA映射区域的管理,有效的规避了效率低下的反复映射及解除映射操做,最终大幅度下降了VFIO DMA映射的时间消耗。
在解决完上述问题后咱们并无止步,对虚拟机实例建立过程当中的可优化的其它地方,咱们也作了相关的处理,例如关闭BIOS boot menu ,优化VFIO PCI 设备reset 的流程,去掉对GPU实例来讲没必要要的操做,最终将GPU实例建立过程当中虚拟化部分的时间开销减小了90%以上,下面这张图展现了单卡小内存规格实例优化先后的耗时对比:
大内存规格和多GPU卡的效果更加显著,时间减小了95%以上,相关数据以下图:


专一于系统虚拟化研究,负责解决滴滴云底层虚拟化相关技术问题。曾就任于Intel 开源软件中心虚拟化组,具有丰富的底层系统软件开发经验。
内容编辑 | Charlotte 联系咱们 | DiDiTech@didiglobal.com
![]()
本文分享自微信公众号 - 滴滴技术(didi_tech)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。