まず、正確な答えは、(1)使用法、つまり関数の入力引数、(2)MPI実装の品質と詳細、(3)使用しているハードウェアに依存します。多くの場合、ハードウェアベンダーがネットワークのMPIを最適化する場合など、(2)と(3)は関連しています。
一般に、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
さらに優れたオプションは、最初の2回の反復中にコードで実験的に測定し、残りの反復で速い方を使用することです。
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
。どちらかの方法で操作を表現するときに、おそらく冗長性が関係していますか?