virtio-nvgpu 在 KVM 客户机中实现接近原生的 NVIDIA GPU 性能

在 KVM 客户机内接近原生的 NVIDIA GPU 访问

要点: virtio-nvgpu 在驱动 ABI 级别在主机和客户机之间转发 NVIDIA 内核驱动 ioctl,使 Linux KVM 客户机能够运行未经修改的 NVIDIA 用户态驱动,并实现与裸机相比在 2% 以内的渲染性能,且几乎没有额外的 CPU 开销。


工作原理

  • 客户机内核驱动(GPL) 注册常规的 /dev/nvidia* 节点。在每次 ioctl() 时,它将原始请求序列化到 virtqueue 上;在 mmap() 时,它将共享内存窗口直接映射到客户机进程。
  • 设备 crate(Apache-2.0,Rust) 在 VMM 中运行,接收这些 virtqueue 消息,转换嵌入的文件描述符和指针,并将 ioctl 转发到主机的 NVIDIA 驱动。缓冲区簿记在此处进行。
  • 事件 virtqueue 在 GPU 完成工作时通知客户机,消除了忙轮询。
  • 隔离计划——未来的每客户机沙箱辅助进程(isolate 组件)将持有真实的设备文件描述符;目前 VMM 进程直接持有它们。

该架构与 chromeos/virtio-media 类似:GPL 客户机驱动旁边是一个宽松许可的、与 VMM 无关的设备 crate,所有 VMM 交互都通过 trait 表达。


性能结果(RTX 3060,驱动 595.99.02)

指标 客户机(virtio-nvgpu) 裸机主机
典型游戏绘制的帧时间(≥2 毫秒) -0.4% 到 +1.7%(在噪声范围内) —
超轻量绘制的帧时间(≤0.5 毫秒) 最高 +40.8%(等待成本占主导) —
100 fps 非节流运行(12 秒)的 CPU 使用率 0.37 秒 0.40 秒
每帧主机-客户机穿越次数 ≈0.02(每约 59 帧一次穿越) 数千次(Venus)
多客户机扩展(一台 RTX 3060 上 4 个客户机) 总计 103.7 fps,每个约 25.8 fps,与单客户机性能相同 —

解读: 对于 GPU 密集型工作负载,客户机与裸机无法区分;唯一可测量的性能损失出现在帧预算小于 GPU 唤醒延迟(约 0.02 毫秒)时。


支持的使用场景

  • Vulkan 和 OpenGL 渲染(无头 EGL 可用)
  • 客户机内的 Wayland 合成器,呈现屏幕外帧
  • CUDA 内存分配以及与 Vulkan/GL 的零拷贝互操作
  • 直接从客户机侧 CUDA 缓冲区进行 NVENC 编码(H.264/H.265 输出)

该设计明确排除了物理扫描输出、MIG/SR-IOV 和完整的统一虚拟内存(cudaMallocManaged)。


驱动 ABI 处理

NVIDIA 的内核驱动 ABI 在不同版本之间会变化。virtio-nvgpu 提供了明确的 ABI 配置文件:

配置文件 覆盖范围
535.129.03 535.129.03 直到下一个配置文件
580.178.04 580.178.04 直到下一个配置文件
595.71.05 595.71.05 及更新版本

任何早于 535.129.03 的驱动都会被拒绝。较新的驱动在最后一个配置文件下被接受,直到添加新的配置文件。这些配置文件是从 NVIDIA 的 open-gpu-kernel-modules 源码机械生成的,而非手工编写。


与其他 GPU 虚拟化方法的比较

方法 客户机驱动 API 转换 GPU 共享 NVENC 支持 隔离性
VFIO 直通 主机驱动绑定到客户机 PCI 设备 无(原生) 每个 GPU 一个虚拟机(或专用显卡) 可用(原生) 强(IOMMU 隔离客户机内存)
virtio-gpu + Venus 客户机 Mesa 驱动(virgl) 每次绘制调用序列化与重放 多个虚拟机共享 GPU 不可行(缓冲区位于主机) 中等
virtio-nvgpu(本项目) 未经修改的 NVIDIA 用户态驱动 在驱动 ABI 级别转发 ioctl(每帧约 1 次穿越) 多个虚拟机共享一张显卡(已测试最多 4 个) 可用,零拷贝 弱——所有 ioctl 都被转发;主机驱动在 TCB 中

关键见解: 通过将转换边界从图形 API 移动到内核驱动,virtio-nvgpu 消除了 Venus 每次绘制调用的巨大开销,同时仍允许多个客户机共享 GPU。


安全与隔离考虑

  • 没有 IOMMU 边界将客户机 GPU 工作与主机内存分离;主机 NVIDIA 驱动运行在主机的 IOMMU 域中,实际上属于可信计算基的一部分。
  • 当前实现转发 所有 驱动 ioctl(除了 ABI 配置文件明确拒绝的)。一个宽松标志(--permissive-abi)可以进一步放宽此限制以用于调试。
  • 未来的工作(isolate/)旨在将真实的设备文件描述符沙箱化到每客户机辅助进程中,但尚未实现。
  • 与 VFIO 相比,攻击面更大:被攻破的客户机可能发出任何允许的 ioctl,类似于在主机上运行多个共享 GPU 的进程。

社区反馈(Hacker News 亮点)

  • @refibrillator 指出了三种主要的 GPU 共享方法(VFIO、virtio-gpu/Venus、virtio-nvgpu),并指出 virtio-nvgpu 提供最弱的隔离,因为主机驱动在 TCB 中。
  • @orphereus 询问为什么不直接使用常规 GPU 直通;答案是直通无法在虚拟机之间共享 GPU。
  • @markasoftware 询问这与 gVisor 的 nvproxy 有何不同;README 将 nvproxy 列为直接灵感来源,但没有详细说明差异。
  • @ericd 对无需 VFIO 复杂性的高性能游戏虚拟机表示兴奋。
  • @majorchord 询问 Windows 客户机支持;当前项目仅针对 Linux 客户机。

仓库布局

目录 许可证 用途
driver/ GPL-2.0 客户机内核模块,通过 virtqueue 转发 ioctl 和 mmap
device/ Apache-2.0 与 VMM 无关的 Rust crate,实现 virtio 设备和 ABI 转换
isolate/ Apache-2.0 未来每客户机沙箱辅助进程的设计说明(尚无代码)
gen/ — 从 NVIDIA 源码自动生成的 ABI 表
protocol/ BSD-3-Clause 或 GPL-2.0+ 共享的线上格式和 ABI 定义

快速开始

  1. 构建客户机驱动(driver/)并在 KVM 客户机内加载。
  2. 通过实现所需的 trait(描述符链 I/O、事件处理、客户机/主机内存映射),将 device/ crate 集成到你的 VMM 中。
  3. 在客户机内运行 Vulkan 或 Wayland 应用程序;README 中的基准测试脚本(BENCHMARKS.md)验证接近原生的性能。

限制与未来工作

  • 已在单个 RTX 3060 上测试最多 四个 客户机;更多客户机未经测试。
  • 仅测试了驱动版本 595.99.02(RTX 3060)和 615.71.09(RTX A2000);其他显卡未经测试。
  • CUDA 功能被转发,但除枚举外未进行彻底验证。
  • 尚不支持 Windows 客户机;项目仅针对 Linux。
  • 隔离改进(每客户机沙箱、seccomp 过滤器)已计划但尚未实现。

许可证

仓库包含三个许可区域:客户机驱动为 GPL-2.0,设备 crate 和 isolate 设计为 Apache-2.0,共享协议头文件为 BSD-3-Clause(或 GPL-2.0+)。


总之,virtio-nvgpu 证明了在 ABI 级别转发 NVIDIA 驱动 ioctl 可以为 KVM 客户机提供接近裸机的 GPU 性能,同时允许多个虚拟机共享一张显卡,尽管隔离性比 VFIO 直通弱。

Sources