C++ mpi全对全分散/聚集的高效实现

C++ mpi全对全分散/聚集的高效实现,c++,c,mpi,C++,C,Mpi,我的每个进程都有一个值数组v和一个大小相同的进程ID数组pidpid[i]指定将项目发送到哪个进程v[i] 我需要实现分散操作(当然还有相应的聚集操作)。 进程ID数组很可能只包含(但不排除)相邻的进程(在笛卡尔拓扑的意义上),并且大多数情况下只包含自己的进程ID(MPI\u Comm\u rank()返回的进程ID)。此外,贴图只初始化一次,并且在整个计算过程中保持不变,而散射/聚集操作经常被调用 我自己的实现已经完成了一半,从一种值开始,这样相邻的元素就被发送到同一个进程中,随后会发送很多I

我的每个进程都有一个值数组
v
和一个大小相同的进程ID数组
pid
pid[i]
指定将项目发送到哪个进程
v[i]

我需要实现分散操作(当然还有相应的聚集操作)。
进程ID数组很可能只包含(但不排除)相邻的进程(在笛卡尔拓扑的意义上),并且大多数情况下只包含自己的进程ID(
MPI\u Comm\u rank()
返回的进程ID)。此外,贴图只初始化一次,并且在整个计算过程中保持不变,而散射/聚集操作经常被调用


我自己的实现已经完成了一半,从一种值开始,这样相邻的元素就被发送到同一个进程中,随后会发送很多ISend和IRecv。现在我遇到了
MPI\u Alltoallv
函数,我想知道我是否应该使用自己的编码,还是应该使用MPI内部函数。有人有这方面的经验吗

在没有看到代码的情况下,我们无法确定,但一般来说,使用MPI集合调用将比对组成部分使用单独的ISend和IRecv调用产生更好的性能和更可读的代码。特别是,MPI_Alltoallv函数将在列出的每个列组上将相邻值批处理为单个发送或接收,这样做不会产生创建单个非阻塞发送/接收所需的所有单个结构的开销


这条规则最大的例外是,将数据转换为集体期望的形式是不切实际的。由于您的模式在整个应用程序过程中保持不变,因此此异常可能不适用于您。

如果您知道您的进程将始终在某个拓扑中通信,那么可以真正减少您需要发送的消息数量的一个因素就是邻居集合。在这里我不会完整介绍教程,但基本思想是向MPI提供拓扑信息,然后使用特殊的集合函数进行通信。特别功能包括:

MPI_NEIGHBOR_ALLGATHER(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, comm)
MPI_NEIGHBOR_ALLGATHERV(sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, comm)
MPI_NEIGHBOR_ALLTOALL(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, comm)
MPI_NEIGHBOR_ALLTOALLV(sendbuf, sendcounts, sdispls, sendtype, recvbuf, recvcounts, rdispls, recvtype, comm)
MPI_NEIGHBOR_ALLTOALLW(sendbuf, sendcounts, sdispls, sendtypes, recvbuf, recvcounts, rdispls, recvtypes, comm)

加上所有非阻塞变体。通过使用这些函数,您不必编写自己的集体函数。您可以使用MPI中的内置内容,这将得到更好的优化,更易于阅读。

ahh thx,我想我会尝试一下,您知道它是否允许零大小的块发送吗?零大小的块应该可以,标准规定{send,recv}计数数组元素必须是非负的,但可以是零。总有可能某个特定的MPI不允许这样做,但就标准而言,只要双方同意大小为零,就允许这样做。谢谢提示,我以前没有注意到这些。我将对我已经拥有的进行基准测试,然后决定是否进一步优化。我有一些希望,在mpi_alltoallv中发送零大小消息的开销不是那么惊人。消息的开销不高,但这不是大的timesink。您的大部分时间都将花在必须与所有其他进程同步这一事实上。如果你的跑步规模相对较小,这可能不会有太大的区别(