一、前言
最近有人问我能不能帮忙在服务器上装个Quantum Espresso (简称 QE),并且要能使用slurm系统进行作业管理。虽然编译个QE难度不大,上网Google一下就有许多教程教你怎么编译,但是奈何这些教程说的五花八门,有的也写的不够全面,遂决定把从slurm队列的部署到程序编译,再到如何使用队列系统详细地写个帖子以便新手当作参考,使得自己折腾一下也能够把这些东西学会。 本文中使用的Linux系统为Rocky Linux-9.4, CPU为双路Intel(R) Xeon(R) Silver 4216 CPU@2.10GHz, oneAPI版本为2023.1。
二、slurm作业系统的简单部署
对于Rocky Linux-9来说,已经有预编译好的slurm-22.05.9的rpm包可供直接下载使用(https://pkgs.org/search/?q=slurm),免去了编译的麻烦。但前提是机子中已经添加了EPEL仓库,如果没有添加的话可以通过 dnf config-manager --set-enabled crb;dnf install epel-release epel-next-release来直接安装。本文中主要针对的是单机用户安装slurm队列,对于集群用户请参考http://bbs.keinsci.com/thread-39120-1-1.html。 1) 准备工作:
修改主机名,假如这里我用master作为主机名。vi /etc/hostname,将主机名改为master
添加计算节点的网络配置。vi /etc/hosts,末尾添加 10.7.159.134 master,其中10.7.159.134为主机的IP地址,因为控制节点和计算节点都是同一台机器。
2)下载安装slurm所需的所有组件,其中slurm-slurmctld是管理节点需要的模块,slurm-slurmd是计算节点需要的模块。
- dnf install slurm slurm-slurmctld slurm-slurmd slurm-perlapi
复制代码 3)安装通信认证的服务的程序Munge
4)在/etc/munge目录下创建Munge认证的密钥,可以直接使用/usr/sbin/create-munge-key工具来生成密钥,或者也可以dd if=/dev/random of=/etc/munge/munge.key bs=1024 count=1来创建密钥文件。接下来需要检查munge目录以及文件夹的所属者/组以及权限,一般来说使用dnf下载安装的munge目录及生成的密钥所属者/组都是munge,目录权限为700,munge.key文件的权限为400,不需要什么修改。一切正常后接下来就需要启动munge服务以及设置其自启动权限。
- systemctl start munge.service
- systemctl enable munge.service
复制代码 5) 配置slurm.conf以及cgroup.conf
自定义slurm.conf内容可以通过网页版的slurm工具创建(简化版
https://slurm.schedmd.com/configurator.easy.html, 完整版
https://slurm.schedmd.com/configurator.html)。嫌麻烦的话可以直接拷贝下面的slurm.conf并稍加修改。下面有几点内容稍作说明:SelectTypeParameters参数如果使用网页工具创建的话默认为CR_Core_Memery,也就是说slurm将cpu核数和内存一同当作消费资源进行管理,所以在提交任务时如果在脚本中不对任务所需内存进行分配的话默认将所有可用内存分配给当前运行任务,也就导致了即便有空闲核数,提交的下一个任务仍旧在排队的状况。解决的办法有两个,一个是在提交任务的脚本中指定任务分配的内存容量,通过添加如#SBATCH --mem=100GB参数实现。另一种做法是在slurm.conf定义仅把cpu核数作为消费资源进行管理,即SelectTypeParameters=CR_Core。另一个需要注意修改的内容是倒数第二行,需要把NodeAddr换成自己主机的IP地址,CPUs换成自己机子可用的物理核心数,RealMemory注意不要分配所有的可用内存容量,需要留给一部分给供系统运行占用。CoresPerSocket=16 指定了每颗CPU的物理核心数,ThreadsPerCore=2如果机子开着超线程就填2,关闭了超线程就填1。
最后将slurm.conf以及cgroup.conf这两个文件一同放到/etc/slurm目录下即可。
- # slurm.conf file generated by configurator easy.html.
- # Put this file on all nodes of your cluster.
- # See the slurm.conf man page for more information.
- #
- ClusterName=master
- SlurmctldHost=master
- AuthType = auth/munge
- CredType = cred/munge
- #
- #MailProg=/bin/mail
- MpiDefault=none
- #MpiParams=ports=#-#
- ProctrackType=proctrack/cgroup
- ReturnToService=2
- SlurmctldPidFile=/var/run/slurmctld.pid
- #SlurmctldPort=6817
- SlurmdPidFile=/var/run/slurmd.pid
- #SlurmdPort=6818
- SlurmdSpoolDir=/var/spool/slurmd
- SlurmUser=root
- #SlurmdUser=root
- StateSaveLocation=/var/spool/slurmctld
- SwitchType=switch/none
- TaskPlugin=task/affinity,task/cgroup
- #
- #
- # TIMERS
- #KillWait=30
- #MinJobAge=300
- #SlurmctldTimeout=120
- #SlurmdTimeout=300
- #
- #
- # SCHEDULING
- SchedulerType=sched/backfill
- SelectType=select/cons_tres
- SelectTypeParameters=CR_Core
- #
- #
- # LOGGING AND ACCOUNTING
- AccountingStorageType=accounting_storage/none
- #JobAcctGatherFrequency=30
- JobAcctGatherType=jobacct_gather/none
- #SlurmctldDebug=info
- SlurmctldLogFile=/var/log/slurmctld.log
- #SlurmdDebug=info
- SlurmdLogFile=/var/log/slurmd.log
- #
- #
- # COMPUTE NODES
- NodeName=master NodeAddr=10.7.159.134 CPUs=32 RealMemory=60000 Sockets=2 CoresPerSocket=16 ThreadsPerCore=2 State=UNKNOWN
- PartitionName=master Nodes=ALL Default=YES MaxTime=INFINITE State=UP
复制代码- ###
- #
- # Slurm cgroup support configuration file
- #
- # See man slurm.conf and man cgroup.conf for further
- # information on cgroup configuration parameters
- #--
- CgroupAutomount=yes
- ConstrainCores=yes
- ConstrainRAMSpace=yes
复制代码
6)启动slurmctld.service 和slurmd.service,并设置开机自启。最后检查队列是否正常运行,输入sinfo,如果看到当前节点的state是idle的话表明slurm队列已经装好了。
- systemctl start slurmctld.service
- systemctl enable slurmctld.service
- systemctl start slurmd.service
- systemctl enable slurmd.service
复制代码后记:如果配置带有GPU的计算节点,假设节点有一块4080显卡,则slurm.conf文件的末尾需要修改为如下所示:
- GresTypes=gpu
- NodeName=master NodeAddr=10.7.159.134 Gres=gpu:RTX_4080:1 CPUs=32 RealMemory=60000 Sockets=2 CoresPerSocket=16 ThreadsPerCore=2 State=UNKNOWN
- PartitionName=master Nodes=ALL Default=YES MaxTime=INFINITE State=UP
复制代码同时,需要另新建一个名为gres.conf的配置文件,文件内容如下所示:
- NodeName=master Name=gpu Type=RTX_4080 File=/dev/nvidia0
复制代码注意修改节点名称,以及File变量中的CUDA安装目录所在位置。
三、编译安装QE
QE的编译安装我将以最新版本的qe-7.3.1为案例进行演示,这里笔者非常推荐使用intel编译器来编译QE,这样编译出来版本的要比GNU编译器的效率高不少。但是考虑到有比较喜欢GNU编译器+OpenMPI库组合的群体,在下文中也做了详细说明如何编译。QE有比较常用的两个插件Enviorn以及Libxc,前者提供了第一性原理程序计算中非常常用的SCCS溶剂模型,后者为QE提供了更加丰富的交换相关泛函的选择。关于QE配置这两个插件将在本章节第三部分讲解,如果不需要安装这两个插件的用户直接看本章节第一部分即可。此外,动力学增强采样PLUMED插件在本文截稿前只支持到了QE-7.2,是否适配QE-7.3.1版本笔者没有进行测试,感兴趣的用户可以自行尝试。
3.1. 仅编译QE主体
这里假定服务器中登录者身份已经切换为了root,oneAPI安装到了/opt目录下。如果用户已经安装了模块化环境管理软件如Lmod的话,输入以下命令来加载frotran,C,mpi, mkl的环境变量,如果没有安装的话可以直接source /opt/intel/oneapi/setvars.sh。
- module load compiler-rt/2023.1.0 tbb/2021.9.0 mkl/2023.1.0 icc/2023.1.0 mpi/2021.9.0
复制代码- ./configure --prefix=/opt/qe7.3.1 \
- --with-scalapack=intel --with-scalapack-qrcp=yes \
- MPIF90=mpiifort FC=ifort FCFLAGS=-O3 CC=icc CFLAGS=-O3 \
- LIBDIRS="${MKLROOT}/lib/intel64/ /opt/intel/oneapi/mpi/latest/lib"
复制代码参数--with-scalapack=intel指定使用intel的MKL数学库来提供对QE所需要的LAPACK和BLAS子程序的支持。--with-scalapack-qrcp=yes指定使用QRCP算法。MPIF90=mpiifort指定编译MPI并行的Fortran程序使用intel MPI 的mpiifort编译器。FC指定Fortran编译器为ifort。FC是对fortran编译器更加现代、通用的封装,能够指向Fortran 77、Fortran 90、Fortran 95、Fortran 2003 或更新版本编译器,所以完全没有必要再指定F90等参数了。对Fortran编译指定了更加激进的-O3以便获得更好的运行性能。CC=icc指定C语言编译器为icc。当configure在标准安装路径中找不到BLAS LIBS, LAPACK LIBS, FFT LIBS, MPI LIBS等时,LIBDIRS参数能够提供额外的configure搜索路径。一般来说只要是标准安装的oneAPI,configure都能找到这些依赖库文件,并不需额外指定LIBDIRS参数。另外,对于2023年上半年及之前部署的oneAPI, 在此之前的fortran以及C/C++语言编译器都没有改名,还称为ifort,icc。后面较新版本的oneapi将Fortran编译器更名为ifx, C编译器为icx, C++编译器为icpx。所以对于如oneAPI-2024版本,编译时参数如下所示:
- ./configure --prefix=/opt/qe7.3.1 \
- --with-scalapack=intel --with-scalapack-qrcp=yes \
- MPIF90=mpiifort FC=ifx FCFLAGS=-O3 CC=icx CFLAGS=-O3 \
- LIBDIRS="${MKLROOT}/lib /opt/intel/oneapi/mpi/latest/lib"
复制代码 ./configure运行结束后,仔细检查make.inc文件中MPIF90= mpiifort,F90= ifort,CC = icx。BLAS库和SCALAPACK库的链接是否正常,正常的话应当为BLAS_LIBS = -lmkl_intel_lp64 -lmkl_sequential -lmkl_core, SCALAPACK_LIBS = -lmkl_scalapack_lp64 -lmkl_blacs_intelmpi_lp64。以及DFLAGS = -D__DFTI -D__MPI -D__SCALAPACK -D__SCALAPACK_QRCP。如果没有问题的话执行下面命令编译QE。
3.2. GNU编译器+OpenMPI库编译QE
GNU编译器编译QE时确保gcc和gfortran已经安装到机子里了。OpenMPI库的编译这里就不再赘述了,细节请看
http://bbs.keinsci.com/thread-18600-1-1.html。这里我们同样
利用效率很高的MKL数学库来提升QE计算速度,首先加载MKL的环境变量,对于module环境管理的用户可以通过以下方式加载,对于其他用户可以source /opt/intel/oneapi/mkl/latest/env/vars.sh来加载MKL环境变量。其次也确保OpenMPI库的环境变量也同样加载了。
- module load compiler-rt/2024.1.0 tbb/2021.12 mkl/2024.1 openmpi/5.0.4
复制代码- ./configure --prefix=/opt/qe7.3.1_gnu \
- --with-scalapack-qrcp=yes \
- MPIF90=mpifort FC=gfortran FCFLAGS=-O3 CC=gcc CFLAGS=-O3 \
- LIBDIRS="${MKLROOT}/lib"
复制代码mpifort是一个更加通用的编译MPI Fortran程序的封装器,对现代的以及更早的Fortran代码具有很好的兼容性,包括 Fortran 77、Fortran 90、Fortran 2003 和 Fortran 2008。所以也就没有必要使用诸如MPIF90=mpif90了。FC指定Fortran编译器为gfortran。CC指定C语言编译器为gcc。
3.3. 编译带Environ和libxc插件支持的QE
我们首先编译Environ,下载最新版本的Environ-3.1并解压缩到/opt目录。--with-qe=/opt/qe-7.3.1指定QE所在目录。注意这里的QE目录是指QE源码包解压缩后所在的目录,并不是编译完QE所在的目录,不要搞错了。
- ./configure --with-qe=/opt/qe-7.3.1 \
- MPIF90=mpiifort FC=ifort FCFLAGS=-O3 CC=icc CFLAGS=-O3
- make -j32 compile
复制代码 接下来编译Libxc,下载最新版本的libxc-6.2.2并解压缩到/opt目录。其中autoreconf -i 用于产生configure文件。对于一些最新版oneapi,如果遇到./configure时出现“configure: error: linking to Fortran libraries from C fails”, 可将./configure --prefix=/opt/libxc6.2.2 FC=ifort FCFLAGS=-O3 CC=icx CFLAGS=-O3再试。
- autoreconf -i
- ./configure --prefix=/opt/libxc6.2.2 FC=ifort FCFLAGS=-O3 CC=icc CFLAGS=-O3
- make -j32
- make install
复制代码最后编译带这两个插件的QE。
- ./configure --prefix=/opt/qe7.3.1 \
- --with-environ=/opt/Environ-3.1 \
- --with-libxc --with-libxc-prefix=/opt/libxc6.2.2 --with-libxc-include=/opt/libxc6.2.2/include \
- --with-scalapack=intel --with-scalapack-qrcp=yes \
- MPIF90=mpiifort FC=ifort FCFLAGS=-O3 CC=icc CFLAGS=-O3 \
- LIBDIRS="${MKLROOT}/lib /opt/intel/oneapi/mpi/latest/lib"
复制代码
四、Slurm作业系统上提交QE计算任务
对于Intel编译器+Intel MPI版本的QE,提交计算任务至slurm作业系统的脚本如下所示:
- #!/bin/bash
- #SBATCH --job-name=qe
- #SBATCH --partition=master
- #SBATCH --nodes=1
- #SBATCH --ntasks-per-node=32
- #SBATCH --cpus-per-task=1
- #SBATCH -o job%j.out
- #SBATCH -e job%j.out
- export I_MPI_PMI_LIBRARY=/usr/lib64/libpmi2.so.0
- inf="Pt.scf.in"
- srun --mpi=pmi2 pw.x -i ${inf} > ${inf//in/out}
复制代码而对于GNU编译器+OpenMPI库版本的QE来说,提交任务的脚本略有不同。另外这个脚本对提交其他使用OpenMPI库的程序都是通用的,比如提交cp2k任务。
- #!/bin/bash
- #SBATCH --job-name=qe
- #SBATCH --partition=master
- #SBATCH --nodes=1
- #SBATCH --ntasks-per-node=32
- #SBATCH --cpus-per-task=1
- #SBATCH -o job%j.out
- #SBATCH -e job%j.out
- inf="Pt.scf.in"
- srun --mpi=pmix pw.x -i ${inf} > ${inf//in/out}
复制代码- #!/bin/bash
- # Note: this is MPI job script used for cp2k.popt.
- #SBATCH --job-name=cp2k
- #SBATCH --partition=master
- #SBATCH --nodes=1
- #SBATCH --ntasks-per-node=32
- #SBATCH --cpus-per-task=1
- #SBATCH -o job%j.out
- #SBATCH -e job%j.out
- inf=`ls *.inp`
- srun --mpi=pmix cp2k.popt -i ${inf} &> ${inf//inp/out}
复制代码在这些slurm脚本中,#SBATCH --job-name=qe用于指定任务的名称。#SBATCH --partition=master用于指定计算节点名称。#SBATCH --nodes=1指定几个计算节点,当前使用1个。#SBATCH --ntasks-per-node=32指定每个节点的任务数目,假如下面的#SBATCH --cpus-per-task=1每个任务数的CPU核数将被指定为1,则节点内的所有任务均以MPI方式并行。所以对于MPI并行任务,#SBATCH --cpus-per-task=1即可,然后#SBATCH --ntasks-per-node=32可以简单理解为这个任务分配的核数, 所以每次提交任务时只需要简单修改#SBATCH --job-name和指定核数的#SBATCH --ntasks-per-node参数即可。
后记:对于提交使用GPU计算任务的slurm脚本如下所示:
- #!/bin/bash
- #SBATCH --job-name=gmx
- #SBATCH --partition=master
- #SBATCH --nodes=1
- #SBATCH --ntasks-per-node=12
- #SBATCH --cpus-per-task=1
- #SBATCH --gres=gpu:RTX_4080:1
- #SBATCH -o job%j.out
- #SBATCH -e job%j.out
- gmx mdrun -deffnm prod -pin on -nt 12 -bonded gpu -pinoffset 0 -pinstride 1 -ntmpi 1 -ntomp 12 -gpu_id 0
复制代码