作者:jikesong,騰訊 CSIG 騰訊云異構計算研發副總監
〇、本文寫作背景
大約 2 年前,在騰訊內網,筆者和很多同事討論了 GPU 虛擬化的現狀和問題。從那以后,出現了一些新的研究方向,并且,有些業界變化,可能會徹底顛覆掉原來的一些論斷。
但這里并不是要重新介紹完整的 GPU 虛擬化的方案譜系。而是,我們將聚焦在英偉達 GPU + CUDA 計算領域,介紹下我們最新的技術突破 qGPU,以及它的意義究竟是什么。關于 GPU 虛擬化的歷史性介紹,我將直接摘抄當時的討論。
這也不是一篇介紹 TKE qGPU 產品特性的文章。而是,我們將潛入到前所未有的深度,去探索 GPU 調度和 QoS 的本質。本文也不是巨細靡遺的系統性探索,但你可以在這里看到別處不曾出現過的知識。
本文涉及對一些廠商的推測性技術介紹,不保證準確性。
一、術語介紹
GPU ————— Graphics Processing Unit,顯卡
CUDA ———— Compute Unified Device Architecture,英偉達 2006 年推出的計算 API
VT/VT-x/VT-d — Intel Virtualization Technology。-x 表示 x86 CPU,-d 表示 Device。
SVM ————— AMD Secure Virtual machine。AMD 的等價于 Intel VT-x 的技術。
EPT ————— Extended Page Table,Intel 的 CPU 虛擬化中的頁表虛擬化硬件支持。
NPT ————— Nested Page Table,AMD 的等價于 Intel EPT 的技術。
SR-IOV ——— Single Root I/O Virtualization。PCI-SIG 2007 年推出的 PCIe 虛擬化技術。
PF ————— Physical Function,亦即物理卡
VF ————— Virtual Function,亦即 SR-IOV 的虛擬 PCIe 設備
MMIO ——— Memory MApped I/O。設備上的寄存器或存儲,CPU 以內存讀寫指令來訪問。
CSR ———— Control & Status Register,設備上的用于控制、或反映狀態的寄存器。CSR 通常以 MMIO 的方式訪問。
UMD ———— User Mode Driver。GPU 的用戶態驅動程序,例如 CUDA 的 UMD 是 libcuda.so
KMD ———— Kernel Mode Driver。GPU 的 PCIe 驅動,例如英偉達 GPU 的 KMD 是 nvidia.ko
GVA ———— Guest Virtual Address,VM 中的 CPU 虛擬地址
GPA ———— Guest Physical Address,VM 中的物理地址
HPA ———— Host Physical Address,Host 看到的物理地址
IOVA ———— I/O Virtual Address,設備發出去的 DMA 地址
PCIe TLP —— PCIe Transaction Layer Packet
BDF ———— Bus/Device/Function,一個 PCIe/PCI 功能的 ID
MPT ———— Mediated Pass-Through,受控直通,一種設備虛擬化的實現方式
MDEV ——— Mediated Device,linux 中的 MPT 實現
PRM ———— Programming Reference Manual,硬件的編程手冊
MIG ———— Multi-Instance GPU,Ampere 架構高端 GPU 如 A100 支持的一種 hardware partition 方案
二、GPU 虛擬化的歷史和譜系
2.1 GPU 能做什么
GPU 天然適合向量計算。常用場景及 API:
此外還有加解密、哈希等場景,例如近些年來的挖礦。渲染是 GPU 誕生之初的應用: GPU 的 G 就是 Graphics —— 圖形。
桌面、服務器級別的 GPU,長期以來僅有三家廠商:
- 英偉達:GPU 的王者。主要研發力量在美國和印度。
- AMD/ATI:ATI 于 2006 年被 AMD 收購。渲染稍遜英偉達,計算的差距更大。
- Intel:長期只有集成顯卡,近年來開始推獨立顯卡。
2006 這一年,GPU 工業界發生了三件大事: ATI 被 AMD 收購;nVidia 黃仁勛提出了 CUDA 計算;Intel 宣布要研發獨立顯卡。
日光之下并無新事。如同經常發生的,這些事有成功有失敗: Intel 很快就放棄了它的獨立顯卡,直到 2018 才終于明白過來自己到底放棄了什么,開始決心生產獨立顯卡;AMD 整合 ATI 不太成功,整個公司差點被拖死,危急時公司股票跌到不足 2 美元;而當時不被看好的 CUDA,則在幾年后取得了不可思議的成功。
從 2012 年開始,人工智能領域的深度學習方法開始崛起,此時 CUDA 受到青睞,并很快統治了這個領域。
2.2 系統虛擬化和 OS 虛擬化
系統虛擬化演化之路,起初是和 GPU 的演化完全正交的:
- 1998 年,VMWare 公司成立,采用 Binary Translation 方式,實現了系統虛擬化。
- 2001 年,劍橋大學 Xen Source,提出了 PV 虛擬化(Para-Virtualization),亦即 Guest-Host 的主動協作來實現虛擬化。
- 2005 年,Intel 提出了 VT,最初實現是安騰 CPU 上的 VT-i (VT for Itanium),很快就有了 x86 上的 VT-x。
- 2007 年,Intel 提出了 VT-d (VT for Device),亦即 x86 上的 IOMMU。
- 2008 年,Intel 提出了 EPT,支持了內存虛擬化。
- 2010 年,Linux 中的 PV Hypervisor lguest 的作者,Rusty Russell(他更有名的作品是 iptables/netfilter),提出了 VirtIO,一種 Guest-Host 的 PV 設備虛擬化方案。
應該可以說,在 PV 時代和 Binary Translation 時代,虛擬化是危險的。只有當 VT 在硬件層面解決了 CPU 的隔離、保證了安全性之后,公有云才成為可能。VT-x 于 2005 ~ 2006 年出現,亞馬遜 AWS 于 2006 年就提出云計算,這是非常有遠見的。
系統的三個要素: CPU,內存,設備。CPU 虛擬化由 VT-x/SVM 解決,內存虛擬化由 EPT/NPT 解決,這些都是非常確定的。但設備虛擬化呢?它的情況要復雜的多,不管是 VirtIO,還是 VT-d,都不能徹底解決設備虛擬化的問題,這些我們稍后還會談到。
除了這種完整的系統虛擬化,還有一種也往往被稱作「虛擬化」的方式: 從 OS 級別,把一系列的 library 和 process 捆綁在一個環境中,但所有的環境共享同一個 OS Kernel。
嚴格來說,這種容器技術,和以 KVM 為代表的系統虛擬化,有著本質的區別。隨著容器的流行,「虛擬化」這個術語,也被用來指稱這種 OS 級別的容器技術。因此我們也從眾,把它也算作虛擬化的一種 —— 只不過為了區分,稱之為「OS 虛擬化」。
這種 OS 虛擬化最初于 2005 年,由 Sun 公司在 Solaris 10 上實現,名為「Solaris Zone」。Linux 在 2007 ~ 2008 開始跟進,接下來有了 LXC 容器等;到了 2013 年,Docker 橫空出世,徹底改變了軟件分發的生態,成為事實上的標準。
2.3 GPU 虛擬化的譜系
2.3.1 作為 PCIe 設備的 GPU
不考慮嵌入式平臺的話,那么,GPU 首先是一個 PCIe 設備。GPU 的虛擬化,還是要首先從 PCIe 設備虛擬化角度來考慮。
那么一個 PCIe 設備,有什么資源?有什么能力?
2 種資源:
- 配置空間
- MMIO
- (有的還有 PIO 和 Option ROM,此略)
2 種能力:
- 中斷能力
- DMA 能力
一個典型的 GPU 設備的工作流程是:
- 應用層調用 GPU 支持的某個 API,如 OpenGL 或 CUDA
- OpenGL 或 CUDA 庫,通過 UMD (User Mode Driver),提交 workload 到 KMD (Kernel Mode Driver)
- KMD 寫 CSR MMIO,把它提交給 GPU 硬件
- GPU 硬件開始工作... 完成后,DMA 到內存,發出中斷給 CPU
- CPU 找到中斷處理程序 —— KMD 此前向 OS Kernel 注冊過的 —— 調用它
- 中斷處理程序找到是哪個 workload 被執行完畢了,...最終驅動喚醒相關的應用
2.3.2 PCIe 直通
我們首先來到 GPU 虛擬化的最保守的實現: PCIe 設備直通。
如前述,一個 PCIe 設備擁有 2 種資源、2 種能力。你把這 2 種資源都(直接或間接地)交給 VM、針對這 2 種能力都把設備和 VM 接通,那么,VM 就能完整使用這個 PCIe 設備,就像在物理機上一樣。這種方案,我們稱之為 PCIe 直通(PCIe Pass-Through)。它只能 1:1,不支持 1:N。其實并不能算真正的虛擬化,也沒有超賣的可能性。
VM 中,使用的是原生的 GPU 驅動。它向 VM 內核分配內存,把 GPA 填入到 GPU 的 CSR 寄存器,GPU 用它作為 IOVA 來發起 DMA 訪問,VT-d 保證把 GPA 翻譯為正確的 HPA,從而 DMA 到達正確的物理內存。
PCIe 協議,在事務層(Transaction Layer),有多種 TLP,DMA 即是其中的一種: MRd/MWr。在這種 TLP 中,必須攜帶發起者的 Routing ID,而在 IOMMU 中,就根據這樣的 Routing ID,可以使用不同的 IOMMU 頁表進行翻譯。
很顯然,PCIe 直通只能支持 1:1 的場景,無法滿足 1:N 的需求。
2.3.3 SR-IOV
那么,業界對 1:N 的 PCIe 虛擬化是如何實現的呢?我們首先就會想到 SR-IOV。SR-IOV 是 PCI-SIG 在 2007 年推出的規范,目的就是 PCIe 設備的虛擬化。SR-IOV 的本質是什么?考慮我們說過的 2 種資源和 2 種能力,來看看一個 VF 有什么:
- 配置空間是虛擬的(特權資源)
- 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 應用的場景:
- 渲染(OpenGL、DirectX,etc.)
- 計算(CUDA,OpenCL)
- 媒體編解碼(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 的基本工作流程是:
- VM 中的 GPU 驅動,準備好一塊內存,保存的是渲染 workload
- VM 中的 GPU 驅動,把這塊內存的物理地址(GPA),寫入到 MMIO CSR 中
- Host/Hypervisor/驅動: 捕捉到這次的 MMIO CSR 寫操作,拿到了 GPA
- Host/Hypervisor/驅動: 把 GPA 轉換成 HPA,并 pin 住相應的內存頁
- Host/Hypervisor/驅動: 把 HPA(而不是 GPA),寫入到 pGPU 的真實的 MMIO CSR 中
- pGPU 工作,完成這個渲染 workload,并發送中斷給驅動
- 驅動找到該中斷對應哪個 workload —— 當初我是為哪個 vGPU 提交的這個 workload?—— 并注入一個虛擬的中斷到相應的 VM 中
- VM 中的 GPU 驅動,收到中斷,知道該 workload 已完成、結果在內存中
這就是 nVidia GRID vGPU、Intel GVT-g(KVMGT、XenGT)的基本實現思路。一般認為 graphics stack 是 OS 中最復雜的,加上虛擬化之后復雜度更是暴增,任何地方出現一個編程錯誤,調試起來都是無比痛苦。但只要穩定下來,這種 MPT 方案,就能兼顧 1:N 靈活性、高性能、渲染計算媒體的功能完整性...是不是很完美?
其實也不是。
該方案最大的缺陷,是必須有一個 pGPU 驅動,負責 vGPU 的模擬和調度工作。邏輯上它相當于一個實現在內核態的 device-model。而且,由于 GPU 硬件通常并不公開其 PRM,所以事實上就只有 GPU 廠商才有能力提供這樣的 Virtualization-Aware pGPU 驅動。使用了廠商提供的 MPT 方案,事實上就形成了對廠商的依賴。
2.3.6 SR-IOV: revisited
重新回到 GPU 的 SR-IOV。AMD 從 S7150 開始、英偉達從 Turing 架構開始,數據中心 GPU 都支持了 SR-IOV。但是 again,它不是 NIC 那樣的 SR-IOV,它需要 Host 上存在一個 vGPU 的 device-model,來模擬從 VM 來的 VF 訪問。
所以事實上,到目前為止,GPU 的 SR-IOV 僅僅是封裝了 PCIe TLP 層的 VF 路由標識、從而規避了 runtime 時的軟件 DMA 翻譯,除此之外,和基于 MDEV 的 MPT 方案并無本質的不同。
2.3.7 譜系表
在介紹完了上述的這些方案后,我們重新看下 CUDA 計算、OpenGL 渲染兩種場景的軟件棧,看看能發現什么:
CUDA 計算 stack:
OpenGL 渲染 Stack:
可以看出,從 API 庫開始,直到 GPU 硬件,Stack 中的每一個階段,都有被截獲、轉發的可能性。甚至,一概稱之為「API 轉發」是不合適的 —— 以 GRID vGPU、GVT-g 為例的 DEV 轉發,事實上就是 MPT,和任何 API 都沒有關系。
三、容器 GPU 虛擬化
首先,我們這里談到的,都是 nVidia 生產的 GPU、都只考慮 CUDA 計算場景。其次,這里的虛擬化指的是 OS 虛擬化的容器技術,不適用于 KATA 這樣的、基于系統虛擬化的安全容器。
3.1 CUDA 的生態
CUDA 開發者使用的,通常是 CUDA Runtime API,它是 high-level 的;而 CUDA Driver API 則是 low-level 的,它對程序和 GPU 硬件有更精細的控制。Runtime API 是對 Driver API 的封裝。
CUDA Driver 即是 UMD,它直接和 KMD 打交道。兩者都屬于 NVIDIA Driver package,它們之間的 ABI,是 NVIDIA Driver package 內部的,不對外公開。
英偉達軟件生態封閉:
- 無論是 nvidia.ko,還是 libcuda.so,還是 libcudart,都是被剝離了符號表的
- 大多數函數名是加密替換了的
- 其它的反調試、反逆向手段
以 nvidia.ko 為例,為了兼容不同版本的 Linux 內核 API,它提供了相當豐富的兼容層,于是也就開源了部分代碼:
其中這個 26M 大小的、被剝離了符號表的 nv-kernel.o_binary,就是 GPU 驅動的核心代碼,所有的 GPU 硬件細節都藏在其中。
3.2 vCUDA 和友商 cGPU
為了讓多個容器可以共享同一個 GPU,為了限定每個容器能使用的 GPU 份額,業界出現了不同的方案,典型的如 vCUDA 和 cGPU:
vCUDA 架構:
cGPU 架構:
兩者的實現策略不同,cGPU 比 vCUDA 更底層,從而實現了不侵入用戶環境。
3.3 GPU 池化簡介
從截獲的位置,看 GPU 池化的譜系:
以 CUDA API 轉發的池化方案、業界某產品為例,它到了 GPU 所在的后端機器上,由于一個 GPU 卡可能運行多個 GPU 任務,這些任務之間,依然需要有算力隔離。它為了實現這一點,在后端默認啟用了 nVidia MPS —— 也就是故障隔離最差的方案。這會導致什么?一個 VM 里的 CUDA 程序越界訪問了顯存,一堆風馬牛不相及的 VM 里的 CUDA 應用就會被殺死。
所以,很顯然,GPU 池化也必須以同時滿足故障隔離和算力隔離的方案作為基礎。
3.4 算力隔離的本質
從上述介紹中,我們可以看出:算力隔離、故障隔離都是 GPU 虛擬化、GPU 池化的關鍵,缺一不可。如果沒有算力隔離,不管虛擬化損耗有多低,都會導致其方案價值變低;而如果缺少實例間的故障隔離,則基本無法在生產環境使用了。
事實上,英偉達 GPU 提供了豐富的硬件特性,支持 Hardware Partition,支持 Time Sharing。
1. Hardware Partition,亦即: 空分
Ampere 架構的 A100 GPU 所支持的 MIG,即是一種 Hardware Partition。硬件資源隔離、故障隔離都是硬件實現的 —— 這是無可爭議的隔離性最好的方案。它的問題是不靈活: 只有高端 GPU 支持;只支持 CUDA 計算;A100 只支持 7 個 MIG 實例。
2. nVidia MPS
除了 MIG,算力隔離表現最優秀的,是 MPS —— 它通過將多個進程的 CUDA Context,合并到一個 CUDA Context 中,省去了 Context Switch 的開銷,也在 Context 內部實現了算力隔離。如前所述,MPS 的致命缺陷,是把許多進程的 CUDA Context 合并成一個,從而導致了額外的故障傳播。所以盡管它的算力隔離效果極好,但長期以來工業界使用不多,多租戶場景尤其如此。
3. Time Sharing,亦即: 時分
nVidia GPU 支持基于 Engine 的 Context Switch。不管是哪一代的 GPU,其 Engine 都是支持多任務調度的。一個 OS 中同時運行多個 CUDA 任務,這些任務就是在以 Time Sharing 的方式共享 GPU。
鑒于 MIG 的高成本和不靈活、MPS 故障隔離方面的致命缺陷,事實上就只剩下一種可能:Time Sharing。唯一的問題是,如何在原廠不支持的情況下,利用 Time Sharing 支持好算力隔離、以保證 QoS。這也是學術界、工業界面臨的最大難題。
3.4.1 GPU microarchitecture 和 chip
真正決定 GPU 硬件以何種方式工作的,是 chip 型號。不管是 GRID Driver 還是 Tesla Driver,要指揮 GPU 硬件工作,就要首先判斷 GPU 屬于哪種 chip,從而決定用什么樣的軟硬件接口來驅動它。
3.4.2 PFIFO: GPU Scheduling Internals
PFIFO 架構:
概念解釋:
PFIFO
GPU 的調度硬件,整體上叫 PFIFO。
Engine
執行某種類型的 GPU 硬件單元。常見 Engine 有:
- PGRAPH —— CUDA/Graphics
- PCOPY ——— Copy Engine
- PVENC ——— Video Encoding
- PVDEC ——— Video Decoding
- ...
最重要的就是 PGRAPH Engine,它是 CUDA 和渲染的硬件執行單元。
Channel
GPU 暴露給軟件的,對 Engine 的抽象。一個 app 可以對應一或多個 channels,執行時由 GPU 硬件把一個一個的 channel,放在一個一個的 engine 上執行。
channel 是軟件層的讓 GPU 去執行的最小調度單位。
TSG
Timeslice Group。
由一或多個 channel(s)組成。一個 TSG 共享一個 context,且作為一個調度單位被 GPU 執行。
runlist
GPU 調度的最大單位。調度時,GPU 通常是從當前 runlist 的頭部摘取 TSG 或 channel 來運行。因此,切換 runlist 也意味著切換 active TSG/channel。
PBDMA
pushbuffer DMA。GPU 上的硬件,用于從 Memory 中獲取 pushbuffer。
Host
GPU 上和 SYSMEM 打交道的部分(通過 PCIe 系統)。PBDMA 是 Host 的一部分。注意,Host 是 Engine 和 SYSMEM 之間的唯一橋梁。
Instance Block
每個 Channel 對應一個 Instance Block,它包含各個 Engine 的狀態,用于 Context Switch 時的 Save/Restore;包含 GMMU pagetable;包含 RAMFC —— 其中包括 UMD 控制的 USERD。
3.4.3 runlist/TSG/channel 的關系
- Tesla 驅動為每個 GPU,維護一或多個 runlist,runlist 或位于 GPU 顯存,或位于系統內存
- runlist 中有很多的 entry,每個 entry 是一個 TSG 或一個 channel
- 一個 TSG 是 multi-channel 或 single-channel 的
- 一個 channel 必定隸屬于某個 TSG
- 硬件執行 TSG 或 channel,當遇到以下情景之一時,進行 Context Switch:
- 執行完畢
- timeslice 到了
- 發生了 preemption
3.4.4 pending channel notification
pending channel notification 是 USERD 提供的機制。UMD 可以利用它通知 GPU:某個 channel 有了新的任務了【1】。這樣,GPU 硬件在當前 channel 被切換后(執行完畢、或 timeslice 到了),就會執行相應的 channel。
注釋
【1】 不同 chip,實現有所不同。
3.4.5 從硬件調度看 GRID vGPU
GRID vGPU 支持 3 種 scheduler:
1. Best Effort: 所有 vGPU 的任務隨意提交,GPU 盡力執行
現象: 如果啟動了 N 個 vGPU,它們的負載足夠高,那么結果就是均分算力。
原理: 所有的 vGPU 使用同一個 runlist。runlist 內,還是按照 channel 為粒度進行調度。如同在 native 機器上運行多個 CUDA 任務一樣。
2. Equal Share: 所有在用的 vGPU 嚴格擁有同樣的 GPU 配額
現象: 如果啟動了 N 個 vGPU,它們嚴格擁有相同的算力,不管是否需要這么多。
原理: 為每個 vGPU 維護一個 runlist。當它的 timeslice 過了,GRID Host Driver 會寫 GPU 寄存器,觸發當前 runlist 被搶占、下一個 runlist 被調度。
3. Fixed Share: 每個 vGPU 有自己固定的 GPU 配額
現象: 每個 vGPU 嚴格按照創建時的規格來分配算力。
原理: Ditto.
3.5 騰訊云 qGPU 簡介
qGPU == QoS GPU。它是目前業界唯一真正實現了故障隔離、顯存隔離、算力隔離、且不入侵生態的容器 GPU 共享的技術。
3.5.1 qGPU 基本架構
qGPU 基本架構:
3.5.2 qGPU QoS 效果
注釋
【1】 測試數據來自 T4(chip: TU104)。其它 chip 上,正確性、功能性和性能都待驗證,雖然原理上是相通的。
【2】兩個 PoD 的算力配比為 2:1。橫坐標為 batch 值,縱坐標為運行時兩個 PoD 的實際算力比例。可以看到,batch 較小時,負載較小,無法反映算力配比;隨著 batch 增大,qGPU 和 MPS 都趨近理論值 2,vCUDA 也偏離不遠,但缺乏算力隔離的業界某產品則逐漸趨近 1。
四、GPU 虛擬化: 未來展望
2021 以來,GPU 工業界發生了一些變化,e.g.:
1. 英偉達 GPU 的 QoS 突破
英偉達在 CUDA 計算領域占據壓倒性的優勢,但 QoS 表現不盡如人意。
長期以來,學術界和工業界付出了大量的努力,嘗試在英偉達不支持 QoS 的前提下,實現某種程度的算力隔離。遺憾的是,這些努力,要么集中在 CUDA API 層,能夠做到一定的算力隔離,但同樣會帶來副作用;要么嘗試在 low-level 層面突破 —— 但不幸全都失敗了。
qGPU 是十幾年來在英偉達 GPU 上實現 QoS 的最大突破。基于它:
- 騰訊云 TKE 的多容器共享 GPU,將無懸念地領先整個工業界
- 在線推理 + 離線訓練的混布,成為可能
- GPU 池化的后端實現,不管采用哪種方案,都有了堅實的基礎
- Linux/Android 場景的渲染虛擬化,也有了堅實的基礎
2. Vulkan Spec 支持了 video encode/decode
很可能,編解碼 API 不統一的亂象即將終結,這對 API 轉發方案有很大的意義。不遠的將來,或許某種 API 方案的 vGPU 會成為主流。google 在社區的一些活動標明,很可能它就有這樣的計劃。
五、參考資料和項目簡介
1. nVidia MPS
官方。部分文檔公開。
2. nouveau driver in Linux Kernel
開源社區版的英偉達 GPU 驅動,基于 DRM,硬件細節基本靠逆向工程。不支持 CUDA、只支持 OpenGL 渲染。代碼龐大,包含很多有用信息。
3. envytools 及其 nVidia Hardware Documentation
nouveau 的配套項目。除了提供各種 profiling GPU 硬件細節的工具,還維護了一個文檔倉庫,記錄所有已經被成功逆向了的信息。
4. GDEV project, an opensource implementation of CUDA
基于 nouveau 實現了 CUDA driver 和 CUDA runtime,代碼較舊,已不維護。大神級作品。
5. libcudest, a partially RE-ed CUDA driver
英偉達實習生實現的 CUDA Driver 逆向工程。只逆向了一小部分 UMD 和 KMD 之間的接口。已不維護。
6. vCUDA
開源項目。
7. nVidia official: nvidia-uvm driver for Tesla
官方,開源。Telsa Driver 配套的 UVM 驅動,代碼開源。和 Tesla Driver 有很多 low-level 交互,可以從中窺見很多 GPU 硬件細節。
8. Tesla Driver
官方。細節全藏在 nv-kernel.o_binary 文件中。
9. GRID vGPU
官方。細節也是全在 nv-kernel.o_binary 文件中。與 Tesla Driver 不同的是,它為 vGPU 的 Fixed Share 和 Equal Share 兩種調度策略,實現了 per-vGPU runlist。因此有很高的參考價值。
六、思考 & 致謝
"Lasciate ogne speranza, voi ch'intrate." -- Dante Alighieri
"Καιρ?ν γν?θι." -- Πιττακ?ς ο Μυτιληνα?ος
使用 nVidia GPU 進行計算,有兩種場景:1) 推理業務,往往是在線業務;2) 訓練業務,往往是離線業務。這兩種業務之間,很難混布到同一個 GPU 上。甚至兩種在線推理業務之間,也很難進行這樣的混布。因為沒有 QoS 隔離,你不知道哪一個業務會流量突發,影響另一個業務。所以,長期以來,關鍵的在線業務,GPU 利用率都不高,據我們了解,大多在 50%以下,甚至個別 BG 的推理業務只能到~ 20%。即使 GPU 很昂貴,即使一個業務占不滿 GPU,也只能如此。
我們很自然要問:是 nVidia 做不好 QoS 嗎?顯然不是。MPS 也好,GRID vGPU 也好,其 QoS 表現都很優秀。但是,為什么 MPS 會畫蛇添足地引入 CUDA Context Merging 呢?真的是因為這樣會帶來些許性能上的收益嗎?我是持懷疑態度的。在我看來,更可信的解釋是,英偉達公司在擁有市場支配地位的情況下,并不希望提升 GPU 利用率。卓越的硬件加上封閉的軟件生態,當然能帶來豐厚的利潤。
學術界、工業界在 CUDA 算力隔離上的努力,這里不再一一列舉【1】。這其中既有 GDEV 這樣的以一人之力做出的大神級作品,也有毫無營養的灌水式 paper。有意思的是,幾乎所有的努力都在上層,很少人有勇氣下潛到 GPU 硬件的細節中。我們下潛了,也很幸運地成功了。
- 感謝騰訊云虛擬化團隊的各位同事,一起加班到深夜,分析搜羅到的各種靠譜和不靠譜的項目和 paper,腦補各種可能的軟硬件細節,討論技術上的各種可能性;
- 感謝騰訊云 TKE 團隊的各位同事,協調客戶收集需求、協同產品化開發;
- 感謝 WXG 的同事,和我們一起梳理 GPU 利用率的痛點;
- 感謝友商的同類產品,它的 idea 無疑是優秀的;
注釋
【1】 部分列表可參考閻姝含的文章: 針對深度學習的 GPU 共享