Questo test è stato aggiunto al programma goptest solo di recente per implementare le raccomandazioni, in campo di misurazioni di prestazione collettive, riportare nel documento Accurately Measuring MPI Broadcasts in a Computational Grid di B. de Supinski and N. Karonis. Questo documento evidenzia come il classico test Broadcast Round non sia accurato in tutte le situazioni, in quanto permette un certo parallelismo di esecuzione che falsa il risultato finale. Inoltre questo parallelismo non è misurabile a priori, in quanto si presenta con intensità e frequenza non deterministiche (vedi Broadcast Round per dettagli).
Questa variante di Broadcast permette di evitare completamente l'eventuale parallelismo (pipelining) introducendo una sorta di sincronizzazione, il cui overhead è possibile misurare, e quindi sottrarre al tempo finale ottenuto. Concettualmente l'algoritmo è il seguente :
Gli autori di questo hanno provato questo algoritmo con varie implementazioni di MPI_Broadcast (lineare, ad albero binomiale, ecc) ed hanno mostrato come esso dia risultati più coerenti rispetto alla Broadcast classica, dove non sempre l'implementazione teoricamente migliore risulta la più veloce anche dai test.
Nella goptest questo algoritmo viene implementato così :
MPI_Barrier(MPI_COMM_WORLD);
if ( my_pid == root_proc )/*se sono root spedisco*/
{
int rep;
time = MPI_Wtime();
for (rep = 0; rep < reps; rep++) /*ripeto la spedizione molte
volte*/
{
MPI_Recv(&dummy, 0, MPI_BYTE, proc, 0, MPI_COMM_WORLD, &status);
MPI_Send(&dummy, 0, MPI_BYTE, proc, 0, MPI_COMM_WORLD);
}
time_latency = (MPI_Wtime() - time); /* division by 'reps' occurs
later */
}
else if ( my_pid == proc )/*se non sono root prima ricevo e poi spedisco*/
{
int rep;
for (rep = 0; rep < reps; rep++)
{
MPI_Send(&dummy, 0, MPI_BYTE, root_proc, 0, MPI_COMM_WORLD);
MPI_Recv(&dummy, 0, MPI_BYTE, root_proc, 0, MPI_COMM_WORLD,
&status);
}
}
MPI_Barrier(MPI_COMM_WORLD);
if ( my_pid == root_proc ) /* I am the root process */
{
/* priming the line */
MPI_Bcast(lval, len, MPI_INT, root_proc, MPI_COMM_WORLD);
MPI_Recv(&dummy, 0, MPI_BYTE, proc, acker_tag, MPI_COMM_WORLD,
&status);
/* do the actual measurement */
time = MPI_Wtime();
for (i = 0; i < reps; i++)
{
MPI_Bcast(lval, len, MPI_INT, root_proc, MPI_COMM_WORLD);
MPI_Recv(&dummy, 0, MPI_BYTE, proc, acker_tag, MPI_COMM_WORLD,&status);
}
time = MPI_Wtime() - time; /* division by 'reps' occurs later
*/
}
else /* I am the ACKer or any process other than root */
{
if ( my_pid == proc ) /* I am the ACKER */
for (i = 0; i < reps + 1; i++) /* "+ 1" because we primed
the line */
{
MPI_Bcast(lval, len, MPI_INT, root_proc, MPI_COMM_WORLD);
MPI_Send(&dummy, 0, MPI_BYTE, root_proc, acker_tag,
MPI_COMM_WORLD);
}
else /* I am neither root nor the ACKer */
for (i = 0; i < reps + 1; i++) /* "+ 1" because we primed
the line */
MPI_Bcast(lval, len, MPI_INT, root_proc, MPI_COMM_WORLD);
}
(time - time_latency)/reps = OLi;
Come vedremo(I Risultati, Conclusioni) questo test è particolarmente interessante per noi in quanto, al contrario di BroadcastRound, da risultati molto simili sia per MPICH che per MPICH-G2, indipendentemente dalla dimensione del messaggio passato. Questo conferma, come era prevedibile, che entrambi implementano la primitiva MPI_Broadcast nello stesso modo (cioè con albero binomiale), e che quindi le ragioni delle differenze di prestazioni evidenziate con gli altri test dipendono da qualche altra caratteristica di MPICH-G2 che proveremo ad individuare nelle Conclusioni.