PBS pro (openpbs) のインストールと設定

インストール

PBS pro (openpbs) は Debian パッケージがないので, 手動でインストールする.

$ sudo apt-get install git

$ mkdir src
$ cd src
$ git clone https://github.com/openpbs/openpbs

$ cd openpbs

インストール方法を確認する.

$ lv INSTALL

PBS のビルトに必要なパッケージを導入する.

$ sudo apt-get install gcc make libtool libhwloc-dev libx11-dev \
   libxt-dev libedit-dev libical-dev ncurses-dev perl \
   postgresql-server-dev-all postgresql-contrib python3-dev tcl-dev tk-dev swig \
   libexpat-dev libssl-dev libxext-dev libxft-dev autoconf \
   automake

PBS を動作させるに必要なパッケージを導入する.

$ sudo apt-get install expat libedit2 postgresql python3 postgresql-contrib sendmail-bin \
   sudo tcl tk libical3

configure スクリプトと Makefile の作成

$ ./autogen.sh

configure

$ ./configure --prefix=/opt/pbs

make & make install

$ make
$ sudo make install

Configure PBS by executing the post-install script

$ sudo /opt/pbs/libexec/pbs_postinstall

Some file permissions must be modified to add SUID privilege.

$ sudo chmod 4755 /opt/pbs/sbin/pbs_iff /opt/pbs/sbin/pbs_rcp

PATH と MANPATH の追加. /etc/skel/.bashrc にも登録しておく.

$ . /etc/profile.d/pbs.sh

# cat /etc/profile.d/pbs.sh >> /etc/skel/.bashrc

設定

  • 10.0.100.24 : 管理ノード / 計算ノード (Jupyter)
    • GPU 3 本.
    • CPU 32 コア.
  • 10.0.100.21 : 計算ノード
    • GPU 1 本.
    • CPU 128 コア
  • 10.0.100.22,23 : 計算ノード
    • GPU 3 本.
    • CPU 32 コア

ホスト名の登録

お互いのホスト名を /etc/hosts に登録しておく.

# /etc/hosts

  10.0.100.21     ncsv1.matsue-ct.jp      ncsv1
  10.0.100.22     ncsv2.matsue-ct.jp      ncsv2
  10.0.100.23     ncsv3.matsue-ct.jp      ncsv3
  10.0.100.24     ncsv4.matsue-ct.jp      ncsv4
  10.0.100.25     nfsv1.matsue-ct.jp      nfsv1
  10.0.100.26     nfsv2.matsue-ct.jp      nfsv2
  10.0.100.27     nfsv3.matsue-ct.jp      nfsv3
  10.0.100.28     nfsv4.matsue-ct.jp      nfsv4

NFS

既に 10.0.100.24:/work が 10.0.100.21 ~ 10.0.100.23 に NFS マウントされている.

管理ノード

PBS_SERVER に管理ノードのホスト名を登録する. 管理のために pbs_server, pbs_sched, pbs_comm を起動する必要がある. 管理ノードでは PBS での計算はさせないので, pbs_mom は起動しない.

# vi /etc/pbs.conf

  PBS_SERVER=ncsv4
  PBS_START_SERVER=1
  PBS_START_SCHED=1
  PBS_START_COMM=1
  PBS_START_MOM=0
  PBS_EXEC=/opt/pbs
  PBS_HOME=/var/spool/pbs
  PBS_CORE_LIMIT=unlimited
  PBS_SCP=/usr/bin/scp

計算実行場所として使う /work は NFS で共有するために, scp ではなく cp コマンドで ジョブ実行結果をコピーするようにする. $usecp の行を追加する.

# vi /var/spool/pbs/mom_priv/config 

  $clienthost ncsv4
  $restrict_user_maxsysid 999
  $usecp *:/work/ /work/

PBS の再起動

# /etc/init.d/pbs restart

起動の確認

# /etc/init.d/pbs status

  pbs_server is pid 33802
  pbs_mom is pid 33567
  pbs_sched is pid 33569
  pbs_comm is 33557

計算ノード

PBS_SERVER に管理ノードのホスト名を入れる. 計算サーバは MON のみ 1 とし (起動するの意味), SERVER, SCHED, COMM は 0 (起動しない) とする. こうすることで pbs_mom のみ起動させる.

# vi /etc/pbs.conf

  PBS_SERVER=ncsv4
  PBS_START_SERVER=0
  PBS_START_SCHED=0
  PBS_START_COMM=0
  PBS_START_MOM=1
  PBS_EXEC=/opt/pbs
  PBS_HOME=/var/spool/pbs
  PBS_CORE_LIMIT=unlimited
  PBS_SCP=/usr/bin/scp

/work を NFS で共有するために, scp ではなく cp コマンドで ジョブ実行結果をコピーするようにする. $usecp の行を追加する. また, 管理ノード名を入れる.

# vi /var/spool/pbs/mom_priv/config 

  $clienthost ncsv4
  $restrict_user_maxsysid 999
  $usecp *:/work/ /work/

PBS の再起動

# /etc/init.d/pbs restart

pbs_mon が起動していることを確認.

# /etc/init.d/pbs status
  pbs_mom is pid 48528

ジョブの作成

管理ノードで実行する.

計算ノードの登録.

# /opt/pbs/bin/qmgr -c "create node ncsv1"
# /opt/pbs/bin/qmgr -c "create node ncsv2"
# /opt/pbs/bin/qmgr -c "create node ncsv3"

デバッグ用の debug という名前のジョブを作る. 制限時間を 10 分とする.

# /opt/pbs/bin/qmgr -c "create queue debug queue_type=execution"
# /opt/pbs/bin/qmgr -c "set queue debug enabled=True"
# /opt/pbs/bin/qmgr -c "set queue debug priority=50"
# /opt/pbs/bin/qmgr -c "set queue debug resources_default.nodes=1"
# /opt/pbs/bin/qmgr -c "set queue debug resources_default.walltime=600"
# /opt/pbs/bin/qmgr -c "set queue debug started=True"

# /opt/pbs/bin/qmgr -c "set server acl_hosts = ncsv4"
# /opt/pbs/bin/qmgr -c "set server default_queue = debug"
# /opt/pbs/bin/qmgr -c "set server scheduling = True"
# /opt/pbs/bin/qmgr -c "set server node_pack = True"

他のユーザのジョブも qstat で見えるようにする.

# /opt/pbs/bin/qmgr -c "set server query_other_jobs = True"

確認

# /opt/pbs/bin/pbsnodes -a

ncsv1
  Mom = ncsv1.matsue-ct.jp
  Port = 15002
  pbs_version = 20.0.0
  ntype = PBS
  state = free
  pcpus = 256

...(略)...

ncsv2
  Mom = ncsv2.matsue-ct.jp
  Port = 15002
  pbs_version = 20.0.0
  ntype = PBS
  state = free
  pcpus = 32

...(略)...

ncsv3
  Mom = ncsv3.matsue-ct.jp
  Port = 15002
  pbs_version = 20.0.0
  ntype = PBS
  state = free
  pcpus = 32

...(略)...

作成したジョブのテスト

$ mkdir /work/jxxxx
$ chown adm01.adm01 /work/jxxxx

$ cd /work/jxxxx

$ echo "sleep 60; echo done" | qsub

$ qstat

  Job id            Name             User              Time Use S Queue
  ----------------  ---------------- ----------------  -------- - -----
  0.ncsv1           STDIN            adm01             00:00:00 R debug   

実行後に標準出力・エラー出力がジョブを実行したディレクトリに作られる.

$ ls
STDIN.e0  STDIN.o0

なお, 各計算ノードで ps aux | grep sleep をすると, 計算ノードでプログラムが 実行されていることがわかる.

また, ホストを指定してジョブを投げることもできる.

$ cd /work/sugiyama   

$ echo "sleep 60; hostname; echo done" | qsub -l select=host=ncsv1
$ echo "sleep 60; hostname; echo done" | qsub -l select=host=ncsv2
$ echo "sleep 60; hostname; echo done" | qsub -l select=host=ncsv3

確認

$ qstat -s

  pbs: 
                                                              Req'd  Req'd   Elap
  Job ID          Username Queue    Jobname    SessID NDS TSK Memory Time  S Time
  --------------- -------- -------- ---------- ------ --- --- ------ ----- - -----
  1.ncsv1         adm01    debug    STDIN       34728   1   1    --  00:10 R 00:00
     Job run at Sat Jan 09 at 17:33 on (ncsv1:ncpus=1)
  2.ncsv1         adm01    debug    STDIN        6473   1   1    --  00:10 R 00:00
     Job run at Sat Jan 09 at 17:33 on (ncsv2:ncpus=1)
  3.ncsv1         adm01    debug    STDIN        7910   1   1    --  00:10 R 00:00
     Job run at Sat Jan 09 at 17:33 on (ncsv3:ncpus=1)

$ cat STDIN.o3

  ncsv3
  done

GPU を計算リソースとして管理するための設定

GPU 数の登録

管理ノードで実行する. リソースとして GPU の数 (ngpus) を登録.

$ sudo /opt/pbs/bin/qmgr -c "create resource ngpus type=long, flag=nh"

管理ノードの設定ファイルの resource: の行に ngpus を追加

$ sudo vi /var/spool/pbs/sched_priv/sched_config

  resources: "ncpus, mem, arch, host, vnode, aoe, eoe, ngpus"

GPU の数の設定

$ sudo /opt/pbs/bin/qmgr -c "set node ncsv1 resources_available.ngpus=1"
$ sudo /opt/pbs/bin/qmgr -c "set node ncsv2 resources_available.ngpus=3"
$ sudo /opt/pbs/bin/qmgr -c "set node ncsv3 resources_available.ngpus=3"

登録内容の確認. ngpus の項目が増えていることがわかる.

$ pbsnodes -a

ncsv1
  Mom = ncsv1.matsue-ct.jp
  ntype = PBS
  state = free
  pcpus = 256
  resources_available.arch = linux
  resources_available.host = ncsv1
  resources_available.mem = 792503920kb
  resources_available.ncpus = 256
  resources_available.ngpus = 1               <===== 注目!
  resources_available.vnode = ncsv1
  resources_assigned.accelerator_memory = 0kb
  resources_assigned.hbmem = 0kb
  resources_assigned.mem = 0kb
  resources_assigned.naccelerators = 0
  resources_assigned.ncpus = 0
  resources_assigned.vmem = 0kb
  resv_enable = True
  sharing = default_shared
  license = l
  last_state_change_time = Thu Dec 10 00:08:24 2020
  last_used_time = Wed Dec  9 23:31:10 2020
 ...(以下略)...

ジョブを投入してみる.

$ echo 'sleep 120; nvidia-smi' | qsub -l select=host=ncsv1:ngpus=1
$ echo 'sleep 120; nvidia-smi' | qsub -l select=host=ncsv1:ngpus=1
$ echo 'sleep 120; nvidia-smi' | qsub -l select=host=ncsv1:ngpus=1
$ echo 'sleep 120; nvidia-smi' | qsub -l select=host=ncsv2:ngpus=1
$ echo 'sleep 120; nvidia-smi' | qsub -l select=host=ncsv2:ngpus=1
$ echo 'sleep 120; nvidia-smi' | qsub -l select=host=ncsv2:ngpus=1
$ echo 'sleep 120; nvidia-smi' | qsub -l select=host=ncsv2:ngpus=1
$ echo 'sleep 120; nvidia-smi' | qsub -l select=host=ncsv2:ngpus=1
$ echo 'sleep 120; nvidia-smi' | qsub -l select=host=ncsv3:ngpus=1
$ echo 'sleep 120; nvidia-smi' | qsub -l select=host=ncsv3:ngpus=1
$ echo 'sleep 120; nvidia-smi' | qsub -l select=host=ncsv3:ngpus=1
$ echo 'sleep 120; nvidia-smi' | qsub -l select=host=ncsv3:ngpus=1
$ echo 'sleep 120; nvidia-smi' | qsub -l select=host=ncsv3:ngpus=1

$ qstat -s
  ncsv4: 
                                                         Req'd  Req'd   Elap
  Job ID          Username Queue    Jobname    SessID NDS TSK Memory Time  S Time
  --------------- -------- -------- ---------- ------ --- --- ------ ----- - -----
  3.ncsv4         sugiyama debug    STDIN      239666   1   1    --  00:10 R 00:00
     Job run at Sat Feb 27 at 13:13 on (ncsv1:ngpus=1:ncpus=1)
  4.ncsv4         sugiyama debug    STDIN         --    1   1    --  00:10 Q   -- 
     Not Running: Insufficient amount of resource: ngpus (R: 1 A: 0 T: 7)
  5.ncsv4         sugiyama debug    STDIN         --    1   1    --  00:10 Q   -- 
     Not Running: Insufficient amount of resource: ngpus (R: 1 A: 0 T: 7)
  6.ncsv4         sugiyama debug    STDIN       20408   1   1    --  00:10 R 00:00
     Job run at Sat Feb 27 at 13:13 on (ncsv2:ngpus=1:ncpus=1)
  7.ncsv4         sugiyama debug    STDIN       20417   1   1    --  00:10 R 00:00
     Job run at Sat Feb 27 at 13:13 on (ncsv2:ngpus=1:ncpus=1)
  8.ncsv4         sugiyama debug    STDIN       20426   1   1    --  00:10 R 00:00
     Job run at Sat Feb 27 at 13:13 on (ncsv2:ngpus=1:ncpus=1)
  9.ncsv4         sugiyama debug    STDIN         --    1   1    --  00:10 Q   -- 
     Not Running: Insufficient amount of resource: ngpus (R: 1 A: 0 T: 7)
  10.ncsv4        sugiyama debug    STDIN       16641   1   1    --  00:10 R 00:00
     Job run at Sat Feb 27 at 13:13 on (ncsv3:ngpus=1:ncpus=1)
  11.ncsv4        sugiyama debug    STDIN       16650   1   1    --  00:10 R 00:00
     Job run at Sat Feb 27 at 13:13 on (ncsv3:ngpus=1:ncpus=1)
  12.ncsv4        sugiyama debug    STDIN       16659   1   1    --  00:10 R 00:00
     Job run at Sat Feb 27 at 13:13 on (ncsv3:ngpus=1:ncpus=1)
  13.ncsv4        sugiyama debug    STDIN         --    1   1    --  00:10 Q   -- 
     Not Running: Insufficient amount of resource: ngpus (R: 1 A: 0 T: 7)

実行結果をみると, GPU 1 本しか指定していないのに, GPU 3 本が全部見えている.

$ cat STDIN.o13 

  Sat Jan  9 17:45:42 2021       
  +-----------------------------------------------------------------------------+
  | NVIDIA-SMI 460.27.04    Driver Version: 460.27.04    CUDA Version: 11.2     |
  |-------------------------------+----------------------+----------------------+
  | 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  Tesla V100S-PCI...  On   | 00000000:3B:00.0 Off |                    0 |
  | N/A   39C    P0    26W / 250W |      0MiB / 32510MiB |      0%      Default |
  |                               |                      |                  N/A |
  +-------------------------------+----------------------+----------------------+
  |   1  Tesla V100S-PCI...  On   | 00000000:86:00.0 Off |                    0 |
  | N/A   40C    P0    27W / 250W |      0MiB / 32510MiB |      0%      Default |
  |                               |                      |                  N/A |
  +-------------------------------+----------------------+----------------------+
  |   2  Tesla V100S-PCI...  On   | 00000000:AF:00.0 Off |                    0 |
  | N/A   40C    P0    27W / 250W |      0MiB / 32510MiB |      0%      Default |
  |                               |                      |                  N/A |
  +-------------------------------+----------------------+----------------------+

  +-----------------------------------------------------------------------------+
  | Processes:                                                                  |
  |  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
  |        ID   ID                                                   Usage      |
  |=============================================================================|
  |  No running processes found                                                 |
  +-----------------------------------------------------------------------------+

cgroups用hookの設定 (cgroupsによるGPUリソースの分離)

PBSProにおいてcgroupsの設定は,ジョブ実行時のhookでpythonスクリプトを実行して実現している. そのPythonスクリプトの設定ファイルを編集するために,まずは現在の設定をpbs_cgroups.json というファイルにエクスポートする.

$ sudo  /opt/pbs/bin/qmgr -c "export hook pbs_cgroups application/x-config default" > pbs_cgroups.json

設定の変更が, 以下のように修正する.

  • devices の enabled をtrueに変更 (cgroupによるデバイスのアクセス制限を有効化)
  • devices の allow にnvidia-uvm等のデバイスを追加 (nvidia-docker関連のデバイスは常にアクセスを許可する)
  • memory のデフォルト値を 20GB に. リザーブを 5GB に.

device の書き方は以下のようになっている. 実際に ls -l してみると nvidia 関連は 195 になっている. <URL:https://www.altairjp.co.jp/pdfs/pbsworks/PBSAdminGuide2020.1.pdf> 参照.

p.578-579
  The allow parameter specifies how access to devices will be controlled. The list consists of entries in one of the follow- ing formats:
  • A single string entry, used verbatim. For example:
  • “b *:* rwm” allows full access (read, write, and mknod) to all block devices
  • “c *:* rwm” allows full access to all character devices

  with that major number.
  • If ls /dev/nvidiactl reported
  “crw-rw-rw- 1 root root 284, 1 Mar 30 14:50 nvidiactl”
  then the line added to the allow file looks like
  “c 284:* rwm”

p.589-590

  15.5.5.1.ii Isolating NVIDIA GPUs
  For NVIDIA GPU isolation to work, you need to restrict access to only those devices assigned to the job. 
  In the “allow” subsection of the devices stion of the configuration file, do not use the broad “c *:* rwm”.

  Make sure that the “allow” section excludes read and write access for the 195 major number (“c 195:* m”), 
  which is what all NVIDIA devices use. Preserve mknod (“m”) access, since other software such as the container hook may need “m” access.

エクスポートしたファイルを以下のように修正する. <URL:https://www.altairjp.co.jp/pdfs/pbsworks/PBSAdminGuide2020.1.pdf> p.590 の記述に従うが, “b *:* m”, “c *:* m”, が入っているとうまくいかなかったので, そこは削除する. また, キャラクタデバイスの 136 は本システムにないので削除しても良さそうな気がするが, とりあえず残しておいた.

$ sudo vi pbs_cgroups.json

     ...(略)...

     "devices" : {
         "enabled"            : true,
         "exclude_hosts"      : [],
         "exclude_vntypes"    : [],
         "allow"              : [
             "c 195:* m",
             "c 136:* rwm",                
             ["fuse","rwm"],
             ["net/tun","rwm"],
             ["tty","rwm"],
             ["ptmx","rwm"],
             ["console","rwm"],
             ["null","rwm"],
             ["zero","rwm"],
             ["full","rwm"],
             ["random","rwm"],
             ["urandom","rwm"],
             ["cpu/0/cpuid","rwm","*"],
             ["nvidia-modeset", "rwm"],
             ["nvidia-uvm", "rwm"],
             ["nvidia-uvm-tools", "rwm"],
             ["nvidiactl", "rwm"]
         ]
     },
     ...(略)...

     "memory" : {
         "enabled"            : true,
         "exclude_hosts"      : [],
         "exclude_vntypes"    : [],
         "soft_limit"         : false,
         "default"            : "50GB",
         "reserve_percent"    : 0,
         "reserve_amount"     : "32GB"     (PBS の使わないメモリ量)
     },
     ...(略)...

作成した設定ファイル pbs_cgroups.json をPBSProにインポートする.

$ sudo /opt/pbs/bin/qmgr -c "import hook pbs_cgroups application/x-config default pbs_cgroups.json"

cgroups のためのhookを有効化

$  sudo /opt/pbs/bin/qmgr -c "set hook pbs_cgroups enabled = true"

PBSを再起動し,設定を反映させる.

$ sudo /etc/init.d/pbs restart

cgroups による制限のテスト

$ cd /work/jxxxx

1 GPU を用いて実行

$ echo 'hostname; echo CUDA_VISIBLE_DEVICES=$CUDA_VISIBLE_DEVICES; nvidia-smi ' | qsub -l select=1:host=ncsv1:ngpus=1 -N test1
$ echo 'hostname; echo CUDA_VISIBLE_DEVICES=$CUDA_VISIBLE_DEVICES; nvidia-smi ' | qsub -l select=1:host=ncsv2:ngpus=1 -N test2
$ echo 'hostname; echo CUDA_VISIBLE_DEVICES=$CUDA_VISIBLE_DEVICES; nvidia-smi ' | qsub -l select=1:host=ncsv3:ngpus=1 -N test3

$ cat test3.o16

  ncsv3
  CUDA_VISIBLE_DEVICES=GPU-a478fcef-90a8-f595-6260-85b310526d6d
  Sat Feb 27 13:22:15 2021       
  +-----------------------------------------------------------------------------+
  | NVIDIA-SMI 460.32.03    Driver Version: 460.32.03    CUDA Version: 11.2     |
  |-------------------------------+----------------------+----------------------+
  | 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  Tesla V100S-PCI...  On   | 00000000:AF:00.0 Off |                    0 |
  | N/A   41C    P0    27W / 250W |      0MiB / 32510MiB |      0%      Default |
  |                               |                      |                  N/A |
  +-------------------------------+----------------------+----------------------+

  +-----------------------------------------------------------------------------+
  | Processes:                                                                  |
  |  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
  |        ID   ID                                                   Usage      |
  |=============================================================================|
  |  No running processes found                                                 |
  +-----------------------------------------------------------------------------+

2 GPU を用いて実行

$ echo 'hostname; echo CUDA_VISIBLE_DEVICES=$CUDA_VISIBLE_DEVICES; nvidia-smi ' | qsub -l select=1:host=ncsv2:ngpus=2 -N test

$ cat test.o17

  ncsv2
  CUDA_VISIBLE_DEVICES=GPU-c6d14151-65dd-a54b-accb-7419b3a7a457,GPU-c0cf94f2-e63f-2c04-f286-43b7d3cd746f
  Sat Feb 27 13:24:07 2021       
  +-----------------------------------------------------------------------------+
  | NVIDIA-SMI 460.32.03    Driver Version: 460.32.03    CUDA Version: 11.2     |
  |-------------------------------+----------------------+----------------------+
  | 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  Tesla V100S-PCI...  On   | 00000000:3B:00.0 Off |                    0 |
  | N/A   37C    P0    25W / 250W |      0MiB / 32510MiB |      0%      Default |
  |                               |                      |                  N/A |
  +-------------------------------+----------------------+----------------------+
  |   1  Tesla V100S-PCI...  On   | 00000000:AF:00.0 Off |                    0 |
  | N/A   37C    P0    28W / 250W |      0MiB / 32510MiB |      0%      Default |
  |                               |                      |                  N/A |
  +-------------------------------+----------------------+----------------------+

  +-----------------------------------------------------------------------------+
  | Processes:                                                                  |
  |  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
  |        ID   ID                                                   Usage      |
  |=============================================================================|
  |  No running processes found                                                 |
  +-----------------------------------------------------------------------------+

docker からの利用. 前もってジョブを実行するユーザを計算ノードの docker グループに加えておく必要がある.

計算ノード$ sudo usermod -aG docker sugiyama

PBS では GPU 数を 1 に制限し, docker では特に GPU 数に制限をかけないで実行してみる. cgroups でうまく docker に制限をかけられていないことがわかる.

$ echo 'sleep 30; docker run --gpus all --rm nvidia/cuda nvidia-smi -L' | qsub -l select=1:host=ncsv3:ngpus=1

$ cat STDIN.o46

  GPU 0: Tesla V100S-PCIE-32GB (UUID: GPU-d19054e2-f863-3da6-c30b-f299bb053a27)
  GPU 1: Tesla V100S-PCIE-32GB (UUID: GPU-cf4c7b4a-6a73-1407-4d80-c5a8000eca26)
  GPU 2: Tesla V100S-PCIE-32GB (UUID: GPU-a478fcef-90a8-f595-6260-85b310526d6d)

なお,計算ノードにインストールされていない docker イメージを指定すると, 計算ノードが自動でそのイメージをインストールする.

$ cat STDIN.e46

  Unable to find image 'nvidia/cuda:latest' locally
  latest: Pulling from nvidia/cuda
  da7391352a9b: Pulling fs layer
  ...(以下略)...  
注) PBS から docker を利用する方法として, PBS で docker のコンテナエンジンを使う設定を行う方法もあるらしい. <URL:https://www.altairjp.co.jp/pdfs/pbsworks/PBSAdminGuide2020.1.pdf> の p.597 の 16 章を参照のこと.

docker での GPU 制限

<URL:https://github.com/puyogo-suzuki/gpudocker-inside-batchsys> を利用する (Thanks to Suzuki-kun).

元々のパスを確認

$ which docker

  /usr/bin/docker

各ノードで以下を実行する.

$ wget https://raw.githubusercontent.com/puyogo-suzuki/gpudocker-inside-batchsys/main/docker.sh
$ sudo mv docker.sh /usr/local/bin/docker
$ sudo chmod 755 /usr/local/bin/docker

パスが正しく設定されているか確認する.

$ which docker

  /usr/local/bin/docker

但し, /usr/local/bin/docker の 54 行目はフルパス (/usr/bin/docker) に書き換えた.

実際に試してみる. GPU 数に制限がかかっていることがわかる.

$ echo 'hostname; docker run --gpus all --rm nvidia/cuda nvidia-smi -L' | qsub -l select=1:host=ncsv2:ngpus=119.ncsv4
$ echo 'hostname; docker run --gpus all --rm nvidia/cuda nvidia-smi -L' | qsub -l select=1:host=ncsv3:ngpus=120.ncsv4
$ echo 'hostname; docker run --gpus all --rm nvidia/cuda nvidia-smi -L' | qsub -l select=1:host=ncsv3:ngpus=2

$ cat STDIN.o19

  ncsv2
  GPU 0: Tesla V100S-PCIE-32GB (UUID: GPU-c0cf94f2-e63f-2c04-f286-43b7d3cd746f)

$ cat STDIN.o20

  ncsv3
  GPU 0: Tesla V100S-PCIE-32GB (UUID: GPU-d19054e2-f863-3da6-c30b-f299bb053a27)

$ cat STDIN.o21

  ncsv3
  GPU 0: Tesla V100S-PCIE-32GB (UUID: GPU-d19054e2-f863-3da6-c30b-f299bb053a27)
  GPU 1: Tesla V100S-PCIE-32GB (UUID: GPU-cf4c7b4a-6a73-1407-4d80-c5a8000eca26)

queue の追加設定

デフォルトのキューを削除.

# /opt/pbs/bin/qmgr -c "delete queue workq"     

CPU メイン (GPU なし) のキューの作成

# /opt/pbs/bin/qmgr -c "create queue cpu queue_type=execution"
# /opt/pbs/bin/qmgr -c "set queue cpu enabled=True"
# /opt/pbs/bin/qmgr -c "set queue cpu priority=30"
# /opt/pbs/bin/qmgr -c "set queue cpu resources_default.nodes=1"
# /opt/pbs/bin/qmgr -c "set queue cpu resources_default.ncpus=1"
# /opt/pbs/bin/qmgr -c "set queue cpu resources_default.ngpus=0"
# /opt/pbs/bin/qmgr -c "set queue cpu resources_default.walltime=72:00:00"
# /opt/pbs/bin/qmgr -c "set queue cpu resources_max.nodes=1"
# /opt/pbs/bin/qmgr -c "set queue cpu resources_max.ncpus=64"
# /opt/pbs/bin/qmgr -c "set queue cpu resources_max.ngpus=0"
# /opt/pbs/bin/qmgr -c "set queue cpu max_group_run=2"
# /opt/pbs/bin/qmgr -c "set queue cpu started=True"
# /opt/pbs/bin/qmgr -c "set queue cpu resources_default.mem=100gb"

GPU 利用のキューの作成

# /opt/pbs/bin/qmgr -c "create queue gpu queue_type=execution"
# /opt/pbs/bin/qmgr -c "set queue gpu enabled=True"
# /opt/pbs/bin/qmgr -c "set queue gpu priority=30"
# /opt/pbs/bin/qmgr -c "set queue gpu resources_default.nodes=1"
# /opt/pbs/bin/qmgr -c "set queue gpu resources_default.ncpus=1"
# /opt/pbs/bin/qmgr -c "set queue gpu resources_default.ngpus=1"
# /opt/pbs/bin/qmgr -c "set queue gpu resources_max.nodes=1"
# /opt/pbs/bin/qmgr -c "set queue gpu resources_max.ncpus=6"
# /opt/pbs/bin/qmgr -c "set queue gpu resources_max.ngpus=1"
# /opt/pbs/bin/qmgr -c "set queue gpu resources_default.walltime=72:00:00"
# /opt/pbs/bin/qmgr -c "set queue gpu max_group_run=3"
# /opt/pbs/bin/qmgr -c "set queue gpu started=True"
# /opt/pbs/bin/qmgr -c "set queue gpu resources_default.mem=50gb"

確認

$ /opt/pbs/bin/qmgr -c "p s"

  #  /opt/pbs/bin/qmgr -c "p s"
  #
  # Create resources and set their properties.
  #
  #
  # Create and define resource ngpus
  #
  create resource ngpus
  set resource ngpus type = long
  set resource ngpus flag = hn
  #
  # Create queues and set their attributes.
  #
  # 
  # Create and define queue debug
  #
  create queue debug
  set queue debug queue_type = Execution
  set queue debug Priority = 50
  set queue debug resources_default.ncpus = 1
  set queue debug resources_default.nodect = 1
  set queue debug resources_default.nodes = 1
  set queue debug resources_default.walltime = 00:10:00
  set queue debug enabled = True
  set queue debug started = True
  set queue debug started = True
  #
  # Create and define queue cpu
  #
  create queue cpu
  set queue cpu queue_type = Execution
  set queue cpu Priority = 30
  set queue cpu resources_max.ncpus = 64
  set queue cpu resources_max.ngpus = 0
  set queue cpu resources_max.nodes = 1
  set queue cpu resources_default.mem = 20gb
  set queue cpu resources_default.ncpus = 1
  set queue cpu resources_default.ngpus = 0
  set queue cpu resources_default.nodect = 1
  set queue cpu resources_default.nodes = 1
  set queue cpu resources_default.walltime = 48:00:00
  set queue cpu max_group_run = 2
  set queue cpu enabled = True
  set queue cpu started = True
  #
  # Create and define queue gpu
  #
  create queue gpu
  set queue gpu queue_type = Execution
  set queue gpu Priority = 30
  set queue gpu resources_max.ncpus = 6
  set queue gpu resources_max.ngpus = 1
  set queue gpu resources_max.nodes = 1
  set queue gpu resources_default.mem = 20gb
  set queue gpu resources_default.ncpus = 1
  set queue gpu resources_default.ngpus = 1
  set queue gpu resources_default.nodect = 1
  set queue gpu resources_default.nodes = 1
  set queue gpu resources_default.walltime = 48:00:00
  set queue gpu max_group_run = 3
  set queue gpu enabled = True
  set queue gpu started = True
  #
  # Set server attributes.
  #
  set server scheduling = True
  set server acl_hosts = ncsv1
  set server default_queue = debug
  set server log_events = 511
  set server mailer = /usr/sbin/sendmail
  set server mail_from = adm
  set server query_other_jobs = True
  set server resources_default.ncpus = 1 
  set server default_chunk.ncpus = 1
  set server scheduler_iteration = 600
  set server node_pack = True
  set server resv_enable = True
  set server node_fail_requeue = 310
  set server max_array_size = 10000
  set server pbs_license_min = 0
  set server pbs_license_max = 2147483647
  set server pbs_license_linger_time = 31536000
  set server eligible_time_enable = False
  set server max_concurrent_provision = 5
  set server max_job_sequence_id = 9999999


#  /opt/pbs/bin/pbsnodes -aS

  vnode           state           OS       hardware host            queue        mem     ncpus   nmics   ngpus  comment
  --------------- --------------- -------- -------- --------------- ---------- -------- ------- ------- ------- ---------
  ncsv1           free            --       --       ncsv1           --            756gb     128       0       1 --
  ncsv2           free            --       --       ncsv2           --            251gb      16       0       3 --
  ncsv3           free            --       --       ncsv3           --            251gb      16       0       3 --

# /opt/pbs/bin/qstat -Qf

  Queue: debug
      queue_type = Execution
      Priority = 50
      total_jobs = 0
      state_count = Transit:0 Queued:0 Held:0 Waiting:0 Running:0 Exiting:0 Begun
          :0 
      resources_default.ncpus = 1
      resources_default.nodect = 1
      resources_default.nodes = 1
      resources_default.walltime = 00:10:00
      resources_assigned.ncpus = 0
      resources_assigned.nodect = 0
      enabled = True
      started = True

  Queue: cpu
      queue_type = Execution
      Priority = 30
      total_jobs = 0
      state_count = Transit:0 Queued:0 Held:0 Waiting:0 Running:0 Exiting:0 Begun
          :0 
      resources_max.ncpus = 64
      resources_max.ngpus = 0
      resources_max.nodes = 1
      resources_default.mem = 100gb
      resources_default.ncpus = 1
      resources_default.ngpus = 0
      resources_default.nodect = 1
      resources_default.nodes = 1
      resources_default.walltime = 72:00:00
      max_group_run = 2
      enabled = True
      started = True

   Queue: gpu
      queue_type = Execution
      Priority = 30
      total_jobs = 0
      state_count = Transit:0 Queued:0 Held:0 Waiting:0 Running:0 Exiting:0 Begun
          :0 
      resources_max.ncpus = 6
      resources_max.ngpus = 1
      resources_max.nodes = 1
      resources_default.mem = 50gb
      resources_default.ncpus = 1
      resources_default.ngpus = 1
      resources_default.nodect = 1
      resources_default.nodes = 1
      resources_default.walltime = 72:00:00
      max_group_run = 3
      enabled = True
      started = True

ジョブのテスト (C, Fortran)

以下で使うプログラムとスクリプトは /work/SAMPLES/CPU に置いてある.

C + MPI

$ vi c_mpi-hello.c

  #include "mpi.h"
  #include <stdio.h>
  int main(int argc, char **argv)
  {
    int n, myid, numprocs, i;
    MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
    MPI_Comm_rank(MPI_COMM_WORLD,&myid);
    printf ("Hello World %d \n", myid);
    MPI_Finalize();
 }

ノード数を select に, 全 CPU コアを ncpus に, MPI の並列数を mpiprocs に指定する. ncpus = mpiprocs にすること.

$ vi c_mpi-hello.sh 

  #!/bin/sh
  #PBS -q cpu
  #PBS -l select=1:ncpus=8:mpiprocs=8

  cd $PBS_O_WORKDIR
  mpicc -o c_mpi-hello c_mpi-hello.c
  mpirun ./c_mpi-hello

実行と確認

$ qsub c_mpi-hello.sh

$ cat c_mpi-hello.sh.o52 

  Hello World 6 
  Hello World 0 
  Hello World 8 
  Hello World 5 
  Hello World 9 
  Hello World 4 
  Hello World 1 
  Hello World 2 
  Hello World 3 
  Hello World 7 

Fortran + MPI

$ vi mpi-hello.f90 

   program sample00
    use mpi
    implicit none
    integer :: myrank, numprocs, ierr
    call MPI_INIT(ierr)
    call MPI_COMM_RANK(MPI_COMM_WORLD, myrank, ierr)
    call MPI_COMM_SIZE(MPI_COMM_WORLD, numprocs, ierr)
    print *, repeat('#',myrank+1)
    call MPI_FINALIZE(ierr)
  end program sample00 

ノード数を select に, 全 CPU コア数を ncpus に, MPI の並列数を mpiprocs に指定する. ncpus = mpiprocs にすること.

$ vi mpi-hello.sh

  #!/bin/sh
  #PBS -q cpu
  #PBS -l select=1:ncpus=8:mpiprocs=8

  cd $PBS_O_WORKDIR
  mpif90 -o mpi-hello mpi-hello.f90
  mpirun ./mpi-hello

実行と確認.

$ qsub  mpi-hello.sh

$ cat mpi-hello.sh.o53

   #
   ##
   ###
   ####
   #####

C + OpenMP

$ cat c_omp-hello.c

  #include <stdio.h>
  #include <omp.h>
  int main()
    {
    #pragma omp parallel
      {
      printf("Hello World from %d of %d\n",
      omp_get_thread_num(), omp_get_num_threads());
      }
  }

ノード数を select に, 全 CPU コア数を ncpus に, OMP の並列数を ompthreads に指定する. ncpus = ompthreads にすること.

$ vi c_omp-hello.sh

  #!/bin/sh
  #PBS -q cpu
  #PBS -l select=1:ncpus=8:ompthreads=8

  cd $PBS_O_WORKDIR
  gcc -fopenmp -o c_omp-hello c_omp-hello.c
  ./c_omp-hello

実行と確認.

$ qsub c_omp-hello.sh

$ cat c_omp-hello.sh.o59

  Hello World from 6 of 10
  Hello World from 0 of 10
  Hello World from 9 of 10
  Hello World from 7 of 10
  Hello World from 3 of 10
  Hello World from 1 of 10
  Hello World from 4 of 10
  Hello World from 8 of 10
  Hello World from 2 of 10
  Hello World from 5 of 10

Fortran + OpenMP

$ cat omp-hello.f90 

  program helloOpenMP
    !$ use omp_lib
      implicit none
      print *, "START"
    !$omp parallel
      print *, "Hello! N =", omp_get_num_threads(), " and I am ", omp_get_thread_num()
    !$omp end parallel
      print *, "END"
  end

ノード数を select に, 全 CPU コア数を ncpus に, OMP の並列数を ompthreads に指定する. ncpus = ompthreads にすること.

$ cat omp-hello.sh

  #!/bin/sh
  #PBS -q cpu
  #PBS -l select=1:ncpus=8:ompthreads=8

  cd $PBS_O_WORKDIR
  gfortran -fopenmp -o omp-hello omp-hello.f90
  ./omp-hello

実行と確認

$ qsub omphello.sh 

$ cat omphello.sh.o57

   START
   Hello! N =          10  and I am            0
   Hello! N =          10  and I am            5
   Hello! N =          10  and I am            8
   Hello! N =          10  and I am            9
   Hello! N =          10  and I am            4
   Hello! N =          10  and I am            7
   Hello! N =          10  and I am            3
   Hello! N =          10  and I am            6
   Hello! N =          10  and I am            2
   Hello! N =          10  and I am            1
   END

C + MPI + OpenMP

$ cat c_mpi-omp-hello.f90 

  #include <stdio.h>
  #include <mpi.h>
  #include <omp.h>

  int main(int argc, char *argv[]) {
    int numprocs, rank, namelen;
    char processor_name[MPI_MAX_PROCESSOR_NAME];
    int iam = 0, np = 1;

    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Get_processor_name(processor_name, &namelen);

    //omp_set_num_threads(4);

  #pragma omp parallel default(shared) private(iam, np)
    {
      np = omp_get_num_threads();
      iam = omp_get_thread_num();
      printf("Hello from thread %d out of %d from process %d out of %d on %s\n", iam, np, rank, numprocs, processor_name);
    }

    MPI_Finalize();
  }

ノード数を select に, 全 CPU コア数を ncpus に, MPI の並列数を mpiprocs に, OMP の並列数を ompthreads に指定する. ncpus = mpiprocs * ompthreads にすること.

$ cat c_mpi-omp-hello.sh

  #!/bin/sh
  #PBS -q cpu
  #PBS -l select=1:ncpus=8:mpiprocs=4:ompthreads=2

  cd $PBS_O_WORKDIR
  mpicc -fopenmp -o c_mpi-omp-hello c_mpi-omp-hello.c
  mpirun ./c_mpi-omp-hello

実行と確認

$ qsub c_mpi-omp-hello.sh

$ cat c_mpi-omp-hello.sh.o124 

  Hello from thread 0 out of 2 from process 0 out of 4 on ncsv1
  Hello from thread 1 out of 2 from process 0 out of 4 on ncsv1
  Hello from thread 0 out of 2 from process 1 out of 4 on ncsv1
  Hello from thread 1 out of 2 from process 1 out of 4 on ncsv1
  Hello from thread 0 out of 2 from process 3 out of 4 on ncsv1
  Hello from thread 1 out of 2 from process 3 out of 4 on ncsv1
  Hello from thread 0 out of 2 from process 2 out of 4 on ncsv1
  Hello from thread 1 out of 2 from process 2 out of 4 on ncsv1

テスト: venv 環境

以下のようなスクリプトを用意する.

#!/bin/sh
#PBS -q gpu
#PBS -l select=1:ncpus=1:ngpus=1

cd $PBS_O_WORKDIR
hostname
. venv-chainer/venv/bin/activate
nvidia-smi -L
python chainer-sample.py -g 0
deactivate

実行する. 別の端末で nvidia-smi を実行すると, GPU で実行されていることが確認できる.

$ qsub venv-chainer.sh

結果の表示

$ cat venv-chainer.sh.o80 

  ncsv1
  GPU 0: Tesla V100S-PCIE-32GB (UUID: GPU-8a30728d-e5e5-a945-aeeb-410b8dd12855)
  Device: @cupy:0
  # unit: 1000
  # Minibatch-size: 100
  # epoch: 20

  epoch       main/loss   validation/main/loss  main/accuracy  validation/main/accuracy  elapsed_time
  0                       2.30979                              0.106                     0.93721       
  1           0.190622    0.100971              0.942067       0.9689                    3.24492       
  2           0.0728783   0.076452              0.977199       0.977                     5.40519       
  ...(以下略)...

テスト : docker 環境

以下のようなスクリプトを用意する.

#!/bin/sh
#PBS -q gpu
#PBS -l select=1:ncpus=1:ngpus=1

cd $PBS_O_WORKDIR
docker image build -t chainer/sugiyama mydocker
docker run --gpus all -v $PWD:/tmp -w /tmp --rm chainer/sugiyama python3 chainer-sample.py -g 0

実行する. 別の端末で nvidia-smi を実行すると, GPU で実行されていることが確認できる.

$ qsub mydocker.sh

結果の表示

$ cat mydocker.sh.o81

  Sending build context to Docker daemon  2.048kB
  Step 1/2 : FROM chainer/chainer
   ---> 2c0563bd9e2b
  Step 2/2 : RUN pip3 install matplotlib
   ---> Running in 01f3df21f1bd
  Collecting matplotlib

  ...(略)...

  Device: @cupy:0
  # unit: 1000
  # Minibatch-size: 100
  # epoch: 20

  epoch       main/loss   validation/main/loss  main/accuracy  validation/main/accuracy  elapsed_time
  0                       2.30979                              0.106                     0.93721       
  1           0.190622    0.100971              0.942067       0.9689                    3.24492       
  2           0.0728783   0.076452              0.977199       0.977                     5.40519       
  ...(以下略)...

docker は内部では root 権限で動いているようで, ファイルやディレクトリを作成すると 所有者が root になってしまう. とりあえずの対処法としては, プログラム中で umask 002 する (group に write 権限をつける) と簡単かもしれない.

...(略)...

import os

...(略)...

   os.umask(0o002)

...(略)...

覚書

現在は使っていないが使うと良さそうな設定

各キューを実行できるホストを登録する. 設定すると, 当該キューは設定されたホストでしか実行できなくなる.

# /opt/pbs/bin/qmgr -c "set node ncsv2 queue = gpu"
# /opt/pbs/bin/qmgr -c "set node ncsv3 queue = gpu"
# /opt/pbs/bin/qmgr -c "set node ncsv4 queue = gpu"

キューの実行数の制限

# qmgr -c "set queue QNAME max_running = 10"

各キューについてユーザの実行可能数を制限

# qmgr -c "set queue QNAME max_user_run = 3"

各キューについてユーザの実行可能数な制限を解除

# qmgr -c "unset queue QNAME max_user_run

テスト (メールの送信)

以下のように -M, -m オプションをつけると, 実行開始時・終了時・何らかのエラーの時, にメールを送ってくれる. 但し, 学内宛のメールしか出せない (おそらく上流で 25 ポートが開いていない).

$ cat mpi-hello.sh

  #!/bin/sh
  #PBS -q debug
  #PBS -M XXXX@matsue-ct.jp
  #PBS -m abe
  #PBS -l select=1:ncpus=5:ngpus=0:host=ncsv3
  cd $PBS_O_WORKDIR
  mpiexec -launcher fork -n 5 ./mpihello

CPU の制限?

  • ncpus = mpiprocs * ompthreads であることが保証されていない?
  • CPU コア数は PBS で適切に管理されている? どうやって確認するかな?

参考