返回介绍

3.6 检测 MPI 的并行环境

发布于 2025-05-06 21:45:55 字数 4331 浏览 0 评论 0 收藏

NOTE : 此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-06 中找到,包含一个 C++和一个 C 的示例。该示例在 CMake 3.9 版(或更高版本) 中是有效的,并且已经在 GNU/Linux、macOS 和 Windows 上进行过测试。 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-06 中也有一个适用于 CMake 3.5 的 C 示例。

消息传递接口(Message Passing Interface, MPI),可以作为 OpenMP(共享内存并行方式) 的补充,它也是分布式系统上并行程序的实际标准。尽管,最新的 MPI 实现也允许共享内存并行,但高性能计算中的一种典型方法就是,在计算节点上 OpenMP 与 MPI 结合使用。MPI 标准的实施包括:

  1. 运行时库
  2. 头文件和 Fortran 90 模块
  3. 编译器的包装器,用来调用编译器,使用额外的参数来构建 MPI 库,以处理目录和库。通常,包装器 mpic++/mpiCC/mpicxx 用于 C++, mpicc 用于 C, mpifort 用于 Fortran。
  4. 启动 MPI:应该启动程序,以编译代码的并行执行。它的名称依赖于实现,可以使用这几个命令启动: mpirunmpiexecorterun

本示例,将展示如何在系统上找到合适的 MPI 实现,从而编译一个简单的“Hello, World”MPI 例程。

准备工作

示例代码( hello-mpi.cpp ,可从 http://www.mpitutorial.com 下载) 将在本示例中进行编译,它将初始化 MPI 库,让每个进程打印其名称:

#include <iostream>
​
#include <mpi.h>
​
int main(int argc, char **argv)
{
  // Initialize the MPI environment. The two arguments to MPI Init are not
  // currently used by MPI implementations, but are there in case future
  // implementations might need the arguments.
  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
  std::cout << "Hello world from processor " << processor_name << ", rank "
            << world_rank << " out of " << world_size << " processors" << std::endl;
​
  // Finalize the MPI environment. No more MPI calls can be made after this
  MPI_Finalize();
}

具体实施

这个示例中,我们先查找 MPI 实现:库、头文件、编译器包装器和启动器。为此,我们将用到 FindMPI.cmake 标准 CMake 模块:

  1. 首先,定义了 CMake 最低版本、项目名称、支持的语言和语言标准:
    cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
    ​
    project(recipe-06 LANGUAGES CXX)
    ​
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_EXTENSIONS OFF)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
  2. 然后,调用 find_package 来定位 MPI:
    find_package(MPI REQUIRED)
  3. 与前面的配置类似,定义了可执行文件的的名称和相关源码,并链接到目标:
    add_executable(hello-mpi hello-mpi.cpp)
    ​
    target_link_libraries(hello-mpi
      PUBLIC
           MPI::MPI_CXX
      )
  4. 配置和构建可执行文件:
    $ mkdir -p build
    $ cd build
    $ cmake .. # -D CMAKE_CXX_COMPILER=mpicxx C++例子中可加,加与不加对于构建结果没有影响╭(╯^╰)╮
    ​
    -- ...
    -- Found MPI_CXX: /usr/lib/openmpi/libmpi_cxx.so (found version "3.1")
    -- Found MPI: TRUE (found version "3.1")
    -- ...
    ​
    $ cmake --build .
  5. 为了并行执行这个程序,我们使用 mpirun 启动器(本例中,启动了两个任务):
    $ mpirun -np 2 ./hello-mpi
    ​
    Hello world from processor larry, rank 1 out of 2 processors
    Hello world from processor larry, rank 0 out of 2 processors

工作原理

请记住,编译包装器是对 MPI 库编译器的封装。底层实现中,将会调用相同的编译器,并使用额外的参数(如成功构建并行程序所需的头文件包含路径和库) 来扩充它。

编译和链接源文件时,包装器用了哪些标志?我们可以使用 --showme 选项来查看。要找出编译器的标志,我们可以这样使用:

$ mpicxx --showme:compile
​
-pthread

为了找出链接器标志,我们可以这样:

$ mpicxx --showme:link
​
-pthread -Wl,-rpath -Wl,/usr/lib/openmpi -Wl,--enable-new-dtags -L/usr/lib/openmpi -lmpi_cxx -lmpi

与之前的 OpenMP 配置类似,我们发现到 MPI 的链接非常简单,这要归功于 FindMPI 模块提供的目标:

正如在前面的配方中所讨论的,对于 CMake 版本低于 3.9,需要更多的工作量:

add_executable(hello-mpi hello-mpi.c)
​
target_compile_options(hello-mpi
  PUBLIC
      ${MPI_CXX_COMPILE_FLAGS}
  )
​
target_include_directories(hello-mpi
  PUBLIC
      ${MPI_CXX_INCLUDE_PATH}
  )
​
target_link_libraries(hello-mpi
  PUBLIC
      ${MPI_CXX_LIBRARIES}
  )

本示例中,我们讨论了 C++项目。其中的参数和方法对于 C 或 Fortran 项目同样有效。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。