• CLion和WSL配置MPI运行及调试环境


    本文将介绍 Windows 下,使用 CLion 和 WSL 配置 MPI 运行及调试环境的方法。

    0. 前提

    阅读本文前,请确保:

    • Windows 下已启用 WSL2,并安装了任一 Linux 发行版

    1. WSL环境配置

    (1) 配置编译环境

    sudo apt-get update
    sudo apt-get install build-essential cmake gdb
    

    (2) 配置MPI

    MPI 环境可选择通过包管理器配置,也可自行编译源码配置。简便起见,本文采用包管理器进行配置,选用的 MPI 实现为 MPICH,安装命令为:

    # Debian、Ubuntu等发行版使用如下命令安装:
    sudo apt-get install mpich
    

    如果安装成功,运行命令 mpichversion,将输出:

    mpichversion

    之后,尝试运行测试程序,将以下代码保存到文件 mpi_hello.c 中:

    /* File:       
     *    mpi_hello.c
     *
     * Purpose:    
     *    A "hello,world" program that uses MPI
     *
     * Compile:    
     *    mpicc -g -Wall -std=C99 -o mpi_hello mpi_hello.c
     * Usage:        
     *    mpiexec -n ./mpi_hello
     *
     * Input:      
     *    None
     * Output:     
     *    A greeting from each process
     *
     * Algorithm:  
     *    Each process sends a message to process 0, which prints 
     *    the messages it has received, as well as its own message.
     *
     * IPP:  Section 3.1 (pp. 84 and ff.)
     */
    #include 
    #include   /* For strlen             */
    #include      /* For MPI functions, etc */ 
    
    const int MAX_STRING = 100;
    
    int main(void) {
       char       greeting[MAX_STRING];  /* String storing message */
       int        comm_sz;               /* Number of processes    */
       int        my_rank;               /* My process rank        */
    
       /* Start up MPI */
       MPI_Init(NULL, NULL); 
    
       /* Get the number of processes */
       MPI_Comm_size(MPI_COMM_WORLD, &comm_sz); 
    
       /* Get my rank among all the processes */
       MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); 
    
       if (my_rank != 0) { 
          /* Create message */
          sprintf(greeting, "Greetings from process %d of %d!", 
                my_rank, comm_sz);
          /* Send message to process 0 */
          MPI_Send(greeting, strlen(greeting)+1, MPI_CHAR, 0, 0,
                MPI_COMM_WORLD); 
       } else {  
          /* Print my message */
          printf("Greetings from process %d of %d!\n", my_rank, comm_sz);
          for (int q = 1; q < comm_sz; q++) {
             /* Receive message from process q */
             MPI_Recv(greeting, MAX_STRING, MPI_CHAR, q,
                0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
             /* Print message from process q */
             printf("%s\n", greeting);
          } 
       }
    
       /* Shut down MPI */
       MPI_Finalize(); 
    
       return 0;
    }  /* main */
    

    编译并执行:

    # 编译
    mpicc -g -Wall -std=C99 -o mpi_hello mpi_hello.c
    
    # 运行,4表示进程数
    mpiexec -n 4 ./mpi_hello
    

    输出应为:

    Greetings from process 0 of 4!
    Greetings from process 1 of 4!
    Greetings from process 2 of 4!
    Greetings from process 3 of 4!
    

    2. CLion运行环境配置

    (1) 新建项目

    CLion 新建一个项目 mpi,将 main.c 或 main.cpp 内容修改为:

    /* File:       
     *    mpi_hello.c
     *
     * Purpose:    
     *    A "hello,world" program that uses MPI
     *
     * Compile:    
     *    mpicc -g -Wall -std=C99 -o mpi_hello mpi_hello.c
     * Usage:        
     *    mpiexec -n ./mpi_hello
     *
     * Input:      
     *    None
     * Output:     
     *    A greeting from each process
     *
     * Algorithm:  
     *    Each process sends a message to process 0, which prints 
     *    the messages it has received, as well as its own message.
     *
     * IPP:  Section 3.1 (pp. 84 and ff.)
     */
    #include 
    #include   /* For strlen             */
    #include      /* For MPI functions, etc */ 
    
    const int MAX_STRING = 100;
    
    int main(void) {
       char       greeting[MAX_STRING];  /* String storing message */
       int        comm_sz;               /* Number of processes    */
       int        my_rank;               /* My process rank        */
    
       /* Start up MPI */
       MPI_Init(NULL, NULL); 
    
       /* Get the number of processes */
       MPI_Comm_size(MPI_COMM_WORLD, &comm_sz); 
    
       /* Get my rank among all the processes */
       MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); 
    
       if (my_rank != 0) { 
          /* Create message */
          sprintf(greeting, "Greetings from process %d of %d!", 
                my_rank, comm_sz);
          /* Send message to process 0 */
          MPI_Send(greeting, strlen(greeting)+1, MPI_CHAR, 0, 0,
                MPI_COMM_WORLD); 
       } else {  
          /* Print my message */
          printf("Greetings from process %d of %d!\n", my_rank, comm_sz);
          for (int q = 1; q < comm_sz; q++) {
             /* Receive message from process q */
             MPI_Recv(greeting, MAX_STRING, MPI_CHAR, q,
                0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
             /* Print message from process q */
             printf("%s\n", greeting);
          } 
       }
    
       /* Shut down MPI */
       MPI_Finalize(); 
    
       return 0;
    }  /* main */
    

    (2) 添加工具链

    在设置 => 构建、运行、部署 => 工具链中添加一个工具链,类型选 WSL。

    添加工具链

    CLion 会自动检测填写,但 C 编译器和 C++ 编译器路径需要手动指定,相应路径使用 which 命令获取:

    # 获取 C 编译器路径
    which mpicc
    
    # 获取 C++ 编译器路径
    which mpicxx
    

    设置工具链

    (3) 指定项目所用工具链

    添加工具链后,必须手动设置项目使用新添加的工具链,在设置 => 构建、运行、部署 => CMake 中进行设置:

    指定项目所用工具链

    (4) 修改项目终端(可选)

    在设置 => 工具 => 终端中,将 Shell 路径修改为所用的发行版路径,该路径一般为:

    # C:\Users\<你的电脑用户名>\AppData\Local\Microsoft\WindowsApps\<发行版名称>.exe,如:
    C:\Users\username\AppData\Local\Microsoft\WindowsApps\ubuntu.exe
    

    修改项目终端

    (5) 修改CMake配置文件

    修改项目根目录下的 CMake 配置文件 CMakeLists.txt:

    • 在 add_executable 所在行之前添加:find_package(MPI REQUIRED)
    • 在 add_executable 所在行之后添加:
      • 如果为 C 项目:target_link_libraries( PRIVATE MPI::MPI_C)
      • 如果为 C++ 项目:target_link_libraries( PRIVATE MPI::MPI_CXX)
    • 可能需要修改 cmake_minimum_required 中的版本号,使其不高于 WSL 中安装的 CMake 版本

    示例:

    cmake_minimum_required(VERSION 3.22)
    project(mpi)
    
    set(CMAKE_C_STANDARD 11)
    
    find_package(MPI REQUIRED)
    add_executable(mpi main.c)
    target_link_libraries(mpi PRIVATE MPI::MPI_C)
    

    之后,重新加载 CMake 配置:

    重新加载CMake配置

    尝试构建项目:

    构建项目

    (6) 修改运行配置

    为了可以一键运行,需要修改运行配置:

    修改运行配置

    需要将可执行文件修改为 mpiexec 的路径(WSL 内通过 which 命令获取),并将程序实参填写为:-n 4 "$CMakeCurrentProductFile$",其中表示运行时使用 4 个进程,可根据需要修改

    运行配置

    之后,点击运行,程序输出如图:

    点击运行

    3. CLion调试MPI程序

    CLion 调试 MPI 程序需要通过使用 GDB 的附加到进程功能间接实现。

    (1) 添加断点

    在需要打断点的位置打上断点,并在所有断点位置上方添加如下代码:

    int i = 0;
    while (!i)
        sleep(5); // 需要包含unistd.h头文件
    

    之后在 sleep(5) 一行添加断点。

    添加断点

    (2) 运行程序

    点击运行按钮,运行程序。

    运行程序

    (3) GDB附加到进程功能

    点击工具 => 附加到进程:

    附加到进程功能

    在 SSH/WSL 中搜索当前可执行文件:

    搜索当前可执行文件

    选取想要调试的进程(在实例中,因为 0 号进程中未添加断点,故不应选取进程号小的进程138113),点击使用WSL GDB附加,进入调试模式。

    调试

    为了程序可以向下运行,需要将 i 的值设置成 1。

    设置值

    之后正常调试即可。

    4. 后记

    • 使用 CLion 只能通过 GDB 一个进程一个进程地调试,未找到方法调用 TotalView 同时跟踪和调试多个进程
    • 运行配置中的程序实参可以填写为:-n $Prompt$ "$CMakeCurrentProductFile$",实现每次运行前弹窗填写需要运行的进程数

    参考资料:

    1. How to work with OpenMPI projects in CLion | CLion Documentation
    2. Clion 可以编译调用 MPI 并行库的项目么? - 知乎
  • 相关阅读:
    聊聊神经网络的基础知识
    总结篇:二叉树遍历
    呕血解决:PicGo + GitHub + Typora 搭建个人图床工具
    java算法学习索引之二叉树问题
    git开发分支管理
    初识Java
    UData查询引擎优化-如何让一条SQL性能提升数倍
    34.企业快速开发平台Spring Cloud+Spring Boot+Mybatis之Highcharts 区间柱形图
    计算机网络:随机访问介质访问控制之ALOHA协议
    如何使用代码来构造HTTP请求?
  • 原文地址:https://www.cnblogs.com/bienboy/p/18098643