Documente Academic
Documente Profesional
Documente Cultură
Dupa aceasta se introduc linkuri simbolice in /usr/lib catre bibliotecile MPI din /usr/local/lib/
$cd /usr/lib
/usr/lib$ sudo ln --symbolic -T /usr/local/lib/libmpi.so.1 libmpi.so.1
/usr/lib$ sudo ln --symbolic -T /usr/local/lib/libopen-pal.so.4 libopen-pal.so.4
/usr/lib$ sudo ln --symbolic -T /usr/local/lib/libmca_common_sm.so.3 \
libmca_common_sm.so.3
/usr/lib$ sudo ln --symbolic -T /usr/local/lib/libopen-rte.so.4 libopen-rte.so.4
Se d restart si se testeaza unele comenzi. Daca totul a fost instalat corect, comanda
mpicc -show afiseaza:
Instalarea OpenMPI ntr-un director oarecare. Daca se doreste instalarea OpenMPI n alt
director dect directorul implicit (/usr/local), de exemplu in /usr/local/openmpi se specific acest
director ca argument al optiunii -prefix al comenzii configure:
./configure --prefix /usr/local/openmpi
sudo make all install
Se editeaz fiierul /etc/hosts (cu sudo gedit) astfel ca sa contina numele si adresa staiilor.
n laboratorul B125a adresele IP sunt statice i fiierul /etc/hosts arat astfel:
141.85.107.201 h1
141.85.107.202 h2
141.85.107.203 h3
...................
141.85.107.216 h16
n laboratorul B138 (ITEMS) adresele IP sunt dinamice (prin router DHCP), dar s-a fcut
rezervarea adreselor n router, astfel ca acestea s rmn nemodificate. Pentru aceasta se intr n
administrarea routerului (http://191.168.0.1) i se selecteaza LAN IP Setup. Se introduce adresa fizica
MAC si adresa de retea in tabela Address Reservation (fie manual, fie selectatnd adresa dispozitivului
respectiv din Address Reservation Table). Fiierul /etc/hosts arat astfel:
ITEMS01.imag.pub.ro 192.168.0.101
ITEMS02.imag.pub.ro 192.168.0.102
.................................
ITEMS12.imag.pub.ro 192.168.0.112
Pentru fiecare utilizator (standard sau administator), pentru care se doreste comunicatia SSH
fara parola, se executa urmatoarele setari.
a) Pe fiecare main, pentru fiecare utilizator care va comunica in retea, se genereaz o pereche
de chei public-privat cu comanda:
$ ssh-keygen -t dsa
Nu se da passphrase de stocare a cheii private. Implicit (pentru utilizatorul user) aceste chei se
depun n locaiile:
Your identification has been saved in /home/user/.ssh/id_dsa
Your public key has been saved in /home/user/.ssh/id_dsa.pub
b) Pentru conectarea ssh la localhost fara parola este necesar ca si cheia publica generata pentru
fiecare host/user sa fie copiata in propria lista de chei autorizate authorized_keys cu comenzile:
cd .ssh
cat id_dsa.pub >> authorized_keys
c) Se copiaz cheia public generat a fiecrei maini pe toate celelalte maini care trebuie s
accepte autentificarea fr parol prin comanda:
$ ssh-copy-id user@remotehost
Se
verific
$ ssh user@hostname
Dac nu se cere parola la autentificare, nseamn c s-a realizat corect conexiunea ssh cu
autentificare fr parol.
n clusterul HPC sunt instalate de administrator serverele ssh i este setat configurarea pentru
comunicaia cu autentificare fr parol i sincronizarea (replicarea) directoarelor utilizatorilor n toate
cele 4 noduri.
3
Tip de
signed
signed
signed
float
double
date C
char
short int
int
Utilizarea bibliotecii MPI se poate face de orice utilizator (standard sau administrator) pentru
care s-a setat comunicatia ssh fr parol.
Descrierea functiilor bibliotecii OpenMPI se gseste pe site-ul oficial (http://www.openmpi.org/doc/current/) si in paginile man pe orice calculator pe care este instalata biblioteca.
Cel mai simplu program MPI:
// Hello_MPI.c
#include <stdio.h>
#include <mpi.h>
// Se poate lansa cu oricate procese
int main(int argc, char *argv[]) {
int rank, len;
char hostname[MPI_MAX_PROCESSOR_NAME];
MPI_Init (&argc,&argv);
MPI_Comm_rank (MPI_COMM_WORLD,&rank);
MPI_Get_processor_name(hostname, &len);
hostname[len] = 0;
// sir terminat cu null
printf ("Hello MPI - Process %d host %s\n", rank, hostname);
MPI_Finalize();
return 0;
}
Pentru aflarea numelui hostului n care are loc executia se foloseste functia MPI :
int MPI_Get_processor_name(char * hostname, int* len)
Bufferul n care se citete numele hostului (hostname) trebuie s aib lungimea suficient ca s
ncap numele staiei (MPI_MAX_PROCESSOR_NAME).
Compilarea acestui program MPI se face cu comanda:
$ mpicc Hello_MPI.c -o Hello_MPI
Functionarea MPI in mod SPMD. Daca se doreste executia aceluiai program n mai multe
statii (mod SPMD Single Program, Multiple Data), se creeaz un fisier (hosts) care contine numele
statiilor si numarul de slot-uri (procesoare disponibile pe care vor fi lansate procese MPI) pentru fiecare
dintre ele; de ex. pe HPC:
$cat hosts_hpc
hpc
slots=1
compute-0-1 slots=1
compute-0-2 slots=1
compute-0-3 slots=1
Statiile care se pot nscrie in fiierul hosts trebuie sa fie din cele incluse in fisierul /etc/hosts
(cu adresa IP a fiecareia) si pentru care s-a setat comunicatia ssh fara parola pentru userul respectiv.
Dup definirea fisierului hosts, se da acest fisier ca parametru opiunii hostfile a comenzii mpirun:
$ mpirun -hostfile hosts_hpc -np 10 Hello_MPI
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
MPI
MPI
MPI
MPI
MPI
MPI
MPI
MPI
MPI
Proces
Proces
Proces
Proces
Proces
Proces
Proces
Proces
Proces
0
4
8
5
9
1
7
2
3
host
host
host
host
host
host
host
host
host
hpc.intern
hpc.intern
hpc.intern
compute-0-1.local
compute-0-1.local
compute-0-1.local
compute-0-3.local
compute-0-2.local
compute-0-3.local
Functionarea este corect dac pe toate nodurile se gasesc aceeasi utilizatori si aceleasi fisiere
executabile cu acelasi nume si cale n ierarhia de fiiere. n HPC aceste condiii sunt asigurate prin
software-ul de cluster (Rocks). n clusterele din laboratoarele B125a sau B138, trebuie copiat manual
fiierul executabil pe fiecare staie, n aceeai cale. Daca acest lucru este dificil, trebuie instalat NFS.
Dac nu este instalat nici un planificator de procese (resource manager SLURM, Condor, PBS
etc.), aa cum este cazul atr n laborator ct i n HPC, procesele sunt creeate i distribuite n execuie
de modulul de control al execuiei din biblioteca OpenMPI, ORTE (OpenMPI Real-Time Executive).
Fisierul de executie apppfile conine cte un fiier executabil pentru fiecare host. Se creeaz
nc trei fiiere surs Hello_MPI_v0.c, Hello_MPI_v1.c i Hello_MPI_v2.c care afieaz i versiunea
de program (v0, v1, v2) i se adaug versiunea i la numele executabilului. Se creeaz fiierul
appfile_hpc astfel:
$ cat appfile_hpc
# Comments are supported; comments begin with #
# Application context files specify each sub-application in the
# parallel job, one per line.
-np 1 -host user@hpc /home/user/Hello/Hello_MPI
-np 1 -host user@compute-0-0 /home/user/Hello/Hello_MPI_v0
-np 1 -host user@compute-0-1 /home/user/Hello/Hello_MPI_v1
-np 1 -host user@compute-0-2 /home/user/Hello/Hello_MPI_v2
Se lanseaz execuia cu comanda:
$ mpirun --app appfile_hpc
MPI
MPI
MPI
MPI
Exerciiul E4.1.a Compilai i executai programul Hello_MPI.c cu diferite valori ale numrului de
procese i hosturi n clusterul local i pe HPC. Experimentai modurile de execuie SPMD i MPMD.
4.1.6. Comunicaii MPI
Biblioteca MPI implementeaz att comunicaii punct-la-punct ct i comunicaii de grup
(colective), transferndu-se mesaje formate din vectori de date de un tip de date.
n MPI sunt definite grupuri de procese i contexte de comunicaie (communicators
comunicatori). Un grup este o colecie ordonat de procese, fiecare proces cu un numr de identificare
(rank rang, id), care este folosit ca nume pentru comunicaiile ntre procese. Numerele rank ncep cu
0 i sunt n continuare, n ordine.
Un comunicator este un context de comunicaie ntre procese MPI; exist 2 tipuri:
Intra-comunicator comunicator definit ntr-un singur grup de procese, att pentru
comunicaii punct-la-punct, ct i pentru comunicaii colective
Inter-comunicator definete comunicaia ntre dou grupuri de procese disjuncte.
Toate implementrile MPI definesc un intra-comunicator implicit (reprezentat prin constanta
MPI_COMM_WORLD), care cuprinde grupul de procese creat la iniializare (MPI_Comm_Init). Pentru
Pentru definirea dinamic a altor procese i regiuni paralele exist funcia MPI_COMM_SPWAN,
dar aceasta este foarte costisitoare ca timp de execuie i nu este recomandat (nici n standardul MPI,
nici n doc. de implementare). De aceea, n general n MPI sunt preferai algoritmii cu o singur reg
paralel.
Comunicaii MPI punct-la-punct. Biblioteca MPI implementeaz att comunicaii punct-lapunct ct i comunicaii de grup (colective) prin functii de transfer multiplu.
O comunicaie punct-la-punct are loc ntre 2 procese dintr-un comunicator. Procesul surs
trimite un mesaj (send) ctre procesul destinaie (care execut funcia receive)
Completarea unei comunicaii nseamn c transferul mesajului s-a terminat i locaiile de
memorie folosite (bufferul) pot fi accesate n siguran:
la transmitere (send), poate fi reutilizat bufferul de tranmisie
la recepie (receive), pot fi folosite variabilele recepionate n bufferul de recepie
Modurile de comunicaie MPI difer dup modul de completare a transferului:
blocante revenirea din funciile apelate nseamn c tranferul este complet
ne-blocante funciile revin imediat, dar utilizatorul trebuie s testeze completarea
Funcia de transmitere blocant:
int MPI_Send (void *buffer, int count, MPI_Datatype datatype,
int dest, int tag, MPI_Comm comm)
Numrul real de date recepionate se obine n variabila indicat de pointerul count - din
structura de tip MPI_Status, prin apelul funciei:
Exemplu Send_Receive_MPI.c
// Send_Receive_MPI.c
#include <stdio.h>
#include <mpi.h>
// Se lanseaza in executie cel putin 2 procese MPI
int main(int argc, char *argv[]) {
int rank, i, count, len = 8;
float sendbuf[100], recvbuf[100];
MPI_Status status;
MPI_Init (&argc,&argv);
MPI_Comm_rank (MPI_COMM_WORLD, &rank);
if(rank == 0) {
// procesul transmitator
for(i = 0; i < len; ++i) sendbuf[i] = i;
MPI_Send(sendbuf, len, MPI_FLOAT, 1, 55, MPI_COMM_WORLD);
}
else if (rank == 1){
// procesul receptor
MPI_Recv(recvbuf, 100, MPI_FLOAT, MPI_ANY_SOURCE, 55,
MPI_COMM_WORLD, &status);
MPI_Get_count(&status, MPI_FLOAT, &count);
printf("Procesul %d a primit %d numere de la procesul %d
\n", rank, count, status.MPI_SOURCE);
for (i = 0; i < count; i++) printf(%4.0f ); printf(\n);
}
MPI_Finalize();
return 0;
}
Compilare :
$ mpicc Send_Receive_MPI.c -o Send_Receive_MPI
Execuie:
$ mpirun -np 2 Send_Receive_MPI
Mesajul afiat la consol : Procesul 1 a primit 8 numere de la procesul 0:
0
1
2
3
4
5
6
7
Comunicaii colective MPI. Comunicaiile colective sunt sincrone, adic funciile nu revin
dect dup ce s-a terminat transferul. Aceasta funcionare asigur sincronizarea ntre procesele
comunicante; de ex. ntre procesul root si toate celelalte procese n comunicaiile one-to-all, all-to-one:
procesul root nu continu dect dup ce s-au term toate transferurile. Dar procesele care nu comunic
ntre ele pot s termine operaiile colective asincron i, dac este necesar sincronizarea, trebuie s
apelm explicit MPI_Barrier().
MPI_Barrier implementeaz o operaie de sincronizare (barier) ntre toate procesele din
comunicatorul dat ca parametru:
int MPI_Barrier (MPI_Comm comm);
MPI_Bcast - operaie de difuziune unul-la-toate (one-to-all) prin care procesul root trimite
count date de tipul datatype din bufferul buffer, tuturor proceselor din comunicatorul dat ca
parametru (comm); prototipul funciei MPI_Bcast() :
int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, \
MPI_Comm comm)
Exemplu - Bcast_MPI.c:
// Bcast_MPI.c
#include <stdio.h>
#include <mpi.h>
/* Executie cu oricate procese */
int main (int argc, char *argv[]) {
int rank, root = 0, buffer[8];
MPI_Init (&argc, &argv);
MPI_Comm_rank (MPI_COMM_WORLD, &rank);
if (rank == root) for (i = 0; i < 8; i++) buffer[i] = i;
MPI_Bcast (&buffer, 8, MPI_INT, root, MPI_COMM_WORLD);
printf("P%d: );
for (i = 0; i < 8; i++) printf(%4d,buffer[i]);
printf(\n);
MPI_Finalize();
return 0;
}
Datele din vectorul X se initializeaz n procesul root cu valori cresctoare, de la 0 la (n-1) iar
n celelalte procese cu 0. Procesul root transmite cte o partiie de s elemente celorlalte procese, care o
recepioneaz n prima partiie (primele s elemente ale vectorului) apoi le modific nmulindu-le cu 10.
Dup modificare toate procesele ateapt la o barier de sincronizare, dup care procesul root
colecteaz datele de la celelalte procese. Rezultatul execuiei este:
$ mpirun -np 4 Scatter_Gather
P0 dupa MPI_Scatter: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
P1 dupa MPI_Scatter: 4 5 6 7 0 0 0 0 0 0 0 0 0 0 0 0
P2 dupa MPI_Scatter: 8 9 10 11 0 0 0 0 0 0 0 0 0 0 0 0
P3 dupa MPI_Scatter: 12 13 14 15 0 0 0 0 0 0 0 0 0 0 0 0
MPI_Barrier
P1 dupa MPI_Gather: 40 50 60 70 0 0 0 0 0 0 0 0 0 0 0 0
P2 dupa MPI_Gather: 80 90 100 110 0 0 0 0 0 0 0 0 0 0 0 0
P3 dupa MPI_Gather: 120 130 140 150 0 0 0 0 0 0 0 0 0 0 0 0
P0 dupa MPI_Gather: 0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150
10
4.2.
Se paralelizeaz acelai algoritm secvenial ca i n lucrrile precedente, adic cel mai simplu
algoritm sevenial de nmulire a dou matrice ptrate a i b de dimensiuni n x n, cu rezultat matricea c:
for (i = 0; i < n; i++)
for (j = 0; j < n; j++) {
c[i][j] = 0;
for (k = 0; k < n; k++)
c[i][j] += a[i][k]*b[k][j];
}
In fisierul Matrix_Mult_MPI.c este dat programul MPI de nmulire paralel a dou matrice prin
partiionare unidimensional orientat pe linii. Aceast partiionare este echivalent cu distribuirea
iteraiilor buclei exterioare a algoritmului, deoarece aceste iteraii sunt independente.
Partea de program de alocare a datelor i nmulire a submatricelor este urmtoarea:
#include <mpi.h>
int main(int argc, char *argv[]) {
int n = 1024;
// Diensiune matrice
int p = 2;
// Nr procese MPI
int max_rep = 1;
// Numar de repetari executie
int rank, root = 0;
int i, j, k, s, rep;
// Citire parametri n, p, max_rep din linia de comanda ...
// Initializare MPI
MPI_Init (&argc,&argv);
MPI_Comm_rank (MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &p);
s = n / p;
// Alocarea matricelor
float **a = (float**)malloc(sizeof(float*)*n);
float **b = (float**)malloc(sizeof(float*)*n);
float **c = (float**)malloc(sizeof(float*)*n);
float *ma = (float*)malloc(sizeof(float)*n*n);
float *mb = (float*)malloc(sizeof(float)*n*n);
float *mc = (float*)malloc(sizeof(float)*n*n);
for (i = 0; i < n; i++){
a[i] = ma; ma += n;
b[i] = mb; mb += n;
c[i] = mc; mc += n;
}
// Initializarea matricelor ...
// Transmiterea matricelor a, b
if (rank == root && root == 0)
MPI_Scatter(a[0],s*n,MPI_FLOAT,MPI_IN_PLACE,s*n,MPI_FLOAT,root,\
MPI_COMM_WORLD);
else MPI_Scatter(a[0],s*n,MPI_FLOAT,a[0],s*n,MPI_FLOAT,root, \
11
Numrul de procese MPI (p) nu este definit n program; se creaz attea procese cte sunt
specificate prin comanda mpirun, dar trebuie ca n (dimensiunea liniilor i coloanelor matricelor a, b,
c) s fie divizibil cu p; dac n nu este divizibil, trebuie s se adauge cod care s trateze aceast situaie.
Fiecare din cele p procese prelucreaz s = n / p linii (partiionare pe linii, cu partiii continue); dac p <
P (numrul de proceseare din cluster), atunci cele p procese se execut pe p procesoare diferite,
performanele depinznd de p i de ncrcarea general a clusterului.
Dimensiunea matricelor (n) se introduce ca parametru de execuie (valoarea implicit este
n = 1024), iar matricele a, b, c se aloca dinamic, fiecare matrice fiind un tablou bidimensional ca bloc
continuu de memorie, cu dimensiunea n x n. n acest fel liniile matricelor sunt memorate la adrese
consecutive n memorie i pot fi transmise mai multe linii consecutive direct din matrice (cu
MPI_Scatter, MPI_Bcast, MNPI_Gather), fr s fie nevoie s fie copiate ntr-un buffer.
Aceast implementare este posibil i dac se aloc static matricele (dar atunci trebuie
recompilat programul pentru fiecare nou valoare a lui n) i dac se aloc matricele ca tablouri
unidimensionale (dar atunci elementul a[i][j] se acceseaz cu expresia a[i*n+j]).
n schimb, alocarea matricelor cu linii neadiacente (aa cum s-a fcut n programele Pthread i
OpenMP) nu garanteaz continuitatea blocului de memorie n care sunt memorate liniile consecutive i
programul nu va funciona.
Procesul root initializeaz datele de intrare, distribuie datele de intrare celorlalte procese,
calculeaz propria partiie de date i colecteaz partiiile rezultatului.
Pentru distribuirea matricei a se folosete funcia MPI_Scatter care transmite fiecrui proces
cte o partiie de s= n/p linii. Matricea b este transmis tuturor celorlalte procese cu funcia MPI_Bcast.
Dup distribuirea datelor folosind MPI_Scatter datele ajung n prima partiie (partiia cu indice
0) n fiecare proces i operaiile de calcul se execut folosind aceast partiie (indicele i parcurge valori
de la 0 la s 1), iar rezultatul se obine tot n aceast partiie.
Colectarea rezultatului n procesul root cu funcia MPI_Gather aranjeaz corect partiiile rez.,
aa cum se vede n figura de mai jos pentru operaia de nmulire a dou matrice cu 4 procese MPI.
12
P1
P2
P3
Matricea b
n toate procesele
Matricea c n root
dup MPI_Gather
n acest program a fost alocat spaiu pentru toate datele (matricele a, b, c) n toate procesele.
Dar se observ c n toate procesele care nu sunt root se poate aloca numai o partiie de dimensiune s
(s linii de cte n elemente din matricele a i c). Pentru aceasta, se poate face o alocare dinamic a
datelor cu dimensiuni care depind de n, size (p) i root.
Compilarea se face cu comanda:
$ mpicc Matrix_Mult_MPI.c -o Matrix_Mult_MPI
Lansarea n execuie ntr-un cluster Linux sau clusterul HPC se face cu comanda:
$ mpirun -hostfile hosts np p Matrix_Mult_MPI
Numarul de procese lansate p este dat de argumentul optiunii np si aceste procese se distribuie
uniform procesoarelor (cores, slots) din lista hosts.
nmulirea a dou matrice cu n = 2048 n HPC cu p = 1,2,4,8,16,32,64 procesoare d rezultatele:
$
1
$
1
$
1
$
1
$
1
$
1
$
1
mpirun
rep, n
mpirun
rep, n
mpirun
rep, n
mpirun
rep, n
mpirun
rep, n
mpirun
rep, n
mpirun
rep, n
-hostfile
= 2048, p
-hostfile
= 2048, p
-hostfile
= 2048, p
-hostfile
= 2048, p
-hostfile
= 2048, p
-hostfile
= 2048, p
-hostfile
= 2048, p
13
14
4.3.
4.4.
4.5.
Funciile de reducere sunt folosite pentru a calcula un rezultat prin combinarea datelor
distribuite ntr-un grup de procese MPI:
Funcia MPI_Reduce returneaz valoarea rezultat prin combinarea valorilor din sendbuf n
bufferul recvbuf n procesul root, iar MPI_Allreduce n toate procesele.
Operaia se aplic la count valori din sendbuf, cu rezultat n recvbuf (count 1).
15
Maximum
Minimum
Sum
Product
Logical
Bitwise
Logical
Bitwise
Logical
Bitwise
Maximum
Minimum
AND
AND
OR
OR
exclusive OR
exclusive OR
and index
and index
if u > v
i
u v w
int rank;
4.7.
Bibliografie
1. Felicia Ionescu, Calcul paralel, 2014, slide-uri publicate pe site-ul moodle ETTI.
2. Message Passing Interface Standard, 2009
3. B. Barney, Message Passing Interface, Lawrence Livermore National Laboratory, 2013,
https://computing.llnl.gov/tutorials/MPI/
17