mac 搭建mpi集群

版权声明:皆为本人原创,复制必究 https://blog.csdn.net/m493096871/article/details/84965765

MPI
MPI(Message Passing Interface)是一个跨语言的通讯协议,用于编写并行计算程序。MPI的实现版本主要有两个,即Open MPI (https://www.open-mpi.org/)和MPICH (http://www.mpich.org/),正确安装和配置后,便可以在 C,C++和Fortran语言中直接调用MPI所提供的各种API。本博客之前介绍过在Windows下通过MPJ来实现MPI编程开发的基本方法(有需要的读者可以参阅本博客相关文章),下面我们就来看看在Mac OS X上如何使用MPI进行并行开发。

我们之前在介绍OpenMP(注意跟本文的OpenMPI不同)时曾经提到过,因为新版本的Xcode的编译器从GCC变成了clang,所以对非Apple的产品都不再提供默认支持了。所以我们要首先在Mac OS X上正确的安装GCC,这部分内容本博客的其他文章也已经介绍过,这里不再重复。

接下来安装OpenMPI,需要使用Homebrew(同样要确认你已经安装了它),打开Terminal,然后输入如下指令

brew install openmpi
安装过程可能需要几分钟。安装成功后,在使用mpicc编译时,需要注意,如果不做任何操作,mpicc会使用默认的gcc,也就是clang的链接来编译,使得编译出错。所以在编译之前需要设置环境变量(假设你要编写的是C++程序):

export OMPI_CXX=g++-5
编写第一个MPI程序
下面我们来写一个简单的Hello World程序,注意MPI中各个API的介绍我们这里不详细介绍,这个例子只是帮助读者熟悉MPI程序的编译和执行等步骤。首先编辑输入下面代码,并


#include <cstdio>
#include <mpi.h>

int main (int argc, char **argv)
{
  int rank, size;

  MPI_Init (&argc, &argv);  /* starts MPI */

  MPI_Comm_rank (MPI_COMM_WORLD, &rank);    /* get current process id */
  MPI_Comm_size (MPI_COMM_WORLD, &size);    /* get number of processes */

  printf( "Hello world from process %d of %d\n", rank, size );

  MPI_Finalize();

  return 0;
}

然后在Terminal下输入(注意要转到你CPP源文件所在的目录下):

mpic++ helloworld.cpp -o helloworld.out
mpirun -n 2 ./helloworld.out
第一句是编译,第二句是执行,其中 -n 2 表示使用两个核(或两个nodes)。

同时使用OpenMP和MPI
我们之前已经有文章介绍过OpenMP的基本使用,下面我们想把MPI和OpenMP结合起来。来看下面这个程序,它实现的功能是即使复平面上某个矩形区域中,在某个给定的分辨率下,Mandelbrot 集合中点的数量:

#include <cstdio>
#include <cstdlib>
#include "mpi.h"
#include "omp.h"

// return 1 if in set, 0 otherwise
int inset(double real, double img, int maxiter){
    double q = (real - 0.25)*(real - 0.25) + img*img;
    if(q*(q+(real - 0.25)) < 0.25*img*img || (real+1)*(real+1) + img*img < 1/16)
        return 1;

    double z_real = real;
    double z_img = img;

    for(int iters = 0; iters < maxiter; iters++){

        double z2_real = z_real*z_real-z_img*z_img;
        double z2_img = 2.0*z_real*z_img;
        z_real = z2_real + real;
        z_img = z2_img + img;

        if(z_real*z_real + z_img*z_img > 4.0) return 0;
    }

    return 1;
}

// main
int main(int argc, char *argv[]){
    double real_lower;
    double real_upper;
    double img_lower;
    double img_upper;
    int num;
    int maxiter;
    int num_regions = (argc-1)/6;

    //double start = omp_get_wtime();

    MPI_Init(&argc,&argv);

    for(int region=0;region<num_regions;region++){
        // scan the arguments

        sscanf(argv[region*6+1],"%lf",&real_lower);
        sscanf(argv[region*6+2],"%lf",&real_upper);
        sscanf(argv[region*6+3],"%lf",&img_lower);
        sscanf(argv[region*6+4],"%lf",&img_upper);
        sscanf(argv[region*6+5],"%i",&num);
        sscanf(argv[region*6+6],"%i",&maxiter); 

        int count=0;
        double real_step = (real_upper-real_lower)/num;
        double img_step = (img_upper-img_lower)/num;

        int size, rank;
        MPI_Comm_size(MPI_COMM_WORLD, &size);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);

        int new_num = ((real_upper-real_lower)/size) /real_step;

        if(rank != size -1){
            #pragma omp parallel
            {
                #pragma omp for schedule(dynamic) reduction(+:count) nowait
                for(int real = rank * new_num; real <= (rank+1)*new_num-1; real++){
                    for(int img=0; img<=num; img++){
                        count+=inset(real_lower + real * real_step,img_lower+img*img_step,maxiter);
                    }
                }
            }
        }
        else{
            #pragma omp parallel
            {
                #pragma omp for schedule(dynamic) reduction(+:count) nowait
                for(int real = rank * new_num; real <= num; real++){
                    for(int img=0; img<=num; img++){
                        count+=inset(real_lower+real*real_step,img_lower+img*img_step,maxiter);
                    }
                }
            }
        }

        int global_sum = 0;
        MPI_Reduce(&count, &global_sum, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);

        if(rank == 0)
            printf("%d\n", global_sum);

    }
    MPI_Finalize();

    //double end = omp_get_wtime();

    //printf("Time = %fs\n", end-start);

    return EXIT_SUCCESS;
}

要编译上述程序需要在Terminal下输入:

mpic++ -fopenmp mandelbrot.cpp -o test_mpi 
执行上述程序则使用:

mpirun -n 4 ./test_mpi -2.0 1.0 -1.0 1.0 100 10000 -1 1.0 0.0 1.0 100 10000
 

猜你喜欢

转载自blog.csdn.net/m493096871/article/details/84965765