まずはこちらを参照してください→ SGE用スクリプトファイルをPBS用に書き換える方法。本記事ではこちらで扱われていない内容を記します。
アレイジョブをqdelする
PBSではアレイジョブは1234[]
といったjob IDがつきます。これを削除するには、bashなどがパス名展開して余計なことをしないようqdel "1234[]"
とダブル(orシングル)クォーテーションで囲む必要があります。qhold
などのコマンドを実行する際にも同様です。
qsubを実行したディレクトリをカレントディレクトリにする(が、直接実行もいけるようにする)
UGEでは$# -cwd
で済んでいましたが、PBSではこれが使えないので、スクリプトの頭のほうでcd ${PBS_O_WORKDIR}
します。しかしそれだとPBSを使わずに直接実行した際にはcd (空文字列)
が評価されてしまいます。単純に以下で回避しましょう。
cd "${PBS_O_WORKDIR:-$(pwd)}"
蛇足ですが、PBSのアレイジョブで実行するスクリプトを直接実行もできるようにする際にも同様のテクニックが便利です。すなわち、input/file1
... input/file100
まで処理したいファイルがあるとき、以下のようにするとアレイジョブではすべてのファイルを処理し、直接実行すると1番目のファイルだけを単一プロセスで処理するようにできます。
find input/ -type f | sort | awk "NR==${PBS_ARRAY_INDEX:-1}"
JOBIDやARRAYIDを付加してログを出力する
UGEでは以下のようqsubへの引数を書くことで、ログファイル名を一意に定めることができました。また、少々ややこしいことにスクリプト内では$SGE_TASK_ID
でアレイジョブの何番目かを取ってくる仕様でした。
#$ -o log/stdout_$HOSTNAME_$JOB_ID_$TASK_ID
#$ -e log/stderr_$HOSTNAME_$JOB_ID_$TASK_ID
PBSを使用する際、スクリプト内では$SGE_TASK_ID
の代わりに$PBS_ARRAY_INDEX
を使うことができます。しかし$JOB_ID
と$TASK_ID
に相当するものがありません。
そこで代替策としては、実行するスクリプトの内容をすべて{}
でグループコマンド化し、まるごと標準出力と標準エラー出力をリダイレクトしてやる手があります(もっといい方法があったら教えてください!)。
#!/bin/bash
#PBS -S /bin/bash
#PBS -N demojob
#PBS -V
#PBS -o /dev/null
#PBS -e /dev/null
#PBS -J 1-4
cd "${PBS_O_WORKDIR:-$(pwd)}"
{
echo hoge
echo fuga
python nonexistent.py
}&>log/$(date +"%Y%m%d%H%M%S")_"${PBS_JOBNAME}_${PBS_JOBID:--$$}"
このようにすると以下のログ出力が得られます。cd
はグループに入る前に実行する必要があることに注意してください。ファイル名にはついでに日時も付加してあります。なお、PBSを経由しないで実行するときのために$PBS_JOBID
がなければプロセスIDが入るようにしてあります。
hoge
fuga
python: can't open file 'nonexistent.py': [Errno 2] No such file or directory
スクリプトに引数を与える際の留意点
UGEではqsub myscript.sh myarg
とするだけでした。PBSではqsub -- $HOME/mydir/myscript.sh myarg
とすれば与えることができます。このときは絶対パスでスクリプトを指定する必要があることに注意してください。しかし、これをするとスクリプト本体内で#PBS ...
と指定しているものが無効になってしまいます。たとえば#PBS -V
も無効になりますから、PATHの設定が消えてしまいますし、#PBS -J ...
も消えてアレイジョブになりません(このトレードオフを解消する方法をご存じの方はぜひ教えてください!)。
いまのところの対応策は
- スクリプト内にqsubへの引数を書くのをやめて、
qsub -V -J 1-4 -- $HOME/mydir/myscript.sh myarg
など直接qsubの引数にする - スクリプトに引数を渡すことをあきらめて、qsub実行前に
export MYVAR=foobar
など環境変数を設定したうえで単にqsub myscript.sh
して、スクリプト内で環境変数を読み取る。コマンドがすっきりするので個人的にはこちらが好みです。
ジョブ一つあたりのCPU数を指定する
上記記事で扱われている内容なので冗長ですが、よく使うので書いておきます。一つのジョブが10CPUを使うときにUGEでは#$ -pe make 10
など指定したところ、PBSでは#PBS -l select=10
としてください。#PBS -l select=10:mem=10GB
なら10CPUとメモリ10GBを確保します。
スクリプトひな形
ここまでの内容を合わせて、スクリプトのひな型はこんな感じになります。環境変数による切り替えの例としてDRYRUN
が空でなければ実際の処理をスキップするようにしてあります。Queueの設定などはそれぞれの環境に合わせて行ってください。
#!/bin/bash
#PBS -S /bin/bash
#PBS -N demojob
#PBS -o /dev/null
#PBS -e /dev/null
#PBS -V
#PBS -J 1-4
cd "${PBS_O_WORKDIR:-$(pwd)}"
{
INPUTFILE=$(find input/ -type f | sort | awk "NR==${PBS_ARRAY_INDEX:-1}")
echo "Executing something for ${INPUTFILE}"
if [ -n "${DRYRUN}" ]; then
echo "----Dry run flag is set... skipping execution"
else
some_command_you_want_to_run "${INPUTFILE}"
fi
echo "----Done"
}&>log/$(date +"%Y%m%d%H%M%S")_"${PBS_JOBNAME}_${PBS_JOBID:--$$}"