MPI in dettaglio Chi ha definito MPI

Transcript

MPI in dettaglio Chi ha definito MPI
MPI in dettaglio
Salvatore Orlando
CALCOLO PARALLELO - S. Orlando
1
CALCOLO PARALLELO - S. Orlando
2
Chi ha definito MPI
Il modello Message-Passing Model
•
•
•
Ad un processo è tradizionalmente associato con
– program counter & address space.
Processi possono però avere threads multipli (program counters & private
stacks) che condividobo un singolo address space
– Le versioni correnti di MPI supportano la comunicazione tra processi,
non tra thread
Interprocess communication (message-passing) combina
– Sincronizzazione
– Movimento di dati dall’address space di un processo (mittente),
all’address space di un altro processo (destinatario)
Process 0
Process 1
Send(data)
Receive(data)
CALCOLO PARALLELO - S. Orlando
3
Operazioni One-Sided di comunicazione
•
•
•
MPI-2 permette anche operazioni One-Side tra processi
– remote memory read & writes
Solo un processo deve esplicitamente partecipare.
Vantaggio
– comunicazione e sincronizzazione sono disaccoppiate
Process 0
Process 1
Put(data)
(memory)
(memory)
Get(data)
CALCOLO PARALLELO - S. Orlando
4
Un semplice programma MPI
#include <mpi.h>
#include <stdio.h>
int main( int argc, char *argv[] )
{
MPI_Init( &argc, &argv );
printf( "Hello, world!\n" );
MPI_Finalize();
return 0;
}
CALCOLO PARALLELO - S. Orlando
5
Compilare un programma MPI
•
Con MPICH possiamo semplicemente compilare programmi in C usando il
comando:
mpicc
– È uno script che invoca cc/gcc con i parametri corretti, risolvendo i
problemi dovuti
• INCLUDE (es. mpi.h)
• LIB (es. mpi.a)
•
Con MPICH è possibile linkare speciali librerie, e instrumentare così il
codice per analizzare le prestazioni
mpicc –o myprog -mpitrace myprog.c
CALCOLO PARALLELO - S. Orlando
6
Eseguire un programma MPI
•
Lo standard MPI-1 non specifica come eseguire un programma MPI
•
In generale, eseguire il programma MPI dipende dalla specifica
implementazione della libreria
– Potrebbe richiedere vari scripts, argomenti, e/o variabili di ambiente
– Con MPICH si usa
mpirun [-np<num>] [-machinefile <nomefile>]
-np <num>
:
<execfile>
specifica grado di parallelismo
-machinefile <nomefile>
:
lista di IP address o
domain name dei calcolatori del cluster
CALCOLO PARALLELO - S. Orlando
7
Scoprire a run-time informazioni sull’ambiente
•
Ogni processo può avere necessità di chiedere :
– Quanti processi partecipano in questa computazione?
– Chi sono io?
•
MPI fornisce funzioni per rispondere a questi quesiti:
– MPI_Comm_size() restituisce il numero di processi
– MPI_Comm_rank restituisce il rank, un numero tra 0 e size-1,
che identifica il processo chiamante
CALCOLO PARALLELO - S. Orlando
8
Un Hello.c migliore
#include <mpi.h>
#include <stdio.h>
int main( int argc, char *argv[] )
{
int rank, size;
MPI_Init( &argc, &argv );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
MPI_Comm_size( MPI_COMM_WORLD, &size );
printf( "I am %d of %d\n", rank, size );
MPI_Finalize();
return 0;
}
CALCOLO PARALLELO - S. Orlando
9
Comunicatori: Gruppi e Contesti
•
•
•
I processi MPI possono essere organizzati in gruppi
Ogni messaggio è inviato in un gruppo, ma all’interno di uno specifico
contesto
– Il msg deve anche essere ricevuto nello stesso contesto
Gruppo e Contesto insieme formano
– Un comunicatore
•
Nota: per lo stesso gruppo potremmo così avere comunicatori diversi
•
Un processo è identificato dal suo rank nel gruppo associato con un
comunicatore
• MPI_COMM_WORLD
– Comunicatore di default
CALCOLO PARALLELO - S. Orlando
10
MPI Datatypes
•
I dati in un messaggio da inviare/ricevere descritti da una tripla:
– address, count, datatype
•
Un MPI datatype è definito ricorsivamente come:
– Predefinito, corrispondente a un datatype di base del linguaggio ospite
(es., MPI_INT, MPI_DOUBLE_PRECISION)
– Un array contiguo di MPI datatypes
– Un block di datatypes con stride
– Un struttura arbitraria di datatypes
•
Ad esempio, è possibile costruire datatypes come
– Un array di coppie (int, float)
– Una riga di una matrice, memorizzata però per colonne (stride fisso)
CALCOLO PARALLELO - S. Orlando
11
Perché sono necessari i Datatypes?
•
Un’implementazione MPI può così permettere comunicazioni tra processi
allocati su macchine eterogenee, i cui datatype elementari
– hanno diversa rappresentazione in memoria
– hanno lunghezze differenti
•
Con i datatype si possono specificare layout application-oriented dei dati
– Questo riduce copie memory-to-memory nell’implementazione
CALCOLO PARALLELO - S. Orlando
12
MPI Tags
•
I messaggi sono inviati accompagnati con un tag intero user-defined
– Questo serve al processo ricevente per identificare il messaggio
– I messaggi possono essere selezionati dal ricevente specificando il tag
– I messaggi possono non essere scelti dal ricevente sulla base del tag
• Specificando MPI_ANY_TAG come tag nella receive.
•
I tag sono considerati come message type in alcuni sistemi messagepassing, ma non in MPI
– MPI li chiama semplicemente tag per evitare confusione con i
datatypes.
CALCOLO PARALLELO - S. Orlando
13
Tag e Contesti
•
E’ noto che la separazione dei messaggi da adottare per la comunicazione
all’interno di specifico contesti può essere realizzata usando i tag, ma
– Questo richiede che eventuali librerie usate siano a conoscenza dei tag
usati dal programma chiamante o da altre librerie
– In ogni caso, avremmo problemi con i “wild card” per i tag (ANY_TAG)
•
I contesti in MPI sono differenti dai tag
– Non sono permessi wild card
– Sono allocati dinamicamente e univocamente dal sistema quando ad
esempio una libraria stabilisce di usare un comunicatore per i suoi
scopi
•
Usa MPI_Comm_split per creare nuovi contesti (communicatori)
CALCOLO PARALLELO - S. Orlando
14
Uso dei comunicatori: vantaggi
•
Subroutine Sub1() e Sub2(), corrispondenti a librerie MPI diverse
– Nota: subroutine chiamate da tutti i processi (codice SPMD)
•
Funzionamento corretto:
CALCOLO PARALLELO - S. Orlando
15
Uso dei comunicatori: vantaggi
•
Usando lo stesso comunicatore, a causa dell’uso di ANY_TAG, il
funzionamento potrebbe essere scorretto:
CALCOLO PARALLELO - S. Orlando
16
MPI Basic (Blocking) Send
MPI_SEND (start, count, datatype, dest, tag, comm)
•
•
•
•
•
Comunicazione standard, Asincrona/Buffered/Bloccante
Il buffer del messaggio è descritto da
– start, count, datatype
Il processo destinazione è specificato da dest, che è il rank del
processo target nel comunicatore specificato da comm.
Quando la funzione ritorna, i dati sono già stati consegnati al
sistema e il buffer può essere riusato
Il messaggio può non essere stato ricevuto dal processo ricevente
CALCOLO PARALLELO - S. Orlando
17
MPI Basic (Blocking) Receive
MPI_RECV(start, count, datatype, source, tag, comm, status)
•
Comunicazione standard, Asincrona/Buffered/Bloccante
•
Attende fino a quando un matching message (rispetto a comm, source e
tag) è ricevuto dal sistema, e copiato nel buffer utente (start,
count, datatype)
• source è il rank nel comunicatore specificato da comm, oppure
MPI_ANY_SOURCE.
• tag è il tag atteso e associato al messaggio, oppure MPI_ANY_TAG
• status è un parametro in output, e conterrà informazioni sulla
comunicazione
• Si possono ricevere meno di count occorrenze di un datatype, ma
riceverne di più è un errore
CALCOLO PARALLELO - S. Orlando
18
Status
• Status è una struttura dati allocata nello user’s program, che
conterrà informazioni sulla receive appena conclusa:
int recvd_tag, recvd_from, recvd_count;
MPI_Status status;
MPI_Recv(..., MPI_ANY_SOURCE, MPI_ANY_TAG, ..., &status )
recvd_tag = status.MPI_TAG;
recvd_from = status.MPI_SOURCE;
MPI_Get_count( &status, datatype, &recvd_count );
CALCOLO PARALLELO - S. Orlando
19
Calcolo PI greco
E’ noto che l’area del cerchio è r2 π, per
cui l’area del semicerchio con r=1 è:
1
π/4
y
Curva cerchio (teorema di Pitagora):
x2 + y2 = 1
y = √(1-x2)
0
x
1
L’area del semicerchio corrisponde al
calcolo del1seguente integrale:
Equivalentemente
possiamo calcolare
∫
1− X 2
0
1
1
∫0 1 + x 2
ARCTAN(1) = π/4
ARCTAN(0) = 0
Possiamo calcolarlo numericamente.
Maggiore è il numero di intervalli in cui
suddividiamo [0..1], maggiore è la
precisione del calcolo dell’integrale
CALCOLO PARALLELO - S. Orlando
20
Esempio: PI greco in C (1)
#include <mpi.h>
#include <math.h>
int main(int argc, char *argv[])
{
int done = 0, n, myid, numprocs, i, rc;
double PI25DT = 3.141592653589793238462643;
double mypi, pi, h, sum, x, a;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);
if (myid == 0) {
printf("Enter the number of intervals: (0 quits) ");
scanf("%d",&n);
}
MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);
CALCOLO PARALLELO - S. Orlando
21
Esempio: PI greco in C (2)
if (n != 0) {
h
= 1.0 / (double) n;
sum = 0.0;
for (i = myid + 1; i <= n; i += numprocs) {
x = h * ((double) i - 0.5);
sum += 4.0 / (1.0 + x*x);
}
mypi = h * sum;
MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0,
MPI_COMM_WORLD);
if (myid == 0)
printf("pi is approximately %.16f, Error is %.16f\n",
pi, fabs(pi - PI25DT));
}
MPI_Finalize();
return 0;
}
CALCOLO PARALLELO - S. Orlando
22
Codici unsafe e deadlock
•
Anche usando primitive asincrone (bufferizzate), si può generare
un deadlock:
– Supporre di voler inviare un messaggio molto grande dal
processo 0 al processo 1
– se la memoria di sistema (buffer) sul ricevente è insufficiente, la
send deve attendere che l’utente fornisca spazio di memoria
(attraverso una receive)
•
Possibile deadlock:
Process 0
Process 1
Send(1)
Recv(1)
Send(0)
Recv(0)
• Questo codice è chiamato “unsafe”, poiché il suo
funzionamento dipende dalla disponibiltà di buffer
di sistema
CALCOLO PARALLELO - S. Orlando
23
Alcune soluzioni al problema del codice “unsafe”
•
•
Ordinare le operazioni più attentamente:
Process 0
Process 1
Send(1)
Recv(1)
Recv(0)
Send(0)
Usare primitive non-blocking:
Process 0
Process 1
Isend(1)
Irecv(1)
Waitall
Isend(0)
Irecv(0)
Waitall
CALCOLO PARALLELO - S. Orlando
24
Estensioni a MPI(1): MPI-2
•
Oltre alle comunicazioni one-sided
– Dynamic Process Management
• Startup dinamico dei processi
• Determina dinamicamente le connessioni
– I/O parallelo
– Bindings anche per C++/ Fortran-90
• problemi legati a linguaggi diversi e alla rappresentazione dei tipi
semplici e strutturati
CALCOLO PARALLELO - S. Orlando
25
MPICH
•
MPICH è un’implementazione portabile di MPI –1 con alcune nuove
primitive MPI-2
•
Funziona su MPPs, Grid, cluster, e NOWs o Clumps eterogenei
•
Per compilare, decomprimere in /usr/local
– configure
– make
bisogna poi sistemare PATH e MANPATH
•
Per compilare, eseguire e analizzare le prestazioni
mpicc –o myprog myprog.c
mpirun -np 10 myprog
CALCOLO PARALLELO - S. Orlando
26
MPICH (compilazione)
•
•
Esistono quindi diversi script per compilare e linkare (librerie e path
relativi, path degli include sono specificati dagli script)
– C (mpicc)
– C++ (mpiCC)
– Fortran 77 (mpif77)
– Fortran 90
Script di compilazione permettono diverse opzioni:
– -mpilog
• Costruisce eseguibile che genera MPE log files.
– -mpitrace
• Costruisce eseguibile che genera tracce di esecuzione
– -mpianim
• Costruisce eseguibile che genera animazione real-time
– -show
• Mostra solo i comandi che verranno eseguiti
•
Possibile linkare altre librerie
– mpicc -o foo foo.o -lm
CALCOLO PARALLELO - S. Orlando
27
MPICH (esecuzione)
•
mpirun [mpirun_options...] <progname> [options...]
•
Alcune mpirun_options:
-machinefile <machine-file name>
Take the list of possible machines to run on from the
file <machine-file name>. This is a list of all available
machines; use -np <np> to request a specific number of machines.
-np <np>
specify the number of processors to run on
-nolocal
don’t run on the local machine
-t
Testing - do not actually run, just print what would be
executed
•
In un cluster di workstation i processi di un job parallelo sono fatti partire
individualmente su ciascuna workstation
– Se il parametro –machifile non è specificato, mpich cerca una lista di
default:
machines.<arch>
nella directory di istallazione (es.: /usr/local/mpich2.2.21).
CALCOLO PARALLELO - S. Orlando
28
MPICH (machinefile)
•
•
E’ possibile costruire un file delle workstation (machinefile) personale
Esempio di machinefile:
mercury
venus
earth
mars:2
jupiter:4
•
che specifica l’esistenza di 3 macchine con processore singolo
(mercury, venus, and earth), una macchina con 2 processori (mars), e
una con 15 (jupiter).
Eseguendo: mpirun -np 9 .... con il file di sopra, verranno creati
– 1 processo su mercury, venus, e earth
– 2 su mars
– 4 su jupiter
•
Se fossero necessari 10 o più processi, mpirun ripartirebbe dall’inizio
del file, creando processi aggiuntivi su mercury, venus, ecc.
CALCOLO PARALLELO - S. Orlando
29
MPICH (machinefile e rsh/ssh)
•
Deve essere possibile lanciare un processo/comando tramite rsh/ssh su ogni
macchina compresa nel <machinefile>
– Senza digitare la password ogni volta
– Con garanzia di sicurezza
•
rsh
– Meno sicuro
– Un host permette il login remoto ad un insieme di utenti@host listati in un file
(.rhosts)
– Quindi il login è permesso sulla base di un IP e di un user name
•
ssh
– Più sicuro
– Basato sul meccanismo delle chiavi pubbliche/private
– L’host su cui vogliamo collegarci in remoto (server) deve possedere la chiave
pubblica dell’utente@host (client)
– Il client dimostra la propria identità firmando con la propria chiave privata un
messaggio challenge
– Il server verifica il challenge grazie al possesso della relativa chiave pubblica
– Sicurezza garantita dalla protezione della chiave privata
CALCOLO PARALLELO - S. Orlando
30
rsh
•
Per costruire un cluster composto dalle macchine
p0.dsi.unive.it
p1.dsi.unive.it
p3.dsi.unive.it
ponete nella vostra home condivisa il file .rhosts così costruito:
p0.dsi.unive.it
p1.dsi.unive.it
p3.dsi.unive.it
•
•
username
username
username
Una generica macchina py.dsi.unive.it accetterà l’esecuzione locale di una
richiesta remota, proveniente dalla macchina px.dsi.unive.it e con utente
pippo, solo se
– nel file .rhosts presente nella home di pippo su py.dsi.unive.it
apparirà la riga:
px.dsi.unive.it
pippo
NOTA: con MPICH, è il comando mpirun ad aver bisogno di usare rsh per lo spawn
dei vari task del programma SPMD.
Quindi, se compiliamo e lanciamo mpirun sempre da px.dsi.unive.it, basterà
includere in tutti i file . rhosts del cluster l’unica riga di sopra
CALCOLO PARALLELO - S. Orlando 31
MPICH (machinefile e rsh)
•
Potete controllare la corretta configurazione di rsh e .rhosts, ovvero
se dalla una macchina p0 è possibile lanciare job sulla macchina p2
effettuando il comando
> rsh p2.dsi.unive.it ls
che invoca un ‘ls’ remoto sulla home directory.
•
MPICH mette anche a disposizione un tool
> tstmachines -v -machinefile=<miofile>
per controllare il corretto funzionamento di rsh su tutte le workstation
del machinefile.
CALCOLO PARALLELO - S. Orlando
32
SSH
•
Sulle macchine del laboratorio, rsh è stato disabilitato
– In verità, con il meccanismo dei link simbolici,
quando si invoca rsh si sta in realtà invocando ssh
– MPI (ma anche PVM) usano ssh per l’esecuzione remota di
processi/comandi
•
Usando SSH, il meccanismo di autenticazione senza password non è
basato sul file .rhosts
– è necessario generare la coppia di chiavi privata e pubblica
CALCOLO PARALLELO - S. Orlando
33
SSH senza password
•
Digitare
– ssh-keygen -t rsa
• digitare sempre <Invio> alla richiesta di password, senza inserire nulla
• In questo modo però la chiave privata non sarà protetta da passphase
– Questo comando genera in $HOME:/.ssh i file
• id_rsa (chiave privata) e
• id_rsa.pub (chiave publica)
•
•
Copiare il file $HOME:/.ssh/id_rsa.pub in $HOME:/.ssh/authorized_keys
– Poiché la home è condivisa, basta questo per permettere l’invio di
comandi remoti tra tutte le macchine del laboratorio
– Eseguire i test suggeriti per rsh
Suggerimento:
– Conservare in modo sicuro la chiave privata $HOME:/.ssh/id_rsa
– Ad esempio rimuovendola se necessario
CALCOLO PARALLELO - S. Orlando
34
Alcuni semplici esercizi
•
Compila e esegui il programma cpi
– dpkg -L mpich (per verificare i file istallati)
– cp –R /usr/share/doc/mpich/examples/pi mpi_examples
– cd mpi_examples; make cpi
•
Modifica il programma cpi in modo da usare send/receive invece di
bcast/reduce
•
Scrivere un programma che invia un messaggio lungo un anello:
– Processo 0 legge una linea dallo stdin
– Processo 0 invia la linea a Processo 1, che l’invia al Processo 2, etc.
– L’ultimo processi la invia indietro al Processo 0, che lo stampa.
– Usa MPI_Wtime per prendere i tempi (man MPI_Wtime)
Calcola banda di trasmissione e overhead di trasmissione tra 2 processi
– Ping-pong:
•
• il primo processo invia e riceve, il secondo rimbalza i messaggi ricevuti
– Calcolare con MPI_Wtime il tempo impiegato sul primo processo, dividendo
il tempo per il numero Byte trasmessi
– Cosa succede all’aumentare del size dei messaggi?
CALCOLO PARALLELO - S. Orlando
35