Sản phẩm
Virtio-nvgpu: Giải pháp mã nguồn mở giúp máy ảo KVM đạt hiệu năng GPU NVIDIA gần như máy thật
(giờ Việt Nam)
Tóm tắt AI
Dự án virtio-nvgpu vừa ra mắt, cho phép máy ảo KVM truy cập GPU NVIDIA với hiệu năng đạt 98-100% so với máy vật lý nhờ cơ chế chuyển tiếp ioctl trực tiếp, giúp tối ưu hóa đáng kể cho các tác vụ AI và đồ họa trên môi trường ảo hóa.
Chính văn · Bản dịch AI
Truy cập NVIDIA GPU gần như nguyên bản bên trong một KVM guest. Một guest kết xuất (render) với hiệu năng trong phạm vi 2% so với máy chủ vật lý đang chạy và tiêu tốn CPU tương đương.
virtio-nvgpu chuyển tiếp các ioctl của trình điều khiển nhân NVIDIA giữa một Linux guest và host ở cấp độ ABI của trình điều khiển, bỏ qua hoàn toàn việc biên dịch ở cấp độ API. Guest chạy các trình điều khiển chế độ người dùng (user-mode) của chính NVIDIA mà không cần sửa đổi — cùng các thư viện đó, cùng Vulkan và NVENC, giao tiếp với cùng một card đồ họa.
Mục tiêu là truyền phát không màn hình (headless streaming): một compositor bên trong VM thực hiện kết xuất, tổng hợp và mã hóa các khung hình trên GPU, sau đó gửi video đã nén ra ngoài. VM không có màn hình và host vẫn giữ card đồ họa.
Tình trạng hiện tại
Nó hoạt động và đã được đo lường. Một Wayland client hiển thị bên trong guest, lớp capture mã hóa trên chính thiết bị của trò chơi và luồng H.264 xuất ra ở phía bên kia — 618 khung hình mà ffmpeg giải mã không có lỗi.
Đo lường trên RTX 3060 (driver 595.99.02), guest so với cùng một host, bare metal, với tải Vulkan headless giống hệt nhau:
| những gì host tiêu tốn cho một khung hình | thời gian khung hình của guest | |
|---|---|---|
| 39 ms | −0.4% | nhanh hơn bare metal, nằm trong ngưỡng nhiễu |
| 9.9 ms | −0.7% | |
| 2.0 ms | +1.7% | |
| 0.5 ms | +7.1% | một lần đánh thức (wake) tốn ~0.02 ms và khung hình chiếm một nửa trong số đó |
| 0.05 ms | +40.8% |
Trên khoảng 2 ms mỗi khung hình — tức là mọi khung hình mà trò chơi vẽ ra — một guest nằm trong phạm vi 2% so với bare metal. Dưới mức đó, chi phí chờ đợi GPU bắt đầu lộ rõ so với một khung hình gần như không tồn tại.
CPU là nửa còn lại của vấn đề, vì một GPU chia sẻ chỉ đáng giá khi các guest tiêu tốn ít tài nguyên. Không giới hạn tốc độ (unpaced) ở ~100 fps trong 12 giây, một guest:
| CPU đã sử dụng | |
|---|---|
| host, bare metal | 0.40 s |
| guest | 0.37 s |
Một guest tiêu tốn tài nguyên tương đương host. Không có gì bị lãng phí cho việc chuyển tiếp trong vòng lặp kết xuất, vì không có gì được chuyển tiếp: trình điều khiển chế độ người dùng của NVIDIA gửi dữ liệu thông qua bộ nhớ mà nó đã ánh xạ, và bộ nhớ đó là của host. Qua 813.691 khung hình, backend đã phục vụ 13.792 thông điệp — một lần truyền qua mỗi 59 khung hình, gần như tất cả đều là thiết lập thiết bị.
Phương pháp đầy đủ, các lần chạy thô và những điều mà các con số này không hỗ trợ: BENCHMARKS.md.
Nhiều guest trên một card
Bốn guest trên một RTX 3060, cùng một tải trong mỗi guest: 25.84, 26.49, 25.57, 25.79 fps — tổng cộng 103.7, so với 102.9 cho một guest đơn lẻ — với thời gian khung hình p50 lần lượt là 39.165, 39.164, 39.168 và 39.165 ms. Tổng số không thay đổi khi thêm guest và sự phân chia đồng đều đến bốn chữ số thập phân.
Cả bốn đều kết xuất chính xác cùng một lúc và cả bốn đều mã hóa H.264 cùng lúc, mỗi cái được điều tiết chính xác ở 60 Hz, không đạt giới hạn phiên NVENC.
Bốn là số lượng đã chạy, không phải giới hạn được tìm thấy.
Các phiên bản Driver
Đo lường trên 595.99.02; một A2000 trên 615.71.09 có kết xuất nhưng không được đo điểm chuẩn. Các cấu hình ABI được cung cấp: 535.129.03, 580.178.04, 595.71.05, khớp theo phạm vi, với bất kỳ phiên bản nào cũ hơn phiên bản đầu tiên đều bị từ chối. Chi tiết bên dưới.
Những gì đã xác nhận hoạt động
- một guest liệt kê được card — nvidia-smi báo cáo công suất và bộ nhớ thực, và deviceUUID là của host
- Kết xuất Vulkan: vulkaninfo thoát với mã 0, các lệnh vẽ offscreen chính xác từng pixel
- một Wayland client hiển thị thông qua một compositor trong guest
- NVENC thông qua Vulkan Video, mã hóa trên chính thiết bị của client
- các bộ đệm được nhập (imported buffers) là bộ nhớ của host, được ánh xạ thông qua một cửa sổ chia sẻ
Những gì chưa thực hiện
- nhiều hơn bốn guest, hoặc các guest thực hiện bất cứ thứ gì nặng hơn vkcube ở 720p. Bốn guest chia sẻ card đồng đều; tám guest chưa được thử nghiệm.
- hai card, hai phiên bản driver. RTX 3060 / 595.99.02 là nơi lấy các con số; một RTX A2000 / 615.71.09 đã kết xuất nhưng không được đo điểm chuẩn.
- CUDA được chuyển tiếp nhưng chưa được kiểm tra ngoài việc liệt kê thiết bị; trình quản lý (jailer), chia sẻ driver theo phiên bản và bao đóng đa người thuê (multi-tenant envelope) chưa được xây dựng.
Cấu trúc kho lưu trữ
Bốn thành phần, ba vùng giấy phép. Sự phân chia này là có chủ đích: phần guest phải là GPL để chạm vào các ký hiệu nhân, phần host nên có giấy phép thoáng (permissive) để người khác có thể xây dựng dựa trên đó, và các định nghĩa mà cả hai phần chia sẻ phải có thể được bao gồm từ cả hai phía.
| thư mục | giấy phép | mô tả |
|---|---|---|
| driver/ | GPL-2.0 | Module nhân cho guest. Đăng ký /dev/nvidia*, chuyển tiếp ioctl và mmap qua virtqueue. Cố tình không nhận biết ABI. |
| device/ | Apache-2.0 | Thiết bị virtio, dưới dạng một Rust crate không có VMM trong danh sách phụ thuộc. Mọi mối quan tâm về VMM đều là một trait. |
| isolate/ | Apache-2.0 | Một ghi chú thiết kế, chưa phải là mã nguồn. Trình hỗ trợ sandbox cho mỗi guest sẽ giữ các FD thiết bị thực. Hiện tại, backend tự giữ chúng trong chính tiến trình của VMM. |
| gen/ | — | Các bảng ABI được tạo tự động. Đã được kiểm tra và có thể tái tạo. |
| protocol/ | BSD-3-Clause HOẶC GPL-2.0+ | Định dạng truyền tin và các định nghĩa ABI được chia sẻ bởi cả hai phần. Cấp phép kép để driver GPL và crate Apache có thể bao gồm cùng các header. |
Cấu trúc tuân theo chromeos/virtio-media, giải quyết cùng một vấn đề — một kho lưu trữ chứa driver guest GPL bên cạnh một crate thiết bị có giấy phép thoáng và không phụ thuộc vào VMM.
Sử dụng từ một VMM
device/ không phụ thuộc vào bất kỳ trình giám sát máy ảo (virtual machine monitor) nào. Một VMM áp dụng thiết bị này bằng cách triển khai một tập hợp nhỏ các đặc tính (traits) — chuỗi mô tả (descriptor chains) dưới dạng Đọc/Ghi, hàng đợi sự kiện, ánh xạ bộ nhớ khách (guest memory mapping), ánh xạ bộ nhớ chủ (host memory mapping) — và nhận toàn bộ thiết bị mà không cần vá crate. Các tính năng tùy chọn sẽ suy giảm thay vì gây lỗi khi build, vì vậy VMM có thể áp dụng nó trước khi hỗ trợ đầy đủ mọi tính năng.
Việc quản lý bộ đệm (buffer) và cửa sổ (window) nằm trong device/. VMM chỉ cung cấp các hàm map và unmap thô mà không cần gì thêm.
Một thứ sẽ không trở thành trait: isolate. Thiết kế dự kiến sẽ chạy một tiến trình hỗ trợ (helper process) được sandbox cho mỗi tiến trình khách (guest process), vì vậy việc áp dụng nó cuối cùng đồng nghĩa với việc kế thừa một mô hình tiến trình, chứ không chỉ là một phụ thuộc thư viện. Tiến trình hỗ trợ đó hiện chưa được viết — backend hiện tự giữ các mô tả thiết bị — và isolate/ là nơi lưu giữ thiết kế cho đến khi nó được hoàn thiện.
Tại sao
Pipeline truyền phát (streaming pipeline) mà chúng ta mong muốn
Guest VM (headless, no physical display)
──────────────────────────────────────────
Game / application
│ Vulkan or OpenGL
▼
Wayland compositor (guest-side)
│ composites all windows
│ CUDA zero-copy import of composed frame
▼
NVENC hardware encoder (guest-side)
│ H.264 / H.265 bitstream (~100 KB per frame)
▼
Stream to remote clientToàn bộ pipeline render → composite → encode chạy trên GPU, bên trong guest. Chỉ có luồng bit (bitstream) đã nén được truyền ra ngoài. Điều này yêu cầu guest phải có quyền truy cập thực sự ở cấp độ driver vào các tài nguyên GPU: handle bộ đệm, fence, con trỏ thiết bị CUDA, các phiên NVENC.
Tại sao các phương pháp hiện tại chưa đáp ứng được
virtio-gpu + Venus (chuyển đổi cấp API). Venus tuần tự hóa mọi lệnh gọi Vulkan hoặc OpenGL trong guest, truyền qua virtio và phát lại ở phía host. Ba vấn đề đối với trường hợp sử dụng này:
- Độ trễ tích tụ trên các khối lượng công việc nặng về draw-call. Các trò chơi phát ra 1.000–5.000 draw call mỗi khung hình cộng với các lệnh bind, cập nhật descriptor và chuyển đổi render pass, mỗi lệnh đều được tuần tự hóa và phát lại riêng lẻ. Ở tốc độ 60 fps, ngân sách khung hình là 16,6 ms; 1–3 ms dành cho việc tuần tự hóa đã chiếm mất 6–18% thời gian trước khi bất kỳ công việc GPU nào được thực hiện.
- Chi phí CPU rất đáng kể. Việc tuần tự hóa, truyền tải và phát lại tiêu tốn CPU của host mà ứng dụng cần. Ở những nơi tính phí điện toán và tài nguyên có hạn, sự lãng phí đó chính là sản phẩm.
- Mã hóa phía guest không khả thi. Các bộ đệm GPU thuộc sở hữu của host. Trình tổng hợp (compositor) của guest không thể nhìn thấy hoặc import chúng, vì vậy không có con đường thực tế nào để có một CUdeviceptr trong guest trỏ đến bộ đệm do Venus quản lý — điều đó có nghĩa là không thể dùng NVENC nếu không thực hiện đọc ngược (readback) và sao chép toàn bộ qua CPU.
DRM native context (Intel / AMD). Guest chạy driver Mesa thực thụ, xây dựng các command buffer cục bộ và chỉ các lệnh gửi (submissions) mới vượt qua ranh giới. Quyền sở hữu bộ đệm và việc mã hóa phía guest hoạt động chính xác. Điều này không tồn tại đối với NVIDIA.
VFIO passthrough. Hiệu năng gốc và một ngăn xếp driver hoàn chỉnh trong guest, nhưng nó dành riêng toàn bộ GPU cho một VM. Trong các môi trường đa người thuê (multi-tenant), đây thường không phải là một lựa chọn khả thi.
Bài gốc còn tiếp — xem tiếp tại bài gốc ↗
Bài viết được AI dịch và tổng hợp tự động từ Hacker News Nổi bật (buzzing.cc bản dịch tiếng Trung). Liên kết bài gốc ở phía trên. Dữ liệu đồng bộ qua API công khai được ghi nguồn tại AI HOT (canonical) ↗. AIHOT.vn luôn dẫn nguồn đầy đủ — nếu bạn thấy điểm cần chỉnh sửa, hãy gửi ý kiến tại trang phản hồi.