多进程-多线程程序提交
我们介绍一个多进程+多线程程版本的 hello world 程序的并行提交方式。
# 准备工作
- 登录超算系统系统,并切换到相应的工作目录。
- 编写并编译多进程+多线程版本的 hello world 程序,并将可执行文件 a.out 放到工作目录。
# hello world 程序
编写一个文本文件 hello-mpi-omp.c,内容如下:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <omp.h>
int main(int argc, char** argv) {
int rank, size;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
printf("Hello, world! Process %d of %d\n", rank, size);
#pragma omp parallel
{
printf("Hello, world! Thread %d of %d\n", omp_get_thread_num(), omp_get_num_threads());
}
MPI_Finalize();
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
代码说明:
- 包含 mpi.h 和 omp.h 头文件,用于 MPI 和 OpenMP 并行编程。
- 使用 MPI_Init 和 MPI_Finalize 进行 MPI 初始化和终止。
- 使用 MPI_Comm_rank 和 MPI_Comm_size 获取 MPI 进程号和进程数。
- 使用 printf 输出进程号和进程数。
- 使用 OpenMP 并行指令
#pragma omp parallel
声明并行块,并使用 omp_get_thread_num 和 omp_get_num_threads 获取线程号和线程数。 - 使用 MPI_Finalize 进行 MPI 终止。
# 编译 hello world 程序
加载系统上的 mpi 环境,具体加载方法可以参考用户手册,可以使用 module av
命令看看,有的系统 mpi 环境是类似这样的:
$ module av mpi
mpich/xxxx
openmpi/xxxx
MPI/Intel/IMPI/xxxx
1
2
3
4
2
3
4
选择一个进行加载即可!
mpicc -fopenmp hello-mpi-omp.c -o a.out
1
# 提交作业
假设用户可执行文件为 a.out,编写提交脚本 sub.sh 如下:
#!/bin/bash
#SBATCH -n 16 -p debug
export OMP_NUM_THREADS=4
yhrun -n 4 -p debug a.out
1
2
3
4
2
3
4
提交批处理命令如下:
yhbatch sub.sh
1
参数说明:
为什么?
为什么 yhbatch 申请了 16 个核心,而 yhrun 只申请了 4 个核心? 因为 yhbatch 申请的 -n 实际上是申请获得 16 个 task,而每个 task 默认使用 1个 CPU核心,因此获得了 16个可用的 CPU核心。接下来使用 yhrun 命令运行 -n 4 表示启用 4个 MPI 进程运行程序,而由于设置了 export OMP_NUM_THREADS=4
,因此每个 MPI 进程下开启 4 个 OpenMP 线程。刚好 4*4=16
个线程可以运行。
修改
示例中的 -p debug
参数,请根据实际情况进行计算分区名称的调整
# 运行结果
如果作业正常运行结束,会生成一个 slurm-xxxx.out 文件,内容如下:
Hello, world! Process 3 of 4
Hello, world! Thread 0 of 4
Hello, world! Thread 3 of 4
Hello, world! Thread 2 of 4
Hello, world! Thread 1 of 4
Hello, world! Process 0 of 4
Hello, world! Process 2 of 4
Hello, world! Process 1 of 4
Hello, world! Thread 0 of 4
Hello, world! Thread 0 of 4
Hello, world! Thread 0 of 4
Hello, world! Thread 3 of 4
Hello, world! Thread 3 of 4
Hello, world! Thread 3 of 4
Hello, world! Thread 2 of 4
Hello, world! Thread 2 of 4
Hello, world! Thread 2 of 4
Hello, world! Thread 1 of 4
Hello, world! Thread 1 of 4
Hello, world! Thread 1 of 4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
说明:由于 print 函数由进程/线程(无序)执行,因此结果顺序是随机的。