mpi_allgather操作的计算成本与收集/分散操作相比如何?


11

我正在研究一个可以通过使用单个mpi_allgather操作或一个mpi_scatter和一个mpi_gather操作来并行化的问题。这些操作在while循环内被调用,因此它们可能被多次调用。

在使用MPI_allgather方案的实现中,我正在将分布式矢量收集到所有进程中以进行重复矩阵求解。在另一种实现中,我将分布式矢量收集到单个处理器(根节点)上,在该处理器上求解线性系统,然后将求解矢量散布到所有进程中。

我很好奇的是,一次收集操作的成本是否比分散和收集操作的总和还要多。消息的长度是否在其复杂性中起重要作用?在mpi的实现之间是否有所不同?

编辑:


请描述沟通的结构和涉及的规模。一个MPI_Scatter接着MPI_Gather不提供相同的通信语义的MPI_Allgather。当您以任何一种方式表示操作时,可能涉及冗余吗?
杰德·布朗

保罗,杰德说得对,您的意思是MPI_Gather后面跟着一个MPI_Bcast吗?
阿隆·艾玛迪亚

@JedBrown:我添加了更多信息。
保罗

@AronAhmadia:我不应该使用MPI_Bcast,因为我是将向量的一部分发送给每个进程,而不是整个向量。我的理由是,通常,较短的消息比较大的消息要快。这有意义吗?
保罗

矩阵是否已经冗余分配?已经考虑了吗?多个进程共享相同的缓存和内存总线吗?(这将影响解决冗余系统的速度。)系统有多大/贵?为什么要顺序解决?
杰德·布朗

Answers:


9

首先,确切的答案取决于:(1)用法,即函数输入参数,(2)MPI实现质量和详细信息,以及(3)您使用的硬件。通常,(2)和(3)是相关的,例如当硬件供应商为其网络优化MPI时。

通常,对于较小的消息,融合MPI集合更好,因为启动成本可能是微不足道的,并且如果两次调用之间的计算时间存在差异,则应最小化阻塞集合所引起的同步。对于较大的消息,目标应该是最大程度地减少发送的数据量。

例如,从理论上讲,它MPI_Reduce_scatter_block应该比MPI_Reduce紧跟其后的要好MPI_Scatter,尽管前者通常是针对后者实施的,因此没有真正的优势。在大多数MPI实现中,实现质量和使用频率之间存在关联,并且供应商显然可以优化机器合同要求的那些功能。

另一方面,如果一个人在Blue Gene上,则MPI_Reduce_scatter_block使用进行MPI_Allreduce通信(比MPI_Reduce并进行更多的通信MPI_Scatter)实际上要快得多。这是我最近发现的,并且有趣地违反了MPI中的性能自洽性原则(此原则在“自MPI性能准则”中有更详细的描述)。

在分散+聚集与聚集的特定情况下,请考虑在前者中,所有数据必须往返于单个过程,这使它成为瓶颈,而在聚集中,数据可以立即流入和流出所有等级,因为所有等级都有一些要发送到所有其他等级的数据。但是,在某些网络上,一次从所有节点发送数据不一定是一个好主意。

最后,回答此问题的最佳方法是在代码中执行以下操作,并通过实验回答问题。

#ifdef TWO_MPI_CALLS_ARE_BETTER_THAN_ONE
  MPI_Scatter(..)
  MPI_Gather(..)
#else
  MPI_Allgather(..)
#endif

更好的选择是让您的代码在前两次迭代中实验性地对其进行测量,然后在剩余的迭代中使用速度更快的一种:

const int use_allgather = 1;
const int use_scatter_then_gather = 2;

int algorithm = 0;
double t0 = 0.0, t1 = 0.0, dt1 = 0.0, dt2 = 0.0;

while (..)
{
    if ( (iteration==0 && algorithm==0) || algorithm==use_scatter_then_gather )
    {
        t0 = MPI_Wtime();
        MPI_Scatter(..);
        MPI_Gather(..);
        t1 = MPI_Wtime();
        dt1 = t1-t0;
    } 
    else if ( (iteration==1 && algorithm==0) || algorithm==use_allgather)
    {
        t0 = MPI_Wtime();
        MPI_Allgather(..);
        t1 = MPI_Wtime();
        dt2 = t1-t0;
    }

    if (iteration==1)
    {
       dt2<dt1 ? algorithm=use_allgather : algorithm=use_scatter_then_gather;
    }
}

这不是一个坏主意……让它们同时计时并确定哪个更快。
保罗

大多数现代HPC环境硬件都会优化许多MPI调用。有时,这会导致难以置信的加速,而有时会导致极其不透明的行为。小心!
meawoppl 2012年

@Jeff:我刚刚意识到我遗漏了一个重要的细节……我正在德克萨斯高级计算中心的一个集群中工作,在那里他们使用胖树拓扑网络。这会影响全收集方法和聚集广播方法之间的性能差异吗?
保罗

@Paul拓扑不是这里的主导因素,但是一棵胖树具有相当大的二等分带宽,这会使所有的东西便宜。但是,聚会应该总是比聚会便宜。但是对于较大的消息,它可能小于2的倍数
Jeff

5

杰夫(Jeff)唯一确定测量的绝对方法是绝对正确的-毕竟我们是科学家,这是一个经验性的问题-并就如何实施此类测量提供了出色的建议。现在让我提出相反(或补充)的观点。

在编写广泛使用的代码和将其调整到特定的目的之间有一个区别。通常,我们首先要做的是-构建代码,以便a)我们可以在各种平台上使用它,并且b)该代码在以后的几年中是可维护和可扩展的。但是有时候我们在做另一件事-我们在一台大型机器上分配了一年的时间,并且我们正在逐步增加一些所需的大型模拟,并且我们需要一定的性能基线来完成我们在此期间需要完成的工作准予分配的时间。

当我们编写代码时,使其变得广泛可用和可维护比在特定机器上减少百分之几的运行时间更为重要。在这种情况下,正确的选择几乎总是使用最能描述您要做什么的例程-这通常是您可以进行的最具体的调用,它可以执行您想要的操作。例如,如果直接的allgather或allgatherv完成了您想要的操作,则应使用该方法,而不要使自己的操作脱离分散/分散操作。原因是:

  • 现在,该代码可以更清楚地表示您要执行的操作,从而使第二年来您代码的下一个人更容易理解,而下一个人却不知道该代码应该做什么(那个人很可能就是您);
  • 在MPI级别上可以针对这种更特殊的情况进行优化,而在更一般的情况下则无法进行优化,因此MPI库可以为您提供帮助。和
  • 尝试自己动手可能会适得其反;即使在使用MPI实现Y.ZZ的计算机X上性能更好,当您转移到另一台计算机或升级MPI实现时,它的性能也可能会差很多。

在这种相当普遍的情况下,如果您发现某些MPI集合在您的计算机上缓慢运行得不合理,则最好的办法是向mpi供应商提交错误报告;您不想使自己的软件复杂化,而无法在应用程序代码中变通,应该在MPI库级别上正确解决的问题。

但是。如果您处于“调整”模式下-您有一个有效的代码,则必须在短时间内(例如,为期一年的分配)在非常大的范围内进行扩展,并且已对代码进行了概要分析并发现代码的这一特定部分是瓶颈,那么开始执行这些非常具体的调整是有意义的。希望它们不会成为您代码的长期组成部分-理想情况下,这些更改将保留在存储库中某些特定于项目的分支中-但您可能需要这样做。在那种情况下,以预处理器指令区分的两种不同方法的编码,或针对特定通信模式的“自动调整”方法,可能很有意义。

因此,我并不反对Jeff,我只是想添加一些有关何时应该充分关注此类相对性能问题以修改代码以对其进行处理的上下文。


我想我现在对可移植性比对优化更感兴趣,但是我总是很好奇,是否还有其他同样可移植但又更快的实现:)
Paul
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.