Erstens hängt die genaue Antwort ab von: (1) Verwendung, dh Funktionseingabeargumenten, (2) Qualität und Details der MPI-Implementierung und (3) der von Ihnen verwendeten Hardware. Oft hängen (2) und (3) zusammen, z. B. wenn der Hardwareanbieter MPI für sein Netzwerk optimiert.
Im Allgemeinen ist das Zusammenführen von MPI-Kollektiven für kleinere Nachrichten besser, da die Startkosten nicht trivial sein können und die durch das Blockieren von Kollektiven verursachte Synchronisation minimiert werden sollte, wenn die Rechenzeit zwischen den Aufrufen variiert. Bei größeren Nachrichten sollte das Ziel darin bestehen, die Menge der gesendeten Daten zu minimieren.
Zum Beispiel sollte theoretisch MPI_Reduce_scatter_block
besser sein als MPI_Reduce
gefolgt MPI_Scatter
, obwohl das erstere oft in Bezug auf das letztere implementiert wird, so dass es keinen wirklichen Vorteil gibt. Bei den meisten MPI-Implementierungen besteht eine Korrelation zwischen Implementierungsqualität und Nutzungshäufigkeit, und Anbieter optimieren offensichtlich die Funktionen, für die dies im Maschinenvertrag erforderlich ist.
Auf der anderen Seite, wenn man sich auf einem Blue Gene befindet, ist das MPI_Reduce_scatter_block
Verwenden MPI_Allreduce
, das mehr Kommunikation als MPI_Reduce
und MPI_Scatter
kombiniert macht, tatsächlich ziemlich viel schneller. Dies ist etwas, das ich kürzlich entdeckt habe und das einen interessanten Verstoß gegen das Prinzip der Leistungsselbstkonsistenz in MPI darstellt (dieses Prinzip wird ausführlicher in den "Selbstkonsistenten MPI-Leistungsrichtlinien" beschrieben ).
Beachten Sie im speziellen Fall von Scatter + Gather versus Allgather, dass im ersten Fall alle Daten zu und von einem einzigen Prozess gehen müssen, was es zum Engpass macht, während im Allgather Daten sofort in alle Ränge hinein- und aus ihnen herausfließen können , weil alle Ränge einige Daten haben, die an alle anderen Ränge gesendet werden können. In einigen Netzwerken ist es jedoch nicht unbedingt eine gute Idee, Daten von allen Knoten gleichzeitig zu senden.
Der beste Weg, um diese Frage zu beantworten, besteht darin, die folgenden Schritte in Ihrem Code auszuführen und die Frage experimentell zu beantworten.
#ifdef TWO_MPI_CALLS_ARE_BETTER_THAN_ONE
MPI_Scatter(..)
MPI_Gather(..)
#else
MPI_Allgather(..)
#endif
Eine noch bessere Option besteht darin, Ihren Code während der ersten beiden Iterationen experimentell messen zu lassen und dann für die verbleibenden Iterationen diejenige zu verwenden, die schneller ist:
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
gefolgt vonMPI_Gather
liefert nicht die gleiche Kommunikationssemantik wieMPI_Allgather
. Möglicherweise liegt eine Redundanz vor, wenn Sie die Operation in irgendeiner Weise ausdrücken?