HN 日本語サマリー

← 一覧へ戻る
プログラミング

Virtio-nvgpu: KVMゲスト内でNVIDIA GPUへのニアネイティブアクセスを実現

Virtio-nvgpu: Near-native Nvidia GPU access inside a KVM guest (github.com)

40 pointsby WanjohiRyan16 コメント

要約

Virtio-nvgpuは、KVMゲスト環境でNVIDIA GPUへのニアネイティブなアクセスを提供する新しいドライバーです。APIレベルの翻訳を完全にバイパスし、ゲストOSはNVIDIAの公式ユーザーモードドライバーをそのまま使用できます。これにより、GPUレンダリングとエンコードをゲスト内で実行し、ホストへのCPU負荷を最小限に抑えつつ、ヘッドレスストリーミングなどの用途で高いパフォーマンスを発揮します。

全文翻訳

virtio-nvgpu KVMゲスト内でのニアネイティブなNVIDIA GPUアクセス。ゲストは実行対象のマシンと比較して2%以内のオーバーヘッドでレンダリングし、CPUコストも同等です。virtio-nvgpuは、Linuxゲストとホスト間でNVIDIAカーネルドライバーのioctlをドライバーABIレベルで転送し、APIレベルの翻訳を完全にバイパスします。ゲストはNVIDIA自身のユーザーモードドライバーを、変更なしで使用します。同じライブラリ、同じVulkanとNVENCが、同じカードと通信します。ターゲットはヘッドレスストリーミングです。VM内のコンポジターがGPU上でフレームをレンダリング、コンポジット、エンコードし、その後圧縮ビデオを送信します。VMにはモニターがなく、ホストがカードを保持します。 現状 動作しており、測定も行われています。Waylandクライアントがゲスト内で表示され、キャプチャレイヤーがゲーム自身のデバイスでエンコードし、H.264が反対側から出力されます。ffmpegがエラーなしでデコードする618フレームです。RTX 3060(ドライバー595.99.02)で測定され、ゲストとホストは同一で、ベアメタルと同等のヘッドレスVulkan負荷がかかっています。ホストが1フレームにかかる時間に対して、ゲストのフレーム時間は39 msでベアメタルより0.4%高速、ノイズの範囲内です。9.9 msでは-0.7%、2.0 msでは+1.7%、0.5 msでは+7.1%です。ウェイクアップは約0.02 msかかり、フレームは0.05 msの半分です。+40.8%。約2 ms/フレーム(ゲームが描画するすべてのフレーム)を超えると、ゲストはベアメタルから2%以内のパフォーマンスになります。それ以下では、GPUを待つコストが、ほとんど存在しないフレームに対して現れ始めます。 CPUももう半分です。共有GPUは、ゲストのコストが低い場合にのみ共有する価値があるからです。12秒間、ペースなしで約100 fpsで実行した場合、1つのゲストのCPU使用率は、ホストのベアメタルで0.40秒、ゲストで0.37秒です。ゲストのコストはホストのコストと同等です。レンダーループでの転送には何も費やされません。なぜなら、何も転送されないからです。NVIDIAのユーザーモードドライバーは、マッピングされたメモリにサブミットし、そのメモリはホストのものです。813,691フレームにわたって、バックエンドは13,792メッセージを処理しました。これは59フレームあたり1メッセージのクロスオーバーで、ほぼすべてがデバイスセットアップでした。完全な方法、生の実行結果、およびこれらの数値がサポートしないものについては、BENCHMARKS.mdを参照してください。 1枚のカードで複数のゲスト 1枚のRTX 3060で4つのゲスト、それぞれに同じ負荷がかかっています。フレームレートは25.84、26.49、25.57、25.79 fpsです。合計で103.7 fpsとなり、単一ゲストの102.9 fpsと比較して、p50フレーム時間は39.165 ms、39.164 ms、39.168 ms、39.165 msです。ゲストを追加しても合計値は変化せず、分割は小数点以下4桁まで均等です。4つすべてが同時に正しくレンダリングされ、4つすべてが同時にH.264をエンコードし、それぞれが正確に60 Hzでペース設定され、NVENCセッション制限に達することはありませんでした。4は実行された数であり、制限ではありません。 ドライバーバージョン 595.99.02で測定されました。615.71.09のA2000はレンダリングしますが、ベンチマークは行われていません。出荷されたABIプロファイルは、535.129.03、580.178.04、595.71.05で、範囲で一致しており、最初のものより古いものは拒否されます。詳細は以下を参照してください。 動作することがわかっていること ゲストはカードを列挙します。nvidia-smiは実際の電力とメモリを報告し、deviceUUIDはホストのものです。Vulkanはレンダリングします。vulkaninfoは0で終了し、オフスクリーン描画はピクセルパーフェクトです。Waylandクライアントはゲスト内のコンポジターを通じて表示されます。Vulkan Video経由のNVENCは、クライアント自身のデバイスでエンコードします。インポートされたバッファはホストのメモリであり、共有ウィンドウを通じてマッピングされます。 完了していないこと 4つ以上のゲスト、または720pのvkcubeより重いことを行うゲスト。4つはカードを均等に共有します。8つは試されていません。2枚のカード、2つのドライバーバージョン。RTX 3060 / 595.99.02が数値の出所です。RTX A2000 / 615.71.09はレンダリングしますが、ベンチマークは行われていません。CUDAは転送されますが、列挙以外はテストされていません。Jailer、バージョンごとのドライバー共有、マルチテナントエンベロープはビルドされていません。 リポジトリレイアウト 4つのコンポーネント、3つのライセンスゾーン。この分割は意図的です。ゲスト側はカーネルシンボルに触れるためにGPLである必要があり、ホスト側は他の人がそれを基盤に構築できるように、許可的なライセンスである必要があります。両方が共有する定義は、両方からインクルード可能でなければなりません。 ディレクトリ ライセンス 内容 driver/ GPL-2.0 ゲストカーネルモジュール。/dev/nvidia*を登録し、virtqueue経由でioctlとmmapを転送します。ABIを意識しないように意図されています。 device/ Apache-2.0 VMMを依存リストに持たないRustクレートとしてのvirtioデバイス。すべてのVMMの懸念はトレイトです。 isolate/ Apache-2.0 まだコードではない設計ノート。実際のデバイスFDを保持するサンドボックス化されたヘルパーです。現在、バックエンドはVMM自身のプロセス内でディスクリプタを保持しています。 gen/ — 生成されたABIテーブル。チェックインされ、再現可能です。 protocol/ BSD-3-Clause OR GPL-2.0+ ワイヤーフォーマットとABI定義。両方の半分で共有されます。GPLドライバーとApacheクレートが同じヘッダーを含めることができるように、デュアルライセンスされています。 レイアウトは、chromeos/virtio-mediaに従っており、同じ問題を解決しています。つまり、1つのリポジトリに、許可的にライセンスされたVMMに依存しないデバイスクレートの隣にGPLゲストドライバーが含まれています。VMMがdevice/から使用するには、仮想マシンモニターに依存しません。VMMは、小さなトレイトセット(Read/Writeとしてのディスクリプタチェーン、イベントキュー、ゲストメモリマッピング、ホストメモリマッピング)を実装することでデバイスを採用し、クレートをパッチすることなくデバイス全体を取得します。オプションの機能は、ビルドに失敗するのではなく、低下するため、VMMはすべての機能をサポートする前に採用できます。バッファとウィンドウのブックキーピングはdevice/にあります。VMMは生のマップとアンマップのみを提供し、それ以上はありません。 トレイトにならないことの1つは、isolateです。意図された設計では、ゲストプロセスごとに1つのサンドボックス化されたヘルパープロセスを実行するため、最終的に採用することは、ライブラリ依存関係だけでなく、プロセスモデルを引き継ぐことを意味します。そのヘルパーはまだ書かれていません。バックエンドは現在デバイスディスクリプタ自体を保持しており、isolate/は設計が生きている場所です。 なぜ? 私たちが望むストリーミングパイプライン ゲストVM(ヘッドレス、物理ディスプレイなし) ────────────────────────────────────────── ゲーム/アプリケーション │ VulkanまたはOpenGL ▼ Waylandコンポジター(ゲスト側) │ すべてのウィンドウをコンポジット │ CUDAゼロコピー │ コンポジットされたフレームのインポート ▼ NVENCハードウェアエンコーダー(ゲスト側) │ H.264 / H.265ビットストリーム(フレームあたり約100 KB) ▼ リモートクライアントへのストリーム レンダリング→コンポジット→エンコードパイプライン全体がGPU上で、ゲスト内で実行されます。圧縮されたビットストリームのみが出力されます。これには、ゲストがGPUリソース(バッファハンドル、フェンス、CUDAデバイスポインター、NVENCセッション)への実際のドライバーレベルのアクセスを持つ必要があります。 既存のアプローチが不十分な理由 virtio-gpu + Venus(APIレベル翻訳)。Venusはゲスト内のすべてのVulkanまたはOpenGLコールをシリアライズし、virtio経由で転送し、ホスト側で再生します。このユースケースには3つの問題があります。 レイテンシがドローコールが多いワークロードで累積します。ゲームはフレームあたり1,000〜5,000のドローコールを発行し、バインド、ディスクリプタ更新、レンダリングパス遷移が追加され、それぞれが個別にシリアライズおよび再生されます。60 fpsでは、フレーム予算は16.6 msです。シリアライズに1〜3 msかかると、GPU作業が発生する前に6〜18%が失われます。 CPUオーバーヘッドが大きいです。シリアライズ、転送、再生は、アプリケーションが必要とするホストCPUを消費します。コンピューティングが課金され、有限である場合、その無駄は製品です。 ゲスト側エンコーディングは実行可能ではありません。GPUバッファはホストが所有しています。ゲストコンポジターはそれらを表示またはインポートできないため、Venusが管理するバッファを指すゲスト内のCUdeviceptrへの実用的なパスはありません。これは、完全なCPUリードバックとコピーなしではNVENCを意味しません。 DRMネイティブコンテキスト(Intel / AMD)。ゲストは実際のMesaドライバーを実行し、ローカルでコマンドバッファを構築し、サブミッションのみが境界を越えます。ゲスト側バッファの所有権とエンコーディングは正しく機能します。これはNVIDIAには存在しません。 VFIOパススルー。ゲスト内のネイティブパフォーマンスと完全なドライバースタックですが、GPU全体を1つのVMに専念させます。マルチテナント環境では、これはしばしばオプションではありません。 virtio-nvgpuの独自性 翻訳はグラフィックスAPIレベルではなく、カーネルドライバーレベル(/dev/nvidia*へのioctl)で行われます。ゲストはNVIDIAの実際のユーザーモードライブラリを実行し、ローカルでGPUコマンドバッファを構築します。個々のドローコールは決してシリアライズされません。 Venus virtio-nvgpu ────────────── ────────────────────── ドローコールごと: シリアライズ + ローカル関数呼び出し 転送 + (VM出口なし) デシリアライズ + 再生 フレームごと 約2,000メッセージ 約5〜20メッセージ 境界(1