C 为什么MPI_Alltoallv函数接口强制数据只属于一个数组?

C 为什么MPI_Alltoallv函数接口强制数据只属于一个数组?,c,mpi,C,Mpi,假设我有3个进程,每个进程都希望向进程0、1和2发送3个数组a0、a1、a2。 给定MPI\u Alltoallv接口,即 int MPI_Alltoallv(const void *sendbuf, const int *sendcounts, const int *sdispls, MPI_Datatype sendtype, void *recvbuf, const int *recvcounts, const int *rdispls, M

假设我有3个进程,每个进程都希望向进程0、1和2发送3个数组
a0、a1、a2
。 给定
MPI\u Alltoallv
接口,即

int MPI_Alltoallv(const void *sendbuf, const int *sendcounts, const int *sdispls, MPI_Datatype sendtype,
                        void *recvbuf, const int *recvcounts, const int *rdispls, MPI_Datatype recvtype,
                  MPI_Comm comm)
接口强制将
a0、a1、a2的内容连接到
sendbuf
数组中(可能以非连续方式)。但是这对于实现
MPI\u Alltoallv
真的是必要的吗?我认为sendbuf最终必须重新划分为
a0、a1、a2
,因为最终,接收过程是不同的。(这同样适用于
recvbuf

为什么界面不符合以下要求:

int MPI_Alltoallv(const void **sendbuf, const int *sendcounts, MPI_Datatype sendtype,
                        void **recvbuf, const int *recvcounts, MPI_Datatype recvtype,
                  MPI_Comm comm)
我应该在哪里,例如,
int*sendbuf[3]={a0,a1,a2}
?(接收阵列也是如此)

MPI接口是因为:

  • 表演?(见下文)
  • Fortran兼容性
  • 还有别的吗
  • 这些原因是否也适用于MPI\u Neighbor\u alltoall\u v
  • 我是唯一一个对这种“在连接的数组中复制,然后MPI将拆分它,然后您将收到另一个连接的数组,您可能需要立即再次拆分”感到恼火的人吗

    =======================================

    性能:经过一些研究

  • 参考手册中的“给实施者的建议”中说,“实施可以使用树通信模式。消息可以由中间节点转发,如果这样更有效的话,可以在中间节点上拆分(分散)或连接(聚集)”。这可能就是选择此接口的原因。另一方面,我认为只有在数组是连续的情况下才有可能,而在这里,由于
    sdispls
    ,它是不受保证的

  • 提到alltoall算法的3种主要可能实现。其中两个只是对naive send to all/recv from all算法的改进。因此,实际上不需要为这两个请求连续数据。只有第三种“布鲁克算法”使用了分而治之的方法(据我所知,这需要连续的数据)。根据进程的数量和消息的大小,3个进程的执行方式不同

  • 查看一些开源实现:

  • MVAPICH实现了这3种方法
  • MPICH仅实现前两个(据我所知)
  • 我不明白OpenMPI实现在做什么
  • 但对于所有这些算法,似乎都有启发式算法来选择算法,因此出于性能原因,“一个数组中的所有数据”接口不应该是强制性的

    =======================================

    旁注:作为MPI_alltoallv包装的非连续接口的暂定实现(基于@Gilles Gouailladet备注):

    int my\u Alltoallv(const void**sendbuf,const int*scounts,MPI\u数据类型stype,
    void**recvbuf,const int*rcounts,MPI_数据类型rtype,
    MPI_通信(通信){
    国际大学排名;
    MPI_通信大小(通信和n_等级);
    int*sdispls=(*)malloc(n_秩*sizeof(int);
    int*rdispls=(*)malloc(n_秩*sizeof(int);
    
    对于(int i=0;i)您对MPI标准应该是什么的评论最好直接发送到MPI论坛(请参阅上的说明)。同时,您可以使用
    MPI\u Alltoallw()
    MPI\u BOTTOM
    @GillesGouaillardet“您对MPI标准应该是什么的评论”嗯,我不知道标准应该是什么,这就是为什么我想这么理解它。糟糕,我假设你认为标准应该不那么烦人。@GillesGouaillardet我认为根据C,对不同数组使用
    MPI\u Alltoallw()
    是未定义的行为。中给出的等效操作需要
    sdispls[I]
    其中
    sdispls[i]
    将是例如
    a[i]-MPI\u BOTTOM
    ,不在同一数组中的两个指针的差异。这是未定义的行为(但可以肯定的是,它通常做正确的事情…更糟糕的是:D)。
    MPI\u Get\u地址(a[i],&sdispls[i])
    。请随意解释为什么这是未定义的行为。
    int my_Alltoallv(const void **sendbuf, const int *scounts, MPI_Datatype stype,
                           void **recvbuf, const int *rcounts, MPI_Datatype rtype,
                      MPI_Comm comm) {
      int n_rank;
      MPI_Comm_size(comm,&n_rank);
      int* sdispls = (*)malloc(n_rank*sizeof(int);
      int* rdispls = (*)malloc(n_rank*sizeof(int);
      for (int i=0; i<n_rank; ++i) {
        MPI_Aint sdispls_i;
        MPI_Aint rdispls_i;
        MPI_Get_address(sendbuf[i],&sdispls_i);
        MPI_Get_address(recvbuf[i],&rdispls_i);
        sdispls[i] = sdispls_i; // Warning: narrowing from MPI_Aint to int
        rdispls[i] = rdispls_i; // Warning: narrowing from MPI_Aint to int
      }
      return MPI_Alltoallv(MPI_BOTTOM, scounts, sdispls, stype, // is MPI_BOTTOM+sdispls[i] == sendbuf[i] regarding C and MPI ?
                           MPI_BOTTOM, rcounts, rdispls, rtype, // is MPI_BOTTOM+rdispls[i] == recvbuf[i] regarding C and MPI ?
                           comm);
    }