コンテンツにスキップ

3. User Mode Scheduler

3.1. User Mode Schedulerとは

User Mode Scheduler(以降では簡単のためUMSと記載)は1つのジョブの内の複数のプロセスを効率的にスケジュールするスケジューラーです。 TSUBAME 4でも採用されているバッチジョブスケジューラーではジョブの単位でプログラムを実行しますが、 ジョブは1つのプロセスで構成される単純なもの(例: ジョブスクリプトの中でプログラムをフォアグラウンド実行)だけではなく、 複数のプロセスで構成される(例: ジョブスクリプトの中で複数のプログラムをバックグラウンド実行)ものもあります。 UMSは後者の複数のプロセスで構成されるジョブ向けにバッチジョブスケジューラーが提供していなかったプロセスレベルのスケジュール機能します。

UMSはバッチジョブスケジューラーとは別にプログラムを投入して即時実行する機能を提供しており、 この機能によって実行されたプログラムのスケジューリングを行います。 ジョブに割り当てられたホストで複数のプログラムを実行する際、 バッチジョブスケジューラーでは1つのジョブスクリプトの中に全てを記述する必要がありましたが、 UMSでは任意のタイミングでジョブに割り当てられたホストに対してプログラムを投入・実行できるためプログラムを論理的に分割して記述することが可能です。 投入されたプログラムはUMSにより即時実行されます。 また、複数のプログラムの実行を1つのグループにまとめるグルーピング機能も提供しており、 UMSは個々のプログラム単位ではなくこの論理的にまとまったグループ単位でスケジューリングを行います。

3.2. 使い方

Info

本ページのコマンドライン例では、以下の表記を使用します。
[login]$ : ログインノード
[rNnN]$ : 計算ノード
[login/rNnN]$ : ログインノードまたは計算ノード
[yourPC]$ : ログインノードへの接続元環境

3.2.1. 前提条件

ums-から始まるUMSのコマンドはすべてTSUBAME 4のログインノードで実行します。 ログインノードへのログイン方法はログイン方法をご参照ください。

UMSコマンドは資源タイプnode_fで実行中のジョブに対してのみお使いいただけます。 TSUBAME4でのジョブの実行方法や状態確認に関してはジョブの投入ジョブの状態確認をご参照ください。 以下ではUMSを適用する実行中のジョブのIDを[job-id]、ジョブ名を[job-name]とします。

UMSのコマンドを実行する際には、以下のコマンドでモジュールをロードしてください。

[login]$ module purge
[login]$ module load ums

3.2.2. 起動

UMSを使う場合はまず ums-start コマンドで[job-id]のジョブ内でUMSを起動します。

[login]$ ums-start --job [job-id]

UMSの起動が完了すると、[job-id]のジョブに対して以下のUMSコマンドが実行できるようになります。

  • ums-hosts: [job-id]のジョブのホスト一覧を表示します
  • ums-list: [job-id]のジョブで実行中のプログラム一覧を表示します
  • ums-submit: [job-id]のジョブにプログラムを投入します

Tips

UMSを実行するためのジョブを起動するためのジョブスクリプトには相当の長さの sleep コマンド等を記載しておき、利用後には qdelジョブを削除してください。

3.2.3. プログラムを割り当てるホスト一覧の表示

UMSの起動後、ログインノードで以下のums-hostsコマンドを実行すると、[job-id]のジョブに割り当てられたホスト一覧を表示します。

[login]$ ums-hosts --job [job-id]
r1n1,r1n2   # ジョブによって表示は異なります
結果はコンマ区切りで表示されます。

MPIプログラムを実行する場合はこちらのコマンドを使用します。詳しくはTips - MPIプログラムの実行をご参照ください。

3.2.4. プログラムの投入

UMSの起動後、UMSにプログラムを投入する場合は、ログインノードで以下のums-submitコマンドを実行します。

[login]$ ums-submit \
    --group [group] \
    --job [job-id] \
    --name [name] \
    --rank [rank] \
    --stderr-log [stderr-log-path] \
    --stdout-log [stdout-log-path] \
    [command arguments...]

ums-submitコマンドのオプションは以下になります。

オプション名 必須 デフォルト値 説明
--group [group] いいえ (なし) プログラムが所属するグループ名
--job [job-id] はい (なし) ジョブのID
--name [name] はい (なし) ums-listコマンドで表示されるプログラム名
--rank [rank] いいえ 0 プログラムを実行するホストの番号
--stderr-log [stderr-log-path] いいえ /dev/null 標準エラー出力の保存先
--stdout-log [stdout-log-path] いいえ /dev/null 標準出力の保存先

ums-submitコマンドを実行すると、[rank]で指定されたホストに[command arguments...]のプログラムを非同期に実行します。 [rank]は0以上かつ[job-id]のジョブに割り当てられたノード数未満の整数値で指定します。

--groupオプションをつけるとプログラムは指定したグループに所属し、OSによるスケジューリングの他にUMSによってもスケジューリングされます。 UMSでは実行中のグループが2つ以上ある場合、1秒ごとにLeast Recently Used (LRU)方式で実行するグループの切り替え、つまり、最も実行されていないグループを実行し、それ以外のグループについては一時停止を行います。

3.2.5. 実行中のプログラム一覧の表示

ログインノードでums-listコマンドを実行すると、[job-id]のジョブ内で実行されているプログラムを表示します。

[login]$ ums-list --job [job-id]
{"[name-0]":"r1n1","[name-1]":"r1n2"}   # 実行状況に応じて表示は異なります
結果はjson形式の辞書型で表示されます。 辞書のキーはums-submitコマンドの--nameオプションで指定したプログラム名、値は実行しているノード名になります。

3.3. Tips

3.3.1. ログ

ums-startコマンドでUMSを起動すると、[job-id]のジョブに割り当てられたノードのどこか1つでums-controllerを起動し、 ums-controllerは[job-id]のジョブに割り当てられた全てのノードでums-workerを起動します。 ums-controllerとums-workerのログは $HOME/.ums/log/[job-name]-[job-id]/ 以下に作成され、ファイル名はそれぞれ ums-controller.logworker-[rank].log です。

UMSでは以下のフォーマットでログを記録します。

[datetime] [component] [severity] [log]
[datetime]はログを記録した時刻で[YYYY-MM-DD hh:mm:ss.sss]のフォーマットです。 [component]はログを記録したコンポーネント名で[ums-contrller]または[ums-worker]になります。 [severity]はログの深刻度で[info]や[error]などになります。

3.3.1.1. ums-controller起動時のログ

[2025-01-01 00:00:00.000] [ums-controller] [info] job_id: [job-id]
[2025-01-01 00:00:00.000] [ums-controller] [info] job_name: [job-name]
[2025-01-01 00:00:00.000] [ums-controller] [info] A worker on [host] (task: 0, rank: [rank]) has started.
...
ジョブID[job-id]やジョブ名[job-name]、ums-workerが動作するホスト名[host]とそのホストのランク[rank]が記録されます。

3.3.1.2. ums-worker起動時のログ

[2025-01-01 00:00:00.000] [ums-worker] [info] job_id: [job-id]
[2025-01-01 00:00:00.000] [ums-worker] [info] job_name: [job-name]
[2025-01-01 00:00:00.000] [ums-worker] [info] job_world_rank: [rank]
[2025-01-01 00:00:00.000] [ums-worker] [info] job_world_size: [host-count]
ジョブID[job-id]やジョブ名[job-name]、このworkerが動作しているホストのランク[rank]と全ホスト数[host-count]が記録されます。

3.3.1.3. ums-submit時のums-controllerのログ

[2025-01-01 00:00:00.000] [ums-controller] [info] submit work: [name]: [host]
[2025-01-01 00:00:00.000] [ums-controller] [info] launch work: [name]: [host]: [pid]
投入したプログラム名[name]とそのプログラムを実行するホスト名[host]、実行しているホストでのProcess ID(PID)[pid]が記録されます。

3.3.1.4. ums-submit時のums-workerのログ

[2025-01-01 00:00:00.000] [ums-worker] [info] submit work: [name]: [host]
投入したプログラム名[name]とそのプログラムを実行するホスト名[host]が記録されます。

3.3.1.5. グループ切り替え時のログ

[2025-01-01 00:00:00.000] [ums-worker] [info] suspend: [suspend-name]: [suspend-pid]
[2025-01-01 00:00:00.000] [ums-worker] [info] resume: [resume-name]: [resume-pid]
一時停止したプログラム名[suspend-name]とそのPID[suspend-pid]、再開したプログラム名[resume-name]とそのPID[resume-pid]が記録されます。

3.3.1.6. プログラム完了時のums-controllerのログ

[2025-01-01 00:00:00.000] [ums-controller] [info] complete: [name]: [result]
完了したプログラム名[name]とその結果[result]がsuccessまたはfailedとして記録されます。

グループの最後のプログラムが完了した際には以下のように完了したグループ名[group]も記録されます。

[2025-01-01 00:00:00.000] [ums-controller] [info] complete work: group [group]: complete

3.3.1.7. プログラム完了時のums-workerのログ

[2025-01-01 00:00:00.000] [ums-worker] [info] complete: [name]: [result]
完了したプログラム名[name]とその結果[result]がsuccessまたはfailedとして記録されます。

3.3.2. MPIプログラムの実行

UMSでMPIプログラムを実行する際、MPIプログラムを実行するホスト一覧はums-hostsコマンドを使って指定します。 以下はums-submitコマンドでMPIプログラムを実行するシェルスクリプトのサンプルです。

#!/bin/sh

module load openmpi
module load ums
mpirun --host `ums-hosts --job [job-id]` [command arguments...]
module unload ums
module unload openmpi

3.3.3. プログラムの完了待ち

ums-submitコマンドは指定されたコマンドの実行をリクエストするだけでコマンドが完了するまでの待ち合わせは行いません。 コマンドの待ち合わせを行う場合は定期的にums-listコマンドを実行し、プログラム名が実行中のプログラム一覧に含まれるかを確認します。 以下は--nameオプションに[name]を指定したプログラムの完了待ちを行うシェルスクリプトのサンプルです。

#!/bin/sh

module load ums
while [ `ums-list --job [job-id] | jq 'with_entries(select(.key|test("^[name]$"))) | length'` -ne 0 ]
do
    sleep 1
done
module unload ums

3.4. 使用例

3.4.1. 使用例 1: プログラムの実行

3.4.1.1. シナリオ

UMSを使いHello World!と表示するプログラムを1つのホストで実行します。

3.4.1.2. 実行例

まずTSUBAME上で実行するバッチジョブスクリプトを作成します。 今回の例では $HOME/hello-world-job に以下の何もしないバッチジョブスクリプトを作成します。

#!/bin/sh
#$ -l node_f=2          # ノード数
#$ -l h_rt=00:05:00     # 最大実行時間
#$ -N hello-world-job   # ジョブ名
#$ -o /dev/null
#$ -e /dev/null

sleep infinity

次に、以下のスクリプトをログインノードで実行し、$HOME/hello-world-jobの投入およびジョブの実行待ちを行います。

#!/bin/sh
qsub -g [tsubame-group] $HOME/hello-world-job

while [ `qstat -j hello-world-job -json | jq -r '.job_info[0].job_array_tasks[0].job_state // "?"'` != "r" ]
do
  sleep 1
done
ここで[tsubame-group]には所属されているTSUBAMEグループを指定してください。

ジョブが実行状態になったのちに、qstatコマンドを用いて[job-id]を確認してUMSを起動します。

[login]$ ums-start --job [job-id]

次にHello, world!と表示するプログラムを作成します。 今回の例では $HOME/hello-world に以下のシェルスクリプトを作成します。

#!/bin/sh

echo Hello, world!

次に、以下のスクリプトをログインノードで実行し、$HOME/hello-worldの投入します。

#!/bin/sh

module load ums
ums-submit \
    --job [job-id] \
    --name hello-world \
    --stdout-log $HOME/hello-world-stdout.log \
    /bin/bash $HOME/hello-world
module unload ums
このスクリプトを実行すると $HOME/hello-world-stdout.log に結果が保存されます。
[login]$ cat $HOME/hello-world-stdout.log
Hello, world!

3.4.2. 使用例 2: 複数ホストでのプログラム実行

3.4.2.1. シナリオ

UMSを使いHello World!と表示するプログラムを2つのホストで実行します。

3.4.2.2. 実行例

`$HOME/hello-worldP のシェルスクリプトを作成するところまでは使用例 1と同じ手順なので省略します。

$HOME/hello-world の投入を行う以下のスクリプトをログインノードで実行します。

#!/bin/sh

module load ums
for rank in 0 1
do
    ums-submit \
        --job [job-id] \
        --name hello-world-$rank \
        --rank $rank \
        --stdout-log $HOME/hello-world-$rank-stdout.log \
        /bin/bash $HOME/hello-world
done
module unload ums
このスクリプトを実行すると$HOME/hello-worldのシェルスクリプトを2つのノードで独立に実行し、それぞれの結果を$HOME/hello-world-0-stdout.logと$HOME/hello-world-0-stdout.logに保存します。
[login]$ cat $HOME/hello-world-0-stdout.log
Hello, world!
[login]$ cat $HOME/hello-world-1-stdout.log
Hello, world!

3.4.3. 使用例 3: プログラムのグループ実行

3.4.3.1. シナリオ

2つのホストで10秒実行するプログラムshort-runと2つのホストで60秒実行するプログラムlong-runを同時に実行します。

3.4.3.2. 実行例

UMSを起動するところまでは使用例 1と同じ手順なので省略します。

まず10秒実行するshort-runを作成します。今回の例では $HOME/short-run に以下のシェルスクリプトを作成します。

#!/bin/sh

sleep 10

次に60秒実行するlong-runを作成します。今回の例では $HOME/long-run に以下のシェルスクリプトを作成します。

#!/bin/sh

sleep 60

次に、以下のスクリプトをログインノードで実行し、 $HOME/short-run および $HOME/long-run の投入を行います。

#!/bin/sh

module load ums
for rank in 0 1
do
    ums-submit \
        --group short-run \
        --job [job-id] \
        --name short-run-$rank \
        --rank $rank \
        /bin/bash $HOME/short-run
done
for rank in 0 1
do
    ums-submit \
        --group long-run \
        --job [job-id] \
        --name long-run-$rank \
        --rank $rank \
        /bin/bash $HOME/long-run
done
module unload ums
このスクリプトを実行すると2つのノードで独立に $HOME/short-run$HOME/long-run の両方が実行されます。 また、$HOME/short-runshort-run グループ、 $HOME/long-runlong-run グループに所属しており、 以下のログのようにグループを切り替えながら実行されます。
[login]$ cat $HOME/.ums/log/[job-name]-[job-id]/worker-0.log
...
[2025-01-01 00:00:00.000] [ums-worker] [info] suspend: long-run-0: 100
[2025-01-01 00:00:00.000] [ums-worker] [info] resume: short-run-0: 200
[2025-01-01 00:00:01.000] [ums-worker] [info] suspend: short-run-0: 200
[2025-01-01 00:00:01.000] [ums-worker] [info] resume: long-run-0: 100
...
[login]$ cat $HOME/.ums/log/[job-name]-[job-id]/worker-1.log
...
[2025-01-01 00:00:00.000] [ums-worker] [info] suspend: long-run-1: 300
[2025-01-01 00:00:00.000] [ums-worker] [info] resume: short-run-1: 400
[2025-01-01 00:00:01.000] [ums-worker] [info] suspend: short-run-1: 400
[2025-01-01 00:00:01.000] [ums-worker] [info] resume: long-run-1: 300
...

3.5. 制限事項

  • アレイジョブには対応しておりません。
  • MPI環境はOpenMPI環境のみに対応しており、他の環境には対応しておりません。
  • MPIプログラムをグループに所属させて実行させる場合、そのMPIプログラムは他のプログラム(他のグループのプログラムも含む)より先に実行してください。