WSL 簡介
WSL 全名為 Windows subsystem Linux,是微軟 Hyper-V 虛擬機器裏的一個輕量級子系統,可以在 Windows 裏跑 Linux 系統,而且支援 GPU-PV。GPU-PV 稱為顯卡虛擬化,是在 Linux 虛擬機上存取 Windows 宿主機硬体 GPU 的一種技術。這對沒有多餘機器安裝實体 Linux 的人而言,是蠻不錯的選擇。
WSL 僅支援 Windows 10/Windows 11 的 Professional(專業版) 及 EnterPrise(企業版),若是Home(家用版),則無法使用。
安裝 WSL
以系統管理員身份啟動 Dos 視窗命令提示 ,執行如下指令安裝 wsl 系統
wsl --install
上面的指令除了安裝 wsl 子系統外,重新開機後,還會自動安裝 ubuntu 最新的版本。安裝 ubuntu 時需一段時間,請耐心請待。
安裝ubuntu 時,若出現 WslRegisterDistribution failed with error: 0x80370102 錯誤,請參考本篇最下面的核心隔離,然後重新開機,再執行如下指令
wsl --install -d ubuntu
GPU-PV
WSL2 支援 GPU-PV (顯卡虛擬化),所以 WSL2 一裝好,除了 ubuntu 一併裝進去,dxgkrnl 驅動程式也會自動裝好,馬上可以使用 “nvidia-smi” 這個指令測試。
nvidia-smi Fri Apr 19 14:48:15 2024 +-------------------------------------------------------------------------------------+ | NVIDIA-SMI 550.76.01 Driver Version: 552.22 CUDA Version: 12.4 | |-------------------------------------+------------------------+----------------------+ | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=====================================+========================+======================| | 0 NVIDIA GeForce RTX 3080 Ti On | 00000000:01:00.0 On | N/A | | 53% 43C P8 60W / 400W | 1758MiB / 12288MiB | 13% Default | | | | N/A | +-------------------------------------+------------------------+----------------------+ +-------------------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=====================================================================================| | No running processes found | +-------------------------------------------------------------------------------------+
有看到上面的訊息,表示GPU-PV 驅動程式已經安裝完成。
與 VMware相衝
wsl 一打開,市面上常用的 vmware, viturebox 馬上失效,這是因為 “Windows 子系統 Linux 版” 及 “虛擬機器平台” 被打開了,造成 VMware 的 Vituralize Intel VT-x/EPT 無法啟用。請由 “開始/Windows 系統/控制台/程式集/開啟或關閉 Windows 功能” 進入查看。
Vituralize Intel VT-x/EPT 加速虛擬機的技術,若要重新啟用 VMware的 Vituralize Intel VT-x/EPT,請將如下紅線框起來的功能全部都取消。
當然上面的功能關掉,WSL 就無法用。所以如果想要 VMware 與 WSL 共存並用,可以考慮將 VMware的 Virtualize Intel VT-X/EPT 取消,這樣VMware 就又可以執行了,只是速度可能會比較慢。
啟動 Ubuntu
開啟 Dos 視窗,輸入如下指令即可
wsl -d ubuntu
移除 Ubuntu
移除 ubuntu 請執行如下指令。
wsl --unregister ubuntu
手動安裝 Ubuntu
如果要重新安裝或手動安裝其它 ubuntu,進入 Dos 視窗輸入
wsl --install -d ubuntu
移除 WSL
要移除 WSL 請先確認如下步驟
wsl --unregister ubuntu
wsl --shutdown
wsl --uninstall
控制台關掉 windows 子系統 Linux
重新開機
預設安裝路徑
WSL 預設安裝在 C 碟如下目錄
C:\Users\mahal\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu_79rhkp1fndgsc\LocalState
搬移安裝位置
通常我們不會把 utuntu 安裝在 C 碟,所以要作搬移的動作,請依續執行如下指令
wsl --shutdown wsl --export Ubuntu d:\ubuntu.tar wsl --unregister Ubuntu d: mkdir wsl wsl --import Ubuntu d:\wsl d:\ubuntu.tar del d:\ubuntu.tar
搬移後打開 wsl 進入 ubuntu,卻發現登入的帳號是 root。
請在 開始 按右鍵,執行 regedit,依序進入如下位置
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss\{xxxxxx}
然後將 DefaultUid 改成十進位的 1000,最後重新執行 wsl 即會用一般使用者登入。
ubuntu 初始設定
一開始要初始的設定如下
sudo apt-get update sudo apt-get upgrade sudo apt-get install net-tools network-manager ubuntu-drivers-common
sudo apt-get install nvidia-cuda-toolkit
核心隔離
WSL2 有時會出現 WslRegisterDistribution failed with error: 0x80370102 錯誤,網路常教大家切換到 WSL1 即可,但這樣就無法支援 GPU-PV,唯一的方法就是重新安裝 Windows,這應該是微軟的嚴重bug。
若緊急狀況不能重新安裝 Windows ,可以將核心隔離暫時開啟,就可以跑 wsl2 了,但核心隔離一但開啟,整台電腦的效能就會降低很多,由其是 “雷電” 或 “BlueStacks” 等 Android 模擬器更為嚴重,而且 VMware 及 VirtualBox 就無法執行了。所以想要執行其它虛擬器,核心隔離就要再度手動關閉,然後重心開機。
開啟核心隔離的方法,請由 Windows 安全性/裝置安全性/核心隔離/記憶体完整性將之打開,如下圖所示
Hyper-V 虛擬機
使用 Hyper-V 當虛擬機的原因是它可以啟用硬体 GPU。
雖說 VMware 也可以啟動硬体 GPU,但必需加裝 vSphere 套件。Sphere[sfɪr] 是球型、領域的意思,vSphere 可以翻譯成虛擬領域。 VMware 在 2024年2月取消 vSphere 的免費版本,造成全球的經銷商大出走,不想再替 VMware 出售它們的軟体。
另外 Hyper-V 使用系統服務可於開機時自動啟動,不像 VMware 還要自已撰寫服務程式,所以 Hyper-V 看起來方便許多。
那為什麼不直接使用 WSL 呢! WSL 雖說啟動快,但只能使用 NAT,無法取得跟宿主機同網域的 IP,所以不能架設網站,它只是工程師暫時取代實機 Linux 的一個小工具而以。
另有件要注意的事項,市面常見的 Android 模擬器,比如 BlueStack, 雷電等,為了加速效能,會自動把 Windows 的 Hyper-V 及虛擬機器平台關掉,所以為了能正常執行虛擬機,請把 Andorid 模擬器全都移除乾淨,不要再浪費時間在線上遊戲了。
安裝 Hyper-V
開始/Windows 系統/控制台/程式集/開啟或關閉 Windows 功能,將 Hyper-V 勾選,然後重新開機。
然後開啟 “開始/Windows 系統管理工具/Hyper-V 管理員“,連線到伺服器,選擇本機電腦。
建立虛擬交換器
虛擬交換器是為了得到一個能產生 bridge (橋接器) 的虛擬網卡。請選取虛擬交換器管理員,選外部,再按下建立虛擬交換器,名稱填入 HV_Bridge
此時打開網卡設定視窗,多了 vEthernet(Default Switch) 及 vEthernet(HV_Bridge) 二張虛擬網卡
建立虛擬機
按下新增/虛擬機器,虛擬機名稱輸入 “Ubuntu“,勾選將虛擬機儲存在不同位置,然後選其它磁碟機。
接下來的畫面,因Ubuntu 映像檔無法用 UFEI 開機,所以要選第1代。
再來設定啟動記憶体,因為本人的宿主機有64G,所以就設定為 16384MB,然後很重要的一點,就是 為此虛擬機器使動態記憶体 要取消,不然硬体 GPU 無法啟動。
接下來的連線選 “HV_Bridge”,建立虛擬硬碟的大小設定為 1024 GB,安裝作業系統選映像檔,然後選取 ubuntu 的 iso 檔。
上述設定完成後,還沒開始安裝。先在 Ubuntu 按右鍵/設定,處理器的虛擬處理器數目改成4~8。
然後就可以按下連線並啟動,開始進行 Ubuntu 的安裝。
增加 GPU-PV 硬件
虛擬機 Ubuntu 並不是直接存取 Windows 宿主機的 GPU,而是在 Ubuntu 中裝上 GPU-PV 這個虛擬硬體,然後啟用 dxgkrnl 驅動程式並使用 DirectX 與宿主機 GPU 溝通。GPU-PV 其實是顯卡虛擬化的意思。新增 GPU-PV 硬体之前,必需把檢查點的功能取消,否則虛擬機會說新增了 GPUP 而無法執行。請在 Ubuntu虛擬器按右鍵/設定,在檢查點項目中,把啟用檢查點取消,最後記得要把虛擬機關機。
然後在 Windows 宿主機使用系統管理員身份開啟 PowerShell,執行如下指令。請注意,只能用 PowerShell,不可以用 DOS 視窗。
Set-VM -VMName <vmname> -GuestControlledCacheTypes $true -LowMemoryMappedIoSpace 1GB -HighMemoryMappedIoSpace 32GB
Add-VMGpuPartitionAdapter -VMName <vmname>
上面的 <vmname> 就是我們虛擬器的名稱 “Ubuntu”。所以實際指令如下
Set-VM -VMName Ubuntu -GuestControlledCacheTypes $true -LowMemoryMappedIoSpace 1GB -HighMemoryMappedIoSpace 32GB
Add-VMGpuPartitionAdapter -VMName Ubuntu
接下來打開 HV 虛擬器,輸入 lspci,就會看到多了 “3D controller: Microsoft Corporation Device 008e”,這就表示 GPU-PV 新增成功。
執行 sudo lshw -C display,就會看到新增底下紅色的框框的硬体,只是目前沒有驅動程式
安裝 dxgkrnl 驅動程式
dxgkrnl 是 GPU-PV 的驅動程式,使用 DirectX 與 Linux 溝通,底下的 dxgkrnl 是由微軟維護的,比較穩定。先安裝如下套件
sudo apt install build-essential flex bison dwarves libssl-dev libelf-dev
然後在虛擬機查看 Ubuntu 目前的 kernel 版本
uname -r
結果:
5.15.0-105-generic
vim dx.sh,輸入如下代碼。請注意藍色的部份要跟上面所查到的 Ubuntu 核心版本一致,否則會讓虛擬機當機。
#!/bin/bash -e BRANCH=linux-msft-wsl-5.15.y if [ "$EUID" -ne 0 ]; then echo "Swithing to root..." exec sudo $0 "$@" fi
apt-get install -y git dkms git clone -b $BRANCH --depth=1 https://github.com/microsoft/WSL2-Linux-Kernel cd WSL2-Linux-Kernel VERSION=$(git rev-parse --short HEAD) cp -r drivers/hv/dxgkrnl /usr/src/dxgkrnl-$VERSION mkdir -p /usr/src/dxgkrnl-$VERSION/inc/{uapi/misc,linux} cp include/uapi/misc/d3dkmthk.h /usr/src/dxgkrnl-$VERSION/inc/uapi/misc/d3dkmthk.h cp include/linux/hyperv.h /usr/src/dxgkrnl-$VERSION/inc/linux/hyperv_dxgkrnl.h sed -i 's/\$(CONFIG_DXGKRNL)/m/' /usr/src/dxgkrnl-$VERSION/Makefile sed -i 's#linux/hyperv.h#linux/hyperv_dxgkrnl.h#' /usr/src/dxgkrnl-$VERSION/dxgmodule.c echo "EXTRA_CFLAGS=-I\$(PWD)/inc" >> /usr/src/dxgkrnl-$VERSION/Makefile cat > /usr/src/dxgkrnl-$VERSION/dkms.conf <<EOF PACKAGE_NAME="dxgkrnl" PACKAGE_VERSION="$VERSION" BUILT_MODULE_NAME="dxgkrnl" DEST_MODULE_LOCATION="/kernel/drivers/hv/dxgkrnl/" AUTOINSTALL="yes" EOF dkms add dxgkrnl/$VERSION dkms build dxgkrnl/$VERSION dkms install dxgkrnl/$VERSION
儲存後,執行如下指令
sudo chmod 755 dx.sh sudo ./dx.sh
上述代碼的用途是編譯及安裝 dxgkrnl 驅動,有時會編譯錯誤,需重複執行幾次,一直看到有出現 “depmod….“ 才表示安裝成功,如下圖所示。
將虛擬機重新開機後,執行 sudo lshw -C display,即可看到驅動裝起來了
安裝套件
先把 Windows 宿主機底下二個目錄 copy 到 虛擬機的家目錄下。有的人使用 scp copy,本人則是使用 winscp ,比較方便。
C:\Windows\System32\lxss\lib C:\Windows\System32\DriverStore\FileRepository\nv_dispi.inf_amd64_xxxxxx
nv_dispi.inf_amd64 後面的 xxx 每台機器都不一樣。
然後執行如下指令
sudo mkdir -p /usr/lib/wsl/{lib,drivers} sudo cp -r lib/* /usr/lib/wsl/lib/ sudo cp lib/nvidia-smi /usr/bin sudo chmod 755 /usr/bin/nvidia-smi sudo cp -r nv_dispi.inf_amd64_* /usr/lib/wsl/drivers/ sudo chmod -R 0555 /usr/lib/wsl sudo ln -s /usr/lib/wsl/lib/libd3d12core.so /usr/lib/wsl/lib/libD3D12Core.so
接下來執行 sudo vim /etc/ld.so.conf.d/ld.wsl.conf,加入如下
/usr/lib/wsl/lib
最後還要執行如下指令
sudo ldconfig
上述如果出現 “/sbin/ldconfig.real: /usr/lib/wsl/lib/libcuda.so.1 is not a symbolic link”,請不用理會。
測試
終於安裝完成了,請執行 nvidia-smi ,就可以看到如下畫面了
開機自動啟動虛擬機
停止虛擬機,在虛擬機按右鍵/設定,左邊的自動啟動動作,選擇永遠自動啟動此虛擬機器
然後在自動停止動作選項中,選取關閉虛擬機器
怪異現像
Hyper-V 安裝 Ubuntu 後,然後於 Windows 宿主機安裝 MySQL Community Server,會發生 mysql80 因為 3306 port 被佔住無法安裝,換了其它 port 一樣裝不起來。最終發現把 Ubuntu 虛擬機關機,就能成功安裝 MySQL。
接下來重新開機再進行測試,Hyper-V 也正常, MySQL 也正常。這真的是太詭異了,只能說 Hyper-V 的 bug 何其多,實在有待加常。
說老實話,林北本來就有實体的 Linux 伺服器,而且也有實体的 RTX-3080Ti 顯卡,壓根兒就不用去搞這種問題一大堆的 Hyper-V 虛擬機。
沒法度,前世業障過深,今世被指定天命需以教學普渡眾生,所以只好補上這篇。
另外還有個 issue,就是 Asus 控制及監控 GPU 的 Tweak III ,好像有很大的問題。還沒安裝 Hyper-V 前就會偶發黑屏停頓個5、6秒,裝了 Hyper-V 後更是隨性的發狂,目前本人先把 Tweak 移除進行測試中。
參考
https://gist.github.com/krzys-h/e2def49966aa42bbd3316dfb794f4d6a
Hyper-V 及 WSL 安裝 Cuda
無論是在 Hyper-V 或是 WSL,安裝 nVidia 的 Cuda 及 cudnn 的步驟是一樣的。
但在開始安裝 Cuda 時,一定要把虛擬機的硬体驅動程式安裝好,請執行 nvidia-smi,看到如下的畫面才可繼續安裝 Cuda。
安裝 Cuda
到官網 https://developer.nvidia.com/cuda-toolkit-archive 查看相關版本的安裝指令。底下是 cuda 12.4.0 的版本,請選擇 Linux/x86_64/WSL-Ubuntu/2.0/deb(local)。底下是官網說明的安裝方式。
wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-wsl-ubuntu.pin sudo mv cuda-wsl-ubuntu.pin /etc/apt/preferences.d/cuda-repository-pin-600 wget https://developer.download.nvidia.com/compute/cuda/12.4.0/local_installers/cuda-repo-wsl-ubuntu-12-4-local_12.4.0-1_amd64.deb sudo dpkg -i cuda-repo-wsl-ubuntu-12-4-local_12.4.0-1_amd64.deb sudo cp /var/cuda-repo-wsl-ubuntu-12-4-local/cuda-*-keyring.gpg /usr/share/keyrings/ sudo apt-get update sudo apt-get -y install cuda-toolkit-12-4
安裝 cudnn
安裝 cudnn 時, 請勿依官網的方式下載及安裝,只需使用 apt-get install 即可,安裝套件如下。
sudo apt-get -y install nvidia-cudnn
安裝的第一個畫面請按 “OK”
第二個畫面,請選取 “I Agree”,然後再按 “OK”
驗証 GPU 是否啟動
請先在 Python 專案下安裝套件
sudo apt-get install python3.10-venv mkdir pytest cd pytest python3 -m venv .venv source ./.venv/bin/activate pip install tensorflow
然後編寫測試程式,vim test.py
import os os.environ['TF_CPP_MIN_LOG_LEVEL']='2' import tensorflow as tf gpus = tf.config.list_physical_devices(device_type='GPU') print(gpus)
最後執行,python test.py,得到如下的結果就表示硬体 GPU 啟動了
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]
蒙地卡羅測試
執行如下的蒙地卡羅程式,可以看到 GPU 全速在執行。
import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' import tensorflow as tf batch=100_000_000 epochs=2000 incircle=0 #@tf.function def cal(): points=tf.random.uniform([2, batch], dtype=tf.float32) dist=tf.sqrt(tf.square(points[0])+tf.square(points[1])) count=tf.where(dist<=1).shape[0] return count # cpus = tf.config.list_physical_devices (device_type='CPU') # tf.config.set_visible_devices (devices=cpus[0]) #只使用 CPU, device_type預設是'CPU' for e in range(epochs): count=cal() incircle+=count area=incircle /((e+1)*batch) pi=area*4 print(f'epoch:{e+1}, pi={pi}')
上述程式開始跑時,開啟另一個視窗執行如下指令
watch -n 1 nvidia-smi
就可以看到顯卡的功耗到了 355瓦