Corsi tenuti da Giuseppe Levi
  • Home
  • Informatica per Fisici
    • Lezioni Video
    • Riferimenti Utili
    • Esempi discussi nel corso
    • Blog Lezioni
    • Trasparenze
    • Esami
  • Linguaggi Visuali
    • Blog Lezioni Fisica e LabView
  • CORSO HPC
    • Risorse utili
    • Blog Lezioni
    • Game of Life
    • Insieme Mandelbrot
    • Come lanciare un job sul cluster
  • Servizi Web Utili
  • Contatti
  • Appunti di Matematica Vedica Elementare

HABEMUS CLUSTER

28/3/2011

0 Comments

 
Grazie al lavoro dei tecnici finalmente oggi ho potuto sottomettere il primo job con successo !
Da ORA il corso comincia a trattare di programmazione realmente parallela distribuita su più macchine!
0 Comments

Lezioni del 21 e 22 Marzo [DRAFT]

22/3/2011

0 Comments

 
In queste lezioni abbiamo approfondito il tema della divisione dei dati per affrontare il problema del Game of Life.
Abbiamo inoltre trattato le comunicazioni ASINCRONE in MPI.
Le funzioni Isend e Irecv istanziano un send e un receive non bloccanti. Prima di poter usare di nuovo il buffer di invio o poter leggere il i dati nel buffer di ricezione bisogna verificare che le operazioni siano andate a buon fine tramite le chiamate a MPI_Test, MPI_Wait, MPI_Waitall, MPI_Probe o MPI_Iprobe.

int flag;

MPI_Isend(&sendb,1,MPI_INT,dest,tag,MPI_COMM_WORLD,&request[1]);
MPI_Irecv(&receiveb,1,MPI_INT,dest,tag,com,&request[0]);
MPI_Test(&request[0],&flag,&status[0]);

{ int cc=0;
while(!flag)
{
cout << "aspetto il receive e lavoro "<< cc++ << endl; 
MPI_Test(&request[0],&flag,&status[0]);
}}
cout << "L'esecuzione prosegue dopo i send e receive non bloccanti" << endl;
/* MPI_Wait è una chiamata BLOCCANTE 
che in questo caso attende il completamento del SEND in alternativa Waitall attende TUTTE le richieste di comunicazione contenute nel vettore.*/

MPI_Wait(&request[1],&status[1]);
//MPI_Waitall(2,&request[0],&status[0]); 

Se invece che usare il semplice Test o Wait volessimo avere informazioni più dettagliate su una comunicazione in arrivo dovremmo usare MPI_Probe (Bloccante) o MPI_Iprobe (non bloccante).

//MPI_Probe(MPI_ANY_SOURCE,tag,MPI_COMM_WORLD,&status[0]); BLOCCANTE 
MPI_Iprobe(MPI_ANY_SOURCE,tag,MPI_COMM_WORLD,&flag,&status[0]);

{ int cc=0;
while(!flag)
{
cout << "aspetto il receive e lavoro "<< cc++ << endl; 
MPI_Iprobe(MPI_ANY_SOURCE,tag,MPI_COMM_WORLD,&flag,&status[0]);
}}
// con Get_count ottengo informazioni su quanti elementi ha il messaggio
MPI_Get_count(&status[0],MPI_INT,&count);
// Posso allocare il buffer di receive in base a questo e ricevere il messaggio
    receiveb =(int*)malloc(count*sizeof(int));
MPI_Recv(receiveb,count,MPI_INT,status[0].MPI_SOURCE,tag,MPI_COMM_WORLD,&status[1]);

Le informazioni riguardo al tag ( MPI_TAG ), alla sorgente (MPI_SOUCE), ed errore ( MPI_ERROR )   del messaggio possono essere ottenute dalla struttura MPI_status. Altre informazioni possono essere introdotte in questa struttura dalle implementazioni ma sono fuori dallo standard.
0 Comments

Lezione di Martedì 15 Marzo [draft]

18/3/2011

0 Comments

 
In questa lezione abbiamo parlato delle Gost Cells e del primo vero e proprio esercizio di programmazione parallela (obbligatorio) Il Game of Life di Conway.  

Nell'esempio illustrato abbiamo distribuito una matrice 2D tra diversi processi dividendola in colonne. Il disegno illustra il metodo delle "ghost cells" ad ogni matrice locale ad ogni processo A e B vengono aggiunte delle celle (in grigio) in cui ogni processo trasmette i dati di cui l'altro ha bisogno per proseguire il calcolo. Nel disegno la colonna (azzurra) della matrice del processo A viene trasferita nelle ghost cells della matrice del processo B che a suo volta trasferisce i propri dati al processo A. Un buon testo in inglese sulle ghost cells lo trovate qui.

Picture
0 Comments

Lezione di Lunedì 14 Marzo 2011

14/3/2011

0 Comments

 
Ancora MPI. Abbiamo illustrato il send bufferizzato (orribile parolaccia ! trovatemi qualcosa di meglio in Italiano !)Prima si riserva il buffer:
int bsiz=(1+MPI_BSEND_OVERHEAD)*sizeof(int);
int buffer[1+MPI_BSEND_OVERHEAD];
Poi lo si aggancia a MPI e lo si usa:
MPI_Buffer_attach(&buffer,bsiz);     
 
switch (my_id)  
{ case 0:  dest=1; break; case 1:  dest=0; break; }
MPI_Bsend(&sendb,1,MPI_INT,dest,tag,MPI_COMM_WORLD); MPI_Recv(&receiveb,1,MPI_INT,dest,tag,com,&status);Alla fine lo si rilascia: MPI_Buffer_detach(&buffer,&bsiz); 


Inoltre abbiamo presentato la funzione sendrecv che permette di accorpare in una singola chiamata sincrona quindi bloccante le operazioni di send e receive. In questo modo il programma viene semplificato in:
switch (my_id)  { case 0:dest=1; break;case 1:dest=0;break;}
MPI_Sendrecv(&sendb,1,MPI_INT,dest,tag,&receiveb,1,MPI_INT,dest,tag,com,&status);

Fino a questo punto abbiamo trattato di messaggi che contengono solo dati contigui in memoria ma se volessimo trasmettere p.es. una colonna di una matrice di un vettore da un processo a un altro non rientriamo più in questo caso. 
MPI risolve questo problema permettendoci di definire nuovi TIPI di dati.  Il caso più semplice è quello di dati non contigui ma equispazitati e si risolve usanto la chiamata MPI_Type_vector. 
Se nel precedente programma i buffer di  send e receive divengono delle matrici:
int sendb[10][10],receiveb[10][10];
Con le righe:
MPI_Datatype colonna;
MPI_Type_vector(10,1,10,MPI_INT,&colonna);
MPI_Type_commit(&colonna);
definisco il nuovo tipo di dato "colonna" fatto di 10 elementi di 1 MPI_INT spaziati in memoria di 10*sizeof(MPI_INT) che poi può essere usato nelle operazioni di scambio di messaggi. Per Esempio:
MPI_Sendrecv(&sendb[0][0],1,colonna,dest,tag,&sendb[0][9],1,colonna,dest,tag,com,&status);

Notate nella riga di esempio la diversa origine e destinazione. In pratica ogno processo invia la colonna 0 nella colonna 9 dell'altro.
Siamo ora pronti per affrontare il metodo più diffuso per lo scambio di dati fra processi, quello delle ghost cells.

I file sorgente degli esempi discussi in questa lezione:
Esempio Bsend
Esempio Sendrecv . E Sendreceive replace.
Esempio di scambio di vettori colonna.
0 Comments

Lezione di Martedì 8 Marzo 2011

8/3/2011

0 Comments

 
In questa lezione abbiamo dato un esempio di come si possa parallelizzare un algoritmo sia come  "Task Parallelism" che come "Data Parallelism". L'algoritmo parallelizzato era appropriato all'ora prima di pranzo: la ricetta dei tortellini in brodo. La funzione riempimento_e_chiusura(&pasta); ha permesso di illustrare come sia possibile fare una data division o una pipeline.
Abbiamo inoltre mostrato il primo esempio di programma MPI con un semplice scambio di messaggi sincrono fra due processi.
Il codice presentato è stato:

int main(int argc, char* argv[])
{

int i, my_id, numprocs,length;
int sendb,receiveb,tag;
char name[BUFSIZ];
MPI_Comm com;
MPI_Status status;
com=MPI_COMM_WORLD;
MPI_Init(&argc, &argv) ;                    // Chiamata obbligatoria di inizializzazione
MPI_Comm_rank(MPI_COMM_WORLD, &my_id) ;     // Ottiene l'identificativo del processo
MPI_Comm_size(MPI_COMM_WORLD, &numprocs) ;  // Ottiene quanti processi sono attivi
MPI_Get_processor_name(name, &length);      // Il nome del nodo dove il processo è in esecuzione
sendb=my_id;
tag=0;
switch (my_id)  {
case 0:

MPI_Send(&sendb,1,MPI_INT,1,tag,MPI_COMM_WORLD);
MPI_Recv(&receiveb,1,MPI_INT,1,tag,com,&status);

break;
case 1:

MPI_Recv(&receiveb,1,MPI_INT,0,tag,com,&status);
MPI_Send(&sendb,1,MPI_INT,0,tag,MPI_COMM_WORLD);
break;
}

cout << "Sono il Processo "<< my_id << " e ho ricevuto " << receiveb << " da : " << status.MPI_SOURCE << endl;
MPI_Finalize();                             // Chiusura di MPI.
/*
Esercizio:
Modificate il programma in modo da farlo eseguire da un numero PARI di processi. 
I processi pari comunicano con quelli dispari e viceversa (0 <--> 1; 2 <--> 3.... ecc.)

*/

return 0;
}

0 Comments

Lezione di Martedì 1 Marzo

2/3/2011

0 Comments

 
Abbiamo illustrato il programma generale del corso incentrato principalmente su:
Creazione di algoritmi paralleli,
Parallellizzazione in ambito multicore
Parallelizzazione in ambito cluster.
Si illustreranno prima di tutto gli ambiento standard OpenMP e MPI.

Primo esempio abbiamo parlato di un problema che incontriamo solo in ambito multicore noto come False Sharing ovvero il degradamento nelle prestazioni dovuto alla necessità di mantenere il contenuto delle cache coerente fra i diversi core quando questi modificano la stessa pagina di memoria senza per altro operare sulle stesse locazioni di memoria.
L'esempio illustrato a lezione usa la direttiva:
#pragma omp parallel shared( <var>, <var>,...) num_threads(<N>)
Per la creazione delle parti parallele e le funzioni:
omp_get_num_procs();
omp_get_thread_num();
omp_get_num_threads();

Per ottenere il numero di core disponibili, l'indice del thread e il numero totale di thread in esecuzione.

omp_get_wtime();

E' stata usata  per misurare il tempo impiegato dal programma.
COMPITO:Costruite voi un esempio ove rendete evidente questo problema.
Un buon articolo introduttivo a OpenMP:
http://msdn.microsoft.com/en-us/magazine/cc163717.aspx

0 Comments

    Author

    Giuseppe Levi
    Blog delle lezioni del corso di PPSD 2012.

    Archives

    January 2015
    May 2012
    April 2012
    March 2012
    May 2011
    April 2011
    March 2011

    Categories

    All
    Cluster
    Mpi
    Openmp

    RSS Feed

Powered by Create your own unique website with customizable templates.