作业示例¶
根据集群的不同队列、不同应用软件,示例 slurm 作业脚本。
作业提交流程¶
批量非阻塞式计算任务(结果输出至文件)¶
编写作业脚本
vi test.slurm # 根据需求,选择计算资源:CPU 或 GPU、所需核数、是否需要大内存
脚本头部内容示例¶
cpu¶
cpu 队列 slurm 脚本示例:单节点不满核(例如20核),共享使用节点
#!/bin/bash
#SBATCH --job-name=test # 作业名
#SBATCH --partition=cpuXeon6458 # cpu 队列
#SBATCH -n 20 # 总核数 20
#SBATCH --ntasks-per-node=10 # 每节点核数
#SBATCH --output=%j.out
#SBATCH --error=%j.err
cpu 队列 slurm 脚本示例:独占单节点不满核(20核),比如为了独占整个节点的大内存
#!/bin/bash
#SBATCH --job-name=test # 作业名
#SBATCH --partition=cpuXeon6458 # cpu 队列
#SBATCH -n 20 # 总核数 20
#SBATCH --ntasks-per-node=20 # 每节点核数
#SBATCH --output=%j.out
#SBATCH --error=%j.err
#SBATCH --exclusive # 独占节点(独占整个节点的大内存,按照满核计费)
cpu 队列 slurm 脚本示例:单节点满核(40 核)
#!/bin/bash
#SBATCH --job-name=test # 作业名
#SBATCH --partition=cpuXeon6458 # cpu 队列
#SBATCH -n 40 # 总核数 40
#SBATCH --ntasks-per-node=40 # 每节点核数
#SBATCH --output=%j.out
#SBATCH --error=%j.err
cpu 队列 slurm 脚本示例:多节点(160 核)
#!/bin/bash
#SBATCH --job-name=test # 作业名
#SBATCH --partition=cpuXeon6458 # cpu 队列
#SBATCH -n 160 # 总核数 160
#SBATCH --ntasks-per-node=40 # 每节点核数
#SBATCH --output=%j.out
#SBATCH --error=%j.err
gpu¶
gpu 队列 slurm 脚本示例:单节点,分配 2 块 GPU,GPU:CPU 配比 1:6
#!/bin/bash
#SBATCH --job-name=test # 作业名
#SBATCH --partition=gpuA800 # gpuA800 队列
#SBATCH -N 1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=12 # 1:6 的 GPU:CPU 配比
#SBATCH --gres=gpu:2 # 2 块 GPU
#SBATCH --output=%j.out
#SBATCH --error=%j.err
提交作业
sbatch test.slurm
交互式任务¶
申请资源
# 申请资源命令例子,申请一个节点、cpuXeon6458资源分区、使用时长60分钟、32核,排除comput[185-196]主机
$ salloc -N 1 -p cpuXeon6458 -t 60:00 --cpus-per-task=32 -x comput[185-196]
命令行参数解释:
-N <节点数量>
--cpus-per-task=<单进程 CPU 核心数>
--gres=gpu:<单节点 GPU 卡数>
-N <主机台数>
-t <最长运行时间>
-p <使用的分区>
-w <指定主机列>
-x <排除主机列>
获取主机号,并通过ssh登陆至计算节点(下例:申请到的主机号是comput24,任务id为17522)
[rkwu@admin ~]$ # 输入命令,申请计算资源
[rkwu@admin ~]$ salloc -N 1 -p cpuXeon6458 -t 60:00 --cpus-per-task=32 -x comput[185-196]
salloc: Pending job allocation 17522
salloc: job 17522 queued and waiting for resources
salloc: job 17522 has been allocated resources
salloc: Granted job allocation 17522
salloc: Waiting for resource configuration
salloc: Nodes comput24 are ready for job
[rkwu@admin ~]$ # 获取主机号,登录至计算节点
[rkwu@admin ~]$ ssh -Y comput24
Warning: Permanently added 'comput24,192.168.4.24' (ECDSA) to the list of known hosts.
Activate the web console with: systemctl enable --now cockpit.socket
[rkwu@comput24 ~]$
查看作业和资源¶
squeue # 查看正在排队或运行的作业
或
sacct # 查看过去 24 小时内已完成的作业
集群资源实时状态查询
sinfo # 若有 idle 或 mix 状态的节点,排队会比较快
结束作业或已申请的计算资源¶
通过 squeue 命令查看已申请的资源,并获取到任务id
通过“ scancel 任务id ” 结束作业或计算资源
例:
[rkwu@admin ~]$ squeue
JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
17522 cpuXeon64 interact rkwu R 8:29 1 comput24
[rkwu@admin ~]$ scancel 17522
salloc: Job allocation 17522 has been revoked.
各类型作业示例¶
串行作业¶
串行作业仅使用单个CPU核心。这与同时使用多个CPU核心的并行作业形成对比。以下是串行R作业的Slurm脚本示例:
#!/bin/bash
#SBATCH --job-name=slurm-test # create a short name for your job
#SBATCH --nodes=1 # node count
#SBATCH --ntasks=1 # total number of tasks across all nodes
#SBATCH --cpus-per-task=1 # cpu-cores per task (>1 if multi-threaded tasks)
#SBATCH --mem-per-cpu=4G # memory per cpu-core (4G is default)
#SBATCH --time=00:01:00 # total run time limit (HH:MM:SS)
#SBATCH --mail-type=begin # send email when job begins
#SBATCH --mail-type=end # send email when job ends
module purge
Rscript myscript.R
Slurm脚本或多或少是带有一些额外参数的shell脚本,用于设置资源需求:
•--nodes =1-指定一个节点
•--ntasks=1-声明一个任务(默认情况下,每个CPU核心1个)
•--time -申请时间分配,此处为1分钟。格式为DAYS-HOURS:MINUTES:SECONDS
其他设置配置自动电子邮件。如果您不想接收电子邮件,可以删除这些行。
使用以下命令将作业提交到Slurm作业调度程序:
$sbatch job.slurm
在上面的命令中,job.slurm是slurm脚本的文件名。请随意使用其他名称,如submit.sh。 当Slurm作业运行时,除非重定向输出,否则将在运行sbatch命令的目录中生成名为Slurm-#######.out的文件。您可以使用cat、less或任何文本编辑器来查看它。该文件包含程序在交互运行时写入终端的输出。
多线程作业¶
一些软件,如NumPy和MATLAB中的线性代数例程,能够通过使用共享内存并行编程模型(如OpenMP、pthreads或英特尔线程构建块(TBB))编写的库使用多个CPU内核。例如,OpenMP程序在一个节点上作为多个“线程”运行,每个线程使用一个CPU核心。 以下是适用于多线程作业的Slurm脚本:
#!/bin/bash
#SBATCH --job-name=multithread # create a short name for your job
#SBATCH --nodes=1 # node count
#SBATCH --ntasks=1 # total number of tasks across all nodes
#SBATCH --cpus-per-task=4 # cpu-cores per task (>1 if multi-threaded tasks)
#SBATCH --mem-per-cpu=4G # memory per cpu-core (4G is default)
#SBATCH --time=00:15:00 # maximum time needed (HH:MM:SS)
export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK
module purge
module load matlab/R2023a
matlab -nodisplay -nosplash -r for_loop
在上面的脚本中,cpus-per-task参数用于告诉Slurm使用四个CPU内核运行多线程任务。通常,随着每个任务的cpu的增加,作业的执行时间减少,而队列时间增加,并行效率降低。每个任务的cpus的最佳值必须通过分析或者凭经验确定。
重要提示:只有明确编写为使用多个线程的代码才能利用多个CPU内核。对于尚未并行化的代码,每个任务使用大于1的cpus值不会提高其性能。相反,这样做会浪费资源。
多节点/并行MPI作业¶
许多代码使用一种基于MPI(消息传递接口)的分布式内存并行形式。这些代码能够同时在多个节点上使用多个CPU核心。例如,下面的脚本在2个节点中的每个节点上使用32个CPU核心:
#!/bin/bash
#SBATCH --job-name=multinode # create a short name for your job
#SBATCH --nodes=2 # node count
#SBATCH --ntasks-per-node=32 # number of tasks per node
#SBATCH --cpus-per-task=1 # cpu-cores per task (>1 if multi-threaded tasks)
#SBATCH --mem-per-cpu=4G # memory per cpu-core (4G is default)
#SBATCH --time=00:05:00 # total run time limit (HH:MM:SS)
module purge
module load intel/2022.2.0
module load intel-mpi/intel/2021.7.0
srun ${HOME}/.local/bin/myprog <args>
重要提示:只有明确编写为并行运行的代码才能利用多个节点上的多个核心。对于尚未并行化的代码,使用大于1的--ntask值不会提高其性能。相反,你会浪费资源。
重要提示:并行代码的--nodes和--ntask的最佳值必须通过分析或者凭经验确定。随着这些数量的增加,并行效率往往会降低,队列时间也会增加。并行效率是串行执行时间除以并行执行时间和任务数的乘积。如果使用多个节点,那么在大多数情况下,应该尝试使用每个节点上的所有CPU核心。
在请求其他节点之前,应尝试使用一个节点上的所有核心。也就是说,使用一个节点和32个核比使用两个节点和每个节点16个核要好。
MPI作业由跨一个或多个节点运行的多个进程组成。通过点对点和集体操作进行协调。
多节点多线程作业¶
许多代码使用混合OpenMP/MPI方法将多线程与多节点并行性相结合。以下是适用于此类代码的Slurm脚本:
#!/bin/bash
#SBATCH --job-name=hybrid # create a short name for your job
#SBATCH --nodes=2 # node count
#SBATCH --ntasks-per-node=8 # total number of tasks per node
#SBATCH --cpus-per-task=4 # cpu-cores per task (>1 if multi-threaded tasks)
#SBATCH --mem-per-cpu=4G # memory per cpu-core (4G is default)
#SBATCH --time=00:01:00 # total run time limit (HH:MM:SS)
export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK
export SRUN_CPUS_PER_TASK=$SLURM_CPUS_PER_TASK
module purge
module load oneapi/2024.0
srun ${HOME}/.local/bin/myprog <args>
上面的脚本分配了2个节点,每个节点有32个CPU核心。对于OpenMP/MPI代码,上面的脚本将为每个节点生成8个MPI进程。当遇到OpenMP并行指令时,每个进程将使用4个CPU内核执行工作。
如上所述,节点的最优值、每个节点的ntask和每个任务的cpus必须通过分析或者凭经验确定。许多使用混合OpenMP/MPI模型的代码将在单个节点上运行得足够快。
确保每个节点的ntask和每个任务的CPU的乘积等于或小于节点上的CPU核数。使用“scontrol show node $NODENAME”命令并查看“CPUS”列以查看每个节点的CPU核心信息。
Job Array 阵列作业¶
作业阵列用于多次运行同一作业,作业之间只有细微的差异。例如,假设您需要运行100个作业,每个作业都有不同的随机数生成器种子值。或者,您可能想对国内34个省中的每个省的数据运行相同的分析脚本。对于这种情况,作业阵列是最佳选择。 以下是用于运行Python的Slurm脚本示例,其中数组中有5个作业:
#!/bin/bash
#SBATCH --job-name=array-job # create a short name for your job
#SBATCH --output=slurm-%A.%a.out # stdout file
#SBATCH --error=slurm-%A.%a.err # stderr file
#SBATCH --nodes=1 # node count
#SBATCH --ntasks=1 # total number of tasks across all nodes
#SBATCH --cpus-per-task=1 # cpu-cores per task (>1 if multi-threaded tasks)
#SBATCH --mem-per-cpu=4G # memory per cpu-core (4G is default)
#SBATCH --time=00:01:00 # total run time limit (HH:MM:SS)
#SBATCH --array=0-4 # job array with index values 0, 1, 2, 3, 4
echo "My SLURM_ARRAY_JOB_ID is $SLURM_ARRAY_JOB_ID."
echo "My SLURM_ARRAY_TASK_ID is $SLURM_ARRAY_TASK_ID"
echo "Executing on the machine:" $(hostname)
module purge
module load anaconda3/3-2023.09
conda activate myenv
python myscript.py
上述slurm脚本的关键行是:
#SBATCH --array=0-4
在本例中,Slurm脚本将运行五个作业。每个作业将具有不同的SLUM_ARRAY_TASK_ID值(即0、1、2、3、4)。SLURM_ARRAY_TASK_ID的值可用于区分数组中的作业。可以将SLUM_ARRAY_TASK_ID作为命令行参数传递给可执行文件,也可以将其作为环境变量引用。
使用后一种方法,Python脚本(上面称为myscript.py)的前几行可能如下所示:
import os
idx = int(os.environ["SLURM_ARRAY_TASK_ID"])
parameters = [2.5, 5.0, 7.5, 10.0, 12.5]
myparam = parameters[idx]
# execute the rest of the script using myparam
R script you can use:
idx <- as.numeric(Sys.getenv("SLURM_ARRAY_TASK_ID"))
parameters <- c(2.5, 5.0, 7.5, 10.0, 12.5)
myparam <- parameters[idx + 1]
# execute the rest of the script using myparam
MATLAB:
idx = uint16(str2num(getenv("SLURM_ARRAY_TASK_ID")))
parameters = [2.5, 5.0, 7.5, 10.0, 12.5]
myparam = parameters(idx + 1)
# execute the rest of the script using myparam
Julia:
idx = parse(Int64, ENV["SLURM_ARRAY_TASK_ID"])
parameters = (2.5, 5.0, 7.5, 10.0, 12.5)
myparam = parameters[idx + 1]
# execute the rest of the script using myparam
请确保使用SLUM_ARRAY_TASK_ID的值为数组中每个作业的输出文件分配唯一的名称。否则,将导致所有作业使用相同的文件名。
可以将数组编号设置为不同的数字集和范围,例如:
#SBATCH --array=0,100,200,300,400,500
#SBATCH --array=0-24,42,56-99
#SBATCH --array=1-1000
但是,数组编号必须小于数组中允许的最大作业数。
可以使用“%”分隔符指定作业阵列中同时运行的任务的最大数量。例如“--array=0-15%4”会将此作业数组中同时运行的任务数限制为4。
要查看阵列中作业数的限制,请执行以下操作:
$ scontrol show config | grep Array
MaxArraySize = 2501
阵列中的每个作业的nodes、ntasks、cpus-per-task、time等值都是一样的。这意味着作业阵列可以用于处理从串行作业到大型多节点案例的所有内容。
在单一作业中以并行方式运行多个作业¶
通常情况下,应该使用作业数组来执行此任务,但在某些情况下,不同的可执行文件需要同时运行。在下面的示例中,所有可执行文件都是相同的,但这不是必需的。例如,如果我们有三个作业,并且我们想将它们作为一个Slurm作业并行运行,我们可以使用以下脚本:
#!/bin/bash
#SBATCH --job-name=myjob # create a short name for your job
#SBATCH --nodes=1 # node count
#SBATCH --ntasks=3 # total number of tasks across all nodes
#SBATCH --cpus-per-task=1 # cpu-cores per task (>1 if multi-threaded tasks)
#SBATCH --mem-per-cpu=4G # memory per cpu-core (4G is default)
#SBATCH --time=00:01:00 # total run time limit (HH:MM:SS)
module purge
module load anaconda3/2024.2
export SRUN_CPUS_PER_TASK=$SLURM_CPUS_PER_TASK
srun -N 1 -n 1 --exclusive python demo.py 0 &
srun -N 1 -n 1 --exclusive python demo.py 1 &
srun -N 1 -n 1 --exclusive python demo.py 2 &
wait
由于我们希望并行运行作业,我们将&字符放在每个srun命令的末尾,以便每个作业在后台运行。wait命令充当一个屏障,使整个作业保持运行,直到所有作业完成。
如果在整个作业中运行的任务预计具有明显不同的执行时间,请不要使用此方法。这样做会导致处理器闲置,直到最长的任务完成。如果可能,应始终使用作业数组来代替此方法。
对于GPU作业,请确保脚本使用以下参数:
#SBATCH --nodes=1
#SBATCH --ntasks=2
#SBATCH --gres=gpu:2
...
srun -N 1 -n 1 --gres=gpu:1 --exclusive python demo.py 0 &
srun -N 1 -n 1 --gres=gpu:1 --exclusive python demo.py 1 &
wait
大内存作业¶
与笔记本电脑或工作站相比,使用HPC集群的一个优点是每个节点有大量可用的RAM。例如,在某些集群上,您可以使用100 GB的内存运行作业。这对于处理大型数据集非常有用。
#!/bin/bash
#SBATCH --job-name=slurm-test # create a short name for your job
#SBATCH --nodes=1 # node count
#SBATCH --ntasks=1 # total number of tasks across all nodes
#SBATCH --cpus-per-task=1 # cpu-cores per task (>1 if multi-threaded tasks)
#SBATCH --mem=100G # memory per node (4G per cpu-core is default)
#SBATCH --time=00:01:00 # total run time limit (HH:MM:SS)
module purge
module load anaconda3/3-2023.9
conda activate micro-env
python myscript.py
上面的示例使用1个CPU内核和100 GB内存运行Python脚本。在所有Slurm脚本中,您应该使用所需内存的准确值,但为了安全起见,应额外包含20%。
顺序作业¶
在这里,我们解释如何使用Slurm作业依赖项自动运行一系列作业。这对于需要运行时间远远超过时间限制的作业非常有用。或者,由于两者之间的依赖关系,第二个作业只能在第一个作业完成后才能启动。 要使用Slurm作业依赖项分步骤运行长作业,您的应用程序必须有编写检查点文件的方法,并且必须能够在每个作业步骤开始时找出要读取的检查点文件。如果您的应用程序没有提供这两个需求,那么通常可以编写脚本来处理它。 “singleton”作业依赖关系的工作方式是将具有相同作业名称的后续作业排队,直到具有该名称的前一个作业完成。考虑下面的Slurm脚本(job.Slurm),并注意--job-name和--dependency指令:
#!/bin/bash
#SBATCH --job-name=LongJob # create a short name for your job
#SBATCH --nodes=1 # node count
#SBATCH --ntasks=1 # total number of tasks across all nodes
#SBATCH --cpus-per-task=1 # cpu-cores per task (>1 if multi-threaded tasks)
#SBATCH --mem=4G # memory per node (4G per cpu-core is default)
#SBATCH --time=00:01:00 # total run time limit (HH:MM:SS)
#SBATCH --dependency=singleton # job dependency
module purge
module load anaconda3/3-2023.9
conda activate galaxy-env
python myscript.py
然后按五个连续步骤的顺序运行代码:
$ sbatch job.slurm # step 1
$ sbatch job.slurm # step 2
$ sbatch job.slurm # step 3
$ sbatch job.slurm # step 4
$ sbatch job.slurm # step 5
第一个作业步骤可以立即运行。然而,直到步骤1完成,步骤2才能开始,以此类推。也就是说,第一个步骤之后的每个步骤都将等待前一个步骤,因为每个步骤都在等待“LongJob”完成。在 slurm 网站上阅读更多关于工作依赖性的信息。
常用软件作业示例¶
下面根据不同应用软件,示例 slurm 作业脚本
LAMMPS 作业示例¶
cpu 队列 slurm 脚本示例 LAMMPS
#!/bin/bash
#SBATCH --job-name=test # 作业名
#SBATCH --partition=cpuXeon6458 # cpu 队列
#SBATCH -n 80 # 总核数 80
#SBATCH --ntasks-per-node=40 # 每节点核数
#SBATCH --output=%j.out
#SBATCH --error=%j.err
module load lammps
srun --mpi=pmi2 lmp -i YOUR_INPUT_FILE
GROMACS 作业示例¶
cpu 队列 slurm 脚本示例 GROMACS
#!/bin/bash
#SBATCH --job-name=test # 作业名
#SBATCH --partition=cpuXeon6458 # cpu 队列
#SBATCH -n 80 # 总核数 80
#SBATCH --ntasks-per-node=40 # 每节点核数
#SBATCH --output=%j.out
#SBATCH --error=%j.err
module load gromacs/2023
srun --mpi=pmi2 gmx_mpi mdrun -deffnm -s test.tpr -ntomp 1
TensorFlow¶
gpu 队列 slurm 脚本示例 TensorFlow
#!/bin/bash
#SBATCH -J test
#SBATCH -p gpuA800
#SBATCH -o %j.out
#SBATCH -e %j.err
#SBATCH -N 1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=12
#SBATCH --gres=gpu:2
module load anaconda/3-2023.09
source activate YOUR-env
python -c ’import tensorflow as tf; \
print(tf.__version__); \
print(tf.test.is_gpu_available());’
其它示例¶
作业状态邮件提醒¶
--mail-type= 指定状态发生时,发送邮件通知: ALL, BEGIN, END, FAIL
cpu 队列 slurm 脚本示例:邮件提醒
#!/bin/bash
#SBATCH --job-name=test
#SBATCH --partition=cpuXeon6458
#SBATCH -n 20
#SBATCH --ntasks-per-node=20
#SBATCH --output=%j.out
#SBATCH --error=%j.err
#SBATCH --mail-type=end # 作业结束时,邮件提醒
#SBATCH --mail-user=XX@scut.edu.cn #作业提醒邮箱地址
Contributor:B君、eva