Facoltà di Ingegneria Corso di Studi in Ingegneria Informatica Esercitazione di Calcolo Parallelo Prodotto Matrice - Vettore in MPI II Strategia Anno Accademico 2010/2011 Prof.ssa Alessandra D'alessio Candidati Mario Buonomo Lorenzo Carullo Luigi De Simone
Indice 1 Descrizione del problema 1 2 Descrizione Algoritmo 2 2.1 Descrizione............................ 2 2.2 Input, output, errori e subroutine................ 5 3 Analisi del software 6 3.1 Analisi............................... 6 3.2 Tabelle............................... 8 3.2.1 Tempi........................... 8 3.2.2 Speed Up......................... 10 3.2.3 Efficienza......................... 11 4 Esempi d uso e Codice 12 Bibliografia 19 i
Elenco delle figure 2.1 Blocchi della matrice....................... 4 2.2 Operazione di Reduce finale................... 4 2.3 Situazione d errore........................ 5 3.1 Grafico Tempi........................... 9 3.2 Grafico Speed Up......................... 10 3.3 Grafico Efficienza......................... 11 4.1 Esempio d uso........................... 12 ii
Elenco delle tabelle 3.1 Tabella Tempi........................... 8 3.2 Tabella Speed Up......................... 10 3.3 Tabella Efficienza......................... 11 iii
Capitolo 1 Descrizione del problema Si vuole effettuare il calcolo del prodotto matrice vettore: Ax=y, A R nxn, x,y R n su un calcolatore MIMD a memoria distribuita con p processori, con A matrice quadrata di ordine n e vettori x e y di dimensione n; la matrice A deve essere distribuita per colonne. 1
Capitolo 2 Descrizione Algoritmo 2.1 Descrizione L algoritmo sequenziale prevede, ovviamente, il calcolo del vettore y componente per componente: y i = n j=1 a i,j x j, con i=1,...,n Siccome il calcolo di ciascun prodotto delle righe della matrice A per il vettore x può essere fatto indipendentemente dagli altri prodotti, l algoritmo parallelo prevede di distribuire il calcolo delle componenti y ai processori utilizzati. La matrice A può essere distribuita ai processori secondo varie strategie, quella utilizzata in quest algoritmo è la distribuzione per blocchi di colonne. La distribuzione avviene calcolando la lunghezza del blocco di colonne da mandare ad ogni processore che è pari al rapporto tra la dimensione della matrice (N) e il numero stesso di processori utilizzati (nproc); da notare che la dimensione della matrice deve essere multiplo del numero di processori utilizzati: se questo accade viene calcolato la lunghezza del blocco 2
Prodotto Matrice Vettore in MPI di colonne. La strategia adottata per distribuire la matrice è stata quella di linearizzare per colonne la matrice stessa, e successivamente, dato il numero di blocchi di colonne da mandare, il processore root (rank=0) effettua la scatter inviando a se stesso e a tutti gli altri processori il blocco di colonne contigue. Successivamente, sempre il processore root effettuerà la scatter del vettore x in modo tale che ogni processore ha nella sua memoria locale la porzione del vettore x su cui lavorerà. Adesso ogni processore avrà il suo blocco di colonne e un blocco del vettore x e può effettuare il calcolo riga parziale (appartenente al suo blocco di colonne) per colonna (blocco del vettore x): questo è effettuato facendo il prodotto temporaneo di ogni colonna del blocco per l elemento omologo nel vettore x: successivamente tutti i vettori parziali saranno sommati tra loro producendone uno solo, e la root effettuerà l operazione di reduce in modo tale da somma tutti gli altri contributi degli altri processori rimasti. Nella seguente figura vi è un esempio dove abbiamo 4 CPU ed ognuno ha un vettore parziale i quali saranno sommati con l operazione di reduce. 3
Prodotto Matrice Vettore in MPI In figura è mostrato un esempio di suddivisione della matrice A in blocchi a 4 processori: Figura 2.1: Blocchi della matrice Operazione di reduce per sommare i risultati parziali nel processo root: Figura 2.2: Operazione di Reduce finale 4
Prodotto Matrice Vettore in MPI 2.2 Input, output, errori e subroutine L input dell algoritmo è una matrice quadrata A di dimensioni nxn, dove n deve essere multiplo del numero di processori utilizzato; la dimensione della matrice è memorizzata in una costante nel programma C. L output generato dall algoritmo è composto dalla matrice A di ingresso (generata in maniera casuale), il vettore x (generato in maniera casuale), il vettore y contenente il prodotto Ax, il vettore contenente il prodotto Ax calcolato in maniera sequenziale (dal solo processore root) e infine da una stampa con un codice ok che ci da conferma del fatto che il risultato parallelo è corretto (lo si confronta con quello sequenziale). L errore che si può presentare è quando è verificata questa condizione: La dimensione N della matrice non è multiplo del numero di processori utilizzato; In figura è riportato un caso d errore: Figura 2.3: Situazione d errore 5
Capitolo 3 Analisi del software 3.1 Analisi Osserviamo ora il nostro algoritmo analizzando in dettaglio alcune caratteristiche atte a valutare le prestazioni di un software parallelo. Esse consentiranno all utente di capire in quale situazione è più opportuno utilizzare l algoritmo e quando invece il suo utilizzo non reca alcun palese vantaggio. Tali caratteristiche sono: Tempo di esecuzione utilizzando un numero p>1 di processori. Generalmente indicheremo tale parametro con il simbolo T(p) ; Speed up riduzione del tempo di esecuzione rispetto all utilizzo di un solo processore, utilizzando invece p processori. In simboli, avremo S(p) = T(1) / T(p). Il valore dello speed up ideale dovrebbe essere pari al numero p dei processori, perciò l algoritmo parallelo risulta migliore quanto più S(p) è prossimo a p. 6
Prodotto Matrice Vettore in MPI Efficienza, Calcolare solo lo speed-up spesso non basta per effettuare una valutazione corretta, poiché occorre rapportare lo speed-up al numero di processori, e questo può essere effettuato valutando l efficienza. Siano dunque p il numero di processori ed S(p) lo speed - up ad esso relativi. Si definisce efficienza il parametro E(p) = S(p) / p, essa fornisce un indicazione di quanto sia stato usato il parallelismo nel calcolatore. Idealmente, dovremmo avere che E(p) = 1 e quindi l algoritmo parallelo risulta migliore quanto più E(p) è vicina ad 1. 7
Prodotto Matrice Vettore in MPI 3.2 Tabelle Le tabelle che seguono mostrano i dati raccolti analizzando ciascuna delle caratteristiche sopraelencate. I tempi sono stati raccolti presso su un cluster di nodi di calcolo presso il Data Center SCoPE. La prima riga di ogni tabella contiene il valore dei dati forniti in input, mentre la prima colonna elenca il numero di processori impiegati nella computazione. Accanto a ciascuna tabella viene mostrato il relativo grafico (ottenuti attraverso il software Gnuplot [1986])che evidenzia l andamento dei valori esaminati. 3.2.1 Tempi Tabella dei tempi (in microsecondi) N = 16 N = 256 N = 512 N = 1024 1 6.914139 538.825989 1842.975616 7366.895676 2 493.049622 288.963318 948.905945 3706.932068 4 1423.835754 164.031982 510.931015 1883.029938 8 4925.966263 92.983246 280.857086 973.939896 Tabella 3.1: Tabella Tempi 8
Prodotto Matrice Vettore in MPI Grafico Figura 3.1: Grafico Tempi Si può notare dal grafico che per dimensioni della matrice fino a 512 l andamento dei tempi è pressoché decrescente perché il numero di processori che lavorano in parallelo è alto; con dimensione pari a 1024 abbiamo un andamento dei tempi che fino a 4 cpu decresce; utilizzando 8 processori l overhead introdotto dall elevata dimensione della matrice provoca un innalzamento dei tempi di computazione. 9
Prodotto Matrice Vettore in MPI 3.2.2 Speed Up Tabella Speed-Up N = 16 N = 256 N = 512 N = 1024 1 1 1 1 1 2 0.21 18.97 1.93 2.03 4 0.0032 2.64 2.87 2.73 8 0.076 2.82 3.31 0.79 Tabella 3.2: Tabella Speed Up Grafico Figura 3.2: Grafico Speed Up 10
Somma N numeri in MPI 3.2.3 Efficienza Tabella Efficienza N = 16 N = 256 N = 512 N = 1024 1 1 1 1 1 2 0.11 9.49 0.97 1.02 4 0.0008 0.66 0.72 0.68 8 0.0095 0.35 0.41 0.99 Tabella 3.3: Tabella Efficienza Grafico Figura 3.3: Grafico Efficienza 11
Capitolo 4 Esempi d uso e Codice Per compilare il codice, aperta una shell linux digitiamo: mpicc eser11.c e nella directory di lavoro comparirà un nuovo file, quello d esecuzione. Eseguendolo con: mpiexec -n 4 eser11 avremo l output a video: Figura 4.1: Esempio d uso Murli: ed ecco il codice in C, implementando l algoritmo presente nel testo di 12
Somma N numeri in MPI / ========================================================== ================== Name : esercitazione 11 di calcolo parallelo Author : Mario Buonomo Lorenzo Carullo Luigi De Simone Version : Copyright : Your copyright notice Description : Prodotto Matrice per vettore con distribuzione per blocchi di colonne ========================================================== ================== / #include <s t d i o. h> #include <s t d l i b. h> #include "mpi. h" #include <time. h> #include <math. h> #include <windows. h> #define MASTER 0 / Process ID MASTER / #define N 16 / Ordine delle matrici / int main ( int argc, char argv ) { int menum, nproc ; int i, j, k, l ; int rows = N, columns = N, block ; f l o a t v i = ( f l o a t ) malloc ( s i z e o f ( f l o a t ) rows columns ) ; f l o a t vr ; f l o a t x = ( f l o a t ) malloc ( s i z e o f ( f l o a t ) N) ; f l o a t c_proc = ( f l o a t ) malloc ( s i z e o f ( f l o a t ) N) ; f l o a t r e s u l t = ( f l o a t ) malloc ( s i z e o f ( f l o a t ) N) ; f l o a t r e s u l t _ s e q = ( f l o a t ) malloc ( s i z e o f ( f l o a t ) N) ; f l o a t x1, c ; double t0, t1, te, tmax ; // I n i z i a l i z z a z i o n e MPI_Init(& argc, &argv ) ; 13
Somma N numeri in MPI MPI_Comm_rank(MPI_COMM_WORLD, &menum) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc ) ; / Controllo dimensione array / i f (N % nproc!= 0) { f p r i n t f ( s t d e r r, "\nquitting. Size of Matrix must be multiple of Number of Process \n" ) ; MPI_Abort(MPI_COMM_WORLD, 0) ; else block = N/ nproc ; vr = ( f l o a t ) malloc ( s i z e o f ( f l o a t ) rows block ) ; c = ( f l o a t ) malloc ( s i z e o f ( f l o a t ) rows block ) ; x1 = ( f l o a t ) malloc ( s i z e o f ( f l o a t ) block ) ; // i n i z i a l i z z o vettore somme dei prodotti p a r z i a l i e vettore di check for ( i =0; i <N; i ++){ c_proc [ i ]=0; r e s u l t _ s e q [ i ]=0; / MASTER Section / i f (menum == 0) { / I n i z i a l i z z a z i o n e Tempi / t0 = MPI_Wtime ( ) ; / Alloco matrice e vettore colonna da inviare / f l o a t matrix_i = ( f l o a t ) malloc ( s i z e o f ( f l o a t ) rows ) ; for ( k = 0 ; k < rows ; k++) { matrix_i [ k ] = ( f l o a t ) malloc ( s i z e o f ( f l o a t ) columns ) ; / Riempio la matrice con numeri casuali da zero a trenta / srand ( time (NULL) ) ; 14
Somma N numeri in MPI for ( i = 0 ; i < rows ; i ++) for ( j = 0 ; j < columns ; j++){ matrix_i [ i ] [ j ] = ( f l o a t ) ( rand ( ) % 30) ; //genero vettore x random x [ j ] = ( f l o a t ) ( rand ( ) %30) ; / Stampo matrice inviata / p r i n t f ( "\nprocessore : %d invio a tutti per colonne : ", menum) ; p r i n t f ( "\nmatrix A:\n" ) ; for ( i = 0 ; i < rows ; i ++) { for ( j = 0 ; j < columns ; j++) { p r i n t f ( "%4.2f ", matrix_i [ i ] [ j ] ) ; p r i n t f ( "\n" ) ; p r i n t f ( "\narray x:\n" ) ; for ( i = 0 ; i < N; i ++) { // printf ("%4.2 f ", x [ i ] ) ; p r i n t f ( "\n" ) ; //check sequenziale for ( i = 0 ; i < rows ; i ++) for ( j = 0 ; j < columns ; j++) r e s u l t _ s e q [ i ]= r e s u l t _ s e q [ i ]+ matrix_i [ i ] [ j ] x [ j ] ; / Linearizzo la matrice per colonne / i = 0 ; for ( l = 0 ; l < columns ; l ++) { for ( j = 0 ; j < rows ; j++) { v i [ i ] = matrix_i [ j ] [ l ] ; i ++; 15
Somma N numeri in MPI //Dealloco for ( i =0; i <rows ; i ++) f r e e ( matrix_i [ i ] ) ; f r e e ( matrix_i ) ; //broadcast vettore x MPI_Scatter ( x, block, MPI_FLOAT, x1, block, MPI_FLOAT, 0,MPI_COMM_WORLD ) ; // scatter matrice A MPI_Scatter ( vi, rows block, MPI_FLOAT, vr, rows block, MPI_FLOAT, 0, MPI_COMM_WORLD) ; //MPI_Barrier(MPI_COMM_WORLD) ; / printf ("\ nprocessore : %d ho i l vettore x : ", menum) ; for ( i = 0; i < block ; i++) { // i l vettore colonna ha rows elementi printf (" %4.2f ", x1 [ i ] ) ; printf ("\ nprocessore : %d ho la colonna della matrice : ", menum) ; for ( j = 0; j < rows block ; j++) { // i l vettore colonna ha rows elementi printf (" %4.2f ", vr [ j ] ) ; printf ("\n") ; / / I n i z i a l i z z a z i o n e Tempi / t0 = MPI_Wtime ( ) ; // calcolo prodotti p a r z i a l i i =0; for ( j =0; j<rows block ; j++){ c [ j ] = vr [ j ] x1 [ i ] ; i f ( ( j +1)%N==0) i ++; // printf (" i = %d", i ) ; 16
Somma N numeri in MPI / printf ("\n\ncpu : %d Prodotti p a r z i a l i \n",menum) ; for ( i =0;i<rows block ; i++){ printf (" %4.2f ", c [ i ] ) ; printf ("\n") ; / //somma interna al processore del blocco di colonne ( nel caso di piu colonne ) for ( i =0; i <N; i ++) for ( j =0; j<block ; j++){ //Sleep (1) ; c_proc [ i ] = c_proc [ i ] + c [N j+i ] ; / printf ("\ncpu : %d Prodotti p a r z i a l i FINALE\n",menum) ; for / ( i =0;i<N; i++){ printf (" %4.2f ", c_proc [ i ] ) ; //somma dei contributi di ogni processore MPI_Reduce( c_proc, r e s u l t, N, MPI_FLOAT,MPI_SUM, 0,MPI_COMM_WORLD) ; / Fine Tempi / t1 = MPI_Wtime ( ) ; //Calcolo tempo t e = 1. e6 ( t1 t0 ) ; MPI_Reduce(& te,&tmax, 1,MPI_DOUBLE,MPI_MAX,MASTER,MPI_COMM_WORLD) ; i f (menum == 0) { p r i n t f ( "\ncpu : %d RISULTATO FINALE PARALLELO\n",menum) ; for ( i =0; i <N; i ++) 17
Somma N numeri in MPI p r i n t f ( "%4.2f ", r e s u l t [ i ] ) ; p r i n t f ( "\n\ncpu : %d RISULTATO FINALE SEQUENZIALE\n",menum) ; for ( i =0; i <N; i ++) p r i n t f ( "%4.2f ", r e s u l t _ s e q [ i ] ) ; p r i n t f ( "\ntempo d esecuzione : %f usecondi\n", tmax ) ; / Check di controllo per la prodotto / int f l a g = 0 ; for ( i =0; i <N; i ++){ i f ( r e s u l t _ s e q [ i ]!= r e s u l t [ i ] ) { p r i n t f ( "\nerrore nel prodotto parallelo " ) ; f l a g =1; i=n; i f ( f l a g == 0) p r i n t f ( "\nprodotto ok\n\n" ) ; / Dealloco / f r e e ( v i ) ; f r e e ( x ) ; f r e e ( x1 ) ; f r e e ( c ) ; f r e e ( c_proc ) ; f r e e ( r e s u l t ) ; f r e e ( r e s u l t _ s e q ) ; MPI_Finalize ( ) ; return 0 ; implementazione dell algoritmo in C 18
Bibliografia Gnuplot. Gnuplot. URL: www.gnuplot.info/, 1986. Almerico Murli. Lezioni di Calcolo Parallelo. Liguori Editore. 19