节点资源选择

在集群上执行自己的并行作业之前,需要找到每个作业的最佳节点数(-n)、任务数(--ntasks-per-node,--nstasks/-n)、CPU核心数(--cpus-per-task/-c)等参数,在某些情况下还需要选择合适的GPU数量。 本页演示和分析不同参数情况下的作业表现,以帮助我们找到设置这些参数的最佳值。

cpu和gpu使用率

首先要考虑运行脚本能利用好申请的资源。

提交脚本后,用squeue获取申请到的计算节点。

$squeue

然后ssh登录到计算节点,最右侧标记为“NODELIST(REASON)”的列提供运行作业的计算节点的名称。

$ssh NODENAME

登录成功后,用top -u $username(你的用户名) 命令查看cpu使用率。对于gpu卡,使用nvidia-smi或者watch -n 1 nvidia-smi动态查看gpu使用率。

多线程cpu利用率

申请资源如下:

#SBATCH --nodes=1
#SBATCH --cpus-per-task=16

cpu利用率如图所示

../_images/gres_select.png

图中,PID 506125 CPU使用率为1501%,说明使用了多线程,16个核跑满了。

并行作业的cpu利用率

申请资源如下:

#SBATCH --nodes=1
#SBATCH ---ntasks-per-node=16

cpu利用率如图所示

../_images/gres_select2.png

图中,任务相关进程16个(---ntasks-per-node=16),但每个任务只有6%左右的使用率,说明没有利用好cpu。

gpu利用率

申请资源如下:

#SBATCH --nodes=1
#SBATCH -c 9
#SBATCH --gres=gpu:1

gpu使用率如下:

../_images/gres_select3.png

图中,脚本使用了一个gpu卡,其中显存使用39428M,gpu利用率88%。

节点数,cpu或者gpu的数量的选择

多线程下的并行效率

一些软件,如NumPy和MATLAB中的线性代数例程,能够通过使用共享内存并行编程模型(如OpenMP、英特尔线程构建块(TBB)或pthreads)编写的库使用多个CPU内核。 对于纯多线程代码,只能使用单个节点和单个任务(即nodes=1和ntasks=1),然后寻求每个任务的cpus的最佳值:

#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=<T>

请参阅多线程作业的Slurm脚本示例。为了找到<T>的最佳值,我们使用了集群1中/share/case/gaussian/gaussianJob1目录下的脚本进行了如下的分析, 其中每一次任务的CPU是不同的,并且记录每个任务的运行时间:

节点数

cpus-per-task

运行时间(秒)

加速比

并行效率

1

1

15119

1.00

100%

1

2

7552

2.00

100%

1

4

3842

3.94

98%

1

8

1979

7.64

95%

1

16

963

15.70

98%

1

24

803

18.83

78%

1

32

764

19.79

62%

1

64

784

19.28

30%

在上表中,执行时间是作业运行所需的时间,加速比是串行作业的执行时间(每个任务的CPU=1)除以执行时间。 并行效率是相对于串联作业时间进行测量的。也就是说,对于每个任务的cpu=2,我们有15119.0/(7552.0×2)=100%。

上表中的数据揭示了两个关键点:

1.执行时间随着CPU内核数量的增加而减少,直到运行64个cpu的时候,代码运行速度比使用32个内核时还慢,此时可以看到cpu利用率最高也就达到2500%。这表明我们的目标不是使用尽可能多的CPU内核,而是找到最佳值。

2.从并行效率看,每个任务的cpu核数的可以是2、4、8或16,最佳值16。不考虑32个核或者64个CPU核,因为并行效率太低,。

在这种情况下,Slurm脚本可能会使用以下脚本:

#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=16

此时既能保证并行效率,也使计算速度相对来说是最快的。

多节点/并行MPI作业的并行效率

例如,对于使用MPI的多节点代码,您需要改变每个节点的节点数和ntask。如果使用单个节点时并行效率非常高,则仅使用一个以上的节点。要最大限度地缩短完成时间,请选择能提供合理加速的最小Slurm参数集。 对于不使用线程的纯MPI代码(例如,OpenMP),每个任务的cpus=1,目标是找到每个节点的节点和ntask的最佳值:

#SBATCH --nodes=<M>
#SBATCH --ntasks-per-node=<N>
#SBATCH --cpus-per-task=1

以下是并行MPI代码的分析示例(来源于集群1中/share/case/vasp/vaspJob1目录下的作业):

节点数

ntasks-per-node

CPU核数

运行时间(秒)

加速比

并行效率

1

1

1

1173

1.00

100%

1

2

2

631

1.86

93%

1

4

4

341

3.44

86%

1

8

8

182

6.45

81%

1

16

16

104

11.28

70%

1

32

32

77

15.23

48%

1

64

64

54

21.72

34%

2

64

128

42

27.93

22%

我们看到,在使用8个ntasks之前,代码的性能还算良好。一个好的选择可能是使用8个ntasks,其中并行效率还有81%。如果对执行时间要求高一些,可选择16核,此时并行效率仍然有70%。

多节点多线程作业的并行效率

有些代码同时利用了共享和分布式内存并行(例如OpenMP和MPI)。在这些情况下,你需要更改--nodes、--ntasks-per-node--cpus-per-task。 如上所述构造一个表,但每个任务包含一个新的cpus列。在使用整个节点时,--ntasks-per-node--cpus-per-task的乘积应等于每个节点的CPU核总数。

#SBATCH --nodes=<M>
#SBATCH --ntasks-per-node=<N>
#SBATCH --cpus-per-task=<T>

通过表来查找这些Slurm参数的最佳值:

GPU作业

在考虑多个GPU之前,应首先证明使用单个GPU时GPU的高利用率。 如果GPU利用率对于单个GPU来说足够高,那么你应该如上述例子构造表来分析多个GPU情况下作业并行效率。

错误示例

示例1

#!/bin/bash
#SBATCH --job-name python_job
#SBATCH --nodes=1                  # 节点数
#SBATCH --ntasks-per-node=1        # 每个节点的任务数
#SBATCH -p cpuXeon6458
#SBATCH -c 20

module load anaconda/3-2024.02.01
conda activate biotree
python demo.py
conda deactivate

此脚本设置一个进程,20个cpu,用多线程来跑python代码。首先需要确定代码是否支持多线程,另外据了解,python对于多线程的支持并不太好,可以尝试用多进程并行的办法。

示例2

#!/bin/bash
#SBATCH --job-name cp2k_job
#SBATCH --partition cpuXeon6458
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=64

module load cp2k/2024.1
mpirun -n 10 cp2k.psmp -i Ac.inp -o test.out

此脚本申请了64个cpu,但是使用mpirun的时候只设置了10个,造成资源浪费。

示例3

#!/bin/bash
#SBATCH --job-name cp2k_job
#SBATCH --partition cpuXeon6458
#SBATCH --nodes=4
#SBATCH --ntasks-per-node=16

module load cp2k/2024.1
mpirun -n 64 cp2k.psmp -i Ac.inp -o test.out

此脚本使用4个节点跑脚本,每个节点16个进程(一个进程对应一个cpu),但建议尽量将程序运行在同一节点上(设置为-N 1,-n 64),以提高计算性能。

Contributor:mzliu


最后更新: 2025 年 06 月 30 日