https://zhuanlan.zhihu.com/p/158584571

 

 

在本课中,我将向您展示一个基本的 MPI hello world 应用程序,并讨论如何运行 MPI 程序。本课将涵盖初始化 MPI 和跨多个进程运行 MPI 作业的基础知识。本课旨在安装 MPICH2(特别是 1.4)。 

- 此站点的所有代码都在GitHub 上。本教程的代码位于tutorials/mpi-hello-world/code 下。

你好世界代码示例

让我们深入了解本课中位于mpi_hello_world.c 中的代码。下面是代码的一些摘录。

#include <mpi.h>
#include <stdio.h>

int main(int argc, char** argv) {
    // Initialize the MPI environment
    MPI_Init(NULL, NULL);

    // Get the number of processes
    int world_size;
    MPI_Comm_size(MPI_COMM_WORLD, &world_size);

    // Get the rank of the process
    int world_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);

    // Get the name of the processor
    char processor_name[MPI_MAX_PROCESSOR_NAME];
    int name_len;
    MPI_Get_processor_name(processor_name, &name_len);

    // Print off a hello world message
    printf("Hello world from processor %s, rank %d out of %d processors\n",
           processor_name, world_rank, world_size);

    // Finalize the MPI environment.
    MPI_Finalize();
}

您会注意到构建 MPI 程序的第一步是将 MPI 头文件包含在#include <mpi.h>. 在此之后,MPI 环境必须初始化为:

MPI_Init(
    int* argc,
    char*** argv)

在 期间MPI_Init,构造了 MPI 的所有全局和内部变量。例如,围绕所有产生的进程形成一个通信器,并为每个进程分配唯一的等级。目前,MPI_Init接受两个不必要的参数,额外的参数只是留作额外空间,以防将来的实现可能需要它们。

之后MPI_Init,有两个主要函数被调用。这两个函数几乎用在您将要编写的每个 MPI 程序中。

MPI_Comm_size(
    MPI_Comm communicator,
    int* size)

MPI_Comm_size返回通信器的大小。在我们的示例中,MPI_COMM_WORLD(由 MPI 为我们构建)包含作业中的所有进程,因此该调用应返回作业请求的进程数量。

MPI_Comm_rank(
    MPI_Comm communicator,
    int* rank)

MPI_Comm_rank返回进程在通信器中的等级。通信器内的每个进程都被分配一个从零开始的递增等级。进程的等级主要用于发送和接收消息时的识别目的。

该程序中的一个杂项和较少使用的功能是:

MPI_Get_processor_name(
    char* name,
    int* name_length)

MPI_Get_processor_name获取正在执行进程的处理器的实际名称。该程序中的最终调用是:

MPI_Finalize()

MPI_Finalize用于清理 MPI 环境。在此之后不能再进行 MPI 调用。

运行 MPI hello world 应用程序

现在检查代码并检查代码文件夹。其中有一个makefile。

>>> git clone https://github.com/mpitutorial/mpitutorial
>>> cd mpitutorial/tutorials/mpi-hello-world/code
>>> cat makefile
EXECS=mpi_hello_world
MPICC?=mpicc

all: ${EXECS}

mpi_hello_world: mpi_hello_world.c
    ${MPICC} -o mpi_hello_world mpi_hello_world.c

clean:
    rm ${EXECS}

我的 makefile 查找 MPICC 环境变量。如果您将 MPICH2 安装到本地目录,请将您的 MPICC 环境变量设置为指向您的 mpicc 二进制文件。您安装中的 mpicc 程序实际上只是 gcc 的一个包装器,它使编译和链接所有必需的 MPI 例程变得更加容易。

>>> export MPICC=/home/kendall/bin/mpicc
>>> make
/home/kendall/bin/mpicc -o mpi_hello_world mpi_hello_world.c

程序编译完成后,就可以执行了。现在是您可能需要进行一些额外配置的部分。如果在节点集群上运行 MPI 程序,则必须设置主机文件。如果您只是在笔记本电脑或单台机器上运行 MPI,请忽略下一条信息。

主机文件包含将在其上执行 MPI 作业的所有计算机的名称。为了便于执行,您应该确保所有这些计算机都具有 SSH 访问权限,并且您还应该设置一个授权密钥文件以避免 SSH 出现密码提示。我的主机文件看起来像这样。

>>> cat host_file
cetus1
cetus2
cetus3
cetus4

对于我在下载中提供的运行脚本,您应该设置一个名为 MPI_HOSTS 的环境变量并将其指向您的主机文件。当 MPI 作业启动时,我的脚本将自动将其包含在命令行中。如果您不需要主机文件,只需不要设置环境变量。此外,如果您在本地安装了 MPI,则应将 MPIRUN 环境变量设置为指向安装中的 mpirun 二进制文件。

完成此操作后,您可以使用包含在主存储库中的 run.py python 脚本。它存储在教程目录下,可以执行所有教程中的任何程序(它还尝试在执行之前构建可执行文件)。从根 mpitutorial 文件夹尝试以下操作。

>>> export MPIRUN=/home/kendall/bin/mpirun
>>> export MPI_HOSTS=host_file
>>> cd tutorials
>>> ./run.py mpi_hello_world
/home/kendall/bin/mpirun -n 4 -f host_file ./mpi_hello_world
Hello world from processor cetus2, rank 1 out of 4 processors
Hello world from processor cetus1, rank 0 out of 4 processors
Hello world from processor cetus4, rank 3 out of 4 processors
Hello world from processor cetus3, rank 2 out of 4 processors

正如预期的那样,MPI 程序在我的主机文件中的所有主机上启动。每个进程都被分配了一个唯一的等级,它与进程名称一起打印出来。从我的示例输出中可以看出,进程的输出是任意顺序的,因为在打印之前不涉及同步。

注意脚本如何调用 mpirun。这是 MPI 实现用来启动作业的程序。进程在主机文件中的所有主机上生成,MPI 程序在每个进程中执行。我的脚本自动提供-n标志以将 MPI 进程数设置为 4。尝试更改运行脚本并启动更多进程!但是不要意外地使您的系统崩溃。:-)

现在您可能会问,“我的主机实际上是双核机器。我怎样才能让 MPI 在单个机器之前首先跨单个内核生成进程?” 解决方案非常简单。只需修改您的主机文件并在主机名后放置一个冒号和每个处理器的核心数。例如,我指定我的每个主机都有两个内核。

>>> cat host_file
cetus1:2
cetus2:2
cetus3:2
cetus4:2

当我再次执行运行脚本时,瞧!,MPI 作业仅在我的两台主机上生成两个进程。

>>> ./run.py mpi_hello_world
/home/kendall/bin/mpirun -n 4 -f host_file ./mpi_hello_world
Hello world from processor cetus1, rank 0 out of 4 processors
Hello world from processor cetus2, rank 2 out of 4 processors
Hello world from processor cetus2, rank 3 out of 4 processors
Hello world from processor cetus1, rank 1 out of 4 processors

下一个

现在您已经对 MPI 程序的执行方式有了基本的了解,现在是学习基本点对点通信例程的时候了。在下一课中,我将介绍MPI 中的基本发送和接收例程。也可以随意查看MPI 教程,以获取所有 MPI 课程的完整参考。

遇到麻烦?使困惑?请随时在下面发表评论,也许我或其他读者可以提供帮助。