Sunteți pe pagina 1din 228

ARHITECTURI PARALELE

DE CALCUL
O compilaie de
Gheorghe M.Panaitescu
Universitatea Petrol-Gaze Ploiesti
Catedra Automatic si calculatoare
2009
1
2
INTRODUCERE
n editia din anul universitar 2006-2007, cursul de Arhitecturi paralele de
calcul s-a bazat n cea mai mare parte pe cteva tutoriale publicate pe Internet
de Lawrence Livermore National Laboratory, California, Statele Unite ale
Americii, sub semntura lui Blaise Barney.
Toate aceste lectii dense si concise cititorul le poate gsi n versiunea lor
original la adresa http://www.llnl.gov/computing/tutorials/.
Au fost traduse si pe alocuri completate cu informatii din alte surse trei
tutoriale:
Introduction to Parallel Computing (ultima actualizare: iulie 2006)
OpenMP (ultima actualizare: august 2006)
Message Passing Interface (MPI) (ultima actualizare: iulie 2006)
Figurile din text sunt, toate, reproduse de acolo.
Au fost atasate acestor informatii cteva din lectiile tinute de Kathy Yelik
(http://www.cs.berkeley.edu/~yelick/cs267/) la Universitatea din Berkeley,
California, Statele Unite ale Americii, si anume acele lectii care se refer la
structurile hardware si la modelele principale de programare. Din loc n loc, si
continutul acestor lectii a fost prelucrat, uneori prescurtat, alteori adugat, pe
baza altor lecturi din surse similare.
Asadar, cititorul nu trebuie s se astepte la vreo urm de originalitate din partea
autorului acestei juxtapuneri de texte si de material grafic. Ar fi si absurd a cere
aa ceva ntr-un domeniu cu o dinamic extraordinar, care n Romnia, n
particular la Ploieti cunoate abia pasii de nceput.
Alctuirea acestui suport pentru cursul Arhitecturi paralele de calcul nu a fost
lipsit de dificultti.
Prima dificultate si poate cea mai important a constat n selectarea temelor
care urmau a fi incluse n cadrul dat de programa analitic a cursului prevzut a
se derula pe durata a 42 de ore. Pentru aceasta, autorul a citit (aproape de
necrezut) cteva mii de pagini aprute pe parcursul a circa 10 ani. Unele dintre
ele, cteva sute au fost si traduse n limba romn. n aceste conditii nu se poate
afirma cu certitudine c aceast versiune a cursului, a treia, este cea optim. Ar
putea fi cel mult un punct de plecare n realizarea versiunilor urmtoare prin
procedeul de-acum familiar copy-and-paste.
A doua dificultate a constituit-o traducerea nssi. Sunt termeni care nu au nc
echivalene stabile n romneste si, n plus, textele de specialitate n limba
englez abund n acronime a cror semnificatie nu poate fi descoperit
3
totdeauna contextual. Termenii greu traductibili au fost lsati n forma lor
original, nu de putine ori acompaniati de explicatii detaliate, sau au fost lsati
s dubleze traducerile lor n limba romn, uneori aproximative. Pentru
prescurtri si acronime s-au folosit dictionare on-line de tipul celor accesibile la
adresa de Internet primar http://www.thefreedictionary.com/. Rmne de
discutat dac din multiplele semnificatii ale unui acelasi acronim a fost retinut
de fiecare dat cea potrivit.
Subiectele tratate de reuniunea celor trei tutoriale mentionate mai devreme si de
adaosul amitit sunt de natur a familiariza studentii cu principiile generale ale
calculului paralel si cu structurile hardware care le suport. Sunt date, de
asemenea, elemente destul de cuprinztoare privind producerea de software,
realizarea de aplicatii pentru cele dou arhitecturi paralele majore, cea cu
memorie partajat si cea cu memorie distribuit. Standardele OpenMP,
respectiv MPI asociate celor dou arhitecturi fundamentale sunt cuprinse n
liniile lor directoare majore. Cu elementele explicate n cele dou tutoriale
dedicate, studentii pot elabora propriile lor programe destinate executrii n
paralel ntr-una sau alta dintre conjuncturile hardware mentionate.
Structurile hardware acoperite prin acest suport de curs dau o idee destul de
cuprinztoare asupra stadiului curent si asupra tendintelor dezvoltrii calculului
paralel n lume. Pentru detalii nc mai actuale, cititorul interesat n domeniu
poate accesa site-ul http://www.top500.org/.
C U P R I N S U L
INTRODUCERE N CALCULUL PARALEL 5
OpenMP 54
MPI - MESSAGE PASSING INTERFACE 102
MASINI PARALELE SI MODELE DE PROGRAMARE 153
MASINI PARALELE CU MEMORIE PARTAJAT 168
CALCULATOARE CU MEMORIE DISTRIBUIT 185
SURSE DE PARALELISM 202
4
INTRODUCERE N CALCULUL PARALEL
Ce este calculul paralel?
Traditional, programele de calcul s-au scris ndeobste n perspectiva unei
executri secventiale sau seriale. S-au scris pentru a fi rulate pe un calculator
care are o singur unitate central de procesare. n aceste mprejurri,
problemele sunt rezolvate printr-o secvent de instructiuni executate de unitatea
central una cte una. O singur instructiune poate fi n executie la un moment
dat.
n ntelesul cel mai simplu, calculul paralel const n utilizarea concomitent a
unor resurse multiple pentru a rezolva o problem de calcul. Resursele acestea
pot fi:
Un singur calculator cu mai multe procesoare
Un numr arbitrar de calculatoare conectate de o retea de comunicatie
O combinatie a acestora.
Problema de calcul trebuie s exhibe uzual caracteristici de genul:
Posibilitatea de a fi divizat n prti care pot fi rezolvate concomitent
Posibilitatea de a fi executate n oricare moment instructiuni multiple
Perspectiva de a fi rezolvat n timp mai scurt pe resurse de calcul
multiple dect pe o resurs standard unic.
Calculul paralel este o versiune extins a calculului secvential, versiune care
ncearc s imite ceea ce se ntlneste frecvent n natur: multe ntmplri
complexe si corelate se produc n acelasi timp desi sunt n sine secventiale.
Cteva exemple:
Orbitele planetare si galactice, parcurgerea lor de corpurile ceresti
Formele de manifestare ale oceanului planetar si evolutia vremii
Deplasarea plcilor tectonice
Traficul ntr-un oras mare la ore de vrf
Linia de asamblare a unui tip de automobil
Operatiile zilnice n cadrul organizatoric al unei afaceri
Construirea unui centru comercial
Comandarea unui hamburger la un local quick-food
Traditional, calculul paralel a fost considerat nivelul de sus al calculului si a
fost motivat prin simulrile numerice ale unor sisteme complexe si prin mari
provocri n domeniul calculului cum sunt:
5
Prezicerea vremii si a climei
Modelarea reactiilor chimice si nucleare
Transformarea genomului uman si al altor specii
Activitatea geologic si seismic
Proiectarea dispozitivelor mecanice de la proteze la nave spatiale
Modelarea/proiectarea circuitelor electronice
Conducerea proceselor de productie
n zilele noastre, aplicatiile comerciale dau o fort motoare cel putin egal
pentru dezvoltarea calculatoarelor din ce n ce mai rapide. Aceste aplicatii cer
procesarea unor volume mari de date n moduri foarte rafinate. Exemple:
Bazele de date paralel, data-mining
Explorrile geologice
Motoarele de cutare, serviciile comerciale bazate pe Internet
Diagnosticarea medical ajutat de calculator
Managementul corporatiilor nationale si multinationale
Grafic avansat si realitatea virtual, n particular n industria de
entertainment
Tehnologiile video si multimedia n retele
Medii de lucru n cooperare
n ultim instant, calculul paralel este o ncercare de a face timpul elastic: el
pare a fi infinit dar niciodat nu pare a fi suficient.
De ce se utilizeaz calculul paralel?
Sunt dou motive principale pentru care se utilizeaz calculul paralel:
Economia de timp timpul indicat de ceasul din perete
Rezolvarea unor problema de mare amploare
Alte ratiuni pot fi:
A profita de resurse altele dect cele locale (cnd acestea sunt limitate)
prin utilizarea unor resurse dintr-o retea mai larg, situate poate chiar pe
Internet
Economii la costul calculelor prin utilizarea unor resurse multiple
ieftine n loc de a plti timpul consumat pe un supercalculator
Depsirea restrictiilor de memorie: calculatoarele singure au posibilitti
de memorare fatalmente limitate; pentru probleme de amploare, pentru
a depsi acest obstacol paralizant se poate apela la memoriile mai
multor calculatoare.
n limitarea posibilittilor de calcul secvential, n calea aparent simpl a
construirii de calculatoare din ce n ce mai rapide apar restrictii att de natur
fizic ct si de natur practic:
6
Viteza de transmitere depinde direct de ct de repede se pot deplasa
datele prin structura hardware. Limite absolute sunt viteza luminii (30
cm/ns) si limita de transmitere prin fire de cupru (9 cm/ns). Vitezele mai
mari necesit cresterea apropierii dintre elementelele procesoare.
Limitele miniaturizrii: tehnologia procesoarelor permite un numr n
crestere de tranzistoare pe un acelasi cip. Cu toate acestea, chiar cu
componente la nivelul dimensiunilor moleculare sau atomice se atinge o
limit a miniaturizrii de nedepsit.
Limite economice: este din ce n ce mai costisitor s se produc
procesoare unice nc si nc mai rapide. Prin utilizarea unui numr
mare de procesoare ieftine si moderat de rapide, se pot obtine acelesi
performante (sau poate mai bune) la un cost mai redus.
Despre viitor: trendul ultimilor zece ani caracterizat de retele mai rapide dect
nainte, de sisteme distribuite si de arhitecturile cu multe procesoare (chiar la
nivelul calculatoarelor mici) sugereaz c paralelismul este viitorul calculului.
Concepte si terminologie
Arhitectura von Neumann
De peste 40 de ani, aproape toate calculatoarele au urmat un model comun de
masin cunoscut sub numele matematicianului maghiar John von Neumann.
Un calculator von Neumann utilizeaz conceptul de program memorat. Unitatea
central execut un program depus n memorie care indic secventa de operatii,
de lectur si de scriere din/n memorie.
Schema de baz:
Memoria este utilizat pentru a stoca att instructiunile programului ct
si datele
Instructiunile sunt un gen de date codate care spun calculatorului s
execute ceva anume
7
Datele sunt informatii pe care le utilizeaz programul
O unitate central de procesare (CPU) preia instructiuni si/sau date din
memorie, decodeaz instructiunile si apoi le execut secvential.
Clasificarea clasic dup Flynn
Exist modalitti diferite de a clasifica calculatoarele paralel. Una din cele mai
utilizate, n uz din 1966, este clasificarea lui Flynn. Clasificarea Flynn face
distinctie ntre arhitecturile calculatoarelor cu mai multe procesoare n raport cu
dou caracteristici independente, instructiunile si datele. Fiecare din aceste
caracteristici poate avea una din dou stri: unice sau multiple. Tabelul de mai
jos defineste cele patru clase posibile potrivit criteriilor lui Flynn.
SISD
Single instruction, single data
(instructiune unic, date unice)
SIMD
Single instruction, multiple data
(instructiune unic, date multiple)
MISD
Mutiple instruction, single data
(instructiune multipl, date unice)
MIMD
Multiple instruction, multiple data
(instructiune multipl, date multiple)
SISD:
Un calculator secvential (neparalel)
Instructiune unic: un flux de numai o instructiune este executat de
unitatea central n fiecare moment, n fiecare ciclu al ceasului
Date unice: un flux de numai un articol-dat este utilizat ca intrare pe
durata unui ciclu al ceasului
Executia este determinist
Aceasta este cea mai veche form de calculator si pn de curnd cea
mai frecvent ntlnit
Exemple: cele mai multe PC-uri, statiile de lucru cu un singur CPU si
calculatoarele mainframe
8
SIMD:
Un tip de calculator paralel
Instructiune unic: toate unittile procesoare execut aceeasi
instructiune n fiecare ciclu al ceasului
Date multiple: fiecare unitate procesoare poate opera pe un articol-dat
diferit
Acest tip de masin are de obicei un dispecer de instructiuni, o retea
intern de band foarte larg si un masiv cuprinztor de unitti de
instructiuni de foarte mic capacitate
Foarte potrivit pentru probleme speciale caracterizate prin grad nalt de
regularitate, cum ar fi procesarea de imagini
Executie determinist si sincron (pasi cu bariere)
Dou varietti: masive de procesoare si pipeline vectorial
Exemple (unele depsite sau disprute):
Masive de procesoare (Processor Arrays): Connection Machine
CM-2, Maspar MP-1, MP-2
Pipeline vectorial (Vector Pipelines): IBM 9000, Cray C90,
Fujitsu VP, NEC SX-2, Hitachi S820
9
MISD:
Putine exemple reale din aceast clas de calculatoare paralel au existat
vreodat
Cteva exemple de conceput ar putea fi:
Filtre de frecevente multiple care ar opera pe un singur flux de
semnal
Algoritmi de criptografie multipl care ar ncerca s sparg un
mesaj codat unic
MIMD:
n mod curent, cel mai obisnuit tip de calculator paralel
Instructiuni multiple: procesoarele pot executa fluxuri diferite de
instructiuni
Date multiple: fiecare procesor poate lucra pe un flux de date diferit de
al altor procesoare
Executia poate fi sincron sau asincron, determinist sau
nedeterminist
Exemple: cele mai multe din supercalculatoarele curente, grilele de
calculatoare paralele n retea si calculatoarele SMP (Symmetric
MultiProcessing) multiprocesoare inclusiv unele tipuri de PC-uri.
10
Terminologie general pentru calculul paralel
Ca orice sector de activitate, calculul paralel are propriul jargon. n
continuare sunt dati ctiva termeni de uz obisnuit n calculul paralel.
Task o sectiune logic discret a efortului de calcul. Tipic, un task este un
program sau un set de instructiuni asemntoare unui program care este
executat de un procesor.
Task parlel un task care poate fi executat de procesoare multiple n conditii
de sigurant (care genereaz rezultate corecte).
Executie serial executarea secvential a unui program, declaratie cu
declaratie. n sensul cel mai simplu, este ceea ce se ntmpl ntr-o masin cu
un singur procesor. Virtual, si cnd toate task-urile sunt paralel exist sectiuni
ale unui program paralel care trebuie executate serial.
Executie paralel executie a unui program prin mai mult dect un task, cu
fiecare task capabil s execute concomitent aceeasi declaratie sau declaratii
diferite.
Memorie partajat (n indiviziune) din punct de vedere strict hardware este
o arhitectur n care toate procesoarele au acces direct (si de obicei bazat pe
bus) la memoria fizic comun. n sensul programrii, formula descrie un
model n care task-urile paralele au toate aceeasi imagine a memoriei si se
pot adresa si pot accesa direct aceleasi locatii logice de memorie indiferent
unde exist memoria fizic n realitate.
Memorie distribuit n sensul hardware se refer la accesul la o memorie,
care fizic nu este comun, printr-o retea. Ca model de programare, task-urile
pot vedea logic numai memoria local a masinii si trebuie s apeleze la
comunicare pentru a avea acces la memoria altor masini unde alte task-uri sunt
n curs de executie.
11
Comunicare obisnuit, task-urile paralele trebuie s schimbe date. Exist mai
multe moduri n care se poate comunica: printr-un bus al memoriilor utilizat n
indiviziune (partajat) sau printr-o retea. Indiferent de modalitatea utilizat,
schimbul real de date este denumit uzual comunicare.
Sincronizare coordonarea task-urilor paralel n timp real, foarte frecvent
asociat cu comunicarea. Implementat adesea prin stabilirea unui punct de
sincronizare n aplicatie unde un task nu poate continua pn cnd alt(e) task(-
uri) nu ating(e) acelasi punct sau acelasi punct echivalent logic.
Sincronizarea implic uzual asteptri cel putin pentru un task si poate cauza
prin aceasta o crestere a timpului de executie (timp universal ceasul din
perete) a aplicatiei paralel.
Granularitate n calculul paralel, granularitatea este o msur calitativ a
raportului calcul/comunicare. Granularitatea poate fi:
Grosier: relativ mult calcul ntre fazele (evenimentele) de comunicare
Fin: relativ putin calcul ntre fazele (evenimentele) de comunicare
Accelerarea observat a unui cod care a fost paralelizat se defineste ca
raportul:
(timpul dup ceasul din perete la executia serial)/(timpul dup ceasul din
perete la executia paralel)
Este unul din cei mai simpli si mai larg utilizati indicatori ai performantelor
unui program paralel.
Overhead-ul paralel durata necesar pentru a coordona task-urile paralel, n
opozitie cu executarea de lucru util. Overhead-ul paralel poate include elemente
de genul:
Timpul de pornire a task-ului
Sincronizrile
Comunicarea de date
Overhead-ul software impus de compilatoarele paralel, biblioteci,
instrumente (tools), sistemul de operare etc.
Timpul de ncheiere a task-ului
Masiv paralel se refer la un sistem hardware care constituie un sistem
paralel dat, care are multe procesoare. Semnificatia lui multe este n crestere
dar n prezent multe nseamn de la 1000 n sus.
Scalabilitate se refer la capacitatea unui sistem paralel (hardware si/sau
software) de a demonstra n accelerarea (speedup) paralel o crestere
proportional odat cu atasarea mai multor procesoare. Factori care contribuie
la scalabilitate:
Hardware n particular lrgimea de band memorie-CPU si reteaua de
comunicare
Algoritmul aplicatiei
Overhead-ul paralel asociat
Caracteristicile specifice ale aplicatiei si programului
12
Arhitecturi ale memoriei n calculul paralel
Memorie partajat (n indiviziune)
Caracteristici generale:
Calculatoarele paralel cu memorie partajat variaz larg ca structur dar
n general au comun posibilitatea dat tuturor procesoarelor de a accesa
toat memoria ca spatiu de adresare global.
Procesoarele multiple pot opera independent dar folosesc n indiviziune
(partajat) aceleasi resurse de memorie
Schimbrile ntr-o locatie de memorie efectuate de un procesor sunt
vizibile tuturor celorlalte procesoare
Masinile cu memorie partajat pot fi mprtite n dou clase majore pe
baza duratelor de acces la memorie: UMA si NUMA.
Uniform Memory Access (UMA):
Reprezentate azi obisnuit prin multiprocesoarele simetrice (SMP
Symmetric MultiProcessor)
Procesoarele sunt identice
Acees egal si durate de acces egale la memorie
Denumite uneori CC-UMA Cache Coherent UMA. Coerenta cache
nseamn c o actualizare fcut de un procesor ntr-o locatie din
memoria partajat este cunoscut de toate celelalte procesoare. Coerenta
cache este realizat la nivelul hardware.
13
Non-Uniform Memory Access (NUMA):
Alctuit deseori prin legarea fizic a doua sau mai multe SMP-uri
Un SMP poate accesa direct memoria altui SMP
Nu toate procesoarele au durate de acces egale la toate memoriile
Accesul la memorie prin legtur este mai lent
Dac coerenta cache este mentinut atunci se vorbeste de CC-NUMA,
NUMA cu coerent de cache
Avantaje:
Spatiul de adresare global d programatorului o perspectiv prietenoas
asupra memoriei
Partajarea datelor ntre task-uri este si rapid si uniform datorit
proximittii memorie-CPU-uri
Dezavantaje:
Dezavantajul prim este lipsa scalabilittii ntre memorie si CPU-uri.
Atasarea mai multor CPU poate face s creasc geometric traficul
asociat cu administrarea cache/memorie
Responsabilitate crescut a programatorului pentru constructe de
sincronizare care s asigure accesul corect la memoria global
Cheltuieli: devine din ce n ce mai dificil si costisitor a proiecta si a
produce masini cu memorie partajat cu numr de procesoare
permanent cresctor.
Memorie distribut
Caracteristici generale:
Ca si sistemele cu memorie partajat, sistemele cu memorie distribuit
cunosc o varietate larg dar au caracteristici comune. Sistemele cu
memorie distribuit necesit o retea de comunicatie pentru a conecta
memoria procesoarelor.
14
Procesoarele au memoria lor local. Adresele de memorie ale unui
procesor nu se asociaz cu un alt procesor asa nct nu exist conceptul
de spatiu de adresare global care s cuprind toate procesoarele
Deoarece fiecare procesor are memoria sa proprie local, el opereaz
independent. Schimbrile pe care el le face n memoria lui proprie,
local nu are nici un efect asupra memoriilor celorlalte procesoare. Prin
urmare conceptul de coerent cache nu se aplic.
Dac un procesor necesit acces la datele detinute de un alt procesor,
este uzual sarcina programatorului de a defini explicit cum si cnd
datele respective sunt comunicate. Sincronizarea ntre task-uri este tot
asa, n responsabilitatea programatorului.
Testura retelei utilizate pentru transferul de date variaz mult desi ea
poate fi la fel de simpl ca metoda Ethernet.
Avantaje:
Memoria este scalabil cu numrul de procesoare. Cresterea numrului
de procesoare are ca urmare cresterea proportional a memoriei.
Fiecare procesor poate avea acces rapid la memoria proprie fr
interferent si fr overhead-ul legat de ncercarea de a mentine o
coerent de cache.
Eficient sub aspectul costului: se pot utiliza procesoare ieftine si retele
ieftine (commodity, off-the-shelf).
Dezavantaje:
Programatorul este responsabil pentru multe detalii asociate cu
comunicarea ntre procesoare.
Poate fi dificil a asocia (to map) structuri de date existente, bazate pe o
memorie global, pe o astfel de organizare a memoriei.
Comparatie ntre arhitecturile cu memorie partajat si distribuit
Arhitectura CC-UMA CC-NUMA Distribuit
Exemple
Smp-uri
Sun Vexx
DEC/Compaq
SGI Challenge
IBM POWER3
SGI Origin
Sequent
HP Exemplar
DEC/Compaq
IBM POWER4
Cray T3E
Maspar
IBM SP2
Comunicatie
MPI
Threads
OpenMP
shmem
MPI
Threads
OpenMP
shmem
MPI
Scalabilitate
La zeci de
procesoare
La sute de
proesoare
La mii de
procesoare
Neajunsuri Lrgimea de
band memorie-
CPU
Lrgimea de
band memorie-
CPU
Administrarea
sistemului
Programare dificil
15
Timp de acces
neuniform
de dezvoltat si de
ntretinut
Accesibiltatea la
software
Multe mii de ISV Multe mii de ISV Sute de ISV
ISV = Independent Software Vendor (productori independenti de softvare)
Memorii hibride, distribuite si partajate
O recapitulare a caracteristicilor cheie ale masinilor cu memorie partajat si cu
memorie distribuit este dat n tabelul de mai sus.
Calculatoarele cele mai mari si cele mai rapide din lumea contemporan
utilizeaz arhitecturi att cu memorie partajat ct si cu memorie distribuit.
Componentele cu memorie partajat sunt de obicei masini SMP cache-coerente.
Procesoarele unui SMP dat pot adresa memoria acelei masini ca fiind global.
Componenta cu memorie distribuit este o retea de mai multe SMP-uri. SMP-
urile sunt constiente numai de memoria proprie, nu si de memoriile celorlalte
SMP-uri. Prin urmare comunicarea prin retea este necesar pentru a deplasa
date de la un SMP la altul.
Tendinta curent pare a indica faptul c acest tip de arhitectur a memoriei va
continua s prevaleze si s creasc ctre nivelul cel mai de sus al calculului n
viitorul previzibil.
Avantajele si dezavantajele celor dou tipuri pure de arhitectur a memoriei
sunt cumva mprtite de arhitectura aceasta hibrid.
Modele de programare parlel
Generalitti
n uzul comun sunt mai multe modele de programare paralel:
Memorie partajat
16
Fire (threads)
Transfer de mesaje
Paralel pe date
Hibrid
Modelele de programare paralel existente fac abstractie de arhitecturile
hardware si de arhitecturile memoriei.
Desi poate c nu sunt percepute astfel, aceste modele nu sunt specifice vreunui
tip particular de masin sau vreunei arhitecturi de memorie. n realitate, oricare
dintre aceste modele poate fi (teoretic) implementat pe orice structur
hardware. Dou exemple:
1. Modelul cu memorie partajat pe o masin cu memorie distribuit: Kendall
Square Research (KSR) varianta ALLCACHE. Memoria masinii este fizic
distribuit dar apare utilizatorului ca o memorie unitar partajat (spatiu de
adresare global). La modul generic, aceast tratare este denumit memorie
partajat virtual. Not: desi KSR nu mai exist pe piat, nu exist vreun
motiv s se cread c o implementare similar este exclus n viitor.
2. Modelul cu transfer de mesaje pe o masin cu memorie partajat: MPI pe
SGI Origin. SGI Origin utilizeaz arhitectura de memorie partajat de tipul
CC_NUMA, unde fiecare task are acces direct la memoria global.
Capabilitatea de a trimite si receptiona mesaje cu MPI, cum se face obisnuit
ntr-o retea de masini cu memorie distribuit nu este numai implementat ci
este si utilizat uzual.
Alegerea unui model este adesea o combinatie de ceea ce este la ndemn si de
optiune personal. Nu exist un model perfect, desi exist cu certitudine
implementri mai bune, mai reusite ale unui model fat de altele.
Sectiunile urmtoare descriu fiecare din modelele enumerate mai devreme si
aduc n discutie unele din implemetrile lor reale.
Modelul cu memorie partajat
n modelul de programare cu memorie partajat task-urile mpart un spatiu de
adresare comun pe care l folosesc pentru scriere si lectur n mod asincron.
Pentru controlul accesului la memoria partajat se pot folosi mecanisme variate
cum sunt blocajele (locks) si semafoarele.
Din punctul de vedere al programatorului, un avantaj al acestui model este
acela c notiunea de proprietate asupra datelor lipseste, asa nct nu este
necesar a specifica explicit comunicarea de date ntre task-uri. Dezvoltarea unui
program poate fi adesea simplificat.
Un dezavantaj major n materie de performante este faptul c ntelegerea si
managementul localizrii datelor devine mai dificil.
Implementri:
17
Pe platformele cu memoria partajat, compilatoarele dedicate traduc
variabilele programului definite de utilizator n adrese de memorie
reale, care sunt globale.
Nu exist la acest moment nici o implementare pe platforme cu
memorie distribuit. Totusi, cum s-a mentionat mai sus, realizarea KSR
ALLCACHE a dat o vedere a datelor ca ntr-o memorie partajat chiar
dac fizic memoria masinii era distribuit.
Modelul cu fire (threads)
n modelul de programare paralel cu fire, un singur proces poate avea ci de
executie multiple, concurente n sensul c concur la ndeplinirea sarcinii de
calcul.
Probabil c analogia cea mai simpl care poate fi utilizat pentru a descrie firele
o reprezint conceptul programului unic care include un numr de subrutine:
Programul principal a.out este planificat la executie de sistemul de
operare nativ. a.out ncarc si angajeaz toate resursele de sistem si de
utilizator pentru a fi executat.
a.out execut ceva lucru serial si apoi creaz un numr de task-uri
(fire) care pot fi planificate la executie si executate de sistemul de
operare n modul concurent.
Fiecare fir are date locale, dar totodat foloseste n indiviziune toate
resursele lui a.out. Aceasta salveaz din overhead-ul asociat cu
replicarea resurselor programului pentru fiecare fir. Fiecare fir
beneficiaz totodat de vedere spre memoria global deoarece el
utilizeaz partajat spatiul de memorare al programului a.out.
18
Lucrul unui fir poate fi descris cel mai bine ca o subrutin n programul
principal. Orice fir poate executa orice subrutin n acelasi timp cu alte
fire.
Firele comunic ntre ele prin intermediul memoriei globale (prin
actualizarea locatiilor adresate). Aceasta reclam constructe de
sincronizare pentru a fi dat siguranta c niciodat nu se ntmpl ca
mai mult de un fir s actualizeze aceeasi adres global.
Firele pot deveni active si se pot ncheia dar a.out rmne prezent
pentru a asigura resursele partajate necesare pn la ncheierea
aplicatiei.
Firele sunt asociate uzual cu arhitecturile cu memorie partajat si sistemele de
operare partajate.
Implementri:
Obisnuit, din perspectiva programrii, implementarea firelor cuprinde:
O bibliotec de subrutine care sunt apelate din codul surs paralel
Un set de directive de compilare ncorporate fie n codul surs serial, fie
n cel paralel. n ambele cazuri programatorul este responsabil cu
determinarea ntregului paralelism.
Implementarea firelor nu este nou n tehnicile de calcul. Istoric,
productorii de hardware au implementat propria lor versiune de fire
proprietate de firm. Aceste implementri au diferit una de alta, ceea ce
a fcut dificil pentru programatori s dezvolte aplicatii portabile bazate
pe fire.
Prin eforturi de standardizare independente au rezultat dou
implementri de fire, foarte diferite: POSIX Threads si OpenMP.
Implementarea POSIX Threads
Bazat pe biblioteci; cere coduri paralel.
Specificat de standardul IEEE POSIX 1003.1c (1995).
Numai n limbajul C.
Cunoscut uzual ca Pthreads.
Cei mai multi productori de hardware ofer acum Pthreads, aditional la
implementarea de proprietar a firelor.
Paralelism foarte explicit; cere din partea programatorului o atentie la
detalii semnificativ.
Implementarea OpenMP
Bazat pe directive de compilare; poate utiliza cod serial.
Definit si aprobat colectiv de un grup de productori majori de hardware
si software. Varianta OpenMP Fortran API a fost lansat n 1997;
varianta C/C++ API a fost lansat n anul urmtor.
Portabil pe multe platforme, inclusiv pe platforme Unix si Windows
NT.
19
Foarte usor si simplu de utilizat dat fiind capacitatea de a oferi
paralelism incremental.
Microsoft are propria sa implementare pentru fire, care nu este nrudit nici cu
standardul UNIX POSIX, nici cu OpenMP.
Modelul cu transfer de mesaje
Modelul cu transfer de mesaje posed urmtoarele caracteristici:
Un set de task-uri care utilizeaz n timpul calculului propria lor
memorie local. Task-urile multiple pot fi rezidente pe aceeasi masin
fizic la fel de bine ca si pe un numr arbitrar de masini.
Task-urile schimb date prin comunicare, prin expedierea si primirea de
mesaje.
Transferul de date implic de obicei operatii n cooperare executate de
fiecare proces. De pild, o operatie de trimitere trebuie s aib ca
pereche o operatie de primire.
Implementri:
Din perspectiva programrii, implemetrile transferului de mesaje
cuprinde uzual o bibliotec de subrutine care sunt ncorporate n codul
surs. Programatorul este rspunztor de determinarea ntregului
paralelism.
Istoric, o varietate apreciabil de biblioteci pentru tranferul de mesaje a
fost accesibil nc din anii 1980. Aceste implementri difereau
substantial ntre ele, ceea ce fcea dificil pentru programatori
dezvoltarea de aplicatii portabile.
n 1992 s-a format Forum-ul MPI cu scopul principal de a stabili o
interfat standard pentru implementrile transferului de mesaje.
Partea I-a a Message Passing Interface (MPI) a fost lansat n 1994.
Partea a II-a (MPI-2) a fost lansat n 1996. Ambele variante MPI cu
specificatiile continute sunt accesibile la
www.mcs.anl.gov/Projects/mpi/standard.html.
MPI este acum standardul industrial de facto pentru transferul de
mesaje, nlocuind practic toate celelalte implementri. Cele mai multe,
20
dac nu toate platformele populare de calcul paralel ofer cel putin o
implementare MPI. Cteva din ele au implementarea complet a MPI-2.
Pentru arhitecturile cu memorie partajat, implementrile MPI nu
utilizeaz retele pentru comunicarea ntre task-uri. n loc de asta ele
folosesc din motive de performant memoria partajat (cpii ale
memoriei).
Modelul paralel pe date
Modelul paralel pe date are caracteristicile urmtoare:
Cea mai mare parte a lucrului paralel se concentreaz pe executarea
operatiilor pe un set de date. Setul de date este organizat uzual ca o
structur comun, ca un masiv (array) sau ca un cub.
Un set de task-uri lucreaz colectiv pe o aceeasi structur de date, dar
fiecare task lucreaz pe o parte distinct dintr-o partitie a aceleiasi
structuri de date.
Task-urile execut aceeasi operatie pe bucata lor de actiune, de pild
adun numrul 5 la fiecare element al masivului.
Pe arhitecturile cu memorie partajat, toate task-urile au acces la structura de
date din memoria global. La arhitecturile cu memorie distribuit structura de
date este divizat si devine rezident pe zone ale memoriei locale a fiecrui
task.
Implementri:
21
Programarea cu modelul paralel pe date se face uzual prin scrierea unui
program cu constructe de date paralel. Constructele pot fi apeluri la o bibliotec
de subrutine paralel pe date sau directive ale compilatorului recunoscute de un
compilator paralel pe date.
Fortran 90 (F90): extensii standard ISO/ANSI ale Fortranului 77.
Contine tot ce cuprinde Fortranul 77
Un nou format al codului; adugri la setul de caractere
Adugri la structura programului si comenzilor
Adugri de variabile metode si argumente
Pointeri si alocri de memorie n supliment
Procesarea masivelor (tratate ca obiecte) ca adaos
Adaos de functii intrinseci noi si recursive
Implementrile sunt accesibile pentru cele mai multe platforme paralel
obisnuite.
High Perfomance Fortran (HPF): extensii de Fortran 90 care admit/suport
programarea paralel pe date.
Contine tot ceea ce contine si Fortranul 90
Aditional, directive care spun compilatorului cum s distribuie datele
Adugat, asertiuni care pot mbuntti/optimiza codul generat
Suplimentar, constructe de date paralel (acum parte din Fortranul 95)
Implementrile sunt accesibile pentru cele mai multe platforme paralel
obisnuite.
Directive de compilare: permit programatorului specificarea distribuirii si
alinierii datelor. Implementrile Fortran sunt accesibile pentru cele mai multe
platforme paralel obisnuite.
Implementrile cu memorie distribuit ale acestui model au compilatorul
capabil a converti programul ntr-un cod standard cu apeluri la o bibliotec de
transfer de mesaje (uzual MPI) pentru a distribui datele tuturor proceselor.
Toate transferurile de mesaje sunt executate invizibil pentru program.
Alte modele
Exist si alte modele de programare paralel peste acelea mentionate mai sus.
Acestea vor continua s evolueze odat cu lumea calculatoarelor n permanent
schimbare si sofware si hardware. Sunt date mai jos trei din cele mai frecvente.
Un model hibrid:
Acest model combin dou sau mai multe dintre modelele de programare
paralel prezentate pn acum.
Un exemplu la ndemn este modelul care combin modelul cu transfer de
mesaje (MPI) fie cu modelul cu fire (POSIX threads), fie cu modelul cu
22
memorie paralel (OpenMP). Acest model hibrid se potriveste bine sistemelor
din ce n ce mai prezente alctuite din retele de SMP-uri.
Un alt exemplu comun de model hibrid este cel care combin modelul paralel
pe date cu transferul de mesaje. Cum s-a semnalat mai devreme, n sectiunea
dedicat modelului paralel pe date, implementrile paralel (F90, HPF) pe
arhitecturi cu memorie distribuit folosesc de fapt transferul de mesaje pentru a
transmite date ntre task-uri n modul transparent pentru programator.
Program unic, date multiple (SPMD Single Program Multiple Data)
SPMD este de fapt un model de programare de nivel nalt care poate fi
construit pe orice combinatie de modele de programare paralel descrise mai
devreme.
Un singur program este executat de toate task-urile simultan.
La un moment oarecare task-urile pot executa instructiuni identice sau diferite,
dar din acelasi program.
Programele SPMD au de obicei logica necesar programat n ele pentru a
permite diferitelor task-uri s se ramifice sau s execute conditionat numai
acele prti din programul pentru care sunt desemnate s le execute. Asta
nseamn c task-urile nu trebuie obligatoriu s execute ntregul program, ci
foarte probabil numai prti din el.
Task-urile pot utiliza date diferite.
Programe multiple, date multiple (MPMD Multiple Program Multiple
Data)
Ca si SPMD, MPMD este n realitate un model de programare de nivel nalt
care poate fi construit pe baza oricrei combinatii de modele de programare
paralel mentionate mai devreme.
23
Aplicatiile MPMD au tipic fisiere obiect executabile multiple (programe). n
timp ce aplicatia este rulat n paralel, fiecare task poate excuta un acelasi
program sau un program diferit de alte task-uri.
Task-urile pot utiliza date diferite.
Proiectarea de programe paralele
Paralelizarea automat sau manual
Proiectarea si dezvoltarea programelor paralel au fost n esent procese
manuale. Programatorul este de obicei responsabil att pentru identificarea ct
si pentru implementarea real a paralelismului.
Foarte frecvent, dezvoltarea manual a codurilor paralele este consumatoare de
timp, complex, susceptibil de erori si iterativ.
De un numr de ani deja, au devenit accesibile instrumente variate de asistare a
programatorului n conversia programelor secventiale n programe paralele.
Tipul cel mai comun de instrument utilizat pentru a paraleliza automat un
program serial este un compilator paralelizator sau un pre-procesor.
Un compilator de paralelizare lucreaz n general n dou moduri diferite:
Deplin automatizat
Compilatorul analizeaz codul surs si identific paralelismele
posibile.
Analiza include identificarea de inhibitori de paralelism si face o
posibil ponderare prin costuri a situatiilor diferite cnd
paralelismul sporeste performanta sau o diminu.
Buclele (do, for) sunt tinta cea mai frecvent a paralelizrii
automate.
Regizat de programator
Utiliznd directive de compilare sau posibile flag-uri de
compilare, programatorul spune explicit compilatorului cum s
paralelizeze codul.
Operatia poate fi folosit si n combinatie cu o doz anumit de
paralelizare automat.
24
Dac se ncepe cu un cod secvential existent si sunt restrictii de timp sau de
buget, atunci paralelizarea automat poate fi un rspuns. Sunt ns cteva
capcane importante referitoare la paralelizarea automat:
Pot aprea rezultate gresite
Performatele se pot degrada n realitate
Este mai putin flexibil dect paralelizarea manual
Limitat la un subset al codului, de regul buclele
Poate realmente s nu se obtin o paralelizare a codului dac analiza
sugereaz existenta unor inhibitori de paralelizare sau codul este prea
complex
Cele mai multe instrumente de paralelizare automat sunt pentru
Fortran.
n continuarea acestei sectiuni sunt discutate metodele manuale de a dezvolta
coduri paralele.
ntelegerea problemei si a programului
Fr ndoial, primul pas n dezvoltarea de software paralel este a ntelege
problema de rezolvat n paralel. Dac nceputul este cu un program secvential,
si acesta trebuie nteles.
nainte de a consuma timp cu o ncercare de a dezvolta o solutie paralel pentru
o problem, se determin dac acea problem este sau nu una care poate fi
paralelizat practic.
Exemplu de problem paralelizabil:
S se calculeze energia potential pentru fiecare din mai multe mii de
conformatii independente ale unei molecule. Cnd calculul acesta este fcut, s
se afle conformatia de energie minim.
Aceast problem poate fi rezolvat n paralel. Fiecare conformatie molecular
este determinabil independent. Calculul conformatiei de energie minim este
de asemenea paralelizabil.
Exemplu de problem neparalelizabil:
Calculul seriei Fibonacci (1, 1, 2, 3, 5, 8, 13, 21, ) cu utilizarea formulei
F(k + 2) = F(k + 1) + F(k).
Aceasta nu este o problem care s poat fi paralelizat deoarece calculul
secventei Fibonacci, asa cum se vede, implic evaluri dependente, nu
independente. Calcularea valorii pentru k + 2 utilizeaz valorile pentru k + 1 si
pentru k. Acesti trei termeni nu pot fi calculati independent si prin urmare nu
pot fi calculati n paralel.
Identificarea punctelor fierbinti ale programului:
Este important a sti unde se consum partea principal a efortului de
calcul. Majoritatea programelor stiintifice si tehnice au concentrat uzual
acest efort n cteva locuri.
25
Instrumentele de analiz a performantelor si a profilului pot fi de ajutor
n aceast etap.
Concentrare pe paralelizarea acestor puncte fierbinti (hotspot) si
ignorarea acelor sectiuni de program care consum putin timp CPU.
Identificarea strangulrilor din program:
Exist zone care sunt disproportionat de lente sau care produc opriri sau
ntrzieri ale lucrului paralel? De pild, operatiile I/O sunt evenimente care
ncetinesc calculul. Programul poate fi restructurat sau algoritmul poate fi
schimbat pentru a elimina sau a reduce episoadele lente.
Identificarea de inhibitori ai paralelismului. O clas comun de inhibitori o
constituie dependenta datelor cum s-a exemplificat n exemplul cu secventa
Fibonacci.
Investigarea unor algoritmi diferiti dac este posibil. Aceasta poate fi unica
reconsiderare foarte important la proiectarea aplicatiilor paralel.
Partitionarea
Unul din primii pasi n proiectarea unui program paralel este spargerea
problemei n fragmente discrete de actiune care pot fi distribuite task-urilor
multiple. Aceast operatie este cunoscut ca descompunere sau partitionare.
Sunt dou ci fundamentale de a partitiona efortul de calcul ntre task-uri
paralel: descompunerea domeniului si descompunerea functional.
Descompunerea de domeniu:
n acest tip de partitionare, datele asociate unei probleme sunt cele care sunt
descompuse. Fiecare task paralel lucreaz atunci pe o portiune din date.
Modalittile de descompunere si repartizare a datelor sunt diferite:
26
Descompunerea functional:
n acest caz, atentia este focalizat pe calculele care trebuie executate si nu pe
datele manipulate n cursul calculelor. Problema este descompus potrivit cu
efortul de calcul care trebuie fcut. Fiecare task se dedic atunci unei fractiuni
din efortul general.
Descompunerea functional se impune si se aplic n cazul problemelor care
pot fi separate n task-uri diferite. De exemplu:
27
Modelarea ecosistemelor diagrama de mai jos arat cinci procese si fiecare
execut un program diferit. Fiecare program calculeaz populatia unui grup dat,
iar cresterea fiecrui grup depinde de aceea a grupurilor vecine. Cu trecerea
timpului, fiecare proces calculeaz starea sa curent, apoi schimb informatii cu
populatiile vecine. Toate task-urile trec apoi la a calcula starea la momentul
urmtor, dup nc un pas de timp.
Procesarea semnalelor un set de date despre un semnal audio este trecut prin
trei filtre numerice (etape de calcul) distincte. Fiecare filtru este un proces de
calcul separat. Primul segment de date trebuie s treac prin primul filtru
nainte de a avansa la al doilea. Cnd etapa aceasta s-a ncheiat, al doilea
segment de date trece prin primul filtru. La timpul la care al treilea segment
este n primul filtru, toate task-urile sunt ocupate.
28
Modelele climatice fiecare model component poate fi gndit ca un task
separat. Sgetile arat schimburile de date ntre componente pe durata
calculului: modelul atmosferei genereaz vitezele vntului care sunt utilizate n
modelul oceanic, apoi modelul oceanului genereaz temperaturile la suprafata
apei care sunt utilizate de modelul atmosferic s.a.m.d.
Combinarea acestor dou tipuri de descompunere a unei probleme este uzual
si fireasc.
Comunicarea
Cine are nevoie de comunicare? Necesarul de comunicare depinde de problema
care trebuie rezolvat.
Comunicarea nu este necesar n cazul unor probleme care pot fi descompuse
si executate n paralel virtual fr necesitatea ca task-urile s mpart datele, de
pild o operatie de procesare a unei imagini n care fiecrui pixel alb sau negru
trebuie s i se inverseze culoarea. Datele de imagine pot fi usor repartizate pe
task-uri multiple care vor actiona apoi independent unul de altul pentru a-si
face treaba proprie. Problemele de acest tip sunt denumite adesea jenant de
paralele (embarrassingly parallel) deoarece ele sunt att de directe. Este
necesar foarte putin comunicare ntre task-uri.
Comunicarea este necesar pentru multe aplicatii paralel care nu sunt tocmai
simple si necesit utilizarea partajat a datelor de ctre task-uri diferite. De
pild, o problem de transfer de cldur n 3 dimensiuni (3D) cere ca un task s
cunoasc temperaturile calculate de task-urile care detin datele nvecinate unei
zone. Schimbrile datelor nvecinate au efect direct asupra datelor acelui task.
Factori de luat n considerare
Sunt ctiva factori importanti care trebuie luati n considerare la proiectarea
comunicrii dintre task-uri:
Costul comunicrii
Comunicarea ntre task-uri implic virtual totdeauna un overhead.
Cicluri ale masinii si resurse care ar putea fi utilizate pentru calcul sunt
deturnate pentru a mpacheta si a transmite date.
Comunicarea cere frecvent un anumit tip de sincronizare ntre task-uri,
care se poate traduce n timp de asteptare n loc de timp de lucru util.
Traficul comunicational competitiv poate satura lrgimea de band
disponibil a retelei, ceea ce ar putea agrava si mai mult problemele
legate de performant.
Latenta si lrgimea de band
Latenta este timpul consumat pentru a trimite un mesaj minimal (0
bytes) de la punctul A la punctul B. Se exprim uzual n microsecunde.
29
Lrgimea de band este cantitatea de date care pot fi comunicate n
unitatea de timp. Se exprim uzual n megabytes/secund.
Expedierea multor mesaje scurte poate face latena dominant n
overhead-urile de comunicare. Adesea este mai eficient a mpacheta
mesajele mrunte ntr-unul mai mare: prin aceasta se poate mri
lrgimea de band de comunicare efectiv.
Vizibilitatea comunicrii
n cazul modelului cu transfer de mesaje, comunicarea este explicit si
n general este destul de la vedere si sub controlul programatorului.
n cazul modelului paralel pe date, comunicarea apare rareori
transparent programatorului, n particular pe arhitecturile cu memorii
distribuite. Programatorul poate chiar s nu fie capabil a sti exact cum
este efectuat comunicarea ntre task-uri.
Comunicare sincron sau asincron
Comunicarea asincron cere un tip anume de strngere de mn ntre
task-uri care folosesc date n indiviziune. Aceasta poate fi structurat
explicit n cod de programator sau se poate produce la un nivel mai jos
necunoscut programatorului.
Comunicarea sincron este adesea denumit comunicare cu blocare
deoarece alt lucrare trebuie s astepte pn ce comunicarea s-a isprvit.
Comunicarea asincron permite task-urilor s transfere date independent
unul de altul. De pild, task-ul 1 poate pregti si trimite un mesaj task-
ului 2 si apoi s treac imediat la executarea altei lucrri. Nu are
important cnd task-ul 2 primeste n realitate datele.
Comunicarea asincron este denumit uneori comunicare fr blocare
deoarece n timp ce comunicarea are loc se pot derula alte lucrri.
Intercalarea calculului cu comunicarea este singurul mare beneficiu al
utilizrii comunicrii asincrone.
30
Domeniul acoperit prin comunicare
Cunoasterea task-urilor care comunic ntre ele este critic n timpul
etapei de proiectare a unui cod paralel. Ambele delimitri de domeniu
de comunicare descrise mai jos pot fi implementate sincron sau
asincron.
Punct-la-punct implic dou task-uri, unul expeditor/productor de
date, cellalt receptor/consumator.
Colectiv implic diviziunea datelor ntre mai mult de dou task-uri
care sunt specificate adesea ca fiind numere dintr-un gup comun sau
colectiv. Cteva variatiuni obisnuite (exist si altele) n figura de mai
sus.
Eficienta comunicrii
Foarte frecvent, programatorul are de ales n privinta unor factori care pot
afecta performanta n comunicare. Aici sunt mentionate numai cteva .
Care implementare ar trebui utilizat pentru un model dat? Lund modelul cu
transfer de mesaje ca exemplu, o implementare MPI poate fi mai rapid pe o
platform hardware dat dect pe alta.
Ce tip de operatii de comunicare ar trebui folosite? Cum s-a spus mai devreme,
operatiile de comunicare asincron pot mbuntti performanta general a
programului.
Mijlocirea retelelor unele platforme pot oferi mai mult dect o retea de
comunicare. Care este cea mai bun?
31
Overhead si complexitate
Imediat mai jos este (de)scris urmtoarea secvent de program:
void main(int argc, char *argv[])
{
int myrank, size;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
Printf(Processor %d of %d: Hello World!, myrank, size);
MPI_Finalize();
}
Este un exemplu de overhead de comunicare paralel si de complexitate: graful
real al apelurilor pentru programul paralel simplu Hello world. Cele mai
multe dintre rutine sunt preluate din biblioteca de comunicare.
n urma acestei scurte prezentri, este de retinut c aceasta este numai o list
partial de luat n considerare.
Sincronizare
Tipuri de sincronizare:
Bariere
Spun uzual c toate task-urile sunt implicate.
32
Fiecare task execut lucrarea sa pn ajunge la barier. Aici se opreste
sau se blocheaz.
Cnd cel din urm task ajunge la barier, toate task-urile sunt
sincronizate.
Ce se ntmpl de aici ncolo variaz de la caz la caz. Uneori trebuie
executat o lucrare secvential. Alteori task-urile sunt automat relansate
pentru a continua lucrul lor.
Lacte/semafoare
Pot actiona pe orice numr de task-uri
Tipic, sunt utilizate pentru a serializa (a proteja) accesul la date globale
sau la o sectiune din cod. La un moment dat, numai un task poate utiliza
(detine) un lact/semafor/flag.
Primul task care accede lactul l si seteaz. Acel task poate atunci s
accead n sigurant (serial) la datele protejate sau la codul protejat.
Alte task-uri pot ncerca a accede lactul dar trebuie s astepte pn ce
task-ul detintor al lactului l descuie.
Pot fi cu blocare sau fr blocare.
Operatii de comunicare sincron
Cuprind numai acele task-uri care execut o operatie de comunicare.
Cnd un task execut o operatie de comunicare, este necesar un gen de
coordonare cu alt(e) task(-uri) care particip la comunicare. De pild,
nainte ca un task s poat executa o operatie de trimitere el trebuie s
primeasc mai nti o nstiintare de la task-ul receptor c a trimite este
OK.
S-a discutat mai devreme n sectiunea comunicare.
Dependentele datelor
Definitie:
Exist o dependent ntre declaratiile de program atunci cnd ordinea
executrii declaratiilor afecteaz rezultatele calculului.
O dependent de date rezult din utilizarea multipl a aceleiasi/acelorasi
locatii de memorie de ctre task-uri diferite.
Dependentele sunt importante n programarea paralel deoarece sunt
unul din inhibitorii principali ai paralelismului.
Exemple:
Dependent a datelor purtat de o bucl
DO 500 J = MYSTART,MYEND
A(J) = A(J 1)*2.0
500 CONTINUE
33
Valoarea lui A(J 1) trebuie calculat nainte de valoarea lui A(J), prin
urmare A(J) are o dependent de date de A(J 1). Paralelismul este inhibat.
Dac task-ul 2 l are pe A(J) si task-ul 1 l are pe A(J 1), calculul corect al
valorii lui A(J) necesit:
Arhitectura cu memorie distribuit task-ul 2 trebuie s obtin valoarea
lui A(J 1) de la task-ul 1 dup ce task-ul 1 termin calculul su.
Arhitectura cu memorie partajat task-ul 2 trebuie s citeasc valoarea
A(J 1) dup ce task-ul 1 o actualizeaz.
Dependent a datelor independent de bucl
task 1 task 2
------ ------
X = 2 X = 4
... ...
Y = X**2 Y = X**3
Ca si n exemplul precedent, paralelismul este inhibat. Valoarea lui Y este
dependent de:
Arhitectura cu memorie distribuit dac sau cnd valoarea lui X este
comunicat ntre task-uri
Arhitectura cu memorie partajat care task depune ultimul valoarea lui
X.
Desi toate dependentele de date sunt important a fi identificate n cursul
proiectrii programelor paralel, dependentele purtate de bucle sunt mai
importante deoarece buclele sunt posibil cele mai uzuale tinte pentru eforturile
de paralelizare.
Cum se trateaz dependentele de date:
Arhitecturile cu memorie distribuit se comunic datele necesare la
puncte de sincronizare.
Arhitecturile cu memorie partajat se sincronizeaz operatiile de
citire/scriere ntre task-uri.
Echilibrarea ncrcrii
Echilibrarea ncrcrii se refer la practica de a distribui lucrul ntre task-uri
astfel nct toate task-urile sunt mentinute ocupate tot timpul. Poate fi
considerat o minimizare a timpului neocupat al task-urilor.
Echilibrarea ncrcrii este important pentru programele paralel din ratiuni de
performant. De pild, dac toate task-urile sunt subiectul unui punct barier de
sincronizare, task-ul cel mai lent determin performanta general.
34
Cum se obtine echilibrarea ncrcrii?
Se partitioneaz egal lucrul pe care fiecare task l primeste.
Pentru operatii pe matrici si pe masive de date n care fiecare task
execut lucru similar, se distribuie multimea datelor egal ntre task-uri.
Pentru iteratii ntr-o bucl n care lucrul executat este similar la fiecare
iteratie, se distribuie egal iteratiile pe task-uri.
Pentru cazul utilizrii unui amestec eterogen de masini cu caracteristici
de performat variate, trebuie s se execute o analiz de performant
prin intermediul unui instrument adecvat pentru a detecta orice
dezechilibru al ncrcrii. Se ajusteaz repartizarea lucrului n
consecint.
Utilizarea atribuirii dinamice a lucrului
Unele clase de probleme produc debalansri ale ncrcrii chiar dac
datele sunt distribuite egal ntre task-uri:
Masivele rare unele task-uri au date adevrate pe care s
lucreze, altele au mai ales zerouri.
Metode de gril adaptive unele task-uri pot necesita rafinarea
retelei lor de discretizare, pe cnd altele nu.
Simularea problemei celor n corpuri unele particule pot migra
la/de la domeniul task-ului initial la domeniul altui task;
particulele detinute de un task cer mai mult calcul/lucru dect
cele detinute de alte task-uri.
Cnd doza de lucru pentru fiecare task este vdit variabil si nu poate fi
prezis, poate fi de ajutor tratarea prin utilizarea unui sistem
planificator task pool. Cnd un task isprveste lucrul, el se nscrie de
ndat ntr-o coad pentru a obtine o lucrare nou.
Poate aprea necesar a proiecta un algoritm care s detecteze si s
manipuleze dezechilibrele de ncrcare pe msur ce apar, dinamic, n
cod.
Granularitate
35
Raportul calcul/comunicare:
n calculul paralel, granularitatea este o msur calitativ a raportului
dintre calcul si comunicare.
Perioadele dedicate calculului sunt uzual separate de perioadele de
comunicare prin evenimente de sincronizare.
Paralelismul de granulatie fin:
ntre evenimentele sincronizatoare, sunt executate cantitti relativ
sczute de calcul.
Raportul calcul/comunicare este redus.
Echilibrarea ncrcrii este facilitat.
Implic overhead mare cu comunicarea si prezint putine surse/sanse de
mbunttire a performantei.
Dac granularitatea este prea fin este posibil ca overhead-ul cerut de
comunicare si de sincronizarea ntre task-uri s depseasc timpul
dedicat calculului.
Paralelism de granulatie grosier:
ntre evenimentele de comunicare/sincronizare se execut relativ mult
calcul.
Raport calcul/comunicare ridicat.
Implic sanse mai mari de a face performanta s creasc.
Este mai dificil a face o echilibrarea a ncrcrii eficient.
36
Care din cele dou granulatii este mai bun?
Granularitatea cea mai eficace depinde de algoritm si de conjunctura
hardware n care este rulat.
n multe cazuri, overhead-ul asociat cu comunicarea si sincronizarea
este mare fat de viteza de executie astfel c este avantajos a avea o
granularitate de tip grosier.
Paralelismul fin granulat poate fi util n reducerea ovehead-ului datorat
ncrcrii debalansate.
I/O
Vestile rele:
Operatiile I/O sunt privite n general ca inhibitori de paralelism.
Sistemele I/O paralele sunt necoapte nc si nu sunt disponibile pentru
toate platformele.
ntr-o conjuctur n care toate task-urile vd acelasi spatiu de fisiere,
operatiile de scriere produc suprapuneri de scriere n fisiere.
Operatiile de citire sunt afectate de capacitatea serverului de fisiere de a
manipula concomitent cereri de scriere multiple.
I/O care trebuie fcute prin retele (NFS Network File System, non-
locale) pot provoca strangulri severe.
Vestile bune:
Sunt disponibile/accesibile unele sisteme de fisiere paralel. De pild:
GPFS General Parallel File System pentru AIX (IBM)
Lustre: pentru clustere Linux (Cluster File Systems, Inc.)
37
PVFS/PVFS2: Parallel Virtual File System pentru clustere Linux
(Clemson/Argonne/Ohio Sate/altele)
PanFS: Panasas ActiveScale File System pentru clustere Linux
(Panasas, Inc.)
HP SFS: HP Storage Works Scalable File Share. Lustre bazat pe
un sistem de fisiere paralel (Global File System pentru Linux)
un produs de la HP.
Specificatia interfetei de programare paralel I/O pentru MPI este
disponibil din 1996 ca parte din MPI-2. Implementri de proprietar si
gratuite sunt acum disponibile uzual.
Unele optiuni:
Accesul la sistemele paralel de fisiere trebuie acompaniat de
lecturi intense deoarece domeniul este n plin dezvoltare.
Experientele vznd-si-fcnd sunt de asemenea utile. Asta n
cazul c exist o implementare n operare.
Regula #1: reducerea pe ct posibil a operatiilor I/O n general.
Operatiile I/O se ataseaz unor portiuni speciale seriale ale job-
ului si apoi se utilizeaz comunicarea paralel pentru a distribui
datele ctre task-uri paralele. De exemplu, task-ul 1 ar putea citi
un fisier de intrare si apoi ar putea comunica datele cerute altor
task-uri. Asemntor, task-ul 1 ar putea executa operatia de
scriere dup colectarea datelor necesar a fi scrise de la toate
celelalte task-uri.
Pentru sistemele cu memorie distribuit cu spatiu de fisiere
partajat, se execut operatii I/O n spatiul de fisiere local,
nepartajat. De exemplu, fiecare procesor poate avea un spatiu
/tmp (temporar) pe care-l poate utiliza. Aceast schem este
uzual mult mai eficient dect executarea de I/O pe retea pe un
director al unuia din task-uri.
Se creaz nume de fisiere unice pentru fiecare I/O fisier de task.
Limitele si costurile programrii paralel
Legea lui Amdahl: afirm c accelerarea potential a unui program este definit
de fractia din cod (p) care poate fi paralelizat:
speedup = 1/(1 p)
Dac nimic din cod nu se poate paraleliza, p = 0 si accelerarea este speedup = 1
(nici un fel de accelerare). Dac codul poate fi paralelizat n totalitate, p = 1 si
accelerarea este infinit (teoretic).
Dac codul poate fi paralelizat n proportie de 50%, accelerarea maxim este
speedup = 2, ceea ce nseamn c acel cod poate fi executat de dou ori mai
repede.
38
Dac se introduce numrul de procesoare care execut fractia paralel din lucrul
total, relatia de mai sus se poate scrie
speedup = 1/[(p/n) + s]
cu p fractia paralel, n numrul procesoarelor si s fractia serial.
Devine imediat evident c exist limite pentru scalabilitatea paralelismului. De
pild, la p = 0,50, 0,90, 0,99 (ceea ce este totuna cu 50%, 90%, 99% din cod
paralelizabil):
n
speedup la:
p = 0,50 p = 0,90 p = 0,99
10 1,82 5,26 9,17
100 1,98 9,17 50,25
1000 1,99 9,91 90,99
10000 1,99 9,91 99,02
Cu toate acestea, anumite probleme exhib performante crescute la cresterea
dimensiunii problemei. De exemplu:
Calculul pe grila 2D 85 secunde 85%
Fractia paralel 15 secunde 15%
39
Dimensiunea problemei poate fi crescut prin dublarea dimensiunilor grilei si
njumttirea pasului de timp. Asta face grila s aib un numr cvadruplu de
puncte si un numr dublu de pasi de timp. Duratele arat atunci astfel:
Calculul pe grila 2D 680 secunde 97,84%
Fractia paralel 15 secunde 2,16%
Problemele care si cresc procentajul de lucru paralel prin cresterea dimensiunii
lor sunt mai scalabile dect problemele cu un procentaj fix de timp paralel.
Complexitate
n general, aplicatiile paralel sunt mult mai complexe dect aplicatiile seriale
corespunztoare, probabil cu un ordin de mrime. Nu numai c sunt de executat
concomitent un flux multiplu de instructiuni, dar mai sunt si datele care curg
ntre ele.
Costurile complexittii sunt msurate n timp al programatorului, n practic
toate aspectele ciclului de dezvoltare de software: proiectare, codare, depanare,
reglare (tuning), ntretinere.
Adoptarea bunelor practici ale dezvoltrii de software este esential cnd se
lucreaz la aplicatii paralel n special cnd cineva dincolo de persoana
programatorului urmeaz s lucreze cu acel software.
Portabilitate
Multumit standardizrii multor interfete de programare a aplicatiilor (API
Application Programming Interface), cum sunt MPI, POSIX threads, HPF si
OpenMP, problema portabilittii programelor paralel nu este att de serioas ca
n anii trecuti. Totusi
Toate problemele uzuale de portabilitate asociate programelor seriale se
regsesc si la programele paralel. De pild, dac se folosesc unele ameliorri de
productor aduse la Fortran, C sau C++, portabilitatea poate deveni o problem.
Chiar dac exist standarde pentru mai multe API, implementrile difer n
unele detalii, uneori pn la punctul n care sunt cerute modificri de cod pentru
a avea portabilitate.
Sistemele de operare pot juca un rol cheie n problema portabilittii.
Caracteristic, arhitecturile hardware sunt foarte variabile si de aceea pot afecta
portabilitatea.
Necesitti de resurse
40
Intentia prim a programrii paralel este diminuarea timpului de executie
indicat de ceasornicul din perete. Dar pentru a atinge acest obiectiv, timpul
CPU necesar este mai mare. De pild, un cod paralel care lucreaz 1 or pe 8
procesoare utilizeaz n realitate 8 ore de timp unitate central (CPU).
Necesarul de memorie poate fi mai mare pentru codurile paralel dect pentru
cele seriale datorit necesittii de a replica datele si din cauza overhead-urilor
asociate cu bibliotecile si subsistemele de suport paralel.
Pentru programe paralel de durat mic, se constat de fapt o descrestere n
performante comparativ cu implementrile similare seriale. Costurile cu
overhead-ul asociate cu instalarea ambiantei paralele, cu crearea task-urilor, cu
comunicarea si cu ncheierea task-ului pot cuprinde o portiune semnificativ
din timpul total de executie n cazul rulrilor scurte.
Scalabilitate
Capacitatea performantei unui program paralel de a se scala este un rezultat al
unui numr de factori si al interactivittii lor. Adugarea simpl a mai multor
masini este rareori rspunsul la problema scalabilittii.
Algoritmul poate avea limite inerente de scalabilitate. La un anumit punct,
adugarea de mai multe resurse produce scderi n performante. Cele mai multe
solutii paralel demonstreaz la un anumit punct aceast caracteristic.
Factorii hardware joac un rol semnificativ n scalabilitate. Exemple:
Lrgimea de band a bus-ului Memorie-CPU la o masin SMP.
Lrgimea de band a retelei de comunicatie.
Volumul memoriei disponibile pe orice masin dat sau pe un set de
masini.
Viteza ceasului procesorului.
Bibliotecile si subsistemele suport pentru lucrul paralel pot limita scalabilitatea
independent de aplicatie.
Exemple de lucru paralel
Procesarea masivelor de date
Exemplul acesta este o demonstratie relativ la calculele pe un masiv 2D de
elemente, cu calculul pe fiecare element al masivului independent de
elementele celelalte ale acelui masiv.
Programul serial calculeaz element cu element n ordine secvential.
Programul poate avea forma:
do j = 1,n
do i = 1,n
a(i,j) = fcn(i,j)
41
end do
end do
Calculul elementelor este independent unul de altul, ceea ce duce la o stuatie
deranjant de paralel (embarrassingly parallel).
Problema trebuie s fie intensiv sub aspectul calculelor.
O solutie posibil
Se implementeaz un model SPMD.
Procesul conductor initializeaz masivul, trimite informatii proceselor-
lucrtoare si receptioneaz/colecteaz rezultatele.
Procesorul-lucrtor primeste informatii, execut partea sa de calcul si
trimite rezulatele procesului conductor.
Folosind schema de memorare Fortran, se execut distributia n blocuri
a masivului.
Solutia n pseudocod: schimbrile datorate paralelismului evidentiate cu
caractere diferite.
find out if I am MASTER or WORKER

if I am MASTER

initialize the array
send each WORKER info on part of array it owns
send each WORKER its portion of initial array

42
receive from each WORKER results

else if I am WORKER
receive from MASTER info on part of array I own
receive from MASTER my portion of initial array
# calculate my portion of array
do j = my first column,my last column
do i = 1,n
a(i,j) = fcn(i,j)
end do
end do
send MASTER results
endif
O solutie diferit: rezervorul de task-uri
Solutia anterioar a folosit echilibrarea ncrcrii static:
Fiecare task are o cantitate de lucru fix de executat
Pot rezulta timpi de inactivitate semnificativi pentru procesoarele mai
rapide sau mai putin ncrcate task-ul cel mai lent determin
performanta general.
Echilibrarea static nu este uzual o grij major dac toate task-urile execut
acelasi volum de munc pe masini identice.
Dac apare o problem de echilibru unele task-uri lucreaz mai repede dect
altele se poate adopta schema cu rezervorul de task-uri.
Schema cu rezervorul de task-uri:
Sunt utilizate dou tipuri de procese.
Procesul conductor (master):
Detine rezervorul de task-uri pe care procesele-lucrtoare le execut
Trimite procesului lucrtor un task la cerere
Colecteaz rezultate de la procesele lucrtoare
Procesul lucrtor execut repetat urmtoarele:
Preia task-ul de la procesul conductor (master)
Execut calculele
Trimite rezultatele procesului master
Procesele-lucrtoare nu stiu nainte de vremea rulrii care portie din masiv i va
reveni spre manipulare si cte task-uri vor executa.
Echilibrarea ncrcrii se petrece dinamic la vremea rulrii: task-urile mai
rapide vor primi mai mult de lucru.
Solutia n pseudocod cu caractere diferite pentru schimbrile impuse de
paralelism:
43
find out if I am MASTER or WORKER
if I am MASTER
do until no more jobs
send to WORKER next job
receive results from WORKER
end do
tell WORKER no more jobs
else if I am WORKER
do until no more jobs
receive from MASTER next job
calculate array element: a(i,j) = fcn(i,j)
send results to MASTER
end do
endif
Discutie:
n exemplul cu rezervor de task-uri prezentat mai sus, fiecare task calculeaz un
element de masiv ca un job. Raportul calcul/comunicare este fin granulat.
Solutiile fine granular impun overhead mai mare de comunicare pentru a reduce
timpii de inactivitate ai task-urilor.
O solutie mai bun ar putea fi a distribui mai mult de lucru fiecrui job.
Volumul corect de lucru depinde de problem.
Alt exemplu: calculul numrului
Valoarea numrului poate fi calculat n mai multe moduri. Se consider aici
urmtoarea metod de aproximare a lui :
1. Se nscrie un cerc ntr-un ptrat
2. Se genereaz aleator puncte n acel ptrat
3. Se determin numrul de puncte dintre acestea, care sunt comune att
ptratului ct si cercului
4. Fie r raportul numrului de puncte din cerc la numrul de puncte din ptrat
5. 4r
6. De observat c generarea mai multor puncte conduce la aproximri mai
bune
Pseudocodul serial pentru aceast procedur:
44
npoints = 10000
circle_count = 0
do j = 1,npoints
generate 2 random numbers between 0 and 1
xcoordinate = random1 ; ycoordinate = random2
if (xcoordinate, ycoordinate) inside circle
then circle_count = circle_count + 1
end do
PI = 4.0*circle_count/npoints
De notat c n cea mai mare parte din timp acest program execut bucla do.
Duce la o solutie deranjant de paralel, intensiv sub aspectul calculului, cu
comunicare minim, cu operatii I/O minime.
Calculul lui : Solutia paralel:
Strategia paralel: se sparge bucla n portiuni care pot fi executate de task-uri
multiple.
Pentru task-ul de aproximare a lui :
Fiecare task execut portiunea sa din bucl de un numr de ori.
Fiecare task poate face lucrul su fr a cere informatii de la alte task-
uri (nu sunt, asadar, dependente).
Se utilizeaz modelul SPMD. Un task actioneaz ca master si colecteaz
rezultatele.
Solutia n pseudocod cu schimbrile impuse de paralelism n caractere
distincte:
45
npoints = 10000
circle_count = 0
p = number of tasks
num = npoints/p
find out if I am MASTER or WORKER
do j = 1,num
generate 2 random numbers between 0 and 1
xcoordinate = random1 ; ycoordinate = random2
if (xcoordinate, ycoordinate) inside circle
then circle_count = circle_count + 1
end do
if I am MASTER
receive from WORKERS their circle_counts
compute PI (use MASTER and WORKER calculations)
else if I am WORKER
46
send to MASTER circle_count
endif
Ecuatia simpl a cldurii:
Multe probleme din calculul paralel necesit comunicare ntre task-uri. Un
numr de probleme comune cer comunicare cu task-urile vecine.
Ecuatia cldurii descrie schimbarea temperaturii n timp fiind dat distributia
initial de temperaturi si conditiile periferice (la limit).
Pentru rezolvarea numeric a ecuatiei cldurii pe o regiune rectangular
(ptrat) se foloseste o schem cu diferente finite.
Temperatura initial este zero pe periferie si mare n centru.
Conditiile periferice sunt mentinute la zero.
Pentru problema complet explicit se foloseste un algoritm de discretizare n
timp. Elementele unui masiv bidimensional reprezint temperatura n punctele
ptratului.
Calculul pentru un element este dependent de valorile asociate elementelor
vecine.
U
x,y
= U
x,y
+ C
x
(U
x + 1,y
+ U
x 1,y
2U
x,y
) + C
y
(U
x,y + 1
+ U
x,y 1
2U
x,y
)
Un program serial arat astfel:
do iy = 2, ny - 1
do ix = 2, nx - 1
u2(ix, iy) =
u1(ix, iy) +
cx * (u1(ix+1,iy) + u1(ix-1,iy) - 2.*u1(ix,iy)) +
cy * (u1(ix,iy+1) + u1(ix,iy-1) - 2.*u1(ix,iy))
end do
end do

47
Ecuatia simpl a cldurii: solutia paralel
Se implementeaz ca un model SPMD.
ntregul masiv este partitionat si distribuit task-urilor ca submasive. Fiecare
task detine astfel o parte din masivul ntreg.
Se determin dependenta datelor.
Elementele interioare, care apartin unui task sunt independente de alte task-uri.
Elementele de frontier sunt dependente de task-urile vecine, de datele lor si de
aceea necesit comunicare.
48
Procesul master trimite informatia initial task-urilor lucrtoare, verific
convergenta si colecteaz rezultatele.
Procesele-lucrtoare calculeaz solutia, comunic att ct este necesar cu
procesele vecine.
Solutia n pseudocod, cu scriere special pentru schimbrile dictate de
paralelism:
find out if I am MASTER or WORKER
if I am MASTER
initialize array
send each WORKER starting info and subarray

do until all WORKERS converge
gather from all WORKERS convergence data
broadcast to all WORKERS convergence signal
end do
receive results from each WORKER
else if I am WORKER
receive from MASTER starting info and subarray
do until solution converged
update time
send neighbors my border info
receive from neighbors their border info

update my portion of solution array

determine if my solution has converged
send MASTER convergence data
receive from MASTER convergence signal
end do

send MASTER results

endif
Ecuatia simpl a cldurii: a doua solutie paralel cu suprapunerea comunicrii si
calculului:
49
Solutia precedent a admis c task-urile lucrtoare folosesc comunicatii cu
blocare. Comunicarea cu blocare face ca nainte de a continua cu instructiunea
urmtoare programat task-ul s astepte ca procesul de comunicare s se
ncheie.
n solutia precedent, task-urile vecine comunic datele de frontier, apoi
fiecare proces actualizeaz portiunea lui din masiv.
Timpul de calcul poate fi adesea redus prin utilizarea comunicrii fr blocare.
Comunicarea fr blocare permite ca lucrul s fie continuat/executat n timp ce
comunicarea este n derulare.
Fiecare task ar putea actualiza interiorul prtii sale de masiv-solutie, n timp ce
se petrece comunicarea datelor de la frontier si ar putea actualiza frontiera sa
dup ce comunicarea este ncheiat.
Este dat n continuare pseudocodul solutiei paralel numrul 2, cu scrierea cu
caractere distincte a prtii de comunicare fr blocare:
find out if I am MASTER or WORKER

if I am MASTER
initialize array
send each WORKER starting info and subarray

do until all WORKERS converge
gather from all WORKERS convergence data
broadcast to all WORKERS convergence signal
end do

receive results from each WORKER

else if I am WORKER
receive from MASTER starting info and subarray

do until solution converged
update time

non-blocking send neighbors my border info
non-blocking receive neighbors border info
update interior of my portion of solution array
wait for non-blocking communication complete
update border of my portion of solution array

determine if my solution has converged
send MASTER convergence data
receive from MASTER convergence signal
end do

50
send MASTER results

endif
Un alt exemplu: ecuatia undelor 1D:
n acest exemplu, se calculeaz amplitudinea de-a lungul unei coarde vibrante
uniforme dup trecerea unui timp anumit.
Calculul implic:
Amplitudinea pe directia axei y
Un indice i de pozitie pe axa x
Puncte-nod impuse de-a lungul coardei
Actualizarea amplitudinii la pasi discreti de timp.
Ecuatia de rezolvat este ecuatia undelor unidimensional:
A(i,t+1) = (2.0 * A(i,t)) - A(i,t-1)
+ (c * (A(i-1,t) - (2.0 * A(i,t)) + A(i+1,t)))
cu c o constant.
De observat c amplitudinea depinde de pasii de timp anteriori (t, t 1) si de
punctele vecine (i 1, i + 1). Dependenta datelor nseamn c orice solutie
paralel necesit comunicare.
Solutia paralel:
Se implementeaz ca un model SPMD.
Masivul depozitar al tuturor amplitudinilor este partitionat si distribuit task-
urilor ca submasive. Fiecare task obtine o portiune din masivul total.
Echilibrarea ncrcrii: toate punctele reclam lucru egal astfel c punctele
trebuie repartizate egal.
O descompunere n blocuri ar avea lucrul partitionat ntr-un numr de task-uri
ca fragmente care permit fiecrui task s detin ct mai multe date contigue.
51
Comunicarea este necesar si are loc numai n punctele de frontier. Cu ct este
mai mare dimensiunea blocurilor cu att este mai redus comunicarea.
Solutia n pseudocod:
find out number of tasks and task identities
#Identify left and right neighbors
left_neighbor = mytaskid - 1
right_neighbor = mytaskid +1
if mytaskid = first then left_neigbor = last
if mytaskid = last then right_neighbor = first
find out if I am MASTER or WORKER
if I am MASTER
initialize array
send each WORKER starting info and subarray
else if I am WORKER
receive starting info and subarray from MASTER
endif
#Update values for each point along string
#In this example the master participates in calculations
do t = 1, nsteps
send left endpoint to left neighbor
receive left endpoint from right neighbor
send right endpoint to right neighbor
receive right endpoint from left neighbor
#Update points along line
do i = 1, npoints
newval(i) = (2.0 * values(i)) - oldval(i)
+ (sqtau * (values(i-1) - (2.0 * values(i)) +
values(i+1)))
52
end do
end do
#Collect results and write to file
if I am MASTER
receive results from each WORKER
write results to file
else if I am WORKER
send results to MASTER
endif
53
OpenMP
Ce este OpenMP?
OpenMP este o interfat de programare a aplicatiilor (API Application
Program Interface) care poate fi utilizat n paralelismul multifir cu memorie
partajat (n indiviziune). Contine trei componente API primare: directive de
compilare, rutine de bibliotec la executie, variabile de mediu (environment).
Portabilitate: Aceast API este realizat n C/C++ si Fortran. S-a implementat
pe platforme variate, inclusiv pe cele mai multe platforme Unix si Windows
NT.
Standardizare: Este definit si aprobat n comun de un grup de productori
majori de hardware si software. Este de asteptat a deveni n viitor un standard
ANSI (American National Standards Institute).
Ce nseamn OpenMP? nseamn Open specifications for Multi Processing
prin lucrri n colaborare care ntrunesc interese din industria de software si de
hardware, guvernamentale si academice.
Ce nu este OpenMP?
Interfata OpenMP nu este prin ea nssi destinat sistemelor paralel cu memorie
distribuit. Nu este implementat n mod necesar identic de ctre toti
productorii. Nu este garantat c ar asigura utilizarea cea mai eficient a
memoriei partajate (nu exist pentru moment constructe legate de localismul
datelor).
Istoric
Istoria mai veche
n anii 90 timpurii, productorii de masini cu memorie partajat furnizau
extensii de programare Fortran similare, bazate pe directive:
Utilizatorul aduga programelor Fortran secventiale directive care specificau
care bucle trebuia s fie paralelizate.
Compilatorul era responsabil de paralelizarea automat a buclelor de acest gen
pe procesoarele SMP (Symmetric MultiProcessing).
Implementrile erau toate similare functional dar erau, ca de obicei, diferite n
unele detalii.
54
Prima ncercare de a realiza un standard a fost proiectul pentru ANSI X3H5 din
1994. Nu a fost adoptat niciodat, n principal din cauza interesului n scdere
pe msur ce masinile cu memorie distribuit au devenit din ce n ce mai
populare.
Istoria recent
Specificatia de standard OpenMP a fost nceput n primvara anului 1997,
prelund ceea ce a rmas din ncercarea ANSI X3H5, odat ce arhitecturile mai
noi de masini cu memorie partajat au devenit demne de luat n seam.
Pertenerii implicati n specificarea standardului OpenMP sunt:
OpenMP Architecture Review Board (deschis pentru membri noi)
Compaq / Digital
Hewlett-Packard Company
Intel Corporation
International Business Machines (IBM)
Kuck & Associates, Inc. (KAI)
Silicon Graphics, Inc.
Sun Microsystems, Inc.
U.S. Department of Energy ASCI program
Productori de software cu rol de avizare:
Absoft Corporation
Edinburgh Portable Compilers
GENIAS Software GmBH
Myrias Computer Technologies, Inc.
The Portland Group, Inc. (PGI)
Societti de dezvoltare de aplicatii cu rol de avizare:
ADINA R&D, Inc.
ANSYS, Inc.
Dash Associates
Fluent, Inc.
ILOG CPLEX Division
Livermore Software Technology Corporation (LSTC)
MECALOG SARL
Oxford Molecular Group PLC
The Numerical Algorithms Group Ltd.(NAG)
Istoria lansrilor
Octombrie 1997: Fortran versiunea 1.0
Sfrsitul anului 1998: C/C++ versiunea 1.0
Iunie 2000: Fortran versiunea 2.0
Aprilie 2002: C/C++ versiunea 2.0
55
Pentru detalii se recomand vizitarea site-ului http://www.openmp.org.
Scopurile urmrite prin OpenMP
Standardizare: A furniza un standard pentru varietatea de arhitecturi/platforme
cu memorie partajat.
Sprijin si mijloc: Stabilirea unui set simplu si limitat de directive pentru
programarea masinilor cu memorie partajat. O doz nsemnat de paralelism
se poate implementa utiliznd doar 3-4 directive.
Usurinta utilizrii: A oferi posibilitatea de a paraleliza incremental, treptat un
program secvential, spre deosebire de bibliotecile cu transfer de mesaje care
reclam o tratare de genul totul sau nimic.
Portabilitate: Permite Fortran-ul (77, 90 si 95), C si C++.
For public pentru API si calitatea de membru.
Modelul de programare OpenMP
Paralelism pe baz de fire: Un proces cu memorie partajat poate consta n fire
multiple. OpenMP se bazeaz pe existenta firelor multiple n paradigma
programrii cu partajarea memoriei.
Peralelism explicit: OpenMP este un model de programare explicit (nu
automat), care ofer programatorului deplinul control asupra paralelizrii.
Modelul ramificatie-jonctiune: OpenMP uzeaz de un model al executiei
paralel alctuit din ramificatii si jonctiuni (v.figura).
Toate programele OpenMP ncep ca un proces unic, firul master. Firul master
se execut secvential pn cnd ajunge la primul construct numit zon/regiune
paralel.
Ramificatie: firul master creaz un mnunchi de fire paralele. Declaratiile din
program care alctuiesc o zon paralel sunt executate apoi paralel de firele
variate din mnunchi.
56
Jonctiune: cnd firele din mnunchi termin de executat declaratiile din
constructul zon/regiune paralel, ele se sincronizeaz si se ncheie lsnd din
nou numai firul master.
Bazat pe directive de compilare: Virtual, tot paralelismul OpenMP este
specificat prin directive de compilare care sunt ncorporate n codul surs
Fortran sau C/C++.
Suportul pentru paralelismul stratificat: Aceast interfat API asigur plasarea
unui construct paralel n interiorul altor constructe paralel. Implementrile
existente pot s includ sau nu aceast particularitate.
Fire dinamice: Aceast interfat API asigur modificarea dinamic a numrului
de fire care pot fi utilizate pentru executarea unor zone paralel diferite.
Implementrile existente pot s includ sau nu aceast particularitate.
Exemple de structur a codurilor OpenMP.
Fortran structura general a codului:
PROGRAM HELLO
INTEGER VAR1, VAR2, VAR3
Cod secvential
. . . . . .
nceputul sectiunii paralel. Ramificarea mnunchiului de fire.
Specificarea domeniului variabilelor
!$OMP PARALLEL PRIVATE(VAR1, VAR2) SHARED(VAR3)
Sectiunea paralel executat de toate firele
. . . . . .
Toate firele se reunesc n firul master
!$OMP END PARALLEL
Se reia codul secvential
. . . . . .
END
C / C++ structura general a codului:
#include <omp.h>
main() {
int var1, var2, var3;
57
Codul secvential
. . . . . .
nceputul sectiunii paralel. Ramificarea mnunchiului de fire. Specificarea
domeniului variabilelor
#pragma omp parallel private(var1, var2) shared(var3)
{
Sectiunea paralel executat de toate firele
. . . . . .
Toate firele se reunesc n firul master
}
Se reia codul secvential
. . . . . .
}
Directive OpenMP
Formatul directivelor Fortran:
Prefix-gard nume de directiv [clauze ].
Toate directivele OpenMP n Fortran trebuie s nceap cu un prefix-gard.
Prefixele acceptate depind de tipul sursei Fortran. Prefixe posibile: !$OMP sau
C#OMP sau *$OMP.
O directiv OpenMP valid trebuie s apar dup un prefix-gard si naintea
oricrei clauze.
Clauzele sunt optionale, pot fi n orice ordine si pot fi repetate n functie de
necesitti (dac nu sunt cumva restrictionate).
Exemplu:
!$OMP PARALLEL DEFAULT(SHARED) PRIVATE(BETA, PI)
Pentru sursele n form fix sunt acceptate ca prefix-gard !$OMP, C#OMP
sau *$OMP, care trebuie s nceap din coloana 1. Toate regulile de form fix
ale Fortran-ului pentru lungimea liniei, spatii, coloane de continuare si
comentarii se aplic pentru ntrega linie de directiv. Liniile cu directive initiale
trebuie s aib un spatiu/zero n coloana 6. Liniile de continuare trebuie s aib
un caracter diferit de spatiu/zero n coloana 6.
Pentru sursele n form liber, singura gard acceptat este !$OMP. Poate
aprea n orice coloan dar trebuie s fie precedat de un spatiu (exclusiv).
Toate regulile pentru forma liber Fortran, pentru lungimea liniei, spatiu,
coloane de continuare si comentarii se aplic pentru ntreaga linie de directiv.
Liniile de directiv initiale trebuie s aib un spatiu dup prefixul-gard.
58
Liniile de continuare trebuie s aib un caracter & ca ultim caracter al liniei
diferit de blank. Linia urmtoare trebuie s nceap cu un prefix-gard si apoi
continuarea directivelor.
Reguli generale:
Comentariile nu pot aprea pe aceeasi linie cu o directiv.
Compilatoarele Fortran care sunt abilitate OpenMP includ n general o optiune
pentru liniile de comand care spun compilatorului s activeze si s interpreteze
toate directivele OpenMP.
Mai multe directive Fortran OpenMP apar n perechi si au forma
!$OMP directiv
/bloc de cod structurat/
!$OMP end directiv
Formatul directivelor C/C++:
#pragma omp nume de directiv [clauze ] linie-nou.
Prefixul #pragma omp este obligatoriu pentru orice directiv OpenMP n
C/C++.
O directiv OpenMP valid trebuie s apar dup pragma si nainte de orice
clauz.
Clauzele sunt optionale, pot fi n orice ordine, pot fi repetate (dac nu sunt
restrictionri).
Caracterul linie-nou este necesar pentru a trece la blocul structurat care este
inclus n acea directiv.
Exemplu:
#pragma omp parallel default(shared) private(beta,pi)
Reguli generale:
Directivele respect conventiile din standardele C/C++ pentru directivele de
compilare.
Sensibil la upper/lower case.
Pentru o directiv, numai un nume de directiv poate fi specificat (ceea ce se
practic si la Fortran).
Fiecare directiv se aplic la cel mult o declaratie urmtoare, care poate fi un
bloc structurat.
Liniile-directiv lungi pot fi continuate pe linii urmtoare prin combinarea
caracterelor newline (linie-nou) cu un caracter \ la finalul liniei-directiv.
Domeniul directivelor
59
Domeniu static (lexical): Codul inclus textual ntre nceputul si finalul unui
bloc structurat care urmeaz directiva. Domeniul static al unei directive nu
acoper rutine multiple sau fisiere de cod.
Directive orfane: Despre o directiv OpenMP care apare independent de o alt
directiv care o include se spune c este o directiv orfan. Ea exist n afara
domeniului static (lexical) al altei directive. Acoper rutine si posibile fisiere de
cod.
Domeniu dinamic: Domeniul dinamic al unei directive include att domeniul ei
static (lexical) ct si domeniile orfanelor ei.
Exemplu:

PROGRAM TEST
...
!$OMP PARALLEL
...
!$OMP DO
DO I=...
...
CALL SUB1
...
ENDDO
...
CALL SUB2
...
!$OMP END PARALLEL
SUBROUTINE SUB1
...
!$OMP CRITICAL
...
!$OMP END CRITICAL
END
SUBROUTINE SUB2
...
!$OMP SECTIONS
...
!$OMP END SECTIONS
...
END
DOMENIUL STATIC
Directiva DO apare ntr-o regiune
paralel care o include
DIRECTIVE ORFANE
Directivele CRITICAL si
SECTIONS apar nafara unei regiuni
paralel care s o includ
DOMENIUL DINAMIC
De ce aste important aceast precizare? OpenMP specific un numr de reguli
privind domeniul peste care directivele se pot asocia (lega) si se pot include una
n alta. Dac acele reguli ale OpenMP sunt ignorate, pot rezulta programe
incorecte sau neinteligibile. Regulile sunt prezentate ntr-o sectiune urmtoare.
60
Constructul de regiuni PARALLEL.
Scopul acestuia: o regiune paralel este un bloc de cod care va fi executat de mai
multe fire. Este constructul paralel OpenMP fundamental.
Formatul n Fortran:
!$OMP PARALLEL [clause ...]
IF (scalar_logical_expression)
PRIVATE (lista)
SHARED (lista)
DEFAULT (PRIVATE | SHARED | NONE)
FIRSTPRIVATE (lista)
REDUCTION (operator: lista)
COPYIN (lista)
block
!$OMP END PARALLEL
Formatul n C/C++:
#pragma omp parallel [clause ...] newline
if (scalar_expression)
private (lista)
shared (lista)
default (shared | none)
firstprivate (lista)
reduction (operator: lista)
copyin (lista)

structured_block
Not: Cnd un fir ajunge la directiva PARALLEL, el creeaz un mnunchi de
fire si devine firul master al acelui fascicul. Master-ul este un membru al acelui
fascicul si are numrul 0 n fascicul.
La nceputul acelei regiuni paralel, codul este copiat si este executat apoi de
toate firele fasciculului.
Exist la finalul unei regiuni paralel o barier implicit, numai firul master
continu executia dincolo de acest punct.
Cte fire? Numrul de fire dintr-o regiune paralel este determinat de factorii
urmtori, n ordinea prezentat:
Se utilizeaz functia de bibliotec omp_set_num_threads().
Se seteaz variabila de mediu OMP_NUM_THREADS.
Implementarea default
61
Firele sunt numerotate de la 0 (firul master) la N 1.
Fire dinamice: Prin default, un program cu regiuni paralel multiple utilizeaz
acelasi numr de fire pentru a executa fiecare dintre regiuni. Aceast
comportare poate fi modificat pentru a permite la vremea executiei
modificarea dinamic a firelor create pentru o anumit sectiune paralel. Cele
dou metode disponibile pentru a permite fire dinamice sunt:
Utilizarea functiei de bibliotec omp_set_dynamic()
Setarea variabilei de mediu OMP_DYNAMIC.
Regiuni paralel una-n-alta: O regiune paralel n alta rezult prin crearea unui
fascicul nou, constnd ntr-un fir, prin default.
Implementrile pot permite mai mult de un fir n fasciculul cuprins n alt
fascicul.
Clauze: Dac apare clauza IF, ea trebuie s produc .TRUE. (n Fortran) sau o
valoare nenul (n C/C++) pentru a fi creat un fascicul de fire. Altminteri,
regiunea este executat de firul master n mod secvential.
Celelalte clauze sunt descrise ceva mai ncolo.
Restrictii: O regiune paralel trebuie s fie un bloc structurat care nu acoper
rutine multiple sau fisiere de cod multiple. n Fortran, instructiunile I/O
nesincrone prin care mai multe fire se refer la aceeasi unitate au o comportare
nespecific(at). Este ilegal ramificarea din sau ntr-o regiune paralel. Nu este
permis dect o singur clauz IF.
Exemplu de regiune paralel
Program simplu Hello World.
Fiecare fir execut ntregul cod inclus n regiunea paralel.
Rutinele de bibliotec OpenMP sunt utilizate pentru a obtine identificatori de
fire si numrul total de fire.
n Fortran:
PROGRAM HELLO
INTEGER NTHREADS, TID, OMP_GET_NUM_THREADS,
+ OMP_GET_THREAD_NUM
C Fork a team of threads giving them their own copies
of variables
!$OMP PARALLEL PRIVATE(TID)
C Obtain and print thread id
TID = OMP_GET_THREAD_NUM()
PRINT *, 'Hello World from thread = ', TID
C Only master thread does this
IF (TID .EQ. 0) THEN
NTHREADS = OMP_GET_NUM_THREADS()
62
PRINT *, 'Number of threads = ', NTHREADS
END IF
C All threads join master thread and disband
!$OMP END PARALLEL
END
n C/C++:
main () {
int nthreads, tid;
/* Fork a team of threads giving them their own copies of
variables */
#pragma omp parallel private(tid)
{
/* Obtain and print thread id */
tid = omp_get_thread_num();
printf("Hello World from thread = %d\n", tid);
/* Only master thread does this */
if (tid == 0)
{
nthreads = omp_get_num_threads();
printf("Number of threads = %d\n", nthreads);
}
} /* All threads join master thread and terminate */
}
Constructe Work-Sharing (lucru partajat)
Un construct work-sharing mparte executia din regiunea de cod care l include,
ntre membrii fasciculului care l ntlnesc.
Constructele work-sharing nu lanseaz fire noi.
Nu exist barier implicit la intrarea ntr-un construct work-sharing, totusi
exist o barier implicit la sfrsitul unui construct work-sharing.
Tipuri de constructe work-sharing
DO/for partajeaz
iteratiile unei bucle din
fascicul. Reprezint un
SECTIONS sparge
lucrul n sectiuni
separate, discrete.
SINGLE
serializeaz o sectiune
de cod.
63
tip de "paralelism pe
date".
Fiecare sectiune este
executat de un fir.
Poate fi utilizat pentru
implementarea unui
tip de "paralelism
functional".
Restrictii: Un construct work-sharing trebuie s fie inclus dinamic ntr-o
regiune paralel pentru ca directivele s fie excutate n paralel.
Constructele work-sharing trebuie s fie ntlnite de toate firele membre ale
unui fascicul sau de niciunul.
Constructele work-sharing trebuie s fie ntlnite n aceeasi oridine de toate
firele membre ale unui fascicul.
Constructe work-sharing
Directiva DO/for
Scopul: Directiva DO/for specific faptul c iteratiile buclei imediat urmtoare
trebuie s fie executate de fascicul n paralel. Asta presupune c o regiune
parlel a fost deja initiat, altminteri ea se execut secvential pe un singur
procesor.
Formatul n Fortran:
!$OMP DO [clause ...]
SCHEDULE (type [,chunk])
ORDERED
PRIVATE (list)
FIRSTPRIVATE (list)
LASTPRIVATE (list)
SHARED (list)
REDUCTION (operator | intrinsic : list)
64
do_loop
!$OMP END DO [ NOWAIT ]
Formatul n C/C++:
#pragma omp for [clause ...] newline
schedule (type [,chunk])
ordered
private (list)
firstprivate (list)
lastprivate (list)
shared (list)
reduction (operator: list)
nowait
for_loop
Clauze:
Clauza SCHEDULE: descrie cum sunt partajate iteratiile buclei ntre firele
fasciculului. Att pantru Fortran ct si pentru C/C++:
STATIC: Iteratiile buclei sunt mprtite n bucti de dimensiunea chunk si apoi
atribuite static firelor. Dac chunk nu este precizat, iteratiile sunt mprtite
(dac este posibil) egal si contiguu ntre fire.
DYNAMIC: Iteratiile buclei sunt divizate n bucti de dimensiunea chunk si
distribuite dinamic ntre fire; cnd un fir ncheie o bucat, i se atribuie dinamic
alta. Dimensiunea buctilor prin default este 1.
GUIDED: Dimensiunea fragmentului este redus exponential cu fiecare bucat
distribuit a spatiului de iterare. Dimensiunea fragmentului specific numrul
minim de iteratii de distribuit de fiecare dat. Dimensiunea buctilor prin
default este 1.
RUNTIME: Decizia de repartizare este amnat pn la timpul executiei de
variabila de mediu OPM_SCHEDULE. Este ilegal a specifica dimensiunea
fragmentului pentru aceast clauz.
Repartizarea prin default este dependent de implementare. Implementarea
poate fi totodat ntructva variabil n modul n care repartizrile variate sunt
implementate.
Clauza ORDERED: Trebuie s fie prezent cnd n directiva DO/for (vezi mai
sus) sunt incluse directive ORDERED.
Clauza NO WAIT (Fortran)/nowait (C/C++): Dac este specificat, atunci
firele nu se sincronizeaz la finele buclei paralel. Firele trec direct la declaratia
urmtoare de dup bucl. Pentru Fortran, directiva END DO este optional cu
default-ul NO WAIT.
65
Alte clauze sunt descrise mai n detaliu n continuare.
Restrictii: Bucla DO nu poate fi o bucl DO WHILE sau o bucl fr control.
Totodat, variabila de iteratie a buclei trebuie s fie un ntreg si parametrii de
control ai buclei trebuie s fie aceiasi pentru toate firele.
Corectitudinea programului trebuie s nu depind de care fir execut o iteratie
particular.
Este ilegal a ramifica controlul nafara unei bucle asociate cu directiva DO/for.
Dimensiunea fragmetului trebuie s fie specificat ca o expresie ntreag
invariant, ca si cnd nu exist vreo sincronizare n timpul evalurii ei de fire
diferite.
Directiva for din C/C++ necesit ca bucla for s aib forma canonic.
Clauzele ORDERED si SCHEDULE pot aprea fiecare numai o dat.
Exemplu: Directiva DO/for, program simplu de adunare de vectori.
Variabila I va fi private pentru fiecare fir; fiecare fir va avea propriul su
exemplar.
Iteratiile buclei vor fi distribuite dinamic n fragmente de dimensiunea
CHUNK.
Firele nu se vor sincroniza la ncheierea lucrului lor (NOWAIT).
FORTRAN:
PROGRAM VEC_ADD_DO
INTEGER N, CHUNKSIZE, CHUNK, I
PARAMETER (N=1000)
PARAMETER (CHUNKSIZE=100)
REAL A(N), B(N), C(N)
! Some initializations
DO I = 1, N
A(I) = I * 1.0
B(I) = A(I)
ENDDO
CHUNK = CHUNKSIZE

!$OMP PARALLEL SHARED(A,B,C,CHUNK) PRIVATE(I)
!$OMP DO SCHEDULE(DYNAMIC,CHUNK)
DO I = 1, N
C(I) = A(I) + B(I)
ENDDO
!$OMP END DO NOWAIT
!$OMP END PARALLEL
66
END
C/C++:
#include <omp.h>
#define CHUNKSIZE 100
#define N 1000
main ()
{
int i, chunk;
float a[N], b[N], c[N];
/* Some initializations */
for (i=0; i < N; i++)
a[i] = b[i] = i * 1.0;
chunk = CHUNKSIZE;
#pragma omp parallel shared(a,b,c,chunk) private(i)
{
#pragma omp for schedule(dynamic,chunk) nowait
for (i=0; i < N; i++)
c[i] = a[i] + b[i];
} /* end of parallel section */
}
Constructe de divizare a lucrului
Directiva SECTIONS
Scop: Directiva SECTIONS este un construct de divizare a lucrului neiterativ.
Ea specific faptul c sectiunea/sectiunile de cod incluse sunt de divizat ntre
firele din fascicul.
Directive SECTION independente pot fi asezate una ntr-alta n directiva
SECTIONS. Fiecare SECTION este executat o dat de un fir din fascicul.
Sectiuni diferite pot fi executate de fire diferite. Este posibil ca un fir s execute
mai mult de o sectiune dac firul este suficient de rapid si implementarea
permite asa ceva.
Format n Fortran:
!$OMP SECTIONS [clause ...]
67
PRIVATE (list)
FIRSTPRIVATE (list)
LASTPRIVATE (list)
REDUCTION (operator | intrinsic : list)
!$OMP SECTION
block
!$OMP SECTION
block
!$OMP END SECTIONS [ NOWAIT ]
Format n C/C++:
#pragma omp sections [clause ...] newline
private (list)
firstprivate (list)
lastprivate (list)
reduction (operator: list)
nowait
{
#pragma omp section newline
structured_block
#pragma omp section newline
structured_block
}
Clauze: La finalul unei directive SECTIONS exist o barier implicit cu
exceptia cazului n care se utilizeaz o clauz nowait/NOWAIT. Clauzele sunt
descrise n detaliu mai departe.
ntrebri: Ce se ntmpl dac numrul de fire si numrul de SECTION sunt
diferite? Mai multe fire dect SECTION? Mai putine fire dect SECTION?
Dac sunt mai multe fire dect sectiuni, unele fire nu vor executa sectiuni. Dac
sectiunile sunt mai multe dect firele, implementarea trebuie s defineasc
modul cum sectiunile rmase vor fi executate.
Cum se asociaz firele cu sectiunile?
Din nou implementarea trebuie s decid care sectiune va fi executat de care
fir si aceast repartizare poate varia de la executie la executie.
68
Restricitii: Este ilegal a ramifica n sau din blocurile sectiunii.
Directivele SECTION trebuie s apar n extinderea lexical a unei directive
SECTIONS care le include.
Exemplu pentru directiva SECTIONS: program de adunare simpl a vectorilor
similar exemplului utilizat mai devreme pentru directiva DO/for.
Primele n/2 iteratii ale buclei DO sunt distribuite primului fir, restul se
distribuie firului al doilea.
Cnd un fir termin blocul lui de iteratii, trece la executarea a ceea ce urmeaz
conform codului (NOWAIT).
Pentru Fortran:
PROGRAM VEC_ADD_SECTIONS
INTEGER N, I
PARAMETER (N=1000)
REAL A(N), B(N), C(N)
! Some initializations
DO I = 1, N
A(I) = I * 1.0
B(I) = A(I)
ENDDO
!$OMP PARALLEL SHARED(A,B,C), PRIVATE(I)
!$OMP SECTIONS
!$OMP SECTION
DO I = 1, N/2
C(I) = A(I) + B(I)
ENDDO
!$OMP SECTION
DO I = 1+N/2, N
C(I) = A(I) + B(I)
ENDDO
!$OMP END SECTIONS NOWAIT
!$OMP END PARALLEL
END
Pentru C/C++:
#include <omp.h>
#define N 1000
69
main ()
{
int i;
float a[N], b[N], c[N];
/* Some initializations */
for (i=0; i < N; i++)
a[i] = b[i] = i * 1.0;
#pragma omp parallel shared(a,b,c) private(i)
{
#pragma omp sections nowait
{
#pragma omp section
for (i=0; i < N/2; i++)
c[i] = a[i] + b[i];
#pragma omp section
for (i=N/2; i < N; i++)
c[i] = a[i] + b[i];
} /* end of sections */
} /* end of parallel section */
}
Directiva SINGLE
Scop: Directiva SINGLE specific faptul c secventa de cod inclus trebuie
executat numai de un fir din fascicul. Poate fi util n tratarea sectiunilor
codului care nu sunt sigure pe orice fir (cum sunt operatiile I/O).
Formatul n Fortran:
!$OMP SINGLE [clause ...]
PRIVATE (list)
FIRSTPRIVATE (list)
block
!$OMP END SINGLE [ NOWAIT ]
70
Formatul n C/C++:
#pragma omp single [clause ...] newline
private (list)
firstprivate (list)
nowait
structured_block
Clauze: Firele din fascicul care nu execut directiva SINGLE asteapt la finalul
blocului de cod inclus, cu exceptia cazului n care este specificat o clauz
nowait (C/C++) sai NOWAIT (Fortran).
Clauzele sunt descrise ceva mai departe.
Restrictii: Este inacceptabil a ramifica n sau nafara unui bloc SINGLE.
Constructe de divizare a lucrului paralel combinate
Directiva PARALLEL DO/parallel for
Iteratiile buclei DO/for se distribuie n blocuri de dimensiune egal fiecrui fir
din fascicul (SCHEDULE STATIC).
Exemplu pentru Fortran:
PROGRAM VECTOR_ADD
INTEGER N, I, CHUNKSIZE, CHUNK
PARAMETER (N=1000)
PARAMETER (CHUNKSIZE=100)
REAL A(N), B(N), C(N)
! Some initializations
DO I = 1, N
A(I) = I * 1.0
B(I) = A(I)
ENDDO
CHUNK = CHUNKSIZE

!$OMP PARALLEL DO
!$OMP& SHARED(A,B,C,CHUNK) PRIVATE(I)
!$OMP& SCHEDULE(STATIC,CHUNK)
DO I = 1, N
C(I) = A(I) + B(I)
ENDDO
71
!$OMP END PARALLEL DO
END
Exemplu pentru C/C++:
#include <omp.h>
#define N 1000
#define CHUNKSIZE 100
main () {
int i, chunk;
float a[N], b[N], c[N];
/* Some initializations */
for (i=0; i < N; i++)
a[i] = b[i] = i * 1.0;
chunk = CHUNKSIZE;
#pragma omp parallel for \
shared(a,b,c,chunk) private(i) \
schedule(static,chunk)
for (i=0; i < n; i++)
c[i] = a[i] + b[i];
}
Directiva PARALLEL SECTIONS
Scop: Directiva PARALLEL SECTIONS specific o regiune paralel care
contine o directiv SECTIONS unic. Directiva SECTIONS unic trebuie s
urmeze imediat, ca declaratie imediat urmtoare.
Format n Fortran:
!$OMP PARALLEL SECTIONS [clause ...]
DEFAULT (PRIVATE | SHARED | NONE)
SHARED (list)
PRIVATE (list)
FIRSTPRIVATE (list)
LASTPRIVATE (list)
REDUCTION (operator | intrinsic :
list)
COPYIN (list)
ORDERED
structured_block
72
!$OMP END PARALLEL SECTIONS
Format n C/C++:
#pragma omp parallel sections [clause ...] newline
default (shared | none)
shared (list)
private (list)
firstprivate (list)
lastprivate (list)
reduction (operator: list)
copyin (list)
ordered
structured_block
Clauze: Clauzele acceptate pot fi oricare din cele acceptate de directivele
PARALLEL si SECTIONS. Clauzele nediscutate nc sunt descrise n detaliu
mai departe, n sectiunea Clauze cu atribute de domeniu pentru date.
Constructe de sincronizare
Se consider un exemplu simplu n care dou fire pe dou procesoare diferite
ncearc ambele s incrementeze o variabil x n acelasi timp (se presupune c
x este la nceput 0):
THREAD 1:
increment(x)
{
x = x + 1;
}
THREAD 1:
10 LOAD A, (x address)
20 ADD A, 1
30 STORE A, (x address)
THREAD 2:
increment(x)
{
x = x + 1;
}
THREAD 2:
10 LOAD A, (x address)
20 ADD A, 1
30 STORE A, (x address)
O secvent la executie posibil este:
Firul 1 ncarc valoarea lui x n registrul A.
Firul 2 ncarc valoarea lui x n registrul A.
Firul 1 adun 1 la registrul A.
Firul 2 adun 1 la registrul A.
Firul 1 depune registrul A n locatia x.
Firul 2 depune registrul A n locatia x.
73
Valoarea rezultat pentru x va fi 1, nu 2 cum ar trebui s fie.
Pentru a evita situatiile de acest gen, incrementarea lui x trebuie s fie
sincronizat ntre cele dou fire pentru a ne asigura de rezultatul corect.
OpenMP asigur o varietate de constructe de sincronizare care controleaz cum
se deruleaz executia fiecrui fir n relatie cu alte fire ale fasciculului.
Directiva MASTER
Scop: Directiva MASTER specific o regiune care trebuie executat numai de
firul master al fasciculului. Toate celelalte fire din fascicul sar aceast sectiune
a codului. Nu exist vreo barier implicit asociat cu aceast directiv.
Formatul Fortran:
!$OMP MASTER
block
!$OMP END MASTER
Formatul C/C++:
#pragma omp master newline
structured_block
Restrictii: Este interzis a ramifica n sau nafara blocului MASTER.
Directiva CRITICAL
Scop: Directiva CRITICAL specific o regiune de cod care trebuie executat
succesiv (nu concomitent) de firele din fascicul.
Formatul Fortran:
!$OMP CRITICAL [ name ]
block
!$OMP END CRITICAL
Formatul C/C++:
#pragma omp critical [ name ] newline
structured_block
Note:
74
Dac un fir execut curent o regiune CRITICAL si un altul ajunge la acea
regiune CRITICAL si ncearc s o execute, el va sta blocat pn cnd primul
fir prseste regiunea CRITICAL.
Un nume optional face posibil existenta regiunilor CRITICAL multiple:
numele actioneaz ca identificatori globali. Regiunile CRITICAL diferite cu
acelasi nume sunt tratate ca aceeasi regiune.
Toate sectiunile CRITICAL fr nume sunt tratate ca o aceeasi sectiune.
Restrictii: nu este permis a se ramifica controlul n sau nafara unui bloc
CRITICAL.
Exemplu de construct CRITICAL: Toate firele dintr-un fascicul vor ncerca s
execute paralel din cauza constructului CRITICAL care ncorporeaz
incrementul lui x, numai un fir va fi abilitat s citeasc/incrementeze/citeasc x
la un moment dat.
n Fortran:
PROGRAM CRITICAL
INTEGER X
X = 0
!$OMP PARALLEL SHARED(X)
!$OMP CRITICAL
X = X + 1
!$OMP END CRITICAL
!$OMP END PARALLEL
END
n C/C++:
#include <omp.h>
main()
{
int x;
x = 0;
#pragma omp parallel shared(x)
{
#pragma omp critical
x = x + 1;
75
} /* end of parallel section */
Constructe de sincronizare
Directiva BARRIER
Scop: Directiva BARRIER sincronizeaz toate firele unui fascicul. Cnd o
directiv BARRIER este atins, orice fir asteapt n acel punct pn cnd toate
celelalte fire ating si ele acea barier. Toate firele reiau atunci executia n
paralel a codului consecutiv barierei.
Format n Fortran:
!$OMP BARRIER
Format n C/C++:
#pragma omp barrier newline
Restrictii: n C/C++, cea mai mic declaratie care contine o barier trebuie s
fie un bloc structurat. De exemplu:
GRESIT CORECT
if (x == 0)
#pragma omp barrier
if (x == 0)
{
#pragma omp barrier
}
Directiva ATOMIC
Scopul: Directiva ATOMIC specific faptul c o locatie particular de memorie
trebuie s fie actualizat atomic si nu lsate mai multe fire s ncerce s scrie n
ea. n esent, aceast directiv asigur o mini-sectiune CRITICAL.
Format n Fortran:
!$OMP ATOMIC
statement_expression
Format n C/C++:
#pragma omp atomic newline
statement_expression
76
Restrictii: directiva se aplic numai unei declaratii, cea imediat urmtoare. O
declaratie atomic trebuie s aibe una din formele urmtoare:
n Fortran:
x = x operator expr
x = expr operator x
x = intrinsic(x, expr)
x = intrinsic(expr, x)
x este o variabil scalar, expr este o expresie scalar care nu face referire la x,
intrinsic este una din functiile MAX, MIN, IAND, IOR sau IEOR, operator
este unul din urmtorii: +, *, -, /, .AND., .OR., .EQV. sau .NEQV.
n C/C++:
x binop = expr
x++
++x
x--
--x
x este o variabil scalar, expr este o expresie scalar care nu face referire la x,
binop nu este overloaded
1
si este una din urmtoarele +, *, -, /, &, ^, |, >> sau
<<.
Restrictii:
Directiva se aplic numai unei declaratii, cea care urmeaz imediat.
O declaratie atomic trebuie s aib una din formele urmtoare:
n Fortran:
x = x operator expr
x = expr operator x
x = intrinsic(x, expr)
x = intrinsic(expr, x)
x este o variabil scalar, expr este o expresie scalar care nu face referire la x,
intrinsic este una din functiile MAX, MIN, IAND, IOR sau IEOR, operator
este unul din urmtorii: +, *, -, /, .AND., .OR., .EQV. sau .NEQV.
n C/C++:
1
Overloading: n programare, abilitatea de a utiliza acelasi nume pentru mai mult de o
variabil sau procedur, care cere compilatorului s fac diferenta ntre ele contextual.
77
x binop = expr
x++
++x
x--
--x
x este o variabil scalar, expr este o expresie scalar care nu face referire la x,
binop nu este overloaded si este una din urmtoarele +, *, -, /, &, ^, |, >> sau
<<.
Not: numai ncrcarea si depozitarea lui x sunt atomice; evaluarea expresiei nu
este atomic.
Directiva FLUSH
Scopul: directiva FLUSH identific un punct de sincronizare la care
implementarea trebuie s furnizeze o vedere consistent a memoriei. La acest
punct, variabilele vizibile din fir sunt scrise napoi n memorie.
Formatul n Fortran:
!$OMP FLUSH (list)
Formatul n C/C++:
#pragma omp flush (list) newline
Note:
Lista optional este o list de variabile cu nume care vor fi evacuate n scopul
evitrii evacurii tuturor variabilelor. Pentru pointerii din list, pointerii nsisi
sunt evacuati, nu obiectele la care ei se refer.
Implementrile trebuie s asigure c orice modificare a variabilelor vizibile din
fir este vizibil tuturor firelor dup acest punct; compilatoarele trebuie s
restituie valorile din registre n memorie, hardware-ul ar putea necesita
evacuarea bufferelor de scriere etc.
Directiva FLUSH este implicat pentru directivele din tabelul de mai jos.
Directiva nu este implicat dac este prezent o clauz NOWAIT.
n Fortran n C / C++
BARRIER
CRITICAL si END CRITICAL
END DO
END PARALLEL
END SECTIONS
END SINGLE
barrier
critical la intrare si la iesire
ordered la intrare si la iesire
parallel la iesire
for la iesire
sections la iesire
78
ORDERED si END ORDERED single la iesire
Directiva ORDERED
Scop: directiva ORDERED specific faptul c iteratiile buclei incluse vor fi
executate n aceeasi ordine ca si cnd ar fi executate de un procesor secvential.
Formatul n Fortran:
!$OMP ORDERED
(block)
!$OMP END ORDERED
Formatul n C/C++:
#pragma omp ordered newline
structured_block
Restricitii: o directiv ORDERED poate aprea numai n extensia dinamic a
directivelor DO sau PARALLEL DO din Fortran si parallel for din C/C++.
Numai un fir este permis ntr-o sectiune ordered la un moment dat.
Nu este permis ramificarea n sau din blocurile ORDERED.
O iteratie a unei bucle nu trebuie s execute aceeasi directiv ORDERED mai
mult dect o dat si nu trebuie s execute mai mult de o directiv ORDERED.
O bucl care contine o directiv ORDERED trebuie s fie o bucl cu o clauz
ORDERED.
Directiva THREADPRIVATE
Scopul: directiva THREADPRIVATE este folosit pentru a face variabilele de
domeniu fisier global (n C/C++) sau blocurile common (n Fortran) locale si
persistente pentru un fir n executie de regiuni paralele multiple.
Formatul n Fortran:
!$OMP THREADPRIVATE (/cb/, ...)
cu cb nume de bloc common.
Formatul n C/C++:
#pragma omp threadprivate (list)
Note:
79
Directiva trebuie s apar dup declaratia listei de variabile/blocuri common.
Fiecare fir si ia apoi propria sa copie a variabilelor/blocului comun, astfel
datele scrise de un fir nu sunt vizibile celorlalte fire. De exemplu:
n Fortran:
PROGRAM THREADPRIV
INTEGER ALPHA(10), BETA(10), I
COMMON /A/ ALPHA
!$OMP THREADPRIVATE(/A/)
C Explicitly turn off dynamic threads
CALL OMP_SET_DYNAMIC(.FALSE.)
C First parallel region
!$OMP PARALLEL PRIVATE(BETA, I)
DO I=1,10
ALPHA(I) = I
BETA(I) = I
END DO
!$OMP END PARALLEL
C Second parallel region
!$OMP PARALLEL
PRINT *, 'ALPHA(3)=',ALPHA(3), ' BETA(3)=',BETA(3)
!$OMP END PARALLEL
END
n C/C++:
#include <omp.h>
int alpha[10], beta[10], i;
#pragma omp threadprivate(alpha)
main () {
/* Explicitly turn off dynamic threads */
omp_set_dynamic(0);
/* First parallel region */
#pragma omp parallel private(i,beta)
for (i=0; i < 10; i++)
alpha[i] = beta[i] = i;
80
/* Second parallel region */
#pragma omp parallel
printf("alpha[3]= %d and beta[3]= %d\n",alpha[3],
beta[3]);
}
La prima intrare ntr-o regiune paralel, datele din variabilele si blocurile
comune THREADPRIVATE ar trebui presupuse nedefinite, cu exceptia cazului
n care n directiva PARALLEL este mentionat clauza COPYIN.
Variabilele THREADPRIVATE difer de variabilele PRIVATE (discutate mai
jos) deoarece ele sunt abilitate s persiste ntre sectiuni paralel diferite ale
codului.
Restrictii:
Datele din obiectele THREADPRIVATE sunt garantate a persista numai dac
mecanismul firelor dinamice este nchis (turned off) si numrul de fire n
regiuni paralel diferite rmne constant. Setarea prin default a firelor dinamice
este nedefinit.
Directiva THREADPRIVATE trebuie s apar dup fiecare declaratie a unei
variabile private/unui bloc comun din fir.
n Fortran, numai blocurile comune cu nume pot fi fcute THREADPRIVATE.
Clauze privind atributul de domeniu al datelor
O problem important pentru programarea OpenMP este ntelegerea si
utilizarea domeniului acoperit de date.
Deoarece OpenMP se bazeaz pe modelul de programare cu memorie partajat,
cele mai multe variabile sunt utilizate n comun (shared) prin default.
Variabilele globale includ n Fortran blocurile COMMON, variabilele SAVE,
variabilele MODULE, iar n C variabilele cu domeniu fisier, statice.
Variabilele private includ indicii pentru bucle, variabilele de stiv din
subrutinele apelate din regiuni paralele. n Fortran variabilele automate dintr-un
bloc de declaratii.
Clauzele privind atributele de domeniu ale datelor sunt utilizate pentru a defini
explicit cum trebuie utilizate variabilele n domenii. n lista clauzelor regsim:
PRIVATE
FIRSTPRIVATE
LASTPRIVATE
SHARED
DEFAULT
REDUCTION
COPYIN
Clauzele privind atributele de domeniu al datelor sunt utilizate n combinatie cu
mai multe dirctive (PARALLEL, DO/for si SECTIONS) pentru a controla
domeniul de utilizare a variabilelor incluse.
81
Aceste constructe fac posibil controlul mediului de date n timpul executrii
constructelor paralel. Ele definesc cum si care variabile din sectiunea
secvential a programului sunt transferate ctre sectiunile paralel ale
programului si invers. Ele definesc care variabile vor fi vizibile tuturor firelor
din sectiunile paralel si care variabile vor fi alocate privat de toate firele.
Not: clauzele privind atributele de domeniu au efect numai n extinderea lor
lexical/static.
A se consulta tabelul cu sumarul clauzelor/directivelor pentru asocierea
directive-clauze.
Clauza PRIVATE
Scop: Clauza PRIVATE declar variabile care sunt private pentru fiecare fir.
Formatul n Fortran:
PRIVATE (list)
Formatul n C/C++:
private (list)
Note: Variabilele PRIVATE se comport dup cum urmeaz:
Un obiect nou de acelasi tip se declar o dat pentru fiecare fir din fascicul.
Toate referirile la obiectul originar sunt nlocuite cu referiri la obiectul nou.
Variabilele declarate PRIVATE sunt neinitializate pentru fiecare fir.
Comparatie ntre PRIVATE si THREADPRIVATE:
PRIVATE THREADPRIVATE
Articol de
date
C/C++: variabil
Fortran: variabil sau
bloc common
C/C++: variabil
Fortran: bloc common
Unde se
declar
La nceputul regiunii sau
grupei de lucru partajat
n declaratiile fiecrei rutine
utiliznd domeniul de bloc sau
de fisier global
Persistenta? Nu Da
Extindere Numai lexical cu
exceptia trecerii ca
argument al unei
subrutine
Dinamic
82
Initializare Cu FIRSTPRIVATE Cu COPYIN
ntrebri: pentru exemplele de cod cu THREADPRIVATE n C/C++ si Fortran:
Ce rezultat asteptati n alpha[3] si n beta[3] n programele de mai sus? De ce?
Pentru ambele exemple, alpha[3] trebuie s fie 3, beta[3] trebuie s fie zero sau
s aib o valoare nedefinit. Aceasta se ntmpl deoarece numai variabilele
THREADPRIVATE pot persista n regiuni paralele succesive.
Clauza SHARED
Scop: clauza SARED declar n lista ei variabile care sunt partajate ntre toate
firele fascicolului.
Formatul n Fortran:
SAHRED (list)
Formatul n C/C++:
shared (list)
Note:
O variabil partajat exist numai ntr-o locatie de memorie si toate firele pot
citi sau scrie la acea adres.
Este n responsabilitatea programatorului a asigura c firele multiple au acces
adecvat la variabilele SHARED (cum ar fi prin sectiunile CRITICAL).
Clauza DEFAULT
Scop: Clauza DEFAULT permite utilizatorului s specifice prin default un
domeniu PRIVATE, SHARED sau NONE pentru toate variabilele din
extinderea lexical a oricrei regiuni paralel.
Formatul n Fortran:
DEFAULT (PRIVATE | SHARED | NONE)
Formatul n C/C++:
default (shared | none)
Note:
Variabilele specifice pot fi absolvite de default utiliznd clauzele PRIVATE,
SHARED, FIRSTPRIVATE, LASTPRIVATE si REDUCTION.
83
Specificatia n C/C++ din OpenMP nu include private ca un default posibil.
Totusi, unele implementri pot avea prevzut aceast optiune.
Restrictii: numai clauza DEFAULT poate fi specificat pe o directiv
PARALLEL.
Clauza FIRSTPRIVATE
Scop: Clauza FIRSTPRIVATE combin comportarea clauzei PRIVATE cu
initializarea automat a variabilelor din lista ei.
Formatul n Fortran:
FIRSTPRIVATE (list)
Formatul n C/C++:
firstprivate (list)
Note:
Variabilele listate sunt initializate potrivit cu valorile obiectelor lor originare
nainte de intrarea n constructul paralel de lucru partajat.
Clauza LASTPRIVATE
Scop: Clauza LASTPRIVATE combin comportarea clauzei PRIVATE cu
copierea din iteratia ultim din bucl sau sectiune n variabila obiect originar.
Formatul n Fortran:
LASTPRIVATE (list)
Formatul n C/C++:
lastprivate (list)
Note:
Valorile copiate napoi n variabilele obiect originare se obtin din ultima iteratie
sau sectiune (secvential) a constructului care o contine.
De pild, un fir membru al unui fascicul care execut iteratia final a unei
sectiuni DO sau un fir membru al unui fascicul care execut ultima SECTION a
unui context SECTIONS execut copierea cu propriile lui valori.
Clauza COPYIN
Scop: Clauza COPYIN asigur un mijloc de a atribui aceeasi valoare
variabilelor THREADPRIVATE pentru toate firele unui fascicul.
84
Formatul n Fortran:
COPYIN (list)
Formatul n C/C++:
copyin (list)
Note:
Lista contine numele variabilelor de copiat. n Fortran lista poate contine att
nume de blocuri common ct si nume de variabile.
Variabilele firului master sunt sursa tuturor cpiilor. Firele fasciculului sunt
initializate cu valorile lor la intrarea n constructul paralel.
Clauza REDUCTION
Scop: Clauza REDUCTION execut o reducere pe variabilele care apar n list.
Pentru fiecare fir se creaz o copie privat pentru fiecare variabil din list. La
sfrsitul reducerii, variabila de reducere este aplicat tuturor cpiilor private ale
variabilelor partajate si rezultatul final este scris n variabila global folosit
partajat.
Formatul n Fortran:
REDUCTION (operator|intrinsic: list)
Formatul n C/C++:
reduction (operator: list)
Exemplu: REDUCTION produsul scalar de vectori:
Iteratiile buclei paralel vor fi distribuite n blocuri de dimensiune egal fiecrui
fir din fascicul (SCHEDULE STATIC).
La finalul constructului buclei paralel toate firele vor aduna valorile rezultatelor
lor pentru a actualiza copia global din firul master.
n Fortran:
PROGRAM DOT_PRODUCT
INTEGER N, CHUNKSIZE, CHUNK, I
PARAMETER (N=100)
PARAMETER (CHUNKSIZE=10)
REAL A(N), B(N), RESULT
85
! Some initializations
DO I = 1, N
A(I) = I * 1.0
B(I) = I * 2.0
ENDDO
RESULT= 0.0
CHUNK = CHUNKSIZE
!$OMP PARALLEL DO
!$OMP& DEFAULT(SHARED) PRIVATE(I)
!$OMP& SCHEDULE(STATIC,CHUNK)
!$OMP& REDUCTION(+:RESULT)
DO I = 1, N
RESULT = RESULT + (A(I) * B(I))
ENDDO
!$OMP END PARALLEL DO NOWAIT
PRINT *, 'Final Result= ', RESULT
END
n C/C++:
#include <omp.h>
main () {
int i, n, chunk;
float a[100], b[100], result;
/* Some initializations */
n = 100;
chunk = 10;
result = 0.0;
for (i=0; i < n; i++)
{
a[i] = i * 1.0;
b[i] = i * 2.0;
}
#pragma omp parallel for \
default(shared) private(i) \
schedule(static,chunk) \
reduction(+:result)
86
for (i=0; i < n; i++)
result = result + (a[i] * b[i]);
printf("Final result= %f\n",result);
}
Restrictii:
Variabilele din list trebuie s fie variabile scalare cu nume. Ele nu pot fi
masive sau variabile de tipul stucturilor. Ele trebuie de asemenea s fie
declarate SHARED n contextul care le include.
Operatiile de reducere pot s nu fie asociative pentru numere reale.
Clauza REDUCTION este gndit pentru a fi utilizat pe o regiune sau pe un
construct cu lucru partajat n care variabilele de reducere sunt utilizate numai n
declaratii care au una din formele urmtoare:
Fortran C / C++
x = x operator expr
x = expr operator x (except
subtraction)
x = intrinsic(x, expr)
x = intrinsic(expr, x)
x = x op expr
x = expr op x (except subtraction)
x binop = expr
x++
++x
x--
--x
x este o variabil scalar din list
expr este o expresie scalar care nu
face referire la x
intrinsic este MAX, MIN, IAND,
IOR sau IEOR
operator este +, *, -, .AND.,
.OR., .EQV. sau .NEQV.
x este o variabil scalar din list
expr este o expresie scalar care nu
face referire la x
op nu este overloaded si este +, *,
-, /, &, ^, |, && sau ||
binop nu este overloaded si este +,
*, -, /, &, ^ sau |
Un sumar al clauzelor/directivelor OpenMP
Tabelul urmtor sumarizeaz clauzele si acceptarea lor de directivele OpenMP.
Clauze Directive
87
P
A
R
A
L
L
E
L
D
O
/
f
o
r
S
E
C
T
I
O
N
S
S
I
N
G
L
E
P
A
R
A
L
L
E
L

D
O
/
f
o
r
P
A
R
A
L
L
E
L

S
E
C
T
I
O
N
S
IF x x x
PRIVATE x x x x x x
SHARED x x x x
DEFAULT x x x
FIRSTPRIVATE x x x x x x
LASTPRIVATE x x x x
REDUCTION x x x x x
COPYIN x x x
SCHEDULE x x
ORDERED x x
NOWAIT x x x
Urmtoarele directive OpenMP nu admit clauze:
MASTER
CRITICAL
BARRIER
ATOMIC
FLUSH
ORDERED
THREADPRIVATE
Implememtrile pot diferi si difer uneori de standard n ceea ce priveste
acceptarea clauzelor de ctre fiecare directiv.
88
Reguli de legtur si de asezare una-n-alta pentru directive
2
Cu exceptia mentiunii exprese, regulile se aplic att pentru implementrile
Fortran ct si pentru cele C/C++.
Not: Fortranul API defineste de asemenea un numr de reguli pentru Data
Environment. Acele reguli nu au fost reluate aici.
Reguli de legtur pentru directive:
Directivele DO/for, SECTIONS, SINGLE, MASTER si BARRIER sunt legate
de includerea dinamic PARALLEL dac exist o asemenea includere. Dac nu
este executat o regiune paralel, directivele acestea nu au nici un efect.
Directiva ORDERED se leag de buclele DO/for dinamice care o includ.
Directiva ATOMIC oblig accesul exclusiv n raport cu directivele ATOMIC
din toate firele, nu numai din fasciculul curent.
Directiva CRITICAL oblig accesul exclusiv n raport cu directivele
CRITICAL din toate firele, nu numai din fasciculul curent.
O directiv nu poate niciodat s se lege la vreo directiv din afara celei mai
apropiate directive PARALLEL care o include.
Reguli de asezare una-n-alta:
O directiv PARALLEL interioar dinamic unei alte directive PARALLEL
stabileste un nou fascicul care este compus numai din firul curent cu exceptia
cnd a fost abilitat paralelismul unul-n-altul.
Directivelor DO/for, SECTIONS si SINGLE care sunt legate de aceeasi
directiv PARALLEL nu li se permite a fi una-n-alta.
Directivele DO/for, SECTIONS si SINGLE nu sunt admise n extinderea
dinamic a regiunilor CRITICAL, ORDERED si MASTER.
Directivele CRITICAL cu acelasi nume nu sunt permise a fi una n interiorul
alteia.
Directivele BARRIER nu sunt permise n extinderea dinamic a regiunilor
DO/for, ORDERED, SECTIONS, SINGLE, MASTER si CRITICAL.
Directivele MASTER nu sunt permise n extinderea dinamic a directivelor
DO/for, SECTIONS si SINGLE.
Diectivele ORDERED nu sunt permise n extinderea dinamic a regiunilor
CRITICAL.
Orice directiv care este permis cnd se execut dinamic n interiorul unei
regiuni PARALLEL este de asemenea legal cnd se execut n afara regiunii
paralel. Cnd se execut dinamic n afara unei regiuni paralel specificat de
utilizator, directiva este executat n raport cu un fascicul compus numai din
firul master.
Rutinele de bibiliotec run-time
2
Sectiunea aceasta este n bun msur orientativ. Utilizatorii sunt ndemnati s consulte
documentatia implementrii de care dispun. Este posibil ca regulile s fie diferite de cele
prezentate aici.
89
Privire general:
Standardul OpenMP defineste o interfat API pentru apeluri la bibiliotec care
execut o varietate de functii:
Afl prin chestionare numrul de fire/procesoare, stabileste numrul de fire de
utilizat.
Blocri de domeniu general prin rutine adecvate (semafoare).
Rutine portabile pentru msurarea timpului universal (wall clock time).
Setarea functiilor de mediu de excutie: paralelism unul-n-altul, ajustarea
dinamic a firelor.
Pentru C/C++ poate fi necesar specificarea fisierului de incluziune omp.h.
Pentru functiile/rutinele de ncuiere (Lock):
Variabiele lact trebuie s fie accesate numai prin rutinele de ncuiere.
Pentru Fortran, variabilele lact trebuie s fie de tipul ntreg si de un gen
suficient de larg pentru a retine o adres.
Pentru C/C++, variabila lact trebuie s aib tipul omp_lock_t sau tipul
omp_nest_lock_t, n functie de functia utilizat.
Note de implemetare:
Implementarea poate s suporte sau poate s nu suporte paralelismul unul-n-
altul si/sau firele dinamice. Dac paralelismul unul-n-altul este suportat, este
adesea numai nominal prin acea c o regiune paralel una-n-alta poate avea
numai un fir.
Oricum, documentatia implementrii trebuie consultat pentru aceste detalii
sau se pot experimenta unele aspecte pentru a afla ceea ce nu este scris explicit
n documentatie.
OMP_SET_NUM_THREADS
Scop:
Seteaz numrul de fire care vor fi utilizate n regiunea paralel urmtoare.
Trebuie s fie un ntreg pozitiv.
Formatul n Fortran:
SUBROUTINE OMP_SET_NUM_THREADS(scalar_integer_expression)
Formatul n C/C++:
#include <omp.h>
void omp_set_num_threads(int num_threads)
Note si restrictii:
Mecanismul firelor dinamice modific efectul acestei rutine.
90
Enabled: specific numrul maxim de fire care pot fi utilizate pentru orice
regiune paralel prin mecanismul firelor dinamice.
Disabled: specific numrul exact de fire de utilizat pn la apelul urmtor la
aceast rutin.
Aceast rutin poate fi apelat numai din portiunile secventiale ale codului.
Acest apel are precedent fat de variabila de mediu OMP_NUM_THREADS.
OMP_GET_NUM_THREADS
Scop: returneaz numrul de fire care sunt n fasciculul curent si execut
regiunea pralel din care este apelat.
Format n Fortran:
INTEGER FUNCTION OMP_GET_NUM_THREADS()
Format n C/C++:
#include <omp.h>
int omp_get_num_threads(void)
Note si restrictii:
Dac acest apel este fcut dintr-o portiune secvential a programului sau dintr-o
regiune paralel una-n-alta care este serializat, returul este 1.
Numrul prin default al firelor este dependent de implementare.
OMP_GET_MAX_THREADS
Scop: returneaz valoarea maxim care poate fi returnat de un apel la functia
OPM_GET_NUM_THREADS.
Format n Fortran:
INTEGER FUNCTION OMP_GET_MAX_THREADS()
Format n C/C++:
#include <omp.h>
int omp_get_max_threads(void)
Note si restrictii:
Reflect n general numrul de fire setat de variabila de mediu
OMP_NUM_THREADS sau de rutina OMP_SET_NUM_THREADS() din
bibliotec.
Poate fi apelat att din regiunile seriale ale codului ct si din cele paralele.
91
OMP_GET_THREAD_NUM
Scop: returneaz numrul de fir al firului, n interiorul fasciculului, prin acest
apel. Numrul acesta va fi ntre 0 si OMP_GET_NUM_THREADS 1. Firul
master din fascicul este firul 0.
Format n Fotran:
INTEGER FUNCTION OMP_GET_THREAD_NUM()
Format n C/C++:
#include <omp.h>
int omp_get_thread_num(void)
Note si restrictii: dac este apelat dintr-o regiune paralel una-n-alta, functia
aceasta returneaz 0.
Exemple:
Exemplul 1 este modul corect de a determina numrul de fire ntr-o regiune
paralel.
Exemplul 2 este incorect variabila TID trebuie s fie PRIVATE.
Exemplul 3 este incorect apelul OMP_GET_THREAD_NUM este n afara
unei regiuni paralel.
Exemplele de determinare a numrului de fire dintr-o regiune paralel (n
Fortran):
Exemplul 1:
PROGRAM HELLO
INTEGER TID, OMP_GET_THREAD_NUM
!$OMP PARALLEL PRIVATE(TID)
TID = OMP_GET_THREAD_NUM()
PRINT *, 'Hello World from thread = ', TID
...
!$OMP END PARALLEL
END
Exemplul 2:
92
PROGRAM HELLO
INTEGER TID, OMP_GET_THREAD_NUM
!$OMP PARALLEL
TID = OMP_GET_THREAD_NUM()
PRINT *, 'Hello World from thread = ', TID
...
!$OMP END PARALLEL
END
Exemplul 3:
PROGRAM HELLO
INTEGER TID, OMP_GET_THREAD_NUM
TID = OMP_GET_THREAD_NUM()
PRINT *, 'Hello World from thread = ', TID
!$OMP PARALLEL
...
!$OMP END PARALLEL
END
OMP_GET_NUM_PROCS
Scop: returneaz numrul de procesoare care sunt la dispozitia programului.
Format n Fortran:
INTEGER FUNCTION OMP_GET_NUM_PROCS()
Format n C/C++:
#include <omp.h>
int omp_get_num_procs(void)
OMP_IN_PARALLEL
93
Scop: poate fi apelat pentru a determina dac sectiunea de cod n executie este
paralel sau nu.
Formatul n Fortran:
LOGICAL FUNCTION OMP_IN_PARALLEL()
Formatul n C/C++:
#include <omp.h>
int omp_in_parallel(void)
Note si restrictii:
n Fortran aceast functie returneaz .TRUE. dac este apelat din extensia
dinamic a unei regiuni care lucreaz n paralel si .FALSE. n alte situatii. n
C/C++ ea returneaz un ntreg nenul dac apelul este dintr-o zon paralel, zero
altminteri.
OMP_SET_DYNAMIC
Scop: abiliteaz si desabiliteaz ajustarea dinamic (de sistemul de executie) a
numrului de fire disponibile pentru executarea regiunilor paralel.
Formatul n Fortran:
SUBROUTINE OMP_SET_DYNAMIC(scalar_logical_expression)
Formatul n C/C++:
#include <omp.h>
void omp_set_dynamic(int dynamic_threads)
Note si restrictii:
Pentru Fortran, dac este apelat cu .TRUE. atunci numrul de fire disponibile
pentru regiunile paralel urmtoare poate fi modificat dinamic de mediul de
executie (run-time). Dac este apelat cu .FALSE. ca argument, modificarea
dinamic este fcut imposibil, este dezabilitat.
Pentru C/C++, dac argumentul dynamic_threads este nenul, atunci
mecanismul este abilitat, altminteri este dezabilitat.
Subrutina OMP_SET_DYMAMIC are ntietate fat de variabila de mediu
OMP_DYNAMIC.
Setarea prin default depinde de implementare.
Poate fi apelat dintr-o sectiune serial/secvential a programului.
94
OMP_GET_DYNAMIC
Scop: determinarea strii abilitat/dezabilitat a modificrii dinamice a firelor.
Formatul n Fortran:
LOGICAL FUNCTION OMP_GET_DYNAMIC()
Formatul n C/C++:
#include <omp.h>
int omp_get_dynamic(void)
Note si restrictii:
Pentru Fortran, aceast functie returneaz .TRUE. sau .FALSE. dup cum
modificarea dinamic a firelor este abilitat/dezabilitat.
Pentru C/C++, rezultatul apelului este non-zero/zero pentru cele dou situatii.
OMP_SET_NESTED
Scop: abilitarea sau dezabilitarea paralelismului unul-n-altul.
Formatul n Fortran:
SUBROUTINE OMP_SET_NESTED(scalar_logical_expression)
Formatul n C/C++:
#include <omp.h>
void omp_set_nested(int nested)
Note si restrictii:
Pentru Fortran, apelarea acestei functii cu argumentul .FALSE. dezabiliteaz
paralelismul unul-n-altul si l abiliteaz dac argumentul este .TRUE.
Pentru C/C++, dac variabila nested este nenul, atunci paralelismul unul-n-
altul este abilitat; dac este nul l dezabiliteaz.
Defaultul este cu paralelismul unul-n-altul dezabilitat, suspendat.
Apelul este mai tare ca precedent fat de variabila de mediu OPM_NESTED.
OMP_GET_NESTED
Scop: determin dac paralelismul unul-n-altul este abilitat sau nu.
Formatul n Fortran:
LOGICAL FUNCTION OMP_GET_NESTED
95
Formatul n C/C++:
#include <omp.h>
int omp_get_nested (void)
Note si restrictii:
n Fortran, aceast functie returneaz .TRUE. dac paralelismul unul-n-altul
este abilitat si .FALSE. n caz contrar.
n C/C++, se returneaz o valoare nenul dac paralelismul unul-n-altul este
abilitat si zero n caz contrar.
OMP_INIT_LOCK
Scopul: subrutina initializez un lact asociat cu variabila de lock.
Formatul n Fortran:
SUBROUTINE OMP_INIT_LOCK(var)
SUBROUTINE OMP_INIT_NEST_LOCK(var)
Formatul n C/C++:
#include <omp.h>
void omp_init_lock(omp_lock_t *lock)
void omp_init_nest_lock(omp_nest_lock_t *lock)
Note si restrictii:
Starea initial este unlocked.
Pentru versiunea Fortran var trebuie s fie un ntreg suficient de mare pentru a
retine o adres, cum ar fi INTEGER*8 pentru sistemele pe 64 de biti.
OMP_DESTROY_LOCK
Scop: aceast subrutin disociaz o variabil lact de orice lact.
Formatul n Fortran:
SUBROUTINE OMP_DESTROY_LOCK(var)
SUBROUTINE OMP_DESTROY_NEST_LOCK(var)
Formatul n C/C++:
#include <omp.h>
void omp_destroy_lock(omp_lock_t *lock)
void omp_destroy_nest_lock(omp_nest_lock_t *lock)
96
Note si restrictii:
Este nepermis a apela aceast subrutin cu o variabil lock care nu este
initializat.
n Fortran var trebuie s fie un ntreg suficient de larg pentru a retine o adres,
cum este INTEGER*8 pentru sistemele pe 64 de biti.
OMP_SET_LOCK
Scop: aceast subrutin oblig firul executant s astepte pn cnd un lact
specificat este disponibil. Un fir este proprietar al unui lock cnd acesta devine
disponibil.
Formatul n Fortran:
SUBROUTINE OMP_SET_LOCK(var)
SUBROUTINE OMP_SET_NEST_LOCK(var)
Formatul n C/C++:
#include <omp.h>
void omp_set_lock(omp_lock_t *lock)
void omp_set_nest_lock(omp_nest_lock_t *lock)
Note si restrictii:
Este nepermis a apela aceast rutin cu o variabil lock neinitializat.
Pentru Fortran, var trebuie s fie un ntreg suficient de larg pentru a retine o
adres, de pild INTEGER*8 pentru sistemele pe 64 de biti.
OMP_UNSET_LOCK
Scop: aceast subrutin descuie un lock dintr-o subrutin n executie.
Formatul n Fortran:
SUBROUTINE OMP_UNSET_LOCK(var)
SUBROUTINE OMP_UNSET_NEST_LOCK(var)
Formatul n C/C++:
#include <omp.h>
void omp_unset_lock(omp_lock_t *lock)
void omp_unset_nest_lock(omp_nest_lock_t *lock)
Note si restrictii:
Nu este permis a se apela aceast subrutin cu o variabil lock neinitializat.
97
Pentru Fortran, var trebuie s fie un ntreg suficient de mare pentru a retine o
adres, de pild INTEGER*8 pentru un sistem pe 64 de biti.
OMP_TEST_LOCK
Scop: aceast subrutin ncearc a seta un lock dar nu blocheaz dac lactul
este indisponibil.
Formatul n Fortran:
SUBROUTINE OMP_TEST_LOCK(var)
SUBROUTINE OMP_TEST_NEST_LOCK(var)
Formatul n C/C++:
#include <omp.h>
int omp_test_lock(omp_lock_t *lock)
int omp_test_nest_lock(omp_nest_lock_t *lock)
Note si restrictii:
n Fortran, este restituit .TRUE. dac lactul a fost setat cu succes, altminteri se
returneaz .FALSE.
Tot n Fortran, var trebuie s fie un ntreg suficient de mare pentru a retine o
adres, de pild INTEGER*8 pentru un sistem pe 64 de biti.
Pentru C/C++, este restituit o valoare nenul dac lactul a fost setat cu
succes, altminteri este restituit zero.
Este interzis a apela aceast subrutin cu o variabil lock neinitializat.
OMP_GET_WTIME
Scop: furnizeaz o rutin portabil de temporizare n timp universal (wall
clock).
Returneaz o valoare n dubl precizie egal cu numrul de secunde scurse de
la un anumit punct n trecut. Uzual, este folosit n pereche cu valoarea de la
primul apel sczut din valoarea apelului al doilea pentru a obtine timpul scurs
pentru un bloc de cod.
Proiectat a da timpii pe fir si de aceea nu poate fi consistent global, pe toate
firele unui fascicul; depinde de ceea ce face un fir comparativ cu alte fire.
Formatul n Fortran:
DOUBLE PRECISION FUNCTION OMP_GET_WTIME()
Formatul n C/C++:
98
#include <omp.h>
double omp_get_wtime(void)
Note si restrictii:
Necesit suportul versiunii OpenMP 2.0.
OMP_GET_WTICK
Scop: furnizeaz o rutin portabil de temporizare n timp universal (wall
clock).
Returneaz o valoare n dubl precizie egal cu numrul de secunde ntre dou
tic-uri succesive ale ceasului.
Formatul n Fortran:
DOUBLE PRECISION FUNCTION OMP_GET_WTICK()
Formatul n C/C++:
#include <omp.h>
double omp_get_wtick(void)
Note si restrictii:
Necesit suportul versiunii OpenMP 2.0.
Variable de mediu (de programare)
OpenMP furnizeaz patru variabile de mediu pentru controlul executiei unui
cod paralel.
Toate numele variabilelor de mediu sunt scrise cu majuscule. Valorile atribuite
lor nu sunt sensibile la upper/lower case.
OMP_SCHEDULE
Se aplic numai la directivele DO, PRALLEL DO (Fortran) si for, parallel for
(C/C++) care au clauzele lor schedule setate n timpul executiei (RUNTIME).
Valoarea acestei variabile determin modul cum sunt planificate iteratiile buclei
pe procesoare. De pild:
setenv OMP_SCHEDULE "guided, 4"
setenv OMP_SCHEDULE "dynamic"
OMP_NUM_THREADS
Fixeaz numrul maxim de fire utilizate n timpul executiei. De exemplu:
setenv OMP_NUM_THREADS 8
99
OMP_DYNAMIC
Abiliteaz sau dezabiliteaz ajustarea dinamic a numrului de fire disponibile
pentru executarea unei regiuni paralel. Valorile valide sunt TRUE sau FALSE.
De exemplu:
setenv OMP_DYNAMIC TRUE
OMP_NESTED
Abiliteaz sau dezabiliteaz paralelismul unul-n-altul. Valorile valide sunt
TRUE sau FALSE. De exemplu:
setenv OMP_NESTED TRUE
Note de implementare:
O implementare sau alta poate s permit sau nu paralelismul unul-n-altul
si/sau firele dinamice. Dac paralelismul unul-n-altul este suportat, el este
adesea numai nominal, n aceea c o regiune paralel una-n-alta poate avea
numai un fir.
Pentru detalii trebuie consultat documentatia implementrii utilizate sau se
poate experimenta pentru a afla ceea ce nu se poate gsi n documentatie.
Probleme de memorie si performant
Dimensiunea stivei de fir:
Standardul OpenMP nu specific ct spatiu de stiv trebuie s aib un fir. n
consecint, implementrile pot diferi prin dimensiunea de default a stivei de fir.
De obicei, dimensiunea prin default a stivei de fir este usor a fi epuizat. De
pild:
Compilator
Limita
stivei
Dimesiunea aproximativ a matricilor
(dubl precizie)
KAI Guide 1 MB 353 x 353
IBM AIX 4 MB 707 x 707
HP/Compaq
Tru64
5 MB 790 x 790
Intel IA32
Linux
8 MB 1000 x 1000
100
Firele care depsesc alocarea lor de stiv pot sau nu da eroare de segmentare. O
aplicatie poate continua executia cu coruperea datelor.
Cresterea limitei stivei de fir este de obicei posibil. Tabela de mai jos arat
cum se majoreaz dimensiunea stivei la 12 MB pentru mai multe platforme
uzuale.
Platforma Comenzi shell csh Comenzi shell ksh
IBM AIX
limit stacksize
12288
setenv XLSMPOPTS
"stack=12000000"
ulimit -s 12288
export
XLSMPOPTS="stack=12000000"
IA-32 Linux
limit stacksize
12288
setenv
KMP_STACKSIZE
12000000
ulimit -s 12288
export
KMP_STACKSIZE=12000000
HP/Compaq
Tru64
limit stacksize
12288
setenv
MP_STACK_SIZE
12000000
ulimit -s 12288
export
MP_STACK_SIZE=12000000
SGI Origin
limit stacksize
12288
setenv
MP_SLAVE_STACKSIZE
12000000
ulimit -s 12288
export
MP_SLAVE_STACKSIZE=12000000
Codurile legate statistic ar putea fi supuse la restrictii de stiv suplimentare.
101
MPI MESSAGE PASSING INTERFACE
Ce este MPI?
MPI (Message Passing Interface) este o interfat care poate fi considerat o
specificatie pentru cei care dezvolt si utilizeaz bibliotecile pentru transferul
de mesaje. Interfata MPI nu este ea nssi o bibliotec, ci mai curnd o
descriere a ceea ce ar trebui s fie o astfel de bibliotec. Mai direct, scopul MPI
este acela de a furniza un standard de uz larg n scrierea de programe care
transfer mesaje. Interfata ncearc s fie practic, portabil, eficient, flexibil.
Specificatiile interfetei au fost definite pentru programe scrise n C/C++ si n
Fortran.
Istorie si evolutie
MPI a rezultat din eforturile mai multor grupuri si persoane, eforturi care s-au
extins pe o perioad de circa 2 ani, ntre 1992 si 1994. Cteva repere istorice:
n anii 80 si anii 90 timpurii ai secolului trecut se dezvolt calculul paralel cu
memorie distribuit dar si un numr de instrumente software (incompatibile
mutual) de scriere a programelor, uzual cu compromisuri ntre portabilitate,
performante, functionalitate si pret. S-a nscut n mod natural necesitatea unui
standard.

102
n aprilie 1992 are loc un Workshop on Standards for Message Passing in a
Distributed Memory Environment sponsorizat de Center for Research on
Parallel Computing, Williamsburg, Virginia. S-a discutat despre trsturile de
baz ale unui standard de transfer al mesajelor, s-a constituit un grup de lucru
pentru continuarea procesului de standardizare. Imediat s-a elaborat si o
propunere preliminar.
n noiembrie 1992 grupul de lucru se ntruneste la Minneapolis. Este prezentat
n proiect MPI-1 de ctre ORNL (Oak Ridge National Laboratory). Grupul
adopt procedurile si organizarea pentru a forma un MPI Forum. MPIF a
cuprins ulterior 175 de persoane si 40 de organizatii care includeau productori
de calculatoare paralel, productori de software, persoane din mediul academic
si de cercetare.
n noiembrie 1993 are loc Supercomputing 93 Conference unde este prezentat
n proiect standardul MPI.
Versiunea final a fost lansat n mai 1994 si este accesibil la:
www.mcs.anl.gov/Projects/mpi/standard.html.
MPI-2 a recoltat ceea ce prima specificatie MPI a lsat n urm si se refer la
subiectele care sunt dincolo de acea prim specificatie. Originalul MPI a
devenit cunoscut ca MPI-1. MPI-2 este descris pe scurt mai jos. A fost finalizat
n 1996.
Azi, implementrile MPI sunt o combinatie de MPI-1 si MPI-2. Putine
implementri includ functionalittile complete ale ambelor versiuni.
Ratiuni de utilizare a MPI
Standardizare: MPI este unica bibliotec de transfer de mesaje care poate fi
considerat un standard. Este suportat de aproape toate platformele HPC (High
Performance Computing). Practic, MPI a nlocuit toate bibliotecile anterioare
care sunt orientate pe transferul de mesaje.
Portabilitate: Nu trebuie modificat codul surs cnd se trece de la o platform la
alta dac platformele suport (sau se pliaz pe) standardul MPI.
Performante: Implementrile productorilor sunt abilitate s exploateze
particularittile hardware native pentru a optimiza performatele.
Functionalitate: Sunt definite peste 115 rutine.
Accesibilitate: Este accesibil o varietate de implementri, att de domeniul
public ct si proprietate de firm.
Modelul de programare
103
MPI se preteaz la cele mai multe (dac nu la toate) modele(le) de programare
paralel cu memorie distribuit. n plus, MPI este utilizat la modul comun n
implementarea (din culise a) unor modele cu memorie partajat, cum este cel
paralel-pe-date, pe arhitecturi cu memorie distribuit.
Platforme hardware
Memorie distribuit: la origine, MPI a fost destinat sistemelor cu memorie
distribuit.
Memorie partajat: pe msur ce sistemele cu memorie partajat s-au rspndit,
n particular arhitecturile SMP/NUMA (Symmetric MultiProcessing/Non-
Uniform Memory Access), au aprut si implementrile MPI pe acest gen de
platforme.
Hibride: interfata MPI este acum utilizat aroape pe orice arhitectur paralel
obisnuit, inclusiv pe masinile masiv paralele, clusterele SMP, clusterele de
statii de lucru si retelele eterogene.
ntregul paralelism este explicit: programatorul este responsabil pentru
identificarea corect a paralelismului si pentru implementarea algoritmilor
paraleli prin mijlocirea constructelor MPI.
Numrul de taskuri dedicate de rulat ntr-un program paralel este static.
Taskurile noi nu pot fi derulate dinamic n timpul executiei (MPI-2 se ocup de
aceast problem).
Initializare
Fisierul header: cerut pentru toate programele/rutinele care fac apel la
biblioteca MPI.
n C
#include mpi.h
n Fortran
include mpif.h
Formatul apelurilor MPI:
n C
rc = MPI_Xxxxx(parametru, )
Exemplu:
rc = MPI_Bsend(&buf,count,type,dest,tag,comm)
Cod de eroare: returnat ca rc. MPI_SUCCESS dac apelul a reusit.
n Fortran
CALL MPI_XXXXX(parametru, , ierr)
call mpi_xxxxx(parametru, , ierr)
Exemplu:
CALL MPI_BSEND(buf,count,type,dest,tag,comm,ierr)
104
Cod de eroare: returnat ca parametru ierr. MPI_SUCCESS dac apelul a
reusit.
Numele din C sunt sensibile la upper/lower case. Numele din Fortran nu fac
distinctie ntre caracterele mari si mici.
Structura general a programelor MPI
Fisierul MPI include
. . . . . .
Initializarea MPI environment
. . . . . .
Executie si apeluri pentru transferul de mesaje
. . . . . .
ncheierea MPI environmemt
Comunicatori si grupuri
Pentru a defini procesele grupate ntr-o colectie, procese care pot comunica
ntre ele, MPI utilizeaz obiecte numite comunicatori si grupuri. Multe dintre
rutinele MPI cer specificarea unui comunicator ca argument.
Comunicatorii si grupurile vor fi obiectul unei discutii mai trziu. Deocamdat
se utilizeaz simplu MPI_COMM_WORLD ori de cte ori se cere un
comunicator; acesta este comunicatorul predefinit care include toate procesele
MPI.
Rang
105
ntr-un comunicator, fiecare proces are propriul su identificator de tipul ntreg
atribuit de sistem la initializarea sistemului. Un rang este uneori denumit
identificator de proces (process ID). Rangurile sunt numerotate fr lacune si
numerotarea ncepe cu 0.
Rangul este utilizat de programator pentru a specifica sursa sau destinatia
mesajelor. Uneori este utilizat de aplicatie conditional pentru a controla
executia programului (if rank = 0 etc.).
Rutine de administrare a mediului
Rutinele de administrare a mediului MPI sunt utilizate pentru definirea
domeniilor, cum ar fi initializarea si ncheierea mediului MPI, pentru
chestionarea mediului si identificare etc. Cea mai mare parte a acestor rutine
utilizate curent sunt descrise n continuare.
MPI_Init. Initializeaz mediul MPI de executie. Aceast functie trebuie apelat
n orice program MPI nainte de orice alt functie MPI si trebuie s fie chemat
o singur dat ntr-un program. Pentru programele n C, MPI_Init poate fi
utilizat pentru a trece argumentele din linia de comand tuturor proceselor, desi
aceast trecere nu-i cerut de standard si este dependent de implementare.
MPI_Init (&argc, &argv)
MPI_INIT (ierr)
MPI_Comm_size. Determin numrul de procese ntr-un grup asociat cu un
comunicator. n general se utilizeaz n comunicatorul MPI_COMM_WORLD
pentru a determina numrul de procese utilizate de o aplicatie.
MPI_Comm_size (comm, &size)
MPI_COMM_SIZE (comm, size, ierr)
MPI_Comm_rank. Determin rangul procesului apelant ntr-un comunicator.
Initial, fiecrui proces i se atribuie un rang ntreg unic ntre 0 si numrul de
procesoare 1 cuprinse n comunicatorul MPI_COMM_WORLD. Acest rang
este numit uneori task ID, identificator de task. Dac un proces se asociaz cu
alti comunicatori, el va avea un rang unic n fiecare din acesti comunicatori.
MPI_Comm_rank (comm, &rank)
MPI_COMM_RANK (comm, rank, ierr)
MPI_Abort. ncheie un proces asociat cu un comunicator. n cele mai multe
implementri MPI aceast functie ncheie toate procesele indiferent de
comunicatorul specificat.
MPI_Abort (comm, errorcode)
MPI_ABORT (comm, errorcode, ierr)
106
MPI_Get_processor_name. Returneaz numele procesorului dar si lungimea
numelui. Bufferul pentru name trebuie s fie de cel putin
MPI_MAX_PROCESSOR_NAME caractere. Ce se returneaz n name este
dependent de implementare poate s nu fie acelasi lucru cu iesirea comenzilor
hostname sau host.
MPI_Get_processor_name (&name, &resultlength)
MPI_GET_PROCESSOR_NAME (name, resultlength, ierr)
MPI_Initialized. Indic dac s-a apelat MPI_Init si returneaz un flag logic true
(1) sau false (0). MPI cere ca MPI_Init s fie apelat o dat si numai o dat de
fiecare proces. Acest problem se pune pentru module care vor s utilizeze
MPI si astfel sunt pregtite s apeleze MPI_Init dac este necesar.
MPI_Initialized rezolv tocmai aceast problem.
MPI_Initialized (&flag)
MPI_INITIALIZED (flag, ierr)
MPI_Wtime. Returneaz n secunde (dubl precizie) timpul universal (wall
clock time) scurs pe procesorul apelant.
MPI_Wtime ()
MPI_WTIME ()
MPI_Wtick. Returneaz rezolutia n secunde (dubl precizie) a MPI_Wtime.
MPI_Wtick ()
MPI_WTICK ()
MPI_Finalize. ncheie mediul de executie MPI. Aceast functie trebuie s fie
apelat ultima n orice program MPI nici o alt rutin MPI nu mai poate fi
apelat dup ea.
MPI_Finalize ()
MPI_FINALIZE (ierr)
Exemple de rutine de administrare a mediului:
n C:
#include "mpi.h"
#include <stdio.h>
int main(argc,argv)
int argc;
char *argv[]; {
int numtasks, rank, rc;
rc = MPI_Init(&argc,&argv);
if (rc != MPI_SUCCESS) {
107
printf ("Error starting MPI program.
Terminating.\n");
MPI_Abort(MPI_COMM_WORLD, rc);
}
MPI_Comm_size(MPI_COMM_WORLD,&numtasks);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
printf ("Number of tasks= %d My rank= %d\n",
numtasks,rank);
/******* do some work *******/
MPI_Finalize();
}
n Fortran:
program simple
include 'mpif.h'
integer numtasks, rank, ierr, rc
call MPI_INIT(ierr)
if (ierr .ne. MPI_SUCCESS) then
print *,'Error starting MPI program. Terminating.'
call MPI_ABORT(MPI_COMM_WORLD, rc, ierr)
end if
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr)
print *, 'Number of tasks=',numtasks,' My rank=',rank
C ****** do some work ******
call MPI_FINALIZE(ierr)
end
Rutine de comunicare punct la punct
Concepte generale
Tipuri de operatii punct-la-punct: Operatiile MPI punct-la-punct constau n
principal n transferul de mesaje ntre dou si numai dou taskuri MPI diferite.
Un task execut o operatie de expediere si cellalt task execut operatia de
primire.
108
Sunt tipuri diferite de rutine de trimitere si de primire utilizate pentru scopuri
diferite. Exemple:
Send sincron
Send/receive blocant
Send/receive fr blocare
Send bufferizat
Send/receive combinat
Send de tipul ready
Orice tip de rutin de trimitere (send) trebuie s aib ca pereche o rutin de
primire (receive).
MPI asigur si cteva rutine asociate cu operatiile send receive, cum sunt cele
pentru asteptarea sosirii unui mesaj sau pentru verificarea sosirii la destinatie a
unui mesaj.
Bufferizare: ntr-un univers perfect, fiecare operatie send ar fi perfect
sincronizat cu perechea receive. Practic, rareori se ntmpl asa. ntr-un mod
sau altul, implementrile MPI trebuie s aib capacitatea de a memora date
dac cele dou taskuri sunt nesincrone.
Iat dou cazuri:
Procesul A trimite un mesaj cu 5 secunde mai nainte ca receptia n B s fie
pregtit. Unde se gseste mesajul pn la momentul cnd procesul B este gata
s-l preia?
Mai multe trimiteri sosesc deodat la acelasi proces destinatie, proces care nu
poate accepta trimiterile altfel dect una dup alta: ce se ntmpl cu mesajele
sosite?
Implementarea MPI (nu standardul MPI) decide ce se ntmpl cu datele n
aceste cazuri. Tipic, este alocat/rezervat un buffer de sistem pentru a retine
datele n tranzit. Figura alturat ilustreaz o posibilitate.
109
Spatiul de bufferizare al sistemului este:
Opac pentru programator si este administrat integral de biblioteca MPI.
Resurs finit care poate fi cu usurint epuizat.
Adesea misterios si nu prea bine documentat/explicat.
Posibil a exista la procesul expeditor, la procesul receptor sau la ambele
procese.
Ceva care poate spori performanta programului deoarece admite ca
operatiile send receive s fie asincrone.
Spatiul de adresare administrat de utilizator (variabilele programului) este
denumit buffer de aplicatie. MPI asigur si un buffer de trimiteri administrabil
de utilizator.
Cu blocare/fr blocare: Multe din rutinele MPI punct-la-punct pot fi blocante
sau non-blocante.
Cu blocare: O rutin de trimitere cu blocare revine numai dup ce este sigur
c a modificat bufferul de aplicatie (prin trimiterea datelor) care este gata
pentru a fi reutilizat. Sigur nseamn c modificrile nu vor afecta datele
destinate taskului de receptie. Sigur nu implic receptionarea efectiv a acelor
date: ele pot foarte bine s mai stea nc un timp n bufferul de sistem.
O trimitere cu blocare poate fi sincron, ceea ce nseamn c exist un schimb
(handshaking) cu taskul de primire care confirm trimiterea n sigurant.
O trimitere cu blocare poate fi asincron dac este utilizat un buffer de sistem
pentru retinerea (temporar a) datelor n vederea livrrii ulterioare ctre
receptor.
O primire cu blocare revine numai dup ce datele au sosit si sunt gata pentru
a fi utilizate de program.
110
Fr blocare: Rutinele de trimitere si de primire fr blocare se comport
similar: ele revin aproape imediat. Pentru a se ncheia, ele nu asteapt vreun
eveniment comunicational, cum ar fi copierea unui mesaj din memoria
utilizator n spatiul bufferului de sistem sau sosirea efectiv a mesajului.
Operatiile fr blocare cer pur si simplu bibliotecii MPI s execute operatia
de ndat ce poate. Utilizatorul nu poate prezice cnd se va produce executia
acelei operatii.
Este nesigur a modifica bufferul de aplicatie (spatiul variabilelor) pn cnd nu
se cunoaste faptul c operatia fr blocare cerut a fost efectiv executat de
bibliotec. Exist rutine de asteptare utilizate pentru a face aceast confirmare.
Comunicatiile fr blocare sunt utilizate n primul rnd pentru a suprapune
calculele cu comunicarea si pentru exploatarea unor posibile cstiguri de
performant.
Ordine si corectitudine:
Ordine: MPI garanteaz c mesajele nu se amestec unul cu altul. Dac un
expeditor trimite succesiv dou mesaje (mesajul 1 si mesajul 2) la aceeasi
destinatie si ambele sunt pereche cu acelasi receive, operatia de receptie va
primi mesajul 1 nainte de mesajul 2. Dac un receptor posteaz succesiv dou
primiri (primirea 1 si primirea 2) si ambele caut spre acelasi mesaj, primirea 1
se va produce naintea primirii 2. Regulile de ordine nu se aplic dac sunt mai
multe fire care particip la operatiile de comunicare.
Corectitudine: Interfata MPI nu garanteaz corectitudinea este obligatia
programatorului a preveni operatiunile incomplete (operation starvation).
Exemplu: Taskul 0 trimite un mesaj la taskul 2. Dar si taskul 1 trimite un mesaj
n competitie care este pereche cu receive-ul din taskul 2. Numai una din
trimiteri va fi executat pn la capt.
Argumentele rutinelor MPI de transfer de mesaje
Rutinele MPI de comunicare punct-la-punct au n general o list de argumente
care arat ca n exemplele care urmeaz.
Trimitere cu blocare:
MPI_Send(buffer,count,type,dest,tag,comm)
Trimitere fr blocare:
MPI_Isend(buffer,count,type,dest,tag,comm,request)
Receptie cu blocare:
MPI_Recv(buffer,count,type,source,tag,comm,status)
Receptie fr blocare:
MPI_Irecv(buffer,count,type,source,tag,comm,request)
Buffer: spatiul de adresare al unei aplicatii (program) care se asociaz datelor
care trebuie trimise sau primite. n cele mai multe cazuri, acesta este pur si
simplu numele variabilei care trebuie trimis/primit. Pentru programele n C,
111
acest argument este trecut prin referire si trebuie uzual s fie prefixat de
caracterul ampersand: &var1.
Contor de date (count): indic numrul de articole-date de un anumit tip care
trebuie trimise.
Tipul datelor (type): din ratiuni de portabilitate, MPI predefineste tipurile sale
de date elementare. Tabelul care urmeaz contine tipurile de date prevzute de
standardul MPI.
Tipuri de date n C Tipuri de date n Fortran
MPI_CHAR char cu semn MPI_CHARACTER Character(1)
MPI_SHORT
short int cu
semn
MPI_INT int cu semn MPI_INTEGER integer
MPI_LONG
long int cu
semn
MPI_UNSIGNED_CHAR char fr semn
MPI_UNSIGNED_SHORT
short int fr
semn
MPI_UNSIGNED int fr semn
MPI_UNSIGNED_LONG
long int fr
semn
MPI_FLOAT float MPI_REAL real
MPI_DOUBLE double MPI_DOUBLE_PRECISION
double
precision
MPI_LONG_DOUBLE long double
MPI_COMPLEX complex
MPI_DOUBLE_COMPLEX
double
complex
MPI_LOGICAL logical
MPI_BYTE 8 digiti binari MPI_BYTE 8 digiti binari
MPI_PACKED date n
pachete sau
nu, cu
MPI_Pack()/
MPI_PACKED date n
pachete sau
nu, cu
MPI_Pack()/
112
MPI_Unpack MPI_Unpack
Note:
Programatorii pot crea tipuri de date proprii (tipuri de date derivate; v.mai jos).
MPI_BYTE si MPI_PACKED nu corespund tipurilor standard din C sau
Fortran.
Standardul MPI include urmtoarele tipuri de date optionale:
C: MPI_LONG_LONG_INT.
Fortran: MPI_INTEGER1, MPI_INTEGER2, MPI_INTEGER4, MPI_REAL2,
MPI_REAL4, MPI_REAL8.
Unele implementri pot include tipuri de date elementare n plus
(MPI_LOGICAL2, MPI_COMPLEX32 etc.). Trebuie verificat fisierul MPI
header.
Destinatie (dest): un argument al rutinelor de trimitere care indic procesul
unde mesajul trebuie livrat. Se mentioneaz ca rangul procesului primitor.
Sursa (source): un argument al rutinelor de primire care indic procesul de
provenient a mesajului. Specificat ca rangul procesului expeditor. Sursa poate
fi setat universal ca fiind MPI_ANY_SOURCE, ceea ce face posibil primirea
unui mesaj de la orice task.
Tag: un ntreg nenegativ arbitrar atribuit de programator pentru identificarea
unic a mesajului. Operatiile send si receive trebuie s se potriveasc la
etichetele (tags) mesajului. Pentru operatia de primire se poate utiliza
MPI_ANY_TAG pentru a primi orice mesaj, indiferent de eticheta lui.
Standardul MPI garanteaz utilizarea de etichete (tags) de la 0 la 32767 dar
unele implementri permit domenii mai ntinse dect acesta.
Comunicator (comm): indic contextul comunicrii sau multimea de procese
pentru care cmpurile surs si destinatie sunt valide. Cu exceptia cazurilor n
care programatorul creeaz comunicatori noi, se foloseste de obicei
comunicatorul predefinit MPI_COMM_WORLD.
Status: pentru o operatie de primire, indic sursa mesajului si eticheta lui. n C,
acest argument este un pointer la o structur predefinit MPI_Status (explicit:
stat.MPI_SOURCE stat.MPI_TAG). n Fortran, este vorba de un masiv de
ntregi de dimensiunea MPI_STATUS_SIZE (explicit: stat(MPI_SOURCE)
stat(MPI_TAG).
n plus, numrul adevrat de bytes primiti este obtenabil din Status via rutina
MPI_Get_count.
Request: utilizat de operatiile de trimitere si primire fr blocare. Deoarece
operatiile fr blocare pot reveni nainte ca spatiul cerut de bufferul sistemului
s fie obtinut, sistemul genereaz un request number unic. Programatorul
utilizeaz acest handle atribuit (ntr-o rutin de tip WAIT) pentru a determina
ncheierea operatiei fr blocare. n C, acest argument este un pointer ctre o
structur predefinit MPI_Request. n Fortran acesta este un ntreg.
113
Rutine de transfer de mesaje cu blocare
Rutinele de transfer de mesaje cu blocare cel mai frecvent utilizate sunt descrise
n continuare.
MPI_Send. Operatia de trimitere cu blocare de baz. Rutina revine numai dup
ce bufferul de aplicatie din taskul expeditor este liber pentru refolosire. De
retinut c aceast rutin poate fi implementat diferit pe sisteme diferite.
Standardul MPI permite utilizarea unui buffer de sistem dar nu-l reclam
neaprat. Unele implementri pot utiliza n realitate o trimitere sincron
(discutat mai departe) pentru a implementa trimiterea de baz cu blocare.
MPI_Send (&buf,count,datatype,dest,tag,comm)
MPI_SEND (buf,count,datatype,dest,tag,comm,ierr)
MPI_Recv. Primeste un mesaj si blocheaz pn cnd datele cerute sunt
disponibile n bufferul de aplicatie din taskul receptor.
MPI_Recv(&buf,count,datatype,source,tag,comm,
&status)
MPI_RECV(buf,count,datatype,source,tag,comm,
status,ierr)
MPI_Ssend. Trimitere sincron cu blocare. Trimite un mesaj si blocheaz pn
cnd bufferul de aplicatie din taskul expeditor este liber pentru reutilizare si
pn cnd procesul destinatar a nceput primirea mesajului.
MPI_Ssend (&buf,count,datatype,dest,tag,comm)
MPI_SSEND (buf,count,datatype,dest,tag,comm,ierr)
MPI_Bsend. Trimitere bufferizat cu blocare: permite programatorului s aloce
spatiul necesar bufferului n care datele pot fi copiate/depuse pn cnd sunt
expediate. Fereste comunicarea de problemele asociate cu un spatiu al
bufferului de sistem insuficient. Rutina revine dup ce datele au fost copiate din
spatiul bufferului de aplicatie n bufferul alocat trimiterii. Trebuie utilizat cu
rutina MPI_Buffer_attach.
MPI_Bsend (&buf,count,datatype,dest,tag,comm)
MPI_BSEND (buf,count,datatype,dest,tag,comm,ierr)
MPI_Buffer_attach si
MPI_Buffer_detach sunt utilizate de programator pentru alocarea/dealocarea
spatiului pentru bufferul de mesaj utilizat de rutina MPI_Bsend. Argumentul
size este specificat n bytes date actuale, nu ca un numr de elemente-date.
Unui proces nu i se poate atasa mai multe buffere concomitent, ci unul singur.
De notat c implementarea IBM utilizeaz MPI_BSEND_OVERHEAD bytes
ai bufferului alocat pentru overhead.
MPI_Buffer_attach (&buffer,size)
MPI_Buffer_detach (&buffer,size)
MPI_BUFFER_ATTACH (buffer,size,ierr)
MPI_BUFFER_DETACH (buffer,size,ierr)
114
MPI_Rsend. Trimitere ready cu blocare. Trebuie utilizat numai atunci cnd
programatorul este sigur c perechea receive a fost deja postat, este activ.
MPI_Rsend (&buf,count,datatype,dest,tag,comm)
MPI_RSEND (buf,count,datatype,dest,tag,comm,ierr)
MPI_Sendrecv. Expediaz un mesaj si afiseaz un receive nainte de blocare.
Blocheaz pn cnd bufferul de aplicatie expeditor este liber pentru reutilizare
si pn cnd bufferul de aplicatie receptor contine mesajul receptionat.
MPI_Sendrecv(&sendbuf,sendcount,sendtype,dest,
sendtag,&recvbuf,recvcount,recvtype,source,
recvtag,comm,&status)
MPI_SENDRECV(sendbuf,sendcount,sendtype,dest,
sendtag,recvbuf,recvcount,recvtype,source,
recvtag,comm,status,ierr)
MPI_Wait
MPI_Waitany
MPI_Waitall
MPI_Waitsome. MPI_Wait blocheaz pn cnd o operatie specificat de
trimitere sau primire fr blocare este ncheiat. Pentru operatii fr blocare
multiple programatorul poate specifica un final oarecare, toate finalurile sau
unele din finaluri.
MPI_Wait (&request,&status)
MPI_Waitany (count,&array_of_requests,&index,
&status)
MPI_Waitall (count,&array_of_requests,
&array_of_statuses)
MPI_Waitsome (incount,&array_of_requests,&outcount,
&array_of_offsets, &array_of_statuses)
MPI_WAIT (request,status,ierr)
MPI_WAITANY (count,array_of_requests,index,status,
ierr)
MPI_WAITALL (count,array_of_requests,
array_of_statuses,ierr)
MPI_WAITSOME (incount,array_of_requests,outcount,
array_of_offsets, array_of_statuses,ierr)
MPI_Probe. Execut o testare a blocrii pentru un mesaj. Argumentele generale
MPI_ANY_SOURCE si MPI_ANY_TAG pot fi utilizate pentru a testa un
mesaj de la nu import ce surs la nu import ce destinatie. Pentru rutina n C,
se returneaz sursa si eticheta real n structura de stare status, ca
status.MPI_SOURCE si status.MPI_TAG. Pentru rutina n Fortran, sursa si
eticheta se returneaz n masivele ntregi status(MPI_SOURCE) si
status(MPI_TAG).
MPI_Probe (source,tag,comm,&status)
MPI_PROBE (source,tag,comm,status,ierr)
Exemple de rutine de transfer de mesaje cu blocare. Taskul 0 trimite un ping la
taskul 1 si asteapt returnarea unui ping.
115
n C:
#include "mpi.h"
#include <stdio.h>
int main(argc,argv)
int argc;
char *argv[]; {
int numtasks, rank, dest, source, rc, count, tag=1;
char inmsg, outmsg='x';
MPI_Status Stat;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (rank == 0) {
dest = 1;
source = 1;
rc = MPI_Send(&outmsg, 1, MPI_CHAR, dest, tag,
MPI_COMM_WORLD);
rc = MPI_Recv(&inmsg, 1, MPI_CHAR, source, tag,
MPI_COMM_WORLD, &Stat);
}
else if (rank == 1) {
dest = 0;
source = 0;
rc = MPI_Recv(&inmsg, 1, MPI_CHAR, source, tag,
MPI_COMM_WORLD, &Stat);
rc = MPI_Send(&outmsg, 1, MPI_CHAR, dest, tag,
MPI_COMM_WORLD);
}
rc = MPI_Get_count(&Stat, MPI_CHAR, &count);
printf("Task %d: Received %d char(s) from task %d with tag
%d \n",
rank, count, Stat.MPI_SOURCE, Stat.MPI_TAG);
MPI_Finalize();
}
n Fortran:
program ping
116
include 'mpif.h'
integer numtasks, rank, dest, source, count, tag, ierr
integer stat(MPI_STATUS_SIZE)
character inmsg, outmsg
outmsg = 'x'
tag = 1
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr)
if (rank .eq. 0) then
dest = 1
source = 1
call MPI_SEND(outmsg, 1, MPI_CHARACTER, dest, tag,
& MPI_COMM_WORLD, ierr)
call MPI_RECV(inmsg, 1, MPI_CHARACTER, source, tag,
& MPI_COMM_WORLD, stat, ierr)
else if (rank .eq. 1) then
dest = 0
source = 0
call MPI_RECV(inmsg, 1, MPI_CHARACTER, source, tag,
& MPI_COMM_WORLD, stat, err)
call MPI_SEND(outmsg, 1, MPI_CHARACTER, dest, tag,
& MPI_COMM_WORLD, err)
endif
call MPI_GET_COUNT(stat, MPI_CHARACTER, count, ierr)
print *, 'Task ',rank,': Received', count, 'char(s)
from task',
& stat(MPI_SOURCE), 'with tag',stat(MPI_TAG)
call MPI_FINALIZE(ierr)
end
Rutine pentru transferul de mesaje fr blocare
Sunt descrise mai jos cele mai utilizate rutine pentru transferul de mesaje fr
blocare.
MPI_Isend. Identific o zon de memorie care s serveasc ca buffer de
trimitere. Procesarea continu imediat fr asteptarea copierii mesajului din
bufferul de aplicatie. Un handle de cerere de comunicare este returnat pentru a
manipula starea (status) mesajului n derulare. Programul nu trebuie s
117
modifice bufferul de aplicatie pn cnd apelurile urmtoare la MPI_Wait sau
la MPI_Test nu indic ncheierea acelei expedieri fr blocare.
MPI_Isend (&buf,count,datatype,dest,tag,comm,
&request)
MPI_ISEND (buf,count,datatype,dest,tag,comm,
request,ierr)
MPI_Irecv. Identific o zon din memorie care s serveasc ca buffer de
primire. Procesarea continu imediat fr a astepta ca mesajul s fie primit si
copiat n bufferul de aplicatie. Este returnat un handle pentru solicitarea de
comunicare, pentru manipularea strii mesajului n derulare. Programul trebuie
s utilizeze apeluri la la MPI_Wait sau la MPI_Test pentru a determina dac
operatia de primire fr blocare s-a finalizat si mesajul cerut este disponibil n
bufferul de aplicatie.
MPI_Irecv (&buf,count,datatype,source,tag,comm,
&request)
MPI_IRECV (buf,count,datatype,source,tag,comm,
request,ierr)
MPI_Issend. Trimitere sincron fr blocare. Similar cu MPI_Isend(), cu
exceptia detaliului c MPI_Wait() sau MPI_Test() indic momentul cnd
procesul destinatar a primit mesajul.
MPI_Issend (&buf,count,datatype,dest,tag,comm,
&request)
MPI_ISSEND (buf,count,datatype,dest,tag,comm,
request,ierr)
MPI_Ibsend. Trimitere bufferizat fr blocare. Similar cu MPI_Bsend() cu
exceptia faptului c MPI_Wait() sau MPI_Test() indic momentul cnd
procesul destinatar a primit mesajul. Trebuie utilizat cu rutina
MPI_Buffer_attach.
MPI_Ibsend (&buf,count,datatype,dest,tag,comm,
&request)
MPI_IBSEND (buf,count,datatype,dest,tag,comm,
request,ierr)
MPI_Irsend. Trimitere ready fr blocare. Similar cu MPI_Rsend() cu
deosebirea c MPI_Wait() sau MPI_Test() indic momentul cnd procesul
destinatar a primit mesajul. Trebuie utilizat numai dac programatorul este
sigur c receive-ul pereche a fost deja postat.
MPI_Irsend (&buf,count,datatype,dest,tag,comm,
&request)
MPI_IRSEND (buf,count,datatype,dest,tag,comm,
request,ierr)
MPI_Test
MPI_Testany
MPI_Testall
MPI_Testsome. MPI_Test verific statutul/starea unei operatii de trimitere sau
de primire fr blocare. Parametrul flag este returnat ca true (1) dac operatia
118
s-a ncheiat, sau ca false (0) dac operatia nu s-a ncheiat. Pentru operatii fr
blocare multiple, programatorul poate specifica any, all sau some adic
orice finalizare, toate finalizrile sau unele finalizri.
MPI_Test (&request,&flag,&status)
MPI_Testany (count,&array_of_requests,&index,&flag,
&status)
MPI_Testall (count,&array_of_requests,&flag,
&array_of_statuses)
MPI_Testsome (incount,&array_of_requests,&outcount,
&array_of_offsets, &array_of_statuses)
MPI_TEST (request,flag,status,ierr)
MPI_TESTANY (count,array_of_requests,index,flag,
status,ierr)
MPI_TESTALL (count,array_of_requests,flag,
array_of_statuses,ierr)
MPI_TESTSOME (incount,array_of_requests,outcount,
array_of_offsets, array_of_statuses,ierr)
MPI_Iprobe. Execut un test fr blocare pentru un mesaj. Identificatorii
generali MPI_ANY_SOURCE si MPI_ANY_TAG pot fi utilizati pentru
testarea unui mesaj din nu import ce surs sau care poart indiferent ce
etichet. Parametrul ntreg flag este returnat true (1) dac un mesaj a sosit si
false (0) dac acesta nu a sosit. Pentru rutina n C, sursa real si eticheta real
sunt returnate n structura de stare ca status.MPI_SOURCE si status.MPI_TAG.
Pentru rutina Fortran, ele sunt returnate n masivele intregi
status(MPI_SOURCE) si status(MPI_TAG).
MPI_Iprobe (source,tag,comm,&flag,&status)
MPI_IPROBE (source,tag,comm,flag,status,ierr)
Exemple de rutine de transfer de mesaje: schimbarea cu vecinul cel mai
apropiat n topologia circular.
n limbajul C:
#include "mpi.h"
#include <stdio.h>
int main(argc,argv)
int argc;
char *argv[]; {
int numtasks, rank, next, prev, buf[2], tag1=1, tag2=2;
MPI_Request reqs[4];
MPI_Status stats[4];
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
119
prev = rank-1;
next = rank+1;
if (rank == 0) prev = numtasks - 1;
if (rank == (numtasks - 1)) next = 0;
MPI_Irecv(&buf[0], 1, MPI_INT, prev, tag1, MPI_COMM_WORLD,
&reqs[0]);
MPI_Irecv(&buf[1], 1, MPI_INT, next, tag2, MPI_COMM_WORLD,
&reqs[1]);
MPI_Isend(&rank, 1, MPI_INT, prev, tag2, MPI_COMM_WORLD,
&reqs[2]);
MPI_Isend(&rank, 1, MPI_INT, next, tag1, MPI_COMM_WORLD,
&reqs[3]);

{ do some work }
MPI_Waitall(4, reqs, stats);
MPI_Finalize();
}
n Fortran:
program ringtopo
include 'mpif.h'
integer numtasks, rank, next, prev, buf(2), tag1, tag2,
ierr
integer stats(MPI_STATUS_SIZE,4), reqs(4)
tag1 = 1
tag2 = 2
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr)
prev = rank - 1
next = rank + 1
if (rank .eq. 0) then
prev = numtasks - 1
endif
if (rank .eq. numtasks - 1) then
next = 0
endif
120
call MPI_IRECV(buf(1), 1, MPI_INTEGER, prev, tag1,
& MPI_COMM_WORLD, reqs(1), ierr)
call MPI_IRECV(buf(2), 1, MPI_INTEGER, next, tag2,
& MPI_COMM_WORLD, reqs(2), ierr)
call MPI_ISEND(rank, 1, MPI_INTEGER, prev, tag2,
& MPI_COMM_WORLD, reqs(3), ierr)
call MPI_ISEND(rank, 1, MPI_INTEGER, next, tag1,
& MPI_COMM_WORLD, reqs(4), ierr)
C do some work
call MPI_WAITALL(4, reqs, stats, ierr);
call MPI_FINALIZE(ierr)
end
Rutine de comunicare colectiv
Comunicarea colectiv trebuie s implice toate procesele din domeniul unui
comunicator. Toate procesele sunt prin default membre ale comunicatorului
MPI_COMM_WORLD.
Este responsabilitatea programatorului a se asigura c toate procesele dintr-un
comunicator particip n orice operatie colectiv.
Tipuri de operatii colective:
Sincronizarea procesele asteapt pn cnd toate procesele membre ale
grupului au atins punctul de sincronizare.
Deplasri de date difuzare (broadcast), distribuire/colectare, toti-cu-toti.
Calcule colective (reduceri) un membru al grupului colecteaz date de la
ceilalti membri si execut o operatie (min, max, add, multiply etc.) asupra
acelor date.
Consideratii si restrictii la programare:
Operatiile colective sunt blocante.
Rutinele de comunicare colectiv nu preiau ca argumente etichete de mesaj.
Operatiile colective ntr-un subset de procese sunt executate prin partitionarea
prealabil a subseturilor n grupe noi si apoi atasarea grupelor noi la
comunicatori noi (ceea ce se discut mai jos n sectiunea privind administrarea
rutinelor de comunicare n grup si pe comunicator).
Se pot utiliza numai cu tipurile MPI predefinite, nu cu tipurile MPI derivate.
Rutinele de comunicare colectiv sunt prezentate sistematic imediat mai jos.
121
MPI_Barrier. Creaz o sincronizare cu barier ntr-un grup. Cnd ajunge la
apelul MPI_Barrier, fiecare task se blocheaz pn cnd toate taskurile din grup
ating acelasi apel la MPI_Barrier.
MPI_Barrier (comm)
MPI_BARRIER (comm,ierr)
MPI_Bcast. Difuzeaz (trimite) un mesaj de la procesul cu rangul root tuturor
celorlalte procese din grup.
MPI_Bcast (&buffer,count,datatype,root,comm)
MPI_BCAST (buffer,count,datatype,root,comm,ierr)
MPI_Scatter
MPI_Scatter. Distribuie mesaje distincte de la o singur surs fiecrui task din
grup.
MPI_Scatter (&sendbuf,sendcnt,sendtype,&recvbuf,
recvcnt,recvtype,root,comm)
MPI_SCATTER (sendbuf,sendcnt,sendtype,recvbuf,
recvcnt,recvtype,root,comm,ierr)
122
MPI_Gather
MPI_Gather. Colecteaz mesaje distincte de la fiecare task din grup pentru un
singur task destinatie. Este o rutin reciproc fat de rutina MPI_Scatter.
MPI_Gather (&sendbuf,sendcnt,sendtype,&recvbuf,
recvcount,recvtype,root,comm)
MPI_GATHER (sendbuf,sendcnt,sendtype,recvbuf,
recvcount,recvtype,root,comm,ierr)
MPI_Allgather. Concatenarea de date (de) la toate taskurile din grup. Fiecare
task din grup execut ca efect o operatie de difuzare unul-la-toate n cadrul
grupului.
MPI_Allgather (&sendbuf,sendcount,sendtype,&recvbuf,
recvcount,recvtype,comm)
MPI_ALLGATHER (sendbuf,sendcount,sendtype,recvbuf,
recvcount,recvtype,comm,info)
MPI_Reduce. Aplic o operatie de reducere pe toate taskurile din grup si
plaseaz rezultatul la un task.
123
MPI_Reduce (&sendbuf,&recvbuf,count,datatype,op,
root,comm)
MPI_REDUCE (sendbuf,recvbuf,count,datatype,op,
root,comm,ierr)
Operatiile de reducere MPI predefinite sunt date imediat mai jos. Utilizatorii
pot defini ei nsisi functii de reducere utiliznd rutina MPI_Op_create.
Operatia de
reducere MPI
Tipuri de date C
Tipuri de date
Fortran
MPI_MAX
maximum integer, float
integer, real,
complex
MPI_MIN
minimum integer, float
integer, real,
complex
MPI_SUM
sum integer, float
integer, real,
complex
MPI_PROD
produs integer, float
integer, real,
complex
MPI_LAND
AND logic integer logical
MPI_BAND
AND bit-cu-bit
integer,
MPI_BYTE
integer, MPI_BYTE
MPI_LOR
OR logic integer logical
MPI_BOR
OR bit-cu-bit
integer,
MPI_BYTE
integer, MPI_BYTE
MPI_LXOR
XOR logic integer logical
MPI_BXOR
XOR bit-cu-bit
integer,
MPI_BYTE
integer, MPI_BYTE
MPI_MAXLOC
Valoarea
maxim si
locatia
float, double and
long double
real, complex,double
precision
MPI_MINLOC
Valoarea
minim si
locatia
float, double and
long double
real, complex, double
precision
124
MPI_Allreduce. Aplic o operatie de reducere si plaseaz rezultatul la toate
taskurile grupului. Este echivalent cu un MPI_Reduce urmat de un
MPI_Bcast.
MPI_Allreduce (&sendbuf,&recvbuf,count,datatype,
op,comm)
MPI_ALLREDUCE (sendbuf,recvbuf,count,datatype,
op,comm,ierr)
MPI_Reduce_scatter. Mai nti face o reducere element-cu-element pe un
vector n toate taskurile din grup. Apoi vectorul rezultat este separat n
segmente disjuncte si distribuit pe taskuri. Aceasta este echivalent cu un
MPI_Reduce urmat de o operatie MPI_Scatter.
MPI_Reduce_scatter (&sendbuf,&recvbuf,recvcount,
datatype,op,comm)
MPI_REDUCE_SCATTER (sendbuf,recvbuf,recvcount,
datatype,op,comm,ierr)
MPI_Alltoall. Fiecare task dintr-un grup execut o operatie de distribuire
(scatter) trimitnd un mesaj distinct tuturor taskurilor din grup ordonat prin
indice.
MPI_Alltoall (&sendbuf,sendcount,sendtype,&recvbuf,
recvcnt,recvtype,comm)
MPI_ALLTOALL (sendbuf,sendcount,sendtype,recvbuf,
recvcnt,recvtype,comm,ierr)
MPI_Alltoall
MPI_Scan. Execut o operatie de scanare n raport cu o operatie de reducere pe
un grup de taskuri.
MPI_Scan (&sendbuf,&recvbuf,count,datatype,op,comm)
MPI_SCAN (sendbuf,recvbuf,count,datatype,op,comm,
ierr)
125
Exemple de comunicare colectiv: se execut o operatie de distribuire pe linii a
unui masiv.
n limbajul C:
#include "mpi.h"
#include <stdio.h>
#define SIZE 4
int main(argc,argv)
int argc;
char *argv[]; {
int numtasks, rank, sendcount, recvcount, source;
float sendbuf[SIZE][SIZE] = {
{1.0, 2.0, 3.0, 4.0},
{5.0, 6.0, 7.0, 8.0},
{9.0, 10.0, 11.0, 12.0},
{13.0, 14.0, 15.0, 16.0} };
float recvbuf[SIZE];
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
if (numtasks == SIZE) {
source = 1;
sendcount = SIZE;
recvcount = SIZE;
MPI_Scatter(sendbuf,sendcount,MPI_FLOAT,recvbuf,recvcoun
t,
MPI_FLOAT,source,MPI_COMM_WORLD);
printf("rank= %d Results: %f %f %f
%f\n",rank,recvbuf[0],
recvbuf[1],recvbuf[2],recvbuf[3]);
}
else
printf("Must specify %d processors.
Terminating.\n",SIZE);
MPI_Finalize();
}
n Fortran:
program scatter
126
include 'mpif.h'
integer SIZE
parameter(SIZE=4)
integer numtasks,rank,sendcount,recvcount,source,ierr
real*4 sendbuf(SIZE,SIZE), recvbuf(SIZE)
C Fortran stores this array in column major order, so the
C scatter will actually scatter columns, not rows.
data sendbuf /1.0, 2.0, 3.0, 4.0,
& 5.0, 6.0, 7.0, 8.0,
& 9.0, 10.0, 11.0, 12.0,
& 13.0, 14.0, 15.0, 16.0 /
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr)
if (numtasks .eq. SIZE) then
source = 1
sendcount = SIZE
recvcount = SIZE
call MPI_SCATTER(sendbuf,sendcount,MPI_REAL,recvbuf,
& recvcount, MPI_REAL, source, MPI_COMM_WORLD, ierr)
print *, 'rank= ',rank,' Results: ',recvbuf
else
print *, 'Must specify',SIZE,
' processors. Terminating.'
endif
call MPI_FINALIZE(ierr)
end
Iesire ilustrativ a programului:
rank= 0 Results: 1.000000 2.000000 3.000000 4.000000
rank= 1 Results: 5.000000 6.000000 7.000000 8.000000
rank= 2 Results: 9.000000 10.000000 11.000000 12.000000
rank= 3 Results: 13.000000 14.000000 15.000000 16.000000
Tipuri de date derivate
Cum s-a mentionat mai devreme, MPI si predefineste tipurile de date
primitive:
127
Tipuri de date n C Tipuri de date n Fortran
MPI_CHAR
MPI_SHORT
MPI_INT
MPI_LONG
MPI_UNSIGNED_CHAR
MPI_UNSIGNED_SHORT
MPI_UNSIGNED_LONG
MPI_UNSIGNED
MPI_FLOAT
MPI_DOUBLE
MPI_LONG_DOUBLE
MPI_BYTE
MPI_PACKED
MPI_CHARACTER
MPI_INTEGER
MPI_REAL
MPI_DOUBLE_PRECISION
MPI_COMPLEX
MPI_DOUBLE_COMPLEX
MPI_LOGICAL
MPI_BYTE
MPI_PACKED
MPI d posibilitatea programatorului s defineasc propriile structuri de date
bazate pe secvente ale tipurilor primitive de date MPI. Asemenea structuri
definite de utilizator sunt numite tipuri derivate de date.
Tipurile de date primitive sunt contigue, tipurile de date derivate permit
specificarea de date necontigue ntr-o manier convenabil si utilizarea lor ca si
cnd ar fi contigue.
MPI furnizeaz mai multe metode de a construi tipuri derivate de date:
contigue, vectori, indexate, structuri.
Rutine pentru tipuri de date derivate
MPI_Type_contiguous. Este cel mai simplu constructor. Produce un tip de date
nou prin efectuarea unor cpii numrate ale unui tip existent de date.
MPI_Type_contiguous (count,oldtype,&newtype)
MPI_TYPE_CONTIGUOUS (count,oldtype,newtype,ierr)
MPI_Type_vector
MPI_Type_hvector. Similare rutinei contiguous, dar permit spatii regulate
(stride
3
) n deplasare. MPI_Type_hvector si MPI_Type_vector sunt identice cu
exceptia faptului c pasul (stride) este specificat n bytes pentru prima dintre
rutine.
MPI_Type_vector (count,blocklength,stride,oldtype,
&newtype)
MPI_TYPE_VECTOR (count,blocklength,stride,oldtype,
newtype,ierr)
MPI_Type_indexed
MPI_Type_hindexed. Este furnizat un masiv de deplasri pentru tipul de date
3
strided se spune despre o secvent de citiri sau scrieri ale memoriei la adrese separate
fiecare de ultima printr-un interval constant numit lungimea-de-pas (the stride length) sau
numai pasul (the stride).
128
de intrare, ca o hart pentru noul tip de date. MPI_Type_hindexed este identic
cu MPI_Type_indexed cu exceptia faptului c offseturile sunt specificate n
bytes.
MPI_Type_indexed (count,blocklens[],offsets[],
old_type,&newtype)
MPI_TYPE_INDEXED (count,blocklens(),offsets(),
old_type,newtype,ierr)
MPI_Type_struct. Noul tip de date este format potrivit unei hrti complet
definite de tipuri de date componente.
MPI_Type_struct (count,blocklens[],offsets[],
old_types,&newtype)
MPI_TYPE_STRUCT (count,blocklens(),offsets(),
old_types,newtype,ierr)
MPI_Type_extent. Returneaz dimensiunea n bytes a tipului de date specificat.
Util pentru subrutinele MPI care cer specificarea offsetului n bytes.
MPI_Type_extent (datatype,&extent)
MPI_TYPE_EXTENT (datatype,extent,ierr)
MPI_Type_commit. Angajeaz tipuri de date noi pe sistem. Cerut de toate
tipurile de date (derivate) construite de utilizator.
MPI_Type_commit (&datatype)
MPI_TYPE_COMMIT (datatype,ierr)
MPI_Type_free. Dealocarea obiectului de tipul de date specificat. Utilizarea
acestei rutine este de important special n prevenirea epuizrii memoriei cnd
sunt create multe obiecte tip de date cum ar fi ntr-o bucl.
MPI_Type_free (&datatype)
MPI_TYPE_FREE (datatype,ierr)
Exemple pentru tipul de date derivat Contiguous (contiguu): se creaz un tip de
date care reprezint o linie a unui masiv si se distribuie o linie diferit tuturor
proceselor.
n C:
#include "mpi.h"
#include <stdio.h>
#define SIZE 4
int main(argc,argv)
int argc;
char *argv[]; {
int numtasks, rank, source=0, dest, tag=1, i;
float a[SIZE][SIZE] =
{1.0, 2.0, 3.0, 4.0,
5.0, 6.0, 7.0, 8.0,
9.0, 10.0, 11.0, 12.0,
13.0, 14.0, 15.0, 16.0};
129
float b[SIZE];
MPI_Status stat;
MPI_Datatype rowtype;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
MPI_Type_contiguous(SIZE, MPI_FLOAT, &rowtype);
MPI_Type_commit(&rowtype);
if (numtasks == SIZE) {
if (rank == 0) {
for (i=0; i<numtasks; i++)
MPI_Send(&a[i][0],1,rowtype,i,tag,MPI_COMM_WORLD);
}
MPI_Recv(b,SIZE,MPI_FLOAT,source,tag,MPI_COMM_WORLD,
&stat);
printf("rank= %d b= %3.1f %3.1f %3.1f %3.1f\n",
rank,b[0],b[1],b[2],b[3]);
}
else
printf("Must specify %d processors.
Terminating.\n",SIZE);
MPI_Type_free(&rowtype);
MPI_Finalize();
}
n Fortran:
program contiguous
include 'mpif.h'
integer SIZE
parameter(SIZE=4)
integer numtasks, rank, source, dest, tag, i, ierr
real*4 a(0:SIZE-1,0:SIZE-1), b(0:SIZE-1)
integer stat(MPI_STATUS_SIZE), columntype
C Fortran stores this array in column major order
data a /1.0, 2.0, 3.0, 4.0,
& 5.0, 6.0, 7.0, 8.0,
& 9.0, 10.0, 11.0, 12.0,
& 13.0, 14.0, 15.0, 16.0 /
130
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr)
call MPI_TYPE_CONTIGUOUS(SIZE,MPI_REAL,columntype,ierr)
call MPI_TYPE_COMMIT(columntype, ierr)

tag = 1
if (numtasks .eq. SIZE) then
if (rank .eq. 0) then
do 10 i=0, numtasks-1
call MPI_SEND(a(0,i), 1, columntype, i, tag,
& MPI_COMM_WORLD,ierr)
10 continue
endif
source = 0
call MPI_RECV(b, SIZE, MPI_REAL, source, tag,
& MPI_COMM_WORLD, stat, ierr)
print *, 'rank= ',rank,' b= ',b
else
print *, 'Must specify',SIZE,
' processors. Terminating.'
endif
call MPI_TYPE_FREE(columntype, ierr)
call MPI_FINALIZE(ierr)
end
Iesire ilustrativ a programului:
rank= 0 b= 1.0 2.0 3.0 4.0
rank= 1 b= 5.0 6.0 7.0 8.0
rank= 2 b= 9.0 10.0 11.0 12.0
rank= 3 b= 13.0 14.0 15.0 16.0
Exemple pentru tipul derivat Vector: se creaz un tip de date care reprezint o
coloan a unui masiv si se distribuie coloane diferite tuturor proceselor.
n C:
#include "mpi.h"
#include <stdio.h>
131
#define SIZE 4
int main(argc,argv)
int argc;
char *argv[]; {
int numtasks, rank, source=0, dest, tag=1, i;
float a[SIZE][SIZE] =
{1.0, 2.0, 3.0, 4.0,
5.0, 6.0, 7.0, 8.0,
9.0, 10.0, 11.0, 12.0,
13.0, 14.0, 15.0, 16.0};
float b[SIZE];
MPI_Status stat;
MPI_Datatype columntype;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);

MPI_Type_vector(SIZE, 1, SIZE, MPI_FLOAT, &columntype);
MPI_Type_commit(&columntype);
if (numtasks == SIZE) {
if (rank == 0) {
for (i=0; i<numtasks; i++)
MPI_Send(&a[0]
[i],1,columntype,i,tag,MPI_COMM_WORLD);
}

MPI_Recv(b,SIZE,MPI_FLOAT,source,tag,MPI_COMM_WORLD,
&stat);
printf("rank= %d b= %3.1f %3.1f %3.1f %3.1f\n",
rank,b[0],b[1],b[2],b[3]);
}
else
printf("Must specify %d processors.
Terminating.\n",SIZE);

MPI_Type_free(&columntype);
MPI_Finalize();
}
n Fortran:
program vector
include 'mpif.h'
132
integer SIZE
parameter(SIZE=4)
integer numtasks,rank,source,dest,tag,i,ierr
real*4 a(0:SIZE-1,0:SIZE-1), b(0:SIZE-1)
integer stat(MPI_STATUS_SIZE), rowtype
C Fortran stores this array in column major order
data a /1.0, 2.0, 3.0, 4.0,
& 5.0, 6.0, 7.0, 8.0,
& 9.0, 10.0, 11.0, 12.0,
& 13.0, 14.0, 15.0, 16.0 /
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr)
call MPI_TYPE_VECTOR(SIZE,1,SIZE,MPI_REAL,rowtype,ierr)
call MPI_TYPE_COMMIT(rowtype, ierr)

tag = 1
if (numtasks .eq. SIZE) then
if (rank .eq. 0) then
do 10 i=0, numtasks-1
call MPI_SEND(a(i,0), 1, rowtype, i, tag,
& MPI_COMM_WORLD, ierr)
10 continue
endif
source = 0
call MPI_RECV(b, SIZE, MPI_REAL, source, tag,
& MPI_COMM_WORLD, stat, ierr)
print *, 'rank= ',rank,' b= ',b
else
print *, 'Must specify',SIZE,' processors.
Terminating.'
endif
call MPI_TYPE_FREE(rowtype, ierr)
call MPI_FINALIZE(ierr)
end
Iesire ilustrativ a programului:
rank= 0 b= 1.0 5.0 9.0 13.0
133
rank= 1 b= 2.0 6.0 10.0 14.0
rank= 2 b= 3.0 7.0 11.0 15.0
rank= 3 b= 4.0 8.0 12.0 16.0
Exemple pentru tipul de date derivat Indexed: se creaz un tip de variabil prin
extragerea de portiuni dintr-un masiv si distribuindu-l tuturor taskurilor.
n C:
#include "mpi.h"
#include <stdio.h>
#define NELEMENTS 6
int main(argc,argv)
int argc;
char *argv[]; {
int numtasks, rank, source=0, dest, tag=1, i;
int blocklengths[2], displacements[2];
float a[16] =
{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0,
9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0};
float b[NELEMENTS];
MPI_Status stat;
MPI_Datatype indextype;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
blocklengths[0] = 4;
blocklengths[1] = 2;
displacements[0] = 5;
displacements[1] = 12;
MPI_Type_indexed(2, blocklengths, displacements,
MPI_FLOAT, &indextype);
MPI_Type_commit(&indextype);
if (rank == 0) {
for (i=0; i<numtasks; i++)
MPI_Send(a, 1, indextype, i, tag, MPI_COMM_WORLD);
}

MPI_Recv(b, NELEMENTS, MPI_FLOAT, source, tag,
MPI_COMM_WORLD, &stat);
134
printf("rank= %d b= %3.1f %3.1f %3.1f %3.1f %3.1f
%3.1f\n",
rank,b[0],b[1],b[2],b[3],b[4],b[5]);

MPI_Type_free(&indextype);
MPI_Finalize();
}
n Fortran:
program indexed
include 'mpif.h'
integer NELEMENTS
parameter(NELEMENTS=6)
integer numtasks, rank, source, dest, tag, i, ierr
integer blocklengths(0:1), displacements(0:1)
real*4 a(0:15), b(0:NELEMENTS-1)
integer stat(MPI_STATUS_SIZE), indextype
data a /1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0,
& 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0 /
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr)
blocklengths(0) = 4
blocklengths(1) = 2
displacements(0) = 5
displacements(1) = 12
call
MPI_TYPE_INDEXED(2,blocklengths,displacements,MPI_REAL,
& indextype, ierr)
call MPI_TYPE_COMMIT(indextype, ierr)

tag = 1
if (rank .eq. 0) then
do 10 i=0, numtasks-1
call
MPI_SEND(a,1,indextype,i,tag,MPI_COMM_WORLD,ierr)
10 continue
endif
source = 0
135
call
MPI_RECV(b,NELEMENTS,MPI_REAL,source,tag,MPI_COMM_WORLD,
& stat, ierr)
print *, 'rank= ',rank,' b= ',b
call MPI_TYPE_FREE(indextype, ierr)
call MPI_FINALIZE(ierr)
end
Iesire ilustrativ a programului:
rank= 0 b= 6.0 7.0 8.0 9.0 13.0 14.0
rank= 1 b= 6.0 7.0 8.0 9.0 13.0 14.0
rank= 2 b= 6.0 7.0 8.0 9.0 13.0 14.0
rank= 3 b= 6.0 7.0 8.0 9.0 13.0 14.0
Exemple pentru tipul de date derivat Struct: se creaz un tip de date care
reprezint o particul si se distribuie un masiv de astfel de particule tuturor
proceselor.
n C:
#include "mpi.h"
#include <stdio.h>
#define NELEM 25
int main(argc,argv)
int argc;
char *argv[]; {
int numtasks, rank, source=0, dest, tag=1, i;
typedef struct {
float x, y, z;
float velocity;
int n, type;
} Particle;
Particle p[NELEM], particles[NELEM];
MPI_Datatype particletype, oldtypes[2];
int blockcounts[2];
/* MPI_Aint type used to be consistent with syntax of */
/* MPI_Type_extent routine */
MPI_Aint offsets[2], extent;
MPI_Status stat;
136
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);

/* Setup description of the 4 MPI_FLOAT fields x, y, z,
velocity */
offsets[0] = 0;
oldtypes[0] = MPI_FLOAT;
blockcounts[0] = 4;
/* Setup description of the 2 MPI_INT fields n, type */
/* Need to first figure offset by getting size of
MPI_FLOAT */
MPI_Type_extent(MPI_FLOAT, &extent);
offsets[1] = 4 * extent;
oldtypes[1] = MPI_INT;
blockcounts[1] = 2;
/* Now define structured type and commit it */
MPI_Type_struct(2,blockcounts,offsets,oldtypes,
&particletype);
MPI_Type_commit(&particletype);
/* Initialize the particle array and then send it to each
task */
if (rank == 0) {
for (i=0; i<NELEM; i++) {
particles[i].x = i * 1.0;
particles[i].y = i * -1.0;
particles[i].z = i * 1.0;
particles[i].velocity = 0.25;
particles[i].n = i;
particles[i].type = i % 2;
}
for (i=0; i<numtasks; i++)
MPI_Send(particles,NELEM,particletype,i,tag,
MPI_COMM_WORLD);
}

MPI_Recv(p,NELEM,particletype,source,tag,MPI_COMM_WORLD,
&stat);
/* Print a sample of what was received */
printf("rank= %d %3.2f %3.2f %3.2f %3.2f %d %d\n",rank,
p[3].x,p[3].y,p[3].z,p[3].velocity,p[3].n,p[3].type);

137
MPI_Type_free(&particletype);
MPI_Finalize();
}
n Fortran:
program struct
include 'mpif.h'
integer NELEM
parameter(NELEM=25)
integer numtasks, rank, source, dest, tag, i, ierr
integer stat(MPI_STATUS_SIZE)
type Particle
sequence
real*4 x, y, z, velocity
integer n, type
end type Particle
type (Particle) p(NELEM), particles(NELEM)
integer particletype, oldtypes(0:1), blockcounts(0:1),
& offsets(0:1), extent
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr)
C Setup description of the 4 MPI_REAL fields x, y, z,
velocity
offsets(0) = 0
oldtypes(0) = MPI_REAL
blockcounts(0) = 4
C Setup description of the 2 MPI_INTEGER fields n, type
C Need to first figure offset by getting size of MPI_REAL
call MPI_TYPE_EXTENT(MPI_REAL, extent, ierr)
offsets(1) = 4 * extent
oldtypes(1) = MPI_INTEGER
blockcounts(1) = 2
C Now define structured type and commit it
call MPI_TYPE_STRUCT(2, blockcounts, offsets, oldtypes,
& particletype, ierr)
call MPI_TYPE_COMMIT(particletype, ierr)

138
C Initialize the particle array and then send it to each
task
tag = 1
if (rank .eq. 0) then
do 10 i=0, NELEM-1
particles(i) = Particle ( 1.0*i, -1.0*i, 1.0*i,
& 0.25, i, mod(i,2) )
10 continue
do 20 i=0, numtasks-1
call MPI_SEND(particles,NELEM,particletype,i,tag,
& MPI_COMM_WORLD, ierr)
20 continue
endif
source = 0
call MPI_RECV(p, NELEM, particletype, source, tag,
& MPI_COMM_WORLD, stat, ierr)
print *, 'rank= ',rank,' p(3)= ',p(3)
call MPI_TYPE_FREE(particletype, ierr)
call MPI_FINALIZE(ierr)
end
Iesire ilustrativ a programului:
rank= 0 3.00 -3.00 3.00 0.25 3 1
rank= 2 3.00 -3.00 3.00 0.25 3 1
rank= 1 3.00 -3.00 3.00 0.25 3 1
rank= 3 3.00 -3.00 3.00 0.25 3 1
Rutine de administrare a comunicatorului si a grupelor
Grupe si comunicatori: O grup este o multime ordonat de procese. Fiecare
proces dintr-un grup este asociat unui rang ntreg unic. Valorile rangului
pornesc de la 0 si merg pn la N 1, unde N este numrul de procese din grup.
n MPI, un grup este reprezentat n memoria sistemului ca un obiect. El este
accesibil programatorului numai printr-un handle. Un grup este totdeauna
asociat cu un obiect comunicator.
Un comunicator cuprinde un grup de procese care pot comunica ntre ele. Toate
mesajele MPI trebuie s specifice un comunicator. n sensul cel mai simplu,
comunicatorul este o etichet suplimentar care trebuie inclus n apelurile
MPI. Ca si grupele, comunicatorii sunt reprezentati n memoria sistemului ca
obiecte si sunt accesibili programatorului numai prin handles. De exemplu,
139
un handle pentru comunicatorul care cuprinde toate taskurile este
MPI_COMM_WORLD.
Din perspectiva programatorului, un grup si un comunicator sunt totuna.
Rutinele grupului sunt utilizate n principal pentru a specifica procesele care
trebuie utilizate pentru a construi un comunicator.
Scopurile principale ale obiectelor grup si comunicator:
Permit organizarea taskurilor, pe baza unor functii, n grupuri de taskuri.
Abiliteaz operatiile de comunicare colectiv ntr-un subset de taskuri ntr-un
fel n relatie.
Asigur baza pentru implementarea topologiilor virtuale definite de utilizator.
Asigur siguranta comunicrii.
Restrictii si alte consideratii asupra programrii:
Grupurile/comunicatorii sunt obiecte dinamice pot fi create si distruse n
timpul executiei programului.
Procesele pot fi n mai mult de un grup/comunicator. Ele vor avea un rang unic
n fiecare grup/comunicator.
MPI contine peste 40 de rutine relativ la grupuri, comunicatori si topologii
virtuale.
Utilizri tipice:
Extragere de handle al unui grup global din MPI_COMM_WORLD utiliznd
MPI_Comm_group.
Formarea unui grup nou ca o submultime a unui grup global utiliznd
MPI_Group_incl.
Crearea unui comunicator nou pentru un grup nou utiliznd
MPI_Comm_create.
Determinarea unui rang nou ntr-un comunicator nou utiliznd
MPI_Comm_rank.
Conducerea comunicrii utiliznd orice rutin MPI de transfer de mesaje.
Cnd calculul se termin, eliberarea comunicatorului nou si (optional) a
grupului nou, utiliznd MPI_Comm_free si MPI_Group_free.
Rutine de administrare a grupurilor si a comunicatorilor
Exemple:
Sunt create dou grupuri de procese diferite pentru schimb separat de
comunicare colectiv. Este cerut si crearea de comunicatori noi.
n C:
#include "mpi.h"
#include <stdio.h>
#define NPROCS 8
140
int main(argc,argv)
int argc;
char *argv[]; {
int rank, new_rank, sendbuf, recvbuf, numtasks,
ranks1[4]={0,1,2,3}, ranks2[4]={4,5,6,7};
MPI_Group orig_group, new_group;
MPI_Comm new_comm;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
if (numtasks != NPROCS) {
printf("Must specify MP_PROCS= %d.
Terminating.\n",NPROCS);
MPI_Finalize();
exit(0);
}
sendbuf = rank;
/* Extract the original group handle */
MPI_Comm_group(MPI_COMM_WORLD, &orig_group);
/* Divide tasks into two distinct groups based upon
rank */
if (rank < NPROCS/2) {
MPI_Group_incl(orig_group,NPROCS/2,ranks1,&new_group);
}
else {
MPI_Group_incl(orig_group,NPROCS/2,ranks2,&new_group);
}
/* Create new new communicator and then perform collective
communications */
141
MPI_Comm_create(MPI_COMM_WORLD, new_group, &new_comm);
MPI_Allreduce(&sendbuf,&recvbuf,1,MPI_INT,MPI_SUM,
new_comm);
MPI_Group_rank (new_group, &new_rank);
printf("rank= %d newrank= %d recvbuf= %d\n",
rank,new_rank,recvbuf);
MPI_Finalize();
}
n Fortran:
program group
include 'mpif.h'
integer NPROCS
parameter(NPROCS=8)
integer rank, new_rank, sendbuf, recvbuf, numtasks
integer ranks1(4), ranks2(4), ierr
142
integer orig_group, new_group, new_comm
data ranks1 /0, 1, 2, 3/, ranks2 /4, 5, 6, 7/
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr)
if (numtasks .ne. NPROCS) then
print *, 'Must specify MPROCS= ',NPROCS,
' Terminating.'
call MPI_FINALIZE(ierr)
stop
endif
sendbuf = rank
C Extract the original group handle
call MPI_COMM_GROUP(MPI_COMM_WORLD, orig_group, ierr)
C Divide tasks into two distinct groups based upon rank
if (rank .lt. NPROCS/2) then
call MPI_GROUP_INCL(orig_group, NPROCS/2, ranks1,
& new_group, ierr)
else
call MPI_GROUP_INCL(orig_group, NPROCS/2, ranks2,
& new_group, ierr)
endif
call MPI_COMM_CREATE(MPI_COMM_WORLD, new_group,
& new_comm, ierr)
call MPI_ALLREDUCE(sendbuf, recvbuf, 1, MPI_INTEGER,
& MPI_SUM, new_comm, ierr)
call MPI_GROUP_RANK(new_group, new_rank, ierr)
print *, 'rank= ',rank,' newrank= ',new_rank,' recvbuf=
',
& recvbuf
call MPI_FINALIZE(ierr)
end
Iesire a programului exemplificatoare:
rank= 7 newrank= 3 recvbuf= 22
rank= 0 newrank= 0 recvbuf= 6
rank= 1 newrank= 1 recvbuf= 6
rank= 2 newrank= 2 recvbuf= 6
143
rank= 6 newrank= 2 recvbuf= 22
rank= 3 newrank= 3 recvbuf= 6
rank= 4 newrank= 0 recvbuf= 22
rank= 5 newrank= 1 recvbuf= 22
Topologii virtuale
Ce sunt aceste topologii? n termenii MPI, o topologie virtual descrie o
aplicatie/ordonare a proceselor MPI ntr-o form geometric.
Cele dou tipuri principale de topologii suportate de MPI sunt cea cartezian
(gril) si cea sub form de graf.
Topologiile MPI sunt virtuale poate s nu existe nici o relatie ntre structura
fizic a unei masini paralel si topologia proceselor.
Topologiile virtuale sunt construite pe grupuri si comunicatori MPI.
Trebuie s fie programate de cel care dezvolt aplicatia.
Care este utilitatea lor?
Sunt convenabile. Topologiile virtuale pot fi utile pentru aplicatii cu forme de
comunicare specifice forme (patterns) care se potrivesc unei structuri
topologice MPI.
De exemplu, o topologie cartezian se poate dovedi convenabil pentru o
aplicatie care reclam comunicare cu 4 din vecinii cei mai apropiati pentru date
bazate pe grile.
Eficienta comunicrii. Unele arhitecturi hardware pot exhiba penalitti pentru
comunicarea ntre noduri succesive distante.
O implementare particular poate optimiza aplicarea (mapping) proceselor pe
baza caracteristicilor fizice ale unei masini paralel date.
Aplicarea de procese ntr-o topologie virtual MPI este dependent de
implementarea MPI si poate fi ignorat total.
Exemplu: n figura de mai sus se d o aplicare simplificat a proceselor ntr-o
topologie virtual cartezian.
144
Rutine de topologie virtual
Creaz o topologie cartezian 44 din 16 procesoare si face ca fiecare proces s
schimbe rangul su cu patru vecini.
n C:
#include "mpi.h"
#include <stdio.h>
#define SIZE 16
#define UP 0
#define DOWN 1
#define LEFT 2
#define RIGHT 3
int main(argc,argv)
int argc;
char *argv[]; {
int numtasks, rank, source, dest, outbuf, i, tag=1,
inbuf[4]={MPI_PROC_NULL,MPI_PROC_NULL,MPI_PROC_NULL,
MPI_PROC_NULL,},
nbrs[4], dims[2]={4,4},
periods[2]={0,0}, reorder=0, coords[2];
MPI_Request reqs[8];
MPI_Status stats[8];
MPI_Comm cartcomm;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
if (numtasks == SIZE) {
MPI_Cart_create(MPI_COMM_WORLD, 2, dims, periods,
reorder, &cartcomm);
MPI_Comm_rank(cartcomm, &rank);
MPI_Cart_coords(cartcomm, rank, 2, coords);
MPI_Cart_shift(cartcomm, 0, 1, &nbrs[UP], &nbrs[DOWN]);
MPI_Cart_shift(cartcomm, 1, 1, &nbrs[LEFT],
&nbrs[RIGHT]);
outbuf = rank;
for (i=0; i<4; i++) {
dest = nbrs[i];
source = nbrs[i];
MPI_Isend(&outbuf, 1, MPI_INT, dest, tag,
145
MPI_COMM_WORLD, &reqs[i]);
MPI_Irecv(&inbuf[i], 1, MPI_INT, source, tag,
MPI_COMM_WORLD, &reqs[i+4]);
}
MPI_Waitall(8, reqs, stats);

printf("rank= %d coords= %d %d neighbors(u,d,l,r)= %d
%d %d %d\n",rank,coords[0],coords[1],nbrs[UP],
nbrs[DOWN],nbrs[LEFT],nbrs[RIGHT]);
printf("rank= %d inbuf(u,d,l,r)= %d %d %d %d\n",
rank,inbuf[UP],inbuf[DOWN],inbuf[LEFT],
inbuf[RIGHT]);
}
else
printf("Must specify %d processors.
Terminating.\n",SIZE);

MPI_Finalize();
}
n Fortran:
program cartesian
include 'mpif.h'
integer SIZE, UP, DOWN, LEFT, RIGHT
parameter(SIZE=16)
parameter(UP=1)
parameter(DOWN=2)
parameter(LEFT=3)
parameter(RIGHT=4)
integer numtasks,rank,source,dest,outbuf,i,tag,ierr,
& inbuf(4),nbrs(4),dims(2), oords(2),
& stats(MPI_STATUS_SIZE, 8), reqs(8), cartcomm,
& periods(2), reorder
data inbuf /MPI_PROC_NULL,MPI_PROC_NULL,MPI_PROC_NULL,
& MPI_PROC_NULL/, dims /4,4/, tag /1/,
& periods /0,0/, reorder /0/
call MPI_INIT(ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr)

if (numtasks .eq. SIZE) then
call
MPI_CART_CREATE(MPI_COMM_WORLD,2,dims,periods,reorder,
& cartcomm,ierr)
146
call MPI_COMM_RANK(cartcomm, rank, ierr)
call MPI_CART_COORDS(cartcomm,rank,2,coords,ierr)
print *,'rank= ',rank,'coords= ',coords
call MPI_CART_SHIFT(cartcomm,0,1,nbrs(UP),
nbrs(DOWN),ierr)
call MPI_CART_SHIFT(cartcomm, 1, 1, nbrs(LEFT),
nbrs(RIGHT),
& ierr)
outbuf = rank
do i=1,4
dest = nbrs(i)
source = nbrs(i)
call MPI_ISEND(outbuf,1,MPI_INTEGER,dest,tag,
& MPI_COMM_WORLD, reqs(i), ierr)
call MPI_IRECV(inbuf(i),1,MPI_INTEGER,source,tag,
& MPI_COMM_WORLD, reqs(i+4), ierr)
enddo
call MPI_WAITALL(8, reqs, stats, ierr)
print *,'rank= ',rank,' coords= ',coords,
& ' neighbors(u,d,l,r)= ',nbrs
print *,'rank= ',rank,' ',
& ' inbuf(u,d,l,r)= ',inbuf
else
print *,'Must specify',SIZE,
' processors. Terminating.'
endif
call MPI_FINALIZE(ierr)
end
Iesire (partial) ilustrativ a programului:
rank= 0 coords= 0 0 neighbors(u,d,l,r)= -3 4 -3 1
rank= 0 inbuf(u,d,l,r)= -3 4 -3 1
rank= 1 coords= 0 1 neighbors(u,d,l,r)= -3 5 0 2
rank= 1 inbuf(u,d,l,r)= -3 5 0 2
rank= 2 coords= 0 2 neighbors(u,d,l,r)= -3 6 1 3
rank= 2 inbuf(u,d,l,r)= -3 6 1 3
. . . . .
rank= 14 coords= 3 2 neighbors(u,d,l,r)= 10 -3 13 15
rank= 14 inbuf(u,d,l,r)= 10 -3 13 15
rank= 15 coords= 3 3 neighbors(u,d,l,r)= 11 -3 14 -3
rank= 15 inbuf(u,d,l,r)= 11 -3 14 -3
147
Scurt prezentare a MPI-2
Istorie: Deliberat, specificatiile MPI nu se ocup de mai multe probleme
dificile. Din ratiuni de expunere condensat aceste probleme au fost rezervate
pentru specificatia evoluat MPI-2.
n martie 1995, urmare a lansrii specificatiei initiale MPI, Forumul MPI a
nceput discutarea mbunttirilor standardului MPI. Urmnd acestuia:
Decembrie 1995: conferinta Supercomputing 95 ntlnirea Birds of a Feather
(dup denumirea unui sitcom britanic de succes) pentru a discuta extensiile
propuse pentru MPI.
Noiembrie 1996: conferinta Supercomputing 96 s-a generat un proiect MPI-
2. S-a solicitat dezbaterea lui public. ntlnire pentru a discuta extinderile
interfetei MPI-2.
Proiectul prezentat la Supercomputing 96 a devenit foarte curnd standardul
MPI-2,
n prezent, cei mai multi productori din aria HPC au numai implementri
partiale ale MPI-2.
Domenii cheie si functionalitti noi:
Procese dinamice extinderi care nlocuiesc modelul procesului static al MPI.
Furnizeaz rutine de creat procese noi.
Comunicatii unilaterale furnizeaz rutine pentru comunicatii unidirectionale.
Includ operatii cu memorie partajat (put/get) si operatiuni de acumulare la
distant.
Operatii colective extinse permite operatii colective fr blocare si aplicatii
ale operatiilor colective la inter-comunicatori.
Interfete externe defineste rutine care permit dezvoltatorilor a pune straturi
(layers) suplimentare peste MPI cum sunt programele de depanare (debuggers)
si profilers.
Noi legturi cu limbajele de programare descrie legturi n C++ si discut
probleme legate de Fortran-90.
I/O paralel descrie suportul MPI pentru I/O paralel.
Mai multe informatii despre MPI-2: pe site-ul The Argonne National Lab exist
pagini dedicate informatiilor despre MPI-2.
LLNL Lawrence Livermore National Laboratory Informatii specifice
si recomandri
Implementri MPI
LC (Library Computer) suport pe sistemele sale urmtoarele implementri
MPI:
148
Platforme Implementri Comentarii
IBM AIX
IBM MPI
threaded library
Recommended
IBM MPI signal
library
Not thread safe and not recommended.
POWER3 systems only.
MPICH Not thread safe. POWER3 systems only.
Intel Linux
Quadrics MPI
Recommended. Uses shared memory for
on-node communications and message
passing over the Quadrics switch for
inter-node communications. Not thread-
safe
MPICH shared
memory
On-node communications. Not thread
safe. Only for machines without a
Quadrics switch.
COMPAQ
Tru64
Compaq MPI
shared memory
On-node communications. Use -pthread
compile flag for thread-safety.
MPICH shared
memory
On-node communications. Not thread
safe
MPICH P4
Inter-node communications. Not thread
safe. Not recommeded due to lack of high
speed interconnect between nodes (no
switch).
Pe fiecare masin sunt instalate versiuni multiple pentru fiecare implementare.
Sunt suportate limbajele C, C++, Fortran 77 si Fortran 90.
Compilare, linkare, rulare:
Tabelul de mai jos cuprinde un sumar al comenzilor MPI de compilare/executie
pentru toate sistemele LC. De retinut c acesta este numai un rezumat, detaliile
pot fi gsite prin consultarea surselor bibliografice.
Platforma Implementri Compile/Link Run
IBM AIX IBM MPI
threaded library
mpcc_r code.c
mpxlc_r code.c
mpguidec code.c
mpCC_r code.C
mpxlC_r code.C
mpguidec++ code.c
mpxlf_r code.f
mpguidef77 code.f
149
mpxlf90_r code.F
mpguidef90 code.F
mpxlf95_r code.f
Set required POE environment variables,
then either:
a.out args
poe a.out args
Or, use POE flags instead of environment
variables:
a.out args poe_args
poe a.out args poe_args
IBM MPI signal
library
(POWER3
systems only)
setenv
LLNL_COMPILE_SINGLE_THREADED
TRUE
mpcc code.c
mpxlc code.c
mpCC code.C
mpxlC code.C
mpxlf code.f
mpxlf90 code.F
mpxlf95 code.f
Set required POE environment variables, then
either:
a.out args
poe a.out args
Or, use POE flags instead of environment
variables:
a.out args poe_args
poe a.out args poe_args
MPICH
(POWER3
systems only)
setenv
LLNL_COMPILE_SINGLE_THREADED
TRUE
mpicc code.c
mpiCC code.C
mpif77 code.f
mpif90 code.F
mpirun -nodes n -np p a.out args
- OR -
setenv MP_NODES n
mpirun -np p a.out args
Intel
Linux
Quadrics MPI
(clusters with a
mpicc code.c
mpiicc code.c
150
Quadrics switch
only)
mpipgcc code.c
mpiCC code.C
mpipgCC code.C
mpif77 code.f
mpiifc code.f
mpipgf77 code.f
mpif90 code.F
mpipgf90 code.F
srun -n n -p partition a.out args
MPICH shared
memory
(clusters without
a Quadrics
switch)
mpicc code.c
mpiicc code.c
mpipgcc code.c
mpiCC code.C
mpipgCC code.C
mpif77 code.f
mpiifc code.f
mpipgf77 code.f
mpif90 code.F
mpipgf90 code.F
mpirun -nodes n -np p a.out args
COMPAQ
Tru64
Compaq MPI
shared memory
cc code.c -lmpi -pthread
gcc code.c -lmpi -pthread
cxx code.C -lmpi -pthread
KCC code.C -lmpi -pthread
g++ code.C -lmpi -pthread
f77 code.f -lfmpi -lmpi -pthread
f90 code.F -lfmpi -lmpi -pthread
dmpirun -np p a.out args
MPICH shared
memory
mpicc code.c
mpiCC code.C
mpicxx code.C
mpif77 code.f
mpif90 code.F
mpirun -np p a.out args
MPICH P4
mpicc_p4 code.c
mpiCC_p4 code.C
mpicxx_p4 code.C
mpif77_p4 code.f
mpif90_p4 code.F
mpirun_p4 -machinefile user_machine_file
-np p a.out args
151
Variabile de mediu (environmemnt):
Variabilele de mediu POE (Parallel Operating Environment) IBM:
Variabilele de mediu POE joac un rol critic n modul cum se comport o
aplicatie MPI pe toate sistemele ASC IBM.
LLNL seteaz explicit mai multe din aceste variabile pe fiecare masin ASC
(Advanced Systems Center) IBM.
Variabilele de mediu Elan (Emulated Local Area Network) pentru sistemele
Linux:
Quadrics MPI furnizeaz totodat un numr de variabile de mediu, dintre care
unele sunt setate automat de LC din ratiuni de performant.
32 de biti fat-n-fat cu 64 de biti:
De la retragerea sistemelor ASC Blue, toate SP-urile IBM de la LC sunt
arhitecturi pe 64 de biti.
Toate clusterele Linux IA32 sunt, desigur, arhitecturi pe 32 de biti. Thunder
este o arhitectur Itanium pe 64 de biti.
Arhitecturile pe 64 de biti au spatiul adreselor de 64 de biti 18 miloane de
terabytes. Arhitecturile pe 32 de biti rmn la cca. 4 Gbytes.
Sistemele IBM POWER3 fac compilarea prin default pe 32 de biti. POWER4 si
POWER5 fac compilarea prin default pe 64 de biti. Este probabil o idee bun a
utiliza la compilare flag-urile q64 sau q32 dac default-ul nu este ceea ce
trebuie.
Obiectele pe 32 de biti si pe 64 de biti nu se pot amesteca. O aplicatie trebuie s
fie de de-a-ntregul ori una ori alta.
Sunt probleme importante de luat n considerare la portabilitatea sau la
dezvoltarea aplicatiilor pe 64 de biti.
152
MASINI PARALELE SI MODELE DE PROGRAMARE
Figura alturat ilustreaz o arhitectur paralel generic
Unul din aspectele de detaliu l reprezint localizarea fizic a memoriei. n
figur se pot observa memorii atasate procesoarelor si memoria n utilizare
comun tuturor procesoarelor.
n ceea ce priveste modelele diverse de programare paralel trebuie avute n
vedere mai multe aspecte:
1. Controlul, cu detalierea:
Cum este creat paralelismul
Ce ordine exist n executarea diferitelor operatii
Cum se sincronizeaz firele de control (threads) diferite
2. Datele:
Care date sunt private, care date sunt folosite n diviziune
Cum sunt accesate sau comunicate logic datele n diviziune
3. Operatiile:
Care sunt operatiile atomice, indivizibile
4. Costul:
Cum se contabilizeaz costurile fiecrei pozitii din cele de mai sus
Un exemplu simplu. Se consider o sum a valorilor unei functii de un masiv de
date:

1
0
]) [ (
n
i
i A f
. O descompunere paralel posibil:
Fiecare evaluare si fiecare sum partial se constituie ca un task separat,
se atribuie n/p numere fiecruia din cele p proces(oar)e
Fiecare proces calculeaz si obtine rezultate independente si sume
partiale private
153
Unul dintre procese (sau toate) colecteaz cele p sume partiale si
calculeaz suma general
Se disting dou clase de date:
Date care sunt logic n diviziune numerele initiale (n) si suma
general
Date care sunt logic private, particulare rezultatele evalurilor
individuale ale functiei
Dar ce se poate spune despre sumele partiale individuale? Sunt aici mai multe
rspunsuri.
Modelul de programare 1: Memorie n indiviziune (partajat). Programul este o
colectie de fire de control (threads) care sunt initiate de la bun nceput sau n
unele limbaje pot fi create dinamic (mid-execution).
Fiecare fir are un set de variabile private, de pild variabilele din stiva local.
Exist, de asemenea, un set de variabile n indiviziune, partajate, de pild
variabilele statice, blocurile comune n indiviziune sau heap-ul global.
Firele comunic implicit prin scrierea si lectura variabilelor partajate si se
coordoneaz pe aceste variabile prin sincronizare.
Figura de mai sus este baza prezentrii unui scurt program (cod) cu memorie
partajat, pentru calculul unei sume
154
Apare problema unei competitii (a unei conditii race) pe variabila s din
program. O conditie race sau data race apare cnd:
Dou procesoare (sau dou fire) acceseaz aceeasi variabil si cel putin
unul face o scriere
Accesrile sunt concurente (nu sunt sincronizate) astfel nct ele ar
trebui s aib loc simultan
Se admite c s = 27, f(A[i]) = 7 pe firul 1 si f(A[i]) = 9 pe firul 2. Dac
programul lucreaz corect, s ar trebui s fie la final 43, dar poate fi 43, 34 sau
36.
Operatiile atomice sunt citirile si scrierile si niciodat nu trebuie s se vad
un numr numai pe jumtate. Toate calculele se produc n registre (private).
Iat acum un cod pentru calculul sumei de mai sus mbunttit.
Deoarece adunarea este o operatie aritmetic asociativ si comutativ,
rearanjarea ordinei este oricnd permis. Cea mai mare parte a calculului se
face n variabile private.
Frecventa de utilizare partajat aste si ea redus, ceea ce ar putea mri
viteza de calcul
155
Dar nc exist o conditie race la actualizarea variabilei partajate s
Conditia race poate fi rezolvat prin adugarea de interdictii (locks) cu
precizarea c numai un fir poate detine un lock la un moment; celelalte
fire asteapt pentru ca acel lock, acea interdicitie de acces s fie
deblocat() (unlock).
Modelul de programare 1a: Memorie n indiviziune (partajat). Toate
procesoarele sunt conectate la o memorie n indiviziune cuprinztoare. Tipic,
asemenea sisteme de calcul sunt denumite multiprocesoare simetrice (SMP
Symmetric MultiProcessors). Exist n uz multe asemenea SMP-uri produse de
Sun, HP, Intel, IBM etc.
Memoria local nu este (de obicei) parte separat din hardware. Structura
este dificil de scalat la numr mare de procesoare, tipic mai putin de 32 de
procesoare. Avantajul major: acces uniform la memorie (UMA uniform
memory access). Relativ la costuri: mult, mult mai ieftin accesul la date n
memoria cache dect n memoria principal. Figura urmtoare ilustreaz
structura unui SMP (fr a evidentia grafic simetria liminal).
Aceast structur are probleme cu scalarea memoriei partajate. Se pune firesc
ntrebarea, de ce nu se pun laolalt mai multe procesoare (cu memorie mai
mare)? Rspunsul: bus-ul memoriei devine loc ngust, este stangulant.
Un exemplu de astfel de situatie l furnizeaz aplicatia PSTSWM (Parallel
Spectral Transform Shallow Water Model) dezvoltat pentru a evalua algoritmii
paralel pentru metoda transformrii spectrale asa cum este utilizat n modelele
globale de circulatie atmosferic. n cod sunt ncorporati algoritmi paraleli
multipli, care pot fi selectati n timpul executiei n raport cu dimensiunea
problemei, cu numrul de procesoare, cu descompunerea datelor. O surs de
detalii posibil: http://www.csm.ornl.gov/chammp/pstswm/.
Graficul care urmeaz prezint performanta unei masini IBM p690 pe modelul
PSTSW si sensibilitatea ei la ncrcare.
156
Degradarea performantei este o functie neted de numrul de proces(oar)e.
Problema nu implic nici un fel de date partajate ntre procese, astfel c ar
trebui s existe un paralelism perfect. Codul a fost rulat pentru 18 niveluri
verticale cu un domeniu (range) pe dimensiunea orizontal fix.
Model al masinii 1b: memoria partajat este distribuit. Memoria este logic n
indiviziune dar fizic este distribuit. Orice procesor poate accesa orice adres
din memorie. Liniile cache (sau paginile) sunt transferate peste tot (passed
around) n masin.
Origin SGI (Silicon Graphics, Inc.) este exemplul canonic (la fel masinile de
cercetare).
Scalare la sute de ori
Limitarea const n protocoalele coerente din punctul de vedere al
memoriilor cache: necesit a detine pentru aceeasi adres cpii n cache
consistente
Modelul de programare 2: transmiterea de mesaje. Programul const ntr-o
colectie de proces(oar)e cu nume.
157
Numele sunt fixate uzual la momentul pornirii programului
Firul de control plus spatiul de adresare sunt locale datele sunt
utilizate partajat NU (non uniform)
Datele n indiviziune logic sunt partitionate pe procese locale
Procesele comunic prin perechi de instructiuni explicite trimite/primeste
(send/receive)
Coordonarea este implicit n fiecare eveniment comunicational
MPI (Message Passing Interface) este exemplul cel mai comun
Un exemplu simplu: calculul sumei s = A[1] + A[2] pe fiecare procesor.
Prima solutie posibil:
Ce ar putea merge ru:
Dac send/receive actioneaz ca n sistemul telefonic?
Dac send/receive actioneaz ca prin oficiul postal?
A doua solutie posibil:
Not de traducere: se pare c n firul procesorului 2 trebuie pus xlocal si nu xloadl.
n 2002 MPI a devenit standardul de facto pentru calculul paralel.
O provocare pentru productorii de software: depsirea limitelor MPI
MPI a creat finalmente un standard pentru dezvoltarea de aplicatii n
comunitatea HPC (High Performance Computing)
158
Standardele sunt totdeauna un obstacol pentru continuarea dezvoltrilor
Standardul MPI este o constructie ca un numitor comun minimal n
raport cu tehnologia anilor 80 mijlocii
Modelul de programare reflect structura hardware.
Nu sunt sigur cum voi programa un calculator de Petaflops, dar sunt sigur c
voi avea nevoie de MPI undeva HDS 2001
Modelul de masin 2a: memorie distribuit. Cray T3E, NOW, IBM SP2 IBM
SP3, Millenium, CITRIS sunt masini cu memorie distribuit dar nodurile sunt
SMP-uri. Fiecare procesor are propria sa memorie si propriul su domeniu
cache dar nu poate accesa direct memoria vreunui alt procesor. Fiecare nod
are o interfat de retea (NI Network Interface) pentru toat comunicarea si
pentru sincronizare.
Clusterele de PC-uri, contributiile de genul Beowulf reprezint un experiment
interesant n materie de sisteme de calcul n paralel. Se bazeaz pe o viziune de
cost sczut pentru calcule cu final nalt. A demonstrat eficacitatea clusterelor de
PC-uri pentru unele (nu toate) clase de aplicatii. A generat si a furnizat software
de retea. A transferat rezultatele ctre o comunitate larg (great PR). A generat
tutoriale si crti. A generat standarde de proiectare pentru ralierea (rally)
comunittii celor care se ocup cu calculul paralel, a generat crti, oameni
educati/priceputi, cu alte cuvinte un cerc virtuos. Fotografia alturat arat un
cluster de PC-uri.
159
Adaptat dup Gordon Bell, prezentare la Salishan
Clusterele au creat modelul de software open source pentru HPC (High
Performance Computing). Este de citat aici legea lui Linus, numit dup Linus
Torvalds, creatorul Linux-ului, care afirm c pentru ochi suficienti, toate
erorile sunt superficiale (given enough eyeballs, all bugs are shallow).
Toate codurile surs sunt deschise
Fiecare structur gen cluster este un loc de testare
Orice porneste mult mai rapid dac fiecare lucreaz pe un cod existent,
la ndemn (HPC: nimic nu se face dac resursele sunt disperse).
Software-ul este sau ar trebui s fie gratuit (Stallman). Oricine poate oferi
suport si poate comercializa codul pentru orice pret. Sofware-ul de cost nul
atrage utilizatorii! Previne situatia n care comunitatea ar pierde sofware HPC
(exemple CM5, T3E).
Exist n lume clustere de Tflop/s. Iat cteva exemple de clustere configurate
din componente separate de retea si procesoare:
Shell: clusterul de engineering/stiintific cel mai mare
NCSA: cluster de 1024 de procesoare (IA64)
Clusterul universittii din Heidelberg
PNNL: cluster de IA64 anuntat a fi de 8 Tflops (la vrf), alctuit din HP
cu interconectare Quadrics
DTF n US: 4 clustere anuntate pentru un total de 13 Teraflops (la vrf)
O mentiune necesar: procesoarele Itanium si McKinley nu sunt produse de
tipul commodity, adic foarte ieftine
Sunt de amintit aici si calculele executate pe Internet detalii la adresa
SETI@home. Rularea ar putea avea loc pe 500.000 PC-uri, aproximativ 1000
160
CPU-an pe zi. Deocamdat 485.821 CPU-an. Sunt distribuite seturi de date de
la radiotelescopul Arecibo (figura urmtoare) .
Pasul urmtor preconizat reteaua de telescoape Allen (figura de mai jos).
Modelul de programare 2b: spatiu de adresare global. Programul const ntr-o
colectie de fire (threads) cu nume
Uzual stabilite la momentul pornirii programului
Datele sunt locale si partajate ca n modelul cu memorie partajat
Dar datele partajate sunt partitionate pe procese locale
Modelele costului spun c datele situate la distant sunt costisitoare.
Exemple: UPC, Titanium, CoArray Fortran
Programarea cu spatiu de adresare global este un punct intermediar ntre
transferul de mesaje si memoria n diviziune
Modelul de masin 2b: spatiul de adresare global. Exemple: Cray T3D, T3E,
X1 si clusterul HP Alphaserver, Clusterele construite cu Quadrics, Myrinet sau
Infiniband.
161
Interfata de retea suport RDMA (Remote Direct Memory Access)
NI (network interface) poate accesa direct memoria fr ntreruperea
CPU
Un procesor poate citi/scrie din/n memorie cu operatii unilaterale
(put/get)
Nu este numai o operatie load/store ca pe o masin cu memorie partajat
Datele situate departe (remote) sunt tipic ne-cache-ate local
Spatiul de adresare global poate fi suportat n grade diferite
Modelul de programare 3: date paralel.
Un singur fir al controlului care const din operatii paralel.
Operatiile paralel se aplic ntregii structuri de date (sau unui subset definit al
acelei structuri), uzual unui masiv.
Comunicarea este implicit n operatorii paralel
Modelul este elegant, usor de nteles si de a rationa asupr-i
Coordonarea este implicit declaratiile (instructiunile) sunt executate
sincron
Similar limbajului Matlab pentru operatii cu masive.
Neajunsuri:
Nu toate problemele se potrivesc n acest model
Dificil de aplicat (to map) pe masini grosier organizate (coarse-grained)
A = masivul tuturor datelor, fA = f(A), s = sum(fA)
Modelul de masin 3a: sisteme SIMD (Single Instruction Multiple Data)
Un numr mare de procesoare (uzual) mici
Un procesor de control unic genereaz fiecare instructiune
Fiecare procesor execut aceeasi instructiune
162
Unele procesoare pot fi oprite (turned off) pentru unele instructiuni.
Masinile sunt foarte specializate pe calculul stiintific, astfel c nu sunt foarte
populare printre distribuitori (CM2, Maspar)
Modelul de programare poate fi implementat n compilator
Aplicarea paralelismului se face n-uplu pe p procesoare, n>>p, dar este
dificil (exemplu, HPF (High Performance Fortran))
Modelul 3b: masini vectoriale.
Arhitecturile vectoriale sunt bazate pe un singur procesor
Unitti functionale multiple
Toate execut aceeasi operatie
Instructiunile pot specifica prin ele nsesi o cantitate mare de paralelism
(de pild 64 de ci) dar hardware-ul execut numai un subset n paralel
Importante sub aspect istoric
Preluate de MPP-uri n anii 90
Re-aprute n anii din urm, recenti
La o scar mare n simulatorul terestru (NEC SX6) si Cray X1
La o scar mic n extensiile media SIMD la microprocesoare
SSE, SSE2 (Intel: Pentium, IA64)
Altivec (IBM/Motorola/Apple: PowerPC)
VIS (Sun: Sparc)
Ideea cheie: compilatorul face o parte din munca dificil de a gsi paralelism,
astfel c hardware-ul nu trebuie s fac asta
Procesoare vectoriale.
Instructiunile vectoriale opereaz pe un vector de elemente
Acestea sunt specificate ca operatii pe registre vectoriale
Un registru vetorial al unui supercomputer retine ~ 32-64 elemente
163
Numrul de elemente este mai mare dect cantitatea de hardware
paralel, denumit pipes sau piste (lanes) vectoriale, s spunem 2-4
Hardware-ul execut o operatie vectorial complet n
#elemente-pe-registru-vectorial / #pipes
Nodul Cray X1.
Cray X1 construieste un vector virtual mai mare, denumit un MSP
(Multiprocessing Server Pack)
4 SSP-uri (Switch to Switch Protocol) (fiecare un procesor vectorial cu
2 pipe-uri) alctuiesc un MSP
Compilatorul va face (sau va ncerca) vectorizarea/paralelizarea pe MSP
Sursa figurii: J.Levesque, Cray
Cray X1: arhitectur vectorial paralel
Cray combin n X1 mai multe tehnologii
Procesoare vectoriale de 12,8 Gflop/s (MSP)
Cache-uri partajate (neuzuale n masinile vectoriale mai
vechi/anterioare)
Noduri de 4 procesoare care mpart pn la 64 GB de memorie
Imaginea unui sistem unic pe 4096 procesoare
Put/get de la distant ntre noduri (mai rapid dect MPI)
164
Arhitectura simulatorului terestru/global
Arhitectur vectorial paralel
Procesoare vectoriale de mare vitez
Lrgime de band mare pentru memorie (arhitectur vectorial)
Retea rapid (comutare nou crossbar)
Rearanjarea prtilor (la pret de commodity) nu poate atinge aceast performant
Modelul de masin 4: clustere de SMP-uri.
SMP-urile sunt cele mai rapide masini la pret de commodity astfel c ele sunt
utilizate ca blocuri constructive pentru masini mai mari cu o retea de
comunicare
Nume obisnuite:
CLUMP = clusters of SMP-uri
165
Masini ierarhizate, constelatii
Multe masini moderne arat n acest mod:
Millenium, IBM SP-urile (dar nu T3E-urile)
Care este modelul de programare potrivit pentru #4?
Se trateaz masina ca plat (flat), se utilizeaz totdeauna transferul
de mesaje, chiar n SMP-uri (simplu, dar ignor o important parte din
ierarhia memoriei)
Memorie partajat ntr-un SMP, dar transmitere de mesaje n afara unui
SMP
Tratarea ca un cluster de SMP-uri
Un supercomputer este un server extrem de extins.
Sistemul paralel este construit prin asamblarea de noduri care sunt de
dimensiuni modeste, comerciale, servere SMP se pun mai multe laolalt
Imagine de la LLNL (Lawrence Livermore National Laboratory)
Tendinte n lumea masinilor reale. TOP500
O list a celor mai puternice 500 de calculatoare din lume.
Jalonul: R
max
din Linpack pentru varianta dens a problemei Ax = b
166
Actualizat de dou ori pe an:
n Germania ISCxy, n iunie xy
n SUA SCxy, n noiembrie xy
Toate datele acestea pot fi vzute pe site-ul www.top500.org
167
MASINI PARALELE CU MEMORIE PARTAJAT
Arhitectura de baz pentru calculul paralel pe memorie partajat
Procesoarele sunt conectate toate la o memorie cuprinztoare partajat, mai
bine zis o memorie utilizat n indiviziune. Fiecare procesor detine o memorie
cache local. Din punct de vedere al costurilor, adic al consumurilor de timp,
lucrul cu memoria cache este mai ieftin dect lucrul cu mempria principal.
n mediul cu memorie partajat realizarea de programe este relativ usoar. Ceva
mai dificil este scalarea
4
.
Acum o privire mai ndeaproape la structur, costuri, limite:
Din perspectiva istoric, masinile paralel cu memorie partajat mentionabile
sunt:
Masinile bazate pe bus
Pentium SMP
Nodul IBM SP
Masinile bazate pe directoare (CC-NUMA, Cache Coherent
NonUniform Memory Access)
Origin 2000
Masinile cu spatiu de adresare global
Cray T3D si (genul) T3E
4
Scalabil este echivalent cu expandabil. Cnd se refer la hardware sau software, termenul are
un sens ntructva diferit: un dispozitiv sau o aplicatie nalt scalabil() nseamn c fr eforturi
exagerate face posibile utilizarea de mai multi utilizatori, ncrcarea mai mare cu taskuri sau cu
tranzactii. Scalabil nu nseamn totdeauna c expansiunea nu cost nimic. Pentru a obtine
maximum de scalabilitate se cer uneori cheltuieli suplimentare cu hardware-ul sau software-ul.
168
Masinile multiprocesoare din anii '60 ai secolului trecut aveau structura din
figura alturat. Capacitatea de memorare sau posibilitatea de comunicare I/O
se puteau ameliora prin adugarea de module de memorie si de dispozitive I/O.
Cresterea capacittii de procesare se putea realiza prin adugarea de procesoare.
Apare deja necesitatea unei interconectri a modulelor de memorie si a
procesoarelor, la fel a legturilor cu canalele I/O (IOC). Se foloseau retele de
tip cross-bar sau multistage (multietajate).
Memoriile cache, marea lovitur a anilor 70 au fost de natur a influenta
puternic structurile de memorare. Sistemele de memorie scalate prin adugarea
de module suplimentare aveau nevoie si de capacitate dar si de vitez
(bandwidth). Memoria era totusi o surs de strangulri. Introducerea
memoriilor cache a schimbat aproape radical datele problemei.
O memorie cache este capabil a face dou lucruri foarte importante:
169
Reducerea timpului mediu de acces (latena)
Diminuarea necesittii de crestere a vitezei de transfer la si de la
memorie.
Cum arat perspectiva tehnologic?
Tabelul care urmeaz indic tendintele curente.
Cresteri de
capacitate
Cresteri de
vitez
Logica 2 ori la 3 ani 2 ori la 3 ani
DRAM (Dynamic Random
Access Memory)
4 ori la 3 ani 1,4 ori la 10 ani
Discuri 2 ori la 3 ani 1,4 ori la 10 ani
Variante de a construi masini paralele.
n medalion este cuprins o masin cu memoria partajat din anii 80: memoria
cache este partajat. Asa erau:
Alliant FX8 (n anii '80 timpurii)
Opt procesoare Motorola 68020 cu crossbar si cache intercalat de 512
KB.
Encore si Sequent produse de firmele cu aceleasi nume
Primele microcalculatoare pe 32 de biti (N32032)
Dou procesoare pe o plac cu cache n diviziune.
170
Figura urmtoare reia medalionul la dimensiuni care vizualizeaz mai bine
detaliile.
Avantajele si dezavantajele masinilor paralel cu memorie cache partajat.
Avantaje
Amplasarea memoriei cache este identic cu aceea a memoriei cache
unic. Se retine numai o copie a fiecrui bloc de cache.
Granularitatea fin (fine grain) este posibil
Existenta unei interferente utile: un procesor poate pre-localiza date
pentru un altul; se poate utiliza partajat date dintr-o linie de cache fr a
deplasa linia.
Dezavantaje
Apare o limitare de vitez (bandwidth)
Exist si o interferent nedorit: un procesor poate spla (flush) datele
utile unui alt procesor.
171
Limitele solutiei cu cache partajat.
Se presupune: procesorul generic (32 bii) la 1 GHz fr cache este capabil de o
vitez (BW) de 4 GB/s pentru instructiuni si de o vitez (BW) de 1,2 GB/s
pentru date la ncrcare-memorare (load-store), ceea ce este o cot de 30% din
viteza pentru instructiuni. Un procesor necesit asadar o vitez pe bus de 5,2
GB/s. Banda de trecere (BW BandWidth) uzual a unui bus este de circa 1
GB/s.
Alternative constructive ale masinilor paralel
172
Un model intuitiv al memoriei spune c citirea executat la o adres trebuie s
returneze ultima valoare scris la acea adres. Cu exceptia operatiilor I/O
aceast relatie este usor de realizat n cazul procesorului unic.
Problema coerentei memoriei cache n cazul masinilor cu mai multe procesoare
(cu memorie partajat) este mai delicat si totodat mai critic din punct de
vedere al performantelor.
Mai riguros, aceasta este de fapt o consistent secvential: Un sistem
multiprocesor este consistent secvential dac rezultatul oricrei executii este
acelasi ca si cnd operatiile tuturor procesoarelor ar fi executate ntr-o anume
ordine secvential si operatiile fiecrui procesor n parte apar n aceast
secvent n ordinea specificat de programul executiei [Lamport, 1979]
Intuirea consistentei secventiale
Consistenta secvential spune c masina se comport ca si cnd ar face
operatiile din figura alturat imediat mai sus.
Semantica consistentei memoriei
Ce implicatii are aceasta asupra comportrii programului?
Nici un proces nu vede vreodat valori gunoi, adic jumtate din dou
valori
Procesoarele vd totdeauna valorile scrise de oricare alt procesor
Valoarea vzut este restrictionat de ordinea programului considerat
pe toate procesoarele
Timpul totdeauna se misc, se scurge nainte
Exemplu:
P1 scrie data = 1, apoi scrie flag = 1
P2 citeste flag, apoi citeste data
173
Dac P2 vede noua valoare a lui y, el trebuie s vad noua valoare a lui x
Dac nu exist o coerent de cache-uri
P1 si P2 au cpii ale datei n cache-uri (ca 0)
P1 scrie data = 1
Poate scrie si n memorie (write through)
P2 citeste data, dar ia copia din cache nvechit
Asta se poate ntmpla chiar dac a citit o valoare actualizat a unei alte
variabile, flag, care vine din memorie
Protocoale de coerent de cache (snoopy) iscoditoare
174
Bus-ul de memorie este un mediu de difuzare (broadcast).
Cache-urile contin informatii despre ce adrese stocheaz ele.
Controlul de cache snoops (spioneaz) toate tranzactiile de pe bus.
O tranzactie este o tranzactie relevant dac implic un bloc de cache
continut la acel moment n acel cache
Se iau msuri de asigurare a coerentei
Invalideaz, actualizeaz sau furnizeaz valori
Depinde de starea blocului si de protocol
Alegeri de baz n coerenta cache-ului
n cache se tin informatii de genul:
Valid/invalid
Murdar (dirty inconsistent cu memoria)
Partajate (n alte cache-uri)
Cnd un procesor execut o operatie de scriere de date partajate, alegerile de
basic design sunt:
relativ la memorie:
scrie through (pn la capt): scrie si n memorie si n cache
scrie back: asteapt si scrie mai trziu, cnd item-ul este splat
(flushed)
relativ la copiile cache celelalte:
actualizeaz: d tuturor celorlalte procesoare valoarea nou
invalideaz: toate celelalte procesoare scot din cache
Exemplu: write-through invalidat
175
Actualizeaz si write-through ambele utilizate; mai mult vitez (bandwidth) de
memorie dac exist scrieri la aceeasi adres
actualizeaz la celelalte cache-uri
write-through la memorie
Scheme write-back/ownership
Cnd un singur cache are proprietatea unui bloc, scrierile procesorului nu
rezult n scrieri de pe bus, astfel conservnd bandwidth.
citirile de ctre altii produc revenirea blocului la starea shared
Multe multiprocesoare de azi bazate pe bus utilizeaz astfel de scheme.
Multe variante de protocoale pe baz de proprietate (ownwership-based).
Limitele memoriei partajate bazate pe bus
Se presupune: procesor de 1 GHz fr cache 4 GB/s BW pentru instructiuni
pe fiecare procesor (32-bit) 1,2 GB/s BW pentru load-store date la 30%.
Se admite o rat de succes (hit rate) pentru instructiuni de 98% si o rat de
succes pentru date de 95% 80 MB/s BW pentru instructiuni la fiecare
procesor 60 MB/s BW pentru date la fiecare procesor 140 MB/s BW
combinat.
Admitnd BW pentru bus de 1 GB/s, 8 procesoare satureaz bus-ul
176
Inginerie: Intel Pentium Pro Quad
SMP-uri pentru mase:
toat coerenta si tot lipiciul multiprocesrii n modulul procesorului
nalt integrat, cu tinta la volum mare
latent redus si BW larg
Inginerie: SUN Enterprise
177
Proc + mem card I/O card
16 plci de fiecare tip
toat memoria accesat pe bus, deci simetric
BW mai nalt, bus de latent mai mare
Alternative constructive ale masinilor paralel
Coerenta de cache bazat pe director
Multiprocesoare coerente cache, scalabile din anii 90
178
SGI Altix 3000
Un nod contine pn la 4 procesoare Itanium 2 si 32GB de memorie.
Reteaua este SGIs NUMAlink, tehnologie de interconectare NUMAflex.
Utilizeaz un amestec de coerent snoopy si directory-based.
Pn la 512 procesoare care sunt coerente cache (spatiul adreselor globale este
posibil pentru masini mai mari).
Coerenta cache si consistenta memoriei
Coerenta cache si consistenta secvential
Mult munc, mult hardware pentru a asigura coerenta cache.
Niciodat mai mult de o versiune de date pentru o adres dat din cache
Datele sunt totdeauna valori scrise de unul din procesoare
179
Dar alte particularitti hardware pot sparge consistenta secvential (SC)
Compilatorul reordoneaz/nlocuieste codul (de pild your spin lock
blocarea rotirii).
Compilatorul aloc un registru pentru flag pe procesorul 2 si suceste
(spins) valoarea pe acel registru fr vreo finalitate.
Scrie buffere (loc de stocare a scrierilor n timp ce este asteptat finalul.
Procesoarele pot reordona scrierile pentru a unifica (to merge)
adrese (not FIFO).
Scrie x =1, y = 1, x = 2 (al doilea write n x se poate produce
naintea write-ului n y).
Instructiunile de prelocalizare (prefetch) produc reordonarea citirii
(citire de date nainte de flag).
Reteaua reordoneaz cele dou mesaje de scriere.
Scrierea n flag este n apropiere, in timp ce data este departe.
Unele din acestea pot fi prevenite prin declararea de variabile volatile.
Violri ale consistentei secventiale (SC)
Programul flag/data este un exemplu care se bazeaz pe SC.
Fiind dat o memorie coerent, toate violrile de SC bazate pe reordonare a
operatiilor independente sunt n figur.
Vezi articolul lui Shasha si Snir pentru detalii
Operatiile pot fi liniarizate (deplaseaz timpul nainte) dac SC
Conditii suficiente pentru consistent secvential
Procesoarele lanseaz operatii cu memoria n ordinea din program.
Procesorul asteapt pentru store a se finaliza nainte de a lansa orice alt
operatie cu memoria.
De pild, asteapt pentru write-through si invalidri.
Procesorul asteapt pentru load a se finaliza nainte de a lansa orice alt
operatie cu memoria.
180
De pild, data din alt cache poate c trebuie marcat ca partajat mai
curnd dect exclusiv
Un load trebuie s astepte de asemenea pentru ca store-ul care produce valoarea
s se isprveasc
De pild, dac data este n cache si evenimentul update schimb
valoarea, toate celelalte cache-uri trebuie s fi procesat de asemenea
acel update
Exist si modalitti mai agresive de a implementa SC, dar cele mai multe SMP-
uri comerciale curente renunt (give up) la asemenea metode
Clasificare pentru modele relaxate
Optimizrile pot fi n general categorisite prin
Relaxarea ordinei din program
Write Read
Write Write
Read Read, Write
Citeste write-ul altora mai nti
Citeste propriul write mai nti
Toate modelele asigur o plas de sigurant (safety net), de pild
O instructiune gard de write asteapt ca write-urile s fie complete
O gard de read previne prelocalizrile de a se deplasa naintea acestui
punct
Prelocalizrile (prefetches) pot fi sincronizate automat la utilizare
Toate modelele mentin dependentele de date si de control uniprocesor,
serializarea de write
Modelele de memorie difer prin ordine la dou locatii diferite
Slide source: Sarita Adve et al.
Cteva modele curente centrate pe sistem (system-centric)
181
Data-race-free-0: unele definitii
(se consider executii SC ordine total global)
Competitie (race) pentru dou operatii n conflict dac
De la procesoare diferite
Se execut una dup alta (consecutiv)
Competiile (races) etichetate uzual ca sincronizri, altii date.
Se pot optimiza operatii care niciodat nu vin n competitie.
Programarea cu modele de memorie slabe
Cteva reguli de programare cu aceste modele
evitati conditiile de competitie (race)
utilizati primitive de sincronizare furnizate de sistem
dac aveti conditii de competitie pe variabile, faceti-le volatile
la nivel de asamblare puteti utiliza direct garduri (fences) (sau
analoagele)
182
Suportul pentru acestea n limbajele de nivel nalt difer.
primitivele de sincronizare built-in includ n mod normal operatiile
fence necesare
lock: include un fence la read
unlock: include un fence de write
astfel toate operatiile cu memoria se petrec n regiunea critic.
Memorie n diviziune cache-coerent si performanta
Cache-uri n calculul stiintific
Cache-urile tind s lucreze foarte prost pe aplicatii solicitante care opereaz pe
seturi de date voluminoase
procesarea tranzactiilor
sistemele de operare
matrici rare
Codurile stiintifice moderne uzeaz de tiling/blocking pentru a deveni cache-
friendly
mai usor pentru codurile dense dect pentru cele rare
tiling-ul si paralelismul sunt transformri similare
Utilizarea partajat (sharing): o problem de performant
Partajarea adevrat:
write-uri frecvente pe o variabil poate crea loc ngust, strangulri
OK pentru date read-only sau care se scriu infrecvent, rar
Technic: se fac cpii ale valorii, una pe fiecare procesor, dac aceasta e
posibil n algoritm
Problem exemplificatoare: structura de date care nmagazineaz
freelist/heap pentru malloc/free
Partajare fals:
Blocul de cache poate de asemenea s introduc artefacte
Dou variabile distincte n acelasi bloc de cache
Tehnic: se aloc datele utilizate de fiecare procesor n mod contiguu
sau cel putin cu evitarea intercalrii
Problem exemplu: un masiv de ntregi, unul scris frecvent de fiecare
procesor
Ce este de retinut?
Programarea masinilor cu memorie partajat:
183
Se pot aloca date n regiuni mari partajate fr prea mari griji asupra
locului unde sunt
Ierarhia memoriei este critic pentru performant
Chiar mai mult dect pe uniprocesoare, din cauza coerentei de
trafic
Pentru reglarea (tuning) performantei se urmreste partajarea att cea
adevrat ct si cea fals
Semantic:
Necesit a bloca (lock) aceesul la variabile partajate pentru read-
modify-write
Consistenta secvential este semantica natural
Arhitectii lucreaz din greu pentru a face asta s lucreze
Cache-urile sunt coerente cu bus-urile sau directoarele
Nu cache-uri pentru date deprtate pe masinile cu spatiu de
adresare partajat
Dar compilatorul si procesorul pot nc s-o scoat la cap
Write-urile non-blocking, read-urile prelocalizate, miscarea
codului
A se evita competitia (races) sau a se utiliza cu grij gardurile
specifice masinii
184
CALCULATOARE CU MEMORIE DISTRIBUIT
Perspectiva istoric
La nceput masinile erau:
Colectii de microprocesoare
Comunicarea era executat utiliznd legturi bidirectionale ntre vecinii
cei mai apropiati
Mesajele erau naintate de procesoare pe o cale (path)
Retelizare era de tipul Memoreaz si naiteaz, trimite mai departe
n algoritmi exista un accent puternic pe topologie pentru a minimiza numrul
de srituri (hops) de la un nod la altul.
Analogia cu retelele
Pentru a avea un numr mare de transferuri care se petrec deodat, este necesar
un numr mare de fire distincte
Retelele sunt ca strzile:
Link = strad
Switch = intersectie
Distante (salturi = hops) = numrul de blocks (cvartaluri) parcurse
Algoritm de rutare = plan de cltorie
Proprietti:
Laten: ct ia parcursul ntre noduri n retea
185
Bandwidth (BW): ce cantitate de date poate fi deplasat n unitatea de
timp
BW este limitat de numrul de fire si de viteza la care fiecare
fir poate accepta datele
Caracteristicile unei retele
Topologia (cum sunt conectate lucrurile)
Crossbar, ring, tor 2D si 3D, hipercuburi, retele omega
Algoritmul de rutare:
Exemplu: totul est-vest apoi totul nord-sud (evit blocajele)
Strategia de comutare:
Comutare de circuit: calea complet rezervat pentru ntregul mesaj, ca
la telefon
Comutare n pachete: mesajul spart n pachete rutate separat, ca la
oficiul postal
Controlul traficului (ce se ntmpl dac se produce o congestie, un ambuteiaj):
Opreste, depune datele temporar n buffere, re-ruteaz datele ctre alte
noduri, spune nodului surs s se opreasc temporar, decarteaz etc.
Proprietti ale unei retele: laten
Diametru: maximul (pe toate perechile de noduri) celui mai scurt drum ntre o
pereche de noduri
Laten: ntrzierea ntre momentele de trimitere si de primire
Latenta tinde s varieze larg cu arhitecturile
Distribuitorii raporteaz adesea latenta hardware (timpul firelor)
Programatorii de aplicatii se preocup de latenta software (program
utilizator la program utilizator)
Observatii:
Latentele hardware/software difer adesea cu 1-2 ordine de mrime
Latenta maxim hardware variaz cu diametrul, dar variatia n latenta
software este uzual neglijabil
Latenta este important pentru programele cu multe mesaje de mici dimensiuni.
Propriettile unei retele: bandwidth (BW)
O retea este partitionat n dou sau mai multe subgrafuri disjuncte dac unele
noduri nu pot ajunge la altele.
Lrgimea de band (BW) este o valoare link = w*1/t
w este numrul de fire unidirectional sau bidirectional
186
t este timpul pe bit
BW este tipic n Gigabytes (GB), adic, 8*2
20
biti.
BW efectiv este uzual mai jos dect BW a legturii fizice din cauza overhead-
ului de pachet.
BW este important pentru aplicatii n care cele mai multe mesaje sunt de mare
dimensiune.
Proprietti ale unei retele: BW la bisectie
BW la bisectie: BW de-a curmezisul celei mai mici tieturi care divide reteaua
n dou prti egale.
BW de-a curmezisul prtii celei mai nguste a retelei.
BW la bisectie este important pentru algoritmii n care toate procesoarele
trebuie s comunice cu toate celelalte.
Topologia retelei
n trecut, a existat o cercetare de volum considerabil n ceea ce priveste
topologia retelelor si algoritmii de aplicare (mapping) pe topologie
costul cheie de minimizat: numrul de hops ntre noduri (care fac
store and forward)
retelele moderne ascund costul de hop (prin rutarea wormhole),
astfel c topologia nu mai este un factor major n performanta
algoritmului
187
Exemplu: pe un sistem IBM SP, latenta hardware variaz de la 0,5 s la 1,5 s,
dar latenta transmiterii mesajelor la nivelul utilizatorului este, grosier vorbind,
36 s.
Este necesar o baz n topologia retelelor
algoritmii pot avea o topologie a comunicrii
topologia afecteaz BW la bisectie
Topologii liniare si circulare
Retea liniar
diametru = n 1; distanta medie ~n/3
BW la bisectie = 1 (unittile sunt BW de link)
Toruri sau cercuri
Diametru = n/2; distanta medie n/4
BW la bisectie = 2
Natural pentru algoritmi care lucreaz cu masive 1D
Site (meshes) si toruri
Sita bidimensional
Diametrul = 2*(sqrt(n) 1)
BW la bisectie = sqrt(n)
Toruri bidimensionale
Diametrul = sqrt(n)
BW la bisectie = 2*sqrt(n)
188
Se generalizeaz la dimensiuni mai mari (Cray T3D utilizeaz torul 3D).
Naturale pentru algoritmi care lucreaz pe masive de date 2D si/sau 3D.
Hipercuburi
Numrul de noduri n = 2
d
, cu d dimensiunea
Diametrul = d
BW la bisectie = n/2
Popular n masinile timpurii (Intel iPSC, NCUBE).
Multi algoritmi inteligenti (clever)
Vezi Notele la CS267 din 1996
Adresarea prin coduri Greycode.
Fiecare nod conectat la alte d noduri cu un bit diferit
189
Arbori
Diametru = logn
BW la bisectie = 1
Asezare facil ca un graf plan.
Multi algoritmi arborescenti (de pild nsumarea)
Arborii grasi (fat trees) evit problema BW la bisectie:
Mai multe (sau mai largi) legturi aproape de top
Exemplu: Thinking Machines CM-5
Fluturi
Diametru = logn
BW la bisectie = n
Cost: multe fire
Utilizat n BBN Butterfly un supercalculator dezvoltat de BBN
Technologies, denumit dup reteaua de comutare n trepte, de tip fluture,
piesa central a constructiei. Poate avea pn la 512 CPU conectate pentru a
permite acesul fiecrei CPU la toate celelalte CPU, dar cu o latent de circa 15
ori mai mare dect propria latent. Modelele mai vechi GP-1000 foloseau 256
190
de procesoare Motorola 68020, modelele mai recente TC-2000 utilizeaz pn
la 512 procesoare Motorola 88100.
Natural pentru FFT (Fast Fourier Transform).

Topologii n masini reale
Multe din acestea sunt aproximri: de pild, masina Cray X1 este n realitate un
hipercub cu ptrate rigidizate (quad bristled hypecube) si unii din arborii
grasi nu sunt att de grasi pe ct ar trebui la vrf.
191
Evolutia masinilor cu memorie distribuit
Conexiuni ale unor cozi speciale sunt nlocuite prin acces direct la memorie
(DMA direct memory access).
Procesorul mpacheteaz sau copiaz mesajele
Initializeaz transfer, merge mai departe cu calculul
Bibliotecile de transfer de mesaje furnizeaz scheme store-and-forward:
Pot trimite/receptiona ntre orice pereche de noduri, nu numai de-a
lungul unui fir
Timpul este proportional cu distanta deoarece fiecare procesor de pe o
cale trebuie s participe la transfer
Rutarea wormhole n hardware
Procesoare speciale de mesaje care nu ntrerup procesoarele principale
pe acea cale
Trimiterile de mesaje sunt n stilul pipeline
Procesoarele nu asteapt pentru a isprvi un mesaj nainte de a nainta
(forwarding) un altul
Modele ale performantei
PRAM Parallel Random Access Memory
Toate operatiile de acces la memorie sunt complete ntr-o perioad a ceasului
conceptul de memorie ierarhizat absent (too good to be true)
OK pentru a ntelege dac un algoritm are suficient paralelism (at all)
Strategia de proiectare a algoritmilor paraleli: mai nti faci algoritmul
PRAM, apoi te preocupi de timpul de memorie/comunicare (ceea ce
uneori merge)
Ceva mai realist: PRAM Concurrent Read Exclusive Write (CREW)
Modelul latentei si BW
Timpul de trimitere a unui mesaj de lungime n este, grosier vorbind:
Timpul = latenta + n*costul_per_cuvnt (word)
= latenta + n/BW
Topologia este presupus irelevant.
Adesea denumit modelul si scris ca
Timpul = + n*
Uzual, >> >> timpul per flop
Un mesaj lung este mai ieftin dect mai multe scurte
192
+ n* << n*( + 1*)
Se pot face sute sau mii de flops n costul unui singur mesaj
Lectie de retinut: e necesar un raport mare calcul-pe-comunicare pentru a fi
eficient.
Parametri si pe masini contemporane:
este n s, este n s per Byte
Aceste numere au fost obtinute empiric.
Ct de bine prezice modelul
Timpul = + n*
performanta real?
Diagrame cu BW
Date de la Mike Welcome NERSC
193
Model dimensiunea mesajului cu timp variabil & masini
Timpul mesajului msurat
Parametrii logP: overhead & latent
194
Costul fr suprapunere Costul cu suprapunere
Parametri logP: gap.
The gap este intervalul ntre trimiterea de mesaje.
The gap poate fi mai mare dect overhead-ul trimiterii
NIC (Network Interface Card) poate fi ocupat cu finalizarea procesrii
ultimului mesaj si nu poate accepta unul nou
Controlul fluxului sau presiunea din spate pe retea poate preveni/opri
NIC-ul s accepte urmtorul mesaj de trimis
The gap reprezint inversul BW a retelei pentru trimiteri de mesaje mici.
Rezultate: EEL si overheadul
195
Date de la Mike Welcome NERSC
Limitri ale modelului logP
Modelul logP are un cost fixat pentru fiecare mesaj.
Aceasta-i util n a arta cum se iuteste difuzarea (broadcast) unui
singur word
Alte exemple si n articolele (despre) logP
Pentru mesaje mai mari, exist o variatie logGP
Doi parametri de gap, unul pentru mesaje mici, altul pentru mesaje mari
Gap-ul pentru un mesaj mare este din modelul anterior
Nu se ia n considerare topologia (se ignor limitele pentru BW de bisectie)
Se presupune o retea complet conectat
Pentru unii algoritmi cu comunicare cu vecinul cel mai apropiat, dar cu
comunicare toti-cu-toti aceasta se cere a fi rafinat suplimentar
Acesta este un model plat, adic fiecare procesor este conectat la retea.
Clusterele de SMP-uri nu sunt modele precise/potrivite
Tendinte n masinile noi
Latena cap la cap n timp
Latena nu s-a mbunttit semnificativ n timp.
T3E (memorie partajat) era punctul cel mai de jos
Federation n 2003 nu va atinge acel nivel 7 ani mai trziu!
196
Date de la Kathy Yelik, UCB si NERSC
Overhead pentru trimitere n timp
Overhead-ul nu s-a mbunttit semnificativ; T3D a fost cel mai bun
Lips de integrare; lips de atentie n software
Date de la Kathy Yelik, UCB si NERSC
Implementarea transferului de mesaje sincron
197
Operatiile send complete dup potrivirea lui receive si dup ce datele surs au
fost trimise
Operatiile receive complete dup ce transferul de date este complet de la send
pereche
Exemplu: permutarea de date
Schimbare de date ntre procesoarele 0 si 1, versiunea 1: ce merge ru?
Procesorul 0 Procesorul 1
send(1, item0, 1, tag1) send(0, item1, 1, tag2)
recv(1, item1, 1, tag2) recv(0, item0, 1, tag1)
Blocare!
Schimbare de date ntre procesoarele 0 si 1, versiunea 2:
Procesorul 0 Procesorul 1
send(1, item0, 1, tag1) recv(0, item0, 1, tag1)
recv(1, item1, 1, tag2) send(0, item1, 1, tag2)
Dar ce se ntmpl la o permutare general, cnd procesorul j vrea s trimit la
procesorul s(j), cnd s(1), s(2), , s(P) este o permutare de 1, 2, , P?
Implementarea transmiterii de mesaje asincron
Protocolul optimist ntr-o singur faz presupune c destinatia poate la cerere s
tin datele ntr-un buffer
198
Transmitere de mesaje asincron sigur
Uzeaz de un protocol n trei faze.
Buffer de partea expeditorului.
Variatii de completare a unui send
Asteapt pn datele se copiaz de la utilizator n buffer-ul sistemului
Nu astepta f utilizatorul constient de modificarea datelor
Exemplu reluat: permutarea de date
Procesorul j trimite un item la procesorul s(j), unde s(1), , s(P) este o
permutare a numerelor 1, , P
Procesorul j
199
Send_asynch(s(j), item, 1, tag)
Recv_block(ANY, item, 1, tag)
Ce poate merge ru?
E necesar a ntelege semantica lui send si receive.
Multe nuante la ndemn.
Alte operatii nafar de send/receive
Comunicatii colective (ntre mai mult de dou procesoare)
Difuzarea general (broadcast) de la un proces la toate celelalte
Bariere
Reduceri (suma, produsul, max, min, boolean si #, ) unde # este orice
operatie asociativ
mprstie/colecteaz
Prefix paralel procesorul j detine x(j) si calculeaz y(j) = x(1) # x(2) #
# x(i)
Se poate aplica tuturor celorlalte procesoare sau unui subset definit de
utilizator
Cost = O(logP) utiliznd un arbore
Operatii de status
Chestioneaz despre/asteapt pentru ncheierea de send/receives
Cte procesoare exist?
Care este numrul procesorului meu?
Exemplu: sharks and fish
N pesti pe P procesoare, N/P pesti per procesor
La fiecare pas de timp, se calculeaz fortele pe pesti si acestia se
deplaseaz
E necesar a calcula interactiunea gravitational
ntr-un algoritm n
2
uzual, fiecare peste depinde de oricare alt peste
Fiecare peste trebuie s viziteze fiecare procesor, chiar dac el
trieste numai pe unul
Care este costul?
Doi algoritmi pentru gravitatie: care sunt costurile lor
Algoritmul 1
Copiaz masivul Fish local de lungime N/P n masivul Tmp
for j = 1 to N
for k = 1 to N/P, calculeaz forta lui Tmp(k) pe Fish(k)
200
Roteste Tmp cu 1
for k = 2 to N/P, Tmp(k) Tmp(k 1)
recv(my_proc 1, Tmp(1))
send(my_proc + 1, Tmp(N/P))
Algortimul 2
Copiaz masivul Fish local de lungime N/P n masivul Tmp
for j = 1 to P
for k = 1 to N/P
for m = 1 to N/P, calculeaz forta lui Tmp(k) pe Fish(m)
Roteste Tmp cu N/P
recv(my_proc 1, Tmp(1:N/P))
send(my_proc + 1, Tmp(1:N/P))
Ce ar putea merge anapoda? (grij la scrierea peste n Tmp)
Alti algoritmi pentru gravitatie
Algoritmul 3 (n codul sharks and fish):
Toate procesoarele trimit pestii lor la procesorul 1
Procesorul 1 difuzeaz toti pestii ctre toate procesoarele
Algoritmi arborescenti:
Barnes-Hut, Greengard-Rokhlin, Anderson
O(NlogN) n loc de O(N
2
)
Paralelizabili cu inteligent
Numai o aproximare, dar att de precis ct doriti (adesea sunt
necesari numai ctiva digiti, asa c de ce s pltesti pentru mai multi)
Aceeasi idee lucreaz pentru alte probleme unde efectele obiectelor la
distant devin netede sau compresibile
Electrostatic, turbulent,
Radiozitatea n grafic
Orice fenomen care verific ecuatia Poisson sau ceva de genul ei
201
SURSE DE PARALELISM
Paralelism si localism n simulare
Problemele din lumea real au paralelism si localism:
Multe obiecte opereaz independent de altele
Obiectele depind adesea mai mult de obiectele apropiate dect de cele
situate la distant
Dependenta de obiectele de la distant poate fi adesea simplificat
Modelele stiintifice pot introduce paralelism n plus
Cnd o problem continu este discretizat, dependentele n domeniul
temporal sunt n general limitate la pasi de timp adiacenti
Efectele de cmp ndeprtat, n multe cazuri pot fi ignorate sau
aproximate
Multe probleme exhib paralelism la niveluri multiple
Exemplu: circuitele pot fi simulate la mai multe niveluri si n fiecare
poate exista paralelism n sau ntre subcircuite
Exemplu: simulare de circuite
Circuitele sunt simulate la multe niveluri diferite
202
Tipurile de baz ale simulrii
Sisteme cu evenimente discrete:
Exemple: Jocul vietii, simularea circuitelor la nivelul logicii
Sisteme de particule:
Exemple: biliardul, simularea dispozitivelor semiconductoare, galaxiile
Variabile concentrate care depind de parametri continui:
Ecuatiile diferentiale ordinare, exemple: simularea circuitelor (Spice),
mecanica structurilor, cinetica chimic
Variabile continue (distribuite) care depind de variabile continue:
Ecuatii cu derivate partiale, de pild pentru cldur, n elasticitate, n
electrostatic
Un fenomen dat poate fi modelat la niveluri multiple.
Multe simulri combin mai multe dintre aceste tehnici.
Idei generale (outline)
Sistemele cu evenimente discrete timpul si spatiul discrete
Sistemele de particule caz special important al sistemelor cu parametri
concentrati (lectia precedent)
Ecuatii diferentiale ordinare (ODE Ordinary Differential Equations) sisteme
cu parametri concentrati, locatia entittilor este discret timpul este continuu
Ecuatii cu derivate partiale (PDE Partial Differential Equations) timpul si
spatiul continue (lectia urmtoare)
(de la discret sus la continuu jos)
Revedere asupra sistemelor de particule
n sistemele de particule exist
Forte externe care sunt usor de paralelizat
Fortele de cmp apropiat pot fi rezolvate cu comunicare limitat
Fortele de cmp ndeprtat sunt mai dificil de manipulat (cer mult
comunicare)
Algoritmii O(n
2
) cer ca toate particulele s vorbeasc cu toate
celelalte
Calcul scump n calculul pe masini seriale
Scumpete si n comunicare pe o masin paralel
Algoritmii inteligenti si structurile de date inteligente pot ajuta
Metodele retelelor de particule
Metodele bazate pe arbori
203
Sisteme cu evenimente discrete
Sistemele sunt reprezentate ca:
Multimea de variabile de cardinal finit
Multimea valorilor pe care le iau variabilele la un moment dat se
numeste stare
Fiecare variabil este actualizat prin evaluarea unei functii de
tranzitie care depinde de alte variabile
Sistemul poate fi:
Sincron: la fiecare pas de timp discret evaluaz toate functiile de
tranzitie; denumit si masin de stare
Asincron: functiile detranzitie sunt evaluate numai dac intrrile se
modific pe baza unui eveniment dintr-o alt parte a sistemului;
denumit si simulare condus (driven) de evenimente
Exemplu: Jocul vietii:
Cunoscut si ca S&F #3:
http://www.cs.berkeley.edu/~yelik/cs267/SharksAndFish
Spatiul divizat n celule, anumite reguli guverneaz continutul celulei la
fiecare pas
Simularea este sincron
Se utilizeaz dou copii ale grilei (veche si nou)
Valoarea fiecrei noi celule din gril depinde numai de 9 celule (ea
nssi si cele 8 vecine) din grila veche
Simularea se face n pasi de timp fiecare celul este actualizat la
fiecare pas
Usor de paralelizat prin partitionarea domeniului fizic
repet
calcul local pentru actualizarea sistemului local
barier()
schimb informatii privind starea cu celulele vecine
pn cnd se termin simularea
Localismul se obtine utiliznd zone mari de ocean
204
Numai valorile de frontier de la zonele vecine sunt necesare
Simularea circuitelor sincron
Circuitul este un graf alctuit din subcircuite conectate prin fire
Simulrile componente trebuie s interactioneze dac ele au un fir
comun
Strucutura datelor este neregulat graf de subcircuite
Algoritmul paralel este mnat de timing sau sincron
Evalueaz toate componentele la fiecare pas de timp (determinat
de ntrzierea circuitului cunoscut)
Partitionarea grafului atribuie subgrafuri procesoarelor (NP-complet)
Determin paralelismul si localismul
ncercri de a distribui egal subgrafuri la noduri (echilibru de sarcin)
ncercri de a minimza traversarea de limite (minimizarea comunicrii)
Traversri de limite: 6 n primul graf, 10 n al doilea.
Simularea asincron
Simularea sincron poate risipi timpul.
Se face simulare chiar atunci cnd intrrile nu se schimb
Simulrile asincrone actualizeaz numai cnd se produce un eveniment
provenit de la o alt component:
Nu pasi de timp globali ci evenimente individuale care contin marca
timpului
Exemplu: Jocul vietii n pooluri slab conectate (nu simuleaz poolurile
goale)
Exemplu: simularea circuitelor cu ntrzieri (evenimentele sunt
schimbarea portilor)
Exemplu: simularea traficului (evenimentele sunt vehicule care schimb
banda etc.)
Simularea asincron este mai eficient dar mai greu de paralelizat
205
n MPI evenimentele sunt implementate natural ca mesaje, dar cum se
poate sti cnd se execut un receive?
Planificarea simulrii circuitelor asincron
Conservativ:
Simuleaz numai pn la (inclusiv) marca de timp minim a intrrilor
Poate necesita detectia blocajelor dac n graf exist cicluri, sau altfel
mesaje null
Exemplu: simulatorul de circuite Pthor in Splash1 de la Stanford
Speculativ (sau optimist)
Presupune c nici un impuls nou nu va sosi si merge nainte cu
simularea
Poate necesita backup dac presupunerea e gresit
Exemplu: Timewarp [D.Jefferson], Parswec [Wen, Yelik]
Optimizarea echilibrului de sarcin si localismului este dificil:
Localism nseamn punerea unui subcircuit cuplat puternic pe un
procesor
Deoarece partea activ a circuitului este probabil a fi un subcircuit
puternic cuplat, asta poate fi ru pentru echilibrarea de sarcin de calcul
Sumar despre simularea discret
Modelul lumii este discret, si n timp si n spatiu.
Tratare:
Se descompune domeniul, adic ntr-un set de obiecte
Se execut fiecare component nainte utiliznd
Sincronul: comunicare la fiecare sfrsit de pas al timpului
Asincronul: comunicare la cerere
Planificare conservativ asteptare pentru intrri
Planificare speculativ se peresupun intrri inexistente,
se revine dac este necesar
Sisteme cu parametri concentrati
Sisteme cu variabile concentrate
Multe sisteme sunt aproximate prin
Sistem cu variabile concentrate (lumped)
Fiecare depinde de parametri continuu (uzual timpul)
Exemplu circuit:
206
Aproximat ca un graf
Legturile sunt arce
Noduri sunt conexiunile ntre 2 sau mai multe fire
Fiecare arc are un rezistor, o capacitate, o inductant sau o surs
de tensiune
Sistemul este concentrat deoarece nu se calculeaz tensiunile sau
curentii n fiecare punct al firului ci numai la capetele lui
Variabilele sunt legate prin legea lui Ohm, legile lui Kirchhoff etc.
Se formeaz un sistem de ecuatii diferentiale ordinare (ODE Ordinary
Differential Equations).
Derivatele sunt n raport cu timpul
Exemplul unui circuit
Starea sistemului este reprezentat de
permanent
v ramuri pe tensiunile
i ramuri n curentii
v noduri n tensiuni
b
b
n

Ecuatiile includ
1
1
1
1
]
1

1
1
]
1

1
1
1
1
1
1
]
1


0
0
0
0
0
0
0
0
0 0
inductante
capacitati
Ohm
tensiuni pentru Kirchhoff
curenti pentru Kirchhoff
S
v
i
v
I
dt
d
L
dt
d
C I
I R
I A
A
b
b
n
Se scrie ca un singur sistem de ODE cuprinztor (cu posibile restrictii)
Exemplu de analiz structural
Un alt exemplu este analiza structural fcut de inginerii constructori
Variabilele sunt deplasrile unor puncte ntr-o cldire
Se aplic legile lui Newton si ale lui Hook (elastic)
Modelarea static: se aplic forte si se determin deplasrile
Modelarea dinamic: se aplic forte continue (ca la un cutremur de
pmnt)
Probleme de valori proprii: se potrivesc modurile rezonante ale cldirii
cu un cutremur?
207
Proiectul OpenSees la CE de la Berkeley priveste aceast sectiune de 880, ntre
altele
Rezolvarea ODE
n aceste exemple si n multe altele matricile sunt rare:
Adic multe dintre elementele masivului sunt nule
Nici memorare, nici calcule asupra acestor zerouri
Fiind dat un set de ODE, apar dou tipuri de ntrebri:
Calculul valorilor variabilelor la un timp t
Metode explicite
Metode implicite
Calculul modurilor de vibratie
Probleme de valori proprii
Rezolvarea de ODE: metode explicite
Se admite c ODE sunt x(t) = f(x) = A*x, cu A o matrice rar
Se calculeaz x(i*dt) = x[i] la i = 0, 1, 2,
Se aproximeaz x(i*dt) ca x[i+1] = x[i] + dt*panta (cu panta n x[i])
208
Metodele explicite, de pild metoda Euler (nainte)
Se aproximeaz x(t) = A*x prin (x[i+1] x[i])/dt = A*x[i]
x[i+1] = x[i] + dt*A*x[i], adic multiplicare de matrice rar cu vector
Concesii (tradeoffs):
Algoritm simplu: multiplicare de matrice rar cu vector
Probleme de stabilitate: pot fi necesari pasi de timp foarte mici, n
spacial dac sistemul este stiff (se schimb rapid)
Rezolvarea ODE: metodele implicite
Se admite c ODE sunt x(t) = f(x) = A*x, cu A o matrice rar
Se calculeaz x(i*dt) = x[i] la i = 0, 1, 2,
Se aproximeaz x(i*dt) ca x[i+1] = x[i] + dt*panta (cu panta n x[i+1])
Metoda implicit, de pild Euler napoi rezolv:
Se aproximeaz x(t) = A*x prin (x[i+1] x[i])/dt = A*x[i+1]
(I dt*A)*x[i+1] =x[i], adic e necesar rezolvarea unui sistem liniar
de ecuatii algebrice
209
Compromisuri:
Pasi de timp posibil mai mari: n sepcial pentru probleme rigide (stiff)
Algoritm mai dificil: necesit rezolvarea unui sistem rar la fiecare pas
Rezolvarea ODE: valori proprii
Calcularea modurilor de vibratie: determinarea valorilor proprii si vectorilor
proprii
Se caut solutia ecuatiei x(t) = A*x de forma x(t) = sin(f*t)*x
0
, cu x
0
un
vector constant
Se introduce (plug in) pentru a obtine f
2
*x
0
= A*x
0
, astfel nct f
2
este
o valoare proprie si x
0
este un vector propriu al lui A
Schemele solutiei se reduc fie la multiplicarea de matrici rare sau la
rezolvarea de sisteme liniare rare.
ODE si matrici rare
Toate acestea se reduc la probleme cu matrici rare:
Explicit: multiplicare matrice rar cu vector
Implicit: rezolvarea unui sistem liniar rar
Rezolvare direct (eliminarea Gauss)
Rezolvare iterativ (utilizeaz multiplicare matrice rar cu
vector)
Algoritmii pentru valori proprii/vectori proprii pot fi, de asemenea,
expliciti sau impliciti
Multiplicarea paralel matrice rar vector
y = A*x, cu A rar (nn)
Probleme:
Care procesor memoreaz y[i], x[i] si A[i, j]?
Care procesor calculeaz y[i] = sum (de la 1 la n) A[i, j]*x[j] = (linia i
a lui A)*x un produs punctual rar?
210
Partiionarea
Multimea de indici {1, 2, , n} se partitioneaz n N
1
, N
2
, , N
p
Pentru toti i din N
k
, procesorul k memoreaz y[i], x[i] si linia i din A
Pentru toti i din N
k
, procesorul k face calculul (linia i din A)*x; cea mai
problematic operatie
Regula proprietarul calculeaz: procesorul k face calculul
propriilor y[i]
Reordonarea matricilor prin partitionarea grafurilor
Structura ideal a matricei pentru paralelism: bloc-diagonal.
p (numrul de procesoare) blocuri, tot calculul se poate face local
Putinele valori nenule situate n afara acestor blocuri necesit
comunicare
Se pot reordona liniile/coloanele pentru a avea o asemenea structur?
Scopurile reordonrii
Scopuri care vizeaz perfomanta:
Echilibrarea sarcinii (cum se msoar ncrcarea?)
Echilibrarea memoriei (ct memoreaz fiecare procesor?)
Minimizarea comunicrii (ct se comunic?)
Unii algoritmi face reordonarea pentru alte motive:
Reducerea numrului de valori nenule n rezultat (fill)
Ameliorarea propriettilor numerice.
Partitionarea grafurilor si matricile rare
Relatia dintre matrici si grafuri
211
O partitie bun a unui graf are:
Numr egal (ponderat) de noduri n fiecare parte (sarcin si memorie
balansate)
Numr minim de muchii (arce) care leag prtile (minimizarea
comunicrii)
Se reordoneaz liniile/coloanele prin punerea laolalt a tuturor nodurilor dintr-o
parte a partitiei.
Metode implicite si probleme de valori/vectori proprii
Metode directe (eliminarea Gauss):
Denumite descompuneri LU din cauza factorizrii A = L*U
Lectiile viitoare vor lua n discutie ambele cazuri, dens si rar
Mai complicat dect multiplicarea matrice rar vector
Metode de rezolvare iterative:
Vor fi discutate mai multe din ele mai ncolo
Jacobi, overrelaxarea succesiv (SOR Succesive Over-
Relaxation), gradientii conjugati (CG), multigrila,
Multe au ca miez multiplicarea matrice rar vector
Probleme de valori/vectori proprii:
Unele lectii viitoare se vor concentra si pe cazurile dense si pe cele rare
Metodele directe depind de asemenea de multiplicarea matrice rar
vector.
Ecuatii cu derivate partiale PDE
Variabile continue, parametri continui
Sisteme de acest gen:
212
Probleme parabolice (dependente de timp):
Fluxul de cldur: temperatura este functie de pozitie si de timp
Difuzia: concentratia este functie de pozitie si de timp
Probleme eliptice (stri stationare):
Potentialul gravitational sau electrostatic: potentialul depinde de
pozitie
Probleme hiperbolice (unde):
Mecanica cuantic: functia de und depinde de pozitie si de timp
Multe probleme combin aspectele de mai sus.
Curgerea fluidelor: vitez, presiune, densitate, toate sunt functii de
pozitie si de timp
Elasticitate: efortul, tensiunile mecanice sunt functii de pozitie si de
timp
Terminologie
Termenii hiperbolic, parabolic, eliptic vin de la cazuri speciale ale formei
generale a PDE de ordinul al doilea liniar
0
2
2 2
2
2
+

f
y
u
e
x
u
d
y
u
c
y x
u
b
x
u
a
unde y este timpul.
Prin analogie cu solutiile ecuatiei ptratice generale
0
2 2
+ + + + + f ey dx cy bxy ax
Exemplu: scrierea ecuatiei cldurii
Se consider o problem simpl:
O bar cilindric de material omogen, izolat cu exceptia capetelor
Fie u(x, t) temperatura la pozitia x la timpul t
Cldura circul de la x h la x + h cu debitul proportional cu derivata a
doua n coordonata x
h
h t h x u t x u h t x u t h x u
C
t
t x u / )] , ( ) , ( [ / )] , ( ) , ( [ ) , ( +

Prin trecere la limit, h 0, se obtine ecuatia


2
2
) , ( ) , (
x
t x u
C
t
t x u

213
Detalii despre metoda explicit pentru ecuatia cldurii
Din observatii experimentale se obtine:
u(x, t)/t = [u(x, t)/x]
(pentru simplitate, s-a considerat C = 1)
Se discretizeaz timpul si spatiul si se utilizeaz tehnica explicit de a aproxima
derivatele (ca la ODE):
2
/ )] , ( ) , ( 2 ) , ( [ / )] , ( ) , ( [ h t h x u t x u t h x u dt t x u dt t x u + + +
)] , ( ) , ( 2 ) , ( )[ / ( ) , ( ) , (
2
t h x u t x u t h x u h dt t x u dt t x u + + +
)] , ( ) , ( 2 ) , ( )[ / ( ) , ( ) , (
2
t h x u t x u t h x u h dt t x u dt t x u + + + +
Se pune z = dt/h
2
)] , ( ) , ( ) 2 1 ( ) , ( ) , ( t h x zu t x u z t h x zu dt t x u + + + +
Prin schimbarea de variabile x n j si y n i se obtine
u[j,i+1] = z*u[j1,i] + (12*z)*u[j,i] + z*u[j+1,i].
Solutia explicit a ecuatiei cldurii
Se utilizeaz diferentele finite cu u[j,i] ca temperatura la
Timpul t = i*dt (i = 0, 1, 2, ) si pozitia x = j*h (j = 0, 1, , N=1/h)
Conditiile initiale pe u[j, 0]
Conditii pe frontier la u[0, i] si u[N, i]
La fiecare pas de timp, i = 0, 1, 2,
for j=0 to N
u[j,i+1] = z*u[j1,i] + (12*z)*u[j,i] +
z*u[j+1,i]
cu z ca mai sus.
214
Aceasta corespunde la multiplicarea matrice vector, cu cei mai apropiati
vecini pe gril
Vederea matricii din metoda explicit la ecuatia cldurii
Multiplicare cu o matrice tridiagonal la fiecare pas
1
1
1
1
1
1
]
1

z z
z z z
z z z
z z
T
2 1
2 1
2 1
2 1

Graf si decupaj de 3 puncte
Paralelismul n metoda explicit pentru PDE
Partitionarea spatiului (x) n p bucti, cele mai mari
O echilibrare a sarcinii (presupunnd numr mare de puncte relativ la p)
Minimizarea comunicrii (numai p bucti)
Se generalizeaz la:
Dimensiuni multiple
Grafuri arbitrare (= matrici rare arbitrare)
Tratarea explicit este utilizat adesea pentru ecuatii hiperbolice.
Probleme cu tratarea explicit pentru ecautia cldurii (parabolic):
Instabilitate numeric
Solutia explodeaz ulterior dac z = dt/h
2
> 0,5
Devine necesar a face pasii de timp foarte mici cnd h este mic: dt <
0,5*h
2
Instabilitti n rezolvarea ecuatiei cldurii explicit
215
Solutia implicit a ecuatiei cldurii
Din observatii experimentale se obtine:
u(x, t)/t = [u(x, t)/x]
(pentru simplitate, s-a considerat C = 1)
Se discretizeaz timpul si spatiul si pentru aproximarea derivatei se utilzeaz
varinta implicit (Euler napoi backward):
2
/ )] , ( ) , ( 2 ) , ( [ / )] , ( ) , ( [ h dt t h x u dt t x u dt t h x u dt t x u dt t x u + + + + + +
)] , ( ) , ( 2 ) , ( )[ / ( ) , ( ) , (
2
dt t h x u dt t x u dt t h x u h dt t x u dt t x u + + + + + + +
Se pune z = dt/h
2
si se schimb variabilele x n j si y n i. Se obtine:
u[:,i] = (I z*L)*u[:,i+1]
cu I matricea unitate si cu L laplaceanul
1
1
1
1
1
1
]
1

2 1
1 2 1
1 2 1
1 2
L
216
Discutia de mai sus se bazeaz pe aproximarea Euler napoi, dar regula
trapezelor are rezultate numerice mai bune.
Asta se traduce prin rezolvarea ecuatiei
[I + (z/2)*L]*u[:, i + 1] = [I (z/2)*L]*u[:, i]
din nou cu I matricea unitate si cu L de aceeasi form.
Graf si decupaj de 3 puncte
Aceasta este n esent rezolvarea ecuatiei Poisson n spatiul 1D.
Metoda implicit pentru 2D
Este similar cazului 1D, dar matricea L este acum
1
1
1
1
1
1
1
1
1
1
1
1
]
1

4 1 1
1 4 1 1
1 4 1
1 4 1 1
1 1 4 1 1
1 1 4 1
1 4 1
1 1 4 1
1 1 4
L
Decupaj de 55 puncte
Cazul 3D este similar (cu decupaj de 77 puncte).
Multiplicarea cu aceast matrice (ca n cazul explicit) este simplu: un calcul pe
vecinii cei mai apropiati pe o gril 2D.
217
Pentru a rezolva acest sistem sunt tehnici multiple.
Relatia ecuatiei Poisson cu gravitatia, cu electrostatica
Ecuatia Poisson apare n multe probleme, de exemplu, forta exercitat asupra
unei particule situat n pozitia (x, y, z) de o particul situat n origine se
exprim ca (x, y, z)/r
3
, cu r = sqrt(x
2
+ y
2
+ z
2
).
Forta este totodat gradientul potentialului V = 1/r
(d/dx V, d/dy V, d/dz V) = grad V
V satisface ecuatia lui Poisson (a se verifica)
Algoritmi pentru ecuatia lui Poisson 2D (N variabile)
PRAM este un model paralel idealizat cu costul comunicrii nul.
Referiri: James Demmel, Applied Numerical Linear Algebra, SIAM, 1997.
Privire general asupra algoritmilor
Sortati n dou oridini (grosier)
De la cei mai lenti la cei mai rapizi pe masini secventiale
218
De la cei mai generali (care lucreaz pe orice matrice) la cei mai
specializati (care lucreaz pe matrici ca T tridiagonal de mai sus)
LU dens: eliminarea Gauss, lucreaz pe orice matrice NN.
LU band: exploateaz faptul c T are elemente nenule numai pe sqrt(N)
diagonale cele mai apropiate de diagonala principal.
Jacobi: n esent face o multiplicare matrice vector prin T ntr-o bucl
interioar a algoritmului.
Inversa explicit: presupune c se doreste a se rezolva multe sisteme cu T,
astfel ca se poate precalcula si memoriza T
1
fr cheltuieli prea mari si numai
prin multiplicarea cu ea nssi (dar nc scump).
Gradientii conjugati: se utilizeaz multiplicarea matricevector, ca la Jacobi,
dar se exploateaz propriettile matematice ale matricei T pe care metoda
Jacobi nu le exploateaz.
SOR rosu-negru (Succesive Over-Relaxation): variatie a metodei Jacobi care
exploateaz totusi diferitele proprietti matematice ale matricei T. Utilizat n
schemele multigril.
LU: eliminarea Gauss care exploateaz structura particular de zerouri a
matricei T.
FFT (Fast Fourier Transform): lucreaz numai pe matrici foarte asemntoare
cu T.
Multigrid: lucreaz de asemenea pe matrici de genul T care provin din PDE
eliptice
Lower Bound: serial (timp pentru a tipri rspunsul); paralel (timp pentru a
combina N intrri)
Detalii n notele de clas si www.cs.berkeley.edu/~demmel/ma221
Mflop/s si timp de executie n practic
Problema: un solver iterativ pentru o problem de convectie-difuzie; se execut
pe o masin cu 1024-CPU NCUBE-2
Referire: Shadid si Tuminaro, SIAM Parallel Processing Conference, March
1991
Care solver ar fi de ales?
Sumar al metodelor de rezolvare a PDE
219
Ca si n cazul ODE, sunt posibile tratri explicite sau implicite.
Explicit, multiplicarea matrice rar vector
Implicit, rezolvarea matricei rare la fiecare pas
Rezolvarea direct este dificil (mai mult, mai departe)
Rezolvarea iterativ se traduce n multiplicare matrice rar
vector
Corespondenta gril si matrice rar:
Multiplicarea matrice rar vector este medierea vecinilor cei mai
apropiati pe grila/reteaua suport (underlying).
Nu toate calculele cu vecinii cei mai apropiati au acceasi eficient.
Factorii sunt structura retelei (structur non-zero) si numrul de flops
per punct.
Comentaiu asupra retelelor practice
Retele regulate 1D, 2D, 3D
Importante ca constructie de blocuri pentru retele mai complicate
Retele (meshes) practice sunt adesea neregulate
Retele compuse, care constau n retele regulate ndoite multiple
reunite pe muchii
Retele nestructurate, cu puncte de retea si conexiuni arbitrare
Retele adaptive, care si schimb rezolutia n timpul procesului de
solutionare a problemelor pentru a pune efortul de calcul acolo unde
este necesar
Paralelism n retele regulate
Calculul unui decupaj (stencil) ntr-o retea regulat
Necesit a comunica punctele din apropierea frontierei ntre procesoare
nvecinate
Adesea cu regiuni fantom (ghost)
Raportul suprafat la volum tine comunicarea sczut, dar
Poate fi nc problematic n practic
220
Implementat utiliznd regiuni fantom
Adaug un overhead de memorie
Rafinarea adaptiv a retelelor (AMR Adaptive Mesh Refinement)
Retea adaptiv njurul unei explozii
Rafinarea fcut prin calcularea erorilor
Paralelism
Majoritar ntre benzi (patches), distribuite procesoarelor pentru
sarcin balansat
Se poate exploata ceva n interiorul unei benzi (patch) (SMP)
Proiecte:
Titanium (http://www.cs.berkeley.edu/projects/titanium)
Chombo (P.Colella, LBL), KeLP (S.Baden, UCSD), J.Bell, LBL
Retele adaptive
221
Unde de soc n dinamica unui gaz utiliznd AMR (Adaptive Mesh Refinement)
A se vedea http://www.llnl.gov/CASC/SAMRAI/
Retele compuse de la o structur mecanic
222
Convertirea unei retele ntr-o matrice
223
Efectele reordonrii asupra eliminrii Gauss
Retele neregulate: profilul NASA n 2D
224
Retele neregulate: tubul ngustat (multigrid)
Exemplu: retele Prometeu
225
Probe de gril de intrare si de grile grosiere
Provocarea grilelor neregulate
Cum s fie generate la nceput
Triunghiul, un partitionator de gril 2D de Jonathan Shewchuk
Mai dificil pentru 3D
Cum s se partioneze acestea
ParMetis, un partitionator de graf paralel
Cum s se proiecteze rezolvrile iterative
PETSc (Portable Extensible Toolkit for Scientific Computing), un
toolkit portabil extensibil pentru calcule stiintifice
Prometheus, un solver multigril pentru problemele de element finit pe
retele neregulate
Cum se proiecteaz solveri directi
SuperLU, eliminarea Gauss paralel n conditii de matrici rare
Acestea sunt provocri pentru executia secvential, cu att mai mult pentru
executia n paralel
Proiecte finale
Propunere de proiect
Echipe de 3 studenti, tipic din departamente diferite
Aplicatii sau sisteme paralel interesante
Articol de calitatea prezentrii unei conferinte
Performanta nalt este cheia:
ntelegerea performantei, reglarea (tuning), scalarea etc.
Mai important dificultatea problemei
Control (leverage)
Proiecte n alte clase (dar discutie cu lectorul mai nti)
Proiecte de cercetare
Idei de proiect
Aplicatii
Implemetarea programelor secventiale sau cu memorie n indiviziune
existente pe memorie distribuit
Investigarea negocierilor (trade-offs) SMP (utiliznd numai MPI n
comparatie cu paralelismul baazat pe MPI si fire threads)
Tools si sisteme
226
Efectele reordonrii asupar factorizrii matricilor rare si rezolvrilor
Algoritmi numerici
Solver mbunttit pentru metoda de frontier imersat
Utilizarea de vectori multipli (algoritmi n blocuri) n solveri iterativi
Noi platforme de calcul
Exploatarea ierarhiei clusterelor SMP n testele de banc (benchmarks)
Operatii de calcul agregate pe retele ad hoc (Culler)
mpingerea/explorarea limitelor calculului pe grile
Performanta sub defecte (under failures)
Benchmarking detaliat si analiza performantelor, inclusiv identificarea
posibilittilor de optimizare
Titanium
UPC (Unit Processing Code)
IBM SP (Blue Horizon)
227
228