Linux下的CUDA多版本管理
關于CUDA、cuDNN等的簡介和安裝可參考:顯卡、顯卡驅動、CUDA、CUDA Toolkit、cuDNN 梳理。
CUDA多版本
有時我們會在一臺機器上同時看到多個版本的CUDA,比如nvcc -V
和nvidia-smi
的輸出就可能會不同:
在我們實驗室的服務器上nvcc --version
顯示的結果如下:
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2018 NVIDIA Corporation
Built on Tue_Jun_12_23:07:04_CDT_2018
Cuda compilation tools, release 9.2, V9.2.148
而nvidia-smi
顯示結果如下:
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 410.104 Driver Version: 410.104 CUDA Version: 10.0 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla V100-PCIE... On | 00000000:01:00.0 Off | Off |
| N/A 28C P0 26W / 250W | 0MiB / 16130MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
| 1 Tesla P100-PCIE... On | 00000000:02:00.0 Off | Off |
| N/A 24C P0 30W / 250W | 0MiB / 16280MiB | 0% Default |
+-------------------------------+----------------------+----------------------++-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
可以看到nvcc
的CUDA 版本是9.2,而nvidia-smi
的CUDA版本是10.0。如果nvidia-smi命令列出的CUDA版本與nvcc -V列出的版本號不一致,可能是由以下原因之一引起的:
1)安裝多版本cuda后,還沒有刷新環境變量,刷新即可;
2)CUDA有兩種API,分別是運行時API和驅動API,即所謂的Runtime API與Driver API,nvidia-smi的結果除了有GPU驅動版本型號,還有CUDA Driver API的版本號,這里是10.0,而nvcc的結果是對應CUDA Runtime API。
對于原因二的一個具體解釋如下:
CUDA有兩個主要的API:runtime(運行時) API和driver(驅動) API。這兩個API都有對應的CUDA版本(如9.2和10.0等)。
- 用于支持driver API的必要文件(如
libcuda.so
)是由GPU driver installer安裝的。nvidia-smi
就屬于這一類API。 - 用于支持runtime API的必要文件(如
libcudart.so
以及nvcc
)是由CUDA Toolkit installer安裝的。(CUDA Toolkit Installer有時可能會集成了GPU driver Installer)。nvcc
是與CUDA Toolkit一起安裝的CUDA compiler-driver tool,它只知道它自身構建時的CUDA runtime版本。它不知道安裝了什么版本的GPU driver,甚至不知道是否安裝了GPU driver。
綜上,如果driver API和runtime API的CUDA版本不一致可能是因為你使用的是單獨的GPU driver installer,而不是CUDA Toolkit installer里的GPU driver installer。
補充說明:在安裝CUDA 時候會安裝3大組件,分別是 NVIDIA 驅動、toolkit和samples。NVIDIA驅動是用來控制GPU硬件,toolkit里面包括nvcc編譯器等,samples或者說SDK 里面包括很多樣例程序包括查詢設備、帶寬測試等等。上面說的CUDA Driver API是依賴于NVIDIA驅動安裝的,而CUDA Runtime API 是通過CUDA toolkit安裝的。
runtime API 與 driver API 的區別
下圖很清楚的展示前面提到的各種概念之間的關系,其中runtime API和driver API在很多情況非常相似,也就是說用起來的效果是等價的,但是你不能混合使用這兩個API,因為二者是互斥的。也就是說在開發過程中,你只能選擇其中一種API。簡單理解二者的區別就是:runtime是更高級的封裝,開發人員用起來更方便,而driver API更接近底層,速度可能會更快。
兩種API詳細的區別如下:
-
復雜性
- runtime API通過提供隱式初始化、上下文管理和模塊管理來簡化設備代碼管理。這使得代碼更簡單,但也缺乏驅動程序API所具有的控制級別。
- 相比之下,driver API提供了更細粒度的控制,特別是在上下文和模塊加載方面。實現內核啟動要復雜得多,因為執行配置和內核參數必須用顯式函數調用指定。
-
控制
- 對于runtime API,其在運行時,所有內核都在初始化期間自動加載,并在程序運行期間保持加載狀態。
- 而使用driver API,可以只加載當前需要的模塊,甚至動態地重新加載模塊。driver API也是語言獨立的,因為它只處理
cubin
對象。
-
上下文管理
上下文管理可以通過driver API完成,但是在runtime API中不公開。相反,runtime API自己決定為線程使用哪個上下文:
- 如果一個上下文通過driver API成為調用線程的當前上下文,runtime將使用它,
- 如果沒有這樣的上下文,它將使用“主上下文(primary context)”。
主上下文會根據需要創建,每個設備每個進程一個上下文,并進行引用計數,然后在沒有更多的引用時銷毀它們。在一個進程中,所有runtime API的用戶都將共享主上下文,除非上下文已成為每個線程的當前上下文。runtime使用的上下文,即當前上下文或主上下文,可以用cudaDeviceSynchronize()
同步,也可以用cudaDeviceReset()
銷毀。
但是,將runtime API與主上下文一起使用會有tradeoff。例如,對于那些需要給較大的軟件包寫插件的開發者來說者會帶來不少麻煩,因為如果所有的插件都在同一個進程中運行,它們將共享一個上下文,但可能無法相互通信。也就是說,如果其中一個在完成所有CUDA工作后調用cudaDeviceReset()
,其他插件將失敗,因為它們使用的上下文在它們不知情的情況下被破壞。為了避免這個問題,CUDA clients可以使用driver API來創建和設置當前上下文,然后使用runtime API來處理它。但是,上下文可能會消耗大量的資源,比如設備內存、額外的主機線程和設備上上下文切換的性能成本。當將driver API與基于runtime API(如cuBLAS或cuFFT)構建的庫一起使用時,這種runtime-driver上下文共享非常重要。
CUDA多版本管理
我們可以通過:
ls -l /usr/local | grep cuda
來查看自己的機器上有多少個cuda版本,通常不帶版本號的 cuda
會是其他帶版本號的cuda-x.x
的軟鏈接。即像下面這樣:
lrwxrwxrwx 1 root root 21 12月 10 2020 cuda -> /usr/local/cuda-11.1/
而我們只要把我們使用cuda時都指向這個軟鏈接/usr/local/cuda
,并在需要切換版本時切換這個軟鏈接的指向即可。
sudo rm -rf cuda
sudo ln -s /usr/local/cuda-9.0/ /usr/local/cuda
注意此時如果nvcc -V
的輸出還是更改之前的CUDA版本的話,要修改環境變量:
export PATH=/usr/local/cuda/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH
并且要去 ~/.bashrc 中查看以下是不是會顯式地指定CUDA版本如:
export PATH=/usr/local/cuda-11.1/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda-11.1/lib64:$LD_LIBRARY_PATH
如果有這兩句的話,直接換成上面兩句指向軟鏈接 /usr/local/cuda
的兩句即可。
Ref
https://bbs.huaweicloud.com/blogs/detail/140384
https://blog.csdn.net/weixin_38705903/article/details/101850116