0. modules模块概述

在高性能计算平台上经常需要编译不同的计算程序,不同的程序所要求的编译器以及版本都多多少少会存在一些差异,这时候就需要在编译程序或者运行相关计算程序前前设置不同的环境变量,加载不同的链接库。这些操作往往很冗长且千篇一律,modules模块可以将这些操作整合进单个modulefile文件中,在需要激活相关环境变量的时候只需要执行一条简单的加载命令。

该教程主要介绍了centos7中modules模块的使用,以及modulefile的简单编写技巧。

1. modules模块安装

一些超算平台中往往已经集成了modules模块,有些没有的话集群管理员可能需要手动安装。安装的方法一般有两种,yum仓库中有的话直接使用yum安装即可。

# rocks7已集成modules模块,故不需要安装
# 常规的centos7可以通过yum命令进行安装
yum install environment-modules -y

有特殊需求的话,也可以通过手动编译源码安装modules模块。

# 获取tarball源码包
curl -LJO https://github.com/cea-hpc/modules/releases/download/v5.0.1/modules-5.0.1.tar.gz
# 解压缩源码包
tar xfz modules-5.0.1.tar.gz
# 简单编译安装,有特别需求可以手动设置配置参数
./configure
make
make install
# 常用的配置参数
--prefix=PREFIX #执行文件安装路径
--modulefilesdir=DIR #modulefile文件目录

2. modules模块简单使用

modules模块的指令格式如下:

module [switches] [subcommand] [subcommand-args]

switches部分用于控制输出的信息格式和输出行为,switches的可选命令如下:

-H|--help		打印帮助信息
-V|--version	查看模块的版本信息和编译配置参数(即configure所带参数)
-f|--force		force active dependency resolution
-t|--terse		terse    format avail and list format
-l|--long		long     format avail and list format
-h|--human		readable format avail and list format
-v|--verbose	启用输出详细信息
-s|--silent		静默模式,与-v相反
-c|--create		create caches for avail and apropos
-i|--icase		case insensitive
-u|--userlvl <lvl>	设置用户等级,可选参数:nov/exp/adv  (nov[ice],exp[ert],adv[anced])

subcommand所有子命令如下:

只需要记住常见的使用命令,load/unload/switch/avail/list/use/clear即可。

add|load			modulefile [modulefile ...] # 加载模块
rm|unload			modulefile [modulefile ...] # 卸载模块
switch|swap			[modulefile1] modulefile2 # 切换模块
display|show		modulefile [modulefile ...] # 查看模块的相关信息
avail				[modulefile [modulefile ...]] # 查看系统中可用的模块
use [-a|--append]	dir [dir ...] #将用户modulefile目录加入到MODULEPATH中
unuse				dir [dir ...] # 将用户modulefile目录从MODULEPATH中移除
update
refresh
purge
list				# 列出已经加载的模块
clear
help				[modulefile [modulefile ...]]
whatis				[modulefile [modulefile ...]] 
apropos|keyword		string
initadd				modulefile [modulefile ...]
initprepend			modulefile [modulefile ...]
initrm				modulefile [modulefile ...]
initswitch			modulefile1 modulefile2
initlist
initclear

2.1 查看所有可用的modules模块

module avail可以列出系统中可用的所有模块。rocks集群中默认的modulefiles文件夹路径为:/usr/share/Modules/modulefiles以及/etc/modulefiles

[root@lfpara mpi]# module avail 

----------------------- /usr/share/Modules/modulefiles -----------------------
dot              module-info      null             rocks-openmpi_ib
module-git       modules          rocks-openmpi    use.own

------------------------------ /etc/modulefiles ------------------------------
mpi/openmpi-x86_64

2.2 查看所有以加载的modules模块

module list指令可以列出系统中已经加载的模块,例如:

[root@lfpara ~]# module list
Currently Loaded Modulefiles:
  1) rocks-openmpi

以上例子可以看到rocks集群中以及加载了自带的openmpi模块。

2.3 卸载已加载的modules模块

module unload <模块名>指令可卸载已加载模块,例如:

[root@lfpara ~]# module list
Currently Loaded Modulefiles:
  1) rocks-openmpi   2) module-git
[root@lfpara ~]# module unload module-git
[root@lfpara ~]# module list
Currently Loaded Modulefiles:
  1) rocks-openmpi

2.4 查看相关模块的详细信息

module show <模块名>指令可查看相关模块的具体详细信息,包括描述、环境变量、链接库等。例如:

[root@lfpara ~]# module show rocks-openmpi
-------------------------------------------------------------------
/usr/share/Modules/modulefiles/rocks-openmpi:

module-whatis	 Use Rocks-compiled OpenMPI with tcp,self transport 
setenv		 MPIHOME /opt/openmpi 
setenv		 OMPI_MCA_btl self,sm,tcp 
prepend-path	 PATH /opt/openmpi/bin 
prepend-path	 LD_LIBRARY_PATH /opt/openmpi/lib 
-------------------------------------------------------------------

3. modulefile的编写指南

该部分主要简明介绍modulefile的项目组织,文件的一般结构,以及常用的相关指令。

3.1 modulefile文件如何进行系统性组织

例举一个常见的常见,当超算平台中存在多个不同的计算软件,每个计算软件都要求不同版本的MPI进行并行计算支持。这是可以针对这一些不同版本不同厂商的MPI软件的modulefile进行组织,建议在公用的用户目录下创建一个privatemodules文件夹,在该文件夹中组织相关的modulefile。

使用前需要将该目录加入modulepath中,例如:

module use -a /home/lfpara/privatemodules

例如:

privatemodules/
├── cmake
│   ├── 3.8.0
│   └── 3.9.0
├── gcc
└── mpi
    ├── intel
    ├── mpich2
    └── openmpi
        ├── 3.1.1
        ├── 3.1.2
        └── 3.1.3

需要激活相关版本的时候只需要执行加载命令即可:module load mpi/openmpi/3.1.1

3.2 modulefile文件结构详解

下面用两个modulefile的实际例子来刨析modulefile的一个大致的文件结构。

modulefile以工具命令语言(Tool Command Language)编写,由modulecmd.tcl作为解释器。

以rocks自带的openmpi为例:

#%Module1.0
##
## rocks-openmpi modulefile
##
## modulefiles/
##
proc ModulesHelp { } {
	global rocks-openmpiversion 

	puts stderr "\t Use /opt/rocks/openmpi as your MPI"
	puts stderr "\n\tVersion $rocks-openmpiversion\n"
}

module-whatis	"Use Rocks-compiled OpenMPI with tcp,self transport"

# for Tcl script use only
set	rocks-openmpiversion 2.1.1

set mpiHome /opt/openmpi
setenv MPIHOME $mpiHome
setenv OMPI_MCA_btl self,sm,tcp
prepend-path	PATH $mpiHome/bin	
prepend-path	LD_LIBRARY_PATH $mpiHome/lib	
  1. modulefile以#%Module1.0开头,1.0为modules模块的版本。

  2. 后续以##开头的行数的为该模块的相关注释,可以在此编写相关的注释信息。

  3. proc开头为模块的帮助函数,当执行module help <模块名>命令时,会打印出该函数中的相关帮助信息。该函数内部puts语句将字符串打印至标准错误输出中:puts stderr "... ..."

proc ModulesHelp { } {
	... ....
	puts stderr "输出的帮助信息"
}
  1. module-whatis 指令用于描述该模块的相关功能。

  2. set 变量名 变量值指令则用于设置变量。

  3. setenv 环境变量名 变量值指令用于设置环境变量。

  4. prepend-path 环境变量名 变量值指令用于将新变量值增加到现有的变量值之前,例如prepend-path PATH $mpiHome/bin等同于export PATH=$mpiHome/bin:$PATH

了解以上的相关指令便可以初步写一些简单的modulefile文件。

后面将以两个不同版本的cmake和两个不同版本的openmpi为例来编写modulefile文件,进行实战练习。

4. modulefile实战练习

4.1 cmake的modulefile编写实战

在集群中已经编译3.8与3.20两个版本的cmake,路径分别为

/home/lfpara/zcyapp/cmake/
├── 3.20.0
│   ├── bin
│   ├── doc
│   ├── man
│   └── share
└── 3.8.0
    ├── bin
    ├── doc
    ├── man
    └── share

分别在/home/lfpara/privatemodules/cmake下编写两个不同版本cmake的modulefile:

文件树形图如下:

/home/lfpara/privatemodules/
├── cmake
    ├── 3.20.0
    └── 3.8.0

3.8.0版本cmake的modulefile如下所示:

#%Module1.0
## cmake-3.8.0
proc ModulesHelp { } {
    puts stderr "\t Use cmake/3.8.0 as your cmake"
}

set cmakeHome /home/lfpara/zcyapp/cmake/3.8.0
prepend-path PATH $cmakeHome/bin

3.20.0版本cmake的modulefile如下所示:

#%Module1.0
## cmake-3.20.0
proc ModulesHelp { } {
    puts stderr "\t Use cmake/3.20.0 as your cmake"
}

set cmakeHome /home/lfpara/zcyapp/cmake/3.20.0
prepend-path PATH $cmakeHome/bin

添加后可以通过指令查看添加的模块:

[lfpara@lfpara cmake]$ module avail 

----------------------- /usr/share/Modules/modulefiles -----------------------
dot              module-info      null             rocks-openmpi_ib
module-git       modules          rocks-openmpi    use.own

------------------------------ /etc/modulefiles ------------------------------
mpi/openmpi-x86_64

------------------------ /home/lfpara/privatemodules/ ------------------------
cmake/3.20.0              mpi/openmpi/rocks-openmpi
cmake/3.8.0

可以使用以下指令使用模块:

# 使用cmake-3.8.0
module load cmake/3.8.0
# 切换到cmake-3.20.0
module switch cmake/3.20.0
# 卸载cmake-3.20.0模块
module unload cmake/3.20.0