PBS作业管理下集群环境的相关使用方法
PBS作业管理,即以qsub
、qstat
、qdel
命令为核心的集群作业管理系统,且它是开源的。
在此环境下运行,用户不需要指定程序在哪些节点上运行,程序所需的硬件资源由PBS管理和分配。
qsub
、qstat
、qdel
的功能分别为“提交作业”、“查看作业状态”、“删除作业”。
非PBS下mpi计算
通常来说,使用mpirun
即可,例如mpirun -np 16 ./pom.kii2b.exe < /dev/null > pom.log
,意为在一个节点上使用16核执行pom.kii2b.exe
,stdin
重定向至空,stdout
重定向至pom.log
。
之后可能会再执行几个mv
命令之类的,例如把pom.log
文件移动至别处,防止多次调用时覆盖log。
PBS作业提交
直接执行qsub
会提示输入PBS作业脚本,这样很不方便,因此通常来说都是把qsub脚本写到文件里,重定向输入来进行作业提交,例如qsub < cess.sbpom.qsub
(其实不加<
也可以),提交一个写在cess.sbpom.qsub
文件里的PBS脚本。
PBS脚本形如下面那段代码从#!/bin/sh
到mv pom.log ../$TIME.pom.log
的部分。
由于存在需要多次提交相似作业的可能,例如我有20个文件夹的数据,每个文件夹里数据的处理方式相同,调用同一个程序,总不能写20个PBS脚本。因此更为通常的做法是,使用shell脚本进行qsub脚本输出再提交,举例如下:
PNAME=fz_letkf
NODE=1
NP=16
QSUBTIME="24:00:00"
NOWDIR=`pwd`
QSUB=cess.letkf.qsub
LETKF=letkf020.m01
cat <<EOF >$QSUB
#!/bin/sh
#PBS -q hpca
#PBS -V
#PBS -N $PNAME
#PBS -l nodes=$NODE:ppn=$NP
#PBS -l walltime="$QSUBTIME"
#PBS -o /home/xfh_stu/WORK3/qsublog
#PBS -j oe
cd $NOWDIR
mpirun ./$LETKF < /dev/null
mv pom.log ../$TIME.pom.log
EOF
qsub $QSUB >cessrunid
调用此脚本就会自动将PBS脚本输出至$QSUB
文件中,并提交此作业。通常在这段代码外面会套上循环,每次修改相应变量,从而实现一次提交多个相似作业。
在这里cat
命令使用了一种叫做heredoc的写法,用于输出大段文字,同时还要替换其中的变量。界定符EOF是可以自定义的,不过通常来说都使用EOF。另外,用于结束的界定符必须顶格写(想不顶格也是可以的,但是有其他限制,且不方便)。
下面解释一下参数的意思。
-q
:指定使用的队列。可使用qstat -q
查看队列信息,包括队列名、资源限制、正在运行的任务数等。-V
:将执行qsub
命令时拥有的环境变量都export该作业。-N
:指定作业名。-l
:指定作业使用的节点数与核数、时间限制等。-o
:重定向此作业的stdout
至指定的文件夹中,名为作业名.o作业ID
。-j oe
:合并此作业的stdout
与stderr
。
qsub
成功提交作业后,会在stdout
输出Job ID,形如作业ID.主机名
,例如15252.manager
。在上面的例子中,我将qsub
的结果重定向至cessrunid
文件中,用于存储作业ID,以便后续处理。
查看作业状态
执行qstat
即可查看当前正在执行的作业以及刚刚完成的作业。在S
那一列,C
表示已完成,R
表示正在执行,Q
表示正在等待,还有一些其他不常见的状态,可以man qstat
并以job state为关键词查询即可。
现在还有个问题,即如何在脚本中判断作业完成与否呢?一个很实际的例子是,我在脚本中一次提交完多个作业后,后续的脚本必须在完成这些作业后才能继续执行,那么就需要知道这些作业有没有完成。
通常有两种思路:
一是查看程序本应输出的文件有没有正常输出,即判断输出文件是否存在。或者在程序中写一些日志输出语句,脚本就可以通过查找日志文件某关键的一句话有没有输出从而知道程序运行有没有正常完成。
二是查看上文中通过-o
参数指定的作业stdout
输出文件,文件名为作业名.o作业ID
。这也就是为什么我要把qsub提交信息保存到cessrunid这个文件里。通常来说,只要作业正常完成了,就会生成此文件。
对于第一种思路,就要根据程序具体情况来编写了。
对于第二种思路,一个典型的判断脚本如下:
while :
do
temp=`cat cessrunid`
runid=${PNAME}.o${temp%.manager}
runfilename='/home/xfh_stu/WORK3/qsublog/'$runid
if [ -f "$runfilename" ]; then
break
fi
sleep 60
done
大意为:
提取出cessrunid
这个文件里的qsub
提交信息,并去掉后面的.manager
主机名(CESS集群主机名为manager),之后改写成作业名.o作业ID
的形式,并加上路径,判断该文件是否存在。
如果文件存在,则说明作业已完成,即可break
掉这个无限循环,继续后面的操作了。
这里需要注意的一个地方就是,在无限循环里的每次判断中间要加上一个sleep
语句,比如我设置的是每分钟跑一次循环,这样机器就不会由于每时每刻都在执行判断而耗尽资源。
删除作业
执行qdel -W 15 15303
即可在15秒后停止并删除Job ID为15303的作业。
脚本的正确使用方法
通常来说,我们都是在shell脚本中进行qsub脚本输出再提交该qsub脚本。
这里存在一个问题,即shell脚本自身需要后台执行。如果执行前台执行脚本,就会导致断开SSH连接后,脚本就会停止执行。
因此,需要使用nohup ./your.script.name.sh &
命令,它可以脚本在后台执行且将stdout
重定向至nohup.out
文件中。要注意命令最后的&
是不可缺少的,如果不写,脚本虽然也会在后台执行,但是在关闭SSH后就会停止。
另外,在执行完这个命令之后要按一下回车,使其回到shell上来。
当我们解决脚本后台执行的问题后,又出现了新问题,即如何停止该脚本?
通过脚本提交的PBS作业可以通过qdel
命令结束掉,而脚本本身停止就需要kill
掉该脚本的进程了。
首先,我们使用ps -ef | grep your.script.name.sh
查询到脚本的进程PID,之后执行kill xxxxx
即可停止PID为xxxxx的进程了。
其他一些技巧
并行编译
使用make
时,可用make -j
来使make
可以调用多核从而同时编译多个文件。可以通过-jx
来指定任务数,例如-j4
,如果不指定,就会尽可能调用处理器进行编译。
(另外,如果文件名不是Makefile,可以通过-f
指定要make
的文件。例如make -f cess.makefile
)
记录时间
如需知道脚本运行时间,可以在脚本首尾加上date
语句,这样就可以在nohup.out
文件里看到开始和结束时间了。
感谢
http://blog.csdn.net/bupt_bu/article/details/7308312
http://www.cnblogs.com/allenblogs/archive/2011/05/19/2051136.html