MPI入门
参考OpenMPI的文档
Rank可以理解为进程的编号。
CUDA里最基本的线程逻辑结构是顺序的,像一维数组一样,有一个连续递增的线程号(threadIdx.x
),且总线程数是线程可知的(blockDim.x
)。
MPI也有这两个特性(事实上MPI(1991)要先于CUDA(2007),而我只是恰好先了解的CUDA),不过命名...就没有CUDA那么友好了:使用MPI_Comm_size(...)
获取总进程数,通常记为comm_sz
这不说谁看得懂啊;使用MPI_Comm_rank
获取当前进程编号,通常记为my_rank
。这种表记方式来自Peter S. Pacheco的《并行程序设计导论》。
MPI_Init(int *argc, char ***argv)
在调用任何MPI函数前调用,类似于初始化的作用
MPI_Send()
阻塞性函数,对面不接受就一直阻塞
MPI_Sendrecv(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
int dest, int sendtag, void *recvbuf, int recvcount,
MPI_Datatype recvtype, int source, int recvtag,
MPI_Comm comm, MPI_Status *status)
由于MPI_Send
和MPI_Recv
是阻塞性函数,由于线程竞争或者不恰当的程序逻辑很容易导致死锁,MPI_Sendrecv
可以解决这个问题:同时进行发送和接收消息两个动作。
参数依次是:
发送区域起始地址 / 发送数据数量 / 发送数据类型
(向...发送数据的)目标进程编号 / (似乎是)发送的消息编号 / 接收区域起始地址 / 接收数据最大数量
接收数据类型 / (从...接收数据的)源进程编号 / (似乎是)想接收的消息编号
(MPI通讯器?不清楚) / (MPI状态?不清楚)
关于Sendrecv
,这个博客的例子比较简洁易懂。
没仔细看,先丢在这里,关于send/recv tag
的:https://stackoverflow.com/questions/31386659/when-to-use-tags-when-sending-and-receiving-messages-in-mpi
MPI_Finalize()
(尚不清楚是否一定要求调用)清除进程中所有的MPI状态量,类似于退出MPI环境,在该进程中,之后MPI的函数库中只能调用MPI_Get_version
, MPI_Initialized
, MPI_Finalized
三个函数。