Programmazione con il paradigma Message Passing - Cap. 6

Pagina creata da Federica Carboni
 
CONTINUA A LEGGERE
Programmazione con il paradigma
       Message Passing

             Cap. 6

                                  1
Programmi per il message passing
„   Asincroni
    „   I task concorrenti vengono eseguiti in modo asincrono:
    „   Può avere un comportamento non deterministico
    „   è estremamente difficile da leggere e capire

„   Debolmente asincroni
    „   I task si sincronizzano per eseguire le interazioni
    „   Diventa più semplice ragionare sui programmi
        è prevista anche l’esecuzione di job diversi su diversi processori,
               ma in questo modo i programmi non sono scalabili
    „   La maggior parte dei programmi che fanno uso di
        message passing sono scritti usando l’approccio
              single program multiple data: SPMD
                                                                              2
Operazioni Send e receive
„   Nella forma più generale:

     send(void *sendbuf, int nelems, int dest);

    Buffer che contiene i dati    Numero di dati   Identificatore del
    che devono essere spediti     da spedire       processo che riceve i
                                                   dati

      receive(void *recvbuf, int nelems, int source);

               Buffer che             Numero di dati    Identificatore del processo
               memorizza i dati       da ricevere       da cui vengono spediti i
               ricevuti                                 dati

                                                                                      3
Esempio                                                         Memorizzo il dato
                                                                ricevuto in a
                    Po                                     P1
                                                                   Uno solo
        a = 100;                          receive(&a,1,0);             Ricevuto dal
        send(&a,1,1);                     printf(“%d\n”,a);            processo 0
        a=0;

                                                       Quale valore riceve
modifico il                                            il buffer destinatario?
valore di a       uno solo
                                                 La semantica dell’operazione di send
    invio il dato                             richiede che il valore ricevuto da P1 sia 100
    contenuto            al processo 1
    nel buffer a
                                         Tuttavia
              Se la piattaforma hw supporta l’accesso diretto alla memoria
              (il dato vinene direttamente copiato da una memoria all’altra)
                          e il trasferimento asincrono dei messaggi,
                  il processo P1 potrebbe ricevere il valore 0 invece di 100
    L’operazione di send deve bloccare fino a quando la semantica
                      dell’operazione non è garantita.
   se send sblocca (permette l’esecuzione del resto del programma prima che P1
              abbia ricevuto il dato) P1 può ricevere il dato sbagliato.
                                                                                        4
Message passing bloccante non buffered
„   Blocking non-buffered send-receive
    „   L’operazione di send non termina finché il processo ricevente non ha
        avuto il messaggio (handsahke tra il processo mittente e destinatario che
        permette l’inizio dell’operazione di trasferimento)

                                                                                    5
Message passing bloccante con buffer
„   Blocking buffered send-receive
     „   Con l’uso dei buffer, quando il processo mittente deve eseguire una send mette
         il messaggio nel buffer e termina dopo che la copia nel buffer è completata.
         Può continuare con le altre operazioni. I dati trasferiti vengono memorizzati in
         un buffer del processo ricevente. Quando il processo destinatario incontra
         un’operazione di receive verifica che i dati siano nel suo buffer
     „   Solo il ricevente ha un buffer: i dati vengono depositati nel buffer e presi solo
         quando viene invocata la receive

                            2 buffer      Solo 1 buffer al ricevente                     6
Considerazioni
„    I protocolli che ammettono buffer non hanno tempi di
     attesa
„    Bisogna tenere sotto controllo la quantità di dati inviati
     al buffer in base alla sua capacità
„    C’è ancora pericolo di deadlock

                      Po                                 P1

             receive(&a,1,1);             receive(&a,1,0);
             send(&b,1,1);                send(&b,1,0);

    Entrambe le receive attendono che i dati inviati siano caricati nel buffer

    Probelmi nel protocollo bloccante
    Senza buffer – tempi d’attesa
    Con buffer – gestione del buffer
                                                                                 7
Message passing non bloccante
„   I protocolli non bloccanti terminano le send/receive
    prima che sia assicurata la loro correttezza semantica
„   Sono accompagnate da un’operazione check-status
    che indica se la semantica di un trasferimento
    precedente è stata o non violata
„   una volta che la non blocking send/receive termina, il
    processo è libero di continuare
„   Successivamente il processo controlla se l’operazione
    di trasferimento è stata completata
„   Anche la non blocking può essere buffered o non-
    buffered

                                                             8
Non blocking non-buffered e buffered

•Manda una richiesta di send                  •Manda una richiesta di send e mette i dati
•Continua a fare altre operazioni              nel buffer
•Quando il processo ricevente dà ok al send   •Continua a fare altre oprazioni
  vengono inviati i dati                      •Quando il processo ricevente dà ok al
•Il check status indica la riuscita della     send vengono inviati i dati nel buffer
  comunicazione                               • non c’è bisogno di controllare il check
                                              status                                    9
considerazioni
„   PVM e MPI implementano sia operazioni bloccanti e
    non bloccanti
„   Le operazioni bloccanti facilitano il programmatore
„   Le operazioni non bloccanti migliorano le prerformance

                                                        10
Message Passing Interface

                        MPI

    Un programma MPI è costituito da processi autonomi,
         ciascuno dei quali esegue il proprio codice
                      nello stile MIMD

                                                          11
MPI: caratteristiche
„   Libreria di funzioni per il message passing di supporto
    allo sviluppo di programmi paralleli (’92)
„   Non richiede hw specializzati
„   Asincrono / debolmente sincrono
„   Preferibilmente Single Program Multiple Data
„   Assume la memoria partizionata:
    Dal punto di vista logico una macchina è composta da p processori
      ognuno dei quali ha una sua memoria (memoria non condivisa) e
      accede solo ai suoi dati locai e.g.: cluster
„   Supporta solo parallelizzazione esplicita
    „   Svantaggi: codice poco strutturato e complesso
    „   Vantaggi: pieno controllo da parte del programmatore – performance e
        scalabilità alte

                                                                          12
Caratteristiche
„   Comunicazioni punto-punto
„   Comunicazioni collettive
„   Supporto topologico
„   Gestione degli errori
„   MPI ha 125 funzioni
„   6 sono le più usate

                                13
Terminologia MPI
„   Tutti gli identificatori MPI, inclusi gli identificatori di
    funzioni iniziano con MPI_ seguito da una lettera
    maiuscola e altre minuscole
„   Es: MPI_Init(&argc, &argv)

„   Tutte le costanti MPI sono stringhe composte da
    lettrere maiuscole e _ precedute sempre da MPI_
„   Es: MPI_COMM_WORLD

„   Header file per un programma C
       #include 

                                                                  14
Init e Finalize
„   MPI_Init     MPI_Init(&argc, &argv)
„   Inizializza l’ambiente MPI
„   Deve essere chiamata prima di ogni altra funzione MPI
„   Non deve essere necessariamente la prima istruzione del
    programma
„   È la prima funzione che eseguono tutti i processi
„   Esegue il setup del sistema che permette tutte le successive
    chiamate parallele

„   MPI_Finalize MPI_Finalize()
„   È l’ultima istruzione MPI
„   Viene chiamata da tutti i processi
„   Libera la memoria allocata da MPI

                                                                   15
Esempio: Hello world!

                        16
Dominio di comunicazione
„   Insieme di processi che possono comunicare tra loro
„   Le variabili del tipo MPI_Comm memorizzano i domini di
    comunicazione communicators
„   I comunicatori devono essere specificati in ogni istruzione di
    trasferimento di messaggi
„   Identificano in modo univoco i processi che partecipano alle
    operazioni di trasferimento
„   Un processo può appartenere a differenti domini di comunicazione
„   MPI_COMMON_WORLD è una costante che include tutti i processi
    coinvolti nell’esecuzione parallela
„   Se c’ è un solo gruppo di comunicatori coincide con
    MPI_COMMON_WORLD

                                                                  17
Comm_size e Common_rank
„   int MPI_Comm_size(MPI_Comm comm, int *size)
„   Restituisce nella variabile size il numero di processi
    del communicator domain comm
„   Se si chiama
    MPI_Comm_size(MPI_COMM_WORLD,&size)
    Quando c’ è un singolo processo per processore in
    size viene restituito il numero di processori usati dal
    programma
„   rank il rango di un processo è un intero che identifica
    il processo (0 … n. processi-1)
„   int MPI_Comm_rank(MPI_Comm comm, int *rank)
„   Il comunicatore comm assegna al processo il suo rank
                                                             18
Esempio: Hello world 2

                         19
Esempio: Hello world 3

                         20
Hello 3 run

              21
Send e receive
„   int MPI_Send (void *buf, int count, MPI_datatype
                 datatype, int dest, int tag, MPI_Comm comm)
„   int MPI_Recv (void *buf, int count, MPI_datatype
                 datatype, int source, int tag, MPI_Comm
                 comm, MPI_Status *status)
„   buf punta al buffer che contiene il messaggio da inviare/ricevere;
„   count numero di elelmenti del tipo MPI_datatype contenuti nel buffer;
„   datatype tipo di dato supportato da MPI;
„   dest/source numero del processo destinatario/ricevente del
    messaggio che appartiene al dominio di comunicazione comm;
„   tag valore intero associato al messaggio [0…32767];
„   comm dominio di comunicazione;
„   status struttura dati che contiene informazioni sull’esito
    dell’operazione receive:
     „ Typedef struct MPI_Status

        { int MPI_SOURCE; int MPI_TAG; int MPI_ERROR;};
                                                                       22
Corrispondenza tra i tipi di dato MPI e C

                                            23
Gruppi di comunicatori
„   MPI_Comm_split ( MPI_Comm comm, int color, int key,
    MPI_Comm *newcomm)
„   Viene chiamata da tutti I processi del dominio
„   Partiziona il gruppo di processi in sottogruppi disgiunti in base a
    color
„   All’interno di ogni sottogruppo (newcomm) i processi vengono
    rinumerati

                                                                          24
Esempio: master – slave …

                            25
… master – slave

                   26
Send&receive
Int MPI_Sendrecv(
void *sendbuf,
int sendcount,
MPI_Datatype senddatatype,
int dest,
ind sendtag,
void *recvbuf,
int recvcount,
MPI_Datatype recvdatatype,
int source,
int recvtag,
MPI_comm comm,
MPI_Status status)
                             27
Esempio: odd-even sort
„   Input: un array di lunghezza n (random), p processi
„   Output: l’array ordinato in ordine crescente
„   Algoritmo parallelo:
     „   Si determinano p processi (n multiplo di p)
     „   si generano p sotto-array (random) cisacuno di n/p elementi
     „   Si ordinano gli p array con un algoritmo di oridnamento (e.g.
         quick-sort)
     „   Si esegue un ciclo in cui le coppie contigue (e disgiunte) di
         array oridnati vengono fuse e divise nuovamente in due array,
         alternando le coppie i,i+1 e i-1,i ad ogni ciclo di calcolo
     „   Dopo p-1 iterazioni i sotto-array, se presi in sequenza, danno
         luogo all’array ordinato
                               Esempio:
                               n=18, p=6
             9,7,1    5,4,5   10,3,8 9,1,4      2,6,5    8,0,3
                                                                          28
Topologie virtuali per i processi
„   Modo conveniente per identificare un processo all’interno di un
    gruppo. Per default si ha un ranking dei processi lineare (0..k-1).
    Spesso conviene organizzarei processi secondo pattern 2-3dim.
„   Topologia cartesiana
    int MPI_Cart_create(…,
    int ndims, numero di dimensioni della topologia
    int *dims, array: lunghezza di ogni dimensione
    int *periods, periods[i]!=0 non ci sono wraparound
    …)
„Ogni processo è identificato dalle sue coordinate nella topologia
…. il processo coord(i,j)

MPI_Cart_rank n. del processo a partire dalle sue coordinate
MPI_Cart_coord coordinate del processo a partire dal suo rank
                                                                          29
Operazioni di comunicazione collettive
„   Sincronizzazione
    „   MPI_Barrier sincronizza tutti i processi di un gruppo: termina
        solo dopo che tutti i processi del gruppo l’hanno chiamamta
„   Broadcast
    „   MPI_Bcast
„   Riduzioni
    „   MPI_Reduce

                                                                         30
Riferimenti
„  Manuale MPI in linea
http://www.mpi-forum.org/docs/mpi-11-html/mpi-
   report.html

„  Implementazione open source per MPI: LAM/MPI
http://www.lam-mpi.org

„  OcamlMPI: interfaccia con MPI
http://paulliac.inira.fr/~xleroy/software.html

                                                  31
Puoi anche leggere