適用於Linux 2的Windows子系統上的CUDA
Announcing CUDA on Windows Subsystem for Linux 2
為了響應大眾的需求,微軟在2020年5月的構建會議上宣布了WindowsSubsystem for Linux2(WSL2)的一個新特性——GPU加速。這一特性為許多計算應用程序、專業工具和工作負載打開了大門,目前只有Linux才有,但現在可以在Windows上按原樣運行,並從GPU加速中獲益。
最重要的是,NVIDIA CUDA加速度現在來到了WSL。在這篇文章中,將討論在WSL 2的公共預覽中對CUDA的期望。
What is WSL?
WSL是Windows 10的一個特性,使能夠直接在Windows上運行本機Linux命令行工具,而不需要復雜的雙引導環境。在內部,WSL是一個與Microsoft Windows操作系統緊密集成的容器化環境。這使得可以在傳統的Windows桌面和現代商店應用程序的同時運行Linux應用程序。
WSL主要是開發人員的工具。如果正在Linux容器中處理計算工作負載,則可以使用熟悉的本地Linux工具在Windows PC上本地開發和測試工作負載。通常,這些應用程序需要大量的黑客、第三方框架和庫才能在Windows系統上運行。所有這些都隨WSL 2而改變,WSL 2為Windows世界帶來了完整的Linux內核支持。
借助WSL 2和GPU半虛擬化(GPU-PV)技術,微軟正在為Windows上的Linux支持添加另一個功能,允許運行針對GPU硬件的計算工作負載。在本文后面,將更詳細地介紹WSL 2以及GPU是如何添加到其中的。
有關更多信息,請參見DirectX進入Windows Linux子系統和GitHub中的WSL2 Linux Kernel/driver/gpu目錄。
CUDA in WSL
要利用WSL 2中的GPU,目標系統必須安裝支持Microsoft WDDM模型的GPU驅動程序。這些驅動程序由NVIDIA等GPU硬件供應商提供。
CUDA允許編程NVIDIA GPU。幾十年來,在Windows圖形中的WDDM模型中得到了支持。新的Microsoft WSL 2容器提供了GPU加速,CUDA可以利用在WSL內部運行CUDA工作負載。有關更多信息,請參閱《關於WSL的CUDA用戶指南》。
在WSL中對CUDA的支持包含在針對WDDM 2.9模型的NVIDIA顯示驅動程序中。只需要在Windows主機上安裝驅動程序。WSL中的CUDA用戶模式驅動程序(利布達)自動映射到容器內並添加到該容器的加載程序搜索路徑中。
NVIDIA驅動程序開發團隊為CUDA驅動程序添加了對WDDM模型和GPU-PV的支持,以便能夠在Windows上的Linux上運行。仍然是一個預覽驅動程序,在Windows 10中WSL的官方GPU支持發布之前不會發布。有關該版本的更多信息,請參閱CUDA WSL 2下載。
圖2顯示了如何將CUDA驅動程序插入Linux客戶機中的新WDDM模型的簡單圖。
Figure 1. Stack image showing layers involved while running Linux AI frameworks in WSL 2 containers.
Figure 2. A diagram of the WDDM model supporting CUDA user mode driver running inside Linux guest.
如果是從Microsoft Windows Insider程序的Fast Ring(build 20149或更高版本)在最新的Windows版本上安裝了WSL發行版並將容器設置為以WSL 2模式運行的開發人員,並且如果是PC中NVIDIA GPU的受啟發所有者,則可以嘗試該驅動程序並在WSL 2中運行工作負載。只需在Windows主機操作系統上安裝驅動程序,然后打開WSL容器。CUDA將在那里與CUDA應用程序一起工作,而不需要任何額外的努力。圖3顯示了在WSL 2容器中運行CUDA TensorFlow工作負載的屏幕截圖。
WSL中的GPU為當前僅在本機Linux環境中運行的各種CUDA計算應用程序打開了大門。
英偉達仍在積極地進行這一項目,並作出調整。除此之外,正在努力將以前特定於Linux的api引入WDDM層,以便越來越多的應用程序可以開箱即用地處理WSL。
另一個焦點是表現。如前所述,WSL 2 GPU支持極大地利用了GPU-PV,可以影響較小的GPU工作負載,而無需任何流水線。現在,正在盡可能減少這些開銷。
NVML
NVML不包含在初始驅動程序包中,對此存在一些問題。為了解決這個問題,計划將NVML和其庫一起引入WSL。
首先啟動了核心CUDA驅動程序,讓可以在這個早期預覽中嘗試大部分現有的工作負載。意識到一些容器和應用程序甚至在加載CUDA之前就利用NVML查詢GPU信息。這就是為什么把NVML放在WSL的首要任務中。請繼續關注此主題的更多更新。
GPU containers in WSL
除了DirectX和CUDA支持之外,NVIDIA還在WSL 2中添加了對NVIDIA容器工具包(以前是NVIDIA-docker2)的支持。數據科學家准備在Linux本地硬件下運行或在雲中執行的容器化GPU工作負載,現在可以在Windows PC上的WSL2中運行。
不需要特定的WSL包。NVIDIA運行時庫(libnvidia容器)可以動態檢測libdxcore,並在具有GPU加速的WSL 2環境中運行時使用。這是在Docker和NVIDIA容器工具包包安裝之后自動發生的,就像在Linux上一樣,允許GPU加速的容器以開箱即用的方式運行。
建議使用Docker工具的最新版本(19.03或更高版本),以利用對--gpus選項的額外支持。要啟用WSL 2支持,請按照針對Linux發行版的GitHub repo上的自述步驟進行操作,並安裝可用的最新版本。
那么是如何工作的呢?所有特定於WSL 2的工作都由libnvidia容器庫處理。這個庫現在能夠在運行時檢測libdxcore.so文件並用來檢測所有暴露在這個接口上的gpu。
如果需要在容器中使用這些gpu,則使用以下命令查詢驅動程序存儲的位置:包含Windows主機和WSL 2的所有驅動程序庫的文件夾libdxcore.so文件. 這取決於libnvidia-container設置容器以便正確映射驅動程序存儲,並為WSL 2 GPU支持的核心庫進行設置,如圖4所示。
Figure 4. Discovery and mapping scheme used by libnvidia-container.so on WSL 2.
而且,這與WSL之外使用的邏輯不同。這完全是由libnvidia-container.so抽象出來的-對最終用戶來說應該盡可能透明。此早期版本的一個限制是在多GPU環境中缺少GPU選擇:容器中始終可見所有GPU。
以下是可以在WSL容器中運行的內容:目前熟悉的任何NVIDIA Linux容器。NVIDIA支持專業人士使用的大多數現有Linux工具和工作流。從NVIDIA NGC下載最喜歡的容器工作負載並進行嘗試。
在下一節中,將描述如何在WSL 2中運行TensorFlow和n-body容器,同時使用NVIDIA GPUs加速工作負載。
Running the N-body container
使用Docker安裝腳本安裝Docker:
user@PCName:/mnt/c$ curl https://get.docker.com | sh
安裝NVIDIA容器工具包。從nvidia-docker2 v2.3和底層運行庫libnvidia container 1.2.0-rc.1開始,就提供了WSL 2支持。
建立穩定的實驗庫和GPG密鑰。支持WSL 2的運行時更改在實驗存儲庫中可用。
user@PCName:/mnt/c$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
user@PCName:/mnt/c$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
user@PCName:/mnt/c$ curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
user@PCName:/mnt/c$ curl -s -L https://nvidia.github.io/libnvidia-container/experimental/$distribution/libnvidia-container-experimental.list | sudo tee /etc/apt/sources.list.d/libnvidia-container-experimental.list
安裝NVIDIA運行時包及其依賴項:
user@PCName:/mnt/c$ sudo apt-get update
user@PCName:/mnt/c$ sudo apt-get install -y nvidia-docker2
打開WSL容器並在那里啟動Docker守護進程。應該看到dockerd服務輸出。
user@PCName:/mnt/c$ sudo dockerd
physical GPU (device: 0, name: GeForce GTX 1070, pci bus id: 0000:01:00.0, compute capability: 6.1)" src="file:///C:/Users/JIANMI~1.HAS/AppData/Local/Temp/msohtmlclip1/01/clip_image010.gif" border="0" v:shapes="圖片_x0020_13">
Figure 5. Starting the Docker daemon.
在另一個WSL容器窗口中,下載並啟動N-body仿真容器。確保用戶有足夠的權限下載容器。可能需要在sudo中運行以下命令。GPU在輸出中突出顯示。
user@PCName:/mnt/c$ docker run --gpus all nvcr.io/nvidia/k8s/cuda-sample:nbody nbody -gpu -benchmark
Figure 6. Starting the N-body simulation container.
Running the TensorFlow container
嘗試另一個流行的容器:WSL 2中Docker中的TensorFlow。
下載TensorFlow Docker圖像。為了避免Docker連接問題,該命令在sudo中運行。
user@PCName:/mnt/c$ docker pull tensorflow/tensorflow:latest-gpu-py3
保存稍微修改過–使用主機驅動器C上TensorFlow教程中的GPU,默認情況下,該驅動器在WSL2容器中映射為/mnt/C。
user@PCName:/mnt/c$ vi ./matmul.py
import sys
import numpy as np
import tensorflow as tf
from datetime import datetime
device_name = sys.argv[1] # Choose device from cmd line. Options: gpu or cpu
shape = (int(sys.argv[2]), int(sys.argv[2]))
if device_name == "gpu":
device_name = "/gpu:0"
else:
device_name = "/cpu:0"
tf.compat.v1.disable_eager_execution()
with tf.device(device_name):
random_matrix = tf.random.uniform(shape=shape, minval=0, maxval=1)
dot_operation = tf.matmul(random_matrix, tf.transpose(random_matrix))
sum_operation = tf.reduce_sum(dot_operation)
startTime = datetime.now()
with tf.compat.v1.Session(config=tf.compat.v1.ConfigProto(log_device_placement=True)) as session:
result = session.run(sum_operation)
print(result)
# Print the results
print("Shape:", shape, "Device:", device_name)
print("Time taken:", datetime.now() - startTime)
在GPU和CPU上運行此腳本的結果如下所示,該腳本是從安裝的驅動器C啟動的。為了簡單起見,減少了輸出。
user@PCName:/mnt/c$ docker run --runtime=nvidia --rm -ti -v "${PWD}:/mnt/c" tensorflow/tensorflow:latest-gpu-jupyter python /mnt/c/matmul.py gpu 20000
Figure 7. Running the matmul.py script.
當在WSL 2容器中使用GPU進行先前的計算場景時,會有顯著的加速。
下面是另一個演示,看看GPU加速的工作:Jupyter筆記本教程。當容器啟動時,應該會看到打印到筆記本服務器的鏈接。
user@PCName:/mnt/c$ docker run -it --gpus all -p 8888:8888 tensorflow/tensorflow:latest-gpu-py3-jupyter
Figure 8. Launching the Jupyter notebook.
現在應該可以在Jupyter筆記本上運行演示示例了。連接到筆記本時,請小心使用Microsoft Edge瀏覽器中的localhost,而不是127.0.0.1。
導航到tensorflow教程並運行分類.ipynb筆記本。
要查看Windows PC的GPU加速的工作,請導航到“單元格”菜單,選擇“全部運行”,然后檢查Jupyter筆記本的WSL 2容器中的日志。
physical GPU (device: 0, name: GeForce GTX 1070, pci bus id: 0000:01:00.0, compute capability: 6.1)" src="file:///C:/Users/JIANMI~1.HAS/AppData/Local/Temp/msohtmlclip1/01/clip_image018.gif" border="0" v:shapes="圖片_x0020_27">
Figure 9. The Jupyter notebook log.
這個演示和這個容器中的其一些演示突出了小提交的虛擬化層當前的開銷問題,前面也提到過。與這些玩具模型相關聯的提交會導致GPU運行時比同步開銷本身要短。在WSL 2上的這些極小型模型案例中,CPU時間可能比GPU時間更好。目前正在對其進行優化,並應僅限於較小的非流水線工作負載。
WSL overview
為了了解GPU是如何添加到WSL 2的,現在討論Windows上的Linux是什么以及硬件是如何暴露給容器的。
微軟在2016年的構建會議上引入了WSL。很快獲得了發展勢頭,並成為Linux開發人員中的一個流行工具,希望在運行Linux開發工具和目標工作負載的同時運行Office等Windows應用程序。
WSL 1允許運行未修改的Linux二進制文件。但是,仍然使用Linux內核仿真層,是作為NT內核內的子系統實現的。該子系統通過將來自Linux應用程序的調用轉發到相應的Windows 10功能來處理這些調用。
WSL 1是一個很有用的工具,但並不兼容所有的Linux應用程序,因為需要模擬可能每個Linux系統調用。一般來說,文件系統的訪問也很慢,這導致了一些實際應用程序無法接受的性能。
考慮到這一點,微軟決定走另一條路,推出了WSL 2,一個新版本的WSL。WSL 2容器在虛擬化環境中運行完整的Linux發行版,同時仍然充分利用Windows 10新容器系統的優點。 雖然使用Windows 10的Hyper-V服務,WSL 2仍然不是一個傳統的VM,而是一個輕量級的實用VM。該實用程序管理虛擬地址備份內存,允許wsl2容器從主機Windows系統動態分配內存。
WSL 2的一些主要目標是提高文件系統性能並支持完全的系統調用兼容性。還具有更好的整體Windows主機系統集成。允許從Windows shell到運行在容器內的Linux系統的快捷方式,以及對自動裝載到容器文件系統的選定目錄的主機文件系統的訪問。
WSL2作為WindowsInsider程序的預覽功能啟用,並作為最新的Windows10更新版本2004發布。
在最新的Windows版本中,WSL 2容器有了更多的改進,從網絡堆棧到底層存儲VHD。描述所有細節將超出本文的范圍。有關WSL 2容器的一些有趣和令人興奮的新特性的更多信息,請參閱比較wsl2和WSL 1。
WSL 2 Linux kernel
WSL 2中的Linux內核是由微軟基於kernel.org網站. 這個內核專門針對WSL 2進行了調整,針對大小和性能進行了優化,以在Windows上提供Linux體驗。內核由Windows Update提供服務,這意味着無需自己管理即可獲得最新的安全修復和內核改進。
微軟在WSL中支持幾個Linux發行版。遵循開放源代碼社區的規則,WSL2內核源代碼是公共的,可以在WSL2 Linux內核GitHub repo上使用,其中包含允許系統與Windows 10主機集成所需的修改。
GPU in WSL
微軟開發人員正在通過GPU-PV技術將真正的GPU硬件支持引入WSL 2容器,在那里OS圖形內核(dxgkrnl)將運行在guest VM內的用戶模式組件調用封送到主機上的內核模式驅動程序。
在獨立硬件供應商(IHV)的幫助下,微軟開發了這項技術,作為其WDDM圖形驅動程序模型的一項功能。NVIDIA圖形驅動程序自Windows操作系統的Windows Insider程序中的功能預覽早期起就支持GPU-PV。所有當前支持的NVIDIA gpu都可以暴露給運行在Hyper-V VM guest中的Windows操作系統。
對於WSL 2能夠利用GPU-PV的能力,微軟必須在Linux客戶機中實現其圖形框架的基礎:使用GPU-PV協議的WDM模型。新的微軟驅動程序支持Linux上的WDDM模型dxgkrnl。還可以作為WSL2 Linux內核GitHub repo中的源代碼項目使用。
dxgkrnl驅動程序有望為WDDM 2.9版本的wsl2容器帶來對GPU加速的支持。微軟解釋說,dxgkrnl是一個基於GPU-PV協議的Linux GPU驅動程序,與同名的Windows驅動程序沒有任何共同之處。
目前,可以下載預覽版的NVIDIA WDDM 2.9驅動程序。在接下來的幾個月里,NVIDIA WDDM 2.9驅動程序將從Windows Update的WIP版本中分發,這使得手動下載和安裝驅動程序變得不必要。
GPU-PV in a nutshell
dxgkrnl驅動程序在Linux guest中將新的/dev/dxg設備公開給用戶模式。D3DKMT內核服務層已經在Windows上提供,也作為dxcore庫的一部分被移植到Linux上。使用一組私有IOCTL調用與dxgkrnl通信。
來賓Linux版本的dxgkrnl使用多個虛擬機總線通道連接到Windows主機上的dxg內核。主機上的dxg內核對待Linux進程提交的方式與運行在WDDM模型中的本地Windows應用程序提交進程的方式相同。將發送到KMD(一個特定於IHV的內核模式驅動程序),KMD准備並將提交給硬件GPU。圖10顯示了這種通信信道的簡化圖。
Figure 10. A simplified diagram showing Windows host components backing the new graphics dxg device in Linux guest.
NVIDIA驅動程序在許多版本中都支持Windows 10 GPU-PV和Windows來賓。NVIDIA GPU可用於在所有使用Microsoft虛擬化層的最終用戶Windows 10應用程序中加速計算和圖形,並使用GPU-PV功能添加vGPU:
11顯示了在NVIDIA GeForce GTX 1070 GPU上的Windows沙盒容器中運行示例DirectX應用程序的示例。
Figure 11. Windows Sandbox container gets GPU acceleration on an NVIDIA GeForce GTX 1070 GPU.
User mode support
為了在WSL中啟用圖形,Windows圖形團隊還將一個用戶模式組件移植到Linux:dxcore。
dxcore庫提供了一個API函數,用於枚舉系統中符合WDDM的圖形適配器。旨在作為Windows和Linux中DXGI適配器枚舉的跨平台、低級替代品。還使用D3DKMT層API抽象了對dxgkrnl服務(Linux上的IOCTLs和Windows上的GDI調用)的訪問,CUDA和其依賴WSL中WDDM模型支持的用戶模式組件使用該API。
據微軟稱,dxcore(libdxcore.so文件)庫將在Windows和Linux上都可用。NVIDIA計划在驅動程序中添加對DirectX 12和cudapi的支持,目標是WDDM 2.9模型的新WSL特性。兩個API庫都將鏈接到dxcore,以便可以指示dxg內核將請求封送到主機上的KMD。
Try it today
如果想使用Windows PC在Linux環境中進行真正的ML和AI開發,WSL中對CUDA的支持將為帶來一個令人興奮的機會。WSL是Docker CUDA容器被證明是數據科學家中最流行的計算環境之一。
加入Microsoft Windows Insider程序以訪問啟用GPU加速的WSL 2預覽。
下載最新的NVIDIA驅動程序,安裝,並嘗試在WSL 2中運行CUDA容器化工作負載。