catch-img

NVIDIA製GPUのユーザ毎の利用制限

この記事は、2021年8月25日に社内向けに執筆されたものを加筆・修正したものです。


NVIDIAのGPUをユーザ毎に利用制限する方法


概要

大学の研究室で4つのGPUを搭載したサーバ機器を買ったのはいいけれど、「特定のユーザが全てのGPUをずっと専有していて自分に回ってこない!」といった苦情が波のように押し寄せ、サーバ管理者がその対応で疲弊しているという話をよく耳にします。実際に弊社にも「ユーザアカウントごとに使えるGPUを自由に制限できないか」という問い合わせが数多く届いています。

ということで、せっかくの高性能GPUが一部のユーザだけの特権になってしまうのを防ぎたいという切実な声に応えるべく、GPU搭載のLinuxサーバでユーザ毎に使えるGPUを制限する方法を紹介します。これを設定することで、みんなが平等にリソースを利用できるようになり、研究室内の不満が解消され、管理者の笑顔が取り戻せることでしょう。

簡単に実装できそうなものとしては以下の3つの方法があります。

  1. NVIDIAのGPU Virtualization Softwareを使って仮想化したGPUをユーザに割り当てる方法。
    • メーカー公式の方法ですが、この機能に対応している上位のGPUでしか使えません。
    • また、有償のライセンスを購入またはサブスクリプションを契約する必要があるので敷居が高いです。
  2. Slurm等のジョブスケジューラのリソース管理機能でユーザが使えるGPUを制限する方法。
    • Slurmを経由しないジョブの管理はできず、大規模なクラスタシステムでのリソース管理に向いています。
  3. 各GPUのデバイス毎にグループを割り当て、そのグループに所属するユーザからのみGPUが見えるように制限する方法。
    • Linuxのパーミッションを用いてGPUを制限する方法で、最も手軽に試すことができます。
    • この記事ではこちらの方法を紹介します。


手順

1. GPU毎にグループを作成する

  • GPUの数だけユーザグループ(nvidia0, nvidia1, ..., nvidiaN)を作成します。
  • 以下は4つのGPUがある場合の例です。
for i in {0..4}
do
  groupadd nvidia$i
done


2. ユーザの修正

  • ユーザの所属グループに割り当てるGPUのグループを追加します。
  • 以下の例では nvidia0 というグループをユーザ j-yoshimura に割り当てています。
usermod -a -G nvidia0 j-yoshimura

3. デバイスドライバの設定ファイル作成

  •  /etc/modprobe.d/nvidia.conf を作成し、以下のように記述します。
#!/bin/bash
options nvidia NVreg_DeviceFileUID=0 NVreg_DeviceFileGID=0 NVreg_DeviceFileMode=0777 NVreg_ModifyDeviceFiles=0

解説

NvidiaのカーネルモジュールのオプションでNVreg_ModifyDeviceFilesをOFFにすることにより、起動時にGPUデバイスが作成されなくなります。

4. GPUデバイス作成スクリプトの作成

  •  /etc/init.d/gpu-restriction.sh を作成し、以下のように記述します。

### BEGIN INIT INFO
# Provides:          gpu-restriction
# Required-Start:    $all
# Required-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:
# Short-Description: Start daemon at boot time
# Description:       Enable service provided by daemon.
#  permissions if needed.
### END INIT INFO

set -e

start() {
/sbin/modprobe --ignore-install nvidia;
/sbin/modprobe nvidia_uvm;
test -c /dev/nvidia-uvm \
        || mknod -m 777 /dev/nvidia-uvm c $(cat /proc/devices | \
        while read major device; do if [ "$device" == "nvidia-uvm" ]; then echo $major; break; fi ; done) 0 \
&& chown :root /dev/nvidia-uvm; 
test -c /dev/nvidiactl \
        || mknod -m 777 /dev/nvidiactl c 195 255 \
&& chown :root /dev/nvidiactl;
devid=-1;
for dev in $(ls -d /sys/bus/pci/devices/*);
do
    vendorid=$(cat $dev/vendor);
    if [ "$vendorid" == "0x10de" ]; then
    class=$(cat $dev/class);
    classid=${class%%00};
    if [ "$classid" == "0x0300" -o "$classid" == "0x0302" ]; then
        devid=$((devid+1));
        if [ -c /dev/nvidia${devid} ];then
          chmod 660 /dev/nvidia${devid}
        else
          mknod -m 660 /dev/nvidia${devid} c 195 ${devid}
        fi; \
        && chown :nvidia${devid} /dev/nvidia${devid};
    fi;
fi;
done
}

stop() {
:
}

 "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        stop
        start
        ;;
    status)
        # code to check status of app comes here 
        # example: status program_name
        ;;
    *)
        echo $0
  • スクリプトに実行権限を付与します。
chmod 755 /etc/init.d/gpu-restriction.sh

解説

  • 手順3で起動時にGPUデバイスが作成されなくなったので、このスクリプトでデバイスを作成すると同時に、デバイスにグループを割り当て、パーミッションを660に変更しています。
  • これによりデバイスのグループに所属しているユーザのみ、そのデバイスを読み書きできる状態になります。

5. スクリプトをsystemdへ登録

  •  /etc/systemd/system/gpu-restriction.service を作成し、以下のように記述します。
[Unit]
Description = User Restrictions for GPUs

[Service]
ExecStart = /etc/init.d/gpu-restriction.sh start
Restart = no
Type = simple

[Install]
WantedBy = multi-user.target
  • 起動時に実行されるように有効化します。
systemctl daemon-reload
systemctl enable gpu-restriction.service

6. 再起動

  • サーバを再起動すると準備完了です。


確認


実際にGPUを搭載したサーバgpu001上で動作を確認してみます。

  • まず、ユーザ j-yoshimura にGPUを割り当てていない状態でGPUを確認します。
  • すると、 No devices were found と怒られてしまいます。
[j-yoshimura@gpu001 ~]$ id
uid=679000003(j-yoshimura) gid=679000003(j-yoshimura) groups=679000003(j-yoshimura)
[j-yoshimura@gpu001 ~]$ nvidia-smi 
No devices were found
  • 次に、ユーザ j-yoshimura にグループ nvidia0 を割り当ててGPUを確認します。
  • 今度はGPUが1つ見えました。
[j-yoshimura@gpu001 ~]$ id
uid=679000003(j-yoshimura) gid=679000003(j-yoshimura) groups=679000003(j-yoshimura),9904(nvidia0)
[j-yoshimura@gpu001 ~]$ nvidia-smi 
Wed Aug 25 16:18:05 2021       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 465.19.01    Driver Version: 465.19.01    CUDA Version: 11.3     |
|-------------------------------+----------------------+----------------------+
| 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 ...  Off  | 00000000:D8:00.0 Off |                  N/A |
| 33%   50C    P0    50W / 260W |      0MiB / 11016MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                            
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+
  • 同様に nvidia0 nvidia1 の2つのグループを割り当てます。
  • 当然ですが2つのGPUが見えるようになりました。
[j-yoshimura@gpu001 ~]$ id
uid=679000003(j-yoshimura) gid=679000003(j-yoshimura) groups=679000003(j-yoshimura),9904(nvidia0),9905(nvidia1)
[j-yoshimura@gpu001 ~]$ nvidia-smi 
Wed Aug 25 16:25:05 2021     
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 465.19.01    Driver Version: 465.19.01    CUDA Version: 11.3     |
|-------------------------------+----------------------+----------------------+
| 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 ...  Off  | 00000000:D8:00.0 Off |                  N/A |
| 33%   50C    P0    50W / 260W |      0MiB / 11016MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
|   1  NVIDIA A100-PCI...  Off  | 00000000:61:00.0 Off |                    0 |
| N/A   33C    P0    35W / 250W |      3MiB / 40536MiB |      0%      Default |
|                               |                      |             Disabled |
+-------------------------------+----------------------+----------------------+
                                                                            
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+


まとめ


Linuxサーバ上でユーザに使えるGPUを割り当てる方法を紹介しました。

  • 今回はNvidiaのカーネルモジュールの設定により、パーミッションでアクセス制限を行う方法を取り上げましたが、比較的簡単な設定で制限することができました。
  • ただ、大規模なクラスタサーバ環境では個々のサーバで設定するよりも、ジョブスケジューラSlurmを使ってリソースの制限を行う方が効率的かもしれません。

というわけで、近いうちにSlurmを使った制限方法についてもご紹介したいと思います。

今回の記事を書くにあたり、以下のサイトを参考にしました。
https://towardsdatascience.com/defining-user-restrictions-for-gpus-6971a658a9ce

j-yoshimura
j-yoshimura