Sunteți pe pagina 1din 331

Arhitectura sistemelor de calcul paralel

Cuprins
- Paralelism motivatie si aplicatii
- Supercomputere scurt istoric
- Programare paralela concepte / notiuni de baza
- Trenduri de paralelism
- Clasificarea arhitecturilor paralele
- Organizarea memoriei calculatoare cu memorie
distribuita / partajata

Exemple de procese paralele si aplicatii

Lumea reala un laborator gigactic de procese paralele

Aplicatii
Rezolvarea numerica a unor probleme care solicita putere
foarte mare de calcul, spatiu RAM i de stocare de date foarte mari.
Aplicatii in stiinta si tehnologie:

Predicii meteorologice;
Geologie Seismologie;
Microelectronica design-ul circuitelor;
Simulari stiinifice in fizica, chimie i biologie;

Aplicatii in sectorul industrial/comercial:

Baze de date, algoritmi de cautare;


Imagistica medicala;
Modelari financiare econofizica;
Design industria aeronautica, farmaceutica;
Aplicatii grafice, multimedia;

Avantajele utilizarii calculului paralel

Se economiseste timp productivitate sporita

Se pot rezolva probleme ce necesita resurse foarte mari (PetaFLOPS, PetaBytes)


Exemple : "Grand Challenge" (en.wikipedia.org/wiki/Grand_Challenge)

Utilizarea unor retele, platforme virtuale pentru a colabora in cadrul unui proiect
Exemplu: http://www.accessgrid.org/

Avantajele utilizarii calculului paralel

Utilizarea resurselor la distanta :


- SETI@home (setiathome.berkeley.edu) peste 1.3 millioane utilizatori,
3.4 millioane calculatoare distribuite in mai multe tari.
www.boincsynergy.com/stats/ (June, 2013)

- Folding@home (folding.stanford.edu) foloseste peste


320,000 computere in intreaga lume (June, 2013)

Motivatii pentru utilizarea calcului paralel

Limite ale calculului serial:


- limita in viteza de transmisie a datelor
(viteza maxima viteza luminii 30cm/nanosecunda)
cresterea vitezei micsorarea distantelor dintre elementele de procesare

Miniaturizarea elementelor de procesare (tranzistori)


- nodul tehnologic actual (2014) 14nm
- se ajunge in curand la limita scalarii

Limitari economice:
- este mai costisitor sa produci un procesor din ce in ce mai rapid;
- este mai eficienta folosirea unui numar echivalent de procesoare cu putere
de calcul mai scazuta;

Arhitecturile actuale au un nivel


de paralelizare tot mai ridicat
- single core double core quad core

Supercomputere

Performanta masurata in FLOPs (floating point operations)


- FLOPS = cores x clock x FLOPs/cycle
- Exemplu : procesor double-core 2.5GHz, 4 FLOPs/cycle 20 GFLOPs
Noiembrie 2013 :
Tianhe-2 or TH-2 (China)
- 33.86 petaFLOPs = 33 860 000 GFLOPs
- 16,000 noduri de calcul, fiecare avand
2 procesoare Intel Ivy Bridge Xeon
si 3 procesoare Xeon Phi,
totalizand 3 120 000 core-uri
- memorie RAM 88 GB / nod :
64GB - procesoare Intel Bridge Xeon
8GB procesoare Xeon Phi

Supercomputere scurt istoric

1960 Atlas: ~1 000 000 instructiuni/secunda


- University of Manchester -

1965 CDC 6600 : 1 megaFLOPS


- CERN 1976 Cray-1: 80 megaFLOPS
- studii atmosferice
1985 Cray-2: 1.9 gigaFLOPS
- departamentele de
aparare si energie SUA

Performanta top 500 supercomputere


http://www.top500.org/statistics

Nr. 1 (potocaliu) 33 862 700 Gflops/s


Nr. 500 (galben) 117 831 Gflops/s
Total 1-500 (verde) 250 080 467 Gflops/s

Programare paralela

Partitionarea problemei

Programare paralela
Presupune utilizarea simultana a resurselor de calcul
multiple pentru rezolvarea unei probleme de calcul:

Problema este impartita in sarcini (tasks) care pot fi rulate


independent
Fiecare sarcina este divizata intr-un set de instructiuni
Instructiunile din fiecare sarcina se executa simultan pe diferite
noduri de calcul
Exista un sistem de coordonare si control (nodul central)

Concepte de baza

Granularitate dimensiunea sarcinilor;

Potential de paralelizare reflecta proprietatea inerenta a unui algoritm


de a putea fi divizat in sarcini;

Procese si fire de executie (thread-uri) sarcinile sunt asignate unor


procese/fire de executie care sunt rulate pe noduri;

Planificare (scheduling) procesele se desfasoara intr-o anumita


ordine ce poate fi specificata in cod, la compilare sau dinamic.

Mapping atribuirea proceselor pe nodurile de calcul; de obicei o face


sistemul de operare, dar poate fi influentata de programator;

Sincronizare coordonarea proceselor pentru a avea o buna executie a


programului;

Concepte de baza

Memorie partajata exista un spatiu comun de memorie pentru toate


procesoarele; se asociaza de obicei notiunea de fir de executie (thread);
este necesarea sincronizarea intre thread-uri intrucat acceseaza aceeasi
memorie;

Memorie distribuita memoria este accesibila unui singur procesor; se


asociaza de obicei notiunea de proces;

Operatii de comunicare schimbul de informatii de la un procesor la


altul se face prin retea folosing operatii de comunicare;

Operatii bariera este o alta forma de coordonare si sincronizare,


valabila atat pentru thread-uri cat si pentru procese;

Timpul de executie paralela este timpul total de calcul pe

procesoare, timpul asociat transferului de date intre procesoare si timpul


aferent sincronizarii

Concepte de baza

Timp mort (Idle time) este timpul in care un procesor asteapta un


semnal (de la un alt proces) pentru a continua calculul;

Echilibrarea incarcarii (load balancing) pentru a eficientiza calculul


paralel este necesara o incarcare echilibrata, pentru a avea timpi morti cat
mai mici;

Totusi, pentru a realiza in practica o buna echilibrare


costurile pentru transferul de date si sincronizare cresc!

Speedup raportul intre timpul de calcul serial si timpul de calcul paralel;


ideal este numarul de core-uri;

Trenduri de paralelism
Trenduri in designul microprocesoarelor:
- Paralelism la nivel de bit: pana in 1986 : word size = 4 - 32 bits
~ 1990 : word size = 64 bits
- 64 bits asigura o buna precizie si acopera o zona de memorie
suficient de mare;
- Paralelism prin pipelining:
- idea centrala: suprapunerea executiei intre diferite instructiuni
- executarea unei instructiuni contine mai multe etape:
(tipic 2-26 etape)
- fetch : extragerea instructiunii din memorie;
- decode: decodificarea instructiunii;
- execute: incarcarea operanzilor specificati si
executarea instructiunii;
- write: scrierea rezultatului;
Observatii:
- sunt necesari timpi egali intre etape;
- nu exista dependente intre date;
- 26 etape procesoare superpipelined
- nr. de etape cu timpi egali nu poate fi in
practica arbitrar de mare;

Trenduri de paralelism
Trenduri in designul microprocesoarelor:
- Paralelism prin unitati functionale multiple:
- multe procesoare folosesc unitati functionale independente, multiple
- ALUs (arithmetic logical units);
- FPUs (floating points units);
- load/store units;
- branch units;
- procesoarele se clasifica in
- SUPERSCALAR
- VLIW (very long instruction world)
- Observatii: - numarul de unitati este restrictionat de dependente;
- planificarea (scheduling) se face hardware;
- 4 unitati se dovedeste a fi optim;
Cele 3 nivele de paralelizare mentionate presupun existenta un cod serial,
ceea ce este in avantajul programatorului. Totusi, se observa ca exista
limitari.
- Paralelism la nivel de proces sau thread:
- sisteme multi-core;
- cu cat memoria cache este mai mare timp de accesare mai
mare, deci se prefera arhitectura multi-core;

Clasificarea arhitecturilor paralele


Exista mai multe tipuri de arhitecturi paralele in functie de
complexitatea elementelor de procesare, structura retelei de
interconectare, tipul de coordonare a proceselor.
Exista mai multe tipuri de clasificari
- dupa multiplicitatea sirului de instructiuni/date (Flynn);
- single instruction, single data (SISD)
- multiple instruction, single data (MISD)
- single instruction, multiple data (SIMD)
- multiple instruction, multiple data (MIMD)
- dupa structura computerelor (Handler);
- arithmetic logic unit (ALU);
- procesor control unit (PCU);
- bit-level circuit (BLC);
- dupa modul de accesare al memoriei
- partajata (shared) tightly coupled systems;
- distribuita (distributes) loosely coupled systems;
- dupa granularitate;
- nr. de procesoare si tipul lor, organizarea memoriei,
dependenta datelor;

Arhitectura lui Flynn


SINGLE INSTRUCTION, SINGLE DATA (SISD)
- calculator serial
- Single instruction: o singura instructiune intr-un ciclu CPU
- Single data: un singur sir de date este folosit in oricare ciclu CPU

UNIVAC1

IBM 360

CDC 7600

PDP1

CRAY-1

Arhitectura lui Flynn


SINGLE INSTRUCTION, MULTIPLE DATA (SIMD)
- calculator paralel; aplicatii la procesare imaginilor
(unitati GPU);
- Single instruction: fiecare unitate de procesare executa
aceeasi instructione intr-un ciclu CPU
- Multiple data: fiecare unitate de procesare actioneaza asupra
unui elemnt diferit;

Arhitectura lui Flynn


SINGLE INSTRUCTION, MULTIPLE DATA (SIMD)

ILLIAC IV

Cray X-MP

MasPar

Cray Y-MP

Thinking Machines CM-2

Arhitectura lui Flynn


MULTIPLE INSTRUCTION, SINGLE DATA (SIMD)
- calculator paralel, rar intalnit, ne-comercial;
- posibile aplicatii: algoritmi de decriptare, aplicate pe un mesaj
codificat; filtru de frecvente, aplicat pe un semnal;
- Multiple instruction: fiecare unitate de procesare opereaza
independent;
- Single data: un singur sir de date este servit tuturor unitatilor
de procesare;

Arhitectura lui Flynn


MULTIPLE INSTRUCTION, MULTIPLE DATA (MIMD)
- calculator paralel, cel mai des intalnit;
- Multiple instruction: fiecare unitate de procesare opereaza
independent;
- Single data: fiecare procesor lucreaza cu siruri de date diferite;

Organizarea memoriei
SUNT 2 ASPECTE:
- organizarea memoriei fizic pe unitatile de calcul (1);
- punctul de vedere al programatorului (2);
(1) :
memorie partajata (multiprocesoare);
memorie distribuita (multicomputere);
hibrid : memorie virtual partajata (fizic distribuita, partajata
software)
(2):
Pentru programator exista doar primele doua tipuri!

Calculatoare cu memorie distribuita


Distributed Memory Machines (DMM):
- sunt constituite dintr-un numar de elemente de procesare si o
retea de interconexiune (interconnection network) care asigura
transferul de date intre noduri;
- un nod este o unitate independenta alcatuita din: procesor,
memorie locala si eventuale elemente periferice;

- datele din program se gasesc in memoria unuia sau mai multor


noduri; cand un procesor are novie de date, aceste sunt
transmise prin retea, prin message-passing.
Exemplu: Message Passing Interface (MPI)

Calculatoare cu memorie distribuita


Distributed Memory Machines (DMM):
- initial comunicarea se realiza prin conexiuni punct cu punct
(point-to-point communications); reteaua are forma unui graf
regulat (ex. Hypercub).

- Dificultati:
- necesitatea unor buffere, pentru a decupla operatiile de
send/receive si pentru a stoca mesajul pana cand partenerul
este disponibil sa il preia;
- comunicarea se face cu vecinii de ordin I;

Calculatoare cu memorie distribuita


Distributed Memory Machines (DMM):
- prima difucltate inlaturata prin adaugarea controlerului DMA
(direct memory acces) pentru a decupla operatiile de comun
icare de operatiile procesorului; se asigura astfel transferul de
date intre memoriile locale fara participarea procesorului;

- a doua dificultate este inlaturata prin folosirea unui router; astfel


se evita utilizarea procesoarelor pentru transmiterea mesajelor
intre noduri care nu sunt vecini de ordinul I; reteaua devine
omogena;

Calculatoare cu memorie distribuita


Distributed Memory Machines (DMM):
- Observatie:
In functie de reteaua folosita (ethernet, infiniband) diferenta
intre accesarea memoriei locale si remote poate ajunge la 1/100;
de aceea, programarea trebuie sa tina cont de infrastructura!
In conditiile unei retele cu rata de trnasfer mica este mai
eficient sa trimitem blocuri mai mari de date mai rar intre
procese, decat blocuri mici trimise des.

Calculatoare cu memorie partajata


Shared Memory Machines (SMM):
- sunt constituite dintr-un numar de elemente de procesare si o
retea de interconexiune (interconnection network) care asigura
transferul de date intre procesoare si memoria globala; memoria
poate fi implementata sub foma de module;

- din punct de vedere al programarii, se folosesc variabile tip


shared, accesate de toate procesoarele; acestea sunt stocate in
memoria globala;
- dificultate: memoria este accesata de toate procesoarele!
De aceea, sistemul functioneaza eficient pe numai cateva zeci
de procesoare.

Calculatoare cu memorie partajata


Shared Memory Machines (SMM):
- caz particular de SMM: symmetric multiprocessors (SMP)
- procesoare uniform distribuite in jurul unui bus de date
central;
- tipic 32-64 procesoare;
- programare de tip threading; se pot deosebi:
- kernel threads (operate de sistemul de operare);
- user threads (operate de user);
- SMP pot fi utilizate ca noduri intr-un calculator paralel; se poate
utiliza cache coherence protocol pentru a vedea memoria
global, desi fizic este distribuita sisteme de tip distributed
shared memory (DSM)
- in acest caz, timpul de acces al memorie depinde de locul
unde sunt stocate datele!
- aceste sisteme se mai numesc NUMAs
(non-uniform memory acces)

Reducerea timpului de acces al memoriei


Context:
- scalarea continua a elementelor de circuit cresterea
performantei CPU (operatii de tip floating-point) cu 80% / an
- capacitatea memoriei RAM creste gradual, cu 60% / an
- timpul de acces al memoriei RAM descreste cu numai 25 % / an
Concluzie:
- performantele CPU cresc mai rapid decat cele legate de timpul
de acces al memoriei RAM o buna organizare a memoriei este
esentiala!
Doua abordari principale:
1. Simularea unor procesoare virtualede catre fiecare procesor
fizic, multi-threading;
2. Folosirea unor memorii cache locale pentru a salva datele
care sunt accesate des

Ierarhia memoriei intr-un computer

Ierarhia memoriei intr-un computer


Exemplu : Procesorul Intel Haswell Mobile (2013):
* Registrii procesor cel mai rapid acces (de obicei 1 ciclu CPU).
Marimea cateva mii de bytes.
* Cache
o Nivel 0 (L0) Micro operations cache 6 KiB
o Level 1 (L1) Instruction cache 128 KiB
o Level 1 (L1) Data cache 128 KiB. Viteza de acces 700 GiB/s
o Level 2 (L2) Instruction and data (shared) 1 MiB, 200 GiB/s
o Level 3 (L3) Shared cache 6 MiB, 100 GB/s
o Level 4 (L4) Shared cache 128 MiB, 40 GB/s
* Memoria RAM Gigabytes, 10 GB/second. In cazul unei masini
NUMA timpul de acces nu este uniform
* Hard Disk Terabytes, 600 MB/s
* Alte unitati de stocare Exabytes, 160 MB/s

Multi-threading fire multiple de executie


Interleaved multi-threading:
- presupune simularea unui numar mare de procesoare virtuale pe
fiecare procesor fizic;
- datele ajung din memorie la procesor intr-un timp finit (timpul de
acces, latenta)
- dupa efectuarea unei instructiuni, se comuta un alt procesor
virtual;
- numarul de procesoare virtuale este relativ mare pentru a asigura
transferul datelor din memorie; in acest fel, datele sunt procesate
pe masura ce sunt accesate.
- se mai numeste si fine-grained multi-threading o comutare
catre un procesor virtual dupa fiecare instuctiune;
- o alternativa este coarse-grained multi-threading o comutare se
face cand apar blocaje mai costisitoare (level 2 cache misses)
Dezavantaje:
- numarul mare de procesoare virtuale presupune un grad mare de
paralelism (nu este intotdeauna atins)
- procesoarele fizice au design special pentru a emula procesoare
virtuale (este prea lent sa generam acelasi efect software)

Memoria cache
Caracteristici:
- o unitate de memorie mica dar rapida situata intre memoria RAM
principala si procesor;
- contine intotdeauna un subset al datelor din memoria RAM
principala;
- timpul de acces este mult mai mic pentru memoria cache;
- contine mai multe nivele: L1, L2, L3 cu memorie mai mare dar mai
putin rapida (si mai ieftina);
In cazul sistemelor multi-procesoare:
- este necesar ca informatia din cache-ul diferitelor procesoare sa
coincida intre ele si cu memoria RAM ! (cache coherence problem)
- solutia este data de cache coherence protocol

Paralelism la nivel de thread


Thread level paralelism:
- arhitecturile paralele procesoare multi-core necesita folosirea
explicita a programelor paralele ;
- o alternativa ar fi comutarea firelor de executie pe un procesor, prin
intermediul hardware fine-grained / coarse-grained multi-threading;
- o varianta de coarse-grained multi-threading este timeslice
multithreading (multithreading pe intervale temporale) procesorul
comuta intre thread-uri dupa un interval predefinit;
- se poate intampla ca un thread sa astepte un eveniment in mijlocul
unui interval temporal implica existenta unui timp mort;
- solutia este data de switch-on-event multithreading procesorul
comuta la urmatorul thread;

Paralelism la nivel de thread


Thread level paralelism:
- arhitecturile paralele procesoare multi-core necesita folosirea
explicita a programelor paralele ;
- o alternativa ar fi comutarea firelor de executie pe un procesor, prin
intermediul hardware fine-grained / coarse-grained multi-threading;
- o varianta de coarse-grained multi-threading este timeslice
multithreading (multithreading pe intervale temporale) procesorul
comuta intre thread-uri dupa un interval predefinit;
- se poate intampla ca un thread sa astepte un eveniment in mijlocul
unui interval temporal implica existenta unui timp mort;
- solutia este data de switch-on-event multithreading procesorul
comuta la urmatorul thread;
- o astfel de varianta este simultaneous multithreading (SMT); se
mai numeste si hyperthreading pe unele procesoare Intel;

Multithreading simultan
- consta in utilizarea mai multor fire de executie si executarea
instructiunilor din diferite thread-uri in acelsi ciclu CPU, folosind mai
eficient unitatile functionale ale procesorului;
- suportul hardware consta in replicarea unitatilor care stocheaza
starea procesorului:
- program counter (PC) registru al procesorului care indica
punctul de executie al programului
- registrii user / control
- interrupt controller, plus registrii aferenti
- prin aceste replicari, procesorul fizic apare ca un set de
procesoare logice
- starile procesoarelor logice sunt stocate pe unitati distincte (nu
necesita timp de reactualizare la comutare); doar cache-ul, sistemul
bus, unitatile de control sunt comune procesorul nu creste
semnificativ in dimensiune;
- tipic: 2 procesoare logice 30% speedup

Procesoare multi-core
Cresterea performantele procesoarelor se datoreaza in ultimii ani:
- cresterea frecventei de lucru;
- folosirea paralelismului de tip pipeline;
- folosirea unitatilor functionale multiple (aritmetice, logice);
Limitari:
- multiplicarea unitatilor functionale este limitata de dependintele
intre diferite instructiuni;
- frecvent de lucru a procesorului nu poate fi marita semnificativ;
Marirea densitatii de elemente/chip conduce la curenti de tunelare
mari; Marirea memoriei conduce la timpi de acces relativ mari (6-8
cicluri CPU in 1990, 100-250 cicluri CPU in 2006 DRAM);
- viteza maxima a semnalului:
Ex.: procesor 3GHz 0.33ns / ciclu CPU semnalul acopera
10cm / ciclu CPU (care nu este semnificativ mai mare decat
dimensiunea procesorului!)
- dimensiunea maxima a procesorului implica un numar maxim de
pini pentru accesarea memoriei memory wall (reducerea lungimii
de banda) este necesara o ierarhie eficienta a memoriei cache;

Arhitectura sistemelor multicore


Exista mai multe variante de procesoare multicore (in functie de nr.
de miezuri, structura si marimea cache-urilor).
Se disting 3 tipuri principale de arhitecturi multicore:
- Design ierarhic;
- Pipelined Design;
- Design bazat pe retea (network-based design);

Design ierarhic
- diferite miezuri impart diferite memorii cache;
- memoriile cache sunt organizate sub forma unui arbore;
- cache-ul de nivel L1 este separat, insa incepand cu nivelul L2
memoria este impartita cu alte miezuri;
Utilizari:
- tipic pentru symmetric multiprocessors (SMP);
- adesea folosit pentru computere desktop standard sau servere;
Exemple:
- arhitectura IBM Power6;
- familia de procesoare AMD Opteron;
- procesoare SunNiagare (T1 si T2);
- Intel Quad-Core Xeon;
- unitati GPU;

Design ierarhic

Quad-core AMD Opteron

Quad-Core Intel Xeon

Design ierarhic

Nvidia GeForce 8800

Pipelined design
Concept:
- datele sunt procesate de mai multe miezuri in maniera pipeline;
- datele intra in chipul-procesor printr-un port de input si trec
succesiv diferite miezuri si apoi ies din chipul-prcesor printr-un port
de output;
- fiecare miez executa un pas de procesare diferit pe fiecare element
din sirul de date;
Utilizare:
- aplicatii unde intervin secvente lungi de date;
- network processors (rutere), procesoare grafice;
Exemple:
- Xelerator X10 si procesoare X11 : procesarea pachetelor din retea
in maniera pipeline;
- Xelerator X11 are pana la 800 de miezuri!

Pipelined design

Procesor Xelerator X11

Design pe baza de retea


Concept:
- miezurile unui procesor si cache-urile/memoriile locale sunt
inter-conectate prin intermediul unei retele;
- reteaua asigura sincronizarea miezurilor;
Exemplu:
- procesor Intel Teraflop (prototip, produs prin programul Intel Terascale Computing Research);
- zeci-sute de miezuri;
- programul vizeaza: design-ul miezurilor, managementul energiei,
ierarhia cache-urilor si a memoriei, operatii I/O;
- exemplu concret: 80 miezuri intr-o retea 8x10; fiecare miez are
cache local; exista miezuri suplimentare care asigura procesare
grafica, video, criptare;

Design pe baza de retea

Procesor Intel Teraflop

Trenduri actuale
Dificultati ce trebuie avute in vedere in design-ul procesoarelor:
- eficienta interconectarii pe chip transfer de date intre miezuri;
- lungime de banda suficienta pentru transferul intre miezuri;
- design scalabil cu cresterea nr. de miezuri;
- design robust pentru a tolera eventuale cedari fizice
ale unor miezuri;
- mangementul energiei;
- transferul eficient al datelor de la memorie catre miezuri; ierarhie
a memoriilor cache;
- L1 cache separat pe fiecare miez;
- L2 este comun mai multor miezuri;
- L3, L4 (ex. Itanium) pentru a micsora timpul de acces;

Trenduri actuale
Cateva exemple:

Retele de interconectare
Interconnection network :
- conexiune fizica intre diferitele componente ale unui sistem paralel;
- Sarcina principala a unei retele este de a transfera cu o viteza cat
mai mare un mesaj de la un procesor la o destinatie specifica (poate fi
un procesor sau un modul de memorie), mesaj care poate contine
date sau o cerere pentru memorie, de multe ori mesajele trebuie
transferate in mod paralel;
Criterii in design-ul retelelor:
- topologia retelei descrie structura interconexiunii intre diferite
procesoare si module de memorie;
- tehnica de rutare descrie transmiterea mesajelor intre procesoare
si module de memorie;

Retele de interconectare
Topologie:
- structura geometrica poate fi reprezentata intr-un graph in care
procesoare, module de memorie, switch-uri sunt descrise de
noduri, iar conexiunile fizice sunt reprezentate de laturi;
Tipuri:
- retele de interconectare statice si dinamice;
Retele statice:
- conecteaza nodurile direct;
- se mai numesc si retele indirecte, point-to-point networks
- nr de conexiuni poate varia (1-retea stea, nr. de noduri-graf
complet conectat)
Retele dinamice:
- conecteaza nodurile prin elemente de tip switch;
- se mai numesc si retele indirecte;
- exemple : - bus-based networks
- switching networks

Retele de interconectare
Rutare (routing):
- priveste maniera in care sunt transferate mesajele si alegerea
cailor de la sursa la destinatie;
- algoritm de rutare: determina calea utilizata pentru transmisie;
- strategia de switching: determina daca si cum sunt delimitate
mesajele in parti, cum se detemina calea pentru transmisia
mesajului;
Performanta unei retele este data de: algoritmul de rutare de
strategia de swiching si de topologie;
Se vor discuta in continurare:
- tipuri de retele directe si indirecte;
- algoritmi rutare si strategii de switching;

Proprietatile retelelor de interconectare


- reteaua este definita de un graf G = (V,E)
- V setul de noduri; E setul de conexiuni;
- o cale este o secventa de noduri:
- diametrul unei retele este distanta maxima dintre oricare
pereche de noduri:

- gradul unei retele este gradul maxim al unui nod;


- gradul unui nod este dat de numarul de vecini;
- bisection bandwidth numarul de laturi ce trebuie indepartate
pentru a partitiona graful in doua sub-grafuri de marimi egale;

Proprietatile retelelor de interconectare


- conectivitatea nodurilor si conexiunilor:
- masoara nr. de noduri sau laturi care ar trebui sa cedeze
pentru a avea o retea disconectata;
- o buna conectiviate indica o buna fiabilitate a retelei si
este de dorit;

- Observatie: gradul minim al unui nod e o limita superioara a


conectivitatii nodurilor / conexiunilor;
Exemplu:
- nc = 1; ec =2; gradul retelei = 4;

Proprietatile retelelor de interconectare


- flexibilitatea unei retele se leaga de notiunea de embedding;
- fie doua grafuri G = ( V , E ) , G' = ( V', E' );
- o incluziune a lui G' in G presupune ca nodurile lui G' sunt
asociate cu noduri din G, in asa fel incat si conexiunile nodurilor
lui G' se regasesc in G;
- formal exsita o functie:

- Observatie: daca G' este inclus in G, atunci reteaua G este cel


putin la fel de flexibila ca si G';

Proprietatile retelelor de interconectare


Sunt de dorit urmatoarele proprietati topologice :
- diametru mic distante mici pentru trnamsiterea mesajelor;
- gradul nodurilor cat mai mic se reduce incarcare harware a
nodurilor;
- bisection bandwidth cat mai mare rate de trasmisie mari;
- conectivitate mare asigura fiabilitatea retelei;
- flexiblitate mare;
- capacitate de extensibilitate catre un numar mai mare de
noduri;

Retele de interconectare directe


Graf complet : fiecare nod este conectat cu oricare alt nod
- diametru = 1;
- grad = n 1;
- conectivitate nc = ec = n 1;
(pentru a delimita un nod trebuie indepartate n-1 laturi);
- bisection bandwidth = n*n/4;
(pentru a delimita graful in n/2+n/2 noduri se sterg n/2 laturi
comune pentru fiecare din cele n/2 noduri ale unui subset);
- toate celelalte tipuri de grafuri pot fi incluse in graful complet;
- din cauza gradului mare, in partica se foloseste un numar
redus de noduri;

Retele de interconectare directe


Graf liniar : nodurile sunt aranjate in secventa
- diametru = n 1;
(maxim n-1 noduri trebuie traversate)
- grad = 2;
- conectivitate nc = ec = 1;
(pentru a delimita un nod trebuie indepartate o latura);
- bisection bandwidth = 1;
- un graf liniar poate fi inclus in aproape toate retelele standard,
cu exceptia retelelor de tip arbore;
- deoarece exista o singura conexiune intre doua noduri
adiacente, nu ofera o fiabilitate mare (no fault tolerance);

Retele de interconectare directe


Retea tip inel : nodurile sunt aranjate pe un inel
- diametru = n/2; aici difera de reteaua liniara !
(maxim n-1 noduri trebuie traversate)
- grad = 2;
- conectivitate nc = ec = 2;
(pentru a delimita un nod trebuie indepartate o latura);
- bisection bandwidth = 2;
- se folosesc pentru un numar redus de procesoare in contextul
unor retele mai complexe;

Retele de interconectare directe


Retea de tip matrice d-dimensionala : nodurile sunt aranjate
pe un grid d-dimensional
- presupunem o retea simetrica:

- diametrul:
- grad = 2d;
- conectivitate nc = ec = d;
O varianta: torul d-dimensional
- conditii periodice;
- diametrul:
- grad = 2d;
- conectivitate nc = ec = 2d;

Retele de interconectare directe


Sumar al topologiilor:

Integrarea retelelor in reteaua de tip hyper-cub

Topologia retelei de tip hyper-cub este versatila si flexibila.


Vom demonstra aceasta prin integrarea in reteaua hyper-cub a
urmatoarelor retele:
- reteaua de tip inel;
- reteaua de tip matrice bi-dimensionala, d-dimensionala;

Integrarea retelei de tip inel in


reteaua de tip hyper-cub
- consideram o retea de tip inel cu

noduri

- graf V' =
- dorim sa integram reteaua intr-un graf de tip cub k-dimensional
- graf V =
- construim o functie bijectiva de la V' la V, asa incat toate laturile
din V' sa fie mapate pe hyper-cub;
- reflected binary code (Gray code) RGC : sir de secvente binare,
in care secventele difera printr-un singur bit;
-Ex : 000, 001, 011, 010, 110, 111, 101 etc.

Integrarea retelei de tip inel in


reteaua de tip hyper-cub
Reflected Gray Code:
- cum construim secventele ?
- 1-bit RGC : 0, 1
- 2-bit RGC :
- inseram 0 si 1 in fata celor doua valori din 1-bit RGC
00, 01 si 10, 11
- schimbam in al doilea sir si concatenam sirurile
00, 01, 11, 10
- pentru
:
- este construit din codul (k-1)-bit RGC:
unde
- adaugam 0 si 1 in fata codului (k-1)-bit RGC
se obtin sirurile
- se schimba ordinea sirului 2 si se concateneaza:

Integrarea retelei de tip inel in


reteaua de tip hyper-cub
Asadar functia de mapare este :

unde

este secventa i a sirului

Integrarea retelei de tip matrice bi-dimensionala in


reteaua de tip hyper-cub
- Reteaua de integrat :
- matrice bi-dimensionala cu
- consideram
,

n=n1n2

noduri

- Avem doua coduri RGC (pe linii si pe coloane)


- Formam matricea:

- Observatie:
- elementele de pe linii / coloane constituie siruri RGC

Integrarea retelei de tip matrice bi-dimensionala in


reteaua de tip hyper-cub
- Functia de mapare:

Integrarea retelei de tip matrice d-dimensionala in


reteaua de tip hyper-cub
- Generalizare la cazul matrice d-dimensionala.
pe dimensiunea i;
- n noduri in total
- pozitia unui nod
- Functia de mapare:

unde

este stringul binar de pe pozitia

Retele de interconexiune dinamice


- Se mai numesc si retele indirecte :
- procesoarele nu sunt conectate direct,
ci prin intermediul unor switch-uri;
- switch-urile pot fi configurate dinamic;
- Se pot clasifica din punct de vedere al toppologiei:
- retele tip bus (bus networks);
- retele multi-stage (multistage networks);
- retele tip crossbar ( crossbar networks);

Retele de tip bus


- Principial, un bus este un set de conexiuni care pot transmite
date de la sursa la destinatar.

- doar un singur transport de date se poate efectua la un moment


dat bus-ul este utilizat in maniera time-sharing
- daca mai multe procesoare incearca sa trimita date in acelasi
timp, este utilizat un coordonator bus arbiter
- deoarece cu cresterea nr de procesoare, probabilitatea de
transmisie simultana creste in practica retelele de tip bus se
folosesc pentru un numar redus de procesoare.

Retele de tip crossbar


- O retea n x m de tip crossbar are n intrari si m iesiri;

- Pentru un sistem cu memorie partajata, intrarile pot fi


procesoare, iar iesirile module de memorie;
- In functie de cererea explicita al unui nod, switch-urile pot avea
doua valori : fara / cu schimbare de directie;
- se folosesc in retele cu un numar redus de porcesoare din cauza
overhead-ului hardware relativ mare.

Retele multi-stage
- Sunt retele constituite din mai multe trepte (formate din switch-uri)
interconectate;
- input : procesoare; output : procesoare (sisteme cu memorie
distribuita) sau module de memorie (sisteme cu memorie partajata)
- Regular multistage networks:
- acelasi numar de intrari si iesiri la toate switch-urile;
- de obicei switch-urile sunt retele crossbar a x b;

Retele multi-stage
- Retele multi-stage populare:
- omega network;
- baseline network;
- butterfly network;
- Aceste retele folosesc switch-uri crossbar 2x2, aranjate in log(n)
trepte, unde n este numarul de conexiuni intre trepte;
- Fiecare switch se poate gasi in una sin urmatoarele stari:

Reteaua omega
- n x n retea omega se bazeaza pe switch-uri crossbar 2x2;
- fiecare swictch are 2 intrari si 2 iesiri;
- o trepta contine n/2 switch-uri si sunt in total log(n) trepte
(log = log baza 2)
- rezulta un total de (n/2) log(n)
- Ex. Retea omega 16x16 ( n=16, 4 trepte, 8 switch-uri/treapta,
total 32 switch-uri )
- Utilitatea: evitarea creearii unui
Bottleneck pe conexiunea
cpu-memorie
- Ex. Sisteme:
- Illinois Cedar Multiprocessor,
- IBM RP3
- NYU Ultracomputer

Butterfly network
- similara cu retea omega;
- conecteaza
input-uri de
- (k+1) trepte, cu

output-uri

switch-uri pe treapta

- Ex. : retea 16x16 cu 4 trepte

Baseline network
- Ex. : retea 16x16 cu 4 trepte

Retea Benes
- Este constituita din doua retele tip butterfly k-dimensionale:
- primele k+1 trepte sunt cele ale unei retele butterfly;
- urmatoarele k+1 trepte sunt inversate;
- Mapeaza caile de pe un hyper-cub;

Retea de tip fat tree


- Este un arbore binar complet;
- Diferentea fata de un arbore binar obisnuit este ca numarul de
conexiuni creste catre radacina pentru a evita bottlenecks;

Algoritmi de rutare
Daca doua procesoare nu sunt legate direct de o conexiune de
retea, o cale va contine in general o secventa de noduri
cum se selecteaza calea optima ?
- Algoritm de rutare: determina calea de la nodul sursa A la nodul
destinatie B;
- Se poate ajunge in situatie de deadlock: mesaje multiple
transmise pe aceeasi cale;
- Un algoritm de rutare eficient: incearca sa gaseasca calea dintre
doua noduri cu cost minim; costul depinde nu numai de lungimea
caii alese, ci si de incarcarea ei.

Algoritmi de rutare
Urmatoarele aspecte sunt importante pentru alegerea caii:
- topologia retelei: se determina caile disponibile in retea;
- network contention:
- apare in momentul in care doua sau mai multe mesaje trebuie
transmise simultan pe aceeasi conexiune de retea;
- conduce la intarzieri in transmiterea mesajelor;
- network congestion:
- este situatia in care mai multe mesaje sunt destinate unei
resurse restrictionate (buffer);
- mesajele care ajung vor fi inlaturate, deoarece nu mai pot fi
stocate;
- se ajunge astfel la pierderea mesajelor;

Clasificarea algoritmilor de rutare


- Din punctul de vedere al lungimii caii:
- minimali / non-minimali;
- minimal : alege intotdeauna calea cea mai scurta
situatii de congestie a retelei
- Algoritmi de rutare deterministici / adaptativi
- deterministic : - depinde doar de nodul sursa si nodul
destinatie;
- nu depinde de incarcarea retelei;
poate conduce la incarcare inegala a retelei;
- Exemplu: dimension-order routing, in cazul
retelelor de tip matrice, tor, hypercub;
- adaptativ : - selecteaza ruta pe baza incarcarii retelei
- fault tolerant ! Exista mai multe cai de
comunicare in cazul in care apar probleme
hardware;

Algoritmi de rutare. Deadlocks.


- De obicei se intampla ca mesaje multiple sa fie transmise in
acelasi timp;
- Exemplu de deadlock:
- conexiunile suporta un singur mesaj;
- se transmiste un mesaj A-B-C si un mesaj C-B-A;
- conexiunile pot fi deblocate doar cand conexiunea urmatoare
este libera;
- intrucat A-B este blocat de mesajul 1 si C-B de mesajul 2
deadlock
- pot apare situatii de deadlock
- prin limitarea bufferelor (input/output)
- succesiune nepotrivita de operatii SEND / RECEIVE

Algoritmi de rutare. Deadlocks.


- Graful bi-directional XY (matrice bi-dimensionala) nu are
deadlocks!

Tipuri de rutare
- pe baza nodului sursa (source-based):
- algoritm de rutare deterministic
- nodul sursa determina calea in intregime stabileste
secventa indexurilor de iesire :
- nodul urmator sterge primul index si trimite mai departe.
- pe baza tabelelor de rutare (table-based)
- fiecare nod are un tabel cu calea catre oricare alt nod;
- pe baza de redirectionare (turn-model routing)
- se incearca evitarea deadlock-urilor prin selectia potrivita a
redirectionarilor;

Tipuri de rutare
Retea bidimensionala:
- redirectionari posibile:

- redirectionari permise pentru rutare XY (4 din 8 posibile):

- redirectionari posibile in rutare West-first (6 din 8 posibile):

Tipuri de rutare
Retea bidimensionala:
- Observatie:
- doua din cai nu sunt minimale;

Canale virtuale virtual channels


Concept:
- fiecare conexiune fizica este impartita in canele virtuale multiple;
- fiecare canal virtual are propriul buffer;
Observatii:
- canalele virtuale nu cresc numarul de conexiuni fizice;
- asigura evitarea sistematica a situatiilor de deadlock;
O retea poate fi impartita in retele virtuale:
- un mesaj se poate deplasa intr-o sindura directie pentru fiecare
dimensiune;
- fiecare retea virtuala contine toate nodurile retelei, dar doar un
subset al conexiunilor;

Canale virtuale virtual channels


Exemplu:
- reteaua originala cu canale virtuale pe directia y;

Canale virtuale virtual channels


Partitionarea in subretelele +X si X:
- + X : transferul mesajelor de la A la B pentru XA < XB
- X : transferul mesajelor de la A la B pentru XA > XB
- algoritmul de rutare este deadlock free;

Switching
Strategii de switching:
- determina cum este transmis un mesaj pe o cale care a fost
selectata de un algoritm de rutare;
- determina:
- daca si cum se face splitarea unui mesaj (care se numesc
pachete flits, flow control units)
- cum este alocata calea de transmisie sursa-destinatie;
- cum sunt forwardate mesajele de la canalul de input catre
canalul de output al unui switch / ruter; algoritmul de rutare
determina care canal de output trebuie folosit;
Strategia de switching poate avea o mare influenta asupra timpului
de transmisie de la sursa la destinatie;
Vom analiza pentru inceput timpul de transmisie intre doua noduri
care sunt conectate direct.

Transmisia mesajelor intre procesoare vecine


Transmisia mesajelor intre doua procesoare se implementeaza intr-o
serie de pasi:
Sender:
- mesajul este copiat intr-un sistem buffer;
- este calculat un checksum; este adaugat un header la mesaj care
contine alte informatii cu privire la transmisia mesajului;
- este pornit un timer si mesajul este trimis catre interfata de retea;
Receiver:
- mesajul este copiat din interfata de retea intr-un buffer;
- este comparat checksum-ul cu cel calculat la receptie;
- daca valorile coincid un mesaj de acknowledgement e
trimis catre sender;
- daca valorile nu coincid mesajul este inlaturat; mesajul va fi
retrimis dupa ce expira timpul masurat de sender;
- daca valorile checksum coincid mesajul este bufferul sistemului in
bufferul userului, pus la dispozitie de aplicatia care ruleaza; aplicatia
va primi o notificare si isi continua executia;

Transmisia mesajelor intre procesoare vecine


Sender:
- daca soseste certificarea ca mesajul a fost transmis cu succes,
bufferul poate fi golit;
- daca timpul alocat transmisiei s-a scurs, mesajul este trimis din nou;
timer-ul este reinitializat, iar timpul alocat transmisiei este posibil
marit;
Observatii:
- mesajul este mentinut in buffer (sender) pentru a fi retransmis, daca
este necesar;
- daca se tolereaza pierderi de mesaje, bufferul este golit imediat ce
mesajul este transmis;
In practica, protocoalele de transmitere a mesajelor sunt mult mai
complicate, si de obicei au in vedere si alte aspecte:
- network contention;
- buffer overflow (receiver);

Notiuni ce privesc performanta transmiterii mesajelor


- Bandwidth: frecventa maxima la care pot fi transmise datele printr-o
conexiune; se masoara in bytes / secunda;
- byte transfer time: este timpul pentru a transmite un singur byte
printr-o conexiune; este inversul bandwidth;
- time of flight: (channel propagation delay) timpul in care primul bit
din mesaj ajunge la receiver; depinde foarte mult de distnata fizica
dintre sender si receiver;
- transmission time: timpul necesar pentru a transmite mesajul prin
retea;
- transport latency: timpul total de transfer al mesajului prin retea
de la primul bit care intra in retea si ultimul bit care ajunge la receiver;
- sender overhead: (startup time) timpul necesar sender-ului pentru
a pregati transmisia mesajului; include calcul checksum, adaugare
header, executarea algoritmului de rutare;
- receiver overhead: timpul necesar pentru a procesa un mesaj;
inclusiv calcul checksum, generare acknowledgement;
- throughput: (a unei conexiuni) bandwidth efectiv experimentat de o
aplicatie;

Notiuni ce privesc performanta transmiterii mesajelor


- Latenta totala:
Sender / receiver overheads, time of flight, B = bandwidth, m = message size

Strategii de switching
Doua tipuri de strategii de switching:
- circuit switching;
- packet switching;

Circuit switching:
- calea de la nodul sursa la nodul destinatie este stabilita si rezervata
pana la sfarsitul transmisiei mesajului;
- mesajele sunt impartite in pachete (physical units = phits, 1-256 bits)
- pentru a stabili calea se utilizeaza mesaje de proba (probe
messages)
- calea este eliberata in momentul in care ajunge confirmarea
(acknowledgement) de la receiver catre sender;

Strategii de switching
Packet switching:
- mesajele sunt partitionate intr-o secventa de pachete, iar fiecare
pachet este transmis independent prin retea de la sender la receiver;
- folosind algoritm de rutare adaptativ pachetele pot fi transmise pe
cai diferite;
- un pachet contine:
- header informatii de routing;
- data o parte a mesajului;
- trailer error control code;

Strategii de switching
Packet switching - implementare:
- store-and-forward routing : pachetul este stocat (store) pe un
switch (A) inainte sa fie trasmis (forward) catre switch-ul urmator (B);
- in momentul in care mesjul a ajuns la B, conexiunea dintre A si B
este eliberata;
Avantaje:
- se foloseste intreaga lungime de banda atunci cand switch-urile au
rate de transfer diferite (ceea ce se poate intampla frecvent intr-o
retea de tip WAN = wide area network)
- se reduce probabilitatea de deadlocks se elibereaza conexiunile
de indata de pachetul a trecut;
Dezavantaj:
- fiecare pachet trebuie stocat pe fiecare switch, ceea ce creste
necesitatea de memorie / switch;

Strategii de switching
Circuit switching

Packet switching with store and forward

Strategii de switching
Packet switching with Cut-Through Routing :
- utilizarea ideii de pipelining;
- mesajele sunt impartite in pachete, fiecare pachet are o ruta (diferita)
prin retea;
- pachetele sunt transmise in maniera de tip pipeline;
- fiecare switch inspecteaza primii phits (physical units) ai
header-ului, care contine informatia de rutare este
determinat canalul de iesire din switch
- odata ce calea este determinata de header, restul mesajului
este transmis in maniera pipelined;

Strategii de switching
Packet switching Observatii:
- un pachet blocat poate ocupa o cale intreaga sau o parte a unei cai;
- similaritati cu circuit switching la nivel de pachete;
- se pot bloca alte mesaje pe aceeasi cale saturarea retelei;
- pot apare situatii de deadlock prin asteptare ciclica;

Strategii de switching
Cut-Through Routing doua optiuni :
- virtual cut-through routing;
- wormhole routing;
Virtual cut-through routing:
- daca un canal de output este blocat, toate unitatile fizice ale
pachetului sunt stocate intr-un buffer;
- daca acest lucru se intampla la fiecare pas se ajunge la storeand-forward routing;
- in regim partial cut-through routing nu toate pachetele sunt stocate
in buffere;
Wormhole routing:
- abordarea se bazeaza pe flits (flow control units) care au dimensiuni
cel putin la fel de mari ca header-ul;
- header-ul (un flit) stabileste calea de urmat;
- celelalte flit-uri urmeaza in maniera pipelined;
- daca un canal este blocat, doar cateva flit-uri sunt stocate, restul trec
mai departe si eventual stocate la switch-ul urmator;

Flow control mechanisms


Sunt mecanisme de coordonare a mesajelor multiple in retele.
Ex. : TCP (transmission control protocol) / IP (internet protocol)
HTTP hypertext trasfer protocol
IMAP internet message acces protocol
SMTP simple mail transfer protocol
POP3 post office protocol v3
- astfel de mecanisme de control al fluxurilor de pachete au o
important deosebita in cadrul arhitecturilor paralele, intrucat este
necesara transmiterea rapida si eficienta (fara pierderi) a unui numar
mare de mesaje;
- Mecanismele de control al fluxurilor de pachete incearca sa reduca
congestia intr-o retea;

Flow control mechanisms


Consideram urmatoarea situatie:
- un pachet trebuie transmis de la switch-ul A catre switch-ul B,
adica de la portul de iesire a lui A catre portul de intrare a lui B;
- presupunem ca bufferul portului de input B este ocupat;
- pachetul trebuie retinut in bufferul portului de iesire A,
pana cand B este eliberat;
- aceasta situatie pune presiune pe switch-urile care preced pe A;
- se poate folosi link-level control mechanism prin care switch-ul
receiver trimite feedback catre switch-ul sender, prin care anunta ca
spatiul din bufferul de intrare este limitat; acest mesaj se propaga
inapoi in retea pentru ca sursa nu mai trimita pachete se evita
congestia retelei;
Totusi, acest feedback poate fi prea incet, iar reteaua deja
congestionata!
Se poate folosi end-to-end flow control prin care se trimite un mesaj
direct nodului sursa; acesta poate adapta numarul de pachete pentru
a evita posibile buffer-overflows.

Modele de sisteme paralele


1. Modele de masina
2. Modele de arhitectura
3. Modele computationale
4. Modele de programare
1. Modele de masina:
- cel mai coborat nivel de abstractizare;
- descrierea hardware-ului si a sistemului de operare;
- limbaj de tip asembler se bazeaza pe acest tip de modele;
2. Modele de arhitectura:
- descriu retelele de interconectare, organizarea memoriei,
procesare sincrona sau asincrona, si executia instructiunilor in
sisteme de tip SIMD sau MIMD;
3. Modele computationale:
- urmatorul nivel de abstractizare;
- ne indica modul de executie al unui algoritm pe resursele
sistemului; evalueaza algoritmii de calcul si performanta lor
teoretica.

Modele de sisteme paralele


4. Modele de programare
- descriu sistemele paralele in functie de limbajul de programare
Criterii care diferentiaza modelele de programare:
- nivelul de paralelism exploatat in executia paralela (la nivel de
instructiune, la nivel de procedura, bucle paralele);
- specificarea implicita sau explicita (user-defined) a paralelismului;
- modul in care sunt specificate parti ale programului paralel;
- modul de executie a unitatilor paralele (SIMD sau SPMD single
program multiple data, subcategorie a MIMD);
- modalitatile de comunicare intre unitatile de calcul (comunicare
explicita sau variabile de tip shared)
- mecanisme de sincronizare pentru a organiza comunicarea intre
unitatile paralele;

Paralelizarea programelor
Transformarea unui cod serial intr-un program paralel:
1. Partajarea in sarcini (tasks):
- tasks = cele mai mici unitati de paralelism;
- se pot identifica la diferite nivele de executie:
- instruction level;
- data paralelism;
- functional paralelism;
- o sarcina poate implica accesul memoriei partajate sau poate
executa o operatie de tip message-passing;
- descompunerea in sarcini se poate face la inceputul
programului sau sarcinilor pot fi generate dinamic in timpul
executiei programului;
- nr de sarcini maximal reprezinta gradul de paralelism;
- scopul este sa avem suficiente sarcini pentru a mentine
ocupate toate miezurile; insa, fiecare sarcina trebuie sa
contina suficiente operatii pentru ca timpul de executie a unei
sarcini sa nu fie depasit de timpul de scheduling si mapping.

Paralelizarea programelor
Transformarea unui cod serial intr-un program paralel:
2. Asignarea sarcinilor catre procese / threaduri:
- un proces / thread reprezinta o secventa de sarcini executata
de un procesor (core);
- se are in vedere load balancing : fiecare proces / thread ar
trebui sa aibe aceeasi cantitate de operatii de efectuat;
- dar, trebuie sa se aiba in vedere si numarul de comunicatii si
nr. de accesari de memorie; spre exemplu cand se foloseste
memoria partajata este utila asignarea a 2 sarcini care lucreaza
pe acelasi set de date sa fie asignate aceluiasi thread;
- asignarea sarcinilor catre procese / thread-ri se numeste
scheduling;
3. Maparea proceselor / threadu-urilor pe procesoare / miezuri
fizice:
- in general se ataseaza un proces unui procesor /core;
- daca sunt mai multe procese decat nr. de miezuri se face o
mapare de catre sistemul de operare, dar aceasta poate fi
ajustata din cod;

Paralelizarea programelor
Partitionare, Scheduling, Mapping

Nivele de paralelism
Paralelism la nivel de instructiune:
- instructiunile multiple pot fi efectuate in paralel daca sunt
independente;
- pot exista insa dependinte intre date (de la I1 la I2):
- flow dependency: I1 calculeaza o caloare intr-un registru sau
variabila, care apoi este folosita de I2 ca operand;
- anti-dependency: I1 foloseste o variabila ca operand, care
este folosita apoi de I2 pentru a stoca rezultatul calculului;
- output dependency: I1 si I2 folosesc acelasi registru pentru
a stoca rezultatul unui calcul;

Observatie: I1 si I2 nu pot fi executate in paralel sau in ordine


inversa!

Nivele de paralelism
Paralelism la nivel de instructiune:
- Graful dependintelor: flow dependency, anti-dependency, output
dependency;
- I1 I2 ; I1 I4; (a) : R1 folosit ca operand;
- I1 I3 ; (o) R1 este output comun;
- I2 ; (a) cu ea insasi cauzata de R2;
- I2 I3 ; (a) cauzata de R1;

Nivele de paralelism
Paralelism la nivel de date:
- elementele de date sunt distribuite uniform intre procesoare;
- in special folosit in domeniul calculelor stiintifice;
- limbaje de programare secventiale sunt modificate in limbaje de
programare de tip data-parallel;
- Ex: asignarea array-urilor in Fortran 90/95, data-parallel C, PC++,
DINO, High-Performance Fortran
Loop paralelism:
- daca instructiunile dintr-o bucla for nu depind una de cealalta, se
pot executa in paralel;
- secvential loop parallel loop;
Paralelism functional:
- multe programe secventiale contin parti de cod care sunt
independente si pot fi rulate paralel (ex. : bucle, apeluri de functii);

Nivele de paralelism

Paralelism functional:
- Planul de executie:
- static : este determinat la compilare sau la startul programului;
- se face o estimare a timpilor de executie a diferitelor
sarcini;
- dinamic : determinca asignarea sarcinilor pe procesoare la
momentul executiei;
- se foloseste conceptul de task pool: sunt stocate
sarcinile pregatite spre a fi executate;

Paralelism implicit si explicit


Tipuri de paralelism - clasificate dupa modul in care este
specificat paralelismul in cod:
- implicit : codul sursa nu prezinta instructiuni suplimentare;
compilatorul genereaza un program paralel.
- explicit : efort mai mare pentru programator, compilatorul este mai
simplu.
Paralelism implicit:
- effort minim din partea programatorului, care elaboreaza un cod
secvential;
- doua abordari:
- paralelizare automata (compilatoare care paralelizeaza)
- compilatorul analizeaza dependintele;
- sunt distribuite sarcinile pe procesoare, avand in vedere
o incarcare cat mai uniforma;
- in cazul sistemelor cu memorie distribuita se are in vedere
limitarea comunicarii;
- dezavantaje: codurile care se bazeaza pe pointeri
greu de paralelizat, timpul alocat buclelor cu limite
necunoscute greu de apreciat.

Paralelism implicit si explicit


Paralelism implicit:
- doua abordari:
- limbaje de programare functionale
- reprezinta un stil de programare care se bazeaza pe
evaluarea functiilor matematice fara efecte secundare
(side effects)
- astfel, o functie cu aceeasi parametrii de intrare va returna
aceeasi valoare (nu se modifac varibile globale, definite
static);
- se pot folosi functii de ordin superior;
- exemplu de limbaj de programare: Haskell
- potential de paralelizare: variabilele de intrare pot fi
evaluate in paralel (nu exista efecte secundare);
Paralelism explicit cu distributie explicita:
- o clasa intermediara de modele de programare paralela;
- presupune reprezentarea explicita a paralelismului in program,
dar nu si distribuirea explicita pe procese;
- ex. : bucle for paralel
- OpenMP (open multi processing);
- High Performance Fortran (HPF);

Paralelism explicit
Motive (patterns) de programare paralela explicit:
- creearea proceselor si threadurilor;
- conceptul de fork-join;
- parbegin parend;
- SIMD / SPMD;
- schema Master-Slave (Master-Worker)
- Client-Server;
- Pipelining;
- Task pools;
- Producer-Consumer;
Creearea proceselor / thread-urilor:
- se poate face static sau dinamic;
- static: se creeaza un numarfix de thread-uri la startul
programului;
- dinamic: se porneste cu un singur thread si apoi se genereaza
( respectiv, finalizeaza) alte thread-uri

Paralelism explicit
Fork-Join:
- concept simplu de creeare a thread-urilor / proceselor
(initial folosit pentru procese, apoi adaptat pentru thread-uri);
- un thread existent T creeaza un numar de thread-uri copil:
T1, T2, . , Tm
- fiecare thread va executa in paralel cate o parte a programului,
alaturi de T;
- threadul T asteapta terminarea tuturor thrd. T1, , Tm si apoi
executa procedura join;
- folosit in: - OpenMP (open multi processing)
- MPI-2 (comenzile spawn, exit)
Parbegin-parend (cobegin-coend):
- specifica zona din program care se executa paralel;
- similar fork-join, se creeaza o secventa de thread-uri;
- instructiunile care urmeaza blocului parbegin-parend se vor
executa dupa terminarea tuturor thread-urilor;
- implementat in OpenMP;

Paralelism explicit
SIMD / SPMD :
- SIMD : - se foloseste un numar fixat de thread-uri;
- se aplica acelasi program pe seturi de date diferite;
- data paralelism in adevaratul sens.
- se aplica pe seturi mari de date, de ex aplicatii grafice;
- SPMD : - thread-urile lucreaza asincron;
- aceasta situatie poate fi cauza de viteza diferita a
procesoarelor, intarzieri la comunicare etc;
- sincronizarea se face explicit, din cod;
- Ex. : MPI
Schema Master-Worker (Master-Slave) :
- nodul master e responsabil de coordonare
(initializari, timing, output); controleaza
executia programului;
- nodurile de tip worker pot si creeate
static sau dinamic;

Paralelism explicit
Schema Server-Client :
- se genereaza thread-uri multiple care trimit request-uri catre
server, apoi efectueaza calcule pe datele obtinute;

Pipelining :
- descrie o forma speciala de coordonare a diferitelor thread-uri, in
care elementele sunt forwardate de la un thread la altul pentru
diferiti pasi de procesare;
- desi fiecare thread are dependinte intre elemente, thread-urile
multiple organizate in aceasta maniera pot rula paralel;

Paralelism explicit
Task pools:
- task pool : o structura de date in care sarcinile sunt stocate si
din care pot fi extrase pentru executie;
- se foloseste un numar fixat de thread-uri, care sunt finalizate dupa
ce toate sarcinile au fost epuizate;
- in timpul procesarii unei sarcini, un thread poate genera noi sarcini,
care pot fi inserate in task pool;
- accesul la task pool trebuie sincronizat pentru a evita accesul
multiplu al unor thread-uri pe o sarcina;
- acest concept este foarte folositor in contextul unor aplicatii
adaptative, cu profil neregulat;
- structura de date de tip task pool poate fi pusa la dispozitie de
mediul de programare (ex. interfata Executor Java) sau poate fi
inclus in codul paralel;
- de evitat sarcini de dimensiuni
foarte mici;

Paralelism explicit
Producer-Consumer:
- exista thread-uri de tip producer si de tip consumer;
- producer threads produc date;
- consumer threads folosesc datele ca input;
- pentru transferul datelelor de la producer la consumer threads
se foloseste o structura de date comuna un buffer care poate fi
accesat de ambele tipuri de thread-uri;
- Observatii: un thread producer poate scrie date daca bufferul nu
este plin, iar un thread consumer poate accesa date doar daca
bufferul nu este gol se utilizeaza sincronizarea thread-urilor.

Schimbul de informatie
- Este necesar schimbul de informatii intre diferitele procesoare;
- Depinde foarte mult de tipul de memorie partajata / distribuita;
Variabile de tip shared :
- fiecare thread poate accesa o zona de memorie comuna, iar datele
sunt sotcate in variabile de tip shared;
- variabilele care nu sunt accesibile tuturor thread-urilor sunt
variabile private;
- in cod se poate spefica tipul variabilelor, folosind termenii
shared/private; se pot declara reguli prin care variabilele globale
sunt de tup shared, in timp ce cele locale (din functii) sunt private;
- in cazul variabilelor de tip shared este nevoie de sincronizare,
pentru situatia in care aceeasi variabila este accesata de mai multe
thread-uri in acelasi timp se foloseste secventializarea accesului
(sequentialization)
- Observatie: - se poate ajunge la race condition situatia in care
thread-uri multiple citesc/scriu in aceeasi variabila de
tip shared;
- pentru a evita aceasta situatie se foloseste
un lock mechanism

Operatii de comunicare
- Intr-un sistem cu memorie distribuita schimbul de infomatii intre
procesoare se face prin operatii de comunicare ;
- Schimbul de date este asigurat de transferul de mesaje intre
procesoare modele de programare de tip messaje-passing ;
- Pentru a trimite un mesaj se fololseste o pereche de operatii de tip
send / receive;
- O operatie de tip send trimite un bloc de date de la zona de
memorie locala catre un alt procesor; o operatie de tip receive
primeste un bloc de date de la un alt procesor si il scrie in memoria
locala;
- Acest tip de comunicare se numeste point-to-point
communication;
- In plus fata de aceasta se mai pot folosi operatii de comunicare
globala (global communication operations) in care sunt implicate
mai multe procesoare.

Un set de operatii de comunicare


- Vom considera un set de operatii de comunicare intr-un sistem de
p procesoare identice;
Single transfer:
- doua procesoare implicate;
- primul procesor trimite mesajul intr-un buffer send, impreuna cu
rangul procesorului (procesului) care urmeaza sa primeasca
mesajul;
- procesorul care primeste mesajul executa o operatie de receive
prin care mesajul este copiat intr-un buffer receive;
- Observatii: - daca perechea send / receive nu este
corespunzatoare se ajunge la deadlock!
- daca transmisiile sunt regulate sunt mai eficiente si
mai usor de implementat operatiile de comunicare
globale;

Operatii de comunicare
Single broadcast:
- un singur procesor Pi trimite un bloc de date catre mai multe
procesoare; Pi se numeste procesor root;

- inaintea executiei operatiei de broadcast, mesajul este stocat in


memoria locala a procesorului root, iar dupa executie mesajul va fi
stocal in memoria locala a fiecarui procesor;
- pentru a efectua operatie, fiecare procesor trebuie execute o
operatie de tip broad cast in care se specifica procesorul root;

Operatii de comunicare
Single accumulation:
- fiecare procesor pune la dispozitie un bloc de date de acelasi tip si
aceeasi marime;

- datele sunt adunate la procesorul root (P1);


- pentru a efectua operatia de single accumulation fiecare nod
cheama operatia specificand nodul root;

Operatii de comunicare
Gather:
- fiecare procesor pune la dispozitie un bloc de date ;

- procesorul root (P1) va primi p mesaje ;


- nu are loc operatia de reducere (operatie comutativa, asociativa)
ca in cazul single-accumulation;
- pentru a efectua operatia de single accumulation fiecare nod
cheama operatia specificand nodul root; in plus, acesta specifica un
buffer suficient de mare pentru a primi toate blocurile;

Operatii de comunicare
Scatter:
- un anume procesor (root) pune la dispozitie cate un bloc de date
pentru fiecare procesor ;

- pentru a efectua operatia de scatter fiecare nod cheama operatia


specificand nodul root si un buffer unde urmeaza sa fie stocat blocul
de date;
- procesorul root specifica, de asemenea, bufferul send.

Operatii de comunicare
Multi-broadcast:
- operatia este echivalenta cu o serie de operatii single-broadcast
efectuate de fiecare procesor;

- nu exista un procesor root!


- pentru a efectua operatia de multi-broadcast, fiecare procesor
cheama operatia si specifica un buffer send, dar si un buffer de
receive;
- dupa incheierea operatiei, fiecare procesor va avea blocurile de
date in succesiunea data de rangul procesorului;
- operatia este utila pentru a colecta datele calculate pe toate
procesoarele;

Operatii de comunicare
Multi-accumulation:
- fiecare procesor executa o operatie de tip single-accumulation ;

- fiecare procesor pune la dispozitie un alt bloc;


- datele bloc pentru un anume receiver sunt combinate printr-o
operatie de reducere;
- nu exista procesor root;
- fiecare procesor cheama operatia, specifica un buffer send, un
buffer receive si o operatie de reducere;
- in bufferul de send fiecare procesor stocheaza separat blocurile de
date pentru toate celelalte procesoare;

Operatii de comunicare
Total exchange:
- fiecare procesor pune la dispozitia oricarui alt procesor un bloc
posibil diferit ;

- fiecare procesor executa o operatie de tip scatter;


- spre deosebire de multi-broadcast, fiecare receiver primeste
blocuri de date diferite de la acelasi sender;

Reprezentarea operatiilor de comunicare


sub forma de arbore
Single-broadcast:

Single-accumulation:

Single broadcast / accumulation sunt descrise de acelasi arbore


se numesc operatii duale;
Similar, operatii duale sunt si scatter / gather.

Ierarhia operatiilor de comunicare


- Pornind de la cea mai generala operatie de comunicare (total
exchange), celelalte operatii rezulta prin specializare;
- Total exchange este cel mai general tip de comunicare, intrucat
fiecare procesor transmite mesaje diferite catre oricare alt procesor;
- Multi-broadcast e un caz particular de total exchange in care
fiecare procesor trimite acelsi mesaj catre toate celelalte;
- Multi-accumulation e operatia duala pentru multi-broadcast;
- Gather este un caz particular de multi-broadcast, care rezulta din
faptul ca se considera un singur receiver;
- Scatter este operatia duala a operatiei gather;
- Single braodcast este un caz particular de Scatter, in care
procesorul root trimite acelsai mesaj catre toate celelalte
procesoare;
- Single accumulation este operatia duala pentru single broadcast;
- Single transfer este un caz particular de single broadcast pentur
care doar ruta de la procesorul root catre un altul leste relevanta; de
asemenea este un caz particular de single accumulation, in care
root-ul foloseste o operatie speciala de reducere.

Ierarhia operatiilor de comunicare

Operatii de comunicare - exemple


Calculul paralel al produselor scalare

Calculul paralel al unei combinatii liniare

Operatii de comunicare - exemple


Calculul paralel al unei combinatii liniare cu rezultat replicat

Calculul paralel al unei combinatii liniare distributie bloc

Programare de tip Message-Passsing


- Modele de programare care se bazeaza pe message-passing
sunt implementate pe arhitecturi paralele cu memorie distribuita.
- Nu exista memorie comuna.
- Pentru a transfera date din memoria locala a unui procesor A in
memoria locala a unui procesor B, procesorul A va trimite un
mesaj continand datele, iar procesorul B va primi datele intr-un
buffer.
- Pentru a asigura portabilitatea programelor, nu se fac
presupuneri asupra topologiei retelei de interconectare.
- Un program care foloseste message-passing presupune rularea
unui set de procese, in care fiecare proces contine propriul set de
date.
- De obicei fiecare proces este executat pe cate un procesor/miez.
- In principiu, fiecare proces poate executa un program diferit
(MPMD), intre care se schimba date prin operatii de tip
send/receive.
- In practica, fiecare proces va executa acelasi program (SPMD),
flexibilitatea fiind asigurata de asignarea unui rang (rank) pentru
fiecare proces, care va efectua o parte a programului.

Programare de tip Message-Passsing

- Procesele pot schimba date intre ele prin operatii de comunicare.


- Pentru aceasta, sunt apelate functii de comunicare (de tip pointto-point sau broadcast), continute in librarii
(communication library). Ex. : MPI_Send() ; MPI_Recv() ;
- Librariile de comunicare sunt in general portabile (exista si librarii
care sunt specifice hardware); ele definesc sintaxa functiilor de
comunicare si sunt suportate de o gama larga de arhitecturi
paralele;
- Cea mai des intalnita implementare este MPI (Message-Passing
Interface); o alta implementare folosita este PVM (Paralel Virtual
Machine).
In continuare se va face o prezentare a librariei MPI; se vor
descrie operatiile de comunicare specifice de tip point-to-point si
cele de tip global

Introducere in MPI
- MPI defineste sintaxa pentru operatii de comunicare in limbajele
de operare C, C++, Fortran-77, Fortran-95;
- Documentatia oficiala : www.mpi-forum.org
- 2 versiuni de MPI:
- MPI-1 : - operatii de comunicare standard;
- model static de generare / manipulare a proceselor;
- MPI-2 : - suport pentru management dinamic al proceselor;
- comunicare uni-laterala (one-sided communication):
accesarea unei zone de memorie remote fara a
implica celalalt proces; Ex. : MPI_Put() ; MPI_Get();
- paralel I/O;
- Librarii MPI:
- MPICH : www-unix.mcs.anl.gov/mpi/mpich2
- LAM/MPI : www.lam-mpi.org
- OpenMPI : www.open-mpi.org

Introducere in MPI
- Rularea unui program MPI se face cu linia de comanda:
mpiexec -n 4 programname programarguments
sau
mpirun -np 4 programname programarguments
- Tipuri de operatii MPI (operatii de comunicare):
- Blocking operation: o operatie de comunicare este de tip
blocking daca resursele (buffere) nu pot si reutilizate
inainte ca operatia initiata sa fie finalizata;
- Non-blocking operation: operatia de comunicare este
initiata; nu se asteapta finalizarea ei, inainte ca alta
operatie sa fie initiata;
Termenii de blocking / non-blocking reflecta comportamentul
operatiilor din punctul de vedere local al procesului care le
executa.

Introducere in MPI
- Se mai poate deosebi intre comunicare sincrona / asincrona:
- synchronous communication: operatiile de send/receive
sunt sincronizate; dupa finalizarea operatiei de
comunicare bufferele send / receive pot fi reutilizate;
- asynchronous communication: nu exista o coordonare intre
procesele send / receive;
Operatii de comunicare MPI point-to-point:
- Toate operatiile de comunicare se desfasoara folosind un
communicator;
- Un communicator este set de procese care schimba mesaje intre
ele;
- Vom considera pentru inceput communicator-ul MPI default:
MPI_COMM_WORLD care contine toate procesele.

Operatii de comunicare point-to-point


- Modalitatea elementare de a schimba mesaje este cea de tip
point-to-point;
- Un proces executa o operatie Send, iar celalalt o operatie de tip
Receive;
- Operatia de tip Send:
int MPI_Send(void *smessage,
int count,
MPI_Datatype datatype,
int dest,
int tag,
MPI_Comm comm)
- smessage: specifica un buffer care contine elementele de date
care urmeaza sa fie transmise;
- count: numarul de elemente care urmeaza sa fie transmise;

Operatii de comunicare point-to-point


int MPI_Send(void *smessage,
int count,
MPI_Datatype datatype,
int dest,
int tag,
MPI_Comm comm)
- datatype: specifica tipul de date din buffer; toate datele au
acelasi tip;
- dest: specifica rangul procesului care urmeaza sa primeasca
datele;
- tag: o eticheta care permite destinatarului sa distinga intre
diferitele mesaje de la aceesi sursa;
- comm: specifica communicator-ul folosit in comunicare;
- Instructiunea MPI_Send este de tip blocking;
- Marimea mesajului poate fi calculata inmultind numarul count cu
numarul de bytes corespunzator tipului datatype.
- Tag-ul : un numar intreg 0 32737

Operatii de comunicare point-to-point


int MPI_Recv(void *rmessage,
int count,
MPI_Datatype datatype,
int source,
int tag,
MPI_Comm comm,
MPI_Status *status).
- rmessage: specifica bufferul in care se primesc datele;
- count: numarul maxim de elemente care urmeaza sa fie primite;
- datatype: tipul datelor care vor fi primite;
- source: specifica rangul procesului care trimite mesajul;
- tag: eticheta pe care trebuie s-o aibe mesajul pentru a fi primit;
- comm: specifica communicator-ul folosit in comunicare;
- status: este o structura care specifica informatii despre mesaj,
dupa incheierea operatiei de comunicare (id_procesor send, cod
de eroare);

Tipuri de date MPI

- Nu exista corespondent C pentru MPI_PACKED

Tipuri de date MPI


- Alte valori predefinite des uzitate:
- source = MPI_ANY_SOURCE
* un proces poate primi un mesaj de la orice rank;
- tag = MPI_ANY_TAG
* un proces poate primi un mesaj cu orice tag;
- Dupa finalizarea unei operatii de MPI_Recv() , structura status
contine:
* status.MPI_SOURCE : rangul procesului sursa;
* status.MPI_TAG : specifica tag-ul mesajului trimis;
* status.MPI_ERROR : contine un cod de eroare;
-Structura status contine informatii despre marimea mesajului
* se obtine apeland functia:
int MPI_Get_count (MPI_Status *status,
MPI_Datatype datatype,
int *count_ptr),
* functia returneaza numarul de elemente primite in count_ptr

MPI Send / Receive


- O procedura de transfer a unui mesaj MPI se face intern in pasii
urmatori:
* datele trimise sunt copiate din bufferul send intr-un buffer al
sistemului generat la runtime; mesajului I se aduga un
header care contine: informatii despre procesul care
trimite, procesul care primeste, tag-ul si communicator-ul
* mesajul este apoi trimis prin reteaua de inter-conectare;
* datele sunt copiate din bufferul sistemului in bufferul specificat
de MPI_Recv();
- MPI_Send, MPI_Recv sunt operatii de tip blocking, asincrone :
* Operatia de tip receive poate fi pornita inaintea operatiei
MPI_Send si invers;
* Fiecare din operatii va bloca derularea programului in
procesul in care se executa pana cand operatia pereche este
finalizata.

Exemplu de cod MPI

Exemplu de cod MPI


Observatii:
- orice program MPI trebuie sa includa header-ul <mpi.h>
- functia MPI_Init() trebuie chemata inaintea oricarei alte functii
MPI;
- MPI_Comm_rank(MPI_COMM_WORLD, &my rank) returneaza
rangul procesului din communicatorul folosit
(aici MPI_COMM_WORLD)
- MPI_Comm_size(MPI_COMM_WORLD, &p) returneaza in
variabila p numarul de procese;
- procesul (cu rangul) 0 executa o operatie de MPI_Send();
- procesul 1 executa o operatie de MPI_Recv();
- MPI_Finalize() este ultima operatie in orice program MPI

Ordinea operatiilor in MPI


In MPI mesajele sunt trimise in ordinea in care este specificata in
cod. Daca avem 2 operatii de tip MPI_Send succesive intr-un
proces si 2 operatii MPI_Recv in alt proces, ordinea transmiterii
mesajelor se va pastra.
In schimb, daca avem mai multe procese implicate, se poate
intampla ca ordinea sa nu se pastreze. Exemplu:

Situatii de deadlock in operatii de comunicare MPI


Operatiile Send / Receive trebuie folosite cu grija intrucat pot
conduce la aparitia unor situatii de deadlock:

Observatie:
- fiecare proces executa mai intai o operatie de tip Receive,
astfel incat fiecare va astepta date indefinit;

Situatii de deadlock in operatii de comunicare MPI


In functie de implementare, se pot folosi buffere de sistem, iar
datele stocate pot fi preluate ulterior.

Observatie:
- operatiile Send sunt de tip blocking!
- in exemplul de mai sus nu apare situatia de deadlock daca sunt
utlizate bufferele sistemului ;

Situatii de deadlock in operatii de comunicare MPI


Un fragment de cod care nu produce situatii de deadlock, chiar
daca nu sunt folosite bufferele sistemului:
(Secure implementation)

- O implementare secure se poate obtine daca rang-urile pare


executa Send/Receive, iar cele impare Receive/Send:

Situatii de deadlock in operatii de comunicare MPI


Implementarea de tip par/impar evita situatiile de deadlock si in
conditiile in care exista un numar impar de procese:

In aceasta situatie operatia de MPI_Recv() a procesului 2 va fi


inatrziata, dar nu apare deadlock.

Operatii de tip MPI_Sendrecv


- In multe situatii in aceeasi pereche de procese se trimit si
primesc date.
- Se foloseste rutina MPI_Sendrecv():
int MPI_Sendrecv (void *sendbuf,
int sendcount,
MPI Datatype sendtype,
int dest,
int sendtag,
void *recvbuf,
int recvcount,
MPI_Datatype recvtype,
int source,
int recvtag,
MPI_Comm comm,
MPI_Status *status)
Programatorul nu se mai ingrijeste de ordinea operatiilor Send /
Receive; bufferele sendbuf si recvbuf trebuie sa fie distincte !

O varianta operatiei MPI_Sendrecv


- Cand bufferele sendbuf si recvbuf sunt identice se poate folosi
functia MPI_Sendrecv_replace
int MPI_Sendrecv_replace (void *buffer,
int count,
MPI_Datatype type,
int dest,
int sendtag,
int source,
int recvtag,
MPI_Comm comm,
MPI_Status *status)
Observatie:
- datele au acelasi tip;

Operatii de comunicare de tip non-blocking


- Folosirea operatiilor de tip blocking poate conduce la timpi de
asteptare mari;
- De exemplu : un proces care executa o operatie de tip Send
blocking va astepta pana cand bufferul send este copiat in bufferul
sistemului sau in cel de tip receive; se astepata ca mesajul sa
ajunga la destinatar.
- este preferabil adesea ca timpul de asteptare sa fie folosit la
efectuarea unor calcule operatii de comunicare de tip nonblocking; astfel se pot suprapune operatiile de calcul cu cele de
comunicare.
- O operatie de tip non-blocking initiaza o operatie de tip Send si
returneaza imediat controlul procesului care trimite date; Bufferul
Send nu poate fi reutilizat in conditii de siguranta intrucat
transmisia mesajului poate fi inca in progres; Este necesara o alta
operatie pentru a confirma ulterior completarea transmisiei.

Operatii de comunicare de tip non-blocking


- Operatia non-blocking de tip Send:
int MPI_Isend (void *buffer,
int count,
MPI_Datatype type,
int dest,
int tag,
MPI_Comm comm,
MPI_Request *request)
Observatii:
- functia returneaza imediat controlul procesului;
- este demarat procesul de trimitere a datelor;
- exista o variabila suplimentara, request, care poate specifica
informatii despre statusul operatiei de comunicare;

Operatii de comunicare de tip non-blocking


- Operatia non-blocking de tip Receive:
int MPI_Irecv (void *buffer,
int count,
MPI Datatype type,
int source,
int tag,
MPI_Comm comm,
MPI_Request *request)
Inaintea refolosirii bufferului de o alta operatie de comunicare, se
testeaza finalizarea primei operatii de comunicare: se foloseste
obiectul request
int MPI_Test (MPI Request *request,
int *flag,
MPI Status *status)

Operatii de comunicare de tip non-blocking


int MPI_Test (MPI Request *request,
int *flag,
MPI Status *status)
Observatii :
- flag=1 (true) operatia este finalizata
- status : idem MPI_Recv() ; nedefinit daca operatia nu este
finalizata;
- daca request se refera la o operatie de tip Send,
status.MPI_ERROR nedefinita
Procesul care apeleaza functia
int MPI_Wait (MPI_Request *request, MPI_Status *status)
este blocat pana cand operatia identificata prin request este
finalizata. Deci, un buffer poate fi reutilizat dupa ce operatia
MPI_Wait returneaza.
Se pot folosi in pereche MPI_Send / MPI_IRecv si invers.

Operatii de comunicare pe un inel


- Consideram p = 4 procese aranjate pe un inel; fiecare proces
produce un set de date xi, care trebuie trimis la toate celelalte
procese;
Implementare cu operatii de comunicare de tip blocking:

Operatii de comunicare pe un inel


Implementare cu operatii de comunicare de tip blocking:
* nu apare deadlock doar daca se folosesc bufferele sistemului;

Operatii de comunicare pe un inel


Implementare cu operatii de comunicare de tip non-blocking:
* comunicarea se suprapune cu operatii de calcul (send_offset);

Moduri de comunicare
(communication modes)
- MPI pune la dispozitie diferite moduri de comunicare pentru
proceduri de tipul blocking / non-blocking;
- Aceste moduri de comunicare determina coordonarea intre intre
instructiunile de tip send / receive;
Tipuri de moduri de comunicare:
- modul standard (standard mode);
- modul sincron (synchronous mode);
- modul buffered (buffered mode);

Moduri de comunicare
(communication modes)
Modul standard:
- este modul de comunicare descris pana in prezent;
- mediul MPI decide daca mesajele trimise sunt stocate intr-un
buffer al sistemului sau nu;
- mediul MPI poate decide, spre exemplu, de a stoca in buffere
mesajele mai mici de o marime predefinita, in timp ce restul
mesajelor mai mari nu vor fi stocate;
- pentru programator acest lucru inseamna ca nu se poate baza pe
stocarea mesajelor in buffere, asa incat programul trebuie scris
fara a lua in calcul posibilitatea de buffering;

Moduri de comunicare
(communication modes)
Modul sincron:
- in modul standard, o operatie de tip send poate fi incheiata chiar
daca operatia corespunzatoare de tip receive nu a fost initiata ( in
situatia in care se folosesc buffere);
- in modul sincron operatiile send / receive sunt sincronizate;
- instructiunea de tip send in mod blocking este MPI_Ssend() ,
care are aceeasi parametrii ca functia MPI_Send();
- instructiunea de tip send in mod non- blocking este MPI_Issend() ,
care are aceeasi parametrii ca functia MPI_Isend();
- in cazul instructiunii non-blocking, nu exista sincronizare la nivelul
instructiunilor MPI_Issend() si MPI_Irecv(); procesele se desfasoara
ca in cazul MPI_Isend() si MPI_Irecv() (instructiuni non-blocking);
Sincronizarea se face la apelul functiei MPI_Wait();

Moduri de comunicare
(communication modes)
Modul de tip buffered:
- in modul buffered, controlul este returnat procesului care executa
operatia de tip send imediat, chiar daca operatia de tip receive nu a
fost initiata;
- bufferul send poate fi reutilizat imediat, chiar daca se foloseste o
operatie de tip non-blocking;
- o operatie de tip blocking se executa cu MPI_Bsend(), care are
aceeasi parametrii ca si MPI_Send();
- operatatie de tip non-blocking se executa cu MPI_Ibsend(), care
are aceeasi parametrii ca si MPI_Isend();
- bufferul trebuie pus la dispozitie de programator; marimea
bufferului trebuie sa fie suficient de mare;
- bufferul este pus la dispozitie prin:
int_MPI_Buffer_attach (void *buffer, int buffersize)
in care buffersize este marimea in bytes;
- bufferul se poate
int_MPI_Buffer_detach (void *buffer, int buffersize)
- se poate atasa un singur buffer unui proces!

Operatii de comunicare colective


(collective communication operations)
O operatie de comunicare se numeste colectiva / globala daca un
sub-set sau toate procesele sunt implicate.
Vom discuta operatiile de comunicare globala suportate in MPI:

Operatii de comunicare colective


Operatia de tip Broadcast:
- un anumit proces dintr-un grup trimite un bloc de date catre toate
procesele din acel grup;
int MPI_Bcast (void *message,
int count,
MPI_Datatype type,
int root,
MPI_Comm comm)
- root reprezinta procesul care trimite date;
- message bufferul send (procesul root) / receive (celelalte
procese)
- fiecare proces cheama operatia MPI_Bcast, specificand acelasi
root si acelasi comunicator;
- datele trimise prin MPI_Bcast() nu pot fi receptionate folosind
MPI_Recv();

Operatii de comunicare colective


Operatia de tip Broadcast:
- nu se folosesc tag-uri, ca in operatiile de tip point-to-point si deci
procesele care primesc nu pot deosebi mesaje in baza tag-urilor;
- mediul MPI asigura faptul ca
mesajele trimise prin
MPI_Broadcast ajung in
aceeasi ordine in care
sunt trimise;
- Exemplu:
Procesul 0 trimite x, y
prin doua operatii succesive
de broadcast;

Operatii de comunicare colective


Operatia de tip Broadcast:
- in exemplul precedent, cele doua blocuri de date sunt stocate
diferit in procesele 1 si 2;
- desi nu exista sincronizare explicita, ordinea operatiilor de tip
broadcast este mentinuta ca si cum ar exista sincronizare intre
procese;
- operatiile de comunicare colective sunt de tip blocking! Nu exista
versiuni de tipul non-blocking, ca in cazul operatiilor de tip point-topoint;
- operatiile de comunicare colective se folosesc in modul standard
(daca exista buffere de sistem suficient de mari, controlul este
returnat proceselor);

Operatii de comunicare colective


Operatia de tip Reducere (reduction operation):
- O operatie de acumulare se mai numeste si operatie de reducere
globala;
- Fiecare proces pune la dispozitie un bloc de date, care sunt
combinate cu o operatie binara de reducere; rezultatul acumulat
este colectat la procesul root;
int MPI_Reduce (void *sendbuf,
void *recvbuf,
int count,
MPI_Datatype type,
MPI_Op op,
int root,
MPI_Comm comm)

Operatii de comunicare colective


Operatia de tip Reducere (reduction operation):
- sendbuf : un buffer de tip send in care fiecare proces pune la
dispozitie blocul de date;
- recvbuf : specifica bufferul pus la dispozitie de procesul root;
- op : specifica o operatie asociativa;
- MPI pune la dispozitie un numar de operatii, care sunt si
comutative;

Operatii de comunicare colective


Operatia de tip Reducere (reduction operation):
- operatiile predefinite de tip MPI_MAXLOC sau MPI_MINLOC se
pot folosi pentru a extrage maximul / minimul global si returneaza si
indexul corespunzator valorii (rangul procesului);
- operatia MPI_MAXLOC :

- operatia MPI_MINLOC :

Operatii de comunicare colective


Operatia de tip Reducere (reduction operation):
- ambele operatii MPI_MAXLOC, MPI_MINLOC actioneaza asupra
unei perechi (valoare,index);
- MPI pune la dispozitie astfel de tipuri de date:

- sendbuf / recvbuf au aceeasi marime; in cazul procesului root


trebuie sa indice zone de memorie diferite;
- se poate folosi sendbuf = MPI_IN_PLACE datele sunt preluate
din recvbuf si, dupa efectuarea operatiiei de reducere, valoare
rezultata este inlocuita;

Operatii de comunicare colective


Exemplu:
- operatie de reducere globala folosind MPI_MAXLOC;
- fiecare proces are un array de 30 double;
- valorile maxime si indicii corespunzatori sunt stocati in aout[] , ind[]

Operatii de comunicare colective


In MPI se pot defini operatii de reducere folosind urmatoarea functie:
int MPI_Op_create (MPI_User_function *function,
int commute,
MPI_Op *op)
- parametrul function trebuie sa defineasca urmatoarele 4 variabile:
void *in, void *out, int *len, MPI_Datatype *type.
- functia trebuie sa fie asociativa;
- parametrul commute specifica daca functia este comutativa
(commute=1) sau nu (commute=0);
- functia MPI_Op_create returneaza o operatie de reducere op care
poate fi folosita ca parametru in MPI_Reduce();

Operatii de comunicare colective


Exemplu:
- calcul paralel pe p procesoare al produsului scalar intre doi vectori,
x si y, de lungime m;
- ambii vectori sunt impartiti in blocuri: local_m = m / p;
- fiecare proces stocheaza blocuri din x /y in local_x / local_y;

- se efectueaza produs scalar pe fiecare procesor, apoi MPI_SUM

Operatii de comunicare colective


Operatia Gather:
- fiecare procesor pune la dispozitie un bloc, care apoi este colectat
la procesorul root;
- spre deosebire de MPI_Reduce() nu se efectueaza operatia de
reducere;
int MPI Gather(void *sendbuf,
int sendcount,
MPI_Datatype sendtype,
void *recvbuf,
int recvcount,
MPI_Datatype recvtype,
int root,
MPI_Comm comm)
- sendbuf : se specifica buferul send de catre fiecare proces;
- sendcount, sendtype : nr de elemente, tipul lor;
- recvbuf : bufferul in care se primesc datele, la procesul root;
- recvcount, recvtype : nr de elemente si tipul lor;
- Important: acelasi root, count, type !

Operatii de comunicare colective


Operatia Gather Exemplu:
- procesul 0 colecteaza 100 de numere intregi de la fiecare proces;

- Exista o varianta in care fiecare proces poate pune la dispozitie un


numar diferit de elemente : MPI_Gatherv ;
- Similar cu MPI_Gather, cu doua modificari:
* parametrul intreg revcount este inlocuit cu un array,
revcounts[i], care specifica nr de elemente pe fiecare proces;
* un parametru suplimentar displs[i], care specifica p[ozitia din
bufferul receive, unde este stocat blocul de date al procesului i;
Doar root-ul specifica revcounts si displs;

Operatii de comunicare colective


Operatia MPI_Gatherv Exemplu:
- fiecare proces trimite 100 de numere intregi;
- datele sunt stocate in bufferul receive, asa incat exsita un gap intre
blocuri de 10 elemente;
- folosim variabila stride = 110 pentru a defini gap-ul;
- daca stride < 100, datele se vor suprapune;

Operatii de comunicare colective


Operatia Scatter :
- procesul root trimite cate un bloc de date catre toate procesele;
int MPI_Scatter (void *sendbuf,
int sendcount,
MPI_Datatype sendtype,
void *recvbuf,
int recvcount,
MPI_Datatype recvtype,
int root,
MPI_Comm comm)
- sendbuf : bufferul send pus la dispozitie de procesul root, care
contine cate un bloc pentru fiecare proces;
- sendcount, sendtype : nr de elemente, tipul lor;
- recvbuf, recvcount, recvtype : buffere specificate de catre fiecare
proces, nr de elemente primite, tipul elementelor;
Fiecare proces trebuie sa specifice acelais root, nr. de elemente si
acelasi tip !

Operatii de comunicare colective


Operatia Scatter varianta MPI_Scatterv :
- similar cu instructiunile MPI_Gather, MPI_Gatherv;
- difera fata de MPI_Scatter cu urmatoarele doua modificari:
* sendcounts[i] : nr de elemente trimise catre procesul i;
* displs[i] : specifica pozitia blocurilor de elemente din bufferul
send;

Operatii de comunicare colective


Operatia de tip Multibroadcast :
- fiecare proces pune la dispozitie un bloc;
- dupa executarea operatiei, fiecare bloc va fi trimis catre toate
procesele;
int MPI_Allgather (void *sendbuf,
int sendcount,
MPI_Datatype sendtype,
void *recvbuf,
int recvcount,
MPI_Datatype recvtype,
MPI_Comm comm)
int MPI_Allgatherv (void *sendbuf,
int sendcount,
MPI Datatype sendtype,
void *recvbuf,
int *recvcounts,
int *displs,
MPI Datatype recvtype,
MPI Comm comm)

Operatii de comunicare colective


Operatia de tip Multi-accumulation :
- fiecare proces executa o operatie de tip single-accumulation;
- rezultatul este echivalent cu o operatie de single-accumulation,
urmata de single-broadcast;
int MPI_Allreduce (void *sendbuf,
void *recvbuf,
int count,
MPI_Datatype type,
MPI_Op op,
MPI_Comm comm)
- sendbuf : fiecare proces pune la dispozitie un bloc;
- recvbuf : rezultatele acumulate;
- op : operatia de reducere;
Fiecare proces trebuie sa specifice acelasi count, type.

Operatii de comunicare colective


Operatia de tip Multi-accumulation :
Exemplu:
- multiplicare matrice vector : c = A x b;
* matrice A : nxm; vector b : m;
- A este distribuita column-wise in blocuri local_m = m / p;
- vectorul b este divizat in blocuri local_p;

Operatii de comunicare colective


Operatia de tip Total-exchange :
- fiecare proces pune la dispozitie un bloc de date diferit pentru
fiecare alt proces;
- operatia este echivalenta cu:
- fiecare proces executa o operatie scatter (sender view);
- fiecare proces executa o operatie gather (receiver view);
int MPI_Alltoall (void *sendbuf,
int sendcount,
MPI_Datatype sendtype,
void *recvbuf,
int recvcount,
MPI_Datatype recvtype,
MPI_Comm comm)
Exista versiunea MPI_Alltoallv() pentru blocuri de dimensiuni diferite.

Situatii de deadlock in utilizarea operatiilor de


comunicare colective
Utilizarea incorecta a operatiilor de comunicare colective poate
conduce la situatii de deadlock.
Exemplu MPI_Broadcast() :

Exista doua posibilitati:


- sistemul MPI runtime poate potrivi primele operatii de broadcast
ale fiecarui proces--> eroare: se specifica procese root diferite!
- sistemul MPI runtime poate potrivi operatiile de broadcast asa cum
a intentionat programatorul; in aceasta situatie se poate ajunge la
deadlock daca nu se folosesc buffere sau acestea sunt prea mici;

Situatii de deadlock in utilizarea operatiilor de


comunicare colective
Situatii de deadlock pot apare si atunci cand se suprapun operatii
colective cu operatii de tip point-to-point:

Observatie:
- daca nu se folosesc buffere, apare situatia de deadlock, intrucat
procesul 0 se blocheaza la operatia de MPI_Broadcast(), in timp ce
procesul 2 se blocheaza la operatia MPI_Recv() ;

Sincronizarea operatiilor de comunicare colective


Sincronizarea operatiilor de comunicare depinde de utilizarea
bufferelor. Daca nu exista buffere sau sunt prea mici sincronizare;
Exemplu:

- Procesele 0 si 2 trimit cu MPI_Send() catre procesul 1;


- Intrebare : care este ordinea mesajelor primite de procesul 1?

Sincronizarea operatiilor de comunicare colective


Exista doua posibilitati de executie :
1. Procesul 1 primeste primul mesaj de la Procesul 2:

2. Procesul 1 primeste primul mesaj de la Procesul 0:

Sincronizarea operatiilor de comunicare colective


Observatii:
- Situatia nr 2 poate apare doar dacza exsita buffere sufcient de
mari;
- exista un comportament non-deterministic al programului generat
de folosirea/absenta bufferelor;
- pentru a sincroniza un grup de procese, MPI pune la dispozitie
comanda:
MPI_Barrier( MPI_Comm Comm);
Efectul consta in blocarea si sincronizarea tuturor proceselor din
comunicatorul Comm.

Grupuri de procese i comunicatori


Grup de procese mulime ordonat de procese definite de o aplicaie
(program). Proprieti asigurate (garantate) de mediul MPI:
- fiecrui proces i se atribuie un rang;
- un proces poate fi membru al mai multor grupuri i poate avea diferite
ranguri n aceste grupuri;
- sistemul MPI are n sarcin reprezentarea i controlul grupurilor de
procese.;
- grupurile de procese sunt extrem de utile pentru implementarea
programelor cu sarcini de ndeplinit n paralel i stau la baza
mecanismului de comunicare definit de MPI;
- paralelismul la nivel de sarcini de execuie este mult mai uor de
Implementat utiliznd conceptul de grup
- la nivel de utilizator: un grup este un obiect avnd tipul predefinit
MPI_Group, care poate fi accesat doar prin intermediul unui handle.

Grupuri de procese n MPI


Biblioteca MPI asigur suportul necesar pentru implementarea i
manipularea grupurilor de procese (exemplu: restngerea operaiilor
de comunicare colective la anumite grupuri prin utilizarea comunicatorilor
asociai acestora.
MPI exist un comunicator pentru fiecare grup i, invers, fiecare
comunicator definete un grup de procese.
- Comunicarea (unu-la-unu sau colectiv) efectuat ntr-un domeniu de
Comunicare
- un comunicator este informat de existena altor comunicatori n acelai
domeniu.

Comunicatori MPI

intra-grup: asigur comunicarea colectiv n


interiorul unui grup (comunicatori interni).
inter-grup: asigur comunicarea unu-la-unu
ntre dou grupuri de procese (comunicatori
externi).

Grupuri de procese n MPI


La nivel de utilizator:
- un comunicator este un obiect opac de tipul predefinit MPI_Comm;
- MPI_COMM_WORLD : include toate procesele lansate de un program
paralel;
- biblioteca MPI furnizeaz soluii pentru construirea de grupuri de
procese i comunicatori suplimentari, pe baza MPI_COMM_WORLD:
int MPI_Comm_group (MPI_Comm comm, MPI_Group *group);
Rol: creeaz i ntoarce grupul asociat unui comunicator.
Intrare: comunicatorul comm
Ieire: - grupul group asociat comunicatorului (handle, declarat n prealabil);
- o valoare ntreag reprezentnd codul de eroare asociat operaiei
(implementare POSIX).
Valoare predefinit pentru un grup: MPI_GROUP_EMPTY
(un grup de procese vid)

Operaii implicnd grupuri de


procese n MPI
- reuniunea a dou grupuri preexistente group1 i group2:
int MPI_Group_union (
MPI_Group group1,
MPI_Group group2,
MPI_Group * new_group
);
Rol : ntoarce n new_group reuniunea grupurilor existente group1 i
group2. n noul grup procesele din group1 i pstreaz rangurile,
iar cele din group2 care nu sunt n group1 primesc ranguri noi,
cu valori sucesive celor din group1.
Intrare : obiectele group1 i group2 (definite n prealabil);
Ieire : - obiectul new_group (handle declarat anterior);
- la ieire returneaz codul de eroare asociat operaiei (POSIX).

Operaii implicnd grupuri de


procese n MPI
- intersecia a dou grupuri preexistente group1 i group2:
int MPI_Group_intersection (

MPI_Group group1,
MPI_Group group2,
MPI_Group * new_group
);

Rol : ntoarce n new_group intersecia grupurilor existente group1 i


group2. n noul grup procesele capt ranguri succesive, ncepnd
cu 0; ordinea proceselor din group1 este meninut n new_group.
Intrare : obiectele group1 i group2 (definite n prealabil);
Ieire : - obiectul new_group (handle declarat anterior);
- la ieire returneaz codul de eroare asociat operaiei (POSIX).

Operaii implicnd grupuri de


procese n MPI
- diferena a dou grupuri preexistente group1 i group2:
int MPI_Group_difference (

);

MPI_Group group1,
MPI_Group group2,
MPI_Group * new_group

Rol : ntoarce n new_group diferena (n sens de operaii cu mulimi)


grupurilor existente group1 i group2. n noul grup procesele capt
ranguri succesive, ncepnd cu 0; ordinea proceselor din group1
este meninut n new_group.
Intrare : obiectele group1 i group2 (definite n prealabil);
Ieire : - obiectul new_group (handle declarat anterior);
- la ieire returneaz codul de eroare asociat operaiei (POSIX).

Operaii implicnd grupuri de


procese n MPI
- un subgrup al grupului preexistent group1 poate fi obinut apelnd
funcia:
int MPI_Group_incl ( MPI_Group group,
int p,
int * ranks,
MPI_Group * new_group );
Rol : ntoarce n new_group un subgrup al group cu p procese avnd
ranguri de la 0 la p-1; ranks e un ir de ntregi cu p elemente.
n noul grup procesul i este procesul cu rangul ranks[i] n group.
Pentru a asigura execuia corect, group trebuie s conin cel puin
p procese i, pentru 0 <= i < p, ranks[i] trebuie s fie un rang valid
(valori distincte!) din group.
Intrare : obiectul group , p (numrul de elemente) i ranks (rangurile
proceselor de reinut n new_group);
Ieire : - obiectul new_group (handle declarat anterior);
- la ieire returneaz codul de eroare asociat operaiei (POSIX).

Operaii implicnd grupuri de


procese n MPI
- procese specifice pot fi eliminate din grupul preexistent group1
apelnd funcia:
int MPI_Group_excl ( MPI_Group group,
int p,
int * ranks,
MPI_Group * new_group
);
Rol : ntoarce n new_group un subgrup al group obinut prin eliminarea
proceselor avnd rangurile ranks[0],...,ranks[p-1]. Pentru a
asigura execuia corect, group trebuie s conin cel puin p procese
i, pentru 0 <= i < p, ranks[i] trebuie s fie un rang valid (valori
distincte!) din group.
Intrare : obiectul group , p (numrul de elemente) i ranks (rangurile
proceselor de eliminat);
Ieire : - obiectul new_group (handle declarat anterior);
- la ieire returneaz codul de eroare asociat operaiei (POSIX).

Operaii implicnd grupuri de


procese n MPI
Observaii :
- structurile datelor de tip MPI_Group nu pot fi accesate direct de utilizator;
- MPI definete o serie de funcii pentru a obine informaii despre grupuri
de procese :
int MPI_Group_size ( MPI_Group group, int * size);

Rol : ntoarce n size dimensiunea (numrul de elemente) grupului group.


Intrare : obiectul group ;
Ieire : - size (numrul de elemente din group);
- la ieire returneaz codul de eroare asociat operaiei (POSIX).

Operaii implicnd grupuri de


procese n MPI
Observaii :
- rangul procesului apelant din group poate fi obinut cu :
int MPI_Group_rank ( MPI_Group group, int * rank);

Rol : ntoarce n rank rangul procesului care apeleaz funcia n


grupul group.
Intrare : obiectul group ;
Ieire : - rank (rangul procesului apelant din group);
- la ieire returneaz codul de eroare asociat operaiei (POSIX).

Operaii implicnd grupuri de


procese n MPI
Observaii :
- se poate verifica dac group1 i group2 descriu acelai grup apelnd
funcia :
int MPI_Group_compare ( MPI_Group group1,
MPI_Group group2,
int * res
);
Rol : ntoarce n res rezultatul verificrii faptului c group1 i group2 descriu
sau nu acelai grup de procese;
res = MPI_IDENT - ambele grupuri conin aceleai procese n aceeai
ordine;
res = MPI_SIMILAR - ambele grupuri conin aceleai procese dar nu n
aceeai ordine;
res = MPI_UNEQUAL cele dou grupuri conin procese diferite.
Intrare : obiectele group1, group2 ;
Ieire : - res (cu valorile de mai sus);
- la ieire returneaz codul de eroare asociat operaiei (POSIX).

Operaii implicnd grupuri de


procese n MPI
Observaii :
- se poate distruge un grup creat anterior, apelnd funcia :
int MPI_Group_free ( MPI_Group * group );

Rol : elibereaz resursele alocate anterior, la crearea grupului group (handle


pentru un grup deja existent, care la ieire are valoarea
MPI_GROUP_NULL).
Intrare : obiectul group, creat anterior.
Ieire : - la ieire returneaz codul de eroare asociat operaiei (POSIX).

Operaii implicnd comunicatori


n MPI
- se poate crea un nou comunicator intern asociat unui grup de procese :
int MPI_Comm_create (
MPI_Comm comm,
MPI_Group group,
MPI_Comm * new_comm
);
Rol : creeaz un comunicator intern asociat grupului group. Parametrul group
trebuie s specifice un subgrup al grupului de procese asociat
comunicatorului predefinit comm. Pentru o execuie corect toate
procesele din comm trebuie s apeleze MPI_Comm_create() cu acelai
argument group. Procesele apelante membre ale group obin un pointer
pe noul comunicator new_comm, iar cele care nu sunt n group obin
MPI_COMM_NULL ca valoare de ntoarcere n new_comm.
Intrare : obiectele comm i group, create anterior.
Ieire : - la ieire returneaz codul de eroare asociat operaiei (POSIX), iar n
new_comm adresa spaiului alocat noului comunicator sau
MPI_COMM_NULL.

Operaii implicnd comunicatori


n MPI
Observaii :
- MPI furnizeaz funcii specifice pentru a obine informaii despre
comunicatori; aceste funcii sunt implementate ca operaii locale (nu
implic execuia unor funcii de comunicaie)
- se poate obine dimensiunea grupului de procese asociat lui comm :
int MPI_Comm_size ( MPI_Comm comm, int * size );
Rol : ntoarce n size numrul de procese dn grupul lui comm (numrul total
de procese care execut programul dac comm = MPI_COMM_WORLD).
Intrare : obiectul comm ;
Ieire : - size (cu valorile de mai sus);
- la ieire returneaz codul de eroare asociat operaiei (POSIX).

Operaii implicnd comunicatori


n MPI
Observaii :
- se poate obine rangul procesului apelant din grupul lui comm :
int MPI_Comm_rank ( MPI_Comm comm, int * rank );
Rol : ntoarce n rank rangul prcesului apelant din grupul lui comm .
Intrare : obiectul comm ;
Ieire : - rank (rangul procesului apelant);
- la ieire returneaz codul de eroare asociat operaiei (POSIX).

Operaii implicnd comunicatori


n MPI
- doi comunicatori pot fi comparai cu :
int MPI_Comm_compare ( MPI_Comm comm1, MPI_Comm comm2, int * res );
Rol : ntoarce n res rezutatul comparrii lui comm1 i comm2 .
res = MPI_IDENT comm1 i comm2 reprezint acelai comunicator;
res = MPI_CONGRUENT grupurile asociate lui comm1 i comm2 conin
aceleai procese n aceeai ordine;
res = MPI_SIMILAR grupurile asociate lui comm1 i comm2 conin
aceleai procese, dar cu ranguri n ordine diferit;
res = MPI_UNEQUAL grupurile asociate lui comm1 i comm2 conin
procese diferite.
Intrare : obiectele comm1, comm2 ;
Ieire : - res (rezultatul comparrii);
- la ieire returneaz codul de eroare asociat operaiei (POSIX).

Operaii implicnd comunicatori


n MPI
- un comunicator poate fi copiat cu :
int MPI_Comm_dup ( MPI_Comm comm, MPI_Comm * new_comm );

Rol : creeaz un nou comunicator intern new_comm (handle) cu aceleai


caracteristici (grup asociat i topologie) ca ale lui comm .
new_comm reprezint un domeniu de comunicare distinct; copierea
unui comunicator permite programatorului s separe operaiile de
comunicare executate de o bibliotec de funcii de cele executate de
aplicaia (programul) nsi, evitnd astfel conflictele.
Intrare : obiectul comm ;
Ieire : - new_comm (handle, copia comunicatorului);
- la ieire returneaz codul de eroare asociat operaiei (POSIX).

Operaii implicnd comunicatori


n MPI
- un comunicator poate fi distrus cu :
int MPI_Comm_free ( MPI_Comm * comm );

Rol : elibereaz resursele alocate comunicatorului comm (de exemplu,


obinut anterior printr-o operaie de copiere, pentru a separa
comunicaiile unor funcii de bibliotec de acelea ale programului care
le apeleaz)..
Intrare : obiectul comm (handle);
Ieire : - la ieire returneaz codul de eroare asociat operaiei (POSIX).

Operaii implicnd comunicatori n MPI


- un comunicator poate fi despicat cu :
int MPI_Comm_split ( MPI_Comm * comm,
int color,
int key,
MPI_Comm * new_comm );
Rol : grupul asociat lui comm este partiionat n subgrupuri disjuncte, al cror
numr este determinat de color (fiecare subgrup conine toate procesele
care specific acelai parametru color). n fiecare subgrup procesele
sunt ordonate n ordinea definit de key; dac dou procese specific
acelai parametru key, este folosit ordinea din grupul iniial. Dac un
proces din comm specific color = MPI_UNDEFINED, el nu este
selectat n nici unul dintre subgrupurile generate. Subgrupurile nu sunt
furnizate la ieire n forma unui obiect de tipul MPI_Group; fiecare
proces al lui comm primete un pointer new_comm pe comunicatorul
subgrupului cruia i aparine. Dac color = MPI_UNDEFINED, atunci
new_comm = MPI_COMM_NULL.
Intrare : obiectul comm , variabilele color i key;
Ieire : - la ieire returneaz codul de eroare asociat operaiei (POSIX) i adresa
comunicatorului nou alocat new_comm (handle)..

Operaii implicnd comunicatori n MPI


- Exemplu - un grup de 10 procese apeleaz MPI_Comm_split() cu
urmtoarele argumente:
proces
rang
color
key

a
0
0
3

b
1
1

c
2
3
2

d
3
0
5

e
4
3
1

f
5
0
1

g
6
0
1

h
7
5
2

i
8
3
1

j
9
0

( - <=> MPI_UNDEFINED )

Explicaie : sunt generate trei subgrupuri, respectiv {f,g,a,d}, {e,i,c} i


{h}, care conin procesele n aceast ordine.
MPI_Comm_split() poate fi utilizat pentru pregtirea execuiei de
sarcini paralele. Diferiii comunicatori generai pot fi utilizai pentru
comunicaii intra-sarcini, separnd complet domeniile de comunicare.

Topologii de procese
- Adesea e util o reprezentare alternativ a structurii unui grup de procese.
Exemplu : un algoritm efectueaz operaii de calcul sau comunicare pe o reea
2D sau 3D ale cror puncte pot fi asignate diferitelor procese, iar procesele
schimb date (comunic) doar cu vecinii topologici de ordinul I.
Soluia : rearanjarea logic a proceselor prin definirea unei topologii virtuale
pentru comunicatorii interni. O reea cartezian de dimensiune arbitrar
poate fi creat cu:
int MPI_Cart_create (

MPI_Comm comm,
int ndims,
int * dims,
int * periods,
int reorder,
MPI_Comm * new_comm
);

Topologii de procese
int MPI_Cart_create ( ... );
Rol : crearea unei topologii virtuale pentru comunicatorii interni, similare celei
Logice impuse de tipul de comunicare ntre procese.
Intrare : comm comunicatorul original, fr o topologie definit;
ndims numrul de dimensiuni al reelei de generat;
dims ir de ndims ntregi; dims[i] este numrul proceselor n
dimensiunea i. Elementele din dims sunt supuse constrngerii
ca produsul lor s fie egal cu numrul de procese din
new_comm i nu trebuie s depeasc numrul de procese
din comunicatorul original comm.
periods ir de ndims valori cu sens boolean, specificnd pentru
fiecare dimensiune dac reeaua este periodic pe
dimensiunea respectiv ( periods[i] = 1) sau nu (periods[i] = 0)
reorder variabil cu sens boolean (0 procesele din new_comm
au acelai rang ca n comm; 1 la rulare procesele sunt
reordonate pentru a obine o coresponden (mapping) mai
bun a topologiei virtuale cu cea a clusterului de calcul.
Ieire : new_comm (handle pointer pe noul comunicator)
- valoarea de ntoarcere POSIX

Topologii de procese
Exemplu : un comunicator conine 12 procese Cu valorile
ndims = 2; dims = {3,4}; periods = {0,0}; reorder = 0;
apelul funciei
MPI_Cart_create (comm,ndims,dims,periods,reorder,&new_comm);
genereaz reeaua virtual 3x4:

0
(0,0)

1
(0,1)

2
(0,2)

3
(0,3)

4
(1,0)

5
(1,1)

6
(1,2)

7
(1,3)

8
(2,0)

9
(2,1)

10
(2,2)

11
(2,3)

Topologii de procese
int MPI_Dims_create ( int nnodes, int ndims, int * dims );
Rol : selecteaz ncrcarea optim a proceselor pe diferite dimensiuni ale
unei topologii virtuale. Distribuia pe o dimensiune i este efectuat
numai dac dims[i] = 0 la apelul funciei; numrul de procese n
dimensiunea j poate fi fixat dnd lui dim[j] o valoare ntreag pozitiv
nainte de apel (atunci dimenisiunea j nu mai e luat n calcul de
funcie, distribuia viznd doar celelalte dimensiuni).
Intrare : ndims numrul de dimensiuni ale reelei;
nnodes numrul total de procese lansate n execuie;
dims ir de ntregi de lungime ndims.
Ieire : elementele irului dims conin o distribuie a proceselor nnodes
ct mai uniform (balansat) pe cele ndims dimensiuni.
- funcia ntoarce o valoare ntreag conform POSIX

Topologii de procese
Funcii de conversie:
int MPI_Cart_rank ( MPI_Comm comm, int * coords, int * rank );

Rol : ntoarce n rank rangul procesului cu coordonatele coords din


comunicatorul comm cu topologie cartezian.
Intrare : comm comunicator cu topologie cartezian predefinit;
coords ir de ntregi definind poziia procesului n reeaua
virtual;
Ieire : rank rangul procesului cu coordonatele coords;
- funcia ntoarce o valoare ntreag conform POSIX

Topologii de procese
Funcii de conversie:
int MPI_Cart_coords(MPI_Comm comm,int rank,int ndims,int * coords);

Rol : ntoarce n coords coordonatele procesului cu rangul rank din


reeaua virtual a comunicatorului comm cu topologie cartezian
avnd ndims dimensiuni..
Intrare : comm comunicator cu topologie cartezian predefinit;
rank rangul procesului;
ndims numrul de dimensiuni al reelei comunicatorului.
Ieire : coords ir coninnd coordonatele procesului cu rangul rank;
- funcia ntoarce o valoare ntreag conform POSIX

Topologii de procese
Exemplu : 12 procese, aranjate n reea 3x4 cu conexiune periodic la capete
int coords[2], dims[2], periods[2] = {1,1};
int source, dest, my_rank, reorder;
MPI_Comm comm_2D;
/* comunicatorul cu re ea cartezian */
MPI_Status status;
Float a, b;
/* buffer-ul de date */
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); /*rangul procesului apelant*/
Dims[0] = 3; dims[1] = 4; /* retea 3x4 */
Reorder = 0;
//pstrez ordinea din grupul lui MPI_WORLD_COMM
/* creez topologia virtual a comunicatorului comm_2D */
MPI_Cart_create(MPI_WORLD_COMM,2,dims,periods,reorder,&comm_2D);
/* care sunt coordonatele procesului curent n noua re ea? */
MPI_Cart_coords(comm_2D,my_rank,2,coords);
/* care sunt vecinii lui pe direc ia 0? */
MPI_Cart_shift(comm_2D,0,coords[1],&source,&dest);
A = (float) my_rank;
// o valoare local
MPI_Sendrecv(&a,1,MPI_FLOAT,dest,0,&b,1,MPI_FLOAT,source,0,comm_2D,
&status);

Topologii de procese
Exemplu : 12 procese, aranjate n reea 3x4 cu conexiune periodic la capete;
Topologia pe exemplul de cod descris anterior:
Procesul cu rank = 5, coords[1] = 1, deci source = 9 (vecinul de jos pe
dimensiunea 0) i dest = 1 (vecinul de sus pe dimensiunea 0).
0
(0,0)
0|0

1
(0,1)
9|5

2
(0,2)
6|10

3
(0,3)
3|3

4
(1,0)
4|4

5
(1,1)
1|9

6
(1,2)
10|2

7
(1,3)
7|7

8
(2,0)
8|8

9
(2,1)
5|1

10
(2,2)
2|6

11
(2,3)
11|11

Topologii de procese
Funcii de conversie:
int MPI_Cart_sub(MPI_Comm comm,int * remain_dims,MPI_Comm *newcomm);

Rol : ntoarce n newcomm comunicatorului asociat unei subreele a reelei


virtuale a comunicatorului comm. Selecia nodurilor n subreea este
controlat de irul ntreg remain_dims care conine un element pentru
fiecare dimensiune a reelei originale; remain_dims[i] = 1 specific
meninerea direciei i n subreea, remain_dims[i] = 0 specific
eliminarea direciei i.
Intrare : comm comunicator cu topologie cartezian predefinit;
remain_dims irul care specific coninutul subreelei;
Ieire : newcomm comunicatorul asociat noii subreele (handle);
- funcia ntoarce o valoare ntreag conform POSIX

Topologii de procese
Exemplu :
- comm_3D are o reea virtual 2x3x4 deja definit;
int remain_dims[3] = {1,0,1};
MPI_Comm new_comm;
MPI_Cart_sub(comm_3D, remain_dims, &new_comm);
Rezultat : trei subreele 2x4, fiecare proces
dispunnd de un comunicator pentru subreeaua
din care face parte (a se vedea figura alturat).

Topologii de procese
Funcii pentru extragerea informaiei topologice:
int MPI_Cartdim_get(MPI_Comm comm,int * ndims);
Rol : ntoarce n ndims numrul de dimensiuni al reelei virtuale asociate
comunicatorului comm.
Intrare : comm comunicator cu topologie cartezian predefinit;
Ieire : ndims numrul de dimensiuni al reelei virtuale;
- funcia ntoarce o valoare ntreag conform POSIX
int MPI_Cart_get(MPI_Comm comm,int maxdims, int *dims,
int *periods, int *coords);

Rol : ntoarce info asupra topologiei virtuale asociate comunicatorului comm.


Aceasta are maxdims dimensiuni, cu dims[i] procese n direcia i, periodicitatea pe direcia i fiind definit de periods[i].
coords conine coordonatele procesului apelant.
Intrare : comm comunicator cu topologie cartezian predefinit;
Maxdims numrul de dimensiuni ale reelei.
Ieire : dims, periods, coords semnificaie specificat mai sus;
- funcia ntoarce o valoare ntreag conform POSIX

Durata de execuie & terminarea proceselor


double MPI_Wtime(void);
Rol : ntoarce o valoare reprezentnd numrul de secunde scurse de la un
Punct fix n timp din trecut pn la momentul apelului n ndims numrul de
comunicatorului comm.
Intrare : void ;
Ieire : numrul de secunde scurse de la un moment anterior fixat.
double MPI_Wtick(void);
Rol : ntoarce timpul ntre pulsuri de ceas succesive n secunde.
Intrare : void
Ieire : semnificaie specificat mai sus;
int MPI_Abort(MPI_Comm comm, int error_code);
Rol : foreaz terminarea execuiei tuturor proceselor din comunicatorul comm
cu codul de eroare error_code.
Intrare : comm comunicatorul ale crui procese vor fi terminate cu error_code
Ieire : codul de eroare POSIX;

MPI tipuri de date derivate


Exemplu : o aplicaie trebuie s transmit ntre procese distincte sub-blocuri
de date care nu sunt stocate n zone de memorie adiacente;
- imposibil cu o singur operaie de comunicare pe baza tipurilor de date
implicite!!

MPI tipuri de date derivate


Exemplu : o aplicaie trebuie s transmit ntre procese distincte sub-blocuri
de date care nu sunt stocate n zone de memorie adiacente;
- imposibil cu o singur operaie de comunicare pe baza tipurilor de date
implicite!!
Soluia :
- operaii multiple MPI_Send () / MPI_Recv ()
sau
- copierea datelor care urmeaz a fi transmise ntr-un
bloc de memorie distinct

MPI tipuri de date derivate


Exemplu : o aplicaie trebuie s transmit ntre procese distincte sub-blocuri
de date care nu sunt stocate n zone de memorie adiacente;
- imposibil cu o singur operaie de comunicare pe baza tipurilor de date
implicite!!
Soluia :
- operaii multiple MPI_Send () / MPI_Recv ()
sau
- copierea datelor care urmeaz a fi transmise ntr-un
bloc de memorie distinct
- ncrcare prea mare a reelei de comunicaii;
- aplicaie prea lent i prea consumatoare de resurse!.

MPI tipuri de date derivate


Exemplu : o aplicaie trebuie s transmit ntre procese distincte sub-blocuri
de date care nu sunt stocate n zone de memorie adiacente;
Soluia corect : definirea de tipuri de date derivate (acolo unde este posibil)
Crearea unui tip de date derivat:
- se face la momentul rulrii aplicaiei n dou etape:
- definirea propriu-zis a tipului nou de date prin apelul unei funcii
specifice;
- crearea (comiterea) noului tip de date prin apelul funciei
int MPI_Type_commit ( MPI_Datatype * newdatatype );
Intrare : nimic
Ieire : - newdatatype (handle) tipul de date de creat;
- valoarea de ntoarcere ntreag POSIX.
- tipul de date nou trebuie creat nainte de a fi utilizat;

MPI tipuri de date derivate


Orice tip de date derivat este definit prin harta sa, o list de forma:
tipul predefinit 0

deplasarea tipului 0

tipul predefinit 1

deplasarea tipului 1

...

...

tipul predefinit n-1

deplasarea tipului n-1

- deplasrile sunt ntregi (negativi, zero sau pozitivi);


- la momentul apelrii unei funcii de comunicare cu un buffer definit de
noul tip de date, deplasrile sunt interpretate ca offset-uri n raport cu
adresa de nceput a buffer-ului de comunicare, pentru determinarea
adreselor elementelor de transmis;
- un tip de date derivat poate fi interpretat ca o aplicare a unei mti
(ablon) peste buffer-ul de ccomunicare.

MPI funcii pentru tipuri de date derivate


int MPI_Type_contiguous (
int count,
MPI_Datatype oldtype,
MPI_Datatype * newtype
);
Rol : definete newtype ca un tip de date reprezentat prin concatenarea
a count obiecte de tipul pre-existent oldtype, stocate ntr-o zon continu
de memorie.
Intrare : count (ntreg nonnegativ), numrul de replici;
oldtype (handle), tipul de date existent;
Ieire : - newtype (handle) tipul de date de creat;
- valoarea de ntoarcere ntreag POSIX.

MPI funcii pentru tipuri de date derivate


int MPI_Type_vector (
int count, int blocklength, int stride,
MPI_Datatype oldtype, MPI_Datatype * newtype
);
Rol : definete newtype ca un tip de date reprezentat prin ntreeserea
a count obiecte n locaii constnd din blocuri de date de tip oldtype
egal distanate n RAM. Distana dintre blocuri este un multiplu al lungimii
tipului pre-existent oldtype.
Intrare : count (ntreg nonnegativ), numrul de replici (blocuri);
blocklength (ntreg nonnegativ), numrul de elemente dintr-un bloc;
stride (ntreg), numrul de elemente dintre adresele de nceput ale
fiecrui bloc;
oldtype (handle), tipul de date existent;
Ieire : - newtype (handle) tipul de date de creat;
- valoarea de ntoarcere ntreag POSIX.

MPI funcii pentru tipuri de date derivate


oldtype
5 elemente deplasare (stride)

...

newtype
2 elemente/bloc

Fig. 1 Ilustrarea apelrii MPI_Type_vector(...) cu count=2, blocklength=2,


stride=5.
Exemplu de cod (fr legtur cu figura 1!) :
Double mat[LINES][COLS];
MPI_Datatype my_type;
MPI_Type_vector(LINES, 1, COLS, MPI_DOUBLE, &my_type);
MPI_Type_commit(&my_type);
MPI_Ssend(&(mat[0][5]), 1, my_type, dest, tag, comm); //??

MPI funcii pentru tipuri de date derivate


oldtype
5 elemente deplasare (stride)

...

newtype
2 elemente/bloc

Fig. 1 Ilustrarea apelrii MPI_Type_vector(...) cu count=2, blocklength=2,


stride=5.
Exemplu de cod (fr legtur cu figura 1!) :
Double mat[LINES][COLS];
MPI_Datatype my_type;
MPI_Type_vector(LINES, 1, COLS, MPI_DOUBLE, &my_type);
MPI_Type_commit(&my_type);
MPI_Ssend(&(mat[0][5]), 1, my_type, dest, tag, comm);
Trimite coloana 5 a matricii mat.

MPI funcii pentru tipuri de date derivate


int MPI_Type_indexed (
int count, int * array_of_blocklengths,
int * array_of_displacements,
MPI_Datatype oldtype, MPI_Datatype * newtype
);
Rol : definete newtype ca un tip de date reprezentat prin replicarea
a count obiecte ntr-o secven de blocuri, fiecare bloc coninnd un
numr posibil diferit de copii i avnd deplasri diferite. Distana dintre
blocuri este un multiplu al lungimii tipului pre-existent oldtype.
Intrare : count (ntreg nonnegativ), numrul de blocuri;
array_of_blocklengths (ir de ntregi pozitivi de dimensiune count),
numrul de elemente dintr-un bloc;
array_of_displacements (ir de ntregi, de dimensiune count),
deplasrile n octei ale fiecrui bloc;
oldtype (handle), tipul de date existent;
Ieire : - newtype (handle) tipul de date de creat;
- valoarea de ntoarcere ntreag POSIX.

MPI funcii pentru tipuri de date derivate


int MPI_Type_indexed (
int count, int * array_of_blocklengths,
int * array_of_displacements,
MPI_Datatype oldtype, MPI_Datatype * newtype
);
Exemplu: oldtype are harta {(double,0),(char,8)} cu extensia 16 (numrul
de elemente). Dac B={3,1} i D={4,0} apelul
MPI_Type_indexed( 2, B, D, oldtype, &newtype);
produce un tip de date n care primul bloc conine 3 elemente de tip oldtype
cu deplasarea 4*16=64, iar al doilea conine un element cu deplasarea 0,
adic are harta:
{(double,64),(char,72), (double,80),(char,88), (double,96),(char,104)
(double,0),(char,8)}

MPI funcii pentru tipuri de date derivate


int MPI_Type_create_struct (
int count, int array_of_blocklengths[],
MPI_Aint array_of_displacements[],
MPI_Datatype array_of_types[],
MPI_Datatype * newtype
);
Rol : definete newtype ca un tip de date structurat; introdus de standardul
MPI 2, nlocuind MPI_Type_struct().
Intrare : count (ntreg nonnegativ), numrul de blocuri;
array_of_blocklengths (ir de ntregi pozitivi de dimensiune count),
numrul de elemente dintr-un bloc;
array_of_displacements (ir de ntregi, de dimensiune count),
deplasrile n octei ale fiecrui bloc;
array_of_types (ir de handle), tipul de date al elementelor din
fiecare bloc;
Ieire : - newtype (handle) tipul de date de creat;
- valoarea de ntoarcere ntreag POSIX.

MPI funcii pentru tipuri de date derivate


Exemplu:
#define NBLOCKS 2
int lb, extent;
// pentru caracterizarea tipurilor de date (lower bound + extent
struct {
// oldtype
int dimVec;
double vec[NMAX];
} packVec;
int array_of_blocklengths[NBLOCKS] = {1,NMAX};
MPI_Aint array_of_displacements[NBLOCKS];
MPI_Datatype array_of_types[NBLOCKS] = {MPI_INT, MPI_DOUBLE};
MPI_Datatype packVecType; // newtype
array_of_displacements[0]=0;
MPI_Type_get_extent (MPI_INT, &lb, &extent); // ct ocup int?
array_of_displacements[1]=extent; // offset-ul primului element din vec[NMAX]
MPI_Type_struct (2,array_of_blocklengths,array_of_displacements,array_of_types,
&packVecType);
// definirea structurii MPI
MPI_Type_commit (&packVecType);
// crearea efectiv a noului tip
count=1; dest=10; tag=3;
MPI_Ssend (&packVec, count, packVecType, dest, tag, MPI_WORLD_COMM);

MPI-2 extensii definite de noul standard

- MPI-2 include toate funciile i definiiile introduse de MPI-1;


- cele mai importante extensii:
- gestionare dinamic a proceselor (n MPI-1 procesele erau gestionate static)
- introduce funcii de comunicare unidirecional;
- introduce operaii I/O paralelizate;
- extinde funciile de comunicaii colective.

MPI-2 crearea i gestiunea dinamic a


proceselor
- MPI-2 implementeaz funciile necesare pentru crearea i distrugerea
proceselor pe durata execuiei programului
Funciile MPI-2 au un argument suplimentar, de tip MPI_Info, destinat a
furniza informaii despre funcie. Obiectele MPI_Info sunt opace i
conin de regul perechi de date de forma (key, value).
- Funcii de acces i manipulare cu referire la tipul opac MPI_Info
int MPI_Info_create( MPI_Info * info );
Rol : creeaz un nou obiect info, fr perechi (key,value).
Intrare : nimic
Ieire : - obiectul info creat (handle);
- codul de eroare POSIX ca valoare de ntoarcere.

MPI-2 crearea i gestiunea dinamic a


proceselor
- Funcii de acces i manipulare cu referire la tipul opac MPI_Info
int MPI_Info_set (MPI_Info info, char *key, char *value);
Rol : adaug perechea (key,value) la info; suprascrie value dac key
era definit. key i value sunt stringuri terminate cu '\0'. Dac
key sau value este peste valoarea maxim admis, codurile de
eroare MPI_ERR_INFO_KEY sau MPI_ERR_INFO_VALUE sunt
ntoarse.
Intrare/Ieire : info, key, value
Ieire : - codul de eroare POSIX ca valoare de ntoarcere.

MPI-2 crearea i gestiunea dinamic a


proceselor
- Funcii de acces i manipulare cu referire la tipul opac MPI_Info
int MPI_Info_get ( MPI_Info info, char *key,
int valuelen, char *value,
int *flag );
Rol : extrage perechea (key,value) din info; programatorul furnizeaz
parametrul key i lungimea maxim a cmpului value, valuelen.
Dac key exist n info, valoarea asociat este returnat n value i
o valoare nonzero este returnat n flag (altfel flag=0).
Dac stringul corespunztor este mai lung de valuelen, este
trunchiat la valuelen caractere
Intrare : info, obiect MPI_Info (handle);
Key, parametrul info a crui valoare este cutat
Valuelen, lungimea maxim a cmpului value
Ieire : - value, valoarea parametrului key;
- flag, pentru testare a existenei parametrului key;
- codul de eroare POSIX ca valoare de ntoarcere.

MPI-2 crearea i gestiunea dinamic a


proceselor

- Funcii de acces i manipulare cu referire la tipul opac MPI_Info


int MPI_Info_delete ( MPI_Info info, char *key );
Rol : terge intrarea (key,value) din info;
Intrare : info, obiect MPI_Info (handle);
key, parametrul info a crui valoare trebuie tears
Ieire : - codul de eroare POSIX ca valoare de ntoarcere.

MPI-2 crearea i gestiunea dinamic a


proceselor
- Funcii pentru crearea i gestiunea proceselor
int MPI_Comm_spawn (char *command, char *argv[ ],
int maxprocs, MPI_Info info, int root,
MPI_Comm comm, MPI_Comm *intercomm,
int errcodes[ ]);
Rol : creeaz un numr de procese MPI
Intrare : command, numele programului de executat de fiecare dintre procese;
argv[] conine parametrii de transmis programului; aici argv[0] nu
este numele programului ci primul dintre parametri! O list
de argumente vid este specificat de MPI_ARGV_NULL.
maxprocs, numrul de procese de lansat; dac mediul MPI nu le poate
lansa pe toate, o eroare este generat. MPI_UNIVERSE_SIZE
este numrul maxim de procese care poate fi lansat.
info, obiect MPI_Info (handle); specific perechi (key,value) care
asigur instruciuni suplimentare mediului MPI asupra modului
cum trebuie lansate procesele (de exemplu calea ctre fiierul
executabil, parametrii din linia de comand, etc.;

MPI-2 crearea i gestiunea dinamic a


proceselor
- Funcii pentru crearea i gestiunea proceselor
int MPI_Comm_spawn (char *command, char *argv[ ],
int maxprocs, MPI_Info info, int root,
MPI_Comm comm, MPI_Comm *intercomm,
int errcodes[ ]);
Rol : creeaz un numr de procese MPI
Intrare : info, obiect MPI_Info (handle); specific perechi (key,value) care
asigur instruciuni suplimentare mediului MPI asupra modului
cum trebuie lansate procesele (de exemplu calea ctre fiierul
executabil, parametrii din linia de comand, etc.;
ATENIE: probleme de portabilitate! Programele portabile
trebuie s utilizeze MPI_INFO_NULL.
root, rangul procesului rdcin (printe) din care sunt lansate
noile procese. Numai acest proces furnizeaz valorile
parametrilor precedeni (ns toate procesele din comm
trebuie s apeleze funcia).

MPI-2 crearea i gestiunea dinamic a


proceselor
- Funcii pentru crearea i gestiunea proceselor
int MPI_Comm_spawn (char *command, char *argv[ ],
int maxprocs, MPI_Info info, int root,
MPI_Comm comm, MPI_Comm *intercomm,
int errcodes[ ]);
Rol : creeaz un numr de procese MPI
Ieire : intercomm, intercomunicator definit dup execuia cu succes a funciei.
Utilizat pentru comunicarea ntre procesele in comm i
Cele din grupul nou creat. Noile procese aparin unui grup
Separat, cu propriul MPI_COMM_WORLD.
errcodes, ir de dimensiune maxprocs, coninnd codul de eroare
generat la lansarea n execuie a celor maxprocs procese
(MPI_SUCCESS sau altceva).

MPI-2 crearea i gestiunea dinamic a


proceselor
- Funcii pentru crearea i gestiunea proceselor
int MPI_Comm_get_parent(MPI_Comm *parent);
Rol : ntoarce n parent intercomunicatorul creat de MPI_Comm_spawn(), prin
intermediul cruia procesele lansate dinamic comunic cu procesul
printe.
Ieire : parent, intercomunicatorul definit dup execuia cu succes a funciei.
MPI_Comm_spawn()
- codul de eroare POSIX..

MPI-2 crearea i gestiunea dinamic a


proceselor
- Funcii pentru crearea i gestiunea proceselor
int MPI_Comm_spawn_multiple (int count, char *commands[ ],
char **argv[ ], int maxprocs[ ], MPI_Info infos[ ],
int root, MPI_Comm comm, MPI_Comm *intercomm,
int errcodes[ ]);
Rol : lanseaz n execuie programe MPI multiple sau programe MPI cu
parametri diferii.

Intrare : count, numrul de programe diferite de lansat;


commands, ir de count stringuri, reprezentnd numele programelor
de executat de fiecare dintre procese;
argv conine parametrii de transmis fiecrui nou proces; O list
de argumente vid este specificat de MPI_ARGV_NULL.
maxprocs, numrul de copii de lansat pentru fiecare program; dac
mediul MPI nu le poate lansa pe toate, o eroare este generat.

MPI-2 crearea i gestiunea dinamic a


proceselor
- Funcii pentru crearea i gestiunea proceselor
int MPI_Comm_spawn_multiple (int count, char *commands[ ],
char **argv[ ], int maxprocs[ ], MPI_Info infos[ ],
int root, MPI_Comm comm, MPI_Comm *intercomm,
int errcodes[ ]);
Rol : lanseaz n execuie programe MPI multiple sau programe MPI cu
parametri diferii.
Intrare : infos, obiect MPI_Info (handle); conine instruciuni suplimentare
pentru fiecare program;
- celelalte argumente au aceeai semnificaie ca i n cazul funciei
MPI_Comm_spawn()
- spre deosebire de apelarea multipl a MPI_Comm_spawn(),
funcia MPI_Comm_spawn_multiple() creeaz un singur comunicator pentru
toate procesele lansate n execuie.

MPI-2 comunicare unilateral


- Funcii pentru comunicare unilateral
MPI-1 :
- comunicare global implic toate procesele dintr-un grup;
- comunicare unu-la-unu implic dou procese care schimb date
ntre ele.
MPI-2 :
- comunicare unilateral (one-sided) procesul surs poate accesa
spaiul de adrese al procesului destinaie fr participarea
activ a acestuia din urm. Nu exist o pereche de apeluri
Send() (proces surs) / Recv() (proces destinaie).
- se mai numete acces RMA (Remote Memory Access) ;
- faciliteaz comunicarea n cazul proceselor cu un tipar dinamic
de acces la date;
- accesul coordonat al proceselor la regiunea RAM implicat este
n ntregime n sarcina programatorului!

MPI-2 comunicare unilateral


- Funcii pentru comunicare unilateral
Dac procesul A trebuie s acceseze o regiune RAM a procesului B,
(fereastra) procesul B trebuie n prealabil s expun acea regiune pentru
acces RMA.
int MPI_Win_create ( void *base,
MPI_Aint size,
int displ_unit,
MPI_Info info,
MPI_Comm comm,
MPI_Win *win
);
Rol : creeaz fereastra pentru acces RMA. Toate procesele din comm trebuie
s apeleze funcia. Fiecare proces specific o fereastr n spaiul su
RAM expus pentru acces RMA ctre celelalte procese din comm.

MPI-2 comunicare unilateral


- Funcii pentru comunicare unilateral
int MPI_Win_create (void *base, MPI_Aint size, int displ_unit,
MPI_Info info, MPI_Comm comm, MPI_Win *win);
Intrare : base, adresa de nceput a ferestrei;
size, mrimea ferestrei n octei. Tipul MPI_Aint permite valori mai
mari de 232;
displ_unit, deplasarea unitar ntre elemente succesive din fereastr
n octei (1 dac se acceseaz date la nivel de octet,
sizeof(type) altfel);
info, informaie suplimentar pentru mediul MPI (MPI_INFO_NULL
pentru portabilitate);
comm, comunicatorul proceselor n cadrul cruia se face accesul RMA;
Ieire : win, obiect de tip MPI_Win care poate fi folosit pentru RMA n spaiul
RAM al altor procese din comm.
- codul de eroare POSIX

MPI-2 comunicare unilateral

- Funcii pentru comunicare unilateral


int MPI_Win_free ( MPI_Win *win );
Rol : elibereaz spaiul alocat pentru RMA pe fereastra win. Operaiile RMA
trebuie ncheiate nainte de apelul funciei (toate procesele din
comunicator).
Intrare : win, (handle) fereastra alocat pentru RMA;
Ieire : codul de eroare POSIX.

MPI-2 comunicare unilateral


- Funcii pentru comunicare unilateral
int MPI_Put ( void *origin_addr, int origin_count,
MPI_Datatype origin_type, int target_rank,
MPI_Aint target_displ, int target_count,
MPI_Datatype target_type, MPI_Win win);
Rol : transfer un bloc de date n fereastra altui proces. Este non-blocking: la
returnarea controlului ctre procesul apelant nu este garantat
completarea operaiei. Operaii suplimentare de sincronizare sunt
necesare (MPI_Win_fence()). Buffer-ul RMA nu trebuie accesat sau
modificat dect dup finalizarea operaiei de sincronizare.
Intrare : origin_addr, adresa de nceput a blocului de transmis;
origin_count, numrul de obiecte de transmis, stocate ncepnd cu
origin_addr;
origin_type, tipul de date al obiectelor de transmis;

MPI-2 comunicare unilateral


- Funcii pentru comunicare unilateral
int MPI_Put ( void *origin_addr, int origin_count,
MPI_Datatype origin_type, int target_rank,
MPI_Aint target_displ, int target_count,
MPI_Datatype target_type, MPI_Win win);
Intrare : target_rank, rangul procesului destinaie, care primete blocul de date;
Acest proces trebuie s fi creat n prealabil fereastra win printr-un
apel MPI Win create() laolalt cu toate procesele din
comunicatorul procesului apelant al MPI_Put().
target_displ, offset-ul de la nceputul ferestrei win la nceputul bufferului int;
target_count, numrul de obiecte (intrri) n buffer-ul int;

MPI-2 comunicare unilateral


- Funcii pentru comunicare unilateral
int MPI_Put ( void *origin_addr, int origin_count,
MPI_Datatype origin_type, int target_rank,
MPI_Aint target_displ, int target_count,
MPI_Datatype target_type, MPI_Win win);
Intrare : target_type, tipul de date din buffer-ul int; Blocul transferat este
stocat n RAM-ul procesului destinaie la adresa
target_addr := window_base + target_displ * displ_unit
(window_base este adresa ferestrei, displ_unit este offset-ul
dintre obiectele vecine, aa cum a fost el definit de procesul
destinaie la crearea ferestrei prin apelarea MPI Win create().
Ieire : codul de eroare POSIX

MPI-2 comunicare unilateral


- Funcii pentru comunicare unilateral
int MPI_Put ( void *origin_addr, int origin_count,
MPI_Datatype origin_type, int target_rank,
MPI_Aint target_displ, int target_count,
MPI_Datatype target_type, MPI_Win win);
Obs. :
Apelarea MPI_Put() de ctre procesul surs are acelai efect ca:
int MPI Isend (origin addr, origin count, origin type, target rank,
tag, comm)
la procesul surs i
int MPI Recv (target addr, target count, target type, source, tag,
comm, &status)
la procesul destinaie.

MPI-2 comunicare unilateral


- Funcii pentru comunicare unilateral
int MPI_Get ( void * origin_addr, int origin_count,
MPI_Datatype origin_type, int target_rank,
MPI_Aint target_displ, int target_count,
MPI_Datatype target_type, MPI_Win win);
Rol : transfer un bloc de date din fereastra altui proces ntr-un buffer local.
Intrare : origin_addr, adresa de nceput a buffer-ului local;
origin_count, numrul de obiecte de recepionat;
origin_type, tipul de date al obiectelor de recepionat;
target_rank, rangul procesului int, de la care se extrag datele,
din fereastra win, creat anterior. Adresa de nceput a blocului
de transferat din RAM-ul procesului int este:
target_addr = window_base + target_displ * displ_unit.
Ieire : codul de eroare POSIX

MPI-2 comunicare unilateral


- Funcii pentru comunicare unilateral
int MPI_Accumulate ( void * origin_addr, int origin_count,
MPI_Datatype origin_type, int target_rank,
MPI_Aint target_displ, int target_count,
MPI_Datatype target_type, MPI_Op op,
MPI_Win win);
Rol : acumuleaz date n memoria altor procese. Parametrul op definete
operaia de reducere aplicat pentru acumularea datelor (aceleai ca la
MPI_Reduce(), de exemplu MPI_SUM sau MPI_MAX. Spre deosebire de
MPI_Reduce(), nu pot fi folosite operaii de reducere definite de utilizator.
Exist o operaie suplimentar, MPI_REPLACE, care nlocuiete intrrile
din buffer-ul int (indiferent de valorile precedente).
Operaia de reducere este aplicat datelor din buffer-ul surs i din
buffer-ul destinaie, rezultatul fiind ntors n buffer-ul destinaie (furnizat de
un alt proces).
Intrare : parametrii de intrare au aceeai seminficaie ca n cazul MPI_Put().
Ieire : codul de eroare POSIX

MPI-2 comunicare unilateral


- Funcii pentru comunicare unilateral constrngeri:
- nu sunt permise accesri concureniale/conflictuale ale aceleiai
zone de memorie dintr-o fereastr. La orice moment pe durata execuiei
programului fiecare locaie de memorie a unei ferestre poate fi folosit
ca int de cel mult o singur operaie RMA;
- excepii pentru accesarea concurenial - operaiile de acumulare.
Operaii MPI_Accumulate() multiple pot fi executate simultan. Rezultatul
este precizat de ordinea operaiilor, valoarea acumulat fiind aceeai
ntruct operaiile de reducere predefinite sunt comutative.
- o fereastr a procesului P nu poate fi folosit concurenial de o operaie
MPI_Put() sau MPI_Accumulate() a altui proces I de o operaie local de
stocare a lui P, chiar dac sunt indicate locaii diferite din fereastr.

MPI-2 comunicare unilateral &


sincronizare
- Funcii pentru comunicare unilateral sincronizare global
Exist trei mecanisme de sincronizare pentru comunicrile unilaterale:
int MPI_Win_fence (int assert, MPI_Win win);
Rol : operaiile RMA lansate anterior de procesul apelant sunt finalizate LOCAL
nainte de redarea controlului ctre procesul apelant (la ieirea din funcie).
Este o operaie global, care trebuie efectuat de toate procesele din
grupul lui win. MPI_Win_fence() este utilizat pentru definirea segmentelor
de program n care sunt executat operaiile de comunicare unilateral.
Aceste segmente sunt mrginite de apeluri ale MPI_Win_fence(),
separnd etapele de comunicare (access epochs, AE) de etapele de
calcul pe durata crora nu este necesar comunicarea.
Intrare : assert, aseriuni specifice asupra contextului apelului (de exemplu,
assert = MPI_MODE_NOPRECEDE dac MPI_Win_fence() nu ncheie
un AE; de obicei assert = 0 );
win, fereastra definit de MPI_Win_create() anterior.
Ieire : codul de eroare POSIX

MPI-2 comunicare unilateral &


sincronizare
- Funcii pentru comunicare unilateral sincronizare global
int MPI_Win_fence (int assert, MPI_Win win);
Exemplu de utilizare :
while (!converged(A)) /* calcul self-consistent al structurii
* de date A */
{
update(A);
// opera ii local definite
update_buffer(A, source_buf); // opera ie definit local
MPI_Win_fence(0, win);
// bariera de nceput a unui AE
for (i=0; i<num_neighbors; i++)
MPI_Put(&source_buf[i], size[i], MPI_INT, neighbor[i],
dest_disp[i], size[i], MPI_INT, win);
MPI_Win_fence(0, win); // bariera de final a unui AE
}

MPI-2 comunicare unilateral &


sincronizare
- Funcii pentru comunicare unilateral sincronizare slab (liber)
- restrns la perechi de procese care comunic;
- procesul care solicit sincronizarea definete nceputul unui AE apelnd
MPI_Win_start() i finalul AE-ului apelnd MPI_Win_complete();
- procesul int definete segmentul corespunztor de expunere
(exposure epoch, EE) apelnd MPI_Win_post() (pentru a semnala
nceputul EE) i MPI_Win_wait() pentru a finaliza EE;
- sincronizarea este efectuat ntre MPI_Win_start() i MPI_Win_post() n
sensul c toate cererile RMA pe care procesul iniial le emite dup
MPI_Win_start() sunt finalizate DUP CE procesul int a finalizat
MPI_Win_post();
- la fel, sincronizarea este efectuat ntre MPI_Win_complete() i
MPI Win wait() n sensul c MPI_Win_wait() este finalizat de procesul
int DUP CE toate cererile RMA ale procesului iniial sunt finalizate

MPI-2 comunicare unilateral &


sincronizare
- Funcii pentru comunicare unilateral sincronizare slab
int MPI_Win_start (MPI_Group group, int assert, MPI_Win win);

Rol : definete nceputul EE a unui proces. Toate procesele din group trebuie
S apeleze perechea MPI_Win_post(). MPI suport implementarea de
tip blocking (controlul este redat procesului apelant cnd toate procesele
din group au finalizat MPI_Win_post()) i de tip non-blocking (controlul
este redat imediat procesului apelant, care poate efectua operaii RMA
precum MPI_Put() sau MPI Get(), care sunt ntrziate pn cnd procesul
int finalizeaz MPI_Win_post() ). Comportarea exact depinde de
Implementare (trebuie verificat local).
Intrare : group, grupul proceselor care acceseaz win;
assert, aseriuni specifice asupra contextului apelului;
win, fereastra definit de MPI_Win_create() anterior.
Ieire : codul de eroare POSIX

MPI-2 comunicare unilateral &


sincronizare
- Funcii pentru comunicare unilateral sincronizare slab
int MPI_Win_complete (MPI_Win win);
Rol : marcheaz sfritul EE a unui proces. ntre apelarea MPI_Win_start()
i MPI_Win_complete(), sunt permise doar operaii RMA cu fereastra
win a proceselor din group. Procesul apelant este blocat pn la
finalizarea operaiilor RMA.
Intrare : win, fereastra definit de MPI_Win_create() anterior.
Ieire : codul de eroare POSIX

MPI-2 comunicare unilateral &


sincronizare
- Funcii pentru comunicare unilateral sincronizare slab
int MPI_Win_post ( MPI_Group group, int assert, MPI_Win win );
Rol : procesul apelant indic startul unui EE pentru fereastra local win.
Doar procesele din group au acces la win pe durata EE. Fiecare din
procesele din group trebuie s efectueze apelarea perechii
MPI _Win_start(). MPI_Win_post() nu este de tip blocking.
Intrare : group, grupul proceselor cu acces la win;
assert, aseriuni specifice asupra contextului apelului;
win, fereastra definit de MPI_Win_create() anterior.
Ieire : codul de eroare POSIX

MPI-2 comunicare unilateral &


sincronizare
- Funcii pentru comunicare unilateral sincronizare cu blocare (lock)
int MPI_Win_wait (MPI_Win win);
Rol : procesul apelant indic sfritul unui EE pentru fereastra local win.
Procesul apelant este blocat pn cnd toate procesele din group
definite n apelul-pereche MPI_Win_post() au lansat apelurile
MPI_Win_complete() corespunztoare. Astfel este asigurat finalizarea
operaiilor RMA a tuturor proceselor n acest EE. La ieire, procesul
apelant poate reutiliza fereastra win local.
Intrare : win, fereastra definit de MPI_Win_create() anterior.
Ieire : codul de eroare POSIX

MPI-2 comunicare unilateral &


sincronizare
- Funcii pentru comunicare unilateral sincronizare slab
int MPI_Win_test (MPI_Win win, int *flag);

Rol : procesul apelant testeaz completarea operaiilor RMA la fereastra win


local. Este versiunea non-blocking a MPI_Win_wait(). Parametrul
flag=1 este returnat dac toate operaiunile RMA s-au terminat, caz n
care apelul nu trebuie repetat;
flag=0 este returnat dac nu toate operaiunile RMA sunt finalizate; apelu
poate fi repetat.
Intrare : win, fereastra definit de MPI_Win_create() anterior.
Ieire : flag, pentru semnalizarea gradului de finalizare a operaiilor RMA;
codul de eroare POSIX

MPI-2 comunicare unilateral &


sincronizare
- Funcii pentru comunicare unilateral sincronizare slab
Exemplu - acelai fragment de cod ca n cazul MPI_Win_fence():
while (!converged (A))
{
update(A);
update_buffer(A, source_buf);
MPI_Win_start(target_group, 0, win);
MPI_Win_post(source_group, 0, win);
for (i=0; i<num neighbors; i++)
MPI_Put(&source_buf[i], size[i], MPI_INT, neighbor[i],
to_disp[i], size[i], MPI_INT, win);
MPI_Win_complete(win);
MPI_Win_wait(win);
}

MPI-2 comunicare unilateral &


sincronizare
- Funcii pentru comunicare unilateral sincronizare cu blocare (lock)
Ideea: - implementarea modelului spaiului de adrese comun
- doar procesul care acceseaz acest mecanism poate executa
RMA
- se creeaz posibilitatea ca 2 procese s schimbe date via RMA
executat pe fereastra unui al treilea proces fr participarea activ
a acestuia din urm
- pentru evitarea conflictelor de acces spaiul comun de adrese
este blocat de procesul care l acceseaz nainte de operaia
de accesare propriu-zis i este deblocat dup finalizarea ei.

MPI-2 comunicare unilateral & sincronizare


- Funcii pentru comunicare unilateral sincronizare cu blocare (lock)

int MPI_Win_lock (int lock_type, int rank, int assert, MPI_Win win);
Rol : procesul apelant ncepe EE pentru RMA cu blocare pe fereastra win
definit de procesul cu rangul rank. Sunt definite dou tipuri de blocare
- unul exclusiv (lock_type = MPI_LOCK_EXCLUSIVE), care garanteaz
c operaiile RMA urmtoare ale procesului apelant sunt protejate de
operaiile RMA ale altor procese prin asigurarea accesului exclusiv la win
(utilizare tipic pentru MPI_Put() );
- unul non-exclusiv (lock_type = MPI_LOCK_SHARED), care garanteaz c
operaiile RMA urmtoare ale procesului apelant sunt protejate de operaii
exclusive ale altor procese (nu este permis modificarea intrrilor din win),
dar alte procese pot efectua RMA pe aceeai fereastr. Utilizare tipic:
pentru MPI_Get() sau MPI_Accumulate().
Intrare : lock_type, tipul de blocare; rank, rangul procesului apelant
assert, aseriuni pentru descrierea contextului MPI
win, fereastra definit de MPI_Win_create() anterior.
Ieire : codul de eroare POSIX

MPI-2 comunicare unilateral & sincronizare

- Funcii pentru comunicare unilateral sincronizare cu blocare (lock)


int MPI_Win_unlock (int rank, MPI_Win win);
Rol : procesul apelant termin EE pentru RMA cu blocare pe fereastra win
iniializat anterior de procesul cu rangul rank.
Intrare : rank, rangul procesului apelant
win, fereastra definit de MPI_Win_create() anterior.
Ieire : codul de eroare POSIX

MPI-2 comunicare unilateral & sincronizare


- Exemplu (acelai ca n cazul celorlalte dou mecanisme de sincronizare
while (!converged (A))
{
update(A);
update_buffer(A, source_buf);
MPI_Win_start(target_group, 0, win);
for (i=0; i<num neighbors; i++)
{
MPI_Win_lock(MPI_LOCK_EXCLUSIVE, neighbor[i], 0, win);
MPI Put(&source_buf[i], size[i], MPI_INT, neighbor[i],
to_disp[i], size[i], MPI_INT, win);
MPI Win unlock(neighbor[i], win);
}
}

Operatii de Input/Output (I/O) paralel

Materiale utile:
wiki.scinethpc.ca/wiki/images/0/01/Parallel_io_course.pdf
hssl.cs.jhu.edu/~randal/419/lectures/L15.ParallelIO.pdf
http://lisboa.lip.pt/computing/publications/2/wednesday/MPI_and_Parallel_IO-handout.pdf

Problema de I/O in cazul simularilor stiintifice


I/O este folosit pentru:
- stocarea rezultatelor numerice pentru analiza ulterioara
- citirea si stabilirea parametrilor initiali ai simularii
- salvarea periodica a datelor in cazul unei erori a sistemului
- folosirea discului in cazul in care memoria RAM este insuficienta
- in simularile moderne se poate ajunge si la operatii de I/O de ordinul sutelor
de TB
- componenta de I/O este in prezent o problema majora pentru centrele mari
de calcul deoarece este elementul cel mai lent al sistemului si nu poate fi
scalata la fel de usor ca puterea de calcul prin o simpla adaugare de noi
procesoare

I/O secvential (numai nodul 0 citeste/scrie)


Avantaje:
- trivial de folosit pentru sarcini mici de I/O
- poate fi folosit si de librarii de I/O care nu sunt paralele
Dezavantaje:
- limitat de transferul de date pe care il poate sustine un singur nod
- un singur nod poate avea memorie insuficienta pentru anumite sarcini
- nu scaleaza

N fisiere pentru N procese


Avantaje:
- nu este necesara coordonarea sau comunicarea intre procese
- poate scala mai bine ca I/O secvential
Dezavantaje:
- cresterea numarului de procese duce la aparitia multor fisiere de
dimensiune mica
- de multe ori, datele trebuie postprocesate intr-un singur fisier final
- citirea/scrierea necoordonata poate da peste cap sistemul de fisiere

Toate procesele acceseaza un singur fisier


Avantaje:
- existenta unui singur fisier
- datele pot fi stocate intr-un mod obisnuit, evitandu-se postprocesarea
- scalare eficienta daca sistemul este implementat corect
Dezavantaje:
- citirea/scrierea necoordonata poate da peste cap sistemul de fisiere
- este necesar o gandire mai atenta a programului

I/O paralel
Mai multe procese ale unui program paralel acceseaza un singur fisier comun

Avantaje:
- eficienta mai mare decat varianta neparalela prin operatii de I/O colective
- existenta unui singur fisier la oricare moment de timp (utila cand este
nevoie accesarea lui de catre alte aplicatii)
- compatibil cu modul de functionare propriu al sistemelor de fisiere

I/O contiguu si necontiguu


I/O contiguu inseamna mutarea (scrierea/citirea) dintr-un singur bloc de
memorie (RAM) intr-un singur bloc al fisierului (pe disc)
I/O pot fi necontigue in memorie, pe disc sau in ambele locatii
Pentru a putea face operatii de I/O necontigue folosind o singura comanda este
nevoie de un sistem de I/O mai complex

I/O independent sau colectiv


Operatiile de I/O independente specifica numai ce va face un singur proces si
implica o incapacitate de a urmari eficient carui proces ii este asociata o anume
operatie de I/O.
Operatiile de I/O colectiv reprezinta un mod de acces coordonat intre spatiul de
stocare si un grup de procese. Fiind un proces coordonat, se pot optimiza operatiile
de la nivelurile inferioare de software.

Exista mai mult optiuni pentru librariile de I/O:


MPI-IO: MPI-2 Language Standard
HDF (Hierarchical Data Format)
NetCDF (Network Common Data Format)
Adaptable IO System (ADIOS)

MPI-IO foloseste o structura similara cu MPI


Citirea primirea unui mesaj
Scrierea trimiterea unui mesaj
Aceesul la fisiere este grupat sub un comunicator operatii colective
Foloseste tipuri de date definite de utilizator, inclusiv tipuri necontigue
Latenta de I/O este ascunsa de MPI in acelasi mod ca cea de comunicare
Poate fi integral folosit prin chemari de functii

Functiile MPI-IO

Exemplu de folosire a
functiei de deschidere

Pentru a deschide un fisier este nevoie de:


- Un comunicator
- Numele fisierului
- Un handle prin care se utiliza in continuare fisierul
- Alegerea unui mod de accesare:
MPI_MODE_RDONLY
MPI_MODE_RDWR
MPI_MODE_WRONLY
MPI_MODE_CREATE
MPI_MODE_EXCL
MPI_MODE_DELETE_ON_CLOSE
MPI_MODE_UNIQUE_OPEN
MPI_MODE_SEQUENTIAL
MPI_MODE_APPEND

numai citire
citire si scriere
numai scriere
creeaza fisierul daca nu exista
intoarce eroare daca fisierul exista deja
sterge fisierul la inchiderea acestuia
protejeaza fisierul pentru a nu mai fi
deschis de mai multe ori simultan
fisierul va fi accesat in mod secvential
pozitioneaza toti pointerii de fisier la
sfarsitul acestui

- O structura info sau MPI_INFO_NULL

Etype, filetype, file view


MPI-IO foloseste anumite concepte pentru a usura accesul la fisiere:
- etype: permite accesul la fisiere in alte unitati in afara de octeti

- filetype: Fiecare proces trebuie sa defineasca ce parte a unui fisier comun va


folosi. Prin fileype se poate specifica o structura periodica din fisier. Este util
pentru acces necontiguu (pentru acces contiguu filetype=etype)
- deplasarea: punctul de la care un proces incepe accesul in fisier (masurat in
octeti)
Aceste trei concepte dau acces la o fereastra asupra fisierului (file view)
specificata prin functia MPI_File_set_view. Standarul este etype=filetype=MPI_BYTE si
deplasarea=o.

Stabilirea unei ferestre - file view


Se face cu ajutorul functiei MPI_File_set_view, care are prototipul:
MPI_File_set_view ( MPI_File fh, MPI_Offset disp, MPI_Datatype etype, MPI_Datatype
filetype, char *datarep, MPI_Info info );
Lista de argumente contine:
-disp: inceputul ferestrei
-etype si filetype (discutate anterior)
-datarep: modul de reprezentare a datelor
(utilizatorul poate crea o noua reprezentare
cu ajutorul functiei MPI_Register_datarep)
-info: structura pentru informatii
suplimentare

nativ: datele sunt stocate in


fisier exact cum erau si in
memorie
internal: reprezentare a datelor
pentru sisteme de calcul
heterogene cu aceeasi
versiunde de MPI-IO
external32: reprezentare
portabila valabila pe mai multe
platforme si variante de MPI-IO

In cazul operatiilor colective:


-datarep si etype trebuie sa coincida pentru toate procesele
-filetype, disp si info nu trebuie sa fie la fel pentru toate procesele
Operatia de MPI_File_set_view reseteaza in mod implicit pointerul de fisier la zero.

Functiile de citire din MPI-IO

Functiile de scriere din MPI-IO

Dupa deschiderea unui fisier si definierea unui file view, procesele pot citi si
scrie in mod independent in partea de fisier care le-a fost alocata.
Daca operatiile de I/O apar in mod periodic in program, la acelasi moment de
timp pentru fiecare proces, este mai eficienta folosirea unei rutine de I/O colectiv.
Operatiile de I/O individuale pot fi teoretic folosite de fiecare data, dar sunt mai
eficiente atunci cand scrierea/citirea nu este sincrona pentru intregul grup pentru ca
procesele nu se mai asteapta unele pe altele.

Indicii suportate de libraria MPI-IO in structura info


Indiciu

Explicatie

Posibile valori

access_style

Indica modul in care fisierul va fi


accesat

read_once, write_once,
read_mostly, write_mostly,
sequential,
reverse_sequential, random

collective_buffering

Folosirea unui buffer colectiv

true, false

cb_block_size

Dimensiunea blocului de date


pentru bufferului colectiv

Numar intreg

cb_buffer_size

Spatiul total care poate fi folosit


ca buffer colectiv

Numar intreg, multiplu de


cb_block_size

cb_nodes

Numarul de noduri care vor


folosi bufferul colectiv

Numar intreg

io_node_list

Lista de noduri folosite la I/O

Valori separate de virgula

nb_proc

Indica numarul de procese care


vor accesa fisierul

Numar intreg

num_io_nodes

Numarul de noduri pentru I/O


disponibile

Numar intreg

striping_factor

Numarul de noduri de I/O folositi


pentru imaprtirea datelor
(striping)

Numar intreg

striping_unit

Dimensiunea stripului

Numar intreg

Exemplu de operatie de I/O catre mai multe fisiere

Exemplu de operatie paralela de I/O catre un singur fisier

Exemplu de operatie citire a unui fisier

Thread-uri in programare
- Mai multe platforme de programare paralela, in particular
platformele multicore dispun de un spatiu de adresare comun;
- Un model de programare pentru aceste arhitecturi il reprezinta
un model de tip thread in care toate thread-urile au acces la
variabile comune. Aceste variabile comune sunt apoi folosite
pentru informare si schimb de date;
- Pentru a coordona accesul la variabilele comune, mecanismele
de sincronizare trebuie folosite astfel incat sa se evite conditiile de
concurenta in cazul accesarilor concomitente => de aceea
sincronizarea e de tip lock;
- Scopul acestui capitol: conceperea de programe in mod corect
si eficient care apoi sa poata fi folosite de exemplu pe arhitecturi
multicore.

Sumar:

- Creearea si unirea thread-urilor;


- Coordonarea thread-urilor cu Pthreads;
- Variabile de conditie;
- Mecanismul de Lock extins;
- Initializare unica;
- Implementarea unei Task Pool;
- Paralelism prin pipelining;
- Implementarea unui model client-server;

Programare cu Pthread-uri

Thread-urile POSIX (denumite si Pthread-uri) definesc un


standard pentru programarea cu thread-uri bazata pe limbajul
de programare C
Thread-urile procesului impart acelasi spatiu de adresare =>
variabilele globale si datele generate in mod dinamic pot fi
accesate de toate thread-urile procesului respectiv;

Fiecare thread in parte poate contine o stiva a lui cu


functiile si variabilele locale respective, care nu pot fi
accesate de alte thread-uri (stiva fiecarui thread este
stearsa dupa ce thread-ul respectiv se termina si de aceea
ar fi foarte periculos a pasa variabile locale de la un thread
la altul);

Libraria <pthread.h> contine tipurile de date,


definitiile de interfete si macro-urile Pthread-urilor;
Definitia unei functii este sub forma:
pthread[ <object>] <operation> ()

Toate functiile Pthread returneaza valoarea 0 daca se


executa in mod corect;
In cazul in care apare o eroare in timpul executiei unui
Pthread, un cod eroare din libraria <error.h> va aparea;
Tipuri de date ale thread-urilor Pthread:

Crearea si combinarea thread-urilor

Cand un thread de tip Pthread este pornit, un singur thread de tip main este
activ care executa functia main() si acesta poate genera mai multe thread-uri
apeland functia:

Un thread poate sa identifice thread-ul care l-a apelat folosit functia:


pthread_t pthread_self();
Pentru a compara id-urile a doua thread-uri se poate folosi functia:
int pthread_equal( pthread_t t1, pthread_t t2);

Standardul Pthread-urilor determina ca 64 de thread-uri pot fi generate de


orice proces;

Numarul maxim de thread-uri care poate fi pornit poate fi


determinat apeland functia:

maxThreads = sysconf(_SC_THREAD_THREADS_MAX),
daca aceasta limita este atinsa, un apel al functiei
pthread_create() returneaza o eroare cu valoarea EAGAIN;

Un thread poate sa astepte terminarea altui thread apeland


functia:
int pthread_join(pthread_t thread, void **valuep);

Un thread se termina daca functia lui se termina, apeland


return;
Un thread se poate termina explicit apeland functia:
void pthread_exit(void *valuep)

Functia pthread_join() ofera posibilitarea


sincronizarii thread-urilor: daca mai multe threaduri asteapta terminarea aceluiasi thread, ele sunt toate
blocate pana la terminarea respectivului thread, iar
apoi doar unul dintre ele va obtine valoarea returnata a
acestei functii, iar toate celelalte thread-uri vor avea ca
valoare returnata eroarea cu valoarea ESRCH;
Daca functia pthread_join() nu exista pentru un
anume thread, structura lui interna nu este eliberata
dupa terminarea lui si aceasta va ocupa in continuare
memoria pana la terminarea intregului program;
Functia care notifica sistemul runtime ca structura
interna a unui thread poate fi stearsa imediat ce
thread-ul respectiv s-a terminat este:
int pthread_detached(pthread_t thread);

Coordonarea thread-urilor folosind


Pthreads

Thread-urile unui proces impart memoria


astfel incat pot accesa in mod concurent
aceleasi variabile => accesul concurent
trebuie coordonat folosind:

1. Variabile Mutex

2. Variabile de conditie

Variabilele Mutex

Variabile Mutex = o structura de date a tipului predefinit


opac pthread_mutex_t ;
Un astfel de tip de variabila poate fi folosita pentru a
asigura excluderea mutuala
O variabila Mutex are 2 stari: - locked
- unlocked

Inainte ca o variabila Mutex sa fie folosita, ea trebuie


initializata:

- statica:
- dinamica:

Variabilele Mutex

O variabila mutex se poate distruge cu:

Se poate aplica lock pe o variabila mutex cu:

Variabila mutex se poate debloca (unlock):

Se poate verifica, fara blocare daca variabila este


blocata de un alt thread:

Variabile mutex si situatii de deadlock


- Cand threaduri multiple lucreaza cu diferite structuri de date, care fiecare
este protejata de cate o variabila mutex, trebuie avute in vedere aparitia
situatiilor de deadlock;
- 2 threaduri T1 si T2, 2 variabile mutex ma si mb:
- T1 blocheaza ma si apoi mb;
- T2 blocheaza mb si apoi ma;
deadlock, daca T1 blocheaza pe ma, dar nu si pe mb,
In timp de T2 blocheaza pe mb;
- Solutie: fixed locking order;
- fiecare thread blocheaza varibilele mutex critice intotdeauna in
aceeasi ordine;
- Se poate folosi strategia de backoff:
- fiecare thread isi poate bloca variabilele mutex in ordine arbitrara,
dar in schimb, un thread care nu reuseste sa blocheze o variabila trebuie
sa deblocheze toate variabilele pe care le-a blocat anterior;
- dupa backoff, threadul reia procesul incecand sa blocheze prima
variabila mutex;

Variabile de conditie
- Variabilele mutex se folosesc in mod tipic pentru a asigura excluderea
mutuala cand sunt accesate structuri de date globale in maniera
concurenta;
- Variabilele mutex se pot folosi si pentru a astepta ca o anumita conditie
sa fie indeplinita;
- Exemplu:
- un buffer din care un thread consumer poate sa extraga sarcini doar
daca bufferul nu este gol;
- structura este protejata de una (mai multe) variabile mutex;
- pentru a verifica conditia, un thread aplica un lock pe variabila
mutex si evalueaza conditia;
- daca este satisfacuta conditia operatia este efectuata;
- daca nu, lock-ul este eliberat si se reia procesul dupa un timp;
- dezavantaj: threadul care asteapta trebuie sa repete evaluarea,
consumand timp de procesare (active waiting);
- pentru a avea o metoda mai eficienta se foloseste, Pthreads pune la
dispozitie variabile de conditie (condition variable)

Variabile de conditie
- O variabila de conditie este o structura de date opaca, care permite unui
thread sa astepte indeplinirea unei conditii, fara asteptare activa;
- Aceasta se realizeaza printr-un mecanism de semnalizare, care
blocheaza executia thread-ului, in asa fel incat el nu consuma timp CPU;
- Thread-ul este reactivat de indata ce conditia este indeplinita;
- Pentru a folosi mecanismul, threadul defineste o variabila mutex si una
de conditie;
- O varibiala de conditie are tipul : pthread_cond_t
- Initializarea se face cu :
unde: cond este adresa variabilei de conditie;
attr este adresa unei structuri de date ce contine atribute
pentru variabila de conditie;

Variabile de conditie
- Folosind attr=NULL se obtine initializarea default;
- pentru varibile statice se poate folosi pentru initializare:

- O variabila de conditie initializata poate fi distrusa cu:

- Fiecare variabila de conditie trebuie asociata in mod unic cu o variabila


mutex;
- Un thread aplica lock pe variabila mutex asociata cu functia:

Variabile de conditie
- Un bloc de cod standard pentru utilizarea variabilelor de conditie este de
tipul :

- Evaluarea conditiei si apelul functiei pthread_cond_wait() sunt protejate


de variabila mutex, pentru a ne asigura ca aceasta conditie nu se schimba
intre evaluare si apelul functiei pthread_cond_wait();
- Este posibil ca un alt thread sa schimbe valoare unei varibile
care este folosita in aceasta conditie;
- De aceea, fiecare thread trebuie sa foloseasca aceeasi variabila
mutex, pentru a proteja fiecare varaibila din conditie;

Variabile de conditie
Observatii :
1. - daca este indeplinita conditia, functia pthread_cond_wait() nu este
apelata;
- threadul elibereaza variabila mutex si trece la executia in continuare
a programului;
2. - daca nu este indeplinita conditia, se apeleaza pthread_cond_wait()
- variabila mutex este eliberata, iar threadul este blocat;
- se asteapta din partea unui alt thread sa apeleze functia
pthread_cond_signal() pentru a notifica threadul blocat, ca acea
conditie este indeplinita;
- cand un threadul este activat, el incearca sa aplice lock pe variabila
mutex;
- daca un alt thread a blocat acea variabila mutex, threadul este blocat
din nou si asteapta eliberarea variabilei mutex;
- in momentul in care poate exercita lock pe variabila mutex, continua
executia programului;

Mecanism de lock extins


- Consideram un mecanism de lock read/write ca un exemplu prin care se
extinde mecanismul standard de lock pus la distpozitie de variabilele
mutex uzuale;
- Se definesc read/write locks de catre user, care permit accesul unui nr.
arbitrar de threaduri pentru citire, insa avem un singur thread care are
acces pentru a scrie;
Implementare:
- Se definesc variabile de tip r/w locks;
- num_r nr. de permisiuni de tip read;
- num_w ar trebuie sa aibe valoarea maxima 1;
- variabila mutex protejeaza accesul la num_r si num_w;
- variabila de conditie cond coodoneaza accesul la variabila de r/w;

Initializare unica
- In unele situatii este util sa se efectueze o singura operatie, indiferent
cate threaduri sunt implicate;
- Exemplu: operatii de initializare sau deschiderea unui fisier;
- O initializare unica (one-time) se poate obtine folosind o variabila
booleana initializata la 0 si protejata de o variabila mutex;
- Primul thread care ajunge sa efectueze operatia one-time seteaza
variabila la 1, care este protejata de mutex, si efectueaza operatia;
- Oricare alt thread care ajunge in punctul respectiv, gaseste valoare 1 si
nu va mai efectua operatia;
- Pthread pune la dispozitie o alta solutie, folosind o variabila de de
control predefinita de tip pthread_once_t;

Initializare unica
- Variabila de control se initializeaza cu :
- Codul care efectueaza operatia one-time trebuie pus intr-o functie
separata fara parametrii; numim aceasta fucntie once_routine();
- Operatia one-time se efectueaza cu ajutorul functiei:

Observatii:
- aceasta functie poate fi apelata de mai multe threaduri;
- daca executia a fost incheiata se returneaza controlul threadului;
- daca executia rutinei once_routine() nu a fost inceputa, atunci va fi
executata de threadul curent;
- daca executia rutinei a fost inceputa de un alt thread, dar nu a fost
finalizata, atunci threadul care executa pthread_once() asteapta pana
cand celalalt thread a terminat executia rutinei once_routine().

Implementarea unui task pool


- Intr-un program paralel, avem de rezolvat o succesiune de sarcini (tasks);
- O structurare simpla ar presupune asocierea unui task catre un thread; In
functie de granularitatea sarcinilor, aceasta schema poate conduce la
generarea unui numar mare de threaduri overhead semnificativ !
- O implementare eficienta se obtine folosind un task pool;
- Task pool : o structura care contine sarcinile pregatite spre a fi executate;
Pentru executarea sarcinilor se foloseste un numar fix de thread-uri;
In timpul executiei unei sarcini se pot genera noi sarcini, care urmeaza a fi
inserate in task pool; Programul termina atunci cand nu mai exista nici o
sarcina in task pool;
Avantaje:
- un nr. fixat de thread-uri este utilizat, indiferent de numarul de sarcini;
- sarcinile pot fi generate dinamic, ceea ce permite realizarea unor aplicatii
adaptative si iregulare;

Implementarea unui task pool


Structuri implicate:
- o sarcina este reprezentata de tipul de date work_t;

- routine : functia care contine codul aferent sarcinii;


- arg : argumentele functiei routine;
- sarcinile sunt organizate sub forma unei liste legate, unde next este un
pointer catre urmatoarea sarcina din lista;

Implementarea unui task pool


- tipul de date tpool_t reprezinta task pool:

- contine pointerii head si tail corespunzatori primei si ultimei sarcini din


lista;
- num_threads specifica numarul de thread-uri;
- vectorul threads contine thread ID-uri;
- max_size specifica numarul maxim de sarcini;
- current_size specifica numarul curent de sarcini din task pool;

Implementarea unui task pool


- Implementare:

Implementarea unui task pool

- Variabila mutex lock asigura excluderea mutuala atunci cand se incearca


accesarea concomintenta a task pool-ului de mai multe thread-uri;
- daca un thread acceseaza task pool care nu contine sarcini este blocat
de variabila not_empty;
- daca un thread insereaza o sarcina intr-un task pool gol este activat
threadul care este blocat anterior de not_empty;
- daca un thread incearca sa insereze un thread intr-un task pool plin
este blocat de variabila not_full;
- daca un thread primeste o sarcina din task-pool plin este activat threadul care a fost blocat anterior de not_full;

Implementarea unui task pool


- Functia tpool_init() initializeaza task pool, prin alocarea structurii de date si
initializarea cu valorile puse la dispozitie;
- thread-urile sunt generate si ID-urile sunt stocate in:
tpl->threads[i] for i=0, , num_threads-1
- fiecare din aceste thread-uri foloseste functia tpool_thread();
- functia tpool_thread( void *arg) foloseste un singur argument, care
specifica structura de date asociata task pool-ului;
- executia sarcinilor se desfasoara intr-o bucla infinita; in fiecare iteratie, o
sarcina este extrasa din capul listei de sarcini;
- daca task pool = empty thread-ul este blocat;
- daca task pool != empty o sarcina w1 este extrasa;
- daca task pool era plina inainte de extragerea w1 toate thread-urile
blocate prin not_full sunt activate prin pthread_cond_broadcast();
- accesul la task pool este protejat de variabila mutex tp1->lock;
- sarcina w1 este executata de functia w1->routine() , folosind w1->arg;
- sarcini noi care apar in urma executiei w1 se vor insera cu functia
tpool_insert();

Implementarea unui task pool


- tpool_thread()

Implementarea unui task pool


- tpool_insert()
- este utilizat pentru a insera sarcini in task pool;
- daca task pool = full threadul care executa functia este blocat;
- daca task pool != full un thread care este blocat de not_empty este
activat, prin pthread_cond_signal();
- accesul la task pool tp1 este protejat prin variabila tp1->lock
Observatii:
- implementarea este potrivita pentru un model de tip master-worker;
- un thread master foloseste tpoll_init(), pentru a genera un numar de
thread-uri de tip worker, care executa tpool_thread();
- dupa ce executia sarcinilor s-a incheaiat, threadul master trimite semnal
de terminare pentru threadurile de tip worker thread-ul master va activa
toate thread-urile blocate de conditiile not_empty si not_full si apoi le va
termina;

Implementarea unui task pool


- tpool_insert()

OpenMP
- Este un standard portabil pentru programare in cazul sistemelor cu
memorie partajata;
- OpenMP API (application program interface) pune la dispozitie o colectie
de directive de compilator, rutine de librarie si variabile de environment;
- Directivele de compilator se folosesc pentru a extinde limbaje secventiale
de tip Fortran, C, C++ implementate prin single program multiple data
(SPMD)
- Sunt suportate date de tip shared si private;
- Standardul OpenMP a fost dezvoltat in 1997 si mentinut de OpenMP
Arhitecture Review Board (ARB)
- Modelul de programare OpenMP se bazeaza pe thread-uri care ruleaza
simultan pe sisteme multi-core, multi-procesor; thread-urile sunt create si
distruse in maniera de tip fork-join;

OpenMP
- Executia unui program OpenMP incepe cu un singur thread (thread-ul
initial) care executa programul secvential pana cand un prim construct
paralel este intalnit;
- In acest punct, thread-ul initial creeaza o serie de thread-uri noi, formand o
echipa de thread-uri; Thread-ul initial devine master in echipa;
- Operatia de fork este realizata implicit;
- Zona de program in interiorul construct-ului paralel se numeste parallel
region;
- La sfarsitul unei regiuni paralele se afla o bariera de sincronizare implicita;
Doar masterul va continua executia programului;
- Regiunile paralele se pot regasi in alte regiuni paralele (nested);

OpenMP

- OpenMP distinge intre memorie de tip shared si memorie privata;


- Toate thread-urile OpenMP au acces la aceeasi memorie de tip shared;
- Pentru a evita conflicte, race conditions, deadlocks, sunt implicate
mecanisme de sincronizare, pentru care OpenMP pune la dispozitie librarii
corespunzatoare;
- Intr-un program OpenMP se include header-ul omp.h;
- Dupa compilare, codul este transormat in varianta multi-threaded;
Ex. gcc cu optiunea -fopenmp

OpenMP

Directive de compilator:
- In OpenMP paralelismul este controlat prin directive de compilator; Pentru
C si C++ aceste directive sunt specificate prin mecanism #pragma
- Forma generala a unei directive OpenMP este:
#pragma omp directive [clauses [ ] ]
scrisa pe o singura linie; clauzele sunt optionale si sunt folosite pentru a
influenta o directiva;

OpenMP
Regiunea paralela:
- cea mai importanta directiva este contruct-ul paralel :
#pragma omp parallel [ clause [ ] ]
{ // structured block }
- in acest fel se specifica care parte a unui program se executa in paralel;
- se asigneaza un thread ID pentru fiecare, incepand cu 0=master;
- construct-ul paralel asigura creearea echipei de thread-uri, dar nu
distribuie sarcina catre thread-uri;
- daca nu exista o distribuire explicita a sarcinii, fiecare thread executa
acelasi cod cu date diferite (SPMD)

OpenMP
- pentru a executa diferite instante se foloseste thread ID
- este returnat de functia:
int omp_get_thread_num()
- numarul de thread-uri poate fi setat cu clauza
num_threads ( expression )
- nr. de thread-uri in echipa curenta:
int omp_get_num_threads()
- clauzele dintr-o directiva paralela includ clauze care specifica daca datele
sunt private sau de tip shared intre diferitele thread-uri
private(lista_de_variabile)
- o variabila noua este creeata pentru fiecare thread si accesata doar
de thread-ul respectiv;

OpenMP
- similar, clauza
shared ( lista_de_variabile )
- clauza default poate fi folosita pentru a specifica tipul varibilelor in
regiunea paralela:
default( shared )
sau prin
default( none )
Fiecare variabila in construct este specificata explicit drept shared sau
private.

OpenMP

OpenMP
Bucle paralele:
#pragma omp for [clause [clause] ]
for ( i = lower_boun; i op upper_bound; incr_expr) {
{ // loop iterate }
}
Unde op : <, <=, >, >=
incr_expr : ++i, i++, etc
- distributia itaratiilor catre thread-uri se face printr-o strategie de
scheduling;
- Strategii de scheduling:
- schedule( static, blocksize)
- schedule( dynamic, blocksize)
- schedule( guided, blocksize)
- schedule( auto)
- schedule( runtime)

OpenMP
- Strategii de scheduling:
- schedule( static, blocksize)
- in maniera round-robin (time slices);
- schedule( dynamic, blocksize)
- un nou bloc este asignat unui thread indata ce acesta se
elibereaza;
- schedule( guided, blocksize)
- presupune asignarea dinamica a blocurilor, folosind
dimensiuni din ce in ce mai mici;
- blocksize = nr iteratii ramase / nr. thread-uri
- schedule( auto)
- decide compilatorul sau runtime system
- schedule( runtime)
- se decide la runtime:
- exista o variabila OMP_SCHEDULE
set OMP_SCHEDULE dynamic, 4
set OMP_SCHEDULE guided

OpenMP

S-ar putea să vă placă și