CASO 1: prima SEND e poi RECEIVE
Prendiamo in considerazione questa parte di codice:
| if(mype.eq.0)
then
call MPI_SEND(tizio,...) call MPI_RECV(caio,...) elsif(mype.eq.1) then call MPI_SEND(caio,...) call MPI_RECV(tizio) endif |
dove, anche se non esplicitamente segnalato con
le variabili sorgentee
destinazione
nelle funzioni MPI, la comunicazione oggetto delle funzioni MPI chiamate
coinvolge il processo 0 ed il processo1.
In questo modo si è generato un possibile
punto morto poichè
il processo 0 come il processo 1 non potranno mai giungere alla chiamata
RECEIVE nel caso
che le dimensioni del messaggio da spedire superino le dimensioni massime
per un buffer di sistema (cio' che avevo chiamato variabile di sistema):
la chiamata SEND
usata è infatti bloccante e non termina fino a che la copia dalla
variabile del processo a quella di sistema non e' terminata; se il
piu' grande buffer di sistema e' piu' piccolo dei dati da spedire
questo buffer deve essere svuotato dalla chiamata
RECEIVE prima
che possa essere liberato per proseguire con la spedizione della successiva
parte del messaggio.
Per sperimentare questo problema e' possibile
provare ad eseguire il seguente codice al
variare del parametro n.
|
program puntomorto1
include 'mpif.h' parameter (n=100) integer nprocs, mype, ierr, itag, itag2, imesg, imesg2 integer istatus, i dimension imesg(n), imesg2(n) dimension istatus(MPI_STATUS_SIZE)
call MPI_INIT(ierr)
itag = 1
call MPI_FINALIZE(ierr)
|
Il codice torna a funzionare in modo corretto
se invece di una chiamata SEND bloccante se ne usa una non bloccante,
ma con la chimata
ad MPI_WAIT
non immediatamente dopo la chiamata
di MPI_ISEND
(infatti MPI_ISEND
seguito immediatamente da MPI_WAIT
è equivalente ad MPI_SEND):
| if(mype.eq.0)
then
call MPI_ISEND(tizio,...,ireq,...) call MPI_RECV(caio,...) call MPI_WAIT(ireq,...) elsif(mype.eq.1) then call MPI_ISEND(caio,...,ireq,...) call MPI_RECV(tizio) call MPI_WAIT(ireq) endif |
Domanda: era sufficiente che una sola delle due
chiamate SEND diventasse non-bloccante (con MPI_WAIT dopo la chimata RECEIVE)
per far scomparire il punto morto?
Risposta: prova il seguente con il parametro
n sufficientemente grande!
|
program puntomorto2
include 'mpif.h' parameter (n=40000) integer nprocs, mype, ierr, itag, itag2, imesg, imesg2 integer istatus, i dimension imesg(n), imesg2(n) dimension istatus(MPI_STATUS_SIZE)
call MPI_INIT(ierr)
itag = 1
call MPI_FINALIZE(ierr)
|
CASO 2: prima RECEIVE e poi SEND
Ancora si ottiene un punto
morto per i processi coinvolti nella comunicazione
bidirezionale se entrambi chiamano un RECEIVE
bloccante prima di un SEND:
| if(mype.eq.0)
then
call MPI_RECV(caio,...) call MPI_SEND(tizio,...) elsif(mype.eq.1) then call MPI_RECV(tizio,...) call MPI_SEND(caio,...) endif |
mentre la seguente parte di codice viene eseguita
in modo corretto senza punti morti:
| if(mype.eq.0)
then
call MPI_IRECV(caio,...,ireq,...) call MPI_SEND(tizio,...) call MPI_WAIT(ireq,...) elsif(mype.eq.1) then call MPI_IRECV(tizio,...,ireq,...) call MPI_SEND(caio,...) call MPI_WAIT(ireq,...) endif |
CASO 3: SEND e RECEIVE in ordine opposto
In questo caso non
c'è la possibilità di generare punti morti sia che si usino
funzioni di comunicazione punto a punto bloccanti o non bloccanti.
Considerando quindi sia la possibilità
di generare punti morti sia considerando discorsi di prestazioni del codice,
nelle comunicazioni bidirezionali è consigliabile usare la seguente
parte di codice:
| if(mype.eq.0)
then
call MPI_ISEND(tizio,...,ireq1,...) call MPI_IRECV(caio ,...,ireq2,...) elsif(mype.eq.1) then call MPI_ISEND(caio ,...,ireq1,...) call MPI_IRECV(tizio,...,ireq2,...) endif call MPI_WAIT(ireq1,...) call MPI_WAIT(ireq2,...) |