前振り
複数人で1つのGPUサーバを使っている。
実験環境の棲み分けはdockerで出来ているのだが、
物理的なリソースはどうしても 奪い合い 競合が発生する。
特にGPU。
GPU使いたいなー、と思っても誰かのコンテナが既に使っている。
1時間後も使われている。3時間後も使われている。
5時間後も使われている。翌日になっても誰かのコンテナがGPUを使っている。
いい加減にしろよオラァン
どのコンテナがどのGPUを使っているのか、を見つけたくなったので調べてみた。
環境
Ubuntu 16.04.3 LTS
Docker version 19.03.1
dockerは 17.12.0-ce
でもいける。
step1:使われているGPUを見つけよう
nvidia-smi
を使う。
~$ nvidia-smi
Wed Oct 30 14:59:19 2019
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 418.67 Driver Version: 418.67 CUDA Version: 10.1 |
|-------------------------------+----------------------+----------------------+
| 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 K40c On | 00000000:04:00.0 Off | 0 |
| 29% 62C P0 143W / 235W | 10963MiB / 11441MiB | 44% Default |
+-------------------------------+----------------------+----------------------+
| 1 Tesla K40c On | 00000000:05:00.0 Off | 0 |
| 31% 65C P0 174W / 235W | 11025MiB / 11441MiB | 98% Default |
+-------------------------------+----------------------+----------------------+
| 2 Tesla K40c On | 00000000:08:00.0 Off | 0 |
| 23% 23C P8 20W / 235W | 0MiB / 11441MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
(略)
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 14679 C python3 10950MiB |
| 1 40974 C /usr/bin/python3 11010MiB |
+-----------------------------------------------------------------------------+
こんな感じでGPUを使用しているプロセスは見ることができる。
が、どのコンテナが使用しているのかまでは分からない。
step2:稼働しているdockerコンテナを知ろう
docker ps
で見る。
~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
370c2888bfe1 tensorflow/tensorflow:1.13.1-gpu-py3 "/bin/bash" 7 weeks ago Up 7 weeks 0.0.0.0:8888->8888/tcp test01
5a0bb9435b77 tensorflow/tensorflow:latest-gpu-py3 "/bin/bash" 3 weeks ago Up 3 weeks 0.0.0.0:9999->8888/tcp practice
こんな感じで稼働しているコンテナは見ることができる。
が、どのコンテナがどのプロセスを使用しているのかまでは分からない。
step3:コンテナのプロセスIDを見つけよう
/proc/[プロセスID]/cgroup
を見る。
~$ cat /proc/40974/cgroup
11:cpuset:/docker/370c2888bfe1c309f91c4d1d77d50cda72cfc33d29602ed23c22f6c28692db55
10:memory:/docker/370c2888bfe1c309f91c4d1d77d50cda72cfc33d29602ed23c22f6c28692db55
9:perf_event:/docker/370c2888bfe1c309f91c4d1d77d50cda72cfc33d29602ed23c22f6c28692db55
8:pids:/docker/370c2888bfe1c309f91c4d1d77d50cda72cfc33d29602ed23c22f6c28692db55
7:freezer:/docker/370c2888bfe1c309f91c4d1d77d50cda72cfc33d29602ed23c22f6c28692db55
6:blkio:/docker/370c2888bfe1c309f91c4d1d77d50cda72cfc33d29602ed23c22f6c28692db55
5:devices:/docker/370c2888bfe1c309f91c4d1d77d50cda72cfc33d29602ed23c22f6c28692db55
4:cpu,cpuacct:/docker/370c2888bfe1c309f91c4d1d77d50cda72cfc33d29602ed23c22f6c28692db55
3:net_cls,net_prio:/docker/370c2888bfe1c309f91c4d1d77d50cda72cfc33d29602ed23c22f6c28692db55
2:hugetlb:/docker/370c2888bfe1c309f91c4d1d77d50cda72cfc33d29602ed23c22f6c28692db55
1:name=systemd:/docker/370c2888bfe1c309f91c4d1d77d50cda72cfc33d29602ed23c22f6c28692db55
こんな感じで謎の文字列が並んでいるが、 /docker/
以降はコンテナIDになっている。
先頭12桁は docker ps
コマンドで照会できる値と同じ。
1:name=systemd:/docker/370c2888bfe1c309f91c4d1d77d50cda72cfc33d29602ed23c22f6c28692db55
└─この部分─┘
と
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
370c2888bfe1 tensorflow/tensorflow:1.13.1-gpu-py3 "/bin/bash" 7 weeks ago Up 7 weeks 0.0.0.0:8888->8888/tcp test01
└─この部分─┘
が対応しているのが分かる。
ここまでくればあとは簡単。
step4:プロセスIDとコンテナIDとGPU-Noを紐づけよう
今までのstepを組み合わせるだけ。
-
nvidia-smi
でGPUを使っているプロセスIDを取得 -
/proc/[プロセスID]/cgroup
を見てGPUを使っているプロセスIDを使っているコンテナIDを取得 -
docker ps
を使ってコンテナIDから該当するコンテナを見つける GPUを占有しているコンテナの管理者にGPU使用権を賭けて決闘を申し込む
以上。
(おまけ)上記の紐づけ作業をshell化してみる
とりあえず見られれば良いや、という人向け。
エラー回避は一切考慮してないのでご了承ください。
多分もっとスマートでエレガントなやり方があるとは思う。
#!/bin/bash
ids_ary=() # プロセスID記録用の空配列
# nvidia-smiでGPUを使用しているプロセスIDを取得
for proc_id in `nvidia-smi | grep "MiB |$" | awk '{print $3}'`
do
# PIDが記録配列に存在するか
if echo "${ids_ary[@]}" | grep -q "${proc_id}"; then
# 存在したら何もしない
continue
else
# 存在しなければそのプロセスが動いているコンテナ情報(ID, 名称)を取得
cnt_inf=`docker ps --format "{{.ID}} {{.Names}}" | grep \`awk -F/ 'END {print(substr($3,1,8))}' /proc/${proc_id}/cgroup\``
# nvidia-smiっぽく出力してみる
echo "+-----------------------------------------------------------------------------+"
echo "| Processes: GPU Memory |"
echo "| GPU PID Type Process name Usage |"
echo "| CONTAINER ID NAMES |"
echo "|=============================================================================|"
nvidia-smi | awk -v prc="${proc_id}" '$3 == prc {print $0}'
printf "| %-12s %-51s |\n" ${cnt_inf[0]} ${cnt_inf[1]}
echo "+-----------------------------------------------------------------------------+"
echo
fi
# 出力済みPIDを記録配列に追加
ids_ary+=(${proc_id})
done
exit 0
出力は↓こんな感じになる。
~$ bash sample.sh
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
| CONTAINER ID NAMES |
|=============================================================================|
| 0 14679 C python3 10950MiB |
| 5a0bb9435b77 practice |
+-----------------------------------------------------------------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
| CONTAINER ID NAMES |
|=============================================================================|
| 1 40974 C /usr/bin/python3 11010MiB |
| 370c2888bfe1 test01 |
+-----------------------------------------------------------------------------+
1つのコンテナ(プロセス)が複数のGPUを使っているときに出力が重複しないようにしてみた。
その時は↓のような表示になる。
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
| CONTAINER ID NAMES |
|=============================================================================|
| 1 40974 C /usr/bin/python3 11010MiB |
| 2 40974 C /usr/bin/python3 11010MiB |
| 370c2888bfe1 test01 |
+-----------------------------------------------------------------------------+
コンテナの中で複数のプロセス(プログラム)が動いている場合はホスト側でもプロセスIDが別になるので、
各プロセスが別のGPUを使っている場合は、同じコンテナの名前が何回も出てくることになる。
その辺りをまとめて表示したり、見せ方を変えたりもしたかったけどこの辺で妥協。