消息传递界面/接口(英语:Message Passing Interface,缩写MPI)是一个并行计算的应用程序接口(API),常在超级计算机、计算簇等非共享内存环境程序设计。

MPI 是一种接口,常用的实现方式是开源的 OPENMPI 和 Intel 商业化的 IMPI。

单节点/本地

正常的单机使用 mpi,一般不会出现什么问题,直接使用 mpirun -np 并行数 命令即可,以下是完整的一个 C 语言例子。

首先编写源码,如 mpi-hello.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <mpi.h>
#include <stdio.h>

int main(int argc, char** argv) {
    // 初始化 MPI 环境
    MPI_Init(NULL, NULL);

    // 通过调用以下方法来得到所有可以工作的进程数量
    int world_size;
    MPI_Comm_size(MPI_COMM_WORLD, &world_size);

    // 得到当前进程的秩
    int world_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);

    // 得到当前进程的名字
    char processor_name[MPI_MAX_PROCESSOR_NAME];
    int name_len;
    MPI_Get_processor_name(processor_name, &name_len);

    // 打印一条带有当前进程名字,秩以及
    // 整个 communicator 的大小的 hello world 消息。
    printf("Hello world from processor %s, rank %d out of %d processors\n",
           processor_name, world_rank, world_size);

    // 释放 MPI 的一些资源
    MPI_Finalize();
}

然后使用mpicc进行编译,如果是Fortran,使用对应的mpif90或者mpifort

1
mpicc mpi-hello.cpp -o mpi-hello.x

最后使用对应版本的mpirun执行,

1
2
3
4
5
6
$ mpirun -np 5 ./mpi-hello.x
Hello world from processor login1, rank 1 out of 5 processors
Hello world from processor login1, rank 2 out of 5 processors
Hello world from processor login1, rank 3 out of 5 processors
Hello world from processor login1, rank 4 out of 5 processors
Hello world from processor login1, rank 0 out of 5 processors

多节点/集群使用

对于单节点/本地使用,一般不会出错,但很多时候都是在集群上进行的,可能会使用诸如 Torque PBS等任务管理系统,由 系统进行管理和分配计算,这时应当注意,源码撰写和编译和单机使用没有什么不同,但用 mpirun 执行任务时会略有不同。 原因在于,这时候,你的计算任务不是在本地执行的,可能需要使用集群上的几十甚至更多个核,会使用多个节点,就需要 告诉它,应该在哪些节点上进行计算。

那如何告诉 mpi 在哪些节点上执行任务呢?实现的方式很简单,通过加参数来实现。

1
mpirun  -hostfile NODEFILE -np 40 ./mpi-hello.x

其中,NODEFILE是一个文本文件,其中每一行代表一个节点名称。

对于使用PBS系统的来说,NODEFILE该如何设定呢?这里,PBS系统会告诉我们,我们这个任务得到了哪些节点,并把这个节点文件的路径保存为 变量PBS_NODEFILE,所以只需要把上面的NODEFILE替换为 $PBS_NODEFILE 即可。

一个PBS脚本的例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#!/bin/bash -x
#PBS -l nodes=2:ppn=20        ##使用两个节点,每个节点有20个核
#PBS -j oe
#PBS -q test                  ## 任务提交在test队列上
#PBS -N try                   ## 任务名称
#PBS -r y
CMD='/home/test/cluster-test'
#define MPI PATH
MPIRUN=/usr/mpi/openmpi/bin/mpirun
#Setup the OpenMPI topology
n_proc=$(cat $PBS_NODEFILE | wc -l)
cd $PBS_O_WORKDIR
$MPIRUN --mca btl openib,self,sm -hostfile $PBS_NODEFILE -np $n_proc $CMD >log.out 2>&1
exit 0

或许有人会问,如果不加这个hostfile参数会发生什么情况呢?一个可能的情况是,在只有20个核的节点上执行40个mpi进程。一般情况下, 这些任务计算密集型的,同时还会伴随着大量的网络通讯,一个后果就是计算进行的很慢,更严重的后果是导致进程间的通讯网络长时间超负载, 进而导致宕机,很不幸,我就遇到了这种情况,只是不清楚集群的宕机是否跟这个有直接联系。

参考