virtio-nvgpu 在 KVM 客戶端中實現近乎原生的 NVIDIA GPU 性能

KVM 客戶端內的接近原生 NVIDIA GPU 存取

重點: virtio-nvgpu 在驅動程式 ABI 層次上於主機與客體之間轉發 NVIDIA 核心驅動程式 ioctls,使 Linux KVM 客戶端可執行未修改的 NVIDIA 使用者模式驅動程式,並在幾乎無額外 CPU 成本的情況下,達到與裸機相差僅 2 % 的繪圖效能。


工作原理

  • 客體核心驅動程式 (GPL) 註冊常見的 /dev/nvidia* 節點。每次 ioctl() 時,將原始請求序列化至虛擬佇列;在 mmap() 時,直接將共享記憶體視窗映射到客體程序。
  • 裝置 crate (Apache-2.0, Rust) 在 VMM 中執行,接收這些虛擬佇列訊息,翻譯嵌入的檔案描述符與指標,並將 ioctl 轉發至主機的 NVIDIA 驅動程式。緩衝區管理在此處完成。
  • 事件虛擬佇列 在 GPU 完成工作時通知客體,消除忙等輪詢。
  • 隔離計畫 – 未來會有一個針對每個客體沙盒化的輔助程式(isolate 元件)持有真正的裝置檔案描述符;目前則由 VMM 程序直接持有。

此架構模仿 chromeos/virtio-media:一個 GPL 客體驅動程式與一個授權寬鬆、與 VMM 無關的裝置 crate 相鄰,所有 VMM 互動皆以 trait 表示。


性能結果(RTX 3060,驅動程式 595.99.02)

指標 客體(virtio‑nvgpu) 裸機主機
常見遊戲繪圖的幀時間(≥2 ms) ‑0.4 % 至 +1.7 %(在噪音範圍內) —
超輕量繪圖的幀時間(≤0.5 ms) 最多 +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 ms)時。


支援的使用情境

  • Vulkan 和 OpenGL 繪圖(無頭 EGL 可用)
  • 客體內的 Wayland 合成器,呈現離屏幀
  • CUDA 記憶體配置 與 Vulkan/GL 的零複製互操作
  • NVENC 編碼 直接從客體側 CUDA 缓衝區進行(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 一個 VM(或專用卡) 可用(原生) 強(IOMMU 隔離客體記憶體)
virtio-gpu + Venus 客體 Mesa 驅動程式(virgl) 每繪圖呼叫序列化與重播 多個 VM 共用 GPU 不可行(緩衝區位於主機) 中等
virtio-nvgpu(本專案) 未修改的 NVIDIA 使用者模式驅動程式 在驅動程式 ABI 層次轉發 ioctl(每幀約 1 次切換) 多個 VM 共用單一卡(已測試最多 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 透傳;答案是透傳無法跨 VM 共用 GPU。
  • @markasoftware 詢問此方案與 gVisor 的 nvproxy 有何不同;README 列出 nvproxy 為直接靈感來源,但未詳述差異。
  • @ericd 表達對無 VFIO 複雜度的高效能遊戲客體感到興奮。
  • @majorchord 詢問 Windows 客體支援;目前專案僅針對 Linux 客體。

倉儲結構

目錄 授權 目的
driver/ GPL-2.0 客體核心模組,透過虛擬佇列轉發 ioctl 與 mmap
device/ Apache-2.0 與 VMM 無關的 Rust crate,實作 virtio 裝置與 ABI 翻譯
isolate/ Apache-2.0 未來每客體沙盒化輔助程式的設計筆記(尚無程式碼)
gen/ — 從 NVIDIA 原始碼自動產生的 ABI 表格
protocol/ BSD-3-Clause OR 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 filter)已規劃但尚未實作。

授權

倉儲包含三個授權區域:客體驅動程式為 GPL-2.0,裝置 crate 與 isolate 設計為 Apache-2.0,共用協定標頭為 BSD-3-Clause(或 GPL-2.0+)。


總結而言,virtio-nvgpu 證明,在 ABI 層次轉發 NVIDIA 驅動程式 ioctl,可在允許多個 VM 共用單一顯卡的同時,讓 KVM 客體獲得近乎裸機的 GPU 性能,儘管其隔離性弱於 VFIO 透傳。

Sources