首先,确切的答案取决于:(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;
}
}
MPI_Scatter
接着MPI_Gather
不提供相同的通信语义的MPI_Allgather
。当您以任何一种方式表示操作时,可能涉及冗余吗?