使用cGPU服務可以隔離GPU資源,實現多個容器共用一張GPU卡。該服務作為阿里云容器服務Kubernetes版ACK(Container Service for Kubernetes)的組件對外提供服務,應用于高性能計算能力的場景,例如機器學習、深度學習、科學計算等,方便您更高效地利用GPU資源,以加速計算任務。本文介紹如何通過安裝并使用cGPU服務。
cGPU服務的隔離功能不支持以UVM的方式(即調用CUDA API cudaMallocManaged())申請顯存,請您使用其他方式申請顯存,例如調用cudaMalloc()等。更多信息,請參見NVIDIA官方文檔。
前提條件
在進行本操作前,請確保GPU實例滿足以下要求:
GPU實例規格為gn7i、gn6i、gn6v、gn6e、gn5i、gn5、ebmgn7i、ebmgn6i、ebmgn7e、ebmgn6e、ebmgn7ex或sccgn7ex。
GPU實例操作系統為CentOS、Ubuntu或Alibaba Cloud Linux。
GPU實例已安裝Tesla 418.87.01或更高版本的驅動。
GPU實例已安裝Docker 19.03.5或更高版本。
安裝cGPU服務
無論您是企業認證用戶還是個人實名認證用戶,推薦您通過ACK的Docker運行時環境安裝和使用cGPU服務。
安裝1.5.7版本的cGPU組件,可能會導致cGPU內核驅動出現死鎖現象(即并發執行的進程互相牽制),從而導致Linux Kernel Panic(即內核錯誤)問題,建議您安裝1.5.8及以上版本的cGPU,或將低版本cGPU逐步升級到1.5.8及以上版本,避免在新業務上出現內核錯誤問題。
創建集群。
具體操作,請參見創建ACK托管集群。
在集群列表頁面,單擊目標集群名稱,然后在左側導航欄,選擇 。
在基礎能力區域,選中調度策略擴展(批量任務調度、GPU共享、GPU拓撲感知)。
單擊頁面底部的部署云原生AI套件。
組件安裝成功后,在云原生AI套件頁面的組件列表中能看到已安裝的共享GPU組件ack-ai-installer。
在云原生AI套件頁面,單擊一鍵部署。
使用cGPU服務
本文以ecs.gn6i-c4g1.xlarge為例演示2個容器共用1張顯卡。
創建容器時指定環境變量的值,該值可以控制容器通過cGPU服務獲得算力。
環境變量名稱 | 取值類型 | 說明 | 示例 |
CGPU_DISABLE | Boolean | 是否禁用cGPU服務,取值范圍:
默認值:false。 | true |
ALIYUN_COM_GPU_MEM_DEV | Integer | 設置GPU實例上每張顯卡的總顯存大小。 該參數值與實例規格有關,顯存大小按GiB取整數。例如: 對于ecs.gn6i-c4g1.xlarge實例,配備1張NVIDIA Tesla T4顯卡,在GPU實例上執行nvidia-smi可查看總顯存大小。 | 總顯存大小為15109 MiB,取整數為15 GiB。 |
ALIYUN_COM_GPU_MEM_CONTAINER | Integer | 設置容器內可見的顯存大小,與 在一張總顯存大小為15 GiB的顯卡上,設置 說明 如果不指定本參數或指定為0,則不使用cGPU服務,使用默認的NVIDIA容器服務。 | 1 GiB |
ALIYUN_COM_GPU_VISIBLE_DEVICES | Integer或uuid | 指定容器內可見的GPU顯卡。例如: 在一臺有4張顯卡的GPU實例上,執行nvidia-smi -L查看GPU顯卡設備號和UUID。返回示例如下所示:
然后,您可以指定該參數為以下環境變量:
|
|
ALIYUN_COM_GPU_SCHD_WEIGHT | Integer | 設置容器的算力權重,取值范圍:1~max_inst。 | 無 |
ALIYUN_COM_GPU_HIGH_PRIO | Integer | 設置容器的高優先級,取值范圍:
默認值:0。 說明 建議每張GPU卡設置一個高優先級,多個高優先級容器之間遵循相應的調度策略(policy)。
| 0 |
運行cGPU服務
執行以下命令,創建容器并設置容器內可見的顯存。
本示例中,設置
ALIYUN_COM_GPU_MEM_CONTAINER
和ALIYUN_COM_GPU_MEM_DEV
環境變量指定顯卡的總顯存和容器內可見的顯存。例如創建2個容器:gpu_test1:分配6 GiB顯存。
sudo docker run -d -t --gpus all --shm-size=1g --ulimit memlock=-1 --ulimit stack=67108864 --name gpu_test1 -v /mnt:/mnt -e ALIYUN_COM_GPU_MEM_CONTAINER=6 -e ALIYUN_COM_GPU_MEM_DEV=15 nvcr.io/nvidia/tensorflow:19.10-py3
gpu_test2:分配8 GiB顯存。
sudo docker run -d -t --gpus all --shm-size=1g --ulimit memlock=-1 --ulimit stack=67108864 --name gpu_test2 -v /mnt:/mnt -e ALIYUN_COM_GPU_MEM_CONTAINER=8 -e ALIYUN_COM_GPU_MEM_DEV=15 nvcr.io/nvidia/tensorflow:19.10-py3
說明該命令以使用TensorFlow鏡像
nvcr.io/nvidia/tensorflow:19.10-py3
為例,請根據實際情況更換為您自己的容器鏡像。使用TensorFlow鏡像搭建TensorFlow深度學習框架的操作,請參見部署NGC環境構建深度學習開發環境。執行以下命令,查看容器的顯存等GPU信息。
sudo docker exec -i gpu_test1 nvidia-smi
以gpu_test1為例,容器gpu_test1中可見的顯存為6043 MiB,如下圖所示:
通過procfs節點查看cGPU服務
cGPU服務運行時會在/proc/cgpu_km下生成并自動管理多個procfs節點,您可以通過procfs節點查看和配置cGPU服務相關的信息。
執行以下命令,查看procfs節點信息。
ls /proc/cgpu_km/
執行結果如下所示:
節點信息
讀寫類型
說明
0
讀寫
cGPU服務會針對GPU實例中的每張顯卡生成一個目錄。并使用數字作為目錄名稱,例如0、1、2。
本示例中只有一張顯卡,對應的目錄為0。
default_memsize
讀寫
如果沒有設置ALIYUN_COM_GPU_MEM_CONTAINER參數,默認為新創建的容器分配的顯存大小。
inst_ctl
讀寫
控制節點。
upgrade
讀寫
控制cGPU服務的熱升級。
version
只讀
cGPU的版本。
執行以下命令,查看GPU實例的顯卡目錄內容。
本示例中,以顯卡0為例。
ls /proc/cgpu_km/0
執行結果如下所示:
顯卡目錄
讀寫類型
說明
012b2edccd7a
或0852a381c0cf
讀寫
容器對應的目錄。
cGPU服務會針對運行在GPU實例中的每個容器生成一個的目錄,并使用容器ID作為目錄名稱。
說明您可以執行docker ps查看已創建的容器。
free_weight
只讀
用于查詢和修改顯卡上可用的權重。
如果
free_weight=0
,新創建容器的權重值為0,該容器不能獲取GPU算力,不能用于運行需要GPU算力的應用。major
只讀
表示cGPU的major number,即不同的設備類型。
max_inst
讀寫
用于設置容器的最大數量,取值范圍為1~25。
policy
讀寫
cGPU服務支持以下算力調度策略:
0:平均調度。每個容器占用固定的時間片,時間片占比為
1/max_inst
。1:搶占調度。每個容器占用盡量多的時間片,時間片占比為
1/當前容器數
。2:權重搶占調度。當ALIYUN_COM_GPU_SCHD_WEIGHT的取值大于1時,自動使用權重搶占調度。
3:固定算力調度。用于固定算力的百分比。
4:算力弱調度。隔離性弱于搶占調度。
5:原生調度。即GPU驅動本身的調度方式。
您可以通過修改policy的值實時調整調度策略。更多調度策略說明,請參見cGPU服務使用示例。
prio_ratio
讀寫
在線和離線混合使用場景下,高優先級容器最大可以搶占的算力。取值范圍:20~99。
執行以下命令,查看容器對應的目錄內容。
本示例中,以012b2edccd7a容器為例。
ls /proc/cgpu_km/0/012b2edccd7a
執行結果如下所示:
容器目錄
讀寫類型
說明
highprio
讀寫
用于設置容器的優先級,默認值為0。
當
ALIYUN_COM_GPU_HIGH_PRIO
參數取值為1時,表示容器最大可以搶占prio_ratio
參數的算力。說明該功能用于在線和離線混合使用場景。
id
只讀
容器的ID。
memsize
讀寫
用于設置容器內的顯存大小。cGPU服務會根據ALIYUN_COM_GPU_MEM_DEV參數自動設定此值。
meminfo
只讀
包括容器內剩余顯存容量、正在使用GPU的進程ID及其顯存用量。輸出如下所示:
Free: 6730809344 PID: 19772 Mem: 200278016
weight
讀寫
用于設置容器獲取顯卡最大算力的權重,默認值為1。所有運行中的容器的權重之和必須小于等于
max_inst
。(可選)執行以下命令,配置cGPU服務。
了解procfs節點的用途后,您可以在GPU實例中執行命令進行切換調度策略、修改權重等操作,示例命令如下表所示。
命令
效果
echo 2 > /proc/cgpu_km/0/policy
將調度策略切換為權重搶占調度。
cat /proc/cgpu_km/0/free_weight
查看顯卡上可用的權重。如果
free_weight=0
,新創建容器的權重值為0,該容器不能獲取GPU算力,不能用于運行需要GPU算力的應用。cat /proc/cgpu_km/0/$dockerid/weight
查看指定容器的權重。
echo 4 > /proc/cgpu_km/0/$dockerid/weight
修改容器獲取GPU算力的權重。
通過cgpu-smi工具查看cGPU容器
您可以通過cgpu-smi工具查看cGPU容器的相關信息,包括容器ID、GPU利用率、算力限制、使用的顯存以及分配顯存的總量等信息。
cgpu-smi是cGPU的監控示例。部署k8s時,您可以參考或使用cgpu-smi的示例做二次開發集成。
cgpu-smi的監控展示信息如下所示:
升級或卸載cGPU服務
升級cGPU服務
升級cGPU服務支持冷升級和熱升級兩種方式。
冷升級
Docker未使用cGPU服務的情況下,采用冷升級方式升級cGPU服務,操作步驟如下:
執行以下命令,關閉所有運行中的容器。
sudo docker stop $(docker ps -a | awk '{ print $1}' | tail -n +2)
執行以下命令,升級cGPU服務至最新版本。
sudo sh upgrade.sh
熱升級
Docker使用cGPU服務的情況下,可以采用熱升級方式升級cGPU內核驅動,但是對于升級的版本有一定限制。 如需任何協助,請聯系阿里云售后技術團隊。
卸載cGPU服務
關于如何卸載節點上舊版本cGPU服務,具體操作,請參見通過命令升級節點cGPU版本。
cGPU服務使用示例
cGPU服務算力調度示例
cGPU服務加載cgpu_km的模塊時,會按照容器最大數量(max_inst)為每張顯卡設置時間片(X ms),用于為容器分配GPU算力,本示例中以Slice 1、Slice 2或Slice N表示。使用不同調度策略時的調度示例如下所示。
平均調度(policy=0)
在創建容器時,為容器分配時間片。cGPU服務會從Slice 1時間片開始調度,提交任務到物理GPU,并執行一個時間片(X ms)的時間,然后切換到下一個時間片。每個容器獲得的算力相同,都為
1/max_inst
,如下所示。搶占調度(policy=1)
在創建容器時,為容器分配時間片。cGPU服務會從Slice 1開始調度,但如果沒有使用某個容器,或者容器內沒有進程打開GPU設備,則跳過調度,切換到下一個時間片。
示例如下:
只創建一個容器Docker 1,獲得Slice 1時間片,在Docker 1中運行2個TensorFlow進程,此時Docker 1最大獲得整個物理GPU的算力。
再創建一個容器Docker 2,獲得Slice 2時間片。如果Docker 2內沒有進程打開GPU設備,調度時會跳過Docker 2的時間片Slice 2。
當Docker 2有進程打開GPU設備時,Slice 1和Slice 2都加入調度,Docker 1和Docker 2最大分別獲得1/2物理GPU的算力,如下所示。
權重搶占調度(policy=2)
如果在創建容器時設置ALIYUN_COM_GPU_SCHD_WEIGHT大于1,則自動使用權重搶占調度。cGPU服務按照容器數量(max_inst)將物理GPU算力劃分成max_inst份,但如果ALIYUN_COM_GPU_SCHD_WEIGHT大于1,cGPU服務會將多個時間片組合成一個更大的時間片分配給容器。
設置示例如下:
Docker 1:ALIYUN_COM_GPU_SCHD_WEIGHT=m
Docker 2:ALIYUN_COM_GPU_SCHD_WEIGHT=n
調度效果如下:
如果只有Docker 1運行, Docker 1搶占整個物理GPU的算力。
如果Docker 1和Docker 2同時運行,Docker 1和Docker 2獲得的理論算力比例是m:n。和搶占調度不同的是,即使Docker 2中沒有GPU進程也會占用n個時間片的時間。
說明m:n設置為2:1和8:4時的運行表現存在差別。在1秒內切換時間片的次數,前者是后者的4倍。
權重搶占調度限制了容器使用GPU算力的理論最大值。但對算力很強的顯卡(例如NVIDIA V100顯卡),如果顯存使用較少,在一個時間片內即可完成計算任務。此時如果m:n值設置為8:4,則剩余時間片內GPU算力會閑置,限制基本失效。
固定算力調度(policy=3)
您可以通過指定ALIYUN_COM_GPU_SCHD_WEIGHT和max_inst的占比,固定算力的百分比。
算力弱調度(policy=4)
在創建容器時,為容器分配時間片,隔離性弱于搶占調度。更多信息,請參見搶占調度(policy=1)。
原生調度(policy=5)
只用來做顯存的隔離。原生調度表示NVIDIA GPU驅動本身的調度方式。
算力調度策略支持阿里云所有的異構GPU實例,以及GPU實例所配備的NVIDIA顯卡,其型號包含Tesla P4、Tesla P100、Tesla T4、Tesla V100、Tesla A10。以下測試項使用2個容器共享一臺單卡A10的GPU實例,并將2個容器的算力比設置為1:2,將顯存均分,每個容器的顯存為12 G。
以下性能測試結果數據為實驗室數據,僅供參考。
測試項1: 在基于TensorFlow框架訓練的ResNet50模型、精度為FP16的場景下,測試不同batch_size下的性能數據比較。結果如下所示:
框架
模型
batch_size
精度
images/sec(容器1)
images/sec(容器2)
TensorFlow
ResNet50
16
FP16
151
307
TensorFlow
ResNet50
32
FP16
204
418
TensorFlow
ResNet50
64
FP16
247
503
TensorFlow
ResNet50
128
FP16
257
516
測試項2:在基于TensorRT框架訓練的ResNet50模型、精度為FP16的場景下,測試不同batch_size下的性能數據比較。結果如下所示:
框架
模型
batch_size
精度
images/sec(容器1)
images/sec(容器2)
TensorRT
ResNet50
1
FP16
568.05
1132.08
TensorRT
ResNet50
2
FP16
940.36
1884.12
TensorRT
ResNet50
4
FP16
1304.03
2571.91
TensorRT
ResNet50
8
FP16
1586.87
3055.66
TensorRT
ResNet50
16
FP16
1783.91
3381.72
TensorRT
ResNet50
32
FP16
1989.28
3695.88
TensorRT
ResNet50
64
FP16
2105.81
3889.35
TensorRT
ResNet50
128
FP16
2205.25
3901.94
cGPU服務多卡劃分示例
本示例以設置4卡為例,設置0卡為3 G、1卡為4 G、2卡為5 G、3卡為6 G。多卡劃分示例代碼如下所示:
docker run -d -t --runtime=nvidia --name gpu_test0123 --shm-size=1g --ulimit memlock=-1 --ulimit stack=67108864 -v /mnt:/mnt -e ALIYUN_COM_GPU_MEM_CONTAINER=3,4,5,6 -e ALIYUN_COM_GPU_MEM_DEV=23 -e NVIDIA_VISIBLE_DEVICES=0,1,2,3 nvcr.io/nvidia/tensorflow:21.03-tf1-py3
docker exec -i gpu_test0123 nvidia-smi
執行結果顯示如下,您可以看到4卡顯存詳情。
多卡設置顯存參數(即ALIYUN_COM_GPU_MEM_CONTAINER
參數)說明如下所示:
參數取值 | 說明 |
ALIYUN_COM_GPU_MEM_CONTAINER=3 | 表示4卡的顯存都被設置為3 G。 |
ALIYUN_COM_GPU_MEM_CONTAINER=3,1 | 表示4卡的顯存依次被設置為3 G、1 G、1 G、1 G。 |
ALIYUN_COM_GPU_MEM_CONTAINER=3,4,5,6 | 表示4卡的顯存依次被設置為3 G、4 G、5 G、6 G。 |
ALIYUN_COM_GPU_MEM_CONTAINER未設置 | 表示禁用cGPU服務。 |
ALIYUN_COM_GPU_MEM_CONTAINER=0 | |
ALIYUN_COM_GPU_MEM_CONTAINER=1,0,0 |