【问题标题】:Efficient implementation of mpi All-to-All Scatter/Gathermpi All-to-All Scatter/Gather 的高效实现
【发布时间】:2014-09-27 08:55:04
【问题描述】:

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

我需要实现一个分散操作(当然还有相应的聚集操作)。
进程 ID 数组很可能只包含(但不完全是)相邻进程(在笛卡尔拓扑的意义上),并且大多数时候只包含它自己的进程 ID。 (MPI_Comm_rank() 返回的那个)。此外,地图只初始化一次,并且在我的整个计算过程中保持不变,而分散/收集操作经常被调用。

我自己的实现已经完成了一半,从某种值开始,以便将相邻元素发送到同一个进程,然后再发送很多 ISend 和 IRecv。现在我遇到了MPI_Alltoallv 函数,我想知道是我自己编码更好还是应该使用MPI 内部函数。有任何人对此有经验吗?

【问题讨论】:

    标签: c++ c mpi


    【解决方案1】:

    如果您知道您的进程将始终在特定拓扑中进行通信,那么可以真正减少您需要发送的消息数量的一件事就是邻域集合。我不会在这里介绍整个教程,但基本思想是您将拓扑信息提供给 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 中的内置内容,这些内容将得到更好的优化且更易于阅读。

    【讨论】:

    • 感谢您的提示,我以前没有注意到这些。我将对已有的进行基准测试,然后决定是否进一步优化。我希望在 mpi_alltoallv 中发送零大小消息的开销不会那么惊人。
    • 消息的开销并不高,但这并不是最大的时间消耗。您的大部分时间将花在必须与所有其他进程同步的事实上。如果您以相对较小的规模(
    【解决方案2】:

    如果没有看到您的代码,则无法确定,但通常使用 MPI 集体调用将比对组成部分使用单独的 ISend 和 IRecv 调用带来更好的性能和更易读的代码。特别是,MPI_Alltoallv 函数将在列出的每个等级上将相邻值批处理到单个发送或接收中,并且这样做不会产生创建单个非阻塞发送/接收所需的所有单个结构的开销。

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

    【讨论】:

    • 啊,谢谢,我想我会尝试一下,你知道它是否允许发送零大小的块吗?
    • 零大小的块应该没问题,标准规定 {send,recv}counts 数组元素必须为非负数,但可以为零。特定的 MPI 总是有可能不允许这样做,但就标准而言,只要双方同意大小为零,就允许这样做。
    猜你喜欢
    • 2021-08-11
    • 2016-06-29
    • 2017-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-07
    • 1970-01-01
    • 2016-10-02
    相关资源
    最近更新 更多