决定将代码中出现的MPI函数都总结一下:

调用MPI函数,通常要包含头文件

#include "mpi.h"

or

#include <mpi.h>

MPI 环境在初始化时会自动创建两个通信器,一个称为 MPI_COMM_WORLD,它包含程序中的所有进程,另一个称为 MPI_COMM_SELF,它是每个进程独自构成的、仅包含自己的通信器。MPI 系统提供了一个特殊进程号 MPI_PROC_NULL,它代表空进程 (不存在的进程),与 MPI_PROC_NULL 进行通信相当于一个空操 作,对程序的运行没有任何影响。

有好几个来自这个网页:

MPI 常用函数概述_狂草年糕的博客-CSDN博客_mpi函数

MPI_Comm_rank & MPI_Comm_size

    MPI_Comm_size(MPI_COMM_WORLD, &proc.size);
    MPI_Comm_rank(MPI_COMM_WORLD, &proc.rank);

rank返回当前进程,size返回rank的个数即processor总个数

MPI_Gather

MPI_Gather(&npeach, 1, MPI_INT, nptotal1, 1, MPI_INT, 0, MPI_COMM_WORLD);

将进程0从通信域中所有进程收集数据npeach存在数组nptotal1里面。

MPI_GATHER(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, root , comm)
  sendbuf    发送消息缓冲区的起始地址(可变)
  sendcount  发送消息缓冲区中的数据个数(整型)
  sendtype   发送消息缓冲区中的数据类型(句柄) 
   recvbuf   接收消息缓冲区的起始地址(可变,仅对于根进程) 
  recvcount  待接收的元素个数(整型,仅对于根进程)
  recvtype   接收元素的数据类型(句柄,仅对于根进程)
  root      接收进程的序列号(整型)
  comm      通信子(句柄)
函数声明为 
int MPI_Gather(void* sendbuf, int sendcount, MPI_Datatype sendtype, 
               void* recvbuf, int recvcount, MPI_Datatype recvtype, 
               int root, MPI_Comm comm)
————————————————
版权声明:本段为CSDN博主「坚强的小鱼人」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u014247371/article/details/26965185

MPI_Cart_coords

MPI_Cart_coords(MPI_COMM_3D, rank3d, 3, coords)

    MPI_Comm_rank(MPI_COMM_3D, &rank3d);
    MPI_Cart_coords(MPI_COMM_3D, rank3d, 3, coords);

Determines process coords in cartesian topology given rank in group.

int MPIAPI MPI_Cart_coords(
   MPI_Comm               comm,
   int                    rank,
   int                    maxdims,
   _Out_cap_(maxdims) int *coords
);

通常先用 MPI_Comm_rank 获得当前进程在笛卡尔通信器中的等级,再用 MPI_Cart_coords 获得进程的笛卡尔坐标。

MPI_Barrier()

    MPI_Barrier(MPI_COMM_WORLD);
    MPI_Allreduce(&prmt.npp, &prmt.npt, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);

用于通信子中所有进程的同步,即等前面的步骤所有进程都完成才进行后面的步骤。

MPI_Allreduce()

全局规约函数,将所有发送信息进行同一个操作,所有进程均接收信息。

    MPI_Barrier(MPI_COMM_WORLD);
    MPI_Allreduce(&prmt.npp, &prmt.npt, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);

将所有prmt.npp加和赋值给所有prmt.bpt

MPI_Reduce(
    void* send_data,
    void* recv_data,
    int count,
    MPI_Datatype datatype,
    MPI_Op op,
    int root,
    MPI_Comm communicator)
————————————————
版权声明:本文为CSDN博主「Harold Gao」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_40255793/article/details/84201243

 每个进程发送容量为 count 的数组 send_data,root 进程收到后进行 op 操作,存放在容量也为 count 的数组 recv_data 中。

usleep()

    MPI_Barrier(MPI_COMM_WORLD);
    usleep(50000 * proc.rank);
usleep功能把进程挂起一段时间, 单位是微秒(百万分之一秒)

MPI_Send & MPI_Recv()

#ifdef __PERIODIC__
        MPI_Barrier(MPI_COMM_WORLD);
        if (proc.rank == proc.size - 1) {
            MPI_Send(&nptf, 1, MPI_INT, 0, dim * 2, MPI_COMM_WORLD);
        }
        if (proc.rank == 0) {
            MPI_Recv(&npfb, 1, MPI_INT, proc.size - 1, dim * 2, MPI_COMM_WORLD,
                    &proc.status);
        }

        MPI_Barrier(MPI_COMM_WORLD);
#endif

这两个函数通常一起出现,这个代码是将nptf的值发送给npfb。

MPI_Sendrecv

若单纯的利用MPI_Send, MPI_Recv函数进行通讯的话,容易造成死锁,下面介绍MPI_Sendrecv的来解决这个问题。顾名思义,MPI_Sendrecv表示的作用是将本进程的信息发送出去,并接收其他进程的信息.

            MPI_Sendrecv(src, srcsize, MPI_BYTE, proc.fs.x, tag,
                         dst, dstsize, MPI_BYTE, proc.fr.x, tag,
                         MPI_COMM_WORLD, &proc.status);

另外,我对tag的理解就是方便debug的时候判断是哪个位置出错了。 

MPI_Sendrecv( void *sendbuf //initial address of send buffer
              int sendcount //number of entries to send
              MPI_Datatype sendtype //type of entries in send buffer
              int dest //rank of destination
              int sendtag //send tag
              void *recvbuf //initial address of receive buffer
              int recvcount //max number of entries to receive
              MPI_Datatype recvtype //type of entries in receive buffer  (这里数目是按实数的数目,若数据类型为MPI_COMPLEX时,传递的数目要乘以2) 
         int source //rank of source 
         int recvtag //receive tag
         MPI_Comm comm //group communicator
          MPI_Status status //return status;

 

MPI_Status

MPI类型MPI_Status是一个有至少三个成员的结构,MPI_SOURCE,MPI_TAG和MPI_ERROR。假定程序有如下的定义:

#ifdef __USE_MPI__
        MPI_Status status;
#endif

&status作为最后一个参数传递给MPI_Recv函数并调用它后,可以通过检查以下两个成员来确定发送者和标签。

status.MPI_SOURCE
status.MPI_TAG

接收量不是存储在应用程序可以直接访问到的域内,但是用户可以调用MPI_Get_count函数找到这个值。

int MPI_Get_count(
	MPI_Status * 	status_p,
    MPI_Datatype 	type,
    int *			count_p
);

 

MPI_Finalize()

用来清理 MPI 环境的。这个调用之后就没有 MPI 函数可以被调用了。

Logo

汇聚原天河团队并行计算工程师、中科院计算所专家以及头部AI名企HPC专家,助力解决“卡脖子”问题

更多推荐