MPI函数列表


MPI函数
头文件: mpi.h/mpif.h
int MPI_Init(int *argc, char ***argv) 
启动MPI环境,标志并行代码的开始.
并行代码之前,第一个mpi函数(除MPI_Initialize()外).
要求main必须带能运行,否则出错.
 
通信子(通信空间): MPI_COMM_WORLD:
一个通信空间是一个进程组和一个上下文的组合.上下文可看作为组的超级标签,用于区分不同的通信子.
在执行函数MPI_Init之后,一个MPI程序的所有进程形成一个缺省的组,这个组的通信子即被写作MPI_COMM_WORLD.
该参数是MPI通信操作函数中必不可少的参数,用于限定参加通信的进程的范围.

 

int MPI_Comm_size(MPI_Comm comm, int *size);

获得通信空间comm中规定的组包含的进程的数量.
指定一个communicator,也指定了一组共享该空间的进程, 这些进程组成该communicator的group.

 

int MPI_Comm_rank(MPI_Comm comm, int *rank);

得到本进程在通信空间中的rank值,即在组中的逻辑编号(从0开始).

 

int MPI_Finalize() 
标志并行代码的结束,结束除主进程外其它进程.
之后串行代码仍可在主进程(rank = 0)上运行(如果必须).

 

int MPI_Send(void* buf, int count, MPI_Datatype datatype,  int dest, int tag, MPI_Comm comm);

  IN  buf         发送缓冲区的起始地址

     IN  count        要发送信息的元素个数

     IN  datatype  发送信息的数据类型

     IN  dest         目标进程的rank值

     IN  tag          消息标签

     IN  comm       通信子

 

int MPI_Recv(void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status);

  OUT  buf         接收缓冲区的起始地址

     IN  count        要接收信息的元素个数

     IN  datatype    接收信息的数据类型

     IN  source         源进程的rank值

     IN  tag          消息标签

     IN  comm       通信子

  OUT status  status对象,包含实际接收到的消息的有关信息

 

MPI标识一条消息的信息包含四个域:
Source: 发送进程隐式确定,由进程的rank值唯一标识
Destination: Send函数参数确定
Tag: Send函数参数确定,用于识别不同的消息 (0,UB),UB:MPI_TAG_UB>=32767.
Communicator: 缺省MPI_COMM_WORLD
Group:有限/N,有序/Rank    [0,1,2,…N-1]
Contex:Super_tag,用于标识该通讯空间.
 
当使用MPI_ANY_SOURCE或/和MPI_ANY_TAG接收消息时如何确定消息的来源source 和 tag值呢?
在C中,status.MPI_SOURCE, status.MPI_TAG.
在Fortran中, source=status(MPI_SOURCE), tag=status(MPI_TAG).
Status还可用于返回实际接收到消息的长度
int MPI_Get_count(MPI_Status status, MPI_Datatype datatype,int* count)
IN status 接收操作的返回值.
IN datatype 接收缓冲区中元素的数据类型.
OUT count 接收消息中的元素个数. 
 
rank = MPI_PROC_NULL的进程称为空进程
使用空进程的通信不做任何操作.
向MPI_PROC_NULL发送的操作总是成功并立即返回.
从MPI_PROC_NULL接收的操作总是成功并立即返回,且接收缓冲区内容为随机数.
status
status.MPI_SOURCE = MPI_PROC_NULL
status.MPI_TAG = MPI_ANY_TAG
MPI_Get_count(&status,MPI_Datatype datatype, &count) =>count = 0
 
•用户发送缓冲区的重用:
–非阻塞的发送:仅当调用了有关结束该发送的语句后才能重用发送缓冲区,否则将导致错误;对于接收方,与此相同,仅当确认该接收请求已完成后才 能使用。所以对于非阻塞操作,要先调用等待MPI_Wait()或测试MPI_Test()函数来结束或判断该请求,然后再向缓冲区中写入新内容或读取新 内容。
•阻塞发送将发生阻塞,直到通讯完成.
•非阻塞可将通讯交由后台处理,通信与计算可重叠.
•发送语句的前缀由MPI_改为MPI_I, I:immediate:
–标准模式:MPI_Send(…)->MPI_Isend(…)
–Buffer模式:MPI_Bsend(…)->MPI_Ibsend(…) 
 
•int MPI_Isend(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request)
–IN buf 发送缓冲区的起始地址
–IN count 发送缓冲区的大小(发送元素个数)
–IN datatype 发送缓冲区数据的数据类型
–IN dest 目的进程的秩
–IN tag 消息标签
–IN comm 通信空间/通信子
–OUT request  非阻塞通信完成对象(句柄)
•int MPI_Irecv(void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request* request)
 
•发送的完成: 代表发送缓冲区中的数据已送出,发送缓冲区可以重用。它并不代表数据已被接收方接收。数据有可能被缓冲;
•接收的完成:代表数据已经写入接收缓冲区。接收者可访问接收缓冲区。
•通过 MPI_Wait ()MPI_Test ()来判断通信是否已经完成;
 
•int MPI_Wait(MPI_Request* request, MPI_Status * status);

当request标识的通信结束后,MPI_Wait()才返回。如果通信是非阻塞的,返回时request = MPI_REQUEST_NULL;函数调用是非本地的;

 
•MPI_Probe()和MPI_Iprobe()函数探测接收消息的内容。用户根据探测到的消息内容决定如何接收这些消息,如根据消息大小分配缓冲区等。前者为阻塞方式,即只有探测到匹配的消息才返回;后者为非阻塞,即无论探测到与否均立即返回.
•int MPI_Probe(int source, int tag, MPI_Comm comm, MPI_Status* status)
•int MPI_Iprobe(int source, int tag, MPI_Comm comm, int*flag, MPI_Status* status)
–IN source 数据源的rank,可以是MPI_ANY_SOURCE
–IN tag      数据标签,可以是MPI_ANY_TAG
–IN comm  通信空间/通信子
–OUT flag   布尔值,表示探测到与否(只用于非阻塞方式)
–OUT status status对象,包含探测到消息的内容 
 
•mpicc编译并连接用C语言编写的MPI程序
•mpiCC编译并连接用C++编写的MPI程序
•mpif77编译并连接用FORTRAN 77编写的MPI程序
•mpif90编译并连接用Fortran 90编写的MPI程序
 

mpirun –np N <program>

其中:

N: 同时运行的进程数

<program>:  可执行MPI程序名

 

mpirun –p4pg <pgfile> <program>

•<pgfile>为配置文件,其格式为:

<机器名>  <进程数> <程序名>

<机器名>  <进程数> <程序名>

<机器名>  <进程数> <程序名>

•例如: (注:第一行的0并不表示在node0上没有进程,这里的0特指在node0上启动MPI程序) 

node0  0 /public0/dair/mpi/cpi 

node1  1 /public0/dair/mpi/cpi 

node2  1 /public0/dair/mpi/cpi 

•这种方式允许可执行程序由不同的名字和不同的路径
 

mpirun –machinefile <machinefile> -np <N>  <program>

•<machinefile>为配置文件,其格式为:

<机器名>  

<机器名>  

<机器名>  

 
 
•MPI程序的一般启动方式:

mpirun –np <number of processor> <program name and argument>

•完整的MPI运行方式:

mpirun [mpirun_options] <program> [options…]

 
•将原数据类型,按顺序进行多次复制 
MPI_Type_contiguous(count, oldtype, newtype)
IN count 复制个数。
IN oldtype 旧数据类型。
举例:

float  a[1000][1000]; MPI_Datatype C_R;

MPI_Type_contiguous(1000,MPI_FLOAT,&C_R);

MPI_SEND(&(a[0][0]),1,C_R, right,tag ,MPI_COMM_WORLD) 

 
•MPI_Vector()函数首先通过连续复制若干个旧数据类型形成一个“块”,然后通过等间隔地复制该块儿形成新的数据类型。块与块之间的空间时旧数据类型的倍数。

#include "mpi.h"

int MPI_Type_vector  ( 

   int count,   /*数据块个数 (非负整数)*/

   int blocklen,   /*块中元素个数 (非负整数)*/

   int stride,   /*块间起始地址间隔 (非负整数)*/

   MPI_Datatype   old_type,   /*原始数据类型(句柄)*/

   MPI_Datatype   *newtype   /*派生数据类型指针*/

)

举例:

用MPI_Vector进行矩阵的行列置换 

    …    

    float A[10][10];

    MPI_Datatype column_mpi_t;

  

    MPI_Type_vector(10, 1, 10, MPI_FLOAT,  &column_mpi_t);

    MPI_Type_commit(&column_mpi_t);

  

    if (my_rank == 0) 

        MPI_Send(&(A[0][0]), 1, column_mpi_t, 1, 0, MPI_COMM_WORLD);

    else {    /* my_rank = 1 */

        MPI_Recv(&(A[0][0]),  10,  MPI_FLOAT,  0,  0,

                               MPI_COMM_WORLD,  &status);

 

int MPI_Type_indexed  (

   int count,   /*数据块的个数,数据块间不连续*/

  int blocklens[],  /*每一数据块中元素的个数,为一个非负整型数组*/

  int indices[],       /*每一块数据在原始数据类型中的起始位置,整型数组*/

  MPI_Datatype old_type,   /*原始数据类型(名柄)*/

  MPI_Datatype* newtype   /*派生数据类型指针*/

)

举例:
MPI_Type_indexed应用示意(将A矩阵的上三角部分送到另一个处理器中的T矩阵的对应位置) 

float  A[n][n];    /* Complete Matrix */ 

float       T[n][n];     /* Upper Triangle  */ 

int           displacements[n]; 

int           block_lengths[n]; 

MPI_Datatype  index_mpi_t; 

  

for (i = 0; i < n; i++) { 

    block_lengths[i] = n-i; 

    displacements[i] = (n+1)*i; 

MPI_Type_indexed(n, block_lengths, displacements,MPI_FLOAT, &index_mpi_t); 

MPI_Type_commit(&index_mpi_t); 

  

if (my_rank == 0) 

  MPI_Send(A, 1, index_mpi_t, 1, 0, MPI_COMM_WORLD); 

else /* my_rank == 1 */ 

     MPI_Recv(T, 1, index_mpi_t, 0, 0, MPI_COMM_WORLD,  &status); 

 
 
允许每个块不同数据类型的拷贝
MPI_Type_struct(count, array_of_blockths, array_of_displacements, array_of_types, newtype)
IN count 块的数量
IN array_of_blockths 每个块中所含元素数量
IN array_of_displacements 每块偏移字节数
IN array_of_types 块中元素类型
OUT newtype 新数据类型
举例:
•MPI_Type_struct的例子 

struct partstruct {char class; double d[6]; char b[7]};

struct partstruct particle[1000];

int i,dest,rank;

MPI_Datatype particletype,type[3]={MPI_CHAR, MPI_DOUBLE,MPI_CHAR}

int blocklen[3]={1,6,7};

MPI_Aint disp[3]={0,sizeof(double),7*sizeof(double)};

MPI_Type_struct(3,blocklen,disp,type,&particletype);

 

int MPI_Pack (

  void  *inbuf,   /* 输入缓冲区起始地址*/

  int   incount,   /* 输入数据项个数 */

  MPI_Datatype  datatype, /* 输入数据项的数据类型 */ 

  void  *outbuf,  /* 输出缓冲区起始地址 */ 

  int  outcount,  /* 输出缓冲区大小 */ 

  int  *position,  /* 输出缓冲区当前位置 */ 

  MPI_Comm  comm /* 通信域 */ 

)

例:

packsize=0;

MPI_Pack(&a,1,MPI_INT,packbuf,100,&packsize,MPI_COMM_WORLD);

MPI_Pack(&b,1,MPI_DOUBLE, packbuf,100,&packsize,MPI_COMM_WORLD);

 

int MPI_Unpack (

  void  *inbuf,   /* 输入缓冲区起始地址*/

  int   incount,   /* 输入数据项大小*/

  int  *position,  /* 缓冲区当前位置 */

  void  *outbuf,  /* 输出缓冲区起始地址 */ 

  int  outcount,  /* 输出缓冲区大小 */

  MPI_Datatype  datatype, /* 输出数据项的数据类型 */ 

  MPI_Comm  comm /* 通信域 */ 

)

例:

pos=0;

MPI_Unpack(packbuf,packsize,&pos,&a,1,MPI_INT,MPI_COMM_WROLD);

MPI_Unpack(packbuf,packsize,&pos,&b,1,MPI_FLOAT,MPI_COMM_WROLD);

 
•提交:int MPI_Type_commit(MPI Datatype *datatype)
–将数据类型映射进行转换或“编译”
–一种数据类型变量可反复定义,连续提交
•释放:int MPI_Type free(MPI_Datatype *datatype)
将数据类型设为MPI_DATATYPE_NULL
 
 

int MPI_Bcast ( 

   void *buffer,/*发送/接收buf*/

   int     count,  /*元素个数*/

   MPI_Datatype datatype,

   int root,    /*指定根进程*/

   MPI_Comm comm) 

根进程既是发送缓冲区也是接收缓冲区

举例:

int p, myrank; 

float buf;

MPI_Comm comm;

MPI_Init(&argc, &argv);

/*得进程编号*/

MPI_Comm_rank(comm, &my_rank);

/* 得进程总数 */

MPI_Comm_size(comm, &p);

if(myrank==0)

     buf = 1.0; 

MPI_Bcast(&buf,1,MPI_FLOAT,0, comm); 

 
 

根进程接收其他进程来的消息(包括根进程),按每在进程在通信组中的编号依次联接在一下,存放在根进程的接收缓冲区中.

•int MPI_Gather ( void *sendbuf, int sendcnt, MPI_Datatype sendtype,  void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm  comm ) 参数:

•sendbuf 发送缓冲区起始位置 
•sendcount 发送元素个数
•sendtype 发送数据类型
•recvcount 接收元素个数(所有进程相同) (该参数仅对根进程有效)
•recvtype 接收数据类型(仅在根进程中有效)
•root 通过rank值指明接收进程
•comm 通信空间 
 
•int MPI_Gatherv ( void *sendbuf, int sendcnt, MPI_Datatype  sendtype, void *recvbuf, int *recvcnts, int *displs, MPI_Datatype  recvtype, int root, MPI_Comm comm )
•参数:
•sendbuf 发送缓冲区的起始位置 
•sendcount 发送元素个数
•sendtype 发送数据类型 
•recvcounts 整型数组(大小等于组的大小),用于指明从各进程要接收的元素的个数(仅对根进程有效) 
•displs 整型数组(大小等于组的大小). 其元素 i指明要接收元素存放位置相对于接收缓冲区起始位置的偏移量 (仅在根进程中有效)
•recvtype 接收数据类型 
•root 通过rank值指明接收进程
comm 通信空间

 

/*得进程编号*/

MPI_Comm_rank(comm,&my_rank);

/* 得进程总数 */

MPI_Comm_size(comm, &p);

if(myrank==0)

  buf=(float*)malloc(p*10*sizeof(float);/*开辟接收缓冲区*/

MPI_Gather(data,10,MPI_FLOAT,

  buf,10,MPI_FlOAT,0,comm); 

 

根进程中存储了p个消息,第i个消息将传给第i个进程.

int MPI_Scatter ( void *sendbuf, int sendcnt, MPI_Datatype sendtype,  void *recvbuf, int recvcnt, MPI_Datatype recvtype, int root, MPI_Comm  comm )

int p, myrank; 

float data[10];

float* buf;

MPI_Comm comm;

MPI_Init(&argc, &argv);

/*得进程编号*/

MPI_Comm_rank(comm,&my_rank);

/* 得进程总数 */

MPI_Comm_size(comm, &p);

if(myrank==0)

  buf = (float*)malloc(p*10*sizeof(float);/*开辟发送缓冲区*/

MPI_Scatter(buf,10,MPI_FLOAT,

  data,10,MPI_FlOAT,0,comm); 

 

对组中所有进程的发送缓冲区中的数据用OP参数指定的操作进行运算,并将结果送回到根进程的接收缓冲区中. 

int MPI_Reduce ( void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm )

举例:

int p, myrank; 

float data = 0.0;

float buf;

MPI_Comm comm;

MPI_Init(&argc, &argv);

/*得进程编号*/

MPI_Comm_rank(comm,&my_rank);

/*各进程对data进行不同的操作*/ 

data = data + myrank * 10;

/*将各进程中的data数相加并存入根进程的buf中 */

MPI_Reduce(&data,&buf,1,MPI_FLOAT,MPI_SUM,0,comm); 

 
MPI环境管理
•MPI起动与结束:
–MPI_Init();
–MPI_Initialized();测试是否已执行MPI_Init();
–MPI_Finalize();
•MPI计时函数
–double MPI_Wtime();返回自过去某一时刻调用时的时间间隔,以秒为单位.
–double MPI_Wtick();返回用作硬件计时的两次脉冲间的间隔时间,以秒为单位. 
组,上下文和通信空间管理.
 
•通信域:描述进程间的通信关系,包括
–通信上下文:区别不同的通信域,一个上下文所发送的消息不能被另一个上下文所接收
–进程组:多个进程的有序集合 
–虚拟拓扑:多个进程在逻辑上的排列关系,反映了进程间的通信模型
–属性:用户可通过自定义的属性,将任意信息附加到通信域上
 
•MPI_GROUP_NULL
–无效进程组句柄
•MPI_COMM_NULL
–无效通信域句柄
•MPI_GROUP_EMPTY
–有效进程组句柄,包括元素个数为0
•MPI_COMM_SELF
–有效通信域句柄,包括元素仅为当前进程
•MPI_COMM_WORLD
–有效通信域句柄,包括元素为所有进程 
 
•不同的进程可以有不同的分工,可为之建立不同的通信域,这要借助进程组完成。
•得到通信域对应的进程组:

MPI_COMM_GROUP(comm,group)

•根据组创建新的通信域:

MPI_COMM_CREATE(comm,g,ncomm) 

•比较:

MPI_GROUP_COMPARE(g1,g2,result)

•并:      

MPI_GROUP_UNION(g1,g2,newg)

•交:

MPI_GROUP_INTERSECTION(g1,g2,newg)

•差:

MPI_GROUP_DIFFERENCE(g1,g2,newg) 

•所包含的进程形成新组:

MPI_GROUP_INCL(g,n,ranks,newg)

•去除掉进程后形成新组:

MPI_GROUP_EXCL(g,n,ranks,newg)

•得到组的大小 

MPI_GROUP_SIZE(group,size)

•得到当前进程在组中的编号

MPI_GROUP_RANK(group,rank) 

 

•比较 

MPI_COMM_COMPARE(comm1,comm2,result)

•复制

MPI_COMM_DUP(comm,newcomm)

•释放

MPI_COMM_FREE(comm) 

 

•通信域的分裂MPI_COMM_SPLIT(comm,color,key,newcomm)
–根据color值的不同,形成不同的通信域
–根据key值的大小,决定新通信域中的编号顺序 

 

•在许多并行应用程序中,进程的线性排列不能充分地反映进程间的通信模型
•进程经常被排列成二维或三维网格形式的拓扑模型,而且通常用一个图来描述逻辑进程排列
•不同的进程拓扑结构,可使程序设计更为自然,也为在相近的物理拓扑上的高效实现提供支持。 

 

int MPI_Topo_test(comm, status)

IN comm通信域

OUT status通信域comm的拓扑结构

 

MPI_CART_CREATE(comm_old, ndims, dims, periods, reorder, comm_cart)

IN comm_old 输入通信域

IN ndims 笛卡尔网格的维数

IN dims 大小为ndims的整数数组,定义每一维的进程数

IN periods 大小为ndims的逻辑数组,定义在一维上网格的周期性。

IN reorder 标识数是否可以重排序。

OUT comm_cart 带有新的笛卡尔拓扑的通信域。

 

MPI_DIMS_CREATE(nnodes, ndims,dims)

根据用户指定的总进程数nnodes和总维数ndims,得到每一维上的进程个数,放在dims中

 

MPI_CART_COORDS(comm, rank, maxdims, coords) 

得到rank值对应的笛卡尔坐标 

 

平移操作
•MPI_CART_SHIFT(comm, direction, disp, rank_source, rank_dest)
 
创建图拓扑
MPI_GRAPH_CREATE(comm_old, nmodes, index, edges, reorder, comm_graph)
 
得到相邻进程数
MPI_GRAPH_NEIGHBORS_COUNT(comm, rank, nneighbors)
 
得到相邻进程标识
MPI_GRAPH_NEIGHBORS(comm, rank, maxneighbors, neighbors)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值