Tout d'abord, la réponse exacte dépend: (1) de l'utilisation, c'est-à-dire des arguments d'entrée de fonction, (2) de la qualité et des détails de l'implémentation MPI, et (3) du matériel que vous utilisez. Souvent, (2) et (3) sont liés, par exemple lorsque le fournisseur de matériel optimise MPI pour son réseau.
En général, la fusion des collectifs MPI est meilleure pour les petits messages, car les coûts de démarrage peuvent être non triviaux et la synchronisation entraînée par le blocage des collectifs doit être minimisée en cas de variation du temps de calcul entre les appels. Pour les messages plus volumineux, l'objectif doit être de minimiser la quantité de données envoyées.
Par exemple, en théorie, MPI_Reduce_scatter_block
devrait être meilleur que MPI_Reduce
suivi MPI_Scatter
, bien que le premier soit souvent mis en œuvre en fonction du second, de sorte qu'il n'y a pas de réel avantage. Il existe une corrélation entre la qualité de la mise en œuvre et la fréquence d'utilisation dans la plupart des mises en œuvre de MPI, et les fournisseurs optimisent évidemment les fonctions pour lesquelles cela est requis par le contrat de la machine.
D'un autre côté, si l'on est sur un Blue Gene, le fait d' MPI_Reduce_scatter_block
utiliser MPI_Allreduce
, qui fait plus de communication que MPI_Reduce
et MPI_Scatter
combiné, est en fait un peu plus rapide. C'est quelque chose que j'ai récemment découvert et qui constitue une violation intéressante du principe d'auto-cohérence des performances dans MPI (ce principe est décrit plus en détail dans les "Directives de performances MPI auto-cohérentes" ).
Dans le cas spécifique de scatter + rassembler contre allgather, considérez que dans le premier, toutes les données doivent aller vers et depuis un seul processus, ce qui en fait le goulot d'étranglement, tandis que dans l'allgather, les données peuvent entrer et sortir de tous les rangs immédiatement , car tous les rangs ont des données à envoyer à tous les autres rangs. Cependant, l'envoi de données de tous les nœuds à la fois n'est pas nécessairement une bonne idée sur certains réseaux.
Enfin, la meilleure façon de répondre à cette question est de procéder comme suit dans votre code et de répondre à la question par expérience.
#ifdef TWO_MPI_CALLS_ARE_BETTER_THAN_ONE
MPI_Scatter(..)
MPI_Gather(..)
#else
MPI_Allgather(..)
#endif
Une option encore meilleure consiste à demander à votre code de le mesurer expérimentalement pendant les deux premières itérations, puis à utiliser la plus rapide pour les itérations restantes:
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
suiviMPI_Gather
ne fournit pas la même sémantique de communication queMPI_Allgather
. Peut-être y a-t-il une redondance lorsque vous exprimez l'opération d'une manière ou d'une autre?