Documente Academic
Documente Profesional
Documente Cultură
Curs ASCP
Curs ASCP
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
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;
Utilizarea unor retele, platforme virtuale pentru a colabora in cadrul unui proiect
Exemplu: http://www.accessgrid.org/
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;
Supercomputere
Programare paralela
Partitionarea problemei
Programare paralela
Presupune utilizarea simultana a resurselor de calcul
multiple pentru rezolvarea unei probleme de calcul:
Concepte de baza
Concepte de baza
Concepte de baza
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;
UNIVAC1
IBM 360
CDC 7600
PDP1
CRAY-1
ILLIAC IV
Cray X-MP
MasPar
Cray Y-MP
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!
- 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;
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
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;
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
Design ierarhic
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
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;
- diametrul:
- grad = 2d;
- conectivitate nc = ec = d;
O varianta: torul d-dimensional
- conditii periodice;
- diametrul:
- grad = 2d;
- conectivitate nc = ec = 2d;
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.
unde
n=n1n2
noduri
- Observatie:
- elementele de pe linii / coloane constituie siruri RGC
unde
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
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;
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;
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:
Tipuri de rutare
Retea bidimensionala:
- Observatie:
- doua din cai nu sunt minimale;
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.
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
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;
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;
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 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.
Operatii de comunicare
Single broadcast:
- un singur procesor Pi trimite un bloc de date catre mai multe
procesoare; Pi se numeste procesor root;
Operatii de comunicare
Single accumulation:
- fiecare procesor pune la dispozitie un bloc de date de acelasi tip si
aceeasi marime;
Operatii de comunicare
Gather:
- fiecare procesor pune la dispozitie un bloc de date ;
Operatii de comunicare
Scatter:
- un anume procesor (root) pune la dispozitie cate un bloc de date
pentru fiecare procesor ;
Operatii de comunicare
Multi-broadcast:
- operatia este echivalenta cu o serie de operatii single-broadcast
efectuate de fiecare procesor;
Operatii de comunicare
Multi-accumulation:
- fiecare procesor executa o operatie de tip single-accumulation ;
Operatii de comunicare
Total exchange:
- fiecare procesor pune la dispozitia oricarui alt procesor un bloc
posibil diferit ;
Single-accumulation:
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.
Observatie:
- fiecare proces executa mai intai o operatie de tip Receive,
astfel incat fiecare va astepta date indefinit;
Observatie:
- operatiile Send sunt de tip blocking!
- in exemplul de mai sus nu apare situatia de deadlock daca sunt
utlizate bufferele sistemului ;
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!
- operatia MPI_MINLOC :
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() ;
Comunicatori MPI
MPI_Group group1,
MPI_Group group2,
MPI_Group * new_group
);
);
MPI_Group group1,
MPI_Group group2,
MPI_Group * new_group
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 )
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 );
Topologii de procese
Funcii de conversie:
int MPI_Cart_coords(MPI_Comm comm,int rank,int ndims,int * coords);
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);
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);
deplasarea tipului 0
tipul predefinit 1
deplasarea tipului 1
...
...
...
newtype
2 elemente/bloc
...
newtype
2 elemente/bloc
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
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
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
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
Functiile MPI-IO
Exemplu de folosire a
functiei de deschidere
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
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.
Explicatie
Posibile valori
access_style
read_once, write_once,
read_mostly, write_mostly,
sequential,
reverse_sequential, random
collective_buffering
true, false
cb_block_size
Numar intreg
cb_buffer_size
cb_nodes
Numar intreg
io_node_list
nb_proc
Numar intreg
num_io_nodes
Numar intreg
striping_factor
Numar intreg
striping_unit
Dimensiunea stripului
Numar intreg
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:
Programare cu Pthread-uri
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:
maxThreads = sysconf(_SC_THREAD_THREADS_MAX),
daca aceasta limita este atinsa, un apel al functiei
pthread_create() returneaza o eroare cu valoarea EAGAIN;
1. Variabile Mutex
2. Variabile de conditie
Variabilele Mutex
- statica:
- dinamica:
Variabilele 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:
Variabile de conditie
- Un bloc de cod standard pentru utilizarea variabilelor de conditie este de
tipul :
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;
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().
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
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