揭秘GPU虚拟化,算力隔离,和最新技术突破qGPU( 三 )

  • MMIO 是物理的
  • 中断和 DMA,因为 VF 有自己的 PCIe 协议层的标识(Routing ID,就是 BDF),从而拥有独立的地址空间 。
  • 那么,什么设备适合实现 SR-IOV?其实无非是要满足两点:
    • 硬件资源要容易 partition
    • 无状态(至少要接近无状态)
    常见 PCIe 设备中,最适合 SR-IOV 的就是网卡了: 一或多对 TX/RX queue + 一或多个中断,结合上一个 Routing ID,就可以抽象为一个 VF 。而且它是近乎无状态的 。
    试考虑 NVMe 设备,它的资源也很容易 partition,但是它有存储数据,因此在实现 SR-IOV 方面,就会有更多的顾虑 。
    回到 GPU 虚拟化:为什么 2007 年就出现 SR-IOV 规范、直到 2015 业界才出现第一个「表面上的」SRIOV-capable GPU【1】?这是因为,虽然 GPU 基本也是无状态的,但是它的硬件复杂度极高,远远超出 NIC、NVMe 这些,导致硬件资源的 partition 很难实现 。
    注释
    【1】 AMD S7150 GPU 。腾讯云 GA2 机型使用 。
    表面上它支持 SR-IOV,但事实上硬件只是做了 VF 在 PCIe 层的抽象 。Host 上还需要一个 Virtualization-Aware 的 pGPU 驱动,负责 VF 的模拟和调度 。
    2.3.4 API 转发因此,在业界长期缺乏 SRIOV-capable GPU、又有强烈的 1:N 需求的情形下,就有更 high-level 的方案出现了 。我们首先回到 GPU 应用的场景:
    1. 渲染(OpenGL、DirectX,etc.)
    2. 计算(CUDA,OpenCL)
    3. 媒体编解码(VAAPI...)
    业界就从这些 API 入手,在软件层面实现了「GPU 虚拟化」 。以 AWS Elastic GPU 为例:
    • VM 中看不到真的或假的 GPU,但可以调用 OpenGL API 进行渲染
    • 在 OpenGL API 层,软件捕捉到该调用,转发给 Host
    • Host 请求 GPU 进行渲染
    • Host 把渲染的结果,转发给 VM
    API 层的 GPU 虚拟化是目前业界应用最广泛的 GPU 虚拟化方案 。它的好处是:
    • 灵活 。1:N 的 N,想定为多少,软件可自行决定;哪个 VM 的优先级高,哪个 VM 的优先级低,同理 。
    • 不依赖于 GPU 硬件厂商 。微软、VMWare、Citrix、华为……都可以实现 。这些 API 总归是公开的 。
    • 不限于系统虚拟化环境 。容器也好,普通的物理机也好,都可以 API 转发到远端 。
    缺点呢?
    • 复杂度极高 。同一功能有多套 API(渲染的 DirectX 和 OpenGL),同一套 API 还有不同版本(如 DirectX 9 和 DirectX 11),兼容性就复杂的要命 。
    • 功能不完整 。计算渲染媒体都支持的 API 转发方案,还没听说过 。并且,编解码甚至还不存在业界公用的 API!【1】
    注释
    【1】 Vulkan 的编解码支持,spec 刚刚添加,有望被所有 GPU 厂商支持 。见下「未来展望」部分 。
    2.3.5 MPT/MDEV/vGPU鉴于这些困难,业界就出现了 SR-IOV、API 转发之外的第三种方案 。我们称之为 MPT(Mediated Pass-Through,受控的直通) 。MPT 本质上是一种通用的 PCIe 设备虚拟化方案,甚至也可以用于 PCIe 之外的设备 。它的基本思路是:
    • 敏感资源如配置空间,是虚拟的
    • 关键资源如 MMIO(CSR 部分),是虚拟的,以便 trap-and-emulate
    • 性能关键资源如 MMIO(GPU 显存、NVMe CMB 等),硬件 partition 后直接赋给 VM
    • Host 上必须存在一个 Virtualization-Aware 的驱动程序,以负责模拟和调度,它实际上是 vGPU 的 device-model
    这样,VM 中就能看到一个「看似」完整的 GPU PCIe 设备,它也可以 attach 原生的 GPU 驱动 。以渲染为例,vGPU 的基本工作流程是:
    1. VM 中的 GPU 驱动,准备好一块内存,保存的是渲染 workload
    2. VM 中的 GPU 驱动,把这块内存的物理地址(GPA),写入到 MMIO CSR 中
    3. Host/Hypervisor/驱动: 捕捉到这次的 MMIO CSR 写操作,拿到了 GPA
    4. Host/Hypervisor/驱动: 把 GPA 转换成 HPA,并 pin 住相应的内存页
    5. Host/Hypervisor/驱动: 把 HPA(而不是 GPA),写入到 pGPU 的真实的 MMIO CSR 中
    6. pGPU 工作,完成这个渲染 workload,并发送中断给驱动
    7. 驱动找到该中断对应哪个 workload —— 当初我是为哪个 vGPU 提交的这个 workload?—— 并注入一个虚拟的中断到相应的 VM 中


      推荐阅读