Sunteți pe pagina 1din 250

Capitolul 1 Introducere

Domeniul algoritmilor paraleli preocup de mai bine de mai mult timp un numr mare de specialiti. Despre el, ca de altfel despre algoritmi n general, s-a scris mult i din diferite puncte de vedere. Un efort considerabil a fost depus pentru gsirea celor mai bune soluii paralele sau distribuite ale diverselor probleme, prin particularizarea unor soluii secveniale cunoscute sau pornind de la premise conceptuale total distincte de acestea. Lucrarea de fa vizeaz studierea sistematic a algoritmilor paraleli pentru cteva din cele mai reprezentative clase de aplicaii. Aceasta presupune adoptarea unui limbaj de descriere adecvat i utilizarea lui pentru prezentarea i analiza celor mai cunoscute soluii ale claselor de probleme selectate. Descrierea este completat prin discutarea unor aspecte relative la metodele de dezvoltare a algoritmilor paraleli i distribuii, precum i la analiza complexitii lor. Pentru a ncadra mai bine subiectul, vom ncerca s rspundem succint la urmtoarele ntrebri: care sunt principalele categorii de aplicaii paralele? care sunt principalele clase conceptuale de paralelism? care sunt principalele metode de programare? care sunt principalele clase de sisteme paralele folosite? 1.1. Categorii de aplicaii Exist mai multe motive pentru a utiliza calculul paralel n realizarea aplicaiilor: scurtarea timpului de execuie, realizarea unei fiabiliti crescute, specializarea funcional i natura inerent paralel a aplicaiilor. Una din cile de cretere a performanelor unei aplicaii este execuia simultan a diferitelor pari ale programului (pari pe care le numim procese) pe procesoare distincte. De cele mai multe ori, procesele nu sunt complet independente, ci comunic ntre ele. n funcie de frecvena comunicrilor, paralelismul are o granularitate mai mare (comunicri rare) sau mai fin (comunicri frecvente). O mare parte dintre algoritmii paraleli prezentai n literatur se refer la aceast categorie de aplicaii. Problemele care trebuie rezolvate aici sunt legate att de gsirea 1

unei mpriri adecvate n procese a prelucrrilor ce trebuie realizate, ct i de gsirea celor mai potrivite mecanisme de comunicare sau sincronizare ntre procese. Pentru aplicaii la care sigurana n funcionare este un factor critic (de exemplu, comanda unui avion), replicarea unor pri ale lor (procese sau date) poate constitui o soluie de toleran la defecte. Daca anumite procesoare se defecteaz, replicile lor le pot suplini. Ceea ce intereseaz aici sunt tehnicile de realizare corect a comutrii, cu alte cuvinte protocoalele ce asigur comportarea corect n sisteme n care funcionalitatea componentelor este parial. Unele aplicaii pot fi mprite n faze cu funcionaliti distincte: de calcul n virgul mobil, de prelucrri grafice, de prelucrare de fiiere, de imprimare etc. Aceasta permite exploatarea mai bun a caracteristicilor diferitelor componente ale sistemelor de calcul, pentru realizarea unor performane deosebite (folosirea unor procesoare n virgul mobil, a unor procesoare grafice, a unor servere de fiiere sau de imprimare). Problemele importante sunt aici cele legate de partajarea eficient a resurselor sistemelor de calcul. Unele aplicaii sunt inerent paralele. Un exemplu l constituie accesul simultan la o baz de date. Problemele importante aici sunt excluderea mutual i protecia utilizatorilor. Sunt patru categorii de specialiti interesai de calculul paralel i distribuit: specialiti n calculatoare (computer scientists) din domeniile arhitectura, limbaje, algoritmi (cutare i sortare, recunoaterea formelor, tolerana la defecte, algoritmi cu nalt grad de paralelism, algoritmi cu ascunderea latentelor), metodologii; specialiti n calcul numeric (computational scientists) interesai n pachete de programe pentru calcul matriceal, sisteme de ecuaii lineare i nelineare, cu derivate pariale etc. alte domenii tiinifice i inginereti (tehnologii i materiale noi, biomedicina, fizica nuclear i altele) comerciali (data mining, analize de risc etc.) Cerinele acestora i caracteristicile aplicaiilor lor sunt prezente succint n tabelul 1.1.

Domeniu Caracteristici

Cerine

tiinific i ingineresc virgul mobil cod de dimensiune redus rata I/E redus puine date puini utilizatori performana scalabilitate

Tabel 1.1 Comercial ntregi cod de dimensiune mare rata I/E mare multe date muli utilizatori performana sigurana n funcionare disponibilitate

1.2. Clase conceptuale Desprinderea unor clase conceptuale n paralelism este important ca sprijin n prima faz de abordare a unei probleme. ncadrarea ntr-una din aceste clase poate dirija proiectantul pe parcursul conceperii soluiei paralele a unei probleme. Clasificarea adoptat aici este una din mai multele prezentate n literatura de specialitate. Ea aparine lui Carriero i Gelernter i privete paralelismul n termenii: rezultatului unui program, agendei de activiti a programului, unui ansamblu de specialiti care mpreun constituie programul. Pentru a nelege mai bine fiecare concept, vom lua ca exemplu construcia unei case. Folosirea mai multor persoane la acest lucru conduce inerent spre paralelism. Dar, exist mai multe ci de folosire a lucrtorilor. Putem porni prin divizarea produsului final n mai multe componente: fundaie, perei, ferestre, ui, contor electric i conductori, contor de ap, evi, chiuvete etc. Putem apoi trece la construirea simultan a componentelor i la asamblarea lor, pe msur ce sunt terminate. Fiecrui lucrtor i se repartizeaz o parte a produsului final, de a crui construire se ngrijete. Toi pornesc lucrul simultan i lucreaz pn n momentul cnd continuarea depinde de o anumit restricie (de exemplu, de o alt component). Acesta este paralelismul rezultat, numit astfel deoarece rezolvarea unei probleme pleac de la mparirea rezultatului n mai multe fragmente, care sunt calculate n paralel, lund n consideraie (bineneles) restriciile impuse de problem.

Un exemplu tipic este calculul sumei a doi vectori de n elemente, S = A+B. Elementele lui S sunt independente ntre ele i pot fi calculate n paralel, ntr-un singur pas, folosind n procesoare, dup urmtoarea schem:
fa i := 1 to n do in parallel S[i] := A[i] + B[i] af

O alt posibilitate este de a alctui o agend de activiti necesare pentru a construi casa. Unele dintre ele se vor executa n paralel, altele sunt condiionate de o anumit ordine. Oricum, lucrtorii vor fi repartizai activitilor curente din agend, n numrul necesar i fr a se face vreo difereniere ntre ei. Fiecare lucreaz ct timp restriciile naturale ale problemei le permite acest lucru. Cea mai cunoscut paradigm de implementare a acestei clase de paralelsim este replicated workers sau master-worker. Un proces master iniializeaz calculele i creaz un numr de procese worker identice. n mod repetat, fiecare worker preia o sarcin i o execut. Programul se execut la fel, indiferent de numrul proceselor worker i se termin odat cu epuizarea sarcinilor. Pentru exemplificare, s considerm o problem de minim. Dat fiind un ansamblu E de nregistrri, E = {r} i o funcie de cost f:E->R care asociaz fiecrei nregistrri r un cost f(r), se cere min f(r) cu r din E. Procesul master umple un sac cu nregistrrile din E. Fiecare proces worker extrage o nregistrare r, calculeaz f(r) i, dac gsete o valoare inferioar minimului parial curent, o transmite master-ului. Acesta actualizeaz minimul curent. Programul se termin la golirea sacului. n fine, putem avea n vedere faptul c lucrtorii sunt specializai i c realizarea unei case reclam diferite specialiti. Toi lucrtorii pot ncepe simultan. Iniial unii vor atepta, pn cnd condiiile necesare efecturii operaiei pentru care sunt specializai sunt ndeplinite. Oricum, la un moment dat, vor lucra mai multe persoane. Aceasta este abordarea paralelismului ca ansamblu de specialiti. Aceast abordare este specific lucrului n banda de asamblare (pipeline) i se preteaz n cazul prelucrrii mai multor obiecte identice (de exemplu un grup de case). n cazul general, ea conduce la programe organizate ca o reea logic, n care nodurile execut calcule relativ autonome, iar comunicarea ntre noduri se face dupa tipare predictibile. Un exemplu tipic este cel al simulrii unor circuite, n care funcionarea fiecrei componente este reprezentat de descrierea unui proces.

Autorii acestei clasificri insist asupra faptului c diversele clase nu sunt net difereniate ntre ele. De asemenea, evideniaz c paralelismul de date, considerat de ali autori ca o clas conceptual important, nu este dect o form particular a agendei de activiti. n paralelismul de date, fiecare operaie este aplicat sincron tuturor componentelor unei structuri de date. Asupra acestui subiect vom reveni, artnd n ce mod alegerea unei clase conceptuale influeneaz rezultatul proiectrii. 1.3. Metode de programare Odat stabilit clasa conceptual cea mai potrivit pentru aplicaie, urmeaz proiectarea algoritmului folosind o metod de programare adecvat. n programarea folosind comunicare de mesaje (figura 1.1), fiecare proces ncapsuleaz structurile de date folosite (locale procesului), comunicarea ntre procese fcndu-se prin mesaje. Fiecare proces are acces doar la datele sale locale. Pentru comunicare, procesele includ aciuni explicite de transmitere i recepie de mesaje. Comunicarea de mesaje exprim ntr-un mod natural paralelismul specialist. Fiecare proces este un nod al reelei de specialiti, ntre care comunicarea se face prin mesaje. mesaj

date

proces Figura 1.1

O abordare complet diferit (figura 1.2) ncapsuleaz fiecare proces ntr-un obiect. Procesul este responsabil doar de calculul valorii corespunztoare obiectului respectiv. Mediul exterior este interesat doar n cunoaterea valorii unui obiect, nu i n modul n care ea este calculat. Comunicarea nu se face prin aciuni de transmitere i recepie. Pur i simplu, cnd un proces are nevoie de valoarea produs de un alt proces, el o citete prin acces la obiectul respectiv. Aceste obiecte sunt aa numitele structuri active (vii) de date, sau obiecte active. 5

proces

proces

proces

proces

obiect activ

proces Figura 1.2

Aceast metod exprim bine paralelismul rezultat. Relund exemplul sumei a doi vectori, fiecare obiect poate reprezenta un element S[i] al vectorului suma i poate ncapsula procesul ce calculeaz valoarea sa. ntre cele dou abordri extreme se afl cea la care procesele i datele sunt entiti distincte. Procesele pot comunica prin citirea i scrierea datelor partajate (figura 1.3).

date

procese

Figura 1.3 Aceast metod se potrivete bine cu paralelsimul agenda, datele partajate reprezentnd un mijloc eficient de comunicare ntre procesele master i worker. Tabelul 1.2 arat o coresponden posibil ntre clasele conceptuale i metodele de programare paralel. Ea nu trebuie interpretat rigid. Aa cum pentru o problem de 6

rezolvat, programatorul are la dispoziie modele aparinnd, eventual, unor clase conceptuale diferite, n acelai fel, pentru un model el are la dispoziie mai multe metode de programare. Tabel 1.2 Clase conceptuale Metode de programare rezultat obiecte active agenda de activiti date partajate ansamblu de specialiti comunicare de mesaje 1.4. Clase de sisteme paralele i distribuite n principiu, ar trebui ca efortul de gsire a unor algoritmi paraleli eficieni s nu in seama de particularitile unora sau altora din mainile pe care se face implementarea acestora, ci s caute s exploateze ct mai bine paralelismul inerent problemei studiate. n practic, ns, trebuie avute n vedere detalii de implementare legate de maina, care pot afecta (uneori ntr-o msur important) timpul de execuie. Una din clasificrile clasice adoptate pentru calculatoarele paralele este cea a lui Flynn (1966). Ea consider fluxurile de instruciuni i de date, pentru a distinge ntre urmtorele categorii: SISD -Single Instruction stream Single Data stream (flux unic de instruciuni, flux unic de date); SIMD -Single Instruction stream Multiple Data stream; MISD -Multiple Instruction stream Single Data stream; MIMD -Multiple Instruction stream Multiple Data stream. O alt clasificare, asemntoare precedenteia, consider ca elemente de baz procesoarele i memoria, fcnd distincie ntre urmtoarele categorii de sisteme: tablouri de procesoare (processor array) procesoare n linie de asamblare (pipeline processors) sisteme cu memorie partajat (multi-processors) sisteme cu transmitere de mesaje (distributed systems). Dei exist legturi evidente ntre cele dou clasificri, nu se poate face ntre ele o coresponden unu la unu. Astfel, dei modelul SIMD descrie tabloul de procesoare, el este folosit uneori i pentru procesoare n linie de asamblare. Pentru acestea din urm, modelele SISD i MISD sunt, de asemenea, de multe ori aplicabile. A doua 7

clasificare prezentat este uneori preferat pentru corespondenele directe pe care le are n programare. Reprezentrile grafice asociate modelelor lui Flynn sunt cele din figura 1.4. SISD este modelul von Newmann din anii 40. El nu include, n esen, forme de paralelism, operaiile unui algoritm fiind executate secvenial, de un singur procesor.

P P P

P flux instruct SISD flux date

M M

SIMD

C C C

P P P MISD M

C C C MIMD

P P P

M M M

Figura 1.4 C - Control, P - Procesor, M - Memorie n modelul MISD exist un singur flux de date i mai multe fluxuri de control. n ficare pas, procesoarele au acces la o aceeai dat din memorie, creia i pot aplica tratamente diferite, corespunztoare unor fluxuri de instruciuni diferite. De exemplu, putem stabili dac un numr natural este sau nu prim, ntr-un singur pas, dac exist un numr de procesoare egal cu numrul de divizori poteniali. Mai general, procesoarele pot face operaii diferite asupra unei aceleiai valori: primul poate afla 8

rdcina ptrat, al doilea calculeaz puterea a treia a aceluiai numr, iar un alt procesor afl dac numrul este sau nu prim. Spre deosebire de modelele la care ne vom referi n continuare, MISD este mai rigid i are o utilitate practic foarte restrans. Un tablou de procesoare (figura 1.5) const dintr-un numr de procesoare identice, aflate sub controlul unei singure uniti de comand. Fiecare procesor are acces separat la datele sale locale, astfel nct, la un moment dat, o aceeai operaie este executat simultan asupra mai multor uniti de date. Acest mod de lucru sincron este tipic tablourilor de procesoare. n mod natural, operaiile caracteristice sunt cele matriceale. Aa cum s-a menionat, fiecare procesor are propria sa memorie local. Pentru actualizarea ei este necesar comunicarea cu celelalte procesoare sau cu un calculator gazd. Comunicarea poate fi realizat n dou moduri, de unde rezult dou clase de sisteme SIMD: prin memorie partajat (SM - shared memory - SIMD) i prin reea de interconectare. Unitate de control

P M Figura 1.5

P M

P M

Primele sisteme, cunoscute i sub numele de PRAM (Parallel Random - Access Machine), au diferite variante, dup cum accesele la aceeai locaie de memorie pentru citire sau scriere sunt concurente sau exclusive. Evident c performanele algoritmilor sunt influenate de acest aspect, aa cum rezult i din exemplul urmtor, care se refer la o problem de cutare. Fie un fiier cu n intrri, unde n este foarte mare. Dndu-se o valoare oarecare a, se cere s se precizeze dac ea este n fiier. Considerm c fiierul este mprit n N 9

sub-fiiere, fiecare sub-fiier Si, de dimensiune n/N, fiind accesibil unui procesor Pi distinct (sunt deci N procesoare P1, ..., PN). Fiecare procesor Pi citete valoarea lui a, caut aceast valoare n sub-fiierul Si i, n caz de succes, seteaz valoarea unei variabile rezultat R. Problema poate fi rezolvat n n/N pai. Condiia este ns ca accesul la valoarea lui a pentru citire s fie concurent. n plus, dac fiierul nu are nregistrri distincte, este necesar ca i accesul la scriere pentru R s fie concurent. Dac prima condiie nu este ndeplinit, valoarea lui a trebuie difuzat explicit tuturor proceselor. Difuzarea se poate face astfel: - P1 citete valoarea lui a i o comunic lui P2; - P1 i P2 comunic simultan valoarea lui a ctre P3 i P4; - simultan, P1, P2, P3 i P4 comunic valoarea lui a ctre P5, P6, P7 i P8 .a.m.d. Deoarece numrul de procese care cunosc valoarea lui a se dubleaz la fiecare pas, rezult c difuzarea dureaz log2 N pai. ntregul algoritm reclam deci log N + n/N pai n cazul cel mai defavorabil. Exist i variante de terminare a algoritmului imediat ce un procesor a regsit valoarea lui a n sub-fiierul corespunztor. n acest caz valoarea rspunsului R trebuie difuzat celorlalte procese. De data aceasta, valoarea rezultatului este inspectat de fiecare proces, nainte de a continua cutarea n propriul fiier, ceea ce conduce la un total de log N + (n/N).log N pai n cazul cel mai defavorabil. n privina sistemelor SIMD interconectate n reea, topologiile uzuale sunt mai simple dect graful complet. Prezentm cteva variante: a) tabloul uni-dimensional b) tabloul bi-dimensional c) arbore binar complet d) amestecare perfect (perfect shuffle) - date fiind N procesoare P0, ..., PN-1, cu N o putere a lui 2, Pi i Pj sunt legate printr-o linie uni-direcional, unde j = 2.i pentru 0 <= i <= N/2-1 j = 2.i-N+1 pentru N/2 <= i <= N-1. Adesea, fiecare procesor cu numr par este legat prin conexiune bi-direcional cu succesorul su. Pentru N=8, se obine configuraia din figura 1.6.

10

P0

P1

P2

P3

P4 Figura 1.6

P5

P6

P7

e) cub f) hipercub. Alegerea unei configuraii depinde de aplicaie, de performanele dorite i de numrul procesoarelor disponibile. Astfel, pentru suma a n numere, o topologie avantajoas este arborele cu n/2 frunze i log n nivele. Operaia se realizeaz n log n pai (vezi figura 1.7). X0 X1 X2 X3 X4 X5 X6 X7 X0+X1 X0+X1+X2+X3

X2+X3 X4+X5 X4+X5+X6+X7 X6+X7 Figura 1.7

Suma

n cazul a m grupuri de cte n numere, sumele pot fi aflate n log n + m - 1 pai, folosind tehnica liniei de asamblare (pipeline), la care ne referim ceva mai departe n aceast seciune. Exemplele de sisteme SIMD includ mai multe modele comerciale, dintre care cele mai cunoscute sunt CM-2 produs de Thinking Machines i MP-2 produs de Maspar. Din pcate, nici unul din aceste modele (care se bazeaz pe matrice de procesoare) nu a cunoscut succesul de pia. n schimb, mai larg acceptate au fost sistemele vectoriale, dintre care modelele Cray-1, C90 i T90 au dominat domeniul calculului tiinific. 11

Exemple de limbaje de programare: DAP-FORTRAN, Actus (bazat pe Pascal), CMLISP (Connection Machine Lisp). Caracteristicile sistemelor se reflect la nivelul limbajelor. Astfel, pentru FORTRAN, tablourile sunt tratate ca tipuri fundamentale, cu operatori specifici operaiilor matriceale. Prelucrarea n linie de asamblare este un principiu utilizat n multe fabrici i este mprumutat n sistemele de calcul. Ideea este de a mpri o prelucrare n mai multe procese care se deruleaz unul dup altul i se execut fiecare pe un procesor aparte. Fiecare proces depinde de rezultatul procesului precedent din secven i furnizeaz rezultate procesului urmtor. Dac este necesar efectuarea mai multor prelucrri, atunci, derularea lor poate avea loc n paralel: n timp ce procesorul i execut un proces, procesorul i-1 execut procesul i-1 din prelucrarea ce urmeaz, iar procesorul i+1 execut procesul i+1 din prelucrarea precedent. S considerm calculul urmtor:
for i:=1 to 64 do begin E[i]:=A[i]+B[i]; F[i]:=E[i]*C[i]; G[i]:=F[i]-D[i] end

executat pe trei procesoare specializate pentru operaiile de adunare, nmulire i respectiv scdere. Derularea n timp a operaiilor, n condiiile unei prelucrri n linie de asamblare la nivelul instruciunilor poate fi cea din figura 1.8. E[I]:= F[I]:= G[I]:= t 1 1 2 1 2 3 2 1 3 4 3 2 4 4 3 5 n n-1 n-2 n n n-1 n+1

n N+2

Figura 1.8 O clasificare a sistemelor cu prelucrare n linie de asamblare ine cont de nivelul de complexitate al proceselor, care poate fi: al operaiilor aritmetice (faze de instruciune) al instruciunilor 12

al programelor.

Clasa cea mai general este cea a sistemelor MIMD. i aici ntlnim cele dou variante de comunicare: prin memorie partajat (sisteme multiprocesoare) i prin transmitere de mesaje (sisteme multicalculatoare). Un sistem cu memorie partajat (figura 1.9) const din mai multe procesoare care au acces la module de memorie comun (sisteme multiprocesor). Procesoarele pot executa procese diferite, dar care trebuie corelate ntre ele (sincronizate) pentru a evita interferenele (i deci erorile de prelucrare). Numeroase modele au fost propuse pentru programarea acestor sisteme. Dintre ele, amintim: primitivele P si V, regiunile critice, monitoarele. M M M

Interconexiune rapid

P Figura 1.9

Exist destul de multe sisteme experimentale care se nscriu n aceast categorie. Dintre cele comerciale mai recente, amintim Sun Enterprise 10000, care este un sistem din categoria UMA (Uniform Memory Access) pentru care procesoarele au acelai timp de acces la oricare modul de memorie. Configuraia maxim a unui sistem include 64 de procesoare UltraSPARC distribuite n 16 grupuri a cte 4 procesoare. Fiecare grup este dispus pe o plac mpreun cu 4 module de memorie RAM de cte 1 GB fiecare. Conexiunea ntre procesoare i blocurile de memorie este asigurat de un switch crossbar 16*16, numit Gigaplane-XB. Acesta are funcia de a transfera datele ntre memorie i cache-urile procesoarelor. Transferul se face pe 16 octei, astfel c sunt necesare 4 cicluri pentru a transfera o line de cache care are 64 octei. n afara switch-ului, mai exist patru magistrale de adrese care sunt folosite pentru supraveghere (snooping). Fiecare bus este folosit pentru o ptrime din spaiul de adrese fizice, astfel c pentru selecia unei magistrale din patru sunt folosii doi bii 13

de adres. Cnd un procesor nu gsete datele n propria memorie cache el plaseaz adresa pe magistrala de adrese corespunztoare pentru a vedea dac datele sunt n memoria cache a altui procesor. Toate grupurile de procesoare inspectreaz toate cele patru magistrale. Cea care are datele cerute le furnizeaz imediat. Dac nu exist rspuns, datele nu exist n cache i trebuie aduse din memorie. Uneori, memoria partajat este distribuit, astfel nct exist um modul de memorie mai apropiat de fiecare procesor. Accesul la acest modul este mai rapid pentru un procesor i mai lent pentru celelalte. Din acest motiv, modelul se mai numete NUMA (Non Uniform Memory Access). Pentru a scurta timpul de acces, unele sisteme pstreaz o parte a datelor n memoriile cache ale procesoarelor, care, evident trebuie pstrate coerente (ccNUMA - cache coherent NUMA). Aceste sisteme se mai numesc sisteme cu memorie distribuit, alteori sisteme cu memorie local (figura 1.10). Exemple de sisteme ccNUMA includ SGI Origin 2000 i Sequent NUMA-Q 2000. Reea de comunicaie

P M

P M Figura 1.10

P M

Sistemele cu transmitere de mesaje (se mai numesc multicalculatoare) constau din calculatoare interconectate. Procesoarele execut procese diferite, iar sincronizarea este realizat prin schimburi de mesaje. Diferenele ntre sisteme se manifest prin: comunicare sincron sau asincron de mesaje schema de comunicare -direct de la proces la proces -prin cutii potale globale -prin canale de legtur ntre procese Exist dou categorii de multicalculatoare. Prima categorie, cunoscut sub denumirea de MPP, Massively Parallel Processors, include sisteme n care procesoarele (n numr ridicat) sunt interconectate prin reele de mare vitez, construite special ca 14

soluii de firm, pentru a realiza performane foarte ridicate. Exemple de sisteme din aceast categorie sunt: Cray T3E i IBM SP-2. A doua categorie include sisteme construite din PC-uri sau staii de lucru interconectate prin reele comerciale. Astfel de sisteme se numesc NOW (Networks Of Workstations) sau COW (Clusters Of Workstations). Un exemplu de aplicaie pentru multi-calculatoare este jocul de ah, n care se genereaz mutrile posibile, a cror mulime poate fi organizat arborescent: rdcina este configuraia curent; fiii si corespund configuraiilor dup prima mutare .a.m.d. Gsirea mai rapid a celei mai bune mutri se poate face distribuind unor procesoare distincte cutarea n sub-arbori diferii. Comunicarea ntre procesoare este necesar pentru transmiterea celei mai bune soluii gsite pn la un anumit moment i pentru transmiterea unor sub-arbori n vederea continurii inspectrii. La un moment dat, dou procesoare distincte pot executa secvene diferite de instruciuni, ceea ce este n concordan cu caracteristicile sistemelor MIMD.

15

Capitolul 2. Limbajul de descriere a algoritmilor


n accepiunea noastr un program concurent este o colecie de procese paralele comunicante. Exis mai multe categorii de programe concurente, delimitate n funcie de raportul dintre procese i procesoarele pe care acestea se execut. n programele paralele, procesele sunt executate de procesoare distincte care comunic prin variabile partajate aflate n memoria comun. Uneori, organizarea unui program ca o colecie de procese este util chiar n cazul n care acestea se execut pe un singur procesor, intercalat. Fiecare proces poate fi planificat i executat independent de celelalte, existnd practic mai multe fire de execuie (threads) n acelai program multithread. Noiunea de program multithread se extinde i la situaia n care numrul de procese dintr-un program este mai mare ca numrul de procesoare pe care acestea se pot executa. n programele distribuite, procesele se execut pe maini interconectate printr-o reea de calculatoare i, ca urmare, comunic prin schimb de mesaje. Dei exist multe posibiliti de a structura colecia de procese dintr-un program concurent, s-au impus cteva tipare: paralelismul iterativ, paralelismul recursiv, productori i consumatori, clieni i servere, procese egale (interacting peers). Ne vom referi la acestea pe parcursul prezentrii limbajului de descriere a algoritmilor i a unor exemple semnificative. n mod natural, descrierea adoptat pentru programele paralele se ncadreaz n modelul CSP (Communicating Sequential Processes) propus de Hoare. Ea se bazeaz pe construciile clasice ale unui limbaj de programare secvential, extinse cu notaiile ce permit concurena, comunicarea i sincronizarea. n plus, deoarece comenzile cu gard (Dijkstra 1975) introduc nedeterminismul n programarea secvenial, cu efecte asupra calitii reprezentrii programelor, ele sunt adoptate ca elemente constitutive ale deciziilor i ciclurilor. Prezentm la nceput notaiile (pseudocod) corespunztoare descrierii algoritmilor secveniali. n seciunile urmtoare vom introduce construcii specifice programrii paralele (bazate pe variabile partajate i comunicare de mesaje).

16

2.1. Declaraii Tipuri de baz sunt considerate urmtoarele: boolean bool ntreg int real real caracter char ir string enumerat. Declaraia variabilelor are forma general var id1 : tip1 := val1; ... ; idn : tipn := valn; unde iniializrile sunt opionale. Definiiile de constante au forma general const id1 = val1; ... ; idn = valn; Tablourile se declar prin specificarea tipului indicilor i a tipului de baz; uzual, indicele este de tip subdomeniu. Notaia a..b obinuit este nlocuit cu a:b acolo unde elementele tabloului pot fi prelucrate n paralel. Exemplu: var vector: array [1:10] of int; matrice: array [1:n,1:m] of real; Dac vector este un tablou unidimensional, folosim notaia vector[1:5] pentru a desemna primele cinci elemente ale sale (n general, o seciune contigu dintr-un tablou). Similar, folosim un constructor de tablou, ca n exemplul urmtor var forks: array [1:5] of bool := ([5]false); n care se declar tabloul forks i se iniializeaz toate elementele cu valoarea false. O nregistrare se definete ca o colecie de cmpuri cu tipuri potenial diferite. Exemple: type student = rec ( nume : string[20]; virsta : int; clase : array [1:5] of string[15]); var queue: rec ( front : int :=1; rear : int :=1; size : int :=0; contents : array [1:n] of int);
17

2.2. Instruciuni skip este instruciune inoperant. Execuia ei se termin imediat i nu are nici un efect asupra variabilelor programului. Se folosete n comenzile cu gard i n await. Atribuirea x:=e evalueaz expresia e i asociaz rezultatul variabilei x. Aceasta poate fi un scalar, un tablou, o nregistrare, un element de tablou, un cmp de nregistrare. Interschimbarea x1:=:x2 interschimb valorile celor dou variabile. Instruciunea compus este o secven de instruciuni. Nu exist o notaie special pentru ea. Comanda cu gard are forma general B -> S unde B este o expresie boolean S este o instruciune (simpl sau compus). S nu poate fi executat dac B nu este true. Selecia (if) are forma general if B1 -> S1 [] B2 -> S2 ... [] Bn -> Sn fi Grzile sunt evaluate ntr-o ordine arbitrar. Dac Bi este true atunci se execut Si. Cu alte cuvinte, dac mai multe grzi sunt true, alegerea instruciunii executate este nedeterminist. Iteraia (do) are forma general do B1 -> S1 [] B2 -> S2 ... [] Bn -> Sn
18

od Grzile sunt evaluate ntr-o ordine arbitrar. Dac una dintre ele, Bi este true atunci se execut Si, dup care se repet procesul de evaluare. Execuia lui do se termin atunci cnd nici o gard nu este true. Ciclul cu contor (fa) are forma general fa cuantificatori -> instruciuni af Fiecare cuantificator specific un domeniu de valori pentru o variabil contor (de tip implicit int): variabila := val_init to val_finala st B Corpul ciclului este executat o dat pentru fiecare valoare a variabilei contor, dac valoarea expresiei booleene B este true (such that B). n cazul mai multor cuantificatori, acetia se separ prin virgule. Corpul ciclului se execut pentru fiecare combinaie de valori ale variabilelor contor, cu variabila cea mai din dreapta variind cel mai rapid. Exemple: 1) transpunerea matricei m: fa i:=1 to n, j:=i+1 to n -> m[i,j]:=:m[j,i] af 2) ordonarea cresctoare a unui vector: fa i:=1 to n, j:=i+1 to n st a[i]>a[j] ->a[i]:=:a[j] af 2.3. Proceduri O procedur definete un tipar parametrizat al unei operaii. Forma sa general este urmtoarea: procedure p(f1 : t1; ...; fn : tn) returns r : tr; declaraii instruciuni
19

end; unde p este numele procedurii fi sunt parametrii formali cu tipurile ti r este numele valorii ntoarse i are tipul tr. Partea returns este opional.

O procedur fr returns este apelat explicit prin instruciunea call: call p(e1,...,en) n timp ce o funcie (cu returns) apare ca opernd ntr-o expresie: x := p(e1,...,en). n ambele cazuri, ei sunt expresii, avnd acelai tip cu parametrii formali corespunztori. Transmiterea parametrilor se poate face prin valoare (cazul implicit) sau prin referin (parametrul respectiv trebuie calificat cu var i are drept corespondent un parametru efectiv variabil). Exemplu: calculul factorialului.
procedure fact(i : int) returns f: int; if i<0 -> f:=-1 [] i=0 or i=1 -> f:=1 [] i>1 -> f: = i*fact(i-1) fi end;

2.4. Concuren i sincronizare n accepiunea noastr, un program paralel descrie dou sau mai multe procese cooperante. Ca urmare, dac la execuia unui program secvenial exist un singur fir al controlului (thread of control), la cea a unui program paralel exist mai multe fire, cte unul pentru fiecare proces. Fie Si un program secvenial (declaraii + instruciuni). Construcia: co S1 // S2 // ... // Sn oc specific execuia paralel a programelor S1 ... Sn, efectul fiind o anumit ntreesere a aciunilor lor atomice. Execuia lui co se termin atunci cnd se termin execuia fiecrui Si. Exemplu: x:=0; y:=0; co x:= x+1 // y:=y+1 oc
20

z:=x+y; Variabilele declarate nainte de co sunt comune proceselor din co. Procesele pot declara i variabile locale, domeniul unei astfel de variabile fiind procesul n care apare declaraia. Adesea, un program paralel conine procese care execut acelai calcul asupra unor elemente de tablou diferite. Descrierea se poate face folosind cuantificatori la fel ca pentru instruciunea fa. Exemplu: co j:=1 to n -> a[j]:=0 oc Fiecare proces are o copie proprie a lui j, care se comport n cadrul procesului ca o constant. Construcia precedent descrie n procese distincte. Exemplu: nmulirea a dou matrice:
var a, b, c: array [1:n, 1:n] of real; co i:=1 to n , j:=1 to n -> var sum: real := 0; fa k:=1 to n -> sum := sum+a[i,k]*b[k,j] af; c[i,j] := sum oc

Aici sunt n2 procese, fiecare avnd constantele locale i i j, precum i variabilele locale sum i k. n cazul unor procese cu descrieri lungi, se folosete i urmtoarea form, n care se asociaz nume proceselor paralele coninute de un program. Exemplu
var a, b, c: array [1:n, 1:n] of real; co Prod(i:1..n, j:1..n):: var sum : real := 0; fa k:=1 to n -> sum:=sum+a[i,k]*b[k,j] af c[i,j]:=sum oc

2.5. Atomicitatea i sincronizarea Aa cum s-a precizat, execuia unui program paralel poate fi privit ca o ntreesere a aciunilor atomice ale proceselor. Cnd procesele interacioneaz, nu toate combinaiile sunt acceptabile. De exemplu, s considerm urmtorul program i s
21

lum ca aciuni atomice citirea i scrierea unei variabile:


y:= 0 ; z:= 0 ; co x:=y+z // y:=1 ; z:=2 oc

Dac adunarea este realizat prin ncrcarea valorii lui y ntr-un registru i adugarea ulterioar a valorii lui z, valoarea lui x poate fi 0, 1, 2, sau 3, n funcie de vitezele celor dou procese. La prima vedere, evaluarea unei expresii nu poate fi considerat aciune atomic n context paralel, dect dac variabilele din expresie nu sunt alterate de alte procese. In realitate, atomicitatea este asigurat de o condiie mai slab, numit proprietatea cel-mult-o-dat (at-most-once), care se formuleaz astfel: O expresie e satisface proprietatea de cel-mult-o-dat dac ea se refer cel mult o dat la cel mult o variabil simpl (element de tablou sau cmp de nregistare) care ar putea fi schimbat de un alt proces n timpul evalurii lui e. O instruciune de atribuire x:= e satisface proprietatea de cel-mult-o-dat fie dac e satisface aceast proprietate i x nu este citit de un alt proces (adic x este o variabil local), ori dac x este o variabil simpl i e nu se refer la nici o variabil care ar putea fi schimbat de un alt proces. De exemplu, nici o atribuire din construcia: co x := y+1 // y := x+1 oc nu satisface proprietatea menionat. De asemenea, atribuirea x := y+z din exemplul dat la nceputul seciunii nu satisface aceast proprietate, ea referind dou variabile modificate de un alt proces. n cazurile cnd proprietatea anterioar nu este satisfacut, sau dac dorim gruparea mai multor aciuni ntr-o singur aciune atomic de granularitate mai mare, este necesar un mecanism de sincronizare. Pentru a specifica aciuni atomice folosim paranteze unghiulare. De exemplu, <e> nseamn c expresia e trebuie evaluat atomic. Pentru sincronizare, folosim construcia: <await B -> S> unde B este o expresie boolean, iar S este o succesiune de instruciuni (secveniale) care se termin cu siguran.
22

Semnificaia este urmtoarea: se ateapt ndeplinirea condiiei B, dup care se execut S. Execuia este atomic, deci B este cu siguran true la nceperea execuiei lui S i nici o stare intern a lui S nu este vizibil din afar. Exemplu: <await s>0 -> s:=s-1> ntrzie procesul executat pn cnd s devine pozitiv, apoi decrementez pe s. Forma general a instruciunii await specific att excluderea mutual, ct i sincronizarea condiionat. Ea admite formele : <s> pentru a exprima doar excluderea mutual i <await B> pentru a exprima doar sincronizarea condiionat. Exemplu. Programul productor-consumator.
var buf: int, p: int :=0, c:int :=0; co Productor:: var a: array[1:n] of int; do p<n -> <await p=c>; buf := a[p+1]; p := p+1 od Consumator:: var b: array [1:n] of int; do c<n -> <await p>c>; b[c+1] := buf; c := c+1 od oc

Observaii: aciunile atomice se rezum la testele condiiilor, fr a cuprinde i celelalte aciuni asupra variabilelor comune. Sugerm cititorului s ncerce gsirea unei justificri neformale a corectitudinii soluiei. Problem. Elaborai o soluie pentru comunicare printr-un tampon limitat, buf[1:k], cu 1 < k < n. Sincronizarea prin await, dei general, este criticat din motive legate att de claritatea descrierilor rezultate, ct i de eficiena posibilelor implementri: - conduce uneori la soluii complicate, greu de neles i de demonstrat; - nu face o separare clar ntre variabilele utilizate pentru sincronizare i cele folosite pentru rezultatele calculelor; - tehnica de implementare a acestei sincronizri (numit busy waiting - ateptare activ) este ineficient, fiecare proces testnd continuu condiia din await pn cnd
23

aceasta devine adevrat. Nu este, deci, de mirare c s-au cutat mecanisme de sincronizare care s nlture neajunsurile menionate (semafoare, regiuni critice, monitoare, bariere, comunicare de mesaje). Dintre acestea, ne referim n continuare la bariere de sincronizare i la comunicarea prin mesaje, des utilizate n exprimarea algoritmilor paraleli. 2.6. Bariere de sincronizare Barierele reprezint un mecanism de sincronizare asociat unei clase de paralelism numit paralelism de date. Corespondentul arhitectural al acesteia l constituie modelul SIMD. Un algoritm pentru paralelism de date este un algoritm iterativ care prelucreaz n paralel i n mod repetat elementele unui tablou. Acest gen de algoritmi este n mod natural asociat modelului SIMD. El este ns util i n cazul multiprocesoarelor asincrone. Un atribut important al algoritmilor iterativi paraleli este c fiecare iteraie depinde (n general) de rezultatul iteraiei precedente. O variant este s se organizeze fiecare iteraie ca o colecie de procese paralele:
do true -> co k := 1 to n -> cod_proces-k oc od

Soluia este ineficient deoarece creeaz i distruge procese la fiecare iteraie. O a doua soluie, mai eficient, creeaz procesele o singur dat, fcnd sincronizarea lor la trecerea de la o iteraie la alta:
co Proces(i: 1..n):: do true -> cod_proces_i asteapta terminarea tuturor proceselor od oc

Acest tip de sincronizare se numete barier. Pentru a da algoritmilor o form general, utilizm o notaie explicit pentru marcarea barierelor, i anume barrier. Menionm ns c sistemele SIMD asigur prin construcie sincronizarea i elimin necesitatea programrii explicite a barierelor. n
24

cele ce urmeaz, prezentm soluiile unor probleme tipice paralelismului de date. 2.7. Aplicaii folosind paralelismul de date 2.7.1. Operaii cu vectori

din categoria

Considerm n continuare calculul paralel al sumelor tuturor prefixelor unui tablou linear. Mai precis, dat fiind tabloul a[1:n], calculm s[1:n], unde s[i] este suma primelor i elemente ale tabloului a. Soluia secvenial uzual este urmtoarea: s[1] := a[1]; fa i := 2 to n -> s[i] := a[i] + s[i-1] af Pentru a obine o paralelizare a acestei soluii, s considerm mai nti problema simplificat a calculului sumei tuturor elementelor unui tablou. n acest scop, am putea nsuma la nceput elementele tabloului dou cte dou. n etapa urmtoare, nsumm rezultatle obinute tot dou cte dou i aa mai departe. Un exemplu, pentru un tablou cu 8 elemente este dat n figura 2.1.

Figura 2.1 Nu este greu de vzut c putem calcula suma elementelor n log2 n pai, folosind n-1 procesoare. Pentru sumele prefixelor, adaptm aceast soluie, bazat pe ideea dublrii, la fiecare pas, a numrului elementelor ce au fost nsumate. n acest scop, prezentm mai nti o schem modificat a nsumrii tuturor elementelor, care permite deducerea mai simpl a algoritmului paralel. a1 a2 a3 a4 a5 a6
25

a7

a8

+---- +---- +---- +---- a1 s12 a3 s34 a5 s56 a7 s78 +-------- +-------- a1 s12 a3 s14 a5 s56 a7 s58 +------------------ a1 s12 a3 s14 a5 s56 a7 s18 Figura 2.2
var a: array [1:n] of int; co suma (k:1..n):: fa j := 1 to sup(log2 n) -> if k mod 2j = 0 -> a[k] := a[k-2j-1] + a[k] fi barrier af oc

Din pcate, aceast soluie este aplicabil doar dac numrul elementelor tabloului este o putere a lui 2. n caz contrar, putem aduga un numr corespunztor de elemente nule. O alt soluie pleac de la observaia c n algoritmul de nsumare, numrul de procesoare folosite efectiv se njumtete la fiecare pas, tot mai multe procesoare rmnnd libere, Dac folosim aceste procesoare putem ajunge la o soluie general, valabil pentru un numr oarecare de elemente. n acest scop, ncercm s utilizm fiecare procesor la fel ca celelalte: la fiecare pas j, valorii pariale a[k] i se adaug valoarea elementului din poziia k-2j-1, dac aceasta exist. Pentru un tablou cu ase elemente, obinem schema din figura 2.3.

26

a1 s11 s11 s11

a2 s 12 s12 s12

a3 s 23 s 13 s 13

a4 s 34 s 14 s 14

a5 s45 s25 s15

a6 s56 s36 s16

Figura 2.3 Soluia obinut ar avea urmtoarea descriere:


var a: array [1:n] of int; co suma(k:1..n):: fa j := 1 to sup(log2 n) -> if k-2j-1>=1 -> a[k] := a[k-2j-1] + a[k] fi barrier af oc

Dei algoritmul pare satisfctor, el ascunde o potenial eroare de sincronizare. S observm c, la fiecare ciclu, procesele actualizeaz valorile pariale a[k]. Pentru un calcul corect, ar trebui ca toate procesele s execute simultan operaiile de adunare i apoi toate s fac atribuirile. Deoarece acest lucru impune introducerea unei noi bariere ntre adunare i atribuire, cele dou aciuni trebuie desprite. Acest lucru este posibil prin introducerea unui tablou temp, folosit ca depozitar temporar al vechilor valori ale tabloului a. Soluia devine urmtoarea:
var a, temp: array [1:n] of int; co suma(k:1..n):: fa j := 1 to sup(log2 n) -> temp[k] := a[k]; barrier if k-2j-1>=1 -> a[k] := temp[k-2j-1] + a[k] fi barrier af oc

n fine, putem evita operaiile de logaritmare i de ridicare la putere, prin utilizarea unei variabile d care pstreaz distana fa de poziia elementului k, la care se afl elementul cu care acesta se combin:
27

var a, temp: array [1:n] of int; co suma(k:1..n):: var d := 1; do d<n -> temp[k] := a[k]; barrier if k-d>=1 -> a[k] := temp[k-d] + a[k] fi barrier d := 2*d od oc

Problem. Ce modificri trebuie aduse algoritmului pentru a face temp local fiecrui proces? Putem face dou observaii importante: - n forma final, algoritmul calculeaz toate sumele prefix; - algoritmul poate fi folosit pentru orice operaie binar asociativ: nmulirea, maxim, minim, sau logic, i logic, sau-exclusiv etc. Completarea limbajului de descriere a algoritmilor Avnd n vedere c in algoritmii SIMD toate aciunile sunt sincronizate (deci orice aciune ar trebui urmat de o barier), adoptm o notaie simplificat pentru descrierea lor. Astfel, pentru execuia mai multor pai n acelai timp folosim notaia do steps i to j in parallel step i step i+1 ... step j od iar pentru execuia simultan a aceleiai operaii de mai multe procesoare folosim notaia fa i := j to k do in parallel operaiile lui Pi af
28

sau fa i := r, s, ...t do in paralel operaiile lui Pi af sau fa i in S do in paralel operaiile lui Pi af Cu aceste notaii, calculul sumelor prefix poate fi reprezentat n modul urmtor:
var a: array [1:n] of int; fa k := 1 to n do in parallel (Procesor Pk) var temp: int; /* variabile locale procesorului k */ var d := 1; do d<n -> if k-d >=1 -> temp := a[k-d]; a[k] := temp + a[k] fi d := 2*d od af

O alt variant se poate obine prin interschimbarea celor dou cicluri, deci ignornd ntrzierile de planificare a proceselor pe procesoare (aici fiecare procesor execut un singur proces).
var A: array [1:N] of real; fa j := 0 to log N - 1 do fa k := 2j+1 to N do in parallel (Procesor Pk) var t: real; /* t este locala procesorului k */ 1. t := A[k-2j]; 2. A[k] := t + A[k] af af

Observaii - aceast variant evideniaz, mai bine dect precedenta, procesoarele active n fiecare faz a algoritmului;
29

- Aciunile de citire i de scriere relative la memoria comun sunt specificate distinct n algoritm, iar paii executai sincron de procesoare sunt foarte bine precizai; - Deoarece numrul procesoarelor care termin de calculat suma parial se dubleaz la fiecare pas, calculul se face n O(log N) pai folosind O(N) procesoare. - Dimensiunea tabloului A poate fi redusa la N/2, valorile memorate n ultimul pas fiind inutile. - Utilizare tipic: difuzarea lui n, n cazul algoritmilor adaptivi. Difuzarea unei valori O operaie frecvent n algoritmii paraleli este cea de difuzare a unei valori tuturor procesoarelor unui sistem. Fie D celula din memoria comun ce trebuie difuzat celor N procesoare ale unui sistem EREW SIMD. Algoritmul urmtor presupune folosirea pentru difuzare a unui tablou A[1:N].
Pas 1: (Procesorul P1) var t: real; /* t este local procesorului 1 */ 1.1. t := D; 1.2. A[1] := t; Pas 2: fa i = 0 to (log N -1) do fa j = 2i+1 to 2i+1 do in parallel (Procesor Pj) var t: real; /* t este local procesorului j */ 2.1. t := A[j-2i] 2.3. A[j] := t; af af

2.7.2. Operaii cu liste Organizarea arborescent a datelor este mult utilizat pentru motivul c ea conduce la algoritmi de inserare i cutare avnd complexitate sup(log n). Folosirea paralelismului de date permite atingerea unei performane similare chiar i pentru structuri lineare cum sunt listele. Prezentm n continuare algoritmul de gsire a sfritului unei liste simplu nlnuite. Metoda poate fi aplicat i altor operaii, cum ar fi: sumele pariale ale valorilor elementelor din list, inserarea unui element ntr-o list de prioriti, punerea n coresponden a dou liste. Considerm o list de pn la n elemente, pstrate ntr-un tablou data[1:n], legturile
30

ntre elemente fiind pstrate ntr-un tablou distinct, leg[1:n]. Capul listei este pstrat ntr-un element separat, cap. Dac un element i face parte din list, atunci fie cap = i, fie exist un alt element j, cuprins ntre 1 i n, astfel nct leg[j] = i. Legatura ultimului element al listei este 0. De asemenea, leg[k] = 0 dac elementul corespunztor nu face parte din list.

cap

Figura 2.4 Algoritmul secvenial standard pornete din capul listei i parcurge legturile ntre elemente, pn atinge sfritul listei. De aceea, timpul de execuie este proporional cu numrul de elemente. n varianta paralel, folosind tehnica "dublrii" din algoritmul sumelor prefixelor, putem aduce timpul la sup(log n). n acest scop, folosim un tablou end[1:n], i dedicm un proces separat, Afla(i), pentru calculul fiecrui element end[i], al acestui tablou. Presupunem c lista conine cel puin dou elemente. Iniial, fiecare proces poziioneaz end[i] la valoarea lui leg[i]. Valoarea end[i] este actualizat n mod repetat. La fiecare ciclu, dac end[i] i end[end[i]] sunt ambele diferite de 0, atunci Afla(i) seteaz end[i] la valoarea end[end[i]]. Astfel, dup un ciclu, legturile din end indic elemente aflate la dou legturi distan fa de elementele curente, dup dou cicluri pe cele aflate la patru legturi distan etc. Dup sup(log n) pai, toate elementele vor indica sfritul listei. Algoritmul este urmtorul:
var leg, end: array [1:n] of int; co Afla (i:1..n):: var nou: int; d:int:=1; end[i] := leg[i]; barrier do d<n -> nou := 0; if end[i]<>0 and end[end[i]]<>0 -> nou:=end[end[i]] fi barrier if nou<>0 -> end[i]:=nou fi barrier d := 2*d od oc 31

n varianta SIMD dispar barierele, iar ciclul i decizia se contopesc.


var leg, end: array [1:n] of int; fa i:1 to n do in parallel end[i] := leg[i]; do end[i]<>0 and end[end[i]]<>0 -> end[i] :=end[end[i]] od af

Observaie. Algoritmul se poate aplica i pentru gsirea rdcinilor unei pduri de arbori dirijai. Variant. Considerm c pentru fiecare nod i, leg[i] indic printele nodului, ntr-un arbore al pdurii. De asemenea, dac r este rdcina atunci leg[r] = r. n aceste condiii, algoritmul devine:
var leg, end: array [1:n] of int; fa i:1 to n do in parallel end[i] := leg[i]; do end[i]<> end[end[i]] -> end[i] :=end[end[i]] od af

Combinaie sume prefix - pointer jumping. Considerm c fiecrui nod i, i se asociaz o pondere w[i]. Putem calcula, pentru fiecare i, suma ponderilor nodurilor aflate pe calea de la nodul i la rdcina arborelui din care face parte. Se d condiia w[r] = 0 pentru orice rdcin r.
var leg, end, w: array [1:n] of int; fa i:1 to n do in parallel end[i] := leg[i]; do end[i]<> end[end[i]] -> w[i] := w[i] + w[end[i]]; end[i] :=end[end[i]] od af

Probleme - Calculul sumelor pariale ale elementelor unei liste nlnuite.


32

- Punerea n coresponden a elementelor a dou liste. Algoritmul asociaz fiecrui element al unei liste un pointer ctre "prietenul" su din cealalt list. Complexitatea cerut este logaritmic. - Algoritmul de calcul al sfritului unei liste simplu nlnuite, n varianta n care lista poate avea mai puin de dou elemente. 2.7.3. Operaii cu matrice n multe aplicaii, ca prelucrarea imaginilor sau rezolvarea ecuaiilor difereniale, se utilizeaz operaii asupra unor structuri matriceale sau de graf, numite calcule gril sau calcule plas. n grafic, ideea este de a utiliza o matrice care corespunde valorilor pixelilor. n rezolvarea unor ecuaii difereniale, elementele de la exteriorul matricei sunt iniializate cu valorile de grani, scopul fiind gsirea valorilor elementelor din mijloc, ceea ce corespunde gsirii unei soluii stabile a ecuaiei. n ambele cazuri, tiparul prelucrrior este urmtorul: iniializeaz matricea do neterminat -> calculeaz o nou valoare pentru fiecare punct evalueaz terminarea od La fiecare iteraie, noile valori ale punctelor sunt calculate n paralel. Pentru exemplificare, considerm o soluie a ecuaiei lui Laplace (2() = 0) n dou dimensiuni. Fie grila[0:n+1, 0:n+1] o matrice de puncte. Putem utiliza n calcul o metod cu diferene finite (de exemplu, Jacobi). La fiecare iteraie, calculm o valoare a fiecrui punct interior ca media aritmetic a celor patru vecini cei mai apropiai. Metoda este staionar, astfel c putem termina iteraiile atunci cnd noile valori pentru punctele interioare difer cu mai puin de EPS de valorile anterioare.
var grila, noua: array [0:n+1, 0:n+1] of real; var converge: boolean := false; co CalculGrila(i:1..n, j:1..n):: do not converge -> noua[i,j] := (grila[i-1,j]+grila[i+1,j]+grila[i,j-1]+ grila[i,j+1])/4; barrier test_convergenta; 33

barrier grila[i,j] := noua[i,j]; barrier od oc

Matricea noua este folosit pentru ca valorile din grila s depind doar de vechile valori. Calculele se termin atunci cnd toate valorile din noua difer cu mai puin de EPS de valorile din grila. Aceste diferene pot fi calculate n paralel, dar rezultatele trebuie combinate, ceea ce poate fi fcut utiliznd un algoritm prefix paralel. Problem (Etichetarea regiunilor) Dat fiind o imagine bidimensional (o gril de valori de pixeli) s se identifice i s se eticheteze n mod unic toate regiunile. O regiune este un set maximal de pixeli vecini, care au aceeai valoare. 2.8. Comunicarea asincron prin mesaje n cele prezentate pn aici, comunicarea ntre procese este realizat prin date comune (globale), iar sincronizarea prin mecanismul furnizat de instruciunea await. Transmiterea de mesaje, la rndul su, ndeplinete cele dou funcii: comnicarea este realizat deoarece datele ajung de la transmitor la receptor, iar sincronizarea este realizat deoarece un mesaj nu poate fi recepionat nainte de a fi transmis. La utilizarea comunicrii prin mesaje, canalele sunt obiectele puse n comun de procese. Absena unor variabile comune reclam tehnici speciale, diferite de cele folosite n cazul memoriei partajate. Ele in cont de faptul c procesele comunicante prin mesaje pot fi distribuite unor procesoare care nu au memorie comun. Din acest motiv, programele paralele care utilizeaz comunicare de mesaje se mai numesc programe distribuite. Asta nu nseamn c astfel de programe nu pot fi executate de sisteme cu memorie comun. n acest caz, canalele sunt implementate folosind memoria partajat i nu o reea de comunicaie. n cazul comunicrii prin mesaje asincrone, canalele sunt cozi nelimitate de mesaje. Un proces adaug un mesaj unei cozi prin execuia unei operaii send. Deoarece cozile sunt teoretic infinite, operaia nu este blocant. Un proces primete un mesaj dintr-o coad prin execuia unei operaii receive. Cnd coada este vid, operaia ntrzie procesul, pn la primirea unui mesaj. Canalele pstreaz ordinea mesajelor, deci sunt cozi FIFO.
34

Declaraia unui canal are forma urmtoare: chan nume_canal (id1: tip1,...,idn: tipn) n care se specific numele canalului, precum i numele i tipurile cmpurilor care compun un mesaj transmis prin acel canal. Se pot declara i tablouri de canale ca n exemplul urmtor: chan rezultat [1:n](int) n care se declar n canale avnd mesaje cu un singur cmp de tip ntreg. Numele cmpurilor sunt opionale, fapt rezultat i din exemplul specificat. Un proces tansmite un mesaj unui canal executnd operaia send nume_canal (expresie1,..., expresien) unde expresiile trebuie s aib aceleai tipuri cu cele ale cmpurilor mesajelor, specificate n declaraia canalului. Efectul execuiei unui send este calculul valorilor expresiilor, alctuirea unui mesaj cu aceste valori i adugarea lui la sfritul cozii asociate canalului. Un proces recepioneaz un mesaj prin execua unei operaii receive nume_canal (variabila1,..., variabilan) unde variabilele trebuie s aib aceleai tipuri cu cmpurile din declaraia canalului. Efectul este ntrzierea receptorului pn cnd n coad exist cel puin un mesaj, urmat de preluarea primului mesaj din coad i atribuirea valorilor cmpurilor variabilelor din list. Deoarece canalele sunt (declarate) globale, orice proces poate transmite i recepiona pe un canal. Cnd canalele sunt folosite astfel, ele mai sunt numite cutii potale. Cnd receptorul este unic, avem de-a face cu un port. n fine, atunci cnd i transmitorul este unic, avem de-a face cu o legtur. O alt operaie util este testul existenei mesajelor pe un canal, avnd forma empty (nume_canal) i ntrocnd valoarea adevrat sau fals, dup cum canalul nu are nici un mesaj, sau are cel puin unul. Utilizarea acestui test trebuie fcut cu grij, avnd n vedere c:
35

- dac testul este adevrat, nu nseamn c la reluarea execuiei procesului canalul este n continuare gol; - dac testul este fals, nu nseamn c urmtorul receive va produce recepia imediat a unui mesaj (dect dac exist un singur receptor). Exemplu. (Filtru) Prezentm codul unui proces care transform un flux de caractere ntr-o succesiune de linii de lungime maxim cunoscut.
chan input (char), output (array [1:MAXLINE] of char); car_linii:: var line: array [1:MAXLINE] of char, i: int :=1; do true -> receive input (line[i]); do line[i] <> CR and i < MAXLINE -> {line[1:i] conine ultimele i caractere introduse} i := i+1; receive input (line[i]) od send output (line); i := 1 od

Alt exemplu. (Replicated workers) n problema cuadraturii, trebuie calculat aria mrginit de graficul unei funcii continue ne-negative f(x), axa x i dreptele x=l i x=r. Soluia clasic impune mprirea intervalului [l,r] ntr-un numr de subintervale i folosirea unui trapez pentru a aproxima aria corespunztoare fiecrui subinterval. Dublm apoi numrul de subintervale din [l,r] i comparm rezultatul obinut cu cel anterior. Dac diferena este acceptabil calculul se termin, altfel se recurge la o nou dublare a numrului de subintervale. O soluie mai bun este cea adaptiv, n care se pornete procesul cu aria obinut prin considerarea unui singur subinterval [l,r] i apoi a dou subintervale [l,m] i [m,r]. Dac rezultatele snt suficient de apropiate, aria trapezului mare este considerat o aproximaie bun a ariei de sub curba f(x). Dac nu, problema se mparte n dou subprobleme care se trateaz separat: calculul ariei din subintervalul [l,m] i calculul ariei din subintervalul [m,r]. Se repet acest proces pn cnd se obine o soluie acceptabil pentru fiecare subinterval. Spre deosebire de prima soluie, n a doua se genereaz noi subprobleme doar pentru o parte din subintervale. n ambele cazuri, subproblemele snt independente, ceea ce permite paralelizarea uoar a algoritmului.

36

n acest scop, se utilizeaz un proces administrator, care genereaz prima problem i ateapt rezultatul, precum i mai multe procese de lucru, care rezolv subproblemele, genernd eventual alte subprobleme. Procesele de lucru mpart un acelai canal sac, ce conine problemele de rezolvat. O problem este caracterizat prin cinci valori: limitele subintervalului a i b, valorile f(a) i f(b), precum i aria corespunztoare (pentru a evita recalcularea sa). Cnd un proces de lucru gsete rspunsul la o subproblem, el trimite administratorului, printr-un canal separat, rezultatul. Programul se termin cnd administratorul detecteaz calculul ntregii arii.
chan sac (a, b, fa, fb, aria: real); chan rezultat (a, b, aria: real); Administrator:: var l, r, fl, fr, a, b, aria, total: real; alte variabile de marcare a intervalelor terminate; fl := f(l); fr := f(r); aria := (fl+fr)*(r-l)/2; send sac(l, r, fl, fr, aria); do nu s-a calculat toata aria -> receive rezultat (a, b, aria); total := total + aria; marcheaza intervalul [a,b] terminat; od; Lucru(i:1..n):: var a, b, m, fa, fb, fm: real; var arias, ariad, ariat, dif: real; do true -> receive sac (a, b, fa, fb, ariat); m := (a+b)/2; fm := f(m); calculeaz arias si ariad; dif := ariat - arias - ariad; if dif mic -> send rezultat (a, b, ariat); [] dif mare -> send sac (a, m, fa, fm, arias); send sac (m, b, fm, fb, ariad); fi od;

Exerciii 1) In programul precedent, toate procesele de lucru recepioneaz din acelai canal (sac). Modificai programul astfel ncat s se foloseasc doar canale cu un singur receptor i mai muli transmitori.

37

2) Scriei un program de sortare rapid folosind procese replicate. Iniial, tabloul a[1:n] este local administratorului. La terminarea programului, irul sortat trebuie napoiat administratorului care-l va memora n a[1:n]. 3) Folosii metoda proceselor replicate pentru a gsi toate soluiile n problema celor 8 regine. 2.9. Comunicarea sincron prin mesaje Comunicarea asincron de mesaje are unele neajunsuri privind confirmarea recepiei i eficiena: - pentru ca transmitorul s fie informat de recepia mesajului comunicat, este nevoie de un mesaj de rspuns; - dac rspunsul nu sosete, transmitorul nu poate ti dac mesajul a fost sau nu primit (receptorul a czut nainte de , sau dup primirea mesajului); - spaiul ocupat de mesajele transmise dar nerecepionate poate fi mare i deci ineficient utilizat. Comunicarea sincron elimin aceste neajunsuri. Aici, ambele primitive, send i receive sunt blocante. Astfel, la execuia unei transmisii, procesul ateapt pn cnd un altul efectueaz o recepie din acelai canal. Transmitorul poate continua dac mesajul a fost efectiv preluat. Mesajele nu trebuie s fie memorate temporar n cozi. Pe de alt parte, comunicarea sincron este uneori neconvenabil. Dup cum se vede, ea este o legtur unu la unu ntre procese, astfel nct anumite operaii, cum ar fi difuzarea de mesaje, sunt greu de realizat. Pentru reprezentarea primitivelor de comunicare sincron, folosim notaia din CSP (Hoare) relativ la comunicarea cu gard. Aceasta poate fi folosit n egal msur n comunicaia asincron sau n tehnica rendezvous. (Spre deosebire de comunicarea sincron, numit i rendezvous simplu, n tehnica rendezvous extins un proces accept un apel executat de un alt proces, prin intermediul unei instruciuni specifice input sau accept, realizeaz diverse prelucrri i apoi ntoarce rezultatele obinute.) Comunicarea ntre procese are loc prin primitive de intrare/ieire, de forma: Destinaie ! port (e1,...,en) Surs ? port (v1,...,vn)
38

unde Destinaie i Surs sunt procese, iar port identific unul din canalele de comunicaie ale acestora. Pentru prima dintre primitive, de ieire, valorile expresiilor ei sunt transmise portului specificat al procesului Destinaie. Portul poate lipsi, dac nu exist posibilitatea de confuzie, iar dac mesajul are un singur cmp, se poate renuna i la paranteze. Pentru a doua primitiv, mesajul primit la portul specificat, de la procesul Surs, este asociat variabilelor vi. De menionat c primitivele se execut simultan n tandem, dac: - instruciunea de ieire apare n procesul specificat de instruciunea de intrare; - instruciunea de intrare apare n procesul specificat de instruciunea de ieire; - identificatorii porturilor coincid; - toate atribuirile de forma vi := ei ar fi valide. Fie instruciunile: (1) X ? (a,b) i (2) DIV ! (3*x+y, 12). Conform primeia, se preiau de la procesul X dou valori i se atribuie variabilelor a i b. Prin cea de a doua, se evalueaz cele dou expresii i se transmit procesului DIV rezultatele. Dac procesul DIV execut comanda (1), iar procesul X comanda (2), atunci cele dou se deruleaz simultan i au acelai efect ca atribuirea (a,b) := (3*x+y, 12). Exemple. 1) Filtru. Copierea unor valori de la vest la est:
Copy:: var c: char; do true -> vest ? c; est ! c od

2) Client - Server. Calculul cmmdc printr-un proces server:


CMMDC:: var x, y: int; do true -> CLIENT ? arg (x,y); do x > y -> x := x-y; [] x < y -> y := y-x od CLIENT ! result (x) od

CLIENT-ul trebuie s conin instruciunile ...CMMDC ! arg (v1, v2); CMMDC ? result (r);...
39

Primitivele de intrare/ieire pot fi extinse la instruciuni de comunicare cu gard, care au forma: B; C -> S unde B este o expresie bolean opional C est o primitiv de comunicare opional, iar S este o list de instuciuni. Dac B este omis, ea are valoarea implicit true. Dac C este omis, expresia se reduce la o comand cu gard, uzual. mpreun B i C alctuiesc garda. Garda este rezolvat cu succes dac B este true i execuia lui C se poate face imediat (este n ateptare o instruciune de comunicare pereche). n acest caz, se execut mai nti comanda de comunicare C i apoi secvena S. Pe de alt parte, dac B este false garda nu este reuit. n fine, garda se blocheaz dac B este true, dar C nu poate fi executat imediat. Comunicarea cu gard este utilizat n instruciunile if i do. Astfel, la un if, dac cel puin o gard se rezolv cu succes, una din secvenele asociate este luat la ntmplare i executat. Dac toate grzile sunt nereuite atunci if se termin. Dac nici o gard nu este reuit, dar anumite grzi sunt blocate, atunci execuia se ntrzie pn cnd una reuete. Similar se execut i do. n grzi pot apare att instruciuni de intrare, ct i instruciuni de ieire. Exemple. 1) Filtru. Transmitere cu nlocuire. Transmite ctre procesul est caracterele produse de procesul vest. nlocuiete fiecare pereche de asteriscuri ** cu caracterul sgeat ^. Prin convenie, ultimul caracter transmis de vest nu este un asterisc.
INLOCUIRE:: do var c: char; vest?c -> if c<>asterisc -> est!c [] c=asterisc -> vest?c; if c<>asterisc -> est!asterisc; est!c [] c=asterisc -> est!sageata fi fi od

2) Comunicare printr-un tampon limitat.


40

Copy:: var buffer: array [1:10] of char; var front: int := 1, rear: int := 1, count: int := 0 do count<10; vest ? buffer[rear] -> count := count+1; rear := (rear mod 10) +1 [] count > 0; est ! buffer [front] -> count := count -1; front := (front mod 10) +1 od

Procesul are dou grzi. Prima este reuit dac exist loc n tampon i vest este gata s trimit un caracter. A doua reuete cnd exist caractere in tampon i est este pregtit s accepte un caracter. De remarcat c instruciunea do nu se termin niciodat, deoarece cel puin una din condiiile booleene din grzi este ndeplinit. 3) Client - Server. (Calculul cmmdc.) Procesul CMMDC joac rolul unui server, care accept dou numere ntregi pozitive i d ca rezultat cmmdc al lor. Algoritmul este o variant uor modificat a celui de la nceputul seciunii.
CMMDC:: var x, y: int do Client ? arg (x,y) -> do x > y -> x := x-y [] x < y -> y := y-x od Client ! result (x) od

n cazul unui server cu mai muli clieni, fiecare dintre acetia trebuie s aib o identitate distinct, de exemplu un indice distinct, n cazul unui tablou de utilizatori. Ca urmare, pentru a arta c serverul este pregtit s comunice cu oricare dintre utilizatori, folosim o comand cu gard cu un subdomeniu, de exemplu:
do (i:1..100) X(i)?(parametri) -> ... X(i)!(rezultate) od

Exemplu. Calculul cmmdc.


CMMDC:: var x, y: int do (i:1..n) Client(i) ? arg (x,y) -> do x > y -> x := x-y 41

[] x < y -> y := y-x od Client(i) ! result (x) od

Aici, subdomeniul (i:1..n) asociat buclei do exterioare este o prescurtare a unei serii de instruciuni de comunicare cu gard, cte una pentru fiecare valoare a lui i. Ca urmare, construcia se interpreteaz astfel: CMMDC ateapt s primeasc o intrare de la unul dintre clieni; indexul clientului care a furnizat intrarea este folosit pentru a dirija rspunsul n mod corespunztor. Comportarea este aceea a unui monitor (Hoare).

42

Capitolul 3 - Complexitatea algoritmilor paraleli i distribuii


Orice proces de proiectare a unui algoritm urmrete obinerea unui rezultat corect i performant. n cazul algoritmilor paraleli i distribuii, performana nu poate fi caracterizat printr-o singur cifr. Ea depinde de categoria de aplicaii n care este folosit algoritmul, de multe ori performana fiind o funcie de caracteristicile produsului program realizat (timp de execuie, memorie ocupat, numr de procesoare utilizate, scalabilitate, eficien, fiabilitate, toleran la defectri, portabilitate), dar i de costurile implicate de diferitele faze ale ciclului de via (proiectare, implementare i ntreinere). Ca n orice situaie n care exist mai multe alternative, i n cazul algoritmilor paraleli alegerea trebuie fcut pe baza nelegerii costului diferitelor variante. Estimarea costurilor reclam folosirea unor metrici i a unor modele de performan. Ele permit evaluarea comparativ a soluiilor, identificarea zonelor de gtuire, eliminarea ineficienelor, nc nainte de a investi efort n implementarea lor. Deoarece i etapa de evaluare trebuie s fie eficient, modelele alese pentru a fundamenta alegerea soluiei trebuie s fie un compromis ntre efortul de modelare i importana mbuntirilor realizate prin consumarea lui. Recunoscnd importana tuturor factorilor de performan, descrierea care urmeaz se limiteaz la o parte a lor, concentrndu-se n special pe analiza timpului de execuie i a scalabilitii. Alegerea este determinat de faptul c, de cele mai multe ori, acestea reprezint aspectele cele mai problematice ale proiectrii aplicaiilor paralele i distribuite. n analizele concrete pe care un proiectant le face, evaluarea acestor performane trebuie realizat n codiiile nelegerii contextului dat de ceilali factori menionai mai sus.

3.1. Sortarea pe un vector de procesoare


Pentru a discuta msurile de performan asociate algoritmilor paraleli, pornim de la un exemplu simplu: sortarea unui ir de numere folosind un sistem vectorial (un tablou unidimensional de procesoare), ca i cel prezentat n figura 3.1. intrare ieire Figura 3.1 43

Fiecare procesor interior este conectat prin legturi bidirecionale cu vecinii si, din dreapta i din stnga. Procesoarele extreme pot avea doar cte o legtur i pot servi ca puncte de intrare/iesire pentru celelalte procesoare. Fiecare procesor are o memorie local i propriul su program. Sistemul are o funcionare sincron: un ceas global comand execuia simultan a operaiilor de ctre procesoare. La fiecare pas, fiecare procesor realizeaz operaiile urmtoare: recepia unor date de la vecini; inspecia memoriei locale; execuia calculelor specificate de program; modificarea memoriei locale; transmiterea unor date ctre vecini. O astfel de funcionare se numete sistolic. Pentru a sorta o list de N numere, folosim un vector de N procesoare. Fiecare procesor execut un algoritm compus din doua faze. In fiecare pas al primei faze, fiecare procesor realizeaz urmtoarele operaii: 1) accept o valoare de la vecinul din stnga; 2) compar valoarea cu cea memorata local; 3) transmite valoarea mai mare vecinului din dreapta; 4) memoreaz local valoarea mai mic. Un exemplu este ilustrat n figura 3.2. 30512 3051 305 2 2 1 dup pasul 2 iniial dup pasul 1

2 Figura 3.2

dup pasul 9

Nu este greu de artat c dup 2N-1 pai, celulele conin elementele irului n ordine cresctoare. Astfel, prima celul examineaz N elemente din ir, reine valoarea cea 44

mai mic i transmite restul spre dreapta. A doua celul, examineaz restul de N-1 valori, o reine pe urmtoarea mai mic i transmite restul celorlalte celule. Prin inducie, rezult c celula N primete valoarea maxim a irului. Similar, deoarece o valoare ajunge n prima celul dup un pas, n celula a doua dup trei pai .a.m.d., rezult prin inducie c valoarea maxim ajunge n ultima celula dupa 2N-1 pai. In a doua faz a algoritmului, valorile ordonate sunt scoase, prin celula din stnga. Exist mai multe variante: 1. fiecare procesor ncepe s transmit spre stnga, imediat ce numerele sunt sortate; 2. cunoscnd poziia sa din vector i numrnd valorile inspectate, fiecare procesor calculeaz momentul cnd ncepe s transmit spre stnga; 3. procesorul din dreapta este special; el ncepe s transmit spre stnga imediat ce primete o valoare; toate celelalte ncep s transmit spre stnga imediat ce primesc o valoare dinspre dreapta; 4. fiecare procesor ncepe s transmit spre stnga imediat ce nu mai primete o valoare dinspre stnga. Din cele patru metode doar ultimele doua nu impun cunoaterea poziiei procesoarelor n vector i contorizarea valorilor. Metoda 3 reclama 4N-3 pai, n timp ce 4 cere 3N1 pai pentru ambele faze de sortare i de scoatere a rezultatelor. Exerciiu. Alctuii descrieri pentru metodele 3 si 4, considernd pe rnd modelele de calcul paralel cu memorie comuna i cu transmitere de mesaje. n primul caz, comunicarea ntre procese se realizeaz prin variabile comune special dedicate. 3.2. Msuri de performana Msurile obinuite de apreciere a algoritmilor paraleli sunt: timpul total T necesar execuiei i numarul de procesoare utilizate P. In algoritmul prezentat, P = N i T = O(N). Observaie. In seciunea curent timpii se refer la cazul cel mai defavorabil. De multe ori, se compar performanele atinse de un algoritm cu cele mai bune performane ale unui algoritm secvenial care rezolva aceeai problem. Astfel, dac G este timpul de execuie al celui mai rapid algoritm secvenial, se definete accelerarea S (speedup) corespunztoare unui algoritm paralel ca raportul dintre G si T, adic S = G/T. In cazul algoritmului precedent, S= O(N log N)/ O(N) = O(log N). 45

Ideal ar fi ca algoritmul paralel gsit s fie de P ori mai rapid dect cel mai bun algoritm secvenial, sau mcar S = O(P). Un exemplu este cutarea unei valori ntr-un fiier distribuit, folosind maini SIMD cu acces concurent la citire i exclusiv la scriere. Fiecare procesor inspecteaz un sub-fiier de lungime n/P n timp O(n/P). Timpul necesar unui algoritm secvenial pentru cutarea n ntreg fiierul de lungime n, este O(n). Spunem, n acest caz, c acceleraia este linear. Teoretic, nu se poate obtine o acceleraie mai bun. Astfel, dat fiind un algoritm paralel care se execut n T pai pe P procesoare, putem oricnd folosi un singur procesor pe care procesele s se execute secvenial n TP pasi. Ca urmare, G <= TP. Semnul < folosit aici subliniaz faptul c, dac serializarea unui algoritm paralel este totdeauna posibil (simularea lui pe o main multiprogramat), n schimb, nu exist o procedur efectiv de paralelizare a unui algoritm secvenial (exist algoritmi secveniali care, prin natura lor, nu pot fi paralelizai). O acceleraie liniar este realizabil destul de rar, deoarece: mpartirea problemei n P subprobleme, fiecare rezolvabil n 1/P din timpul algoritmului secvenial corespunztor nu este mereu posibil; S considerm c ntr-un algoritm procentajul f din totalul calculelor trebuie s se desfoare secvenial. Obtinem: T = f * G + (1-f) * G / P sau S = 1 / (f + (1-f) / P) Relaia arat c oricte procesoare s-ar folosi, acceleraia nu poate fi mai mare de 1/f (legea lui Amdahl). Pe de alt parte, dependena lui S de f este neliniara, o cretere mic a lui f ducnd la o scdere important a accelerrii S.
topologia sistemului paralel folosit n rezolvarea problemei impune uneori restricii de timp. Astfel, n adunarea a n numere folosind n-1 procesoare dispuse n topologie arborescent, nu se poate obine un numr de pai sub log n, ci sunt necesari pentru propagarea unei valori de la o frunz (intrarea) la rdcina arborelui (ieirea). Oricum, G/P este o margine inferioar pentru timpul de execuie al oricrui algoritm paralel care folosete P procesoare.

O alta msur de performan important este costul C algoritmului. Acesta este definit ca produsul dintre timpul de execuie i numrul de procesoare, adic C = TP. 46

In cazul nostru avem C = O(N2). Aceast msur poate fi folosit n caracterizarea ineficienei datorate nefolosirii complete a procesoarelor, de ctre un algoritm paralel. Mai precis, eficiena E a unui algoritm paralel este raportul E = G/C dintre timpul de lucru al algoritmului secvenial optim i costul algoritmului paralel. Avem E = G/C = G/(TP) = S/P deci eficiena poate fi exprimat i ca raportul dintre accelerare i numrul de procesoare. In cazul exemplului dat avem E = O((log N)/N). 3.3. Cazul unui numr redus de procesoare Majoritatea msurilor de performana sunt calculate pentru situaia ideal n care numrul de procesoare utilizate egaleaza numrul de procese. In exemplul dat anterior, numrul de procesoare utilizate este N, programul de sortare cuprinznd N procese. Ce se ntampl n cazul unui numar mai mic de procesoare? Exist o procedur general foarte simpl de execuie a unui algoritm proiectat pentru o reea de P1 procesoare, pe o reea de P2 procesoare, unde P2<P1. Metoda const n simularea a sup(P1/P2) procesoare pe fiecare procesor real. Cea mai simpla variant este de a plasa pe procesorul i procesele (i-1)*sup(P1/P2)+1, (i-1)*sup(P1/P2)+2,..., i*sup(P1/P2). Orice algoritm care poate fi executat n T pai pe P1 procesoare, poate fi executat n T*sup(P1/P2) pai n cazul a numai P2 procesoare. 3.4. Calculul detaliat al complexitii De multe ori, paralelizarea calculului se face pentru atingerea unui timp de execuie ct mai redus. In legtur cu acest aspect, apare fireasc ntrebarea dac un anumit algoritm este optim sau nu, deci dac exist sau nu un algoritm cu un timp mai mic de execuie. Rspunsul la aceast ntrebare depinde, printre altele, de modelul de evaluare adoptat. In analiza facut anterior pentru algoritmul de sortare, paii algoritmului au fost numrai n termenii unor operaii asupra cuvintelor. O alta posibilitate este de a considera modelul bit, mai detaliat. O astfel de analiz este justificat de existena unor maini la care paralelismul se manifest chiar la nivelul operaiilor asupra biilor 47

de date, precum i de interesul teoretic pe care astfel de msuri de complexitate l prezint. Punctul cheie n detalierea operaiilor algoritmului de sortare la nivel de bit l constituie comparaiile. O metod simpl este compararea numerelor bit cu bit, secvenial, ncepnd cu bitul cel mai semnificativ. A doua metod folosete un arbore binar complet. Numerele sunt comparate bit cu bit, informaiile rezultate fiind apoi condensate prin mperecheri succesive, pn la obinerea rspunsului final. Procedeul este ilustrat n figura 3.3. pas 1 msb 0 0 1 lsb 0 s 0 0 0 1 d = = s d = s s pas 2 pas 3

Figura 3.3 (msb cel mai semnificativ bit; lsb cel mai puin semnificativ bit; s- valoarea din stnga; d - valoarea din dreapta) Arborele binar este superior algoritmului secvenial, din dou motive. Mai nti, el utilizeaz log k + 1 pai pentru a afla rezultatul, n timp ce primul cere k pai. Apoi, acelai arbore poate fi folosit pentru a specifica procesoarelor care dintre cele doua numere trebuie trecut mai departe i care trebuie pstrat (aa cum reiese din figura 3.4).

48

pas 1 msb 0 0 1 lsb 0 s 0 0 0 1 d s s s s

pas 2 s

pas 3

s s

Figura 3.4 Cu aceasta, dupa 2*log k pai, comparaia celor dou numere este terminat i cei k bii ai numarului mai mare pot fi mutai simultan spre urmtoarea celul. Inlocuind fiecare procesor din vectorul folosit pentru sortare, cu un arbore complet de procesoare de un bit, putem construi o reea cu (2k-1)N procesoare de un bit, care face (2N-1)*2*log k pai pentru a executa prima faz a algoritmului. Exist ns un algoritm mai bun de comparare, care, n mod surprinztor, se bazeaz pe un tablou linear de procesoare i nu pe un arbore complet. Secretul const n utilizarea acestuia n linie de asamblare (pipeline). Ideea de baz este ilustrat n figura 3.5, n care se consider un vector de trei procesoare pe bit, folosit pentru a gsi cea mai mic dintre valorile 2, 0, 5, 1, 2 (evident, n reprezentarea lor binar). Vectorul de procesoare face, n mod repetat, compararea valorii memorate cu valoarea primit din stnga, o reine pe cea mai mic i o transmite n dreapta pe cealalt. Soluia are urmtoarele particulariti: execuia n linie de asamblare face ca n timp ce un procesor compar o pereche de bii a dou numere succesive, procesorul de sub el s lucreze cu biii mai puin semnificativi ai perechii de numere anterioare, iar procesorul de deasupra s lucreze cu biii mai semnificativi ai perechii de numere succesoare; la fiecare pas, un procesor primete la intrare un bit, iar de la procesorul de deasupra o informaie asupra comparaiei fcute de el la pasul anterior (aceasta

49

comparaie se refer la biii mai semnificativi ai acelorai numere) - s dac numrul de la intrare este mai mare, d dac numrul memorat este mai mare, = dac cele dou numere sunt egale (n rangurile mai mari dect rangul curent);
3 0 5 1 2 <- iniial --------------------------------------------------------------0 0 1 0 0 [ ] <-msb 0 [0] -> 0 1 0 / / / / / / = / 1 0 0 0 1 [ ] 1 0 [0] -> 0 1 / / / / / / s / 1 0 1 1 0 [ ] <-lsb 1 0 1 [1] -> 0 iniial dup pasul 4 --------------------------------------------------------------0 0 1 0 [0] [0] -> 0 0 1 0 / / / / = / / 1 0 0 0 1 [ ] 1 [0] -> 0 0 1 / / / / = / / 1 0 1 1 0 [ ] 1 0 [1] -> 1 0 dup pasul 1 dup pasul 5 -----------------------------------------------------------0 0 1 [0] -> 0 [0] -> 0 0 1 0 / / / = / / / 1 0 0 0 [1] [0] -> 1 0 0 1 / / / s / / / 1 0 1 1 0 [ ] 1 [0] -> 1 1 0 dup pasul 2 dup pasul 6 ------------------------------------------------------------0 0 [0] -> 1 0 [0] -> 0 0 1 0 / / s / / / / 1 0 0 [0] -> 1 [0] -> 1 0 0 1 / / d / / / / 1 0 1 1 [0] [0] -> 1 1 1 0 dup pasul 3 dup pasul 7 ------------------------------------------------------------rezultat -> 0 3 1 5 2

Figura 3.5

dac primete s, procesorul transmite bitul de la intrare la ieire i transmite s n

jos; dac primete d, procesorul transmite bitul memorat la ieire, memoreaz bitul de la intrare i transmite d n jos; dac primete =, transmite bitul mai mare la ieire, memoreaz bitul mai mic i transmit n jos s, d sau = n mod corespunzator;

50

cnd nu mai primete nimic la intrare, procesorul scoate n stanga valoarea memorat i apoi toate valorile primite din dreapta (faza a doua).

Se poate observa c aciunea vectorului de procesoare pe un bit este similara celei a primului procesor de cuvnt, din algoritmul de ordonare. In ambele cazuri, cea mai mic valoare este pastrat, restul valorilor fiind transmis spre dreapta. Putem, deci, combina N vectori de cte k bii, formnd astfel o matrice de procesoare, pentru a realiza sortarea celor N numere. Prima faz a sortrii se poate executa n (k-1)+(2N-1) = 2N+k-2 pai, la nivel de bit. A doua faz a sortrii se poate derula la fel ca n modelul "cuvnt", ceea ce conduce la sortarea complet a N cuvinte de cte k bii n 3N+k-2 pai cu N*k procesoare pe un bit. 3.5. Limite inferioare Exemplul anterior este util sub dou aspecte. Mai nti, el arat rolul topologiei reelelor de procesoare n atingerea unor performane bune n calculul paralel. Ne putem imagina cu uurin c diferitele combinaii de aciuni exemplificate aici pentru operaii foarte simple, pot apare n general, n calculul paralel, deci i pentru aciuni de o complexitate mai mare. In al doilea rnd, el ne permite discutarea unor aspecte legate de optimalitatea algoritmilor paraleli. Dac ne referim la algoritmul prezentat n termenii vitezei sau eficienei, putem spune ca el nu este optimal, deoarece exist algoritmi mai rapizi care utilizeaz chiar mai puine procesoare. Reeaua necesar pentru aceti algoritmi este ns mai complex dect o matrice k*N. Dac ne limitm la matrice k*N, atunci putem afirma c algoritmul este optim, deoarece orice algoritm de sortare executat pe o astfel de configuraie reclam un timp O(k+N). Motivele sunt urmtoarele: 1) Dac sunt folosite numai k procesoare pentru introducerea datelor, sunt necesari N pai numai pentru citirea tuturor celor N numere. 2) Diametrul unei reele este distana maxim ntre oricare doua noduri ale sale. Distana ntre dou noduri este numrul minim de legturi traversate pentru a ajunge de la un nod la celalalt. Pentru o reea de k*N noduri, diametrul este N+k-2. Diametrul este o indicaie bun asupra complexitii, deoarece comunicarea informaiei ntre nodurile aflate la o distan d consum d pai ai algoritmului.

51

De exemplu, presupunnd c la sortare numerele x1 = x110...01, x2=...=xN= 010...0 sunt dispuse iniial n matricea de procesoare astfel c bitul i cel mai semnificativ al numrului j este dispus n matrice n poziia i,j, atunci timpul trebuie s fie cel puin k+N-2. Aceasta deoarece bitul cel mai puin semnificativ al celui mai mare numr este 1 dac i numai dac x11 = 1, ceea ce nseamn c informaia din pozitia 1,1 trebuie s ajung n poziia k,N pentru ca sortarea s fie terminat. 3) Lrgimea biseciei unei reele este numrul minim de legturi care trebuie indepartate pentru a mpri reeaua n dou subreele separate, avnd acelai numr de noduri (sau diferena de un nod). Aceast caracteristic este important deoarece uneori valorile calculate de o jumatate a reelei sunt necesare celeilalte jumti. De exemplu, n sortare, este posibil ca numerele mai mari s fie plasate n jumtatea stng a matricei de procesoare, iar numerele mai mici n dreapta. Ca urmare, (k*N)/2 bii trebuie s treac din stnga n dreapta reelei i invers. Cu o lrgime a biseciei de k legturi, sunt necesari cel putin N/2 pai. Caracteristicile prezentate trebuie folosite cu grij n calculul complexitii. Exist exemple care arat c luarea lor n consideraie fr discernmnt poate conduce la aprecieri eronate. Astfel, n [Leighton92] se menioneaz cazul sortrii a N numere de K bii folosind un arbore binar complet. O configuraie posibil este prezentat n figura 3.6. Figura arat coninutul procesoarelor frunz, dup sortare. Procesorul rdcina are log N celule (unde N este numrul valorilor irului de sortat). Procesoarele din nodurile intermediare ale arborelui sunt de o celula. In fine, procesoarele frunz au cte K celule (unde K este numrul de bii din reprezentarea unei valori din irul de sortat). Diametrul reelei este 2.log N + 2.K - 2, iar lrgimea benzii de intrare a datelor este K.N (presupunnd c toate numerele sunt introduse deodat). In fine, lrgimea biseciei este 1, dac log N = 1 i 2 n celelalte cazuri.

52

procesorul rdcin are log N celule

procesoare intermediare

0 0 0 1 1

0 1 0 1 5

1 0 0

1 1 1 0 14

procesoare frunza cu cte K celule

1
9

Figura 3.6 Deoarece, n cel mai ru caz, algoritmul trebuie s mute KN bii prin bisecie, ar trebui ca algoritmul de sortare s solicite O(KN) pai. Cu toate acestea, pentru situaii n care k este mic, rezultatul este cu totul altul. In particular, pentru k=1, exist un algoritm O(log N) care realizeaz sortarea. 3.6. Proprieti ale modelului de evaluare Exemplele de evaluare prezentate au evideniat modul de considerare a timpului de calcul i de comunicare n analiza algoritmilor paraleli. Sistematizm n continuare proprietile pe care se bazeaz aceste analize. Proprietile procesoarelor. Fiecare procesor are un control local. Aciunile lui depind de coninutul memoriei locale i de intrrile proprii. Complexitatea depinde de nivelul operaiilor considerate: pe bit sau pe cuvant. Uneori pachetul este considerat ca unitate de date, operaiile uzuale fiind recepia, memorarea i transmisia unui pachet. Proprietile interconexiunilor. Presupunerile care se fac uzual despre reeaua de procesoare sunt urmtoarele: topologia este fix; gradul fiecrui nod este limitat; 53

dimensiunea reelei este o funcie polinomial (uzual linear) de dimensiunea problemei.

Proprietile protocolului de intrare/iesire. Constrngerea uzual este ca o intrare este prevazut o singura dat. Complexitatea include astfel i costul difuzarii intrrii, dac este cazul. In plus, locul i momentul apariiei fiecrei intrri i, corespunztor a fiecrei ieiri, trebuie specificate n avans (adic nainte de nceperea execuiei algoritmului). 3.7. Modele generale Cele prezentate anterior evideniaz faptul c analiza complexitii algoritmilor paraleli presupune folosirea unui model formal, care s permit evaluarea parametrilor de performan, cum sunt timpul de execuie, lucrul, accelerarea etc. Modelul folosit n exemplul dat este particular unei anumite categorii de maini paralele, SIMD cu memorie local. Din pcate, acesta nu este singurul model folosit n calculul paralel, deoarece organizarea mainilor paralele difer mult mai mult ntre ele dect cea a mainilor secveniale. Pe de alt parte, folosirea unui model particular, care s surprind ct mai fidel caracteristicile fiecrei categorii de maini este nepractic, datorit numrului mare de modele care ar fi necesare. O alternativ este folosirea unui numr mic de modele abstracte, care nu ncearc s reproduc fidel comportarea vreunei maini paralele particulare, dar au avantajul c algoritmii dezvoltai pe baza lor pot fi tradui cu uurin n programe care se dovedesc eficiente pe mainile paralele reale. Modelele paralele generalizeaz modelul secvenial RAM, prin introducerea mai multor procesoare. Ele se clasific n trei categorii, n care este uor s plasm arhitecturile de maini paralele definite n capitolul anterior: maini cu memorie local (din care face parte i modelul folosit anterior) maini cu memorie modular i maini paralele cu acces aleator la memorie PRAM. O main cu memorie local cuprinde o mulime de procesoare, fiecare cu propria sa memorie, ataate unei subreele de interconectare. Fiecare procesor poate accesa direct propria memorie i prin intermediul reelei de interconectare celelalte memorii. Accesul local se consider c dureaz o unitate de timp, accesul distant, la memoria unui alt procesor depinde de performanele reelei de interconectare i de nivelul traficului celorlalte procesoare. 54

O main cu memorie modular const din N procesoare i M module de memorie, ataate unei reele comune. Un procesor acceseaz un modul de memorie prin transmiterea unei cereri prin reea. Uzual, timpul de aces al oricrui procesor la oricare modul este uniform, dar depinde de performanele reelei i de "tiparul" operaiilor de acces la memorie. O main PRAM const din N procesoare conectate la o memorie comun, partajat. Se consider c, ntr-un singur pas, procesele pot avea acces simultan, direct la memoria partajat. Desigur, modelele sunt foarte generale i destul de ndeprtate de structura i funcionarea mainilor reale. De exemplu, nici o main real actual nu se conformeaz n mod ideal modelului PRAM, realiznd ntr-o unitate de timp, orice acces la memoria partajat. Cu toate acestea, modelele menionate au fost folosite n dezvoltarea algoritmilor paraleli i distribuii, datorit simplitii lor i a uurinei de folosire n proiectarea algoritmilor. 3.7.1. Modelul grafurilor orientate aciclice (work-depth) O alternativ natural la utilizarea unor modele orientate pe categorii de maini este folosirea unor modele orientate spre algoritmi. Fr a ine seama de particularitile sistemelor de calcul paralele i distribuite pe care urmeaz a fi executai algoritmii dezvoltai, modelele faciliteaz exprimarea fr constrngeri artificiale a rezolvrii problemelor (cum ar fi numrul de procesoare sau topologia sistemului distribuit), exploatnd la maximum paralelismul intrinsec al problemelor. O clas important a unor astfel de modele este cea denumit "lucru-adncmie", la care ne referim n continuare. Multe calcule pot fi reprezentate n forma unor grafuri (circuite) orientate aciclice, dup urmtoarele reguli: fiecare intrare este reprezentata ca un nod fr arce de intrare fiecare operatie este reprezentat ca un nod ale crui arce de intrare provin de la nodurile care reprezint operanzii o ieire este reprezentat ca un nod fr arce de ieire. Un exemplu este prezentat n figura 3.7, care descrie un algoritm de calcul al sumei elementelor unui tablou unidimensional. 55

a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] Figura 3.7 Graful descrie operaiile executate de algoritm i constrngerile de preceden asupra ordinii n care operaiile sunt executate. Modelul este independent de orice arhitectur i orice numr concret de procesoare. El pune n eviden: lucrul efectuat de algoritm, adic numrul total de operaii adncimea, adic lungimea celui mai lung lan de dependene secveniale din algoritm. Raportul lucru / adncime se numete paralelismul algoritmului. In exemplul din figura 3.7, lucrul cerut de calculul sumei este de 7 operaii. Adncimea este de trei operaii i poate fi calculat uor pornind de la orice frunz i numrnd operaiile pe calea pn la rdcina arborelui. In acest caz, generalizarea este foarte simpl: pentru nsumarea a n numere sunt necesare n-1 operaii, adncimea fiind de log n. 3.7.2. Folosirea modelului pentru calculul complexitii Modelul de graf poate fi folosit pentru aprecierea complexitii algoritmilor paraleli pornind de la forma acestora ntr-un limbaj de descriere. S relum problema anterioar, a crei descriere este urmtoarea: 56 + + + + + + +

var a, b: array [1:n] of real; /* presupunem n = 2k */ var s: real; fa i := 1 to n do in parallel b[i] := a[i] af; fa h := 1 to log n do fa i := 1 to n/2h do in parallel b[i] := b[2*i-1] + b[2*i] af af; s := b[1];

Descrierea nu conine nici o mentiune despre numrul de procesoare, sau despre felul n care operaiile vor fi alocate procesoarelor. In schimb, el poate fi analizat n numr de unitti de timp necesare, n fiecare unitate de timp executndu-se n paralel orice numr de operaii. Astfel, numrul total de uniti de timp este log n + 2, deci T(n) = O(log n). In prima unitate de timp sunt executate n paralel n operaii. In iteraia h se fac n/2h operaii, unde 1 <= h <= log n. In ultima unitate de timp are loc o singura operaie. Rezult c lucrul fcut de algoritm este W(n) = n + h = 1, log n n/2h + 1 = O(n). 3.7.3. Principiul de planificare pentru PRAM Dei numrul modelelor ce ar putea fi utilizate n dezvoltarea algoritmilor paraleli este relativ mare, exist, din fericire, deseori tehnici automate de traducere a algoritmilor de la un model la altul. Aceste traduceri conserv lucrul realizat de algoritm, n limitele unui factor constant. Teorema urmtoare, datorat lui Brent, descrie modul de traducere de la modelul work-depth la un algoritm PRAM. Daca se ia n consideraie numrul de procesoare p al unei anumite configuraii de sistem de calcul, atunci cel mult p operaii pot fi executate n paralel n fiecare unitate de timp. Principiul enunat n continuare arat c, pentru un algoritm care ruleaza n T(n) uniti de timp, executnd W(n) operaii, se poate obine o adaptare a algoritmului care s ruleze pe p procesoare PRAM n cel mult inf(W(n)/p) + T(n) uniti de timp (teorema lui Brent). Justificare Fie Wi(n) numrul de operaii executate n unitatea i de timp, unde 1 <= i <= T(n). Pentru fiecare i, 1 <= i <= T(n), fiecare set de Wi(n) operaii se execut n Wi(n)/p pai paraleli, pe cele p procesoare. In cazul n care execuia este reuit, algoritmul PRAM corespunztor pentru p procesoare ia mai puin de i sup(Wi(n)/p) <= i (inf(Wi(n)/p) + 1) <= inf(W(n)/p) + T(n) 57

pai paraleli. Exemplificare Pentru exemplificare, s considerm c executm algoritmul de nsumare a elementelor unui tablou pe un sistem PRAM cu p procesoare, unde p = 2q <= n = 2k. Imprim tabloul A n p subtablouri, astfel nct procesorul s s fie responsabil de subtabloul s, adic de elementele A[l*(s-1)+1] pn la A[l*s]. Iniial, procesorul s copiaz aceste elemente n B[l*(s-1)+1] pn la B[l*s]. La fiecare nivel al arborelui binar, elementele B se njumtesc fa de nivelul anterior, dar se rempart n mod egal ntre cele p procesoare. Numrul de operaii posibil concurente la nivelul h este n/2h . Dac acest numr este mai mare dect numrul de procesoare p = 2q, adic n/2h = 2k-h >= p = 2q ceeace echivaleaz cu k-h >= q atunci operaiile se mpart egal procesoarelor. Altfel, operaiile sunt executate de cele 2k-h procesoare de indici inferiori.
var A, B: array [1:n] of real; /* n = 2k si p = 2q */ var S: real; l: int := n/p; fa s := 1 to p do in parallel fa j := 1 to l -> B[l*(s-1)+j] := A[l*(s-1)+j] af; fa h := 1 to log n -> if k-h-q >= 0 -> fa j := 2 k-h-q(s-1) + 1 to 2 k-h-q s -> B[j] := B[2*j-1] + B[2*j] af [] k-h-q < 0 -> if s <= 2 k-h -> B[s] := B[2*s-1] + B[2*s] fi fi af if s = 1 -> S := B[1] fi af;

Not. Algoritmul merge pentru p >= n/2. Pentru a estima timpul de execuie al algoritmului, observm c primul pas ia O(n/p) uniti de timp, deoarece fiecare procesor execut n/p atribuiri. Iteraia h din ciclu ia O(n/(2hp)), deoarece un procesor are de executat cel mult sup(n/(2hp)) operaii. Ultimul pas ia o unitate de timp. Ca urmare, timpul de execuie pentru p procesoare, Tp(n) este inferior lui 58

n/p + h=1, log n sup(n/(2hp)) <= n/p + h=1, log n (inf(n/(2hp)) + 1) <= <= n/p + h=1, log n inf(n/(2hp)) + log n <= 2n/p + log n i deci Tp(n) = O(n/p + log n), ceeace corespunde principiului planificrii. 3.7.4. Lucru i cost Cele doua noiuni sunt corelate ntre ele. Dat fiind un algoritm de lucru W(n) i de timp T(n), algoritmul poate fi simulat pe p procesoare PRAM ntr-un timp dat de formula: Tp(n) = O(W(n)/p + T(n)) Costul corespunztor (produsul timp*numar_procesoare) este atunci egal cu Cp(n) = Tp(n) p = O(W(n) + p T(n)) In general, costul este mai mare dect lucrul unui algoritm. Aceasta se datoreaz utilizrii pariale a procesoarelor pe parcursul execuiei unui algoritm paralel. Astfel, pentru algoritmul precedent, considernd c se utilizeaz n procesoare, cel mult jumtate pot fi active la prima execuie a ciclului fa exterior, cel mult un sfert rmn active la a doua execuie a ciclului .a.m.d. Abordarea prezentat presupune utilizarea procesoarelor libere pentru alte sarcini. Exist, bineneles, anumite cerine pentru realizarea unor algoritmi PRAM eficieni. Astfel, numrul de procesoare p trebuie s fie mai mic dect n (dimensiunea problemei) i adaptiv (dependent de dimensiunea problemei). Uzual, se consider c p(n) este satisfctor dac este o funcie subliniara de n, de exemplu rdcina ptrat din n. In orice caz, algoritmul s nu depind de numrul de procesoare. Timpul de execuie Tp(n), dependent de dimensiunea problemei, s fie mic, semnificativ mai mic dect cel al variantei secveniale. De asemenea, el s fie adaptiv (fa de dimensiunea problemei) i invers proporional cu numrul de procesoare. In fine, costul s fie minim. De multe ori se compar costul algoritmului paralel cu costul celui mai bun algoritm secvenial care rezolv aceeai problem. Dezvoltarea unor algoritmi cost-optimali va fi prezentat ntr-o alt seciune.

59

3.7.5. Implementare pentru reele de procesoare In cazul implementrii algoritmilor paraleli pe reele de procesoare, exist mai multe posibiliti de alegere a topologiei: liniar, inel, arbore, matrice, cub, hipercub. De regul, folosirea unor topologii diferite conduce la rezolvri diferite ale aceleiai probleme. Transpunerea soluiei pentru un hipercub este deosebit de simpl, datorit capacitii acestuia de adaptare la diferite topologii, printre care i aceea de arbore. Un hipercub const din p = 2d procesoare, indexate de la 0 la p-1, interconectate intrun cub boolean d-dimensional, definit dup cum urmeaz. Fie reprezentarea binar a lui i, 0 <= i <= p-1, de forma id-1id-2i0. Dou procesoare sunt conectate dac indicii lor difer doar ntr-o singur pozitie a reprezentrilor lor binare. De exemplu, ntr-un cub 4-dimensional, nodul 0 (0000) este conectat cu nodurile 1 (0001), 2 (0100), 4 (0100) si 8 (1000). Hipercubul are o structur recursiv. Se poate extinde un cub d-dimensional la unul (d+1)-dimensional, prin dublarea primului i prin realizarea legturilor ntre nodurile corespunztoare din cele doua cuburi d-dimensionale. Indexul nodurilor din primul cub se extinde prin adugarea cifrei semnificative 0, iar indexul nodurilor din cel de al doilea prin adugarea bitului semnificativ 1. Hipercubul este popular datorit regularitii structurii, diametrului redus (egal cu log p) i datorit abilitii de a manevra simplu i rapid multe calcule. Pentru exemplul pe care l rezolvm aici, fiecare element A[i] al tabloului cu n elemente este memorat ntr-un nod P[i] al hipercubului cu n noduri (n=2d). Algoritmul de calcul al sumei consta din d iteraii i memoreaz rezultatul n P[0]. Primul pas const n nsumarea elementelor care se afl n noduri ai cror indeci difer prin cifra cea mai semnificativ. Valorile sunt memorate n cubul (d-1)-dimensional cu nodurile avnd indecii cu cifra cea mai semnificativ egal cu zero. In cazul n care n=8, se realizeaz urmtoarele calcule: A[0] := A[0] + A[4] A[1] := A[1] + A[5] A[2] := A[2] + A[6] A[3] := A[3] + A[7] Celelalte iteraii continu dup reguli similare. Pentru exemplul ales avem: A[0] := A[0] + A[4] + A[2] + A[6] A[1] := A[1] + A[5] + A[3] + A[7] 60

iar n ultimul pas, n A[0] obinem ntreaga sum. In algoritmul urmtor, i(l) denot indexul obinut din i prin complementarea bitului l. Operaia A[i] := A[i] + A[i(l)] se face n doi pai: n primul pas, procesorul P[i] copiaz valoarea A[i(l)] preluat de la procesorul P[i(l)] pe legtura dintre cele dou; n al doilea pas, P[i] face adunarea i memoreaz suma in A[i].
var A: array [0:n-1] of real; /* n = 2d */ fa i := 0 to n-1 do in parallel fa l := d-1 to 0 -> if i <= 2l - 1 -> A[i] := A[i] + A[i(l)] fi af af

Algoritmul se termin n O(log n) uniti de timp, la fel ca i implementarea PRAM. Problem. Descriei algoritmul de nsumare pentru cazul n care numrul de procesoare p este mai mic dect numrul de elemente n i fiecare nod memoreaz n/p elemente ale tabloului A. 3.8. Execuia programelor distribuite In cazul programelor distribuite, timpul total de execuie se definete ca timpul scurs

Figura 3.8 (Foster 1995) 61

din momentul cnd primul procesor ncepe execuia sa (mai precis a unuia din procesele programului distribuit) pn n momentul n care ultimul procesor termin execuia. n evoluia unui proces se disting mai multe perioade: de calcule, de comunicare i de inactivitate, astfel c timpul total de execuie se exprim ca suma timpilor de calcul (Tcomp), de comunicare (Tcommun) si de inactivitate (Tidle) raportat la numarul de procesoare (P): sau unde: T = (1/P) (Tcomp + Tcommun + Tidle) T = (1/P) ( i=0,P-1 Ticomp + i=0,P-1 Ticommun + i=0,P-1 Tiidle) Ticomp = timpul total de calcul pe procesorul i Ticommun = timpul total de comunicare al procesorului i Tiidle = timpul total de inactivitate al procesorului i.

n calculul analitic al timpului total de execuie, se neglijeaz, de regul, timpul de inactivitate. Timpul de calcul depinde de dimensiunea problemei, N, numarul de taskuri sau de procesoare si de caracteristicile procesoarelor si memoriei. Timpul de comunicare este timpul consumat pentru transmiterea i pentru recepia mesajelor. Acetia difer de la un tip de comunicaie la alta; astfel, dac dou procese sunt executate de procesoare diferite, comunicarea ntre ele are o durat mai mare (comunicarea ntre procesoare consum mai mult timp); comunicarea ntre dou procese executate de acelai procesor este mai eficient (consum mai puin timp). Pentru simplificare, se consider c cele dou tipuri de comunicri au durate comparabile i se utilizeaz o formul comun de calcul. Timpul de comunicare a unui mesaj (transmitere sau recepie) are dou componente: ts - corespunde timpului consumat de operaiile de pregtire a comunicrii i este independent de lungimea mesajului; tw corespunde timpului de comunicare a unui cuvnt din mesaj. Cu acestea, timpul de comunicare a unui mesaj de lungime L devine: Tmsg = ts + twL Formula este confirmat experimental (Foster 1995) prin msurarea duratei transmisiei dus-ntors a unui mesaj (round-trip time). 62

ntr-un model de cost mai detaliat, se poate lua n considerare competiia ntre procese pentru comunicarea pe un acelai canal. Evident aceast competiie lungete timpul de comunicare. Daca S procese vor sa utilizeze n acelai timp un canal, durata comunicarii efective se mrete de S ori (evident, timpul de pregtire nu este afectat): Tmsg-b = ts + twSL Valoarea lui S difer de 1 doar dac cele S procese transmit n acelai sens pe un canal, aa cum se arat n Figura 3.9: n cazul (b), P0 i P1 partajeaz canalul (P1,P2), n timp ce n cazul (c), P0 i P3 transmit n sensuri diferite pe acest canal i se consider c transmisiile nu interfer.

(a) S = 1

(b) S = 2 Figura 3.9 (Foster 1995)

(c) S = 1

Ca aplicaie, considerm algoritmul lui Floyd pentru calculul drumurilor celor mai scurte ntr-un graf reprezentat prin matricea de adiacene I, a crui variant secvenial este urmtoarea:
fa k := 0 to N-1 -> fa i := 0 to N-1 -> fa j := 0 to N-1 -> I[i,j]k+1 = min(I[i,j]k, I[i,k]k + I[k,j]k) af af af

63

Dac tc este durata unei iteraii n algoritmul precedent, timpul total de execuie al algoritmului secvenial este: Tsecv = tc N3 Vom analiza dou variante distribuite, ambele folosind P procesoare. n prima variant, se face o descompunere uni-dimensional a matricei I n P grupuri de linii (fiecrui procesor i se asociaz N/P linii). Algoritmul poate folosi cel mult N procesoare, deci ntotdeauna numrul de procesoare este mai mic dact dimensiunea matricei, P<N. Fiecare procesor pstreaz local una sau mai multe linii din I i este responsabil de calculul valorilor elementelor din liniile respective. Dac procesorul p pstreaz liniile de la p_i_start la p_i_end atunci codul su se poate descrie n felul urmtor:
fa k: = 0 to N-1 -> fa i = p_i_start to p_i_end -> fa j = 0 to N-1 -> I[i,j]k+1 = min(I[i,j]k, I[i,k]k + I[k.j]k) af af af

Figura 3.10 (Foster 1995) n pasul k, procesoarele au nevoie de linia k a matricei Ik (Figura 3.10). Procesorul care pstreaz aceast linie o comunic n log P pai folosind algoritmul de difuzare, nainte ca fiecare din celelalte procesoare s nceap calculul liniilor matricei Ik+1 de care rspund. Deoarece fiecare mesaj are N cuvinte, timpul de difuzare a unei linii este: log P ( ts + twN). 64

Timpul total de execuie al acestei variante distribuite este: Tdist-1 = tc N3/P + N log P ( ts + twN) El este compus din timpul de calcul tc N3/P, care este timpul algoritmului secvenial mprit la numarul de procesoare plus timpul de comunicare N log P ( ts + twN), care este de N ori timpul de difuzare a unei linii. n a doua variant, facem o descompunere bi-dimensional, pe linii i coloane: fiecare procesor pstreaz local elementele aflate pe una sau mai multe linii i simultan pe una sau mai multe coloane din I i este responsabil de calculul valorilor elementelor din liniile i coloanele respective. Evident, numarul de procesoare P nu poate fi mai mare de N2. Cele P procesoar se dispun ntr-o matrice de P linii pe P coloane. Dac procesorul p pstreaz elementele aflate pe liniile de la p_i_start la p_i_end i simultan pe coloanele de la p_j_start la p_j_end atunci codul su se poate descrie n felul urmtor:
fa k := 0 to N-1 -> fa i := p_i_start to p_i_end -> fa j := p_j_start to p_j_end -> I[i,j]k+1 = min(I[i,j]k, I[i,k]k + I[k,j]k) af af af

Figura 3.11 (Foster 1995) n fiecare pas k, fiecare proces are nevoie de datele sale locale i de cte N/P valori de la alte dou procese care pstreaz: 65

- elementele din linia k i coloanele de la p_j_start la p_j_end - elementele din coloana k i liniile de la p_i_start la p_i_end. Fiecare din cele dou mesaje are N/P elemente, astfel nct difuzarea unuia dureaz log P ( ts + twN/P) deoarece difuzarea se face unui numr de P procese. n cei N pai, operaia se repet de 2N ori. Ca urmare, timpul total de execuie: Tdist-2 = tc N3/P + 2N log P ( ts + twN/P) = tc N3/P + N log P ( ts + twN/P).

3.9. Modelul LogP Un model mai adecvat studiului performanelor pe maini reale este LogP (Figura 3.12). P M overhead latena L Reea de interconectare Figura 3.12 Modelul LogP Modelul consider P procesoare, fiecare cu memoria sa local, legate printr-o reea de interconectare. Parametrii modelului sunt: L latena, sau ntrzierea de transmitere a unui mesaj coninnd un numr mic de cuvinte, de la procesorul / memoria surs la destinatar o - overhead, durata pentru care procesorul este angajat n transmiterea sau recepia fiecrui mesaj; n timpul acesta procesoul nu poate face alte operaii 66 P M gap g P M overhead

g - gap, intervalul minim de timp ntre dou transmiteri succesive sau dou recepii succesive la acelai modul P - numrul de module procesor / memorie.

Reeaua are o capacitate limitat, astfel c cel mult sup(L/g) mesaje pot fi n tranzit la un moment dat, de la orice procesor sau la oricare procesor. Cea mai simpl operaie de comunicare, transmiterea unui singur pachet de la o main la alta, cere un timp de L+2o. O operaie cerere/rspuns, precum o citire sau o scriere blocant, ia un timp de 2L+4o. Fiecare procesor este implicat un timp de 2o, restul timpului putnd fi utilizat pentru calcul, sau pentru alte operaii de intrare/ieire. Ca aplicaie considerm difuzarea unei valori. Conform modelului PRAM, transmiterea are loc conform tiparului urmtor: P0 -> P1 de la P0 la P1 P0, P1 -> P2, P3 de la P0 i P1 la P2 i P3 P0, P1, P2, P3 -> P4, P5, P6, P7 ... Presupunnd g>=0 i lund P=8, o=2, g=4, L=6, obinem din calcul un timp total de difuzare egal cu 30 de unitai (Figura 3.13).

Figura 3.13. Schema de difuzare pentru tiparul PRAM 67

Pentru modelul LogP, adoptm convenia c orice procesor care primete o valoare, o transmite imediat altor procesoare, cu condiia ca nici un procesor s nu primeasc mai mult de o valoare. Graful corespunztor variantei optime este cel din figura 3.14. Timpul corespunztor este de 24 de uniti (Figura 3.15). 0 10 P5 14 P3 P0 18 P2 22 P1

P7

20

P6

24

24 P4

Figura 3.14. Graful variantei optime


P0 P1 P2 P3 P4 P5 P6 o o o o o o o o o o o o o

P7 o timp 02 04 06 08 10 12 14 16 18 20 22 24 26

Figura 3.15. Schema de difuzare pentru varianta optim

68

Capitolul 4. Dezvoltarea algoritmilor folosind variabile partajate


Una din problemele centrale ale dezvoltrii algortmilor folosind variabile partajate este sincronizarea, n cele dou forme cunoscute: excluderea mutual i sincronizarea condiionat. Prima form nseamn gruparea mai multor aciuni ale unui proces ntr-o singur aciune atomic, ascunznd astfel strile intermediare. Cea de a doua form presupune ntrzierea execuiei unui proces pn la ndeplinirea unei anumite condiii. Nu este, deci, de mirare c n istoria algoritmilor cu variabile partajate s-a consumat un efort considerabil pentru gsirea unor mecanisme de rezolvare sistematic a problemei sincronizrii, cteva rezultate notabile fiind reprezentate de: - semafoare, - regiuni critice, - monitoare. Cteva dintre problemele "clasice" rezolvate prin utilizarea acestora sunt: - productori-consumatori, - cititori-scriitori, - problema filozofilor, - problema brbierului. Fiecare din soluiile gsite i are importana sa deosebit, toate la un loc alctuind o "bibliotec" de modele de rezolvare aflate la dispoziia proiectanilor. nglobarea lor n soluiile diferitelor probleme nu este ntotdeauna o sarcin uoar, dac se urmrete obinerea unor variante eficiente. 4.1 Sectiuni critice Problema: fiecare proces P(i) al unei colectii de procese P(i:1..n) executa ciclic o sectiune critica in care are acces exclusiv la anumite resurse partajate urmata de o sectiune necritica in care foloseste doar resurse locale. Se utilizeaza tipul special sem si primitivele P si V. Rolul lor este asigurarea excluderii mutuale intre procesele care acceseaza sectiunea critica.
var mutex: sem := 1; P(i:1..n):: do true -> P(mutex);

69

od

Sectiune critica; V(mutex); Sectiune necritica

4.2 Producatori si consumatori Problema: se considera mai multi producatori si mai multi consumatori care comunica printr-un singur tampon partajat. Un producator pune o valoare in tampon, iar un consumator ia o valoare din tampon. Trebuie asigurat ca valorile nu sunt suprascrise si nu sunt citite din tampon de mai multe ori.
var buf: T; var gol: sem := 1; plin: sem := 0; Producator (i: 1..M):: var v: T; do true -> v := produce (); P(gol); buf := v; V(plin) od; Consumator (i: 1..N):: var w: T; do true -> P(plin); w := buf; V(gol); consuma (w); od;

Semafoarele gol si plin sunt binare si asigura excluderea mutuala. La un moment dat, un singur proces (fie Producator, fie Consumator) depune sau extrage o valoare din buf.

70

4.3 Comunicarea producator si consumator prin tampon limitat Un producator si un consumator care comunica printr-un tampon limitat la k valori.
var buf: array [1:k] of T; var gol: sem := k; plin: sem := 0; Producator:: var v: T; var ultim: int := 1; do true -> v := produce (); P(gol); buf[ultim] := v; ultim := ultim mod k + 1; V(plin) od; Consumator:: var w: T; var prim: int := 1; do true -> P(plin); w := buf[prim]; prim := prim mod k + 1; V(gol); consuma (w); od;

Semafoarele gol si plin sunt generale. Ele numara locurile goale din buf, respectiv valorile depuse in buf. Procesul Producator acapareaza un loc gol (daca nu exista atunci se blocheaza pana apare unul) si depune o valoare. Procesul Consumator acapareaza o valoare depusa (daca nu exista atunci se blocheaza pana apare una) si preia valoarea din buf. Operatiile de depunere si de extragere nu se exclud. Producator poate depune o valoare in pozitia ultim din buf in timp ce Consumator preia una din pozitia prim din buf. 4.4 Mai multi producatori si mai multi consumatori
var var var var buf: array [1:k] of T; prim: int := 1; ultim: int := 1; gol: sem := k; plin: sem := 0; mutexP: sem := 1; mutexC: sem := 1;

71

Producator(i:1..M):: var v: T; do true -> v := produce (); P(gol); P(mutexP); buf[ultim] := v; ultim := ultim mod k + 1; V(mutexD); V(plin) od; Consumator (i: 1..N):: var w: T; do true -> P(plin); P(mutexC); w := buf[prim]; prim := prim mod k + 1; V(mutexC); V(gol); consuma (w); od;

Variabilele prim si ultim au devenit partajate intre procesele Consumator respectiv Producator. Accesul si modificarea lor trebuie facute in excludere mutuala. Pentru aceasta se foloseste semaforul mutexP pentru procesele Producator, respectiv mutexC pentru procesele Consumator. 4.5 Problema filozofilor Cinci filozofi stau in jurul unei mese rotunde si isi petrec timpul gandind si mancand. In mijlocul mesei este o farfurie cu spaghete. Pentru a putea manca, un filozof are nevoie de doua furculite. Pe masa sunt cinci furculite, fiecare situate intre doi filozofi vecini. Regula este ca fiecare filozof poate folosi furculitele din imediata sa apropiere. Problema este sa se scrie un program care simuleaza comportarea filozofilor. In particular, trebuie evitata situatia in care nici un filozof nu poate acapara ambele furculite (de exemplu furculita din stanga sa si nu ii mai da drumul).
var f: array [1:5] of sem := ([5] 1); Filozof (i:1..4):: do true -> P(f[i]); P(f[i+1]);

72

od;

mananca; V(f[i]); V(f[i+1]); gandeste

Filozof (5):: do true -> P(f[1]); P(f[5]); mananca; V(f[1]); V(f[5]); gandeste od;

Daca toti filozofii ar lua mai intai furculita din stanga si apoi pe cea din dreapta se poate ajunge la blocare definitiva prin asteptare circulara: fiecare asteapta o resursa pe care procesul care a acaparat-o nu o elibereaza. Solutia ca sa se evite asteptarea circulara este ca unul din filozofi sa procedeze altfel si anume sa ia mai intai furculita din dreapta si apoi pe cea din stanga. 4.6 Problema cititorilor si scriitorilor Problema: exista doua tipuri de procese, cititori si sciitori care impart o resursa. Mai multi cititori pot avea acces simultanla resursa comuna daca nici un scriitor nu o modifica in acelasi timp. Un scriitor poate modifica resursa daca ea nu este acesata de nici un cititor.
var nr: int := 0; mutexR: sem := 1; rw: sem := 1; Cititor (i: 1..m):: do true -> P(mutexR); nr := nr+1; if nr = 1 -> P(rw) fi; V(mutexR); citeste din resursa comuna; P(mutexR) nr := nr-1; if nr = 0 -> V(rw) fi; V(mutexR); od; Scriitor (j: 1..n):: do true ->

73

od;

P(rw); scrie in resursa comuna; V(rw);

Algoritmul tine evidenta numarului de cititori nr care folosesc resursa. Solutia acorda preferinta cititorilor: daca un cititor acapareaza resursa, alti cititori pot sa i se alature si sa citeasca. Doar cand ultimul cititor a terminat, resursa este eliberata (V(rw)). Pentru a aplica alte politici, se introduc alte variabile de contorizare a cititorilor si scriitorilor: nw - numarul de scriitori care folosesc resursa nr - numarul de cititori care folosesc resursa dw - numarul de scriitori care asteapta sa foloseasca resursa dr - numarul de cititori care asteapta sa foloseasca resursa. "Split binary semaphore": folosit pentru a implementa atat excluderea mutuala cat si sincronizarea conditionata. Implementat astfel: e semafor de intrare controleaza intrarea intr-o actiune atomica r semafor pentru intarzierea cititorilor (asteapta ca nw=0) w semafor pentru intarzierea scriitorilor (asteapta ca nw=0 si nr=0) Semafoarele formeaza impreuna un "split binary semaphore": - cel mult un semafor este 1 la un moment dat 0<=e+r+w<=1 - fiecare cale de executie incepe cu un P si se termina cu un singur V - instructiunile intre P si V se executa in excludere mutuala. Tehnica se numeste "pasarea stafetei": - initial un semafor este 1 si un proces poate prelua stafeta printr-o operatie P asupra semaforului - cand un proces detine stafeta (se executa intr-o sectiune critica si toate semafoarele sunt 0), el poate pasa stafeta altui proces printr-o operatie V asupra unuia din cele trei semafoare. Varianta urmatoare da preferinta cititorulor asupra scriitorilor.
var nr: int := 0; nw: int := 0; /*(nr=0 or nw=0) and nw<=1*/ var e: sem := 1; r: sem := 0; w: sem := 0; /* 0<=e+r+w<=1*/

74

var dr: int := 0; dw: int := 0; Cititor (i: 1..m):: do true -> P(e); if nw>0 -> dr := dr+1; V(e); P(r) fi; nr := nr+1; if dr>0 -> dr := dr-1; V(r) [] dr=0 -> V(e) fi; citeste din resursa comuna; P(e) nr := nr-1; if nr = 0 and dw>0 -> dw := dw-1; V(w) [] nr>0 or dw=0 -> V(e) fi; od; Scriitor (j: 1..n):: do true -> P(e); if nr>0 or nw>0 -> dw := dw+1; V(e); P(w) fi; nw := nw+1; V(e); scrie in resursa comuna; P(e) nw := nw-1; if dr>0 -> dr := dr-1; V(r) [] dw>0 -> dw := dw-1; V(w) [] dr=0 and dw=0 -> V(e) fi; od;

In solutia urmatoare se prezinta o alta varianta in care: - noile cereri de la cititori sunt intarziate daca un scriitor asteapta - un cititor intarziat este trezit doar daca nu exista un scriitor in asteptare.
var nr: int := 0; nw: int := 0; /*(nr=0 or nw=0) and nw<=1*/ var e: sem := 1; r: sem := 0; w: sem := 0; /* 0<=e+r+w<=1*/ var dr: int := 0; dw: int := 0; Cititor (i: 1..m)::

75

do true -> P(e); if nw>0 or dw>0 -> dr := dr+1; V(e); P(r) fi; nr := nr+1; if dr>0 -> dr := dr-1; V(r) [] dr=0 -> V(e) fi; citeste din resursa comuna; P(e) nr := nr-1; if nr = 0 and dw>0 -> dw := dw-1; V(w) [] nr>0 or dw=0 -> V(e) fi; od; Scriitor (j: 1..n):: do true -> P(e); if nr>0 or nw>0 -> dw := dw+1; V(e); P(w) fi; nw := nw+1; V(e); scrie in resursa comuna; P(e) nw := nw-1; if dr>0 and dw=0 -> dr := dr-1; V(r) [] dw>0 -> dw := dw-1; V(w) [] dr=0 and dw=0 -> V(e) fi; od;

76

Capitolul 5. Accesul concurent la o structur de date


Rezolvarea conflictelor de acces concurent la o structur complex de date se poate face ineficient, impunnd restricii de excludere mutual la nivelul ntregii structuri, sau eficient, reducnd restriciile la minimul necesar. Ilustrm n continuare acest aspect, prin prezentarea operaiilor concurente de acces la cozile de prioriti. Cozile de prioriti au numeroase aplicaii de la cele de simulare discret la gsirea drumurilor minime ntr-un graf. Operaiile de baz asupra unei cozi de prioriti sunt: - nscrierea unui element n coad (enqueue); - extragerea primului element (cel mai prioritar) din coad (dequeue). Prin convenie, prioritile sunt numere reale, iar prioritatea mai mare este reprezentat printr-o valoare mai mic. Deoarece multe aplicaii ale cozilor de prioriti se desfoar n medii MIMD (multiprocesaore cu memorie partajat), este important gsirea unor soluii ct mai puin restrictive n privina excluderii mutuale a proceselor care utilizeaz n comun o coad de prioriti. Timpul necesar unei operaii de introducere n coad, urmat de o extragere nu poate fi mai bun de O(log n). Exist mai multe implementri posibile ale cozilor de prioriti. Cele mai multe folosesc n reprezentare arbori binari ordonai. Unele dintre ele calculeaz noua rdcin a arborelui ce reprezint coada abia la sfritul procedurior de inserare i extragere. Ca urmare, este necesar utilizarea exclusiv a acestor rdcini pentru ntreaga durat a operaiilor. Alte implementri (cum ar fi, de exemplu, heap-ul implicit) nu convin deoarece introducerea n coad implic o cutare ascendent (dinspre o frunz a arborelui), iar extragerea din coad implic o cutare descendent (dinspre rdcina arborelui). Dac excluderea mutual asupra elementelor din heap este cerut pe msur ce operaiile de introducere i de extragere avanseaz, apare pericolul blocrii definitive, la o coliziune ntre cutrile ascendente i descendente. O implementare care nu prezint neajunsurile precedente este varianta descendent a heap-urilor oblice (skew heap). O coad de prioriti este reprezentat ca un arbore binar ordonat, adic un arbore n care prioritatea unui nod este mai mare dect prioritatea oricrui descendent. 77

Extragerea din coad ntoarce rdcina i apoi combin cei doi sub-arbori rmai. Introducerea n coad consider elementul de introdus ca un arbore pe care-l combin cu arborele ce reprezint coada. Combinarea se face prin interclasarea ramurilor din dreapta ale celor doi arbori, de la rdcin n jos, schimbndu-se ntre ei fiii din stnga i din dreapta ai fiecrui nod vizitat. Interschimbarea fiilor asigur limitarea costului amortizat al combinrii la O(log n) pentru un arbore cu n elemente. Obinerea variantei paralele a implementrii pornete de la versiunea serial recursiv propus de Sleator i Tarjan.

78

type ref = ^nod; nod = rec ( stg, dr: ref; prio: real;); coada = ref; procedure rcomb (q1, q2: ref) returns q: ref; procedure rxcomb (q1, q2: ref) returns q: ref; var temp: ref; if q1 = nil -> q := q2 [] q1 <> nil -> if q1^.prio > q2^.prio -> q1 :=: q2 fi q := q1; temp := q1^.dr; q1^.dr := q1^.stg; q1^.stg := rxcomb (temp, q2); fi end; if q2 = nil -> q := q1 [] q2 <> nil -> q := rxcomb (q1, q2) fi end; procedure enqueue (n: ref, q: coada) returns q1: coada; n^.stg := nil; n^.dr := nil; q1 := rcomb (n, q); end; procedure dequeue (var q: coada) returns n: ref; n := q; q := rcomb (q^.stg, q^.dr); end;

Dup cum se vede, responsabilitatea alocrii i dealocrii nodurilor este lsat utilizatorului. Ambele operaii asupra cozii de prioriti apeleaz funcia de combinare rcomb. Aceasta verific dac cel de al doilea sub-arbore este vid, caz n care rezultatul este imediat. n caz contrar, se apeleaz rxcomb, care repreazint partea central a algoritmului. Funcia este recursiv, ieirea din recursivitate fcndu-se atunci cnd sub-arborele stng devine vid (q1=nil). Aceast condiie este suficient, deoarce funcia menine n q1 pointerul nodului cu prioritatea mai mare (vezi interschimbul lui q1 i q2), iar algoritmul de interclasare selecteaz ntotdeauna acest nod (q:=q1). Dup mutarea sub-arborelui din stnga lui q1 n dreapta, el adaug n stnga rezutatul combinrii lui q2 cu fostul sub-arbore drept al lui q1 (temp). 79

Figura 5.1 prezint scoaterea unui nod din coada de prioriti.


q[]->--+ v +------*-------+ |2 1 |3 +---*---+ +---*--+ |4 | |6 |7 +---*---+ *5 +--*--+ * |8 |9 | | +-*-+ +-* * * | | | 10 11 * * * 12 13 14 (a) iniial

q1 []->-+ v 2 +---*---+ |4 | +---*---+ *5 |8 |9 +-*-+ +-* | | | * * * 12 13 14

q2 []->+ v 3 +---*--+ |6 |7 +--*--+ * | | * * 10 11

(b) la apelul lui rxcomb

+---------------------------+ |temp []->+ q2 []->+ | q []--->----+ | | v 3 | q1[]--->---+| | *5 +---*--+ | |2 | |6 |7 | +----*---+ | +--*--+ * |------->* |4 | | | |rxcomb +---*---+ | * * |(temp,q2) |8 |9 | 10 11 | +-*-+ +-* +---------------------------+ | | | * * * 12 13 14

(c) la prima iteraie, imediat nainte de apelul recursiv


q []->-+ |2 +----*-------------+ |3 |4 +---*---+ +----*-----+ |5 |6 |8 | +--* +--*--+ +--*---+ +-*9 | | | | | | * * * * * * 7 10 11 12 13 14

d) dup dequeue
Figura 5.1

80

Dei n aceast variant se calculeaz valoarea q ntoars de rxcomb nainte de apelul recursiv, ea nu este folosit efectiv dect dup apel. Ca urmare, procesul utilizator trebuie s menin accesul exclusiv la elementul care va primi aceast valoare pe ntreaga durat a operaiei de combinare. Aceast cerin ar putea fi eliminat dac valoarea ar fi ntoars printr-unul din parametri, ca efect lateral.
procedure rcomb (var q: ref; q1, q2: ref); procedure rxcomb (var q: ref; q1, q2: ref); var temp: ref; if q1 = nil -> q := q2 [] q1 <> nil -> if q1^.prio > q2^.prio -> q1 :=: q2 fi q := q1; temp := q1^.dr; q1^.dr := q1^.stg; call rxcomb (q1^.stg, temp, q2); fi end; if q2 = nil -> q := q1 [] q2 <> nil -> call rxcomb (q, q1, q2) fi end; procedure enqueue (n: ref, var q: coada); n^.stg := nil; n^.dr := nil; call rcomb (q, n, q); end; procedure dequeue (var q: coada) returns n: ref; n := q; call rcomb (q, q^.stg, q^.dr); end;

Varianta actual a lui enqueue are o specificaie diferit de cea anterioar. De data aceasta, ea modific referina q ctre coad, n loc s produc o nou referin. Codul este recursiv, dar se poate deduce uor i o variant iterativ a sa, deoarece apelul recursiv este la sfritul procedurii rxcomb. Varianta concurent a implementrii poate fi obinut plecnd de la noua variant descris i de la observaia c, n orice moment, procedura rxcomb pstreaz referinele a trei entiti: - q1 i q2 conin pointerii rdcinilor sub-arborilor care se combin; 81

- q reprezint fie un pointer la rdcin, fie pointerul stnga al celui mai din stnga element n arborele actualizat. Ct timp procesul care opereaz asupra cozii menine accesul exclusiv asupra acestor trei elemente, mai multe procese vor fi capabile s execute simultan operaii asupra aceleiai cozi fr s interfere unul cu altul. Varianta urmtoare folosete pentru sincronizare primitivele P i V, precum i cte un semafor, mutex, pentru fiecare entitate de tip nod sau coada. Semaforul mutex dintr-un nod protejeaz referinele stg i dr memorate n nodul respectiv. Similar, semaforul mutex dintr-o variabil de tip coada protejeaz referina cap la primul element din coad i nu nodul aflat n vrful cozii. Fiecare variabil de tip coad conine i un semafor contor, folosit pentru a rezolva o problem productor-consumator. Valorile iniiale ale semafoarelor sunt specificate n comentarii. Semafoarele sunt manipulate doar prin codul prezentat. De asemenea, accesul proceselor la cozi este permis doar prin operaiile enqueue i dequeue descrise.
type ref = ^nod; nod = rec ( stg, dr: ref; mutex: sem; {semafor binar, iniial 1} prio: real;); coada = rec (cap: ref; mutex: sem; {semafor binar, iniial 1} contor: sem;); {semafor general, iniial 0} procedure rcomb (var q: ref; var mutex: sem; q1, q2: ref); procedure rxcomb (var q: ref; var mutex: sem; q1, q2: ref); var temp: ref; {1} if q1 = nil -> q := q2 V(mutex); [] q1 <> nil -> {2,3} if q1^.prio > q2^.prio -> q1 :=: q2 fi {4} q := q1; {5} P(q1^.mutex); {6} V(mutex); temp := q1^.dr; q1^.dr := q1^.stg; {7} call rxcomb (q1^.stg, q1^.mutex, temp, q2); fi end; {rxcomb} {8} if q2 = nil -> q := q1; V(mutex);

82

[] q2 <> nil -> call rxcomb (q, mutex, q1, q2) fi end; procedure enqueue (n: ref, var q: coada); n^.stg := nil; n^.dr := nil; {9} P(q.mutex); V(q.contor); {adaug un element n coad} call rcomb (q.cap, q.mutex, n, q.cap); end; procedure dequeue (var q: coada) returns n: ref; P(q.contor); {cnd coada nevid, ia un element} {10} P(q.mutex); {11} P(q.cap^.mutex); {12} V(q.cap^.mutex); n := q.cap; call rcomb (q.cap, q.mutex, q.cap^.stg, q.cap^.dr); end;

Despre corectitudinea soluiei Ne referim n continuare la problemele de corectitudine relative la accesul concurent al mai multor procese la o coad. Fiecare proces ce execut o operaie de introducere sau de extragere a unui element poate fi vzut ca o "bul" de excludere mutual care parcurge arborele de la rdcin spre frunze. Aceasta asigur evitarea blocrilor definitive. Toate modificrile pe care un proces le face unui arbore se plaseaz n interiorul acestei "bule", care pstreaz controlul exclusiv al (cel puin) unui nod sau a (cel mult) dou noduri. Ultima condiie este asigurat de ordinea liniilor 5 i 6 ale algoritmului. Elementele sunt adugate "bulei" (prin operaia P asupra semaforului asociat) nainte de inspectarea i modificarea referinelor pe care le conin. Elementele nu sunt niciodat eliberate din bul (prin operaia V) nainte ca modificrile asupra lor s fi fost fcute. Urmtorii invariani descriu "bula" de excludere mutual la intrarea n rcomb i rxcomb (liniile 1 i 8 ale algoritmului): - procesul curent are acces exclusiv la variabila pointer q, astfel c semaforul mutex asociat este zero; - q1 i q2 conin referine la care nu au acces alte procese (n afara procesului curent). 83

/ \ / \ "bula" ----+/ \ +-------------------/| \ | q1 q2 q->* || \ | * * \| \ +--|-----|----------+ \ \ +----+ +----+ --+ \ \ v v \ n afara \ / \ / \ \ interesului \ / \ / \ -----------------------------de modificat

Figura 5.2 n apelul lui rcomb, primul invariant este asigurat n liniile 9 i 10 prin P(q.mutex). n rcomb, acest invariant nu este modificat pe ramura care duce la rxcomb, iar n rxcomb el este asigurat, nainte de apelul recursiv la rxcomb din linia 7, prin operaia P din linia 5, deoarece q1^.mutex protejeaz q1^.stg. Al doilea invariant este asigurat n enqueue prin operaia P din linia 9 (q2 primete ca valoare referina q.cap protejat de q.mutex) i prin presupunerea c procesul curent are exclusivitate asupra noului element. n dequeue, invariantul este asigurat prin operaia P din linia 11, care permite accesul exclusiv la referinele q.cap^.stg i q.cap^.dr ale elementul din faa cozii. n mod ciudat, este corect i sigur s se renune imediat la accesul exclusiv asupra fostului cap (linia 12). Dei pare fr sens, seciunea critic "vid" mrginit de liniile 11 i 12 este esenial pentru a asigura c oricare alt proces ce ar modifica fostul vrf al cozii a terminat operaiile asupra lui, nainte ca procesul care execut dequeue s continue. Operaia V din linia 12 nu este absolut necesar, accesul exclusiv la fostul cap putnd fi nlturat oricnd, dar n orice caz nainte de o eventual reintroducere n coad a elementului. 84

Al doilea invariant nu este modificat pe calea de la rcomb la rxcomb i este pstrat pe calea de la intrarea lui rxcomb la apelul recursiv din linia 7. Interschimbul lui q1 cu q2 (linia 2) nu modific invariantul. Dac un pointer la q2 rmne n coad, el este distrus prin atribuirea din linia 4 naintea operaiei V pe semaforul asociat (linia 6). n fine, noua valoare a lui q1 (adic temp) este folosit doar dup operaia P a semaforului corespunztor (linia 5): temp provine din q1^.dr care este protejat de q1^.mutex. Singura problem ar putea apare de la operaia V(mutex) din linia 6, care ridic restricia asupra lui q. Poate q conine o referin egal cu q2, la care un alt proces s capete acces ? Rspunsul se afl n linia 4 unde q devine egal cu q1 nainte de ridicarea restriciei. Serializarea acceselor concurente n modelul de prelucrare paralel pe care l-am adoptat, se presupune c execuia unui program paralel apare ca o ntreesere a aciunilor diferitelor procese ale sale. n acest sens, o ntrebare fireasc se refer la utilizarea concurent a unei structuri partajate: poate proiectantul s presupun c un grup de operaii concurente asupra structurii au acelai efect ca i cel al execuiei secveniale a operaiilor din grup? Cu alte cuvinte, sunt serializabile operaiile concurente asupra structurii? n cazul unei structuri la care excluderea se refer global, la ntreaga structur, rspunsul este simplu. n alte cazuri, analiza trebuie s fie mai atent. Pentru exemplul dat, trebuie s observm c operaiile executate de mai multe procese n paralel sunt serializate n ordinea n care procesele capt accesul exclusiv asupra pointerului la rdcin. Aceasta rezult din faptul c "bula" de excludere mutual deinut de un proces izoleaz toate elementele din coad ce urmeaz a fi inspectate de acel proces, fa de celelalte procese care ncep operaii asupra cozii la momente ulterioare. Procesele ulterioare pot modifica doar acele elemente care nu mai intereseaz procesul curent. Pe de alt parte, procesele sosite mai devreme au terminat deja modificrile unui element, n momentul cnd procesul curent face acces la el. Ca urmare, dei se poate ca structura n totalitate s nu fie ntr-o stare corespunztoare terminrii complete a unei operaii nainte de nceperea alteia, prile necesare noii operaii sunt deja actualizate conform acelei stri. Eficiena soluiei Deoarece, pentru fiecare nod vizitat, se interschimb subarborii stng i drept, operaiile succesive asupra cozii de prioriti viziteaz noduri diferite. Aceasta conduce la un grad redus de conflicte n accesul la nodurile structurii, pentru procese 85

cu viteze de execuie comparabile. Singurul semafor binar mai frecvent utilizat este cel corespunztor pointerului ctre rdcina arborelui. Acest pointer este ns inut un timp relativ scurt, fiind eliberat n linia 6 a procedurii rxcomb. Acest argument sugereaz c aceast implementare reduce timpul cu care nceperea execuiei unei operaii este ntrziat de la O(n) la O(1), ntr-un mediu MIMD n care procesele au viteze comparabile. Timpul maxim ct un proces deine accesul exclusiv la pointerul rdcinii este determinat de calea de la operaia P din linia 10 la operaia V din linia 6 a lui rxcomb. Ea numr cinci atribuiri 3 teste, 2 apeluri, 2 operaii P i o operaie V. Aa cum s-a argumentat mai nainte, operaiile P sunt rareori blocante. Cozile de prioriti pot fi utilizate n aplicaii cum sunt gsirea drumurilor minime sau a arborelui de acoperire ale unui graf. Tiparul general de utilizare este urmtorul:
do not gata -> elem := dequeue (q); actualizeaz (elem); genereaz (elemente_noi); fa i := 1 to nr_elem_nou_generate -> enqueue (elem_nou[i], q); af od

Un acelai tipar se ntlnete n cazul aplicaiilor de simulare conduse de evenimente, n care se extrage un eveniment dintr-o coad de evenimente, se prelucreaz evenimentul actualizndu-se starea modelului, se genereaz noi evenimente i se nregistreaz aceste evenimente n coad. nregistrarea noilor elemente n coad poate fi dat n sarcina mai multor procese, desfurndu-se concurent. Deoarece crearea i distrugerea proceselor pot fi costisitoare, se recurge adesea la o colecie fix de procese care, n urma solicitrior primite, fac nregistrrile necesare.

86

Capitolul 6. Dezvoltarea aplicaiilor pentru calculatoare SM SIMD


O clas important de sisteme paralele este cea care corespunde modelului SIMD cu memorie partajat (Shared Memory SIMD). Ele sunt cunoscute i sub denumirea de PRAM (Parallel Random Access Machines). n funcie de modul de acces la memorie pentru operaiile de citire i scriere, sistemele SM SIMD se subdivid n: - EREW (Exclusive Read Exclusive Write); - CREW (Concurrent Read Exclusive Write); - ERCW (Exclusive Read Concurrent Write); - CRCW (Concurrent Read Concurrent Write). Descrierea urmrete prezentarea unor metode generale de dezvoltare a algoritmilor paraleli (partiionarea, divide et impera) i a unei abordri posibile pentru obinerea algoritmilor cost-optimali. Cteva caracteristici importante ale algoritmilor SM SIMD sunt urmtoarele: algoritmii indic aciunile executate de procesoare (n general, fiecare procesor este dedicat execuiei aciunilor unui proces) algoritmii expliciteaz separat aciunile de citire i cele de scriere (pentru a putea aprecia costul operaiilor n raport cu categoriile de sisteme PRAM menionate) lansarea i terminarea proceselor au "overhead" redus (instruciuni co ... oc pot fi incluse n cicluri) algoritmii se ncadreaz, de obicei, n clasa "fine grain" (granularitate fin).

Aceste caracteristici sunt subliniate prin notaia specific PRAM, care a fost prezentat n capitolul 2 al lucrrii. 6.1. Proprietile (dorite ale) algoritmilor paraleli Numr de procesoare n cele ce urmeaz, n reprezint dimensiunea problemei, iar p(n) este numrul de procesoare utilizate la execuia algoritmului. Numrul de procesoare trebuie s ndeplineasc urmtoarele cerine: - p(n) trebuie sa fie mai mic dact n Este nerealist s presupunem c avem n procesoare. Uzual se ia p(n) ca funcie sublinear de n (de exemplu, log n sau sqrt(n)) - p(n) trebuie s fie adaptiv 87

Algoritmul nu trebuie s depind de un numr fix de procesoare. Timp de execuie n cele ce urmeaz, t(n) este timpul de execuie n funcie de dimensiunea problemei. Condiiile sunt urmtoarele: - t(n) s fie mic, semnificativ mai mic dect timpul de execuie al variantei secveniale - t(n) sa fie adaptiv, i s fie invers proportional cu p(n) Cost n cele ce urmeaz, c(n) este costul algoritmului c(n) = t(n) * p(n). Condiiile sunt urmtoarele: - c(n) s fie minim deci algoritmul s fie cost-optimal. Exemplu Algoritmul de selecie a unei valori din secvena S = {s1, ..., sn}, prezentat mai departe n acest capitol, se execut pe o main EREW SM SIMD cu N procesoare, unde N<n. Algoritmul are proprietile formulate mai nainte. (i) Algoritmul folosete p(n) = n1-x procesoare, cu 0<x<1, unde valoarea lui x se obine din formula N = n1-x. Deci, p(n) este subliniar i adaptiv. (ii) Algoritmul se execut n t(n) = O(nx), cu x obinut ca mai sus. Deci, timpul de execuie este mai scurt dect cel al unui algoritm secvenial. Totodat, algoritmul este adaptiv: cu ct este mai mare p(n), cu att este mai mic t(n). (iii) Costul este c(n) = n1-x * O(nx) = O(n), ceea ce reprezint un optim. Observaii i) Satisfacerea cerinelor menionate este dificil, uneori imposibil. ii) In practic, pentru valorile c(n), p(n), t(n) se consider valorile rotunjite obinute printr-o estimare pesimist.

88

6.2. Dou proceduri utile Dou operaii tipice apar n execuia algoritmilor paraleli n sisteme EREW SIMD: - fiecare procesor trebuie s citeasc coninutul unei celule din memoria comun (difuzarea unei valori); - fiecare procesor trebuie s calculeze valoarea unei funcii dependente de datele deinute de celelalte procesoare (calcule prefix). Difuzarea unei valori Fie D celula din memoria comun ce trebuie difuzat celor N procesoare ale unui sistem EREW SIMD. Algoritmul BROADCAST presupune folosirea unui tablou A[1:N]. Aciunile de citire i de scriere sunt explicitate distinct i explicit n descrierea algoritmului. Acest tratament este specific sistemelor PRAM.
procedure BROADCAST (D, N, A) Pas 1: Procesorul P1 1.1. citete valoarea din D 1.2. o memoreaza n propria memorie 1.3. o scrie n A[1] Pas 2: fa i := 0 to (log N -1) -> fa j := 2i+1 to 2i+1 do in parallel Procesor Pj 2.1. citete valoarea din A[j-2i] 2.2. o memoreaz n propria memorie 2.3. o scrie n A[j] af af end

Aciunile de citire i de scriere sunt specificate distinct i explicit n descrierea algoritmului, iar paii executai sincron de procesoare sunt foarte bine precizai. Observaii - Deoarece numrul de procesoare care dein valoarea din D se dubleaz la fiecare iteraie, timpul de execuie este O(log N). - Dimensiunea tabloului A poate fi redus la N/2, valorile memorate n ultimul pas fiind inutile. - Utilizare tipic: difuzarea lui n, n cazul algoritmilor adaptivi. 89

Calculul sumelor prefix Fiind dat vectorul A[1:N], fiecare procesor Pi calculeaz suma A[1] + ...+ A[i]. Algoritmul este urmtorul:
procedure ALLSUMS (A) fa j = 0 to log N - 1 -> fa i = 2j+1 to N do in parallel Procesor P(i) 1. obine A[i-2j] de la P(i-2j), 2. A[i] := A[i-2j] + A[i] af af end

prin memoria comun

Observaie - Deoarece numrul procesoarelor care termin de calculat suma parial se dubleaz la fiecare pas, calculul se face n O(log N) pai folosind O(N) procesoare. 6.3. Cutarea paralel n cele ce urmeaz, prezentm soluia unei probleme de cutare a unei valori x ntr-o secven ordonat S de n valori, pentru o main SM SIMD. Pentru simplitate, considerm c elementele secvenei sunt toate distincte ntre ele, adic: s[1] < s[2] < ... < s[n]. Metoda secvenial de cutare binar const n compararea lui x cu elementul din mijlocul secvenei S. n funcie de rezultatul acestei comparaii, cutarea se termin sau continu cu una din cele dou jumti separate de elementul din mijloc. Algoritmul are complexitatea O(log n). S considerm mai nti cazul unui sistem EREW format din N procesoare, 1<=N<=n. Pentru a face cunoscut valoarea x tuturor procesoarelor, se poate folosi un algoritm de difuzare (broadcast) care are complexitatea O(log N). Secvena S este divizat n N subsecvene de lungime n/N, fiecare subsecven fiind atribuit unui procesor. Folosind o procedur de cutare binar pe secvena atribuit, un procesor gsete rezultatul n O(log(n/N)) n cazul cel mai defavorabil. Timpul total cerut este 90

deci de ordinul O(log N) + O(log(n/N)) adic O(log n), acelai cu timpul necesar cutrii binare pe un procesor secvenial. n cazul unui sistem CREW, difuzarea valorii lui x se poate face ntr-un singur pas. Mai mult, se poate adopta o politic de cutare diferit, obinndu-se o performan mai bun pentru timpul de execuie. Algoritmul se bazeaz pe mprirea, n fiecare etap, a secvenei n care se face cutarea n N+1 subsecvene de aceeai lungime. Fiecare din cele N procesoare inspecteaz o valoare s aflat n poziia dintre dou secvene adiacente. Dac x<s atunci toate elementele aflate la dreapta lui s sunt ignorate n pasul urmtor. Similar, dac x>s sunt ignorate elementele mai mici ca s. Urmtorul subinterval de cutare se obine fcand intersecia subintervalelor pstrate de diferitele procesoare. Deoarece fiecare etap se aplic unei secvene de dimensiune 1/(N+1) din secvena precedent, sunt necesare O(logN+1(n+1)) etape.
P1 P2 Pi Pi+1 PN +-----------------------------------------------------------------+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | S +-----------------------------------------------------------------+ ^ ^ g g indici elemente ..... i(N+1) -1 (i+1)(N+1) -1 .... |<----->| g-1 dimensiune subinterval (N+1) -1

Figura 6.1 Fie g cel mai mic ntreg astfel c n <= (N+1)g-1. Cu alte cuvinte, g = sup(log(n+1)/log(N+1)). Se poate arta prin inducie c algoritmul are cel mult g etape. Astfel, afirmaia este banal pentru g=0. Fie relaia adevrat pentru (N+1)g-1-1. Pentru a inspecta o secven de lungime (N+1)g-1, procesorul Pi compar x cu s[j], unde j = i(N+1)g-1, aa cum se arat n figura 6.1. n urma comparaiei, se reine o subsecven de dimensiune (N+1)g-1-1, care (conform ipotezei de inducie) se poate inspecta n g-1 etape. O demonstraie mai sugestiv consider mai ntai ultimul pas al algoritmului, n care fiecare element al secvenei rmase este verificat de un procesor, deci n1 = N. Secvena provine din pasul anterior de la una de lungime (N+1)(N+1) -1 = n2. Deci, 91

un sistem cu N procesoare poate acoperi n doi pai o secven de lungime cel mult n2 = (N+1)2 -1 (vezi figura 6.2).
P1 P2 PN +---------+ | | | | | | +---------+ +---------+ | | | | | | +---------+ P1 +-++---------+ | || | | | | | +-++---------+

n1 = N

P2 PN +-++---------+ +-++---------+ | || | | | | | | || | | | | | +-++---------+ +-++---------+ |<--N+1 ---->| |<-----------------------(N+1)(N+1) - 1 ---------------------->|

Figura 6.2 n general, un sistem cu N procesoare poate "acoperi" n g pai o secven de lungime cel mult ng = (N+1)g-1. n primul pas, aceast secven este mprit n subsecvene de ng-1 = (N+1)g-1-1 elemente, procesorul Pi inspectnd elementul din poziia i*(N+1)g-1 (considerand c primul element are poziia 1). Dac primul element are indicele q, atunci poziia care corespunde lui Pi este (q-1)+i*(N+1)g-1. Ca urmare, dat fiind lungimea n a unei secvene de numere, numrul de pai g ai procedurii de cutare rezult din relaia n<=(N+1)g-1, adic este g = sup(log(n+1)/log(N+1)). Exemplul 1 Pentru exemplificarea execuiei algoritmului, fie secvena de numere dat n figura 6.3a i x=45, N=3. Deoarece n=15, g este cel mai mic numr care satisface relaia (N+1)g >= n+1, adic 4g >= 16. Rezult g=2. Lungimea unei subsecvene n primul pas este egal cu 3. Rezolvarea este schiat n figura 6.3.
P1 P2 P3 +--------------------------------------------+ | 1| 4| 6| 9|10|11|13|14|15|18|20|25|32|45|51| +--------------------------------------------+ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

(a)

Figura 6.3a 92

P1 P2 P3 +--------+ |32|45|51| +--------+ 13 14 15

(b)

Figura 6.3b Exemplul 2 S considerm o a doua execuie, cu N=2, x=21. Deci, din relaia (N+1)g>=n+1 rezult 3g>=16, deci g=3. Lungimea unei subsecvene n primul pas este egal cu 8. Rezolvarea este schiat n figura 6.4.
P1 P2 (n afara irului) +--------------------------------------------+ | 1| 4| 6| 9|10|11|13|14|15|18|20|25|32|45|51| (a) +--------------------------------------------+ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 P1 P2 +-----------------+ |18|20|25|32|45|51| +-----------------+ 10 11 12 13 14 15 P1 P2 +-----+ |18|20| +-----+ 10 11

(b)

(c)

Figura 6.4 Pentru a determina subintervalul care rmane n fiecare etap, fiecare proces Pi, 1<=i<=N utilizeaz o variabil c[i] care ia una din valorile stg sau dr, dup cum trebuie reinut partea din stanga, respectiv cea din dreapta. n plus, se folosesc c[0]=dr i c[N+1]=stg. Iniial limitele subsecvenei de cutare sunt q=1 i r=n. De asemenea, g are iniial valoarea numrului maxim de etape g = sup(log(n+1)/log(N+1)) i scade cu o unitate la fiecare iteraie. Algoritmul calculeaz valorile c[i] i gsete i pentru care c[i-1]<>c[i]. Pe baza lui se determin urmtorul subinterval [q,r] de cutare. Mai precis, 93

q := q+(i-1)(N+1)g-1+1, iar r := q+i(N+1)g-1 -1. Un singur procesor calculeaz noile valori pentru q i r, celelalte avnd acces la aceste valori n timp constant. n descrierea ce urmeaz sunt marcate cele trei etape ale algoritmului, precum i paii care-i compun.
/1/ /1.1/ /1.2/ /2/ /2.1/ /2.2/ /2.3/ /* Iniializarea indicilor secvenei de cutat */ var q:int := 1; r:int := n; var x: real ; s: array [1 :n] of real ; /* Iniializarea rezultatului i a numrului maxim de pai */ var k:int := 0; var g:int := sup(log(n+1)/log(N+1)) var c: array [0:N+1] of (stg,dr); c[0] := dr; c[N+1] := stg; /3/ do (q<=r) and (k=0) -> /3.1/ var j: array [0 :N] of int; j[0] := q-1 ; /3.2/ fa i := 1 to N do in parallel ji := (q-1) + i*(N+1)g-1 /* Pi compar x cu s[ji] i determin partea de secv acceptat */ if ji <= r -> if s[ji]=x -> k := ji [] s[ji]>x -> c[i] := stg [] s[ji]<x -> c[i] := dr fi; []ji > r -> ji := r+1; c[i] := stg; fi; /* calculeaz indicii subsecvenei urmtoare */ if c[i] <> c[i-1] -> q := ji - (N+1)g-1; r := ji - 1; fi; if (i=N) and (c[i]<>c[i+1]) -> q := ji +1 fi; af; g := g-1; od;

Observaie Operaiile paralele din algoritm se execut n acelai timp n toate procesoarele. Operaiile secveniale sunt executate de un singur procesor. Pentru exemplificarea execuiei algoritmului, fie secvena de numere dat n figura 6.5a i x=45, N=3. Iniial, q=1, r=15, k=0 i g=2. Rezult j1=4, j2=8 i j3=12. Ca urmare, n prima etap: 94

P1 compar x cu s[4] i deoarece 45>9 alege c[1]=dr; P2 compar x cu s[8] i deoarece 45>14 alege c[2]=dr; P3 compar x cu s[12] i deoarece 45>25 alege c[3]=dr. Rezult c[3]<c[4]. Ca urmare, se pune q=13, iar r rmane 15. Secvena se restrnge la cele trei elemente din figura 6.5b, iar g devine 1.
P1 P2 P3 +--------------------------------------------+ | 1| 4| 6| 9|10|11|13|14|15|18|20|25|32|45|51| +--------------------------------------------+ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 P1 P2 P3 +--------+ |32|45|51| +--------+ 13 14 15

(a)

(b)

Figura 6.5 n a doua etap, se obin valorile j1=13, j2=14 i j3=15. Ca urmare: P1 compar x cu s[13] i deoarece 45>32 alege c[1]=dr; P2 compar x cu s[14] i deoarece 45=45 pune k=14 i las c[2] neschimbat; P3 compar x cu s[15] i deoarece 45<51 alege c[3]=stg. Noile valori pentru q i r sunt 15, respectiv 14. Oricum, iteraiile se opresc datorit condiiei k<>0. S considerm o a doua execuie, cu N=2, x=21. Iniial g=3. n prima iteraie avem j1=9 i j2=18>15, deci n afara secvenei. Ca urmare: P1 compar x cu s[9] i deoarece 21>15 alege c[1]=dr; P2 pune j2 la 16 (deoarece valoarea calculat este n afara secvenei) i actualizeaz c[2]=stg. Deoarece c[1]<>c[2], se stabilesc noile valori q=10 i r=15, obinndu-se subsecvena din figura 6.6b i g=2.
P1 P2 (n afara irului) +--------------------------------------------+ | 1| 4| 6| 9|10|11|13|14|15|18|20|25|32|45|51| (a) +--------------------------------------------+ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Figura 6.6a 95

P1 P2 +-----------------+ |18|20|25|32|45|51| +-----------------+ 10 11 12 13 14 15 P1 P2 +-----+ |18|20| +-----+ 10 11

(b)

(c)

Figura 6.6b,c n a doua iteraie, P1 calculeaz j1=9+3 i compar x cu s[12]. Deoarece 21<25 se obine c[1]=stg. Similar, j2=15 i, deoarece 21<51, avem c[2]=stg. Ca urmare, c[0]<>c[1] i intervalul se restrnge pentru a treia iteraie la r=11 i q nemodificat (figura 6.6c). n a treia iteraie, j1 este 10, P1 calculand c[1] = dr, deoarece 21>18. Similar, P2 calculeaz c[2] = dr, deoarece 21>20. Ca urmare q capt valoarea 12, mai mare dect valoarea lui r provocnd astfel ieirea din ciclu cu k=0. Observaii Deoarece pasul 3 al algoritmului precedent se execut de cel mult g ori, rezult c algoritmul are complexitatea t(n) = O(logN+1(n+1)). Lucrul efectuat de algoritm este O(N logN+1(n+1)), deci algoritmul nu este cost-optimal. Cu toate acestea, se poate arta c el este optim din punct de vedere al timpului de calcul. Pentru a arta acest lucru, s observm c, folosind N procesoare, algoritmul poate compara x cu cel mult N valori s[i], la un moment dat. Dup aceste comparaii i dup eliminarea din secven a elementelor despre care se tie c nu sunt egale cu x, lungimea subsecvenei rmase este de cel puin: sup((n-N)/(N+1)) >= (n-N)/(N+1) = [(n+1)/(N+1)]-1. Dup g repetiii, secvena rmas este de lungime [(n+1)/(N+1)g]-1. Deci, numrul de iteraii cerute de orice algoritm paralel trebuie s fie mai mare de cel mai mic g pentru care avem: [(n+1)/(N+1)g]-1 <=0, adic g = sup(log(n+1)/log(N+1)). n cazul n care N=n problema este rezolvat n timp constant. 96

n privina cerinei ca toate elementele secvenei S s fie distincte, ea poate fi nlturat dac actualizarea lui k la gsirea unei coincidene este realizat printr-o procedur special care evit conflictele de acces simultan (modelele folosite pn acum sunt cu scriere exclusiv). Aceast procedur ia un timp O(log N), mrind astfel timpul de execuie al algoritmului la: t(n) = O(log(n+1)/log(N+1)) + O(log N). Putem aprecia importana acestui timp suplimentar dac lum cazul N=n, n care nu se realizeaz nici o mbuntire fa de algoritmul secvenial. Meninerea eficienei algoritmului n cazul n care n ir pot exista valori egale se poate realiza prin folosirea unui model CRCW. n acest caz, este posibil ca la un conflict (mai multe elemente egale cu x se afl n secvena S), doar cea mai mic valoare a indicilor elementelor respective s fie dat lui k. 6.4. Algoritm de selecie paralel Consideraii (1) Se dau: - o secven de numere ntregi, S = {s1,...,sn} i - un intreg k, 1<=k<=n. Se cere: - cel de al k-lea numr n ordine cresctoare. Limita de complexitate Secvena se consider neordonat, selecia fcndu-se fr ordonarea ei prealabil. Pentru selecie, fiecare valoare a irului trebuie inspectat cel puin o dat. Aceasta stabilete limita inferioar a complexitii algoritmului secvenial la OMEGA(n), care este totodat limita inferioara pentru costul algoritmului paralel. Algoritmul secvenial de selecie Pentru conceperea unei soluii paralele, pornim de la o variant secvenial care are complexitatea O(n) i care: - st la baza derivrii algoritmului paralel - este o procedur apelat n algoritmul paralel. Prezentm mai ntai etapele algoritmului pe un exemplu. Fie secvena S: 3 14 16 20 8 31 22 12 33 1 4 9 10 5 13 7 24 2 14 26 18 34 36 25 14 27 32 35 33 cu n=29, i fie k=21 elementul ce trebuie selectat. 97

Se mparte S n subsecvene de cte 5 elemente (se va arta mai departe de ce 5!). Se afl medianele grupurilor de 5 elemente: M: 14 22 9 14 25 32 Se calculeaz mediana medianelor, m = 14. Se mparte secvena S n trei subsecvene, S1, S2 i S3, cu elemente mai mici, egale i mai mari decat m, respectiv. S1: 3 8 12 1 4 9 10 5 13 7 2 S2: 14 14 14 S3: 16 20 31 22 33 24 26 18 34 25 27 32 35 33 Deoarece |S1|=11 i |S2|=3, al 21-lea element se afl n S3. Se reine S3 n care se caut al 21-14= 7-lea element. Se reia calculul, mprindu-se irul n subsecvene de cte 5 elemente i calculnd medianele: M: 22 26 32 Se afl mediana medianelor, m=26. Se mparte secvena n trei subsecvene, S1, S2 i S3, cu elemente mai mici, egale i mai mari dect m, respectiv. S1: 16 20 22 24 18 25 S2: 26 S3: 31 33 34 36 27 32 35 33 Deoarece |S1|=6 i |S1|+|S2|=7, al 7-lea element se afl n S2, fiind egal cu m=26. Algoritmul (divide-and-conquer) este recursiv. La fiecare etapa, se restrnge mulimea elementelor candidate pentru selecia rezultatului. Fie |S| numrul de elemente din secvena S; fie Q o constant ntreag a crei valoare va fi precizat mai trziu. procedure SEQUENTIAL_SELECT (S, k) returns elk: int;
Pas 1: if |S|<Q -> sorteaza S i afl al k-lea element [] |S|>=Q -> mparte S n |S|/Q subsecvene de Q elemente (cu cel mult Q-1 elemente ramase) Pas 2: Pas 3: Pas 4: Pas 5: Sorteaz fiecare subsecvent si determin mediana sa Apeleaza SEQUENTIAL_SELECT recursiv pentru a afla m, mediana celor |S|/Q mediane aflate la pasul 2 Creeaza trei subsecvente S1, S2, S3 cu elemente din S mai mici dect, egale cu, respectiv mai mari dect m if |S1|>=k -> {al k-lea element din S este in S1}

98

elk := SEQUENTIAL_SELECT (S1, k) [] |S1|<k and |S1|+|S2|>=k -> elk := m [] |S1|+|S2|<k -> elk :=SEQUENTIAL_SELECT (S3, k-|S1|-|S2|) fi fi

Rezultatul poate fi ntors n S[1] sau ntr-un parametru suplimentar al procedurii anterioare. Analiza complexitti este fcut considernd paii algoritmului, unul dup altul. Pas 1. Deoarece Q este constant, sortarea lui S cnd |S|<Q ia un timp constant. Altfel, mprirea lui S ia timpul c1*n (c1 constanta). Pas 2. Fiecare subsecven de Q elemente poate fi sortat n timp constant. Deci etapa dureaz c2*n (c2 constanta). Pas 3. Sunt |S|/Q mediane, deci recursia ia un timp t(n/Q). Pas 4. O trecere prin S creeaz subsecvenele S1, S2, S3. Deci pasul dureaz un timp c3*n (c3 constanta). Pas 5. Deoarece m este mediana a |S|/Q elemente, exist |S|/(2Q) elemente mai mari sau egale cu ea. Fiecare din cele |S|/Q elemente este la rndul su mediana unui set de Q elemente, deci are Q/2 elemente mai mari sau egale cu el. Rezult c (|S|/(2Q))*(Q/2)=|S|/4 elemente ale lui S sunt mai mari sau egale cu m. Ca urmare, |S1|<=3|S|/4. Printr-un raionament similar, |S3|<=3|S|/4. Ca urmare, un apel recursiv n acest pas al procedurii SEQUENTIAL_SELECT cere un timp t(3n/4). Din analiza precedent avem t(n) = c4n + t(n/Q) + t(3n/4), cu c4 = c1+c2+c3. Pentru specificarea lui Q, dac el este ales astfel nct n/Q +3n/4 < n atunci cele doua apeluri recursive din procedur se execut pe secvene din ce n ce mai mici. Orice valoare Q>=5 este bun. Fie Q=5. Deci: t(n) = c4n + t(n/5) + t(3n/4) Aceasta recuren poate fi rezolvat presupunnd c t(n) <= c5n cu c5 constant. Substituind obinem: t(n) <= c4n + c5(n/5) + c5(3n/4) = c4n + c5(19n/20) 99

In final, lund c5 = 20*c4, obinem t(n) <= c5(n/20) + c5(19/20) = c5*n deci t(n) = O(n). Algoritmul paralel de selecie Ideea principal este paralelizarea pasului 2 al algoritmului secvenial. Pentru varianta paralel considerm urmtoarele: (1) Sistemul are N procesoare. (2) Fiecare procesor a primit n i calculeaz x din N = n1-x, cu 0<x<1. (3) Fiecare procesor poate memora nx elemente n memoria local. (4) Fiecare procesor poate executa procedurile BROADCAST si ALLSUMS, precum i procedura SEQUENTIAL_SELECT (prezentat anterior) (5) M[1:N] este un tablou n memoria comun.
procedure PARALLEL_SELECT (S, k) returns elk: int; Pas 1: if |S| <= 4 -> P1 gsete elementul k n cel mult 4 comparatii [] |S| > 4 -> 1.1. S este mprit n |S|1-x subsecvene, fiecare de lungime |S|x, unde 1<=i<=|S|1-x i 1.2. subsecvena Si este asignata procesorului Pi fa i := 1 to |S|1-x do in parallel 2.1. {Pi calculeaz mediana mi din Si} mi = SEQUENTIAL_SELECT (Si, sup(|Si|/2)) 2.2. Pi memoreaz mi n M[i] af Pas 3: {Calculeaz recursiv mediana m a lui M} m := PARALLEL_SELECT (M, sup(|M|/2)) Pas 4: Imparte S n trei subsecvene: L = {si din S | si < m} E = {si din S | si = m} i G = {si din S | si > m} Pas 5: if |L| >= k -> elk := PARALLEL_SELECT (L, k) [] (|L| < k) and (|L|+|E| >= k) -> elk := m [] |L|+|E| >= k -> elk := PARALLEL_SELECT (G, k-|L|-|E|) fi fi end Pas 2:

Valoarea celui de al k-lea element este ntoars fie n S[1], fie ntr-un argument suplimentar al procedurii, n cazul de fa elk. 100

Exemplu Prezentm etapele algoritmului paralel pe un exemplu. Fie secvena S: 3 14 16 20 8 31 22 12 33 1 4 9 10 5 13 7 24 2 14 26 18 34 36 25 14 27 32 35 33 cu n=29, i fie k=21 elementul ce trebuie selectat. De asemenea, fie N=5=|S|1-x. Rezult |S|x=6, deci secvena iniial se mparte n grupuri de cate 6 elemente. Se afl, n paralel, medianele grupurilor de 6 elemente: M: 14 9 7 25 32 Se calculeaz mediana medianelor, m = 14, prin selecie paralel. Se mparte secvena S n trei subsecvene, L, E i G, cu elemente mai mici, egale i mai mari dect m, respectiv. L: 3 8 12 1 4 9 10 5 13 7 2 E: 14 14 14 G: 16 20 31 22 33 24 26 18 34 25 27 32 35 33 Deoarece |L|=11 i |E|=3, al 21-lea element se afl n G. Se reine G n care se caut al 21-14= 7-lea element. Se reia calculul. Deoarece |G|=15, se folosesc 151-x = 3 procesoare pe parcursul acestui apel (deoarece se urmrete un cost optimal, nu se iau 4 procesoare, ct ar rezulta din rotunjire). Se mparte irul n subsecvene de cte 15x=5 elemente i se calculeaz medianele: M: 22 26 32 Se afl mediana medianelor, m=26. Se mparte secvena n trei subsecvene, L, E i G, cu elemente mai mici, egale i mai mari dect m, respectiv. L: 16 20 22 24 18 25 E: 26 G: 31 33 34 36 27 32 35 33 Deoarece |L|=6 i |L|+|E|=7, al 7-lea element se afl n E, fiind egal cu m=26. Analiza complexitii. Considerm, pe rnd, fiecare pas al procedurii. Pas 1. Pentru a ncepe, fiecare procesor trebuie s cunoasc: - adresa A a primului element al secvenei S n memoria comun; - dimensiunea |S| i - valoarea lui k. Pentru aceasta se folosete procedura BROADCAST, care cere un timp O(log n1-x). 101

Daca |S|<=4, P1 ntoarce rezultatul n timp constant. Altfel, Pi calculeaz marginile secvenei Si, prin: - adresa primului element este A + (i-1)*nx - adresa ultimului element este A + i*nx 1, unde n = |S|. Aceasta se face n timp constant. Ca urmare, pasul 1 ia un timp c1*(log n), unde c1 este o constant. Pas 2. SEQUENTIAL_SELECT afl mediana unei secvene de lungime nx ntr-un timp c2.nx, unde c2 este o constant. Pas 3. Deoarece PARALLEL_SELECT este apelat recursiv cu o secven de lungime n1-x, acest pas dureaz t(n1-x). Pas 4. Divizarea secvenei S se poate face astfel: (i) Valoarea m este difuzat prin BROADCAST n O(log n1-x) (ii) Fiecare procesor Pi mparte Si n trei subsecvente Li, Ei si Gi de elemente mai mici, egale, respectiv mai mari ca m. Aceasta se face in timp linear fa de dimensiunea lui Si, adic O(nx) (iii) Subsecvenele Li, Ei i Gi sunt interclasate pentru a forma L, E si G. Artm acest lucru pentru Li, similar fcndu-se pentru celelalte doua. Fie ai = |Li|. Pentru fiecare i, 1<=i<=n1-x, se calculeaza suma zi = a1+...+ai. Toate sumele sunt obinute de n1-x procesoare n timp O(log n1-x) folosind procedura ALLSUMS. Fie acum z0=0. Toate procesoarele interclaseaza simultan subsecventele Li pentru a forma L: procesorul Pi copiaz Li n L pornind din pozitia zi-1+1. Aceasta se face in timp O(nx).Ca urmare, timpul cerut pentru pasul 4 este c3*nx, cu c3 constanta. Pas 5. Dimensiunea lui L necesar n acest pas a fost obinut n pasul 4 prin calculul lui z[n1-x]. La fel pentru dimensiunile lui E si G. Acum trebuie s determinm ct timp ia fiecare din cei doi pai recursivi. Deoarece m este mediana lui M, cu siguran n1-x/2 elemente din S sunt mai mari dect m. Mai mult, fiecare element din M este mai mic dect cel putin nx/2 elemente din S. Astfel, |L| <= 3n/4. Similar, |G| <= 3n/4. Ca urmare, pasul 5 cere cel mult un timp t(3n/4). Analiza precedenta conduce la urmatoarea recuren pentru t(n): t(n) = c1(log n) + c2*nx + t(n1-x) + c3*nx + t(3n/4) a crei soluie este t(n) = O(nx) pentru n>4. Deoarece p(n) = n1-x, obtinem c(n) = p(n) * t(n) = n1-x * O(nx) = O(n). 102

Costul este deci optimal. De notat c nx este asimptotic mai mare decat log n, pentru orice x. Deoarece N = n1-x si n/nx < n/log n, rezult c PARALLEL_SELECT este optimal cu condiia ca N < n/log n. Observaie Algoritmul precedent a fost obinut prin Nu ntotdeauna acest procedeu conduce la ca proiectantul s ignore soluia secvenial problemei. Aceasta abordare poate conduce secveniale cunoscute. paralelizarea unui algoritm secvenial. rezultate optime, uneori fiind necesar i s exploateze paralelismul inerent al la mbuntirea celei mai bune soluii

103

Capitolul 7 Dezvoltarea algoritmilor distribuii folosind comunicarea prin mesaje


7.1. Comunicarea asincron de mesaje. Filtre n dezvoltarea programelor distribuite, atenia proiectantului se concentreaz asupra comunicrii. Nu este de mirare, deci, c se poate vorbi de tipare de interaciune ntre procese, care corespund diverselor clase de aplicaii paralele. Mai important este ns clasificarea proceselor unui program distribuit n: filtre, clieni, servere i procese egale (sau pereche, n engleza peer). Un filtru este un proces care prelucreaz date. El primete iruri de date prin canalele de intrare, face diverse prelucrri asupra lor i transmite iruri de rezultate prin canalele de ieire. Acest comportament permite proiectarea unui filtru independent de proiectarea altor procese. De asemenea, el faciliteaz conectarea filtrelor, formnd astfel reele de filtre, cu condiia ca ntre ieirile unui filtru i intrrile urmtoarelor s existe compatibilitatea necesar. Un client este un proces care solicit un serviciu, declannd astfel o activitate a unui server. Uzual, clientul ateapt rezultatul serviciului solicitat. Serverul ateapt solicitri din partea clienilor i le satisface imediat sau le salveaz pentru o tratare ulterioar. Aciunile serverului depind de natura i parametrii solicitrii, transmii prin mesajul de cerere a serviciului. Un egal este unul din procesele unei colecii de procese identice care interacioneaz n vederea rezolvrii unei probleme. De exemplu, ntr-un sistem distribuit de fiiere, dou procese egale pot interaciona pentru a-i actualiza fiierele i a pstra consistena sistemului. Tipurile de procese menionate se regsesc n sistemele distribuite, indiferent de natura sincron sau asincron a comunicrii. 7.1.1. Filtru de sortare Funcia unui filtru de sortare este de a recepiona un ir de date, de a le pune n ordine i de a transmite irul sortat. Uzual, exist un marcaj care permite depistarea sfritului irului, att pe canalul de intrare ct i pe cel de ieire. 104

Funcia poate fi realizat secvenial, de un singur proces care folosete una din nenumratele metode de sortare cunoscute. Ca alternativ, ea poate fi realizat n paralel, printr-o reea de filtre. Exist mai multe soluii de reele de filtrare, aici prezentndu-se o reea de sortare prin interclasare. Ideea de baz este de a interclasa repetat i n paralel dou liste sortate obinnd una mai mare. Elementul de baz al reelei este un filtru Merge, care primete valorile din dou fluxuri de intrare in1 i in2 i produce un singur flux ordonat out. Presupunem c fiecare ir este marcat prin santinela terminatoare EOS. Merge compar dou valori primite prin in1 i in2 i transmite valoarea mai mic prin out. O nou valoare este recepionat n locul celei selectate. La terminarea tuturor valorilor unui flux, Merge transmite direct la out valorile primite prin celalalt canal. Soluia are urmtoarea descriere:
chan in1(int), in2(int), out(int); Merge:: var v1,v2:int; receive in1(v1); receive in2(v2); do v1 <> EOS and v2 <> EOS -> if v1 <= v2 -> send out(v1); receive in1(v1) [] v2 < v1 -> send out(v2); receive in2(v2) fi [] v1 <> EOS and v2 = EOS -> send out(v1); receive in1(v1) [] v1 = EOS and v2 <> EOS -> send out(v2); receive in2(v2) od; send out(EOS);

Pentru a forma o reea de sortare, utilizm o colecie de procese Merge i tablouri de canale de intrare i de ieire. Dac n este numrul datelor de sortat i este o putere a lui 2, atunci reeaua are structura arborescent prezentat n figura 6.1. Reeaua conine n-1 procese, adncimea ei fiind log2n. Realizarea ei presupune mparirea canalelor ntre diferite procese, ceea ce poate fi programat n dou moduri. n varianta static, se declar toate canalele ca un tablou global, fiecare instant a procesului Merge primind date prin dou elemente ale tabloului i transmind printrun al treilea. Aceasta nseamn proiecia arborelui ntr-un tablou astfel nct canalele folosite de Mergei s fie funcie de i.

105

a1 a2

a3 a4

+--+ in1 merge --- +------+ +--+ --- +---- +--+ +---- +--- out +--+ in2 +--+ --- +------+ --- +--+

+--+ an-3-- +-----+ +--+ an-2-- +---- +--+ +---- +--- - +--+ +--+ an-1-- +-----+ an -- +--+

- - - -+ +--+ +--- +- flux sortat +--- +--+ - - - -+

Figura 7.1. A doua abordare este dinamic. Se declar canalele globale ca mai nainte, se parametrizeaz procesele i se asociaz fiecarui proces, la creare, trei canale. Programarea fiecrui proces Merge este mai simpl, toate procesele fiind textual identice. Ea cere ns ca un proces principal s creeze dinamic i s aloce canalele proceselor Merge. Exerciii 1) S presupunem c procesele reelei de sortare sunt organizate ntr-un tablou Merge[1:n]. Dai declaraiile canalelor i descrierea proceselor, ambele innd cont de necesitatea punerii n coresponden a unui arbore cu un tablou. 2) Proiectai un filtru de partiionare a unui ir de valori terminat cu EOS. Filtrul folosete dou canale de ieire, out1 i out2. El reine prima valoare v din irul de la intrare, dup care trimite valorile mai mici dect v pe canalul out1, iar pe cele mai mari pe canalul out2. Filtrul transmite apoi valoarea v pe out1, dup care transmite EOS pe out1 i pe out2. Considernd c irul de intrare are n elemente i c n este o putere a lui 2, construii o reea de sortare cu procese de partiionare. 106

7.2. Clieni i servere 7.2.1. Servere cu o funcie Reamintim c un server prelucreaz, n mod repetat, cererile transmise de clieni. Pentru nceput, s considerm c serverul poate executa o singur operaie. Cererile sunt transmise serverului pe un singur canal, astfel nct schema de funcionare a acestuia este relativ simpl: preia un mesaj din canalul de cereri, realizeaz prelucrarea solicitat i transmite apoi rezultatul. Deoarece rezultatul este destinat unui singur client, o variant natural este folosirea unor canale distincte pentru clieni. Totodat, n cerere este inclus un cmp care precizeaz canalul pe care trebuie transmis rspunsul. Avem, deci, un tablou de canale, cte unul pentru fiecare client n parte. Soluia prezentat are urmatoarea schi:
chan cerere( int , tipuri_argumente ); chan raspuns[1:n]( tipuri_rezultate ); server:: var variabile_locale; var index:int, lista_argumente, lista_rezultate; initializare; do true -> receive cerere(index,lista_argumente); realizeaza_prelucrarea; send raspuns[index](lista_rezultate) od client(i:1..n):: send cerere(i,valori_argumente); receive raspuns[i](rezultate); ....

Varianta prezentat folosete alocarea static a canalelor. Deoarece canalele sunt globale, fiecare client trebuie programat atent pentru a nu prelua rezultate care nu-i sunt destinate lui. Ca alternativ, fiecare client poate crea un canal propriu de rspuns, pe care-l transmite ca parametru n locul indexului din mesajele de cerere. 7.2.2. Servere cu mai multe funcii Varianta prezentat se extinde cu uurin la cazul n care clientul solicit serverului execuia uneia din mai multe prelucrri posibile. Deoarece parametrii cererilor pot diferi de la o operaie la alta, se poate adopta una din urmtoarele soluii: 107

folosirea unor nregistrri cu variante (union); folosirea unor iruri de caractere, codificarea i decodificarea parametrilor cznd n sarcina proceselor client i server.

Desigur, un cmp al mesajului de cerere trebuie s diferenieze tipurile de operaii solicitate de clieni.
type fel_op = enum (op1 , ... , opn); type fel_arg = union (arg1:atip1 , ... , argn:atipn); type fel_rez = union (rez1:rtip1 , ... , rezn:rtipn); chan cerere(int, fel_op, fel_arg); chan raspuns[1:n](fel_rez); server:: var variabile_locale; var index:int, fel:fel_op, argumente:fel_arg, rezultate:fel_rez; initializare; do true -> receive cerere(index,fel,argumente); if fel = op1 -> prelucrare1; .... [] fel = opn -> prelucraren; fi; send raspuns[index](rezultate); od; client(i:1..n):: var arg:fel_arg, rasp:fel_rez; send cerere(i,opi,arg); receive raspuns[i](rasp);

....

7.2.3. Suspendarea tratrii cererilor Prelucrrile din server pot fi condiionate. Aceasta presupune c uneori cererile nu sunt servite imediat. Satisfacerea lor poate depinde de cererile altor procese. De exemplu, la un alocator de resurse, o cerere de alocare poate fi satisfcut uneori doar dac alte procese trimit cereri de dealocare elibernd astfel suficiente resurse. Ca urmare, dac o cerere nu poate fi satisfcut imediat, serverul va salva cererea pentru a o trata ulterior i pentru a se elibera n vederea acceptrii altor cereri. 108

Alocatorul pe care l descriem n continuare gestioneaz un numr maxim de uniti MAXUNIT, reprezentnd resurse (blocuri de memorie sau fiiere, etc.).
type fel_op = enum(acaparare, eliberare); chan cerere(int, fel_op, id_unitate:int); chan raspuns[1:n](id_unitate:int); Alocator:: var avail:int := MAXUNIT, unitati:set of int; var suspendate:queue of int; var index:int, fel:fel_op, id_unitate:int; initializare unitati la valorile corespunzatoare; do true -> receive cerere(index,fel,id_unitate); if fel = acaparare -> if avail > 0 -> avail := avail-1; id_unitate := remove(unitati); send raspuns[index](id_unitate); [] avail = 0 -> enqueue(suspendate,index); fi [] fel = eliberare -> if empty(suspendate) -> avail := avail+1; insert(unitati,id_unitate); [] not empty(suspendate) -> index := dequeue(suspendate); send raspuns[index](id_unitate); fi fi od; Client(i:1..n):: var id_unitate:int; send cerere(i,acaparare,0); receive raspuns[i](id_unitate); utilizeaza_resursa; send cerere(i,eliberare,id_unitate);

7.2.4. O colecie de servere O alt situaie tipic este cea a unei colecii de servere care gestioneaz resurse de acelai tip. De exemplu, dac ntr-un sistem pot fi deschise simultan n fiiere, putem realiza accesul prin n procese identice. Cererile unui client pot fi satisfcute de oricare dintre ele. Pentru a pstra coerena operaiilor, convenim ca odat stabilit legtura dintre un client i un server la deschiderea unui fiier, toate cererile adresate de 109

clientul respectiv pn la nchiderea fiierului s fie tratate de acelai server, cel care a deschis fiierul. Pentru a realiza acest lucru, convenim ca cererile de deschidere de fiier s fie transmise pe un acelai canal, open, la care ateapt mesaje toate serverele libere. Cererile de acces urmeaz a se transmite pe canale separate, access[1:n], fiecare fiind corespunztor unui server. De asemenea, mesajele de raspuns pentru deschidere i pentru acces sunt transmise pe canale distincte, indexate dup clieni, considerai aici n numr de m. Soluia este urmtoarea:
type fel = enum( read , write , close ); chan open( nume_fisier:string[*] , id_client:int ); chan open_reply[1:m](int); { campul este identificatorul serverului sau indicatia de eroare } chan access[1:n]( fel , tip_argumente ); chan access_reply[1:m]( tip_rezultate ); FileServer(i:1..n):: var nume_fisier:string[*], id_client:int; var k:fel, arg:tip_argumente, rez:tip_rezultate; var OK:boolean := false; do true -> receive open(nume_fisier,id_client); if dechidere_fisier_reusita -> send open_reply[id_client](i); OK := true [] deschidere_fisier_nereusita -> send open_reply[id_client](cod_eroare) fi; do OK -> receive access[i](k,arg); if k = read -> prelucreaza_citire [] k = write -> prelucreaza_scriere [] k = close -> prelucreaza_inchidere; OK := false fi; send access_reply[id_client](rez) od od; Client(j:1..m):: var id_server:int, arg_ef:tip_argumente, rez_ef:tip_rezultate; send open("fisier1",j); receive open_reply[j](id_server);

110

if deschidere_fara_erori -> send access[id_server](read,arg_ef); receive access_reply[j](rez_ef); .... [] deschidere_cu_erori -> trateaza_eroarea fi;

Aici, open este un canal cu mai multe surse i mai muli destinatari. Un proces server liber ateapt un mesaj de deschidere, face operaia cerut i transmite identificatorul sau clientului. Cererile de acces ulterioare sunt primite pe un canal separat, access[i], propriu serverului i. Rspunsurile sunt transmise clienilor personalizate, open_reply i access_reply, avnd ca index identificatorul clientului. Soluia prezentat face o alocare static a canalelor, dar o alocare dinamic este la fel de posibil. Ea nu ar limita la m numrul potenialilor clieni. Pe de alt parte, ntr-un limbaj ce admite crearea dinamic a proceselor, numrul acestora variaz n funcie de solicitri. n fine, o alt soluie este utilizarea apelurilor de proceduri la distan (RPC), de care nu ne ocupm aici. Exerciii 1) Descriei un server pentru gestiunea unui cont bancar. Clienii pot face dou tipuri de cereri: de depunere i de retragere a unei sume de bani. Soldul nu trebuie s devin niciodat negativ. 2) Un server gestioneaz dou resurse A i B diferite. Clienii se ncadreaz n trei categorii: cele care necesit resursa A; cele care necesit resursa B; cele care necesit A sau B (oricare este liber). Descriei funcionarea sistemului. 3) Fie n procese pasager i un proces vagon. Pasagerii ateapt, n mod repetat, s urce n vagon, care poate ine C pasageri, C<n. Vagonul poate face un tur doar atunci cnd este plin. Scriei codul proceselor pasager i vagon, folosind comunicarea prin mesaje. Generalizare: considerai m vagoane i inei cont de faptul c vagoanele nu se pot depai unele pe altele. 4) Implementai un server de ceas. El poate primi dou tipuri de cereri de la clieni: una pentru a furniza ora; alta pentru a realiza o ntrziere cu un interval de timp specificat. n plus, serverul primete periodic mesaje de "tic" de la un driver de ceas.

111

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

MPI - Message Passing Interface 1. Generaliti


MPI este un standard pentru comunicarea prin mesaje, elaborat de MPIForum. n definirea lui au fost utilizate caracteristicile cele mai importante ale unor sisteme anterioare, bazate pe comunicaia de mesaje. A fost valorificat experiena de la IBM, Intel (NX/2) Express, nCUBE (Vertex), PARMACS, Zipcode, Chimp, PVM, Chameleon, PICL. MPI are la baz modelul proceselor comunicante prin mesaje: un calcul este o colecie de procese secveniale care coopereaz prin comunicare de mesaje. MPI este o bibliotec nu un limbaj. El specific convenii de apel pentru mai multe limbaje de programare: C, C++, FORTRAN.77, FORTRAN90. MPI a ajuns la versiunea 2, trecnd succesiv prin versiunile: MPI 1 (1993), un prim document, orientat pe comunicarea punct la punct. MPI 1.0 (iunie 1994) este versiunea final, adoptat ca standard; include comunicarea punct la punct i comunicarea colectiv. MPI 1.1 (1995) conine corecii i extensii ale documentului iniial din 1994, modificrile fiind univoce. MPI 1.2 (1997) conine extensii i clarificri pentru MPI 1.1 MPI 2 (1997) include funcionaliti noi: Procese dinamice Comunicarea one-sided Operaii de I/E paralele

Obiectivele MPI: Proiectarea unei interfee de programare a aplicaiilor Comunicare eficient S fie utilizabil n medii eterogene Portabilitate Interfaa de comunicare s fie sigur (erorile tratate dedesubt) Apropiere de practici curente (PVM, NX, Express, p4) Semantica interfeei s fie independent de limbaj

2. Comunicarea punct la punct


2.1. Operaii de baz

Operaiile de baz pentru comunicarea punct la punct sunt send i receive. n MPI ele apar ca extensii necesare ale operaiilor similare din alte biblioteci de comunicare prin mesaje. Justificm n cele ce urmeaz utilitatea acestor extensii. Considerm mai nti operaia de transmitere de mesaje, n forma uzual: send (adres, lungime, destinaie, tip)
1

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

unde adresa identific nceputul unei zone de memorie unde se afl mesajul de transmis lungime este lungimea n octei a mesajului destinaie este identificatorul procesului cruia i se trimite mesajul (uzual un numr ntreg) tip (flag) este un ntreg ne-negativ care restricioneaz recepia mesajului. Acest argument permite programatorului s rearanjeze mesajele n ordine, chiar dac ele nu sosesc n secvena dorit.

Acest set de parametri este un bun compromis ntre ceea ce utilizatorul dorete i ceea ce sistemul poate s ofere: transferul eficient al unei zone contigue de memorie de la un proces la altul. n particular, sistemul ofer mecanismele de pstrare n coad a mesajelor, astfel c o operaie de recepie recv (adres, maxlung, surs, tip, actlung) se execut cu succes doar dac mesajul are tipul corect. Mesajele care nu corespund ateapt n coad. n cele mai multe sisteme, sursa este un argument de ieire, care indic originea mesajului. n alte cazuri este folosit pentru a restriciona recepia. Ceilali parametri reprezint, respectiv: adres, maxlung descrierea zonei receptoare de mesaj actlung numrul de octei efectiv recepionai

Formele prezentate impun restricii considerate actualmente inacceptabile. Analizm pe rnd aspectele. 2.1.1. Descrierea zonelor tampon Perechea (adres, lungime) este inadecvat pentru c: 1. n multe cazuri mesajul nu ocup o zon contigu. Este dezirabil o form care descrie distribuia original a datelor. 2. Mesajele conin valori cu tip; ntr-un mediu eterogen, transmiterea lor ca simple iruri de octei este inadecvat. Transmiterea ca date cu tip ar putea fi uurat de rutine adecvate de conversie, fcnd parte din biblioteca de comunicare. n MPI, tamponul de comunicaie este definit de tripleta (adres, contor, tip_de_date) care descrie contor valori de tipul tip_de_date situate ncepnd cu adresa adres. Astfel, (A, 300, MPI_DOUBLE) reprezint un vector A de 300 valori reale, n C. O implementare MPI va asigura c aceleai 300 de valori sunt recepionate, chiar dac reprezentarea lor n maina destinatarului difer de reprezentarea pe maina surs. n plus, un utilizator poate construi (folosind rutinele de bibliotec) propriile sale tipuri de date, care se pot referi la date din zone ne-contigue de memorie. 2.1.2. Contextul Fiecare comunicare de mesaj se deruleaz ntr-un anumit context.. Mesajele sunt intotdeauna primite n contextul n care au fost transmise. Mesajele transmise n contexte diferite nu interfer. Contextele sunt alocate de sistem (n timpul execuiei, ca rspuns la cererea utilizatorilor) i sunt folosite, ca i cmpurile de tip (tag) pentru restricionarea recepiei mesajelor. 2.1.3. Grupurile de procese Contextul este partajat de un grup de procese. Procesele unui grup sunt ordonate i fiecare proces este identificat prin numrul su de ordine din grup. Pentru un grup de n procese, numerele valide au valori de la 0 la n-1.
2

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

2.1.4. Comunicator Informaiile de context i de grup sunt asamblate ntr-un parametru suplimentar al operaiilor de comunicare, denumit comunicator. Mesajele poart, n afara datelor, informaii care permit diferenierea lor i recepia lor selectiv. Aceste informaii sunt: Surs Destinatar Tag Comunicator

i constituie plicul (anvelopa) mesajului. MPI prevede un comunicator predefinit, MPI_COMM_WORLD., care permite comunicarea cu orice proces accesibil dup iniializarea MPI i asocierea unui numr de ordine (rank) fiecrui proces. Rolul i modalitatea de a defini noi comunicatori vor fi discutate mai trziu. Cu aceste elemente, sintaxa operaiilor send i receive blocante este urmtoarea: MPI_SEND (buf, count, datatype, dest, tag, comm) unde parametrii sunt: IN buf, adresa iniial a tamponului surs IN count, numrul de elemente (ntreg ne-negativ) IN datatype, tipul fiecrui element IN dest, numrul de ordine al destinatarului (ntreg) IN tag, tipul mesajului (ntreg) IN comm, comunicatorul implicat MPI_RECV (buf, count, datatype, source, tag, comm, status) unde parametrii sunt: OUT buf, adresa iniial a tamponului destinatar IN count, numrul de elemente din tampon (ntreg ne-negativ) IN datatype, tipul fiecrui element IN source, numrul de ordine al sursei (ntreg) IN tag, tipul mesajului (ntreg) IN comm, comunicatorul implicat OUT status, starea, element (structur) ce indic sursa, tipul i contorul mesajului efectiv primit

n limbajul C aceste funcii au urmtoarele prototipuri, valorile returnate reprezentnd coduri de eroare: int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, comm); int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, MPI_Comm comm, MPI_Status *status); MPI_Comm int tag,

Operaia send este blocant. Ea nu red controlul apelantului pn cnd mesajul nu a fost preluat din tamponul surs, acesta din urm putnd fi reutilizat de transmitor. Mesajul poate fi copiat direct n tamponul destinatar (dac se execut o operaie recv) sau poate fi salvat ntr-un tampon temporar al
3

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

sistemului. Memorarea temporar a mesajului decupleaz operaiile send i recv, dar este consumatoare de resurse. Alegerea unei variante aparine implementatorului MPI. i operaia recv este blocant: controlul este redat programului apelant doar cnd mesajul a fost recepionat. Exist i alte operaii MPI, care permit programatorului s controleze modul de comunicare. Vom reveni asupra acestui subiect.

2.2.

Un exemplu complet

Utilizarea funciilor send i recv este ilustrat n urmtorul exemplu: # include mpi.h main (int argc, char **argv) { char message[40]; int myrank; MPI_Status status; MPI_Init (&argc, &argv); MPI_Comm_rank (MPI_COMM_WORLD, &myrank); if (myrank==0) { strcpy (message, Hello, there); MPI_Send (message, strlen(message), MPI_CHAR, 1, 99, MPI_COMM_WORLD); } else { MPI_Recv (message, 20, MPI_CHAR, 0, 99, MPI_COMM_WORLD, printf (\tReceived: %s \n, message); } MPI_Finalize(); }

&status);

n acest exemplu, procesul 0 (myrank==0) trimite un mesaj procesului 1 folosind operaia send. Procesul 1 (myrank!=0) primete acest mesaj prin operaia recv i l afieaz. Descrierile celor dou procese coincid, iar diferenierea ntre aciunile lor se face prin selecia dup numrul de ordine al procesului.

2.3.

Mai multe despre recepie

Recepia unui mesaj este guvernat de valorile din anvelopa sa. Un mesaj este primit de destinatarul su dac anvelopa conine valorile specificate de operaia MPI_Recv pentru argumentele source, tag i comm. Receptorul poate specifica MPI_ANY_SOURCE, respectiv MPI_ANY_TAG pentru a accepta mesaje de la orice surs i/sau cu orice tag. El nu poate specifica valori oarecare pentru comunicatorul comm !! Deci mesajul nu poate fi primit dect de receptorul adresat i pentru un acelai comunicator n cazul folosirii unor valori ANY pentru surs i tag, valorile corespunztoare unui mesaj recepionat pot fi aflate din parametrul status. n limbajul C, status este o structur cu trei cmpuri, MPI_SOURCE, MPI_TAG, MPI_ERROR, care poate conine ns i cmpuri adiionale Lungimea mesajului recepionat poate fi aflat prin apelul operaiei MPI_Get_count.

2.4.

Corespondena tipurilor i conversiile datelor

Corespondena tipurilor datelor se refer dou aspecte: Corespondena tipurilor limbajului gazd (C) cu tipurile specificate n operaiile de comunicare; Corespondena tipurilor la transmitor i receptor.
4

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

n plus, folosirea standardului n medii eterogene necesit conversii de tip. Aceste aspecte nu sunt tratate n lucrarea de fa.

2.5.

Alte operaii MPI

Prezentarea exemplului anterior ne ofer prilejul s comentm i alte operaii MPI. Fiecare program MPI trebuie s conin un apel al operaiei MPI_Init. Rolul acesteia este de a iniializa mediul n care programul va fi executat. Ea trebuie executat o singur dat, naintea altor operaii MPI. Pentru a evita execuia sa de mai multe ori (i deci provocarea unei erori), MPI ofer posibilitatea verificrii dac MPI_Init a fost sau nu executat. Acest lucru este fcut prin MPI_INIATIALIZED (flag) OUT flag, este true dac MPI_Init a fost deja executat

n limbajul C funcia are urmtorul prototip: int MPI_Initialized(int *flag); Aceasta este, de altfel, singura operaie ce poate fi executat nainte de MPI_Init. Revenind la MPI_Init, forma sa general este MPI_INIT() iar n limbajul C prototipul este int MPI_Init (int *argc, char ***argv); Funcia C de iniializare accept ca argumente argc i argv, argumente ale funciei main, a cror utilizare nu este fixat de standard i depinde de implementare. Perechea funciei de iniializare este MPI_Finalize, care trebuie executat de fiecare proces, pentru a nchide mediul MPI. Forma acestei operaii este urmtoarea: MPI_FINALIZE() iar n limbajul C prototipul este int MPI_Finalize (void); Utilizatorul trebuie s se asigure c toate comunicaiile n curs de desfurare s-au terminat nainte de apelul operaiei de finalizare. Dup MPI_Finalize, nici o alt operaie MPI nu mai poate fi executat (nici mcar una de iniializare). Un proces poate afla poziia sa n grupul asociat unui comunicator prin apelul operaiei MPI_COMM_RANK (comm, rank) IN comm, este comunicatorul implicat OUT rank, este rangul procesului apelant

n limbajul C funcia are urmtorul prototip: int MPI_Comm_rank(MPI_Comm comm, int *rank); Procesele din exemplul dat folosesc rspunsul acestei operaii n decizia care urmeaz n program.

2.6.

Alte moduri de comunicare

Modul standard de comunicare n MPI este blocant: controlul nu este redat apelantului pn cnd mesajul nu a fost preluat din tamponul de emisie (ntr-un tampon intermediar sau n tamponul receptorului), astfel nct procesul transmitor poate s modifice din nou tamponul de emisie. Memorarea temporar a mesajelor, n cazul unor operaii blocante, nu este ntotdeauna operaional. Dac mesajele transmise sunt foarte lungi i sistemul nu dispune de suficient memorie temporar, ele
5

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

trebuie transferate direct din tamponul surs n tamponul destinatar. Aceasta presupune, ns, c transmitorul este blocat pn la execuia unei recepii corespondente. n cazul unei combinaii de procese care-i transmit mesaje n lan, mecanismul conduce la degradarea performanelor, aa cum rezult i din exemplul prezentat n figura 1:

Figura 1 Fiecare proces, cu excepia primului i a ultimului, conine o pereche de operaii send-recv: prima transmite un mesaj ctre urmtorul proces din secven, a doua recepioneaz un mesaj de la precedentul proces. Transmiterea direct a datelor ntre tampoanele de emisie i recepie secvenializeaz execuiile operaiilor de comunicare, procesele rmnnd n ateptare (zonele colorate din figura 1) perioade lungi de timp. Exist mai multe soluii pentru a controla execuia operaiilor de comunicare astfel nct programul s nu depind de cantitatea de memorie tampon oferit de sistem. 2.6.1. Ordonarea operaiilor send-recv O soluie este mperecherea operaiilor, de exemplu, procesele de rang par execut operaiile n ordinea send-recv, n timp ce procesele de rang impar n ordine invers, recv-send.

Figura 2 2.6.2. Operaii send-recv combinate Schema precedent este greu de implementat n cazul unei combinaii mai complicate de procese. O alternativ este utilizarea operaiei MPI_Sendrecv, care combin ntr-un singur apel transmiterea unui mesaj ctre o destinaie cu recepia unui mesaj de la un alt proces. Subsistemul de comunicare se ocup de combinarea operaiilor astfel nct s se evite blocarea definitiv a proceselor. Ambele operaii, send i recv, folosesc acelai comunicator, dar eventual diferite tag-uri. Tampoanele de emisie i de recepie trebuie s fie distincte. Operaia are i o varian, MPI_Sendrecv_replace, n care acelai tampon este folosit att pentru emisie ct i pentru recepie, astfel c mesajul transmis este nlocuit cu mesajul recepionat.
6

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

2.6.3. Transmitere prin tampon MPI permite programatorului s prevad un tampon n care datele sunt plasate pn la livrarea lor. Operai MPI_Bsend se termin, eventual nainte de demararea unei recepii corespondente, odat cu plasarea datelor n zona tampon. Programatorul poate rezerva aceast zon prin operaia MPI_Buffer_attach, n care specific dimensiunea dorit, suficient de mare pentru a pstra mesajele n tranzit. Cnd tamponul nu mai este necesar, se folosete MPI_Buffer_detach. Exemplul urmtor ilustreaz utilizarea acestora: #define BuffSize 100000 int size; char *buff; MPI_Buffer_attach(malloc(BuffSize), BuffSize); /* Tamponul de BuffSize octeti poate fi folosit acum */ MPI_Bsend( ... ); MPI_Buffer_detach(&buff, &size); /* Tamponul redus la zero */ MPI_Buffer_attach(buff, size); /* Tamponul disponibil din nou */ Observaii: Dup detaare, utilizatorul poate reutiliza sau dealoca spaiul ocupat de tampon Unele operaii, de ataare i deataare, au un argument de tip void*; ele sunt folosite diferit un pointer la tampon este transmis la attach; adresa pointerului este utilizat la detach, astfel c acest apel ntoarce valoarea pointerului. Argumentele sunt definite ambele ca void * (i nu void * respectiv void **) pentru a evita conversii forate de tip (cast). n exemplul precedent, &buff, care este de tip char **, poate fi transmis ca argument fr a folosi cast. 2.6.4. Transmitere sincron Operaia de transmitere sincron MPI_Ssend poate demara naintea recepiei mesajului, dar se termin doar cnd operaia de recepie corespondent a nceput s preia mesajul transmis. 2.6.5. Transmitere n modul pregtit Operaia de transmitere n modul pregtit, MPI_Rsend poate fi demarat numai dac recepia corespondent a fost demarat anterior.

2.7.

Comunicaia non-blocant

Pentru a permite suprapunerea calculelor cu transferul de date, MPI ofer i operaii send, recv neblocante, pentru toate formele de comunicare: standard, cu tampon, sincron, n mod pregtit. Controlul este redat procesului apelant imediat dup demararea operaiei, mpreun cu un identificator al cererii (de tip MPI_Request). Programatorul trebuie s specifice, prin operaii explicite, terminarea transferului. Oricum, el poate programa alte operaii (de prelucrare) n paralel cu transferul datelor. MPI_Isend demareaz o operaie standard neblocant de transmisie. Terminarea operaiei poate fi verificat prin MPI_Test. n plus, MPI_Wait pune n ateptare procesul executant pn la terminarea operaiei. Pe parcursul desfurrii operaiei de transmitere, zona care conine mesajul nu trebuie modificat. Operaia MPI_Irecv ncepe o recepie neblocant. Terminarea ei poate fi testat cu MPI_Test i ateptat cu MPI_Wait.

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

Pentru testarea sau ateptarea terminrii uneia sau a tuturor operaiilor neblocante ale unei colecii de operaii, MPI furnizeaz operaiile MPI_Testall MPI_Waitall MPI_Testany MPI_Waitany MPI_Testsome MPI_Waitsome

De exemplu, putem ncepe dou operaii neblocante, ateptnd apoi terminarea ambelor operaii. Aceasta ne permite realizarea unei benzi de asamblare n care fiecare proces primete date din stnga i le transmite n dreapta. n timp ce sosesc noile date, precedentele sunt folosite n calcule. MPI_Request request[2]; MPI_Status status[2]; ... while (! done) { MPI_Irecv (buf1, . . . , &request[0]); MPI_Isend (buf2, . . . , &request[1]); /* calcule cu buf2 */ MPI_Waitall (2, request, status); /* schimba buf1 cu buf2 */ } Observaie: Un server cu mai muli clieni ar trebui s foloseasc MPI_Waitsome i nu MPI_Waitany, pentru a nu nghea nici un client. MPI_Waitsome ateapt pn cnd cel puin una din cererile active este terminat, dar ntoarce numrul cererilor terminate i lista indicilor acestora (n tabloul de cereri). Se pot trata apoi toate cererile terminate. MPI_Waitany ntoarce indexul unei singure cereri, alese aleator, ceea ce poate duce la nghearea unui anumit client, defavorizat de aceast alegere.

2.8.

Cereri de comunicare persistente

Cnd ciclul din exemplul anterior (pipeline!) se repet de multe ori este avantajoas crearea unei cereri de transmitere / recepie persistente, folosite ulterior de oricte ori. Aceasta simplific dialogul dintre program i infrastructura de comunicare, evitnd retransmiterea parametrilor operaiei, la fiecare apel. Programatorul poate crea o cerere persistent (MPI_Send_init, MPI_Recv_init, i toate celelalte variante, cu tampon sincrone i n mod pregtit), poate declana operaia (MPI_Start, MPI_Startall) de comunicare, poate atepta terminarea (MPI_Wait) pentru a declana o nou operaie de comunicare, sau poate dealoca cererea persistent cu MPI_Request_free. MPI_Recv_init ( . . ., &request); MPI_Start (request); // are semantica operatiei immediate MPI_Irecv ... MPI_Wait (&request); MPI_Request_free (&request);

2.9.

Procese nule

n cazul transferurilor ntre procesele benzii de asamblare, este convenabil ca pentru procesele de la margine s se considere ca surs (procesul din stnga) respectiv destinaie (procesul din dreapta) nite procese fictive.

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

Valoarea special MPI_PROC_NULL poate fi folosit n locul unui rang de proces surs sau destinatar. Comunicarea cu un proces fictiv nu are nici un efect. O transmitere de mesaj se termin ntotdeauna cu succes. O recepie de la un proces fictiv se ncheie imediat fr a modifica tamponul de recepie.

3. Tipuri de date MPI


O caracterisitic important a MPI este includerea unui argument referitor la tipul datelor transmise / recepionate. MPI are o mulime bogat de tipuri predefinite: toate tipurile tipurile de baz din C (i din FORTRAN) plus MPI_BYTE i MPI_PACKED. De asemenea, MPI furnizeaz constructori pentru tipuri derivate i mecanisme pentru descrierea unui tip general de date.

3.1.

Aspecte generale

n cazul general, mesajele pot conine valori de tipuri diferite, care ocup zone de memorie de lungimi diferite i ne-contigue. n MPI un tip de date este un obiect care specific o secven de tipuri de baz i deplasrile asociate acestora, relative la tamponul de comunicare pe care tipul l descrie. O astfel de secven de perechi (tip, deplasare) se numete harta tipului. Secvena tipurilor (ignornd deplasrile) formeaz semntura tipului general. Typemap = {(type0, disp0), . . . , (typen-1, dispn-1)} Typesig = {type0, . . . , typen-1} Harta tipului, mpreun cu o adres de baz buf descriu complet un tampon de comunicare: Acesta are n intrri Fiecare intrare i are tipul typei i ncepe la adresa buf+ dispi

Observaie: Ordinea perechilor n Typemap nu trebuie s coincid cu ordinea valorilor din tamponul de comunicare. Putem asocia un titlu (handle) unui tip general i putem folosi acest titlu n operaiile de transmitere / recepie, pentru a specifica tipul datelor comunicate. Tipurile de baz sunt cazuri particulare, predefinite. De exemplu, MPI_INT are harta {(int, 0)}, cu o intrare de tip int i cu deplasament zero. Pentru a nelege modul n care MPI asambleaz datele, utilizm noiunea de extindere (extent). Extinderea unui tip este spaiul dintre primul i ultimul octet ocupat de intrrile tipului, rotunjit superior din motive de aliniere. De exemplu, Typemap = {(double, 0), (char, 8)} are extinderea 16, dac valorile double trebuie aliniate la adrese multiplu de 8. Deci, chiar dac dimensiunea tipului este 9, din motive de aliniere, o nou valoare ncepe la o distan de 16 octei de nceputul valorii precedente. Extinderea i dimensiunea unui tip de date pot fi aflate prin apelurile funciilor int MPI_Type_extent (MPI_Datatype datatype, MPI_Aint *extent); int MPI_Type_size(MPI_Datatype datatype, int *size); Deplasrile sunt relative la o anumit adres iniial de tampon. Ele pot fi substituite prin adrese absolute, care reprezint deplasri relative la adresa zero simbolizat de constanta MPI_BOTTOM. Dac se folosesc adrese absolute, argumentul buf din operaiile de transfer trebuie s capete valoarea MPI_BOTTOM. Adresa absolut a unei locaii de memorie se afl prin int MPI_Address (void *location, MPI_Aint *address);
9

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

unde MPI_Aint este un tip ntreg care poate reprezenta o adres oarecare (de obicei este int) MPI_Address reprezint un mijloc comod aflare a deplasrilor, chiar dac nu se folosete adresarea absolut n operaiile de comunicare.

3.2.

Tipuri derivate

MPI prevede constructori de tipuri derivate. 3.2.1. Tipul contiguu Cel mai simplu constructor produce un nou tip de date fcnd mai multe copii ale unui tip existent, cu deplasri care sunt multipli ai extensiei tipului vechi. De exemplu, dac oldtype are harta {(int, 0) , (double, 8)} atunci noul tip creat prin MPI_Type_contiguous (2, oldtype, &newtype); are harta {(int, 0) , (double, 8), (int, 16) , (double, 24)} Noul tip trebuie ncredinat sistemului nainte de utilizare: MPI_Type_commit (&newtype); pentru ca acesta s poat face optimizrile de performan posibile. Cnd un tip de date nu mai este folosit, el trebuie eliberat cu: MPI_Type_free (&newtype); Observaie: Utilizarea tipului contiguu este echivalent cu folosirea unui contor mai mare ca 1 n operaiile de transfer. Astfel apelul: MPI_Send (buffer, count, datatype, dest, tag, comm); este similar cu: MPI_Type_contiguous (count, datatype, &newtype); MPI_Type_commit (&newtype); MPI_Send (buffer, 1, newtype, dest, tag, comm); MPI_Type_free (&newtype); 3.2.2. Tipul vector Acesta permite specificarea unor date situate n zone necontigue de memorie. Elementele tipului vechi pot fi separate ntre ele de spaii avnd lungimea egal cu un multiplu al extinderii tipului (deci cu un pas constant). Pentru exemplificare, s considerm o matrice de 5 linii i 7 coloane (cu elementele de tip float memorate pe linii). Pentru a construi tipul de date corespunztor unei coloane folosim operaia: MPI_Type_vector (5, 1, 7, MPI_FLOAT, &newtype); unde 5 este numrul de blocuri; 1 este numrul de elemente din fiecare bloc (n cazul n care acest numr este mai mare dect 1, un bloc se obine prin concatenarea numrului respectiv de copii ale tipului vechi); 7 este pasul, deci numrul de elemente ntre nceputurile a dou blocuri vecine; MPI_FLOAT este vechiul tip.

Pentru a transmite coloana a treia a matricii folosim:


10

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

MPI_Send (&a[0][2], 1, newtype, dest, tag, comm); 3.2.3. Tipul hvector Este similar tipului vector, exceptnd faptul c pasul se d n numr de octei i nu n numr de elemente. 3.2.4. Tipul indexed n cazul acestui tip, fiecare bloc are un numr particular de copii ale tipului vechi i un deplasament diferit de ale celorlalte. Deplasamentele sunt date n multipli ai extinderii vechiului tip. Utilizatorul trebuie s specifice ca argumente ale constructorului de tip un tablou de numere de elemente per bloc i un tablou de deplasri ale blocurilor. 3.2.5. Tipul hindexed Este similar tipului indexat, cu diferena c deplasrile sunt msurate n octei. 3.2.6. Tipul struct Este o generalizare a tipului precedent, prin aceea c permite ca fiecare bloc s constea din replici ale unor tipuri de date diferite. 3.2.7. Exemplu n multe probleme de simulare din fizic (N-Body) trebuie considerate interaciuni ntre particule sau obiecte. O reprezentare posibil a unei colecii de particule este urmtoarea: # define MAX_PART 1000 Struct Part_struct { int class; /* clasa particulei */ double d[6]; /* coordonatele particulei */ char b[7]; /* alte informatii */ }; struct Part_struct particle[MAX_PART]; int i, dest, rank; MPI_Comm comm; /* constructia tipului care descrie structura MPI a unei particule, ParticleType */ MPI_Datatype ParticleType; MPI_Datatype type[3] = {MPI_INT, MPI_DOUBLE, MPI_CHAR}; /* semnat */ int blocklen [3] = { 1, 6, 7}; /* lungimi blocuri */ MPI_Aint disp[3]; /* deplasari */ int base; /* calculul deplasarilor */ MPI_Address (particle, disp); MPI_Address (particle[0].d, disp+1); MPI_Address (particle[0].b, disp+2); base=disp[0]; for (i=0; i<3; i++) disp [i] -= base; MPI_Type_struct ( 3, blocklen, disp, type, &ParticleType);
11

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

/* transmiterea intregului tablou */ MPI_Type_commit (&ParticleType); MPI_Send (particle, MAX_PART, ParticleType, dest, tag, comm); Construim tipul ce corespunde particulelor de clasa zero, precedate de numrul acestor intrri. Construcia se face n dou etape: Se construiete tipul indexat al particulelor cu clasa zero, Zparticle; particulele succesive avnd clasa zero sunt tratate ca un bloc; Se construiete tipul struct Ztype cu contorul de particule zero i particulele propriu zise. MPI_Datatype Zparticle; /* toate particulele cu clasa zero */ MPI_Aint zdisp [MAX_PART]; /* tabloul deplasarilor blocurilor */ int zblock [MAX_PART],j,k; /* tabloul numerelor de elem per bloc */ MPI_Aint zdisp [MAX_PART]; /* tabloul deplasarilor blocurilor */ MPI_Datatype Ztype; /* include contorul de particule zero */ int zzblock [2]={1,1}; /* lungimi blocuri, */ MPI_Aint zzdisp [2]; /* deplasari si */ MPI_Datatype Zztype[2]; /* tipuri pentru Ztype */ /* particule consecutive cu clasa 0 sunt tratate ca un bloc */ j=0; /* numar de blocuri */ for(i=0; i<MAX_PART; i++) /* parcurge toate particulele */ if (particle[i].class == 0) { for (k=i+1; (k<MAX_PART)&&(particle[k].class == 0); k++) ; zdisp[j] = i; zblock[j] = k-i; /* lungimea blocului */ j ++; i = k; } MPI_Type_indexed(j, zblock, zdisp, ParticleType, &Zparticle); /* pregatesc contorul de particule */ MPI_Address(&j, zzdisp); MPI_Address(particle, zzdisp+1); zztype[0] = MPI_INT; zztype[1] = Zparticle; MPI_Type_struct(2, zzblock, zzdisp, zztype, &Ztype); MPI_Type_commit(&Ztype); MPI_Send (MPI_BOTTOM, 1, Ztype, dest, tag, comm); /* adrese absolute pentru valori ale unor variabile diferite */ Tem:
12

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

Descrierea transmiterii primelor dou coordonate ale tuturor intrrilor Descrierea folosind adresa absolut n tipurile de date

4. Topologii de procese
4.1. Generaliti

Procesele unui grup de au ranguri de la 0 la n-1 (n fiind numrul de procese din grup). n multe aplicaii, ordonarea liniar a proceselor, dup rang, nu reflect tiparul de comunicare ntre procese. Adesea, procesele trebuie aranjate n topologii gril cu dou sau mai multe dimensiuni. n cazul general, tiparul de comunicare ntre procese corespunde unui graf. Un astfel de aranjament al proceselor, care reflect comunicrile punct la punct dintre ele reprezint topologia virtual a grupului de procese. Trebuie fcut distincie ntre topologia virtual a proceselor i topologia real a sistemului pe care acestea sunt executate. Topologia virtual poate fi exploatat de sistem n plasarea proceselor pe procesoare, pentru a ameliora performanele. Cum se face acest lucru este o chestiune ce iese din sfera problemelor MPI. Oricum, s reinem c topologia virtual reflect caracteristicile aplicaiei i poate fi folosit n mbuntirea performanelor. Sunt cunoscute tehnici standard de mapare a unor topologii gril / tor pe hipercuburi sau grile de procesoare. Pentru topologiile graf metodele sunt mai complexe i se bazeaz adesea pe euristici. n afara informaiei furnizate algoritmului de plasare a proceselor pe procesoare, topologiile virtuale au ca rol facilitarea scrierii programelor, ntr-o form mai uor de neles.

4.2.

Topologii virtuale

Topologia virtual poate fi modelat ca un graf, n care nodurile reprezint procese, iar arcele perechile de procese care comunic. Nu trebuie ca o comunicare s fie precedat de o deschidere explicit de canal. Ca urmare, absena unui arc ntre dou noduri din graf nu nseamn c procesele respective nu vor putea comunica ntre ele. Pur i simplu, nseamn c o astfel de comunicare nu conteaz la maparea topologiei virtuale de procese pe o topologie real de precesoare. Arcele grafului de comunicare nu sunt ponderate. Experiene cu tehnici similare din PARMACS arat c aceast informaie (dou noduri sunt sau nu conectate) este suficient pentru o bun mapare. O alt variant ar complica interfaa MPI i ar face mai dificil activitatea programatorului, care ar trebui s specifice mai multe informaii la conceperea aplicaiilor. Dei specificarea topologiei n termeni de graf este foarte general, n multe aplicaii specificarea unei topologii mai simple, regulate, este mai convenabil. De exemplu inel, grile bi- sau tri-dimensionale, tor. Aceste topologii sunt complet definite prin numrul de dimensiuni i prin numrul de procese pe fiecare ax de coordonate. Maparea unor topologii gril sau tor este mai simpl dect maparea unui graf. De aici i interesul din MPI pentru tratarea separat, explicit a acestora. ntr-o structur cartezian, numrtoarea pe fiecare coordonat ncepe de la zero, iar variaia corespunde unei numrri pe linii. De exemplu, pentru o gril de 2x2, corespondena ntre rangul proceselor i coordonatele lor este urmtoarea: Coord (x,y) Coord (0,0) Coord (0,1)
13

Rang k 0 1

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

Coord (1,0) Coord (1,1) O descompunere cartezian bi-dimensional este urmtoarea:

2 3

Figura 3. n figur este schiat i o deplasare cu 1 dup prima dimensiune.

4.3.

Rutine pentru topologii carteziene

MPI include o colecie de rutine pentru definirea, examinarea, manipularea topologiilor carteziene. Funcia MPI_Cart_create (comm_old,ndims,dims,periods,reorder,comm_cart); creaz o topologie cartezian a proceselor din grupul specificat de comm_old i ntoarce un nou comunicator, comm_cart, la care este ataat informaia de topologie cartezian (ca informaie ascuns). Utilizatorul poate preciza numrul de dimensiuni ndims, i numrul de procese pe fiecare dimensiune n tabloul dims. Argumentul periods (tablou boolean de dimensiune ndims) precizeaz dac grila este periodic sau nu, pe fiecare dimensiune (pentru o gril periodic, ultimul ultimul element pe dimensiunea respectiv este conectat cu primul)

14

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

Figura 4 n fine, parametrul reorder precizeaz dac rangurile proceselor pot fi reordonate sau nu, lsnd sau nu MPI s gseasc o asignare convenabil a elementelor topologiei. Descompunerea din figura 2 poate fi produs de dims[0] = 4; periods [0] = 0; dims[1] = 3; periods [1] = 0; MPI_Cart_create (MPI_COMM_WORLD,2,dims,periods,1,comm_cart); Parametrul reorder are valoarea 1, astfel nct se permite reordonarea proceselor. Vectorul dims poate fi calculat convenabil prin funcia MPI_Dims_create (nrnodes, ndims, dims); care realizeaz o distribuie echilibrat a celor nrnodes procese pe cele ndims dimensiuni. Pentru a putea afla poziia i, implicit, vecinii, unui proces inclus ntr-o structur cartezian sunt dou soluii. Una este MPI_Cart_get (comm, maxdims, dims, periods, coords); care furnizeaz dimensiunile dims, perioadele periods i coordonatele coords ale procesului apelant. Cea de-a doua MPI_Cart_coords (comm, rank, maxdims, coords); ntoarce coordonatele procesului cu rangul rank din grupul comm. Argumentul maxdims d dimensiunea vectorilor dims, periods i coords n programul apelant. O alt posibilitate este legat de operaia executat de proces, n general o deplasare de date de-a lungul unei axe de coordonate. Astfel, s considerm o gril bidimensional pentru calculul produsului a dou matrice. Fiecare element [i,j] pstreaz elementele aij, bij ale celor dou matrice i calculeaz elementul cij al produsului. n acest scop sunt necesare deplasri pe linii ale elementelor a, n aa fel nct [i,j] s intre n posesia tuturor elementelor ai1, ai2, . . . , aij, . . . , ain i deplasri pe coloane ale elementelor b astfel nct [i,j] s intre n posesia tuturor elementelor b1j, ba2j, . . . , bnj. Produsul poate fi

15

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

calculat cu formula cunoscut cij = aik * bkj . O operaie MPI_Sendrecv are ca parametru rangul
k

unui proces surs, pentru recepie, i rangul unui proces destinaie pentru transmisie. Funcia
MPI_Cart_shift (comm, direction, disp, ranksource, rankdest);

furnizeaz ambele informaii. Utilizatorul specific direcia de coordonate (coordonata a crei valoare este modificat de deplasare) i dimensiunea pasului, disp, pozitiv sau negativ. n funcie de periodicitatea specificat pentru coordonata respectiv, deplasarea este sau nu circular. n a doua situaie, funcia ntoarce valoarea MPI_PROC_NULL dac este cazul (pentru procesele de la margine).
4.3.1. Exemplu

Comunicatorul comm are asociat o topologie cartezian bidimensional, periodic. Un tablou bidimensional de valori float este memorat, un element per proces, n variabila A. Se dorete modificarea tabloului prin deplasarea dup direcia 0 printr-un numr de pai dat de a doua coordonat (coords[1]). Mesajele vor avea tagul 0.
int coords[2]; MPI_Comm_rank(comm, &rank); MPI_Cart_coords (comm, rank, 2, coords); MPI_Cart_shift (comm, 0, coords[1], &source, &dest); MPI_Sendrecv_replace(&A,1,MPI_FLOAT,dest,0,source,0,comm,&status);

4.4.

Rutine pentru topologii generale

Pentru o topologie general, de graf, utilizatorul trebuie s specifice urmtoarele elemente definitorii: Numrul de noduri, apoi pentru fiecare nod Gradul nodului Lista vecinilor

n MPI aceste informaii se gsesc ntr-o form specific. Constructorul unei topologii generale (graf) este
MPI_Graph_create(comm_old,nnodes,index,edges,reorder,comm_graph);

Unde parametri nnodes, index i edges definesc structura de graf: Parametrul nnodes este numrul de noduri din graf, notate 0 . . nnodes-1 Intrarea i-a din tabelul index pstreaz numrul total de vecini ai primelor i noduri, astfel nct index[0] este gradul nodului 0; index[i]-index[i-1] este gradul nodului i Listele vecinilor nodurilor 0. . nnodes-1 sunt pstrate n elemente succesive n tabloul edges, astfel nct vecinii nodului 0 sunt n edges[j], cu 0<=j<index[0]; vecinii nodului i sunt n edges[j], cu index[i-1]<=j<index[i]

Topologia asociat unui comunicator poate fi aflat cu


MPI_Topo_test(comm, status);

unde status este un ntreg cu urmtoarele valori posibile: MPI_GRAPH MPI_CART MPI_UNDEFINED
16

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

Informaiile despre topologia graf pot fi aflate cu MPI_Graphdims_get, care d numrul de noduri i numrul de muchii din graf MPI_Graph_get, care d tablourile index i edges MPI_Graph_neighbours_count, care d numrul de vecini ai unui nod MPI_Graph_neighbours, care d tabloul rangurilor vecinilor unui nod
4.4.1. Exerciiu

Fie comm un comunicator cu o topologie shuffle; grupul are 2n membri. Fiecare proces, etichetat (a1, a2, an), are trei vecini: exchange (a1, a2, an) = a1, a2, an (an = 1-an) shuffle (a1, a2, an) = a2, a3, an, a1 unshuffle (a1, a2, an) = an, a1, an-1

De exemplu, pentru n=3 avem situaia urmtoare, prezentat apoi n figura 5:


nod 0 1 2 3 4 5 6 7 exchange shuffle unshuffle

1 0 3 2 5 4 7 6

0 2 4 6 1 3 5 7

0 4 1 5 2 6 3 7

Figura 5 Presupunnd c fiecare proces are o variabil A de tip float, s se permute valorile A, cu nlocuire, succesiv, pentru fiecare.
MPI_Comm_rank (comm, &myrank); MPI_Graph_neighbours (comm, myrank, 3, neighbours);
17

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

MPI_Sendrecv_replace(&A,1,MPI_FLOAT,neighbours[0],0,neighbours[0], 0, comm, &status); MPI_Sendrecv_replace(&A,1,MPI_FLOAT,neighbours[1],0,neighbours[2], 0, comm, &status); MPI_Sendrecv_replace(&A,1,MPI_FLOAT,neighbours[2],0,neighbours[1], 0, comm, &status);

5. Comunicarea colectiv
Operaiile colective implic un grup de procese. Pentru execuie, operaia colectiv trebuie apelat de toate procesele, cu argumente corespondente. Procesele implicate sunt definite de argumentul comunicator, care precizeaz totodat contextul operaiei. Multe operaii colective, cum este difuzarea, presupun existena unui proces deosebit de celelalte, aflat la originea transmiterii sau recepiei. Un astfel de proces se numete rdcin. Anumite argumente sunt specifice rdcinii i sunt ignorate de celelalte procese, altele sunt comune tuturor. Operaiile colective se mpart n mai multe categorii: Sincronizare de tip barier a tuturor proceselor grupului
Comunicri colective, n care se include:

Difuzarea Colectarea datelor de la membrii grupului la rdcin Distribuirea datelor de la rdcin spre membrii grupului Combinaii de colectare / distribuire (allgather i alltoall) Operaii de reducere Combinaii reducere / distribuire

Calcule colective:

18

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

Figura 6

5.1.

Caracteristici comune operaiilor colective

5.1.1. Tipul datelor

Cantitatea de date transmis trebuie s corespund cu cantitatea de date recepionat. Deci, chiar dac hrile tipurilor difer, semnturile lor trebuie s coincid.
5.1.2. Sincronizarea

Terminarea unui apel are ca semnificaie faptul c apelantul poate utiliza tamponul de comunicare, participarea sa n operaia colectiv ncheindu-se. Asta nu arat c celelalte procese din grup au terminat operaia. Ca urmare, exceptnd sincronizarea barier, o operaie colectiv nu poate fi folosit pentru sincronizarea proceselor.
5.1.3. Comunicator

Comunicrile colective pot folosi aceiai comunicatori ca cele punct la punct. MPI garanteaz diferenierea mesajelor generate prin operaii colective de cele punct la punct.
5.1.4. Implementare

Rutinele de comunicare colectiv pot fi bazate pe cele punct la punct. Aceasta sporete portabilitatea, fa de implementrile bazate pe rutine ce exploateaz arhitecturi paralele.

5.2.

Difuzarea i calculele colective


la calculul lui prin integrare numeric cu formula:

Exemplul urmtor se refer 1 1 1 1 + x 2 dx = arctan( x) |0 = 4 . 0

Pentru calculul lui se consider integrarea funciei f ( x) =

4 , folosind metoda dreptunghiurilor. 1+ x2 Intervalul (0,1) se mparte ntr-un numr de n subintervale i se nsumeaz ariile dreptunghiurilor avnd ca baz fiecare subinterval. Pentru execuia algoritmului n paralel, se atribuie, fiecruia dintre procesele din grup, un anumit numr de subintervale. Cele dou operaii colective care apar n rezolvare sunt: Difuzarea valorilor lui n, tuturor proceselor
19

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

nsumarea valorilor calculate de procese

Operaia

MPI_Bcast(buffer, count, datatype, root, comm)


difuzeaz mesajul (buffer, count, datatype) de la procesul root la toate procesele grupului din comm. Operaia

MPI_Reduce(sendbuf, recvbuf, count, datatype, op, root, comm)


combin valorile din sendbuf ale fiecrui proces, folosind operaia op i pune rezultatul n recvbuff n procesul root. Tamponul de intrare este definit de (sendbuf, count, datatype), iar cel de ieire de (recvbuf, count, datatype). Ambele tampoane au acelai numr de elemente, cu acelai tip. n cazul n care fiecare proces specific o secven de elemente, operaia se realizeaz separat, pentru fiecare intrare a secvenei.

Figura 7

# include mpi.h # include <math.h> int main (int argc, char **argv) { int n, myid, numprocs, i, rc; double mypi, pi, h, sum, x, a; MPI_Status status; MPI_Init (&argc, &argv); MPI_Comm_size (MPI_COMM_WORLD, &numprocs); MPI_Comm_rank (MPI_COMM_WORLD, &myid);
20

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

while (1) { if (myid==0) { printf(Numar subintervale (0=gata): ); scanf(%d,&n); } MPI_Bcast (&n, 1, MPI_INT, 0, 99, MPI_COMM_WORLD); if(!n) break; h=1.0/(double)n; sum=0.0; for (i = myid + 1; i <= n; i += numprocs) { x = h*((double)i-0.5); sum += (4.0 / (1.0 + x*x)); } mypi = h * sum; MPI_Reduce (&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); if (!myid) printf(pi este %f\n, pi); } MPI_Finalize(); }
MPI furnizeaz o mulime de operatori de reducere asociativi i comutativi, pentru aflarea maximului, muinimului, sumei, produsului, conjunciei, disjunciei, etc.

5.3.

Comunicri colective

Pentru exemplificare, considerm transferul, de la fiecare proces la rdcin, a 100 de valori ntregi. La destinaie, grupurile de 100 de valori sunt plasate la distana stride ntre ele.

Figura 8 Se utilizeaz operaia

21

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

MPI_Gatherv (sendbuf, sendcount, sendtype, recvbuf, recvcounts, comm);

displs,

recvtype,

root,

care permite ca fiecare proces (inclusiv root) s transmit coninutul tamponului su (sendbuf, sendcount, sendtype) procesului root. Contoarele pot fi diferite, astfel c la root valorile care le corespund sunt reprezentate de un tablou, recvcounts. De asemenea, datele sunt plasate n tamponul recvbuf al procesului root, n poziii care sunt descrise de vectorul displs. Datele transmise de procesul j sunt plasate ncepnd din poziia displs[j] (msurat n elemente de recvtype). Tamponul de recepie este ignorat pentru toate procesele diferite de root. Specificaia contoarelor i deplasrilor nu trebuie s conduc la scrierea de mai multe ori a unei locaii din root.

MPI_Comm comm; int gsize, sendarray[100]; int root, *rbuf, stride; int *displs, i, *rcounts; ... MPI_Comm_size (MPI_COMM_WORLD, &gsize); rbuf = (int *) malloc (gsize * stride * sizeof(int)); displs = (int *) malloc (gsize * sizeof(int)); rcounts = (int *) malloc (gsize * sizeof(int)); for (i = 0; i < gsize; i ++) { displs [i] = i * stride; rcounts [i] = 100; } MPI_Gatherv(sendarray, 100, MPI_INT, vbuf, rcounts, displs, MPI_INT,
Observaie. Programul este eronat pentru stride <100!

root, comm);

5.4.

Corectitudinea operaiilor colective

Aa cum s-a precizat mai devreme, operaiile colective pot avea sau nu efectul de sincronizare a tuturor proceselor din grup. Ca urmare, programele trebuie s invoce operaiile colective astfel nct s se evite blocarea definitiv, indiferent dac operaiile sunt sau nu sincronizate. De aici rezult cteva reguli: Operaiile colective trebuie executate n aceeai ordine de toate procesele grupului Nu trebuie s existe dependene circulare ntre operaii Operaiile punct la punct blocante nu trebuie s ncalece operaiile colective

Urmtorul exemplu este eronat:

switch(rank) { case 0: MPI_Bcast (..., 0, comm); MPI_Send (..., 1, tag, comm); break; case 1: MPI_Recv (..., 0, tag, comm, status); MPI_Bcast (..., 0, comm); break;
22

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

}
A treia regul evideniaz un aspect foarte important: dei contextele operaiilor punct la punct i colective, asociate unui comunicator sunt distincte i, deci, traficul operaiilor punct la punct este independent de traficul generat de operaiile colective o programare necorespunztoare a operaiilor poate conduce la interblocarea proceselor, datorit posibilelor restricii impuse de sincronizarea operaiilor.

5.5.

Determinismul operaiilor

Modelele de programare bazate pe comunicarea de mesaje sunt nedeterministe: ordinea sosirii a dou mesaje transmise de dou procese A i B unui al treilea proces C este nedefinit. (din contr, MPI asigur c dou mesaje transmise de un acelai proces A ajung n aceeai ordine la B). Este rolul programatorului de a asigura c un calcul este determinist, acolo unde el trebuie s fie aa. Determinismul poate fi garantat prin definirea unui canal pentru fiecare pereche de procese care comunic. n acest caz, procesul C poate face diferena ntre mesajele primite de la A i cele primite de la B, deoarece ele sosesc pe canale diferite. MPI nu accept conceptul de canal, dar are mecanisme similare, care permit unui receptor s specifice sursa mesajului, tag-ul i contextul. Oricum, deoarece MPI permite specificarea oricrei surse, MPI_ANY_SOURCE i a oricrui tag, MPI_ANY_TAG, folosirea acestor parametri trebuie fcut cu grij. S considerm urmtorul fragment de program, n care un proces transmite i primete de max ori mesaje de date i apoi un mesaj rezultat.

for(i=0;i<max;i++) { MPI_Send (buff, 600, MPI_FLOAT, r1, 1, MPI_COMM_WORLD); MPI_Recv (buff, 600, MPI_FLOAT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); . . . } MPI_Send (buff, 300, MPI_FLOAT, r2, 2, MPI_COMM_WORLD); MPI_Recv (buff, 300, MPI_FLOAT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
Deoarece nu se specific nici o surs i nici un tag n operaiile de recepie, ordinea ntre ultimul mesaj de date i cel de rezultate se poate inversa, conducnd la un rezultat eronat. Eroarea poate fi ndreptat prin specificarea unor valori precise pentru tag-uri i, eventual, pentru procesele surs.

6. Dezvoltarea bibliotecilor paralele peste MPI


Bibliotecile construite peste MPI i orientate ctre aplicaii (de exemplu de algebr liniar) ofer un grad sporit de abstractizare i de portabilitate. Creare unor astfel de biblioteci necesit urmtoarele caracteristici, pe care MPI le posed: Un spaiu de comunicare sigur, care garanteaz c bibliotecile pot comunica fr a avea conflicte cu comunicri din exteriorul su; Limitarea operaiilor colective la nivelul grupului de procese, evitnd sincronizri inutile, cu procese ce execut alte operaii, independente de cele ale grupului; Un mecanism de denumire abstract a proceselor, care s permit bibliotecilor s descrie comunicrile n termeni convenabili propriilor algoritmi i structuri de date;
23

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

Posibilitatea de a mbogi o mulime de procese comunicante cu atribute definite de utilizator, ceea ce permite extinderea operaiilor de comunicare.

Aa cum s-a artat anterior, tag-urile mesajelor furnizeaz un mecanism pentru deosebirea mesajelor folosite n scopuri diferite. Ele nu sunt ns suficiente pentru modularizarea programelor. S considerm o aplicaie care apeleaz o rutin de bibliotec (ce face, de exemplu, transpunerea unei matrici). Este important s se asigure c tag-urile mesajelor folosite n bibliotec sunt distincte de cele folosite n restul aplucaiilor. Altfel pot apare erori. n figur sunt reprezentate patru procese, care apeleaz o rutin de bibliotec (reprezentat prin zona dreptunghiular). Unul din procese termin mai devreme rutina, dup care genereaz un mesaj (linia punctat) interceptat de bibliotec. Utilizarea unor contexe diferite evit aceast situaie (figura din dreapta).

Figura 9 Apelul funciei

MPI_Comm_dup (comm, &newcomm)


permite crearea unui nou comunicator care include acelai grup de procese, dar cu un nou context. Pentru a rezolva problema anterioar, generat de compunerea secvenial a unor programe paralele, se genereaz un nou comunicator, care este trimis ca parametru rutinei de bibliotec.

MPI_Comm_dup (comm, &newcomm) Transpose (newcomm, A) MPI_Comm_free (&newcomm)


Rutina transpose va fi creat astfel nct s fac ux de comunicatorul transmis ca argument.

Compunerea paralel denot execuia paralel a dou sau mai multor componente de program pe mulimi disjuncte de procesoare. Abordarea prin task-uri paralele (figura stnga), se creaz dinamic task-uri care execut componente diferite de program. n figur sunt reprezentate patru noi task-uri, de dou tipuri diferite, pentru a executa dou componente diferite de program.

24

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

Figura 10 n abordarea MPI, procesele i schimb caracterul: procesele disponibile sunt partiionate n dou seturi, corespunztor celor dou componente de program de executat. Pentru aceasta se folosete apelul

MPI_Comm_split (comm, color, myid, &newcomm)


care este o operaie colectiv, executat de procesele din grupul comm. Ea produce comunicatoare noi, cte unul pentru fiecare valoare distinct argumentului color. De exemplu secvena urmtoare produce trei comunicatoare noi, dac grupul iniial conine cel puin trei procese.

MPI_Comm_rank (comm, &myid); color=myid%3; MPI_Comm_split (comm, color, myid, &newcomm)

Figura 11 Pentru a permite crearea unor biblioteci robuste, MPI furnizeaz urmtoarele mecanisme: Contexte Grupuri Topologii virtuale Atribute ascunse Comunicatori

n MPI comunicarea poate avea loc n cadrul unui grup (intra-comunicare), sau ntre dou grupuri distincte (inter-comunicare). Corespunzator, comunicatorii se mpart n dou categorii: intra_comunicatori i inter_comunicatori.
25

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

Un intra-comunicator descrie: Un grup de procese Contexte pentru comunicare punct la punct i colectiv (aceste dou contexte sunt disjuncte, astfel c un mesaj punct la punct nu se poate confunda cu un mesaj colectiv, chiar dac au acelai tag) O topologie virtual (eventual) Alte atribute

MPI are serie de operaii pentru manipularea grupurilor. Aflarea grupului asociat unui comunicator Gsirea numrului de procese dint-un grup i a rangului procesului apelant Compararea a doua grupuri Reuniunea, intersecia, diferena a dou grupuri Crearea unui nou grup din altul existent, prin includerea sau excluderea unor procese Desfiinarea unui grup

Funcii similare sunt prevzute pentru manipularea intra-comunicatorilor: Gsirea numrului de procese sau a rangului procesului apelant Compararea a doi comunicatori Duplicarea, crearea unui comunicator Partiionarea grupului unui comunicator n grupuri disjuncte Desfiinarea unui comunicator

Un inter-comunicator leag dou grupuri, mpreun cu contextele de comunicare partajate de cele dou grupuri. Contextele sunt folosite doar pentru operaii punct-la-punct, neexistnd comunicare colectiv intergrupuri. Nu exist topologii virtuale n cazul intercomunicrii. O inter-comunicare are loc ntre un proces iniiator, care aparine unui grup local i un proces int, care aparine unui grup distant. Procesul int este specificat printr-o pereche (comunicator, rang) relativ la grupul distant. n implementarea MPI un comunicator este reprezentat n fiecare proces printr-un tuplu care conine: Grupul Contextul_send Contextul_receive Sursa

Pentru intercomunicri, discuia trebuie s se refere la ambele procese, iniiator i int. Fie P un proces n grupul GP, care are un inter-comunicator CGP i un proces Q n GQ cu un inter-comunicator CGQ. Atunci: CGP.group descrie grupul Q, iar CGQ.group descrie grupul P CGP.context_send = CGQ. context_receive i contextul este unic n GQ CGQ.context_receive = CGP. context_send i contextul este unic n GP CGP.sursa este rangul lui P n GP i CGQ.sursa este rangul lui Q n GQ.

26

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

Cnd P transmite un mesaj lui Q folosind inter-comunicatorul, P folosete tabela grupului pentru a afla adresa absolut a lui Q. El adaug mesajului informaia despre surs i contextul_send. Q are o recepie cu un argument surs explicit, folosind inter-comunicatorul. Atunci Q compar contextul_receive cu contextul din mesaj i argumentul sursa cu sursa din mesaj. MPI permite urmtoarele operaii relative la inter-comunicatori: Testul unui comunicator pentru a afla dac este intra sau inter Aflarea numrului de procese din grupul distant Aflarea grupului distant Legarea a doi intra-comunicatori ntr-un inter-comunicator

MPI_Intercomm_create (local_comm, local_leader, peer_comm, newintercommunicator);


remote_leader,

tag,

Crearea unui intra-comunicator prin unirea grupurilor local i distant ale unui inter-comunicator Duplicarea i desfiinarea unui inter-comunicator

MPI_Intercomm_merge (inter_comm, high, newintracommunicator);


Crearea unui inter-comunicator presupune c doi membri, selectai cte unul din fiecare grup (leader), pot comunica ntre ei. Deci exist un comunicator cruia cei doi leaderi i aparin. n plus: Fiecare leader tie rangul celuilalt n peer_comm Membrii fiecrui grup cunosc rangul leader-ului lor

Un inter-comunicator este creat printr-o operaie colectiv executat n cele dou grupuri ce urmeaz a fi conectate. Procesele trebuie s specifice un intra-comunicator local, care identific procesele incluse n grupul lor; trebuie s convin asupra unui leader n fiecare grup i asupra unui comunicator printe care leag leaderii i prin care conexiunea poate fi stabilit. Cei doi leaderi sunt identificai prin (local_comm, local_leader) respectiv (peer_comm, remote_leader).

6.1.1. Exemplu
Un inel de trei grupuri.

Figura 12 Fiecare grup necesit doi inter-comunicatori. Mai nti se partiioneaz grupul de procese MPI_COMM_WORLD n trei subgrupuri, utilizndu-se drept culoare restul modulo 3 al rangului, pstrat n variabila membershipkey. Se folosete operaia

MPI_Comm_split (comm, color, key, newcomm)


n noul grup, procesele sunt ordonate dup cheie, coliziunile fiind rezolvate prin utilizarea rangului proceselor din grupul iniial. Apoi se construiesc inter-comunicatorii, cte doi pentru fiecare grup. MPI_Intercomm_create este o operaie colectiv peste grupurile local i distant. n fiecare grup procesele trebuie s prevad argumente local_comm i local_leader identice. Apelul folosete comunicarea punct la punct cu comunicatorul peer_comm i cu tag, ntre leaderii grupurilor.
27

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

int main (int argc, char **argv) { MPI_Comm myComm; MPI_Comm myFirstComm; MPI_Comm mySecondComm; MPI_Status status; int rank, membershipkey;

/* intra-comm grup local */ /* inter-comm */

MPI_Init (&argc, &argv); MPI_Comm_rank (MPI_COMM_WORLD, &rank); ... /* generez membership key in domeniul {0, 1, 2} */ membershipkey = rank % 3; /* construiesc intra-comunicator pentru subgrup local */ MPI_Comm_split (MPI_COMM_WORLD, (color=membershipkey), (key=rank), &mycomm) /* construiesc inter-comunicatorii, taguri fixe */ if (membershipkey==0) /* grupul 0 comunica cu 1 si 2 */ { MPI_Intercomm_create (myComm, 0, MPI_COMM_WORLD, 1, 1, &myFirstComm); MPI_Intercomm_create (myComm, 0, MPI_COMM_WORLD, 2, 2, &mySecondComm); } else if (membershipkey==1) /* grupul 1 comunica cu 0 si 2 */ { MPI_Intercomm_create (myComm, 0, MPI_COMM_WORLD, 0, 1, &myFirstComm); MPI_Intercomm_create (myComm, 0, MPI_COMM_WORLD, 2, 12, &mySecondComm); } else if (membershipkey==2) /* grupul 2 comunica cu 0 si 1 */ { MPI_Intercomm_create (myComm, 0, MPI_COMM_WORLD, 0, 2, &myFirstComm); MPI_Intercomm_create (myComm, 0, MPI_COMM_WORLD, 1, 12, &mySecondComm); } /* alte operatii */ ... /* eliberare comunicatorilor si terminare */ MPI_Comm_free (&myFirstComm); MPI_Comm_free (&mySecondComm); MPI_Comm_free (&myComm); MPI_Finalize(); }
Parametrii subliniai au n ordine semnificaiile urmtoare: Leader
28

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

Comunicator comun al leaderilor Rangul leaderului din grupul distant n comunicatorul comun Tag sigur

Deoarece funciile relative la topologie sunt aplicabile doar intra-comunicatorilor, nu i intercomunicatorilor, MPI_Intercomm_merge este o soluie pentru a construi un intra-comunicator i a induce apoi pe el o topologie cartezian sau graf.

7. Faciliti MPI 2
7.1. Procese dinamice

MPI presupune existena unui mediu de execuie a proceselor, cu care interaciunea este pstrat la un nivel sczut pentru a evita compromiterea portabilitii. Interaciunea se limiteaz la urmtoarele aspecte: Un proces poate porni dinamic alte procese prin MPI_Comm_spawn i MPI_Comm_spawn_multiple Poate comunica printr-un argument info informaii despre unde i cum s porneasc procesul Un atribut MPI_UNIVERSE_SIZE al MPI_COMM_WORLD precizeaz cte procese pot rula n total, deci cte pot fi pornite dinamic, n plus fa de cele n execuie

Comanda

MPI_Comm_spawn(command, array_of_errcodes);

argv,

maxprocs,

info,

root,

comm,

intercomm,

ncearc s porneasc maxprocs copii ale unui program MPI specificat de comanda command; argv conine argumentele transmise programului, n forma unui tablou de iruri de caractere. Parametrul info conine informaii adiionale pentru mediul de execuia n forma unor perechi de iruri de caractere (cheie, valoare). Informaia comunicat prin info este transparent pentru MPI. Operaia este executat n colectiv de procesele grupului comm, dar argumentele anterioare sunt examinate doar de procesul root din acest grup. Procesele puse n execuie sunt considerate fii ai proceselor care execut comanda. Acetia au propriul lor MPI_COMM_WORLD, distinct de acela al prinilor Apelul ntoarce un inter-comunicator pentru comunicare ntre prini i fii. Acesta conine procesele printe n grupul local i procesele copii n grupul distant. Inter-comunicatorul poate fi obinut de copii prin funcia MPI_Comm_get_parent. MPI permite stabilirea unor canale de comunicare ntre procese, chiar dac acestea nu mpart un comunicator comun. Aceasta este util n urmtoarele situaii: Dou pri ale unei aplicaii, pornite independent, trebuie s comunice ntre ele Un instrument de vizualizare vrea s se ataeze la un proces n execuie Un server vrea s accepte conexiuni de la mai muli clieni; serverul i clienii pot fi programe paralele.

7.2.

Accesul distant la memorie RMA (Remote Memory Access)

RMA extinde mecanismele de comunicare MPI, permind unui proces s specifice parametrii de comunicare pentru ambele capete implicate ntr-un tampon de date. Prin aceasta, un proces poate citi, scrie sau actualiza date din memoria altui proces, fr ca al doilea proces s fie explicit implicat n transfer. Cele trei operaii sunt reprezentate n MPI prin MPI_Put, MPI_Get, MPI_accumulate. n afara acestora, MPI furnizeaz operaii de iniializare, MPI_Win_create care permit fiecrui proces al unui grup s specifice o fereastr n memoria sa, pus la dispoziie celorlalte pentru RMA, i
29

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

terminare, MPI_Win_free pentru eliberarea ferestrei, ca i operaii de sincronizare a proceselor care fac acces la datele altui proces. Comunicrile RMA intr n dou categorii: Cu int activ, n care toate datele sunt mutate din memoria unui proces n memoria altuia i ambele sunt implicate n mod implicit. Un proces prevede toate argumentele pentru comunicare, al doilea participa doar la sincronizare Cu int pasiv, unde datele sunt mutate din memoria unui proces n memoria altui proces, i numai unul este implicat n mod implicit n comunicaie dou procese pot comunica fcnd acces la aceeai locaie ntr-o fereastr a unui al treilea proces (care nu particip explicit la comunicare)

MPI 2 prevede i alte faciliti, cum ar fi operaii de intrare/iesire paralele, la care nu ne referim aici.

8. Implementarea MPI
MPI este implementat pe o mare diversitate de sisteme, de la cele de nalt performan la colecii de staii de lucru (Workstation Clusters). Interesul pentru acest din urm a crescut odat cu introducerea noilor tehnologii de comunicare de mare viteze: ATM, FDDI, Myrinet, FastEthernet, etc. Exist deja implementri MPI construite pe baza protocolului TCP/IP, car care au performae reduse. Dintre multiplele implementri MPI am ales MPICH, dezvoltat la Argonne National Laboratory & Mississippi State University. Portabilitatea acestei implementri deriv din construcia ei pe baza unui numr restrns de funcii care creaz independena de hardware, formnd mpreun o interfa de echipament abstract, ADI (Abstract Device Interface). Pentru a porta MPI pe alt sistem este necesar implementarea funciilor ADI. ADI ncapsuleaz detaliile i complexitatea suportului hardware al comunicaiei ntr-un modul separat. El se rezum la servicii de comunicare punct la punct. Peste el, restul MPICH conine implementarea ntregului standard, incluznd: Gestiunea comunicatorilor Tipuri de date derivate Operaii colective

Rutinele ADI de baz se rezum la urmtoarele funcii: Iniializare i terminare ADI MPID_Init, MPID_End Iniializarea unei transmisii / recepii de mesaj, MPID_Port_send (send_ready, send_sync), MPID_Recv. . . Testul terminrii unei operaii sau a sosirii unui anume mesaj, MPID_Test_send, MPID_Test_recv, MPID_Iprobe Terminarea unei transmisii / recepii, MPID_Complete_send, MPID_Complete_recv Anularea unei operaii, MPID_Cancel Verificarea unei operaii n ateptare, MPID_Check_device Aflarea unor informaii legate de rang sau numr de procese, MPID_Myrank, MPID_Mysize.

Ideea de baz ADI este mprierea aplicaiilor de comunicare n dou faze distincte, iniierea i terminarea. Funciilor care realizeaz aceste faze le sunt adugate alte cteva, pentru acumularea unor cereri sau testul terminrii execuiei lor. Desigur, implementarea ADI pe o anumit platform trebuie s in seama de primitivele de comunicare oferite de aceasta. Ne referim n continuare la implementarea pe o colecie de staii de
30

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

lucru conectate prin Myrinet folosind o bibliotec FM (Fast Messages). Biblioteca FM are trei primitive: FM_send_4 (dest, handler, i0,i1,i2,i3), care transmite un mesaj de 4 cuvinte FM_send (dest, handler, buff, size), care transmite un mesaje lung FM_extract (), care prelucreaz mesaje primite

FM difer de alte metode de transfer de mesaje prin aceea c are dou operaii de transmitere asincron, dar nu exist operaii corespunztoare de recepie. n schimb, fiecare mesaj include numele unui handler, care este o funcie definit de utilizator, ce va fi invocat la sosirea mesajului i care va prelucra datele comunicate. Cnd este invocat, FM_extract() prelucreaz mesajele sosite (aflate n ateptare), le scoate din coada mesajelor sosite i pune n execuie handler-ul corespunztor. FM garanteaz recepia sigur i ordonat a mesajelor cu o degradare minim de performane. ntreaga implementare are trei niveluri. Figura urmtoare arat modul de compunere a primitivelor MPI_send i MPI_Recv n termenii primitivelor diferitelor niveluri. Prefixul MPID denot funciile ADI. Funcia FM_extract i rutina async_handler sunt conectate prin linii punctate pentru a arta c ele rspund de evoluia funciilor ADI corespunztoare, dei nu sunt apelate direct de acestea.

Figura 13 Primitivele ADI sunt, semantic, mai apropiate de MPI dect de FM, astfel c fiecare primitiv de comunicare punct la punct MPI i gsete descriere n cteva linii de cod n termenii ADI. Diferene mai mari exist fa de FM: Nu exist o coresponden unu la unu ntre primitivele ADI i FM Primitivele ADI sunt orientate pe faze (start terminare) FM nu are o operaie de recepie explicit

Orientarea pe faze cere ca starea s fie gestionat pentru fiecare operaie n curs. Pe de alt parte, comunicarea n FM se bazeaz pe un modul fr stri. Pentru a suplini diferena, se pstreaz dou cozi, receive i send, fiecare pstrnd o descriere a cererilor i a strilor lor. n plus, la recepie, o coad unexpected pstreaz evidena mesajelor sosite, pentru care nu exist o cerere de recepie corespondent. Fiecare element al cozilor memoreaz un pointer spre spre un tampon temporar i descrierea mesajului corespunztor. Folosirea tampoanelor temporare accelereaz recepia mesajelor, fa de soluia pstrrii acestora la surs pn la apariia unei cereri de recepie. n locul unei operaii de recepie implicite, FM se bazeaz pe funcii definite de utilizatori (handles). Mesajele sosite sunt puse
31

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

n coad n memoria calculatorului gazd i sunt extrase cu FM_extract, care execut handler-ul corespunztor. Deci, implementarea primitivei ADI de recepie nseamn scrierea handler-ului i plasarea corespunztoare a apelurilor FM_extract. Sarcina handler-ului este s copieze mesajul sosit n zona al crei pointer este gsit n cererea de recepie. Handler-ul difer n cazul unei operaii sincrone, el avnd rolul suplimentar de a transmite o confirmare ctre emitor. O abordare diferit este MPI-CCL (Collective Communication Library), care extrage avantaje din faptul c reelele locale ce conecteaz staiile de lucru sunt medii de comunicare cu difuzare. Ca urmare, n locul construciei comunicaiilor colective pe baza transferurilor punct la punct, care nrutete nejustificat performanele operaiilor colective, aceast abordare optimizeaz operaiile colective pentru reelele de staii de lucru, NOW (Network Of Workstations), care furnizeaz un serviciu nesigur de transport cu difuzare (Ethernet, ATM, etc.,). Arhitectura sistemului include dou niveluri, situate ntre nivelul legtur de date al reelei locale i nivelul aplicaiilor MPI (vezi figura). Nivelul inferior, URTP (User-level Reliable Transport Protocol), ofer servicii de transport punct la punct i cu difuzare, sigure, nivelului superior. El realizeaz interfaa cu nivelul legtur de date i convertete n servicii sigure funcionalitatea acestui nivel.

Figura 14 Nivelul superior, MPI-CCL ofer funcionalitatea operaiilor colective ale Mpi. Totodat, el face corespondena necesar, cu nivelul inferior, pentru operaiile punct la punct. n figur sunt precizate cteva noiuni folosite n prezentare: Unitile de date la nivelul aplicaiilor sunt mesajele, de lungime nelimitat; unitile de date la nivelurile inferioare sunt pachetele, limitate superior la 1.5 Koctei; Operaia multireceive este definit ca recepia urmtorului pachet de la fiecare procesor dintr-o colecie specificat.

8.1.1. Programul global


nainte de descrierea principalelor elemente relative la cele dou niveluri, relum aici discuia relativ la corectitudinea programelor MPI, ntr-o form mai detaliat. Un program MPI poate fi vzut ca un singur program global executat pe mai multe procesoare SPMD (Single Program Multiple Data). Modelul garanteaz dou proprieti: Fiecare nod cunoate ordinea pachetelor ateptate de la fiecare din celelalte noduri; Lipsa blocrii datorat spaiului tampon pentru pachete.
32

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

Programele generate de MPI-CCL se supun acestui model. n spe, un astfel de program ar trebui s includ, la fiecare pas: Cel mult o operaie multicast cu anumite procesoare int Cte o operaie receive corespondent pentru fiecare procesor int

O variant mai relaxat (denumit k-buffer correct) specific urmtoarele condiii: Exist o grupare de instruciuni ale programului, n care fiecare grup are cel mult k instruciuni; n fiecare grup, toate operaiile multicast corespund consistent i corect unor operaii receive; Un multicast nu poate corespunde unui receive anterior.

Consecina: se poate obine o implementare corect a unui program k-buffer correct folosind tampoane-sistem pentru k pachete per procesor. De exemplu, pentru o operaie all-to-all cu p procesoare, fiecare procesor poate genera un multicast urmat de p-1 apeluri receive, ntr-o ordine arbitrar. Pentru fiecare procesor sunt suficiente p tampoane pentru p pachete.

8.1.2. Protocolul URTP


URTP a fost proiectat pentru a furniza servicii sigure de transport, punct la punct i multicast, pornind de la idea c, ntr-un LAN, pierderile de pachete se datoreaz n special lipsei spaiului de memorare la receptor. Cerinele avute n vedere sunt urmtoarele: Garantarea ordinii FIFO a pachetelor, indiferent dac sunt punct la punct sau multicast Pstrarea pachetului la transmitor pn la confirmarea recepiei la toate procesoarele int Deoarece anumite pachete pot fi pierdute, se memoreaz la receptor toate pachetele de date, chiar dac se detecteaz o pauz Detecia pierderilor de pachete se poate face cnd MPI-CCL face o cerere receive sau la violarea ordinii FIFO

URTP folosete o versiune modificat a protocolului cu fereastr glisant. Fiecare pereche (sender, receiver) are asociat un contor. La transmiterea punct la punct a unui pachet, valoarea curent a contorului este copiat ntr-un cmp al pachetului. Contorul este apoi incrementat. La un pachet multicast, se introduce un contor pentru fiecare pereche (sender, receiveri). Contoarele sunt apoi incrementate. La transmisie, MPI-CCL d URTP adresa tamponului care conine un pachet i o funcie call-back. Pachetul este transmis, dup care se ateapt confirmrile. Cnd toate sunt recepionate, URTP apeleaz funcia, al crei rol este eliberarea tamponului. Numrul recomandat de tampoane gestionate de MPI-CCL este (p-1)*w, unde p este numrul de procesoare din configuraie, iar w este lrgimea ferestrei. La recepie, MPI-CCL primete, ca urmare a unei cereri de recepie, un pointer la pachetul primit i o funcie call-back de golire a tamponului. Zonele tampon sunt gestionate de URTP i sunt n numr de (p-1)*w+c, unde zona c este rezervat pentru pachete de control (ACK, REQ). Un pachet este confirmat imediat ce ajunge ntr-un tampon URTP. Dac o aplicaie execut o operaie receive i pachetul corespunztor nu este n tamponul URTP, acesta transmite un REQ ctre surs. ACK i REQ sunt pachete punct la punct. De asemenea, unui pachet REQ i se rspunde cu un pachet de date punct la punct, chiar dac pachetul original a fost multicast. Cnd REQ se repet la un pachet nc netransmis, el este ignorat. n fine, pachetelor REQ le este asociat un mecanism time-out. Pachetele REQ acioneaz i cu rol de confirmare. Protocolul este implementat printr-o combinaie de rutine: Unele extind nucleul sistemului de operare
33

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

Altele formeaz o bibliotec URTP n spaiul utilizatorului

8.1.3. MPI-CCL
Scopul acestui nivel este s pun n coresponden rutinele MPI-CCL cu serviciile URTP, ntr-o manier eficient i s mpart mesajele n pachete (sau s refac mesajele din pachete). Pentru interfaa cu URTP se folosesc primitivele multicast, send, receive i multireceive. Ne referim n continuare la implementarea ctorva operaii colective MPI. MPI_Bcast
M Corespondena este direct. Dac M este lungimea mesajului, m lungimea pachetelor URTP, p = m numrul de pachete pe mesaj, pentru implementarea MPI_Bcast Rdcina apeleaz de p ori multicast

Toate celelalte procesoare apeleaz receive de p ori.

MPI_Allgather

Exist dou variante. n prima, fiecare procesor devine pe rnd surs de difuzare, n timp ce restul proceselor primesc. Recepii succesive sunt combinate ntr-un multireceive.

i=mypid; srcs1 = {0, 1, . . . , i-1}; srcs2 = {i+1, i+2, . . . , p-1}; /* p=numar procesoare */ distr = srcs1 srcs2; for (j=0; j<q; j++) /* q=nr pachete/procesor, de difuzat */ { multireceive (srcs1, recvbufs, j); multicast (dests, sendbuf, j); multireceive (srcs2, recvbufs, j); }
n a doua variant, fiecare procesor genereaz k apeluri multicast, urmate de k apeluri multireceive, unde k este un ntreg pozitiv ales conform proprietii kp-buffer correct.

dests = {0, 1, . . . , p-1} {mypid}; j1=0; j2=0; q for (j=0; j< ; j++) k { for (l=0; l<k; l++) if (j1<q) { multicast (dests, sendbuf, i); j1++; } for (l=0; l<k; l++) if (j2<q) { multireceive (dests, recvbufs, j2); } }

MPI_Scatter i MPI_Gather

Pentru mesaje mici, MPI_scatter este implementat prin mpachetarea lor ntr-un singur pachet, care este transmis tuturor proceselor. Pentru mesaje lungi se folosesc transmisii punct la punct. Ultimul pachet al tuturor destinaiilor poate fi transmis prin multicast, dup modelul mesajelor scurte. MPI_Barrier
34

D:\___val_2007\_cursAPD2007\APD_note de curs\7a - MPI.doc

08/11/07

Este implementat ca un MPI_Gather cu un mesaj de lungime 0, de la fiecare procesorla procesorul 0, urmat de MPI_Bcast a unui mesaj de lungime 0 de la procesorul 0.

35

8. Ceasuri logice i ordonarea evenimentelor 8.1 Soluia lui Lamport n vorbirea curent se afirm c un eveniment a s-a produs naintea altui eveniment b dac momentul de timp la care s-a produs a precede momentul producerii lui b. Extinderea acestei accepii la sistemele distribuite ntmpin dificulti, deoarece reclam ca sistemele de calcul s conin ceasuri de timp real, iar ceasurile s msoare cu precizie timpul. O soluie mai realist este aceea a introducerii unor ceasuri logice, care s marcheze ordinea evenimentelor fr a da cu exactitate momentele producerii lor. n acest scop, se definete relaia petrecut nainte pe mulimea evenimentelor dintr-un sistem, notat cu ->, ca fiind cea mai slab relaie care satisface urmtoarele trei condiii: n situaia c a i b sunt evenimente din acelai proces i a l precede pe b, atunci a->b; cnd a reprezint transmiterea unui mesaj de ctre un proces, iar b recepia aceluiai mesaj de ctre un altul, atunci a->b; dac a->b i b->c atunci a->c. S considerm n continuare o modalitate simpl de a introduce ceasuri logice ntr-un program paralel. Pentru aceasta, n loc s se ataeze unui eveniment timpul real de producere, i se asociaz un numr de ordine, care s precizeze poziia sa n raport cu celelalte evenimente. Mai precis, pentru fiecare proces Pi, se definete ceasul logic ca o funcie Ci care asociaz fiecrui eveniment a din Pi un numr unic Ci(a). ntregul sistem de ceasuri poate fi privit ca o funcie C definit pe mulimea tuturor evenimentelor cu valori n mulimea numerelor naturale, care asociaz oricrui eveniment a un numr C(a)=Ci(a), dac a este un eveniment al procesului Pi. Un astfel de sistem de ceasuri este corect dac, pentru orice evenimente a i b, a->b implic C(a)<C(b). Realizarea practic a unui sistem de ceasuri logice presupune folosirea pentru fiecare proces A a unei variabile cl, a crei valoare se mrete la producerea evenimentelor i, pentru fiecare mesaj, a unui cmp care s indice momentul transmiterii sale. Ceasurile logice sunt incrementate conform urmtoarelor reguli: (1) cnd A transmite un mesaj, el incrementeaz cl cu 1 i apoi actualizeaz timpul tt asociat mesajului la valoarea lui cl; (2) cnd A primete un mesaj avnd asociat timpul tt, el actualizeaz cl la valoarea maxim dintre cl i tt + 1 i apoi incrementeaz cl cu 1. 112

Folosind ceasurile logice, putem asocia un moment de timp fiecrui eveniment. Pentru send acesta este timpul nregistrat n mesaj. Pentru receive acesta este valoarea lui cl din procesul receptor dup actualizarea la maximul dintre cl i tt+1 i incrementarea ei. Aceasta asigur c, dac un eveniment a se produce naintea unui eveniment b, timpul asociat lui a s fie mai mic dect timpul asociat lui b. Se induce astfel o ordonare parial pe mulimea evenimentelor unui program.

Figura 8.1Trei procese i evenimentele corespunztoare n figura 8.1 sunt reprezentate evenimentele interne i de comunicare ntre trei procese cu respectarea momentelor de timp fizic la care s-au produs. Considernd c ceasurile logice asociate proceselor au iniial valoarea 0, prin actualizarea lor dup regulile prezentate mai nainte se obin valorile de timp logic prezentate n Figura 8.2.

Figura 8.2 Valorile de timp logic asociate evenimentelor din Figura 8.1 Deoarece dou evenimente din procese diferite pot avea acelai timp logic de producere (de exemplu, evenimentele a i e din Figura 8.2), pentru a obine o ordonare total se poate recurge la ordonarea proceselor i la dispunerea evenimentelor cu acelai timp logic n ordinea proceselor corespunztoare. 113

Ca aplicaie, prezentm utilizarea ordonrii totale a evenimentelor n realizarea excluderii mutuale ntr-un sistem cu transmitere asincron de mesaje, prin semafoare distribuite. Soluia are la baza urmtorul mecanism: cnd un proces execut o operaie P (sau V) el difuzeaz mesaje celorlalte procese, analiznd rspunsurile acestora pentru a determina continuarea execuiei. Folosim forma: broadcast ch(m) pentru a desemna transmiterea mesajului m pe fiecare din canalele unui tablou ch[1:n]. Toate cele n replici ale lui m transmise prin broadcast poart aceeai amprent de timp, calculat la fel ca pentru o singur operaie send. Implementarea semafoarelor se face prin dou colecii de procese. Procesele Utiliz(i) iniiaz operaiile P sau V, prin difuzare de mesaje pe canalele opsem. Procesele Ajutor(i) implementeaz operaiile P si V. La o operaie P sau V, un proces Utiliz difuzeaz un mesaj tuturor proceselor (inclusiv propriului) Ajutor. Mesajul conine identitatea propriului ajutor, un indicator P sau V i un moment de timp, acelai n toate copiile mesajului.
+----------------+ +--------> Utiliz[i] --->-+ +----------------+ +----<-- Utiliz[j] Ajutor[j] +---+ +---+ +---+ start[i] +---+ opsem[i] +---+ +---+ +----------------+ +----<---- Ajutor[i] <----+ +----------------+

Figura 8.3 Fiecare proces Ajutor are o coad local de mesaje qm i un ceas logic cl. Cnd un proces Ajutor primete un mesaj P sau V, el l memoreaz n qm, care este ordonat dup momentele de timp coninute de mesaje (cu amendamentul suplimentar asupra ordonrii proceselor). Mesajele unor procese diferite nu sunt recepionate n aceeai ordine de toate procesele Ajutor. Mai mult, un mesaj cu un timp mai redus poate fi recepionat dup un altul cu un timp mai mare. Dar, mesajele trimise de un acelai proces vor fi recepionate de celelalte procese n ordinea generrii i vor avea momente de timp cresctoare. Ca urmare, dac qm conine un mesaj m cu timpul ts i procesul recepioneaz mesaje cu un timp mai mare de la toate celelalte procese, este 114

sigur c nu va mai apare ulterior un mesaj cu un timp mai mic. n acest moment m este complet confirmat i, odat cu el, toate celelalte mesaje aflate n faa lui n qm. Acestea constituie un prefix stabil, nici un alt mesaj neputnd fi inserat ntre cele din prefix. Totodat, cnd un proces Ajutor primete un mesaj P sau V, acesta difuzeaz o confirmare ack. Mesajele ack au asociai timpi de producere, dar ele nu sunt memorate la recepie n qm i nu sunt confirmate la rndul lor. Ele folosesc doar la a determina cnd un mesaj P sau V devine complet confirmat. Fiecare proces Ajutor simuleaz operaiile cu semafoare. El folosete o variabil local sem, pentru a pstra valoarea semaforului. Cnd procesul primete un ack, el actualizeaz prefixul stabil din qm. Pentru fiecare mesaj V din prefix, procesul incrementeaz sem i terge mesajul. Procesul examineaz apoi mesajele P. Dac sem>0, procesul decrementeaz sem i terge mesajul P. Mesajele P sunt tratate de toate procesele n aceeai ordine. Algoritmul este urmtorul:
type fel = enum(V, P, ack); chan opsem[1:n](transm: int, op: fel, timp: int); chan start[1:n](timp: int); Utiliz(i: 1..n):: var cl: int :=0; {ceas logic} var ts: int; ... cl := cl+1; broadcast opsem(i, V, cl); {operatia V} ... cl := cl+1; broadcast opsem(i, P, cl); {operatia P} receive start[i](ts); cl := max(cl, ts+1); cl := cl+1; ... Ajutor(i: 1..n):: var qm: queue of (int, fel, int); var cl: int := 0; var sem: int := valoare_initiala; var transm: int, k: fel, ts: int; do true -> receive opsem[i](transm, k, ts);

115

cl := max{cl, ts+1); cl := cl+1; if k=P or k=V -> insereaza (transm, k, ts) in locul corespunzator in qm; cl := cl+1; broadcast opsem(i, ack, cl); [] k=ack -> inregistreaza transmiterea unui ack; fa mesajele V complet confirmate -> scoate mesaj din qm; sem := sem+1; af; fa mesajele P complet confirmate st sem>0 -> scoate mesaj (transm, k, ts) din qm; sem := sem-1; if tansm=i -> cl := cl+1; send start[i](cl) fi af fi od

Tema. Alctuii algoritmul distribuit de excludere mutual care funcioneaz n modul descris n continuare. Un proces care dorete s intre n seciunea critic trimite mesaje de cerere request tuturor celorlalte procese. Pentru a putea intra efectiv n seciunea critic, este necesar s primeasc de la fiecare cte un mesaj de rspuns reply. La recepia unui mesaj request, un proces poate determina dac el sau procesul care a facut cererea ar trebui s intre n seciunea critic. Cnd el are prioritate, mesajul reply este ntrziat; altfel, el este transmis imediat procesului ce a generat cererea. 8.2 Ceasuri logice vectoriale Cu soluia ceasurilor logice dat de Lamport, avem urmtoarea relaie: e precede f => amprenta_logic (e) < amprenta_logic (f) deci, dac e precede f atunci timpul logic asociat lui e este mai mic dect cel al lui f. Pe de alt parte, amprenta_logic (e) < amprenta_logic (f) !=> e precede f adic, faptul c timpul logic al lui e este mai mic dect cel al lui f nu nseamn neaprat c e precede f. De exemplu, n Figura 8.2, evenimentul e are timpul logic 1 iar c are timpul logic 3, dar nu se poate spune ca e precede c.

116

Prin utilizarea ceasurilor logice vectoriale, o astfel de implicaie este garantat. Ceasurile logice vectoriale sunt definite n modul descris n continuare. Fiecare proces Pi are asociat un vector V(i)[1..n], reprezentnd ceasul su logic vectorial, n care: V(i)[i] este numrul de evenimente produse n procesul Pi; V(i)[j] este numrul de evenimente despre care Pi tie (a aflat) c au avut loc la Pj. Obs. V nu este o matrice, ci o colecie de vectori, fiecare V(i) din aceast colecie fiind pstrat de procesul Pi n memoria sa local. Procesul Pi actualizeaz V(i) la fiecare eveniment din Pi (trimitere / recepie de mesaj sau alt eveniment). Cnd Pi transmite mesajul m (eveniment "send m"): Pi incrementeaz V(i)[i] Pi adaug V(i) la m ca vector de amprente de timp curent vt(m) Cnd Pj primete mesajul m mpreun cu vt(m) (eveniment "receive m"): Pj ajusteaz vectorul: V(j) [k] = max{V(j)[k],vt(m)[k]} pentru fiecare k Pj incrementeaz V(j)[j] cu 1 Figura 8.4 arat rezultatul aplicrii acestor reguli pe exemplul din Figura 8.2.

Figura 8.4 Aplicarea regulilor ceasurilor logice vectoriale Pe multimea vectorilor de amprente de timp, VT pot fi stabilite cteva relaii. Fie VT1 i VT2 doi vectori VT cu cte N elemente. Atunci, VT1 = VT2 VT1 <= VT2 VT1 < VT2 VT1[i] = VT2[i], pentru i = 1, ..., N VT1[i] <= VT2[i], pentru i = 1, ..., N VT1 <= VT2 i VT1 <> VT2 117

Relaiile anterioare ne permit definirea ordonrii cauzale a evenimentelor. Fie vt(a) i vt(b) vectorii de amprente de timp asociai evenimentelor a i b. Atunci: vt(a) < vt(b) => evenimentul a precede cauzal evenimentul b vt(a) !< vt(b) and vt(b) !< vt(a) and vt(a) != vt(b) evenimentele a i b sunt concurente Aplicaie: Ordonare Cauzal Multicast Presupunem c procesele unei colecii P comunic ntre ele doar prin mesaje cu difuzare (orice mesaj este trimis tuturor proceselor din colecie). Se cere ca oricare dou mesaje m i m' transmise n cadrul coleciei s respecte dependena cauzal, ceeace nseamn c dac mesajul m a fost trimis naintea mesajului m' atunci, la orice proces p din colecie, livrarea lui m s aib loc naintea livrrii lui m': vt(m) < vt(m') => livrarep (m) -> livrarep (m'). Pentru asta, fiecare proces folosete un protocol care ntrzie eventual livrarea mesajelor astfel nct aceasta s aib loc n ordinea cauzal. Protocolul se bazeaz pe o variant uor modificat a ceasurilor logice vectoriale, pe care o numim vectori de timp pentru a face diferenierea fa de varianta de baz. n noua variant, ceasurile sunt avansate doar la operaiile de transmitere de mesaje. Ca i n varianta iniial, fiecare proces Pi (i = 1..n) are asociat un vector V(i)[1..n], cu toate elementele avnd iniial valoarea 0, reprezentnd vectorul su de timp, n care: V(i)[i] este numrul de evenimente de transmitere de mesaje produse n procesul Pi; V(i)[j] este numrul de evenimente de transmitere de mesaje despre care Pi tie (a aflat) c au avut loc la Pj. Procesul Pi actualizeaz V(i) la fiecare eveniment de trimitere sau recepie de mesaj din Pi. Cnd un proces surs Ps transmite mesajul m (eveniment "send m"): Ps incrementeaz V(s)[s] Ps adaug V(s) la m ca vector de amprente de timp curent vt(m) Amprenta vt(m) spune receptorului cte evenimente (din alte procese) au precedat m i ar putea influena cauzal pe m.

118

Cnd procesul de destinaie Pd primete mesajul m mpreun cu vt(m) (eveniment "receive m"), mesajul este livrat (fcut disponibil procesului pentru prelucrare) doar dac nu se violeaza constrangerile de cauzalitate. Mai precis, mesajul este pstrat ntro coad de ntrziere pn cnd sunt ndeplinite urmtoarele dou condiii: vt(m) [s] = V(d)[s] + 1 (m este urmtorul mesaj pe care d l atepta de la s) vt(m) [k] =< V(d)[k] pentru k <> s (toate mesajele primite deja de Ps cnd a trimis m au fost primite i de Pd cnd acesta a primit m). Cnd mesajul este livrat, V(d) este actualizat conform regulilor vectorilor de timp: V(d) [k] = max{V(d)[k], vt(m)[k]} pentru fiecare k = 1,n. Un exemplu de ntrziere a mesajelor este prezentat n figura 8.5. Mesajul cu vectorul de timp (1,1,0) este livrat dup mesajul (1,0,0) dei este primit naintea acestuia de procesul P3.

Figura 8.5 ntrzierea unui mesaj (Birman 1991) Livrarea mesajului m poate determina livrarea altor mesaje, primite anterior, care acum ndeplinesc condiia de cauzalitate. Aciunile protocolului la livrarea mesajelor pot fi rezumate astfel: dac vt(m)[k] > V(d)[k] pentru un oarecare k atunci se ntrzie m Motivul este c Ps a primit mesaje de care mesajul curent poate fi cauzal dependent, dar pe care Pd nc nu le-a primit; 119

dac vt(m)[s] > V(d)[s]+1 atunci se ntrzie m Motivul este c mai sunt mesaje de la Ps pe care Pd nu le-a primit; aceasta asigura ordinea FIFO pentru canale care sunt nonFIFO dac vt(m)[s] < V(d)[s] atunci rejecteaz m Motivul: m este un duplicat al unui mesaj primit anterior.

120

9. Algoritmi und 9.1 Noiuni preliminare 9.1.1. Sensul legturilor Complexitatea comunicrii ntr-un algoritm distribuit depinde de topologie, dar i de cunoaterea ei la nivelul fiecrui nod. n notaia folosit pn acum, instruciunile de comunicare de mesaje fceau appel la identificatori globali ai canalelor utilizate, care nu includeau nici un fel de informaie asupra topologiei globale a reelei de procese. O alternativ util n cazul topologiilor regulate este utilizarea unui singur set de etichete pentru oricare proces, care ar corespunde sensului legturilor cu procesele vecine sau direciilor ctre nodurile vecine. Dimensiunea setului depinde de topologie (de ex. 2 pentru inel, 4 pentru tor, etc). Se adaug o condiie suplimentar de consisten diferit de la o topologie la alta. Prezentm cteva exemple. Inel. Pentru fiecare nod din inel (Figura 9.1a) sunt 2 direcii, denumite: Prec (precedent) i Urm (urmtor). Condiia de consisten este: precedentul lui p este q urmtorul lui q este p

(a) Figura 9.1 Un inel (a) i o clic (b)

(b)

Clica. Clica (Figura 9.1b) conine N noduri de grad N-1. Setul direciilor este {1, 2, , N-1}, iar condiia de consisten este: direcia de la nodul i la j are eticheta (j-i) mod N Hipercub. Pentru un hipercub n dimensional (Figura 9.2), setul direciilor este {0,n-1}, iar condiia de consisten este:

120

doua noduri (b0,,bn-1), (c0,,cn-1) legate prin muchie cu eticheta i difera doar in bitul i

Figura 9.2 Hipercub Cu acestea, notaia pentru transmiterea unui mesaj poate avea dou forme: (1) transmitere prin adresare direct, folosit atunci cnd transmitorul cunoate identitatea unic, global a canalului q ctre receptor send ch[q] (mesaj) (2) transmitere prin adresare indirect, folosind etichete locale ale direciilor send ch[directie] (mesaj) unde directie identific unul din canalele pe care procesul poate transmite. 9.1.2. Sisteme de tranziii n capitolul 2 menionam c un program concurent este o colecie de procese paralele comunicante, iar execuia sa poate fi privit ca o ntreesere a aciunilor atomice ale proceselor. Programul concurent poate fi modelat printr-un sistem de tranziii, care pune n eviden strile coleciei de procese (numite convenional configuraii) i tranziiile ntre stri. Un sistem de tranziii const din muimea tuturor configuraiilor posibile ale sistemului, tranziiile pe care sistemul le poate face ntre configuraii i configuraiile din care sistemul poate porni.

121

Formal, un sistem de tranziii este un triplu S = (C, , I), unde C este o mulime de configuraii este relaia de tranziie binar pe C I este setul configuraiilor iniiale (o submulime a lui C) O execuie a lui S este o secven maximal E = (0, 1, 2, ), unde 0 aparine lui I i i i+1, pentru i>=0. O configuratie terminal nu are succesor (nu exist astfel nct ).

O secven E este maximal dac este infinit sau sfrete ntr-o configuraie terminal. Configuraia este tangibil din dac exist o secvena 0, 1, 2, , k astfel nct = 0 = k i i+1, pentru i = 1, k-1. Prin convenie, se utilizeaz termeni diferii pentru elementele sistemului de tranziii si pentru procese. Astfel, o configuraie corespunde reuniunii strilor proceselor, iar o tranziie corespunde unui eveniment al unui proces. Evenimentele pot fi interne, sau de comunicare: send i receive. Cu aceasta, unei execuii E i corespunde o secven de evenimente din diferite procese. Pentru o execuie E, relaia de ordine cauzal < este cea mai slab relaie care satisface urmtoarele: dac a i b sunt dou evenimente diferite ale aceluiai proces i a se produce naintea lui b atunci a<b dac a este un eveniment send iar b evenimentul receive corespunztor atunci a<b dac a<c i b<c atunci a<c (< este tranzitiv). Dac nici a<b i nici b<a atunci a i b sunt concurente. Evenimentele unei execuii E pot fi re-aranjate n orice alt ordine consistent cu relaia de cauzalitate, fr a afecta rezultatul execuiei. Noua ordonare a evenimentelor produce o alt secven de configuraii, F despre care spunem c este echivalent cu prima. Mai precis, o execuie E este echivalent cu F (E~F) dac:

122

au aceeai colecie de evenimente (ordinea difer) evenimentele respect aceeai relaie de ordine cauzal ultima configuraie a lui E coincide cu ultima configuraie a lui F.

Obs. Dou execuii echivalente pot s nu aib aceleai configuraii. Folosind relaia "~" putem mpri execuiile unui sistem de tranziii n clase de echivalen. Vom numi calcul (computation), al unui algoritm distribuit, o clas de echivalen (sub relaia ~) a execuiilor algoritmului. Cu alte cuvinte, un calcul este o colecie de evenimente parial ordonat prin relaia de ordine cauzal. Numrul de evenimente dintr-un calcul C este notat |C|, iar submulimea evenimentelor produse n procesul p este notat Cp.

123

9.2. Algoritmi und (Wave algorithms) Muli algoritmi distribuii se bazeaz pe transmiterea de mesaje n conformitate cu o anumit schem, dependent de topologie, care asigur participarea tuturor proceselor. Ca exemple menionm algoritmii pentru: difuzarea informaiei, realizarea unei sincronizri globale ntre procese, declanarea unu eveniment n fiecare proces, calculul unei funcii n care fiecare proces particip cu o parte a datelor de intrare. Algoritmii und implementeaz astfel de scheme de transmitere de mesaje. Un algoritm und este un algoritm distribuit care are urmtoarele proprieti:
terminare fiecare calcul este finit decizie fiecare calcul conine cel puin un eveniment de decizie (decide) dependena n fiecare calcul, fiecare decide este precedat cauzal de un

eveniment din fiecare proces. Pentru un astfel de algoritm, un calcul (computation) este denumit und (wave). Se face distincie ntre dou categorii de procese: cele care iniiaz execuia, numite iniiatoare (starters) i celelalte procese, ne-iniiatoare (followers). Primul eveniment dintr-un proces iniiator este unul intern sau un send, n timp ce primul evniment dintr-un proces ne-iniiator este un receive. Algoritmii und pot fi clasificai dup mai multe criterii. Centralizarea. ntr-un algoritm centralizat exist un singur iniiator. ntr-un algoritm descentralizat exist un set arbitrar de iniiatori. Topologia. Poate fi inel, arbore, clic etc. Topologia este: fix atunci cnd nu se produc modificri topologice; conectat dac exist o cale ntre oricare dou procese. n general, topologia este nedirecionat (legturile ntre procese sunt bi-direcionale). Cunostinele iniiale ale unui proces pot include identitatea proprie (nume), identitile vecinilor, sensul direciei (ordinea vecinilor). Numrul de decizii. Regula general este "cel mult o decizie n fiecare proces." Putem avea una din urmtoarele situaii: un singur proces decide; toate procesele decid; doar unele decid. Complexitatetea unui algoritm distribuit se msoar n: numr de mesaje schimbate, numr de bii interschimbai sau n timpul necesar pentru un calcul.

124

Prezentm n continuare civa algoritmi und elementari. 9.2.1. Algoritmul inel Algoritmul are urmtoarele caracteristici: fiecare proces are un vecin dedicat, Urm transmiterea foloseste adresarea prin directie (Urm, Prec) toate canalele selectate prin Urm formeaza un ciclu Hamiltonian algoritmul este centralizat: initiatorul trimite un token (jeton) care este pasat de fiecare proces de-a lungul ciclului pana ajunge inapoi la initiator; initiatorul ia apoi decizia Descrierea este urmtoarea:
chan token[1..n] (tok: tok_type); /*initiator*/ P(I):: var tok: tok_type; send token[Urm](tok); receive token[I](tok); decide /*non-initiators*/ P(k:1..n, k<>I):: var tok: tok_type; receive token[k](tok); send token[Urm](tok);

Numr de mesaje = n Timp = n Obs. Regula folosit pentru calculul complexitii este urmtoarea: complexitatea n timp a unui algoritm distribuit este timpul maxim cerut de un calcul al algoritmului, in urmtoarele condiii un proces poate executa n timp zero orice numr finit de evenimente; timpul ntre transmiterea unui mesaj i recepia lui este de (cel mult) o unitate de timp.

125

2.2. Algoritmul arbore Algoritmul se aplic unei topologii arbore. El poate fi aplicat i unei topologii arbitrare n care se cunoate un arbore de acoperire. Fiecare nod cunoate identitatea proprie i identitile vecinilor. Multimea tuturor identitatilor este Ids. Pentru fiecare proces, se folosesc variabilele locale: Vecini - mulimea identitilor vecinilor (notm q identitatea procesului q) rec[q] = true dac procesul a primit un mesaj de la vecinul q Iniiatorii sunt toate nodurile frunz. n algoritm:
fiecare proces trimite exact un mesaj; cnd un proces a primit un mesaj pe fiecare canal incident mai puin unul (condiie

ndeplinit iniial de frunze) el trimite un mesaj pe canalul rmas; cnd un proces a primit cte un mesaj pe toate canalele sale atunci decide.
chan ch[Ids] (id: Ids, tok: tok_type); /* fiecare proces are un canal propriu */ Proc(p:Ids):: var Vecini: set of Ids := vecinii_lui_p; rec: array [Ids] of bool := ([|Ids|]*false); var r: int := numar_vecini_p; tok:tok_type; id, q0: Ids; do r>1 -> receive ch[p](id,tok); rec[id] := true; r := r-1 od; /* de la un singur vecin, fie el q0, nu s-a primit mesaj */ q0 := id Vecini and rec[id]=false; send ch[q0](p, tok); x:receive ch[p](q0, tok); rec[q0] := true; decide; /* informeaza celelalte procese despre decizie */ /* fa q Vecini\{q0} -> send ch[q](p,tok) af; */

Numr de mesaje = N (egal cu nr. procese) Timp = O(D)

126

Un exemplu de execuie este prezentat n figura 9.3.

(a) nodurile frunza transmit

(b) nodurile de nivel intermediar transmit

(c) p si q transmit reciproc i, dup recepie, decid Figura 9.3 Exemplu de execuie al algoritmului arbore (Tel 1994) n continuare, justificm urmtoarea Teorem. Algoritmul "arbore" este un algoritm und. (justificarea ignor ultima instruciune fa din algoritm, cea inclus n ultimul comentariu). (1) calcul finit Fiecare proces trimite cel mult un mesaj => algoritmul folosete cel mult N mesaje => algoritmul atinge o configuraie terminal dup un numr finit de pai.

(2)

n , cel puin un proces a executat un eveniment "decide" terminal => un exit nici un mesaj n tranzit; pentru N noduri avem N-1 legturi bidirecionale ntre vecini => 2N-2 posibile recepii de mesaje (pentru care procesele ateapt n bucla dup "r" din algoritm).

127

Fie

K procese au trimis un mesaj n F recepii sunt neconsumate => F = 2N2K Presupunem prin absurd c nici un proces nu a executat "decide" n N-K procese nu au trimis mesaj => fiecare din ele mai are de primit cel puin 2 mesaje K procese au trimis dar nici unul nu a decis => fiecare mai are de primit un mesaj => F >= 2(N-K)+K Combinnd cele dou rezultate obinem: 2N2K >= 2(N-K)+K sau -2 >= 0, contradicie => cel puin un proces a executat "decide" n "decide" este precedat de un eveniment in fiecare proces

(3)

Figura 9.4 Subseturile Tpq i Tqp (Tel 1994) Fie:

Tpq subsetul proceselor tangibile din p fr a parcurge legtura pq Tqp subsetul proceselor tangibile din q fr a parcurge legtura qp i evenimentele: fpq p trimite un mesaj lui q gpq q primete un mesaj de la p Se demonstreaz prin inducie peste evenimentele de recepie c: pentru orice s din Tpq exist e Cs : e gpq unde Cs este submulimea evenimentelor produse n procesul s iar denot relaia de preceden.

128

Figura 9.5 Descompunerea lui Tpq (Tel 1994)

Presupunem c aceasta este adevrat pentru toate evenimentele receive care preced gpq i demonstrm c este adevrat i pentru gpq. Observm c: gpq este precedat de fpq (n procesul p) (cf. algoritm p) fpq este precedat de grp de la fiecare vecin r care nu este q (cf. ipotez inducie) pentru toi r i pentru orice s din Trp, exist e din Cs cu e grp deci e gpq

Figura 9.5 Descompunera lui T (Tel 1994)

O decizie dp este precedat de grp pentru toi vecinii r => pentru orice Trp i orice proces s din Trp exist e n Cs: e grp dp => pentru orice proces s exista e n Cs: e dp

129

2.3. Algoritm ecou Algoritmul ecou are urmtoarele caracteristici: se aplic unor topologii arbitrare este centralizat - exista un singur initiator, I versiunea prezentat aici a fost propus de Segall (o variant anterioar, mai puin eficient aparine lui Chang) Ideea: algoritmul este bazat pe inundarea retelei cu mesaje tok pe parcursul acestei operaii se stabilete un arbore de acoperire peste topologia arbitrar de graf mesaje tok sunt transmise inapoi spre radacina prin canalele arborelui de acoperire.
chan ch[Ids] (id: Ids, tok: tok_type); const I=id_initiator; Proc(I):: var Vecini: set of Ids := vecinii_lui_I; var r: int := numar_vecini_I; tok:tok_type; id: Ids; fa q Vecini -> send ch[q](I, tok) af; do r>0 -> receive ch[I](id, tok); r := r-1 od; decide; Proc(p:Ids, p<>I):: var Vecini: set of Ids := vecinii_lui_p; var r: int := numar_vecini_p; tok:tok_type; id, parinte: Ids; receive ch[p](parinte, tok); r := r-1; fa q Vecini\{parinte} -> send ch[q](p, tok) af; do r>0 -> receive ch[I](id, tok); r := r-1 od; send ch[parinte](p, tok);

Numr mesaje = 2|E|, unde E este multimea canalelor Timp = O(N)

130

2.4. Algoritmul fazelor Are urmtoarele proprieti: este un algoritm descentralizat se aplic unor topologii arbitrare n care sunt evideniate canale unidirectionale (digraf) vecinii sunt grupai n dou categorii: in-vecini i out-vecini procesele cunosc diametrul grafului D (sau o valoare D'>D) Ideea: fiecare proces trimite exact D mesaje fiecrui out-vecin mesajul i+1 este trimis fiecrui out-vecin numai dup ce i mesaje au fost primite de la fiecare in-vecin
chan ch[Ids] (id: Ids, tok: tok_type); const D = diametrul_retelei; Proc (p:Ids):: var in: set of Ids := in-vecinii_lui_p; var out: set of Ids := out-vecinii_lui_p; var rec: array [Ids] of int := ([|Ids|] 0); /* rec[q] = numar mesaje primite de la q */ var sent: int := 0; /* numar de mesaje transmise fiecarui out-vecin */ var tok:tok_type; id: Ids; if p este initiator -> fa q out -> send ch[q](p, tok) af; sent := sent+1; fi /* min(rec) este min(rec[q], Vq in) */ do min(rec) < D -> receive ch[p](id, tok); rec[id] := rec[id]+1; if min (rec) >= sent and sent < D -> fa q out -> send ch[q](p, tok) af; sent := sent+1; fi od; decide;

Numr mesaje = 2D|E|, unde E este multimea canalelor Timp = 2D

131

T. Algoritmul "fazelor" este un algoritm unda (1) calcul finit fiecare proces trimite cel mult D mesaje prin fiecare canal => algoritmul atinge o configuratie terminala dupa un numar finit de pasi in , fiecare proces a executat un eveniment "decide" o configuratie terminala a unui calcul C presupunem cel putin un initiator in C (pot fi mai multi) (2.1) fiecare proces a trimis cel putin un mesaj: - exista cel putin un initiator care transmite mesaje out-vecinilor sai - la randul sau, fiecare out-vecin trimite mesaje cel tarziu cand primeste un mesaj o configuratie terminala => nu mesaje in tranzit => pentru canal qp: recp[q] = sentq p trimite mesaje cel tarziu cand primeste un mesaj => recp[q]>0 => sentp >0 exista cel putin un initiator p0 (sentp0 >0) => pentru fiecare out-vecin p, recp[p0] >0 => sentp >0 aplicand recursiv + retea conexa => pentru orice p, sentp >0 (2.2) fiecare proces a decis fie p procesul cu cel mai mic sentp in => pentru orice q: sentq >= sentp in in particular, tine daca q este in-vecin al lui p adica minq (sentq) >= sentp pentru q in dar recp[q] = sentq deci minq (recp[q]) >= sentp => sentp =D; altfel p ar fi trimis mesaje suplimentare la ultima receptie (vezi decizia din algoritm) => sentp =D pentru toti p => recp[q] =D pentru orice canal qp => fiecare proces a decis (3) "decide" este precedat de un eveniment in fiecare proces notatii: fpq(i) al i-lea eveniment "p transmite lui q"

(2)

132

gpq(i) al i-lea eveniment "q primeste de la p" relatia "precede pe" canale FIFO => fpq(i) gpq(i) (dar se dem ca tine si pentru not FIFO) fie P = p0, p1, , pk, cu k<=D o cale in retea => fp(i)p(i+1)(i+1) g p(i)p(i+1) (i+1) pentru 0<=i<k din algoritm => g p(i)p(i+1) (i+1) f p(i+1)p(i+2) (i+2) pentru 0<=i<k-1 => fp(0)p(1)(1) g p(i-1)p(i) (k) diametrul = D => pentru oricare q si p exista o cale q= p0, p1, , pk = p de lungime cel mult D => pentru orice q exista un k<=D si un in-vecin r al lui p a.i. fqq'(1) g rp (k) in plus, din algoritm => g rp (k) dp.

133

2.5. Algoritmul fazelor pentru clici Proprieti: diametrul = 1 doar un mesaj trebuie primit de la fiecare vecin = se tine evidenta intr-o variabila simpla canale unidirectionale
chan ch[Ids] (id: Ids, tok: tok_type); Proc (p:1..N):: var Vecini: set of Ids := vecinii_lui_p; var n_vecini := numar_vecini_p; var rec: int := 0; var sent: int := 0; var tok:tok_type; id: Ids; if p este initiator -> fa q Vecini -> send ch[q](p, tok) af; sent := sent+1; fi do rec < n_vecini -> receive ch[p](id, tok); rec := rec+1; if sent = 0 -> fa q Vecini -> send ch[q](p, tok) af; sent := sent+1; fi od; decide;

Numr mesaje = N(N-1) Timp = 2

134

2.6. Algortimul lui Finn Algoritmul nu cere cunoasterea diametrului se bazeaza pe cunoasterea identificatorilor proceselor in mesaje se transmit seturi de identificatori de procese Ideea: proc p pastreaza doua multimi de ids Inc multimea proceselor q pentru care un eveniment in q precede cel mai recent eveniment in p NInc multimea proceselor q pentru care fiecare vecin r are un eveniment care precede cel mai recent eveniment in p Algoritmul initial Inc = {p} NInc = p trimite mesaje cu Inc si NInc de fiecare data cand Inc sau NInc creste cand p primeste mesaje cu Inc si NInc, actualizeaza Inc si NInc (reuniune) cand p a primit un mesaj de la toti in-vecinii, p este inserat in NInc cand Inc devine egal cu NInc, p decide
type SOP = set of Ids; chan ch[1:N] (id: Ids, Inc:SOP, NInc: SOP); Proc (p:Ids):: var Inc:SOP := {p}; var NInc:SOP := ; var rec: array [Ids] of bool := ([|Ids|] false); /* de la cine a receptionat */ var out: SOP := out-vecinii_lui_p; var in: SOP := in-vecinii_lui_p; var rInc, rNInc:SOP; var id: int; if p este initiator -> fa q out -> send ch[q](p, Inc, NInc) af; fi do Inc <> NInc -> receive ch[p](id, rInc, rNInc); Inc := Inc U rInc; NInc := NInc U rNInc; rec[id] := true;

135

if Vid in: rec[id] -> NInc := NInc U {p}; if Inc sau NInc modificat -> fa q out -> send ch[q](p, Inc, NInc) af; fi od; decide;

Numr mesaje <= 4N|E| Timp = O(D) T. Algoritmul lui Finn este un algoritm unda (1) calcul finit cele doua multimi Inc si NInc sunt crescatoare initial contin impreuna un id putand creste la 2N (N = numar procese) => numarul de mesaje transmise pe fiecare canal este limitat superior la 2N|E| => algoritmul atinge o configuratie terminala dupa un numar finit de pasi in , fiecare proces a executat un eveniment "decide" 2.1. in fiecare proces a trimis cel putin un mesaj pe fiecare canal (dem similara alg fazelor) daca p a trimis mesaje cel putin o data (fiecarui vecin) si q este vecin => q a trimis mesaje cel putin o data => fiecare proces a trimis cel putin un mesaj pe fiecare canal 2.2. in fiecare proces a decis 2.2.1. V p, Incp contine toate procesele (in ) daca exista pq atunci Incp este inclus in Incq (in ) dupa ultima modif, p trimite Incp iar q actualizeaza Incq graf tare conex => Incp = Incq pentru toti p si q V Incp contine p => Incp contine toate procesele in 2.2.2. V p si q, NIncp = NIncq fiecare proc a trimis un mesaj pe fiecare canal => fiecare proces a receptionat de la toti vecinii (Vid in: rec[id])=> cf alg => p este adaugat la NIncp graf tare conex si orice NIncp contine p => NIncp contine toate procesele in => V p, Incp = NIncp

(2)

136

=> fiecare proces a decis in (3) "decide" este precedat de un eveniment in fiecare proces consideram decizia dp in procesul p din: q Incp => un eveniment din q precede dp q Nincp => pentru fiecare vecin r al lui q, un eveniment din r precede dp reteaua este tare conexa rezulta proprietatea

137

13. Alegerea unui lider Alegerea unui lider este necesara ca faza premergatoare executiei unui algoritm centralizat, in care doar unul din procesele unei colectii urmeaza sa execute operatii de initializare sau sa joace rolul de coordonator in derularea algoritmului. Evident, se presupune ca desemnarea statica a liderului nu este aplicabila, de regula pentru ca nu se cunoaste compozitia exacta a grupului de procese. (Este cazul algoritmilor folositi la refacerea unor sisteme dupa defectare - crash). In schimb, fiecare proces isi cunoaste propria identitate si vecinii. Identitatile proceselor apartin unei multimi total ordonate, astfel ca alegerea liderului inseamna determinarea procesului care are identitatea cea mai mica (sau cea mai mare). Algoritmii de alegere a unui lider sunt descentralizati (mai multe procese pot declansa alegerea) si presupun luarea unei decizii cu participarea tuturor proceselor. De aceea, algoritmii unda reprezinta solutii naturale ale problemei. 13.1. Alegerea unui lider cu algoritmi unda Solutia are urmatoarele caracteristici: toate procesele au acelasi algoritm local algoritmul este descentralizat (poate fi initiat de oricare subset de procese) in fiecare calcul algoritmul atinge o configuratie finala in care un proces este lider toate celelalte au pierdut. O varianta mai slaba este cea in care: un proces este lider si este "constient" de acest lucru celelalte procese nu "stiu" ca au pierdut. Evident, liderul poate instiinta celelalte procese ca el a castigat, aducand astfel solutia la cazul precedent. Fiecare proces are una din urmatoarele stari: sleep procesul nu a executat nici o actiune leader procesul a castigat alegerile lost procesul a pierdut. Presupuneri: sistemul este asincron (comunicatie asincrona, fara timp global) fiecare proces este identificat printr-un nume unic identitatile sunt extrase dintr-un set total ordonat 1

aflarea liderului se concretizeaza in aflarea procesului cu cel mai mic identificator Solutia urmatoare se aplica unei topologii arbore sau pe care s-a definit ad hoc un arbore de acoperire. Topologia arbore impune ca cel putin toate frunzele sa fie initiatori. Pentru ca in cazul general doar unele procese sunt initiatori, se adauga o faza de wakeup, in care initiatorii algoritmului de alegere a unui lider trimit mesaje wakeup tuturor proceselor. Fiecare proces foloseste variabilele: ws boolean, asigura ca fiecare proces transmite mesaje wakeup cel mult o data; wr int, contorizeaza mesajele de wakeup receptionate. Cand un proces a primit wakeup prin fiecare canal, el incepe algoritmul de alegere pentru a determina procesul cu cea mai mica identitate. Cand un proces decide, el afla identitatea liderului si, in functie de ea, procesul trece in starea leader sau lost.
chan ch[Ids](id_transm: Ids, id_mic: Ids); chan wakeup[Ids](); Proc(p:Ids):: var ws: bool := false; wr: int := 0; Vecini: set of Ids := vecinii_lui_p; rec: array [1:N] of bool := ([|Ids|]*false); V: Ids := p; state: (sleep, leader, lost) := sleep; var r: int := numar_vecini_p; id: Ids; if p este initiator -> ws := true; fa q Vecini -> send wakeup[q]() af; fi; do wr < numar_vecini_p -> receive wakeup[p](); wr := wr+1; if not ws -> ws := true; fa q Vecini -> send wakeup[q]() af; fi;

od; /* aici incepe algoritmul tree */ do r>1 -> receive ch[p](q,id); rec[q] := true; r := r-1; V := min(V, id); od; /* de la un singur vecin nu s-a primit mesaj, fie el q0 */ q0 := id Vecini and rec[id]=false; send ch[q0](p, V); receive ch[p](q0, id); V := min (V, id); if V=p -> state := leader [] V<>p -> state := lost fi; /* informeaza celelalte procese despre decizie */ fa q Vecini\{q0} -> send ch[q](p,V) af;

Numar mesaje = O(N) Timp = O(D) Pe fiecare canal se trimit doua mesaje wakeup si doua token-uri ceeace inseamna un total de 4N-4 mesaje. In D pasi dupa ce primul proces porneste algoritmul, fiecare proces a trimis mesajele wakeup. Ca urmare, in D+1 pasi fiecare proces a pornit unda. Prima decizie se ia la D pasi dupa pornire, iar ultima dupa alti D pasi. Rezulta totalul de 3D+1 pasi. 13.2 Algoritmi pentru topologia inel Una din situatiile cele mai comune este cea in care procesele, identificate prin numere distincte intre ele, sunt organizate intr-o topologie inel. Problema cere, ca si mai inainte, desemnarea prin conses a unui singur proces drept lider al grupului de procese. De data aceasta convenim ca el sa fie procesul cu identificatorul maxim. Nu se cunoaste apriori numarul de procese din grup. De asemenea, dispunerea proceselor in inel este oarecare (nu neaparat in ordinea numerelor de identificare). In fine, nu exista un control centralizat al alegerii liderului (solutia este distribuita). 3

Exemplu de utilizare: un inel de controlere in care jetonul de control (care asigura protocolul de coordonare a operatiilor din inel) s-a pierdut. Situatia este detectata printr-un timeout, la care fiecare controler declanseaza procedura de selectie a liderului, a carui sarcina este de a genera un nou jeton. 13.2.1 Algoritmul LeLann Presupune realizarea urmatoarelor actiuni: 1. 2. 3. 4. Fiecare proces transmite in inel un mesaj care contine identificatorul sau Fiecare proces colecteaza numerele celorlalte procese Fiecare proces calculeaza maximul. Procesul al carui numar este egal cu maximul devine lider.

Complexitate O(n2) mesaje comunicate - fiecare proces transmite un mesaj care trece pe la toate celelalte. Descrierea detaliata a algoritmului este urmatoarea.
chan ch[Ids](tok: token, id_mare: Ids); Proc(p:Ids):: var List: set of Ids := {p}; var state: (candidate, leader, lost); state := candidate; send ch[Urm](tok, p); receive ch[p](tok, q); do q<>p -> List := List U {q}; send ch[Urm](tok, q); receive ch[p](tok, q) od if p = max(List) -> state := leader p <> max(List) -> state := lost fi

Algoritmul se bazeaza pe proprietatea FIFO a canalelor, conform careia ordinea mesajelor transmise pe inel se pastreaza. Astfel, oricare proces q va trimite un mesaj (tok, q) inainte de primirea (si retrimiterea) mesajului (tok, p) de la procesul p. Ca 4

urmare, (tok, p) va ajunge inapoi la procesul p dupa ce acesta a primit mesaje (tok, q) de la toate celelalte procese. Deci, cand (tok, p) ajunge inapoi la procesul p, variabila sa List va contine identificatorii tuturor proceselor. Acest lucru este valabil pentru toate procesele, care vor identifica un acelasi maxim, deci un acelasi lider al colectiei de procese. 13.2.2 Algoritmul Lelann-Chang-Robert Mesajele sunt transmise in inel in sensul acelor de ceasornic. 1. Fiecare proces transmite procesului aflat in dreapta un mesaj cu identificatorul lui. 2. Un proces care primeste un mesaj m il compara cu identificatorul propriu id a. if m > id -> transmite m in dreapta b. if m < id -> elimina m c. if m = id -> procesul curent devine lider. Propozitie: Algoritmul detecteaza un singur cel mai mare numar Argument: Un mesaj intalneste toate celelalte procese inainte de a reveni, eventual, la transmitator. Numai mesajul cu valoarea cea mai mare nu este eliminat de procesele parcurse. Descrierea detaliata a algoritmului este urmatoarea.
chan ch[Ids](tok: token, id_mic: Ids); Proc(p:Ids):: var state: (candidate, leader, lost); state := candidate; send ch[Urm](tok, p); do state <> leader -> receive ch[p](tok, q); if q=p -> state := leader [] q>p -> if state = candidate -> state := lost fi send ch[Urm](tok, q) fi od

Observatii Conditia de iesire din bucla este "state = leader". Aceasta are doua consecinte: un proces care devine lost ramane in bucla pentru a pasa alte mesaje pe care le primeste doar procesul cu identificatorul maxim termina; celelalte vor ramane blocate in asteptarea unui token; pentru deblocare, liderul ales poate trimite un mesaj special prin care anunta identificatorul lui si faptul ca alegerea s-a terminat. Algoritm modificat In cazul in care nu toate procesele sunt initiatori, se pot introduce urmatoarele modificari: Cel putin un proces initiazeaza alegerea si se auto-marcheaza. Cand un mesaj m ajunge la un proces nemarcat, acesta va genera un mesaj cu id propriu, se va marca si va continua cu prelucrarea mesajului m. Liderul ales asigura ca fiecare proces se va demarca (pentru executia corecta a unei viitoare alegeri de lider). Performanta Masurata in timp si numar de mesaje Timp Daca toate procesele pornesc simultan, este necesar un singur ciclu prin inel. Deci, timpul este O(n), unde n este numarul de procese. Similar, daca procesul cu numarul maxim porneste primul timpul este O(n). Altfel, in cel mult n-1 pasi mesajul de marcare ajunge la procesul cu id maxim si in n pasi se face alegerea acestuia ca lider. Deci timpul este O(n). Numar mesaje a) Cazul cel mai bun. Procesele sunt ordonate crescator in sensul acelor de ceasornic. Fiecare mesaj (exceptand mesajul n) este transmis o data. Mesajul n este transmis de n ori. Rezulta 2n-1 mesaje. b) Cazul cel mai rau. Procesele sunt ordonate descrescator in sensul acelor de ceasornic. Toate mesajele sunt eliminate de procesul n. Mesajul i este transmis de i ori. Rezulta i=1,ni = n(n + 1)/2. 6

c) Cazul mediu.

Sunt i-1 procese mai mici ca i si n-i mai mari ca i. Fie C(a,b) numarul de moduri in care putem alege b obiecte din a (combinari de a luate cate b). Probabilitatea P(i, k) ca mesajul i sa fie pasat de k ori este egala cu probabilitatea ca cei k-1 vecini ai lui i in sensul acelor de ceasornic sa fie mai mici ca i si vecinul k sa fie mai mare, adica: P(i,k) = [C(i-1,k-1)/C(n-1,k-1)]*[(n-i)/(n-k)] Cunoscand ca mesajul n se transmite intotdeauna de n ori si ca exista doar un singur asemenea mesaj, consideram doar n-1 mesaje, fiecare fiind transmis ce cel mult n-1 ori. Numarul probabil de transmiteri pentru mesaje altele decat n este: Ei(k) = k=1,n-1k.P(i,k) Numarul total de transmiteri pentru toate mesajele este: sau E(k) = n + i=1,n-1 k=1,n-1k.P(i,k) E(k) = n + k=1,n-1n/(k+1) = n(1 + 1/2 + 1/3 + ... + 1/n) ~= n(C + ln n) Rezulta ca numarul mediu de mesaje este O(n ln n). 13.2.3 Algoritmul Hirschberg-Sinclair Spre deosebire de algoritmul Chang si Roberts care are o complexitate medie O(n ln n), algoritmul Hirschberg-Sinclair are complexitatea O(n ln n) in cel mai defavorabil caz. 7

El lucreaza pe un inel bidirectional si presupune ca procesele pot detecta din ce directie vine un mesaj astfel ca pot trimite raspunsuri in acea directie. Ca urmare, operatiile de comunicare folosite de procese au o semantica particulara, diferita de cea definita de noi antorior si anume: un proces poate initia mesaje in ambele directii prin sendboth. un proces poate pasa un mesaj (eventual modificat) prin sendpass. un proces poate trimite un raspuns in directia din care a primit un mesaj prin sendecho. Algoritmul are descrierea data in continuare. Executia pentru alegere: status := "candidate" maxnum := 1 do status = "candidate" -> sendboth ("from", myvalue, 0, maxnum); await both replies (but react to other messages); if either reply is "no" -> status := "lost" fi maxnum := 2*maxnum od La receptie mesaj ("from", value, num, maxnum): if value < myvalue -> sendecho ("no", value) fi; [] value > myvalue -> status := "lost"; num := num + 1; if num< maxnum -> sendpass ("from", value, num, maxnum) [] num>= maxnum -> sendeeho ("ok", value) fi [] value = myvalue -> status := "won" fi La receptie mesaj ("no", value) sau ("ok", value): if value <> myvalue -> sendpass the message [] value = myvalue -> this is a reply the processor was awaiting fi

Algoritmul opereaza in faze. In faza k, un proces initiaza mesaje care sunt transmise in ambele directii pe cai de lungimi predeterminate (2k). Procesele de pe o cale citesc mesajul. Daca un proces decide ca nu poate castiga alegerea el va pasa mesajul si nu va mai initia mesajul propriu. Daca procesul decide ca sursa nu poate castiga alegerea transmite un ecou negativ sursei. Procesul de la capatul caii transmite un ecou pozitiv sursei. Un proces care primeste propriul mesaj castiga. (El va trimite apoi un mesaj pentru a anunta celelalte procese ca a castigat.) Netratat in algoritm - actiunile unui proces neinitiator (care un "stie" de alegerea in curs): la primirea unui mesaj devine constient de alegerea in curs si poate deveni candidate daca identitatea are o valoare mai mare decat sursa mesajului. Analiza complexitatii Un proces x initiaza mesaje pe cai de lungime 2i numai daca el nu este "invins" de un proces aflat la distanta 2i-1 (in oricare directie) de x. In orice grup de 2i-1 + 1 procese consecutive, cel mult unul poate initia mesaje pe cai de lungime 2i. Desi este posibil ca toate cele n procese sa initieze cai de lungime 1, cel mult [n/2] (adica superior de n/2) procese vor initia cai de lungime 2, cel mult [n/3] de lungime 4, cel mult [n/5] de lungime 8 etc. Un proces care initiaza mesaje pe cai de lungime 2i provoaca trimiterea de mesaje in ambele sensuri, dus-intors. Ca urmare, vor fi transmise cel mult 4*2i mesaje. Numarul total de mesaje este cel mult 4*( l*n + 2*[n / 2] + 4*[n / 3] + 8*[n / 5] + . . . + 2i*[n/(2i-1 + 1)] + . . . ). Fiecare din termenii din paranteze este mai mic decat 2n si exista nu mai multi de 1 + [log n] termeni. Motivul este ca nici un proces nu va pasa mesaje pe cai de lungime 2n sau mai mari deoarece; odata ce un proces a initiat cai de lungime cel putin n si mesajul este acceptabil pe toata lungime inelului, procesul devine lider si nu mai initiaza mesaje. Ca urmare, numarul total de mesaje transmise este mai mic decat 8n + 8[n log n] = O(n log n). Pentru complexitatea in timp, consideram ca transmiterea mesajelor se suprapune in timp (atat cat permite algoritmul) si ca fiecare mesaj este transmis in cel mult o unitate de timp. Ca urmare, complexitatea este lineara cu numarul de procese. Mai precis: 9

Timp = 2*(1 + 2 + 4 + . . . + 2i + . . . + n ). Cand n este o putere alui 2 (cazul cel mai favorabil): Timp = 4n 2. Cand n este cu 1 mai mare decat o putere a lui 2 (cazul cel mai defavorabil): Timp = 6n - 6. Bibliografie
Ernest Chang and Rosemary Roberts An Improved Algorithm for Decentralized ExtremaFinding in Circular Configurations of Processes, Communications of the ACM Number 5 Volume 22 May 1979 D.S. Hirschberg and J.B. Sinclair Decentralized Extrema-Finding in Circular Configurations of Processors, Communications of the ACM Number 11 Volume 23 November 1980 Gary L. Peterson An O(n log n) Unidirectional Algorithm for the Circular Extrema Problem, ACM Transactions on Programming Languages and Systems, Vol. 4, No. 4, October 1982, Pages 758-762.

10

Capitolul 10 Procese egale. Stabilirea topologiei


10.1 Difuzarea mesajelor folosind sondaje n rezolvrile multor probleme paralele, procesele realizeaz aceleai prelucrri, coopernd de pe poziii egale pentru ndeplinirea unei funcii. Ca exemplu, vom considera problema difuzrii mesajelor folosind sondaje. Fie i nodul surs al informaiei care se difuzeaz. O posibil soluie este utilizarea arborelui de acoperire T pentru a stabili cile de comunicare a informaiei de la i la toate celelalte noduri. Astfel nodul i transmite informaia mpreun cu T vecinilor si. Fiecare vecin inspecteaz T i transmite informaia mpreun cu T fiilor si din T, s.a.m.d. Deoarece T este arbore de acoperire, informaia va ajunge la fiecare nod, o singur dat ( comunicat de tatl din T al nodului respectiv). Algoritmul este urmtorul:
type tip_arb = array [1:N,1:N] of int; chan sondaj[1:N](tip_arb,tip_mesaj); Nod(p:1..N):: var arb:tip_arb, m : tip_mesaj; receive sondaj[p](arb,m); fa q:=1 to N st q este fiul lui p in arb -> send sondaj[q](arb,m) af Initiator:: var i: int := indexul nodului initiator; var top: array[1:N,1:N] of bool; var T : tip_arb, m : tip_mesaj; calculeaza T pe baza top; m := mesaj_de_transmis; send sondaj[i](T,m);

Mesajul este pregtit de un proces Iniiator situat n nodul i i este comunicat procesului Nod(i). Aceasta permite descrierea ntregii reele de difuzare ca o colecie de procese egale. Soluia presupune c procesul Iniiator cunoate topologia reelei, din care deriveaz arborele de acoperire T. n cazul n care nodul iniiator nu cunoate topologia, iar fiecare nod cunoate doar vecinii, difuzarea mesajului se poate face dac fiecare nod retransmite mesajul primit 138

tuturor vecinilor si, ignornd copiile acestuia. Pentru a furniza o soluie complet simetric, adoptm convenia c primul mesaj care se difuzeaz este retransmis chiar i nodului de la care provine. n acest mod, fiecare nod cunoate precis numrul nodurilor de la care primete sau crora le transmite mesajul. Soluia are descrierea urmtoare:
chan sondaj[1:n](tip_mesaj); Nod(p:1..n):: var leg: array [1:n] of bool := vecinii_lui_p; var num: int := numarul_vecinilor; var m: tip_mesaj; receive sondaj[p](m); fa q := 1 to n st leg[q] -> send sondaj[q](m); af; fa q := 1 to num-1 -> receive sondaj[p](m); af; Initiator:: var i:int := indexul_nodului_initiator; var m: tip_mesaj; m := mesaj_de_transmis; send sondaj[i](m);

Comparnd cele dou soluii, putem remarca urmtoarele: - numrul de mesaje transmise de primul algoritm este n-1, n timp ce,n al doilea caz, este 2m, unde m este numrul de legturi din reea; - mesajele transmise de al doilea algoritm sunt mai simple i mai scurte, deoarece nu includ arborele de acoperire T. n esen, arborele de acoperire este construit dinamic, el constnd din legturile pe care sunt primite primele mesaje de ctre noduri. 10.2. Stabilirea topologiei unei reele de procese Ca un alt exemplu, vom considera problema stabilirii topologiei unei reele. Fiecare nod al reelei este reprezentat de un proces, iar legturile dintre noduri sunt realizate prin canale. Fiecare nod poate comunica doar cu vecinii si, cu care are canale directe de legtura. Iniial, fiecare nod cunoate aceste canale i, implicit, vecinii. Problema este ca fiecare nod s determine topologia ntregii reele. Aceasta informaie ar putea fi folosit n dirijarea mesajelor ntre noduri neadiacente. Vom reprezenta fiecare nod printr-un proces Nod(p:1..N). Un tablou de legturi, leg[1:N], local fiecarui proces, va preciza vecinii nodului p: pentru p, leg[q]=TRUE daca q este vecin cu p, altfel leg[q]=FALSE. 139

Relaia de vecintate este simetric, astfel c pentru p, leg[q]=TRUE <=> pentru q, leg[p]=TRUE. Topologia care trebuie calculat este reprezentat n fiecare nod prin matricea de adiacen top, avnd elementele : top[i,j]=TRUE , dac i este vecin cu j top[i,j]=FALSE , n caz contrar. Evident, top se calculeaz folosind valorile cunoscute leg ale fiecrui proces p, astfel c, la terminarea calcului, urmtorul predicat este satisfacut: TOPOLOGIE: ( pentru orice p,q: 1<=p,q<=N : top[p,q] = legp[q] ) Problema are o rezolvare foarte simpl n cazul variabilelor partajate: este suficient ca fiecare proces p sa actualizeze linia p a matricei top. Deoarece procesele folosesc elemente de matrice din linii diferite, non-interferena este asigurat. O alt soluie simpl este cea centralizat: fiecare proces trimite informaii despre vecinii si unui proces central care alctuiete matricea de adiacen, pe care o retransmite apoi diferitelor noduri. Deoarece nu toate nodurile sunt vecine cu nodul central, rezolvarea este inevitabil asimetric, unele noduri jucnd i rolul de intermediere a transferului de mesaje, n timp ce altele nu (prezentm aceast soluie ceva mai trziu). Algoritmul pulsaiilor pentru stabilirea topologiei O soluie uniform este cea distribuit: fiecare proces calculeaz singur topologia, folosind informaiile provenite de la vecini. Dac fiecare nod transmite vecinilor informaia din matricea sa de adiacen i, n acelai timp, primete matricea de adiacen a fiecrui vecin, dup un rund complet, fiecare nod va dispune de informaii de la nodurile vecine. Dup dou runde complete, orice nod va avea informaii de la noduri aflate la distana 2, etc. n general, dupa r runde sunt completate liniile din top corespunztoare nodurilor q aflate la o distan d <= r, adic urmtorul predicat este satisfcut pentru fiecare proces p: RUND: ( oricare ar fi q cu 1<=q<=N: dist(p,q) <=r => top[q,*] este completat ) unde dist(p,q) este distana de la p la q, adic lungimea cii celei mai scurte ntre cele dou noduri. 140

Cunoscnd diametrul D al unei reele, putem face calculul topologiei dup urmtorul algoritm:
type tip_top=array[1:N,1:N] of bool; tip_leg = array [1 :N] of bool; chan topologie[1:N] (tip_top); Nod(p:1..N):: var leg: tip_leg := vecinii_lui_p); {initializat cu vecinii lui p} var top: tip_top := ([N*N]FALSE); top[p,1:N]:= leg; {actualizeaza linia vecinilor} var r: int := 0; var top_nou: tip_top; do r<D -> {transmite topologia curenta tuturor vecinilor} fa q :=1 to N st leg[q]-> send topologie[q](top) af fa q :=1 to N st leg[q]-> receive topologie[p](top_nou); top := top or top_nou; af r := r+1; od

Algoritmul prezentat se numete algoritmul pulsaiilor (inimii) - heartbeat - deoarece aciunile fiecrui nod pot fi asemnate cu btile inimii: transmiterea informaiilor ctre vecini este asemntoare unei contracii, n timp ce culegerea informaiilor de la vecini este asemntoare dilatrii. Algoritmul are dou neajunsuri: unul este faptul c, n general, D nu este cunoscut; cel de al doilea este traficul inutil, anumite noduri primind mesaje chiar dup actualizarea complet a tabloului top local. Pentru a ocoli aceste neajunsuri, trebuie s observm c, deoarece reeaua este conex, putem considera c un nod cunoate ntreaga topologie dac fiecare linie top are cel puin un element TRUE. n acest moment, procesul p trebuie s mai execute un singur rund, dup care se poate termina. Acest ultim rund este necesar pentru a transmite vecinilor informaiile recente primite, eventual, la rundul precedent. Totodat, procesul poate culege ultimele mesaje care i sunt transmise, evitnd abandonarea mesajelor n canale. Deoarece un nod poate termina cu un rund nainte sau dup vecinii si, sunt necesare msuri suplimentare de evitare a blocrii 141

definitive: un proces transmite mesaje doar vecinilor care nu s-au terminat i preia doar mesajele pe care acetia le trimit. Aceste elemente sunt surprinse n descrierea urmtoare:
type tip_top=array[1:N,1:N] of bool; tip_leg = array [1 :N] of bool; chan topologie[1:N](transm: int, gata : bool, top: tip_top); Nod(p:1..N):: var leg: tip_leg := (vecinii_lui_p); var activ: tip_leg := leg; {vecinii activi} var top: tip_top := ([N*N]FALSE); var gata: bool := FALSE; var transm: int, qgata: bool, top_nou: tip-top; top[p,1:N] := leg; {actualizeaza vecinii lui p} do not gata -> {transmite topologia curenta tuturor vecinilor} fa q :=1 to N st leg[q]-> send topologie[q](p,FALSE,top) af {receptioneaza topologiile de la vecini} fa q :=1 to N st leg[q]-> receive topologie[p](transm,qgata,top_nou); top := top or top_nou; if qgata -> activ[transm]:=FALSE fi af if toate liniile din top au un element TRUE -> gata := TRUE fi od {transmite top vecinilor activi in ultimul rund} fa q :=1 to N st activ[q]-> send topologie[q](p,TRUE,top) af fa q :=1 to N st activ[q]-> receive topologie[p](transm,qgata,top_nou); af

Trebuie observat c primul ciclu se termin deoarece, reeaua fiind conex, informaiile despre un nod se propag la fiecare rund. Ca urmare, la un moment dat, toate liniile matricei top vor fi actualizate i gata devine TRUE. Pentru algoritmii distribuii, o msur important de complexitate este numrul de mesaje comunicate ntre procese. n varianta centralizat, menionat la nceputul 142

seciunii, se transmit 2*N mesaje: unul de la fiecare nod la serverul central i cte unul de rspuns, de la server la fiecare nod. De data aceasta, numrul mesajelor este mai mare, dar mesajele se transmit doar ntre vecini. Dac diametrul reelei este D, iar gradul fiecrui nod nu depete valoarea m , numrul mesajelor este limitat superior de 2m*N*(D+1). Justificarea este c se execut D+1 runde, n care fiecare nod schimb cu fiecare vecin dou mesaje. Stabilirea topologiei unei reele are i alte soluii. Unele se bazeaz pe mesajele de sondaj cu ecou, la care ne referim n cele ce urmeaz. Ea folosete mesajele de sondaj pentru a difuza informaia ntr-o reea. Stabilirea topologiei folosind mesaje de sondaj cu ecou Rezolvarea bazat pe mesajele de sondaj cu ecou are urmtoarele etape: un iniiator colecteaz informaii despre topologia local a tuturor celorlalte noduri, determin topologia ntregii reele i o difuzeaz nodurilor. Colectarea se poate face n dou faze: mai nti, fiecare nod transmite cte un mesaj de sondaj vecinilor i recepioneaz topologii ca ecouri; apoi, fiecare nod trimite topologia local actualizat cu ecourile, nodului de la care a primit primul mesaj de sondaj. Iniiatorul mesajului de sondaj primete informaiile cumulate prin ecouri de la toate celelalte noduri. Ca urmare, el poate calcula topologia ntregii reele, pe care o transmite apoi prin legturile arborelui de acoperire. Pentru nceput, s presupunem c reeaua este un graf aciclic, mai precis un arbore i c nodul iniiator i este rdcina acestuia. Nodul i trimite un mesaj de sondaj tuturor vecinilor (fiilor). Ca urmare, mesajele se propag spre frunze. Deoarece acestea nu au ali vecini, ele ncep faza de transmitere a ecourilor. Fiecare frunz trimite un mesaj cu topologia vecinilor si, ctre printe. Dup adunarea mesajelor ecou de la fii, un nod le combin cu propria sa informaie i transmite rezultatul printelui su. Rdcina va primi informaii de la toate celelalte noduri, obinnd prin reuniune topologia reelei.
const sursa=i; type tip_leg = array [1:n] of bool; tip_top = array [1:n, 1:n] of bool; chan sondaj[1:n](transm: int); chan ecou[1:n](top: tip_top); chan ecou_final(top: tip_top);

143

Nod(p:1..n):: var leg: tip_leg := vecinii_lui_p; var top: tip_top := ([n*n] false); top[p, 1..n] := leg; var top_nou: tip_top; var parinte: int; receive sondaj[p](parinte); {transmite sondaje celorlalte noduri vecine, copiii lui p} fa q := 1 to n st leg[q] and (q<>parinte) -> send sondaj[q](p); af; {primeste ecourile si fa reuniunea lor} fa q := 1 to n st leg[q] and (q<> parinte) -> receive ecou[p](top_nou); top := top or top_nou; af; if p=sursa -> send ecou_final(top); [] p<>sursa -> send ecou[parinte](top); fi; Initiator:: var top: tip_top; send sondaj[sursa](sursa); receive ecou_final (top);

n cazul general, adoptm urmtoarele msuri: - ca i mai nainte, dup ce primete un mesaj de sondaj, un nod l trimite tuturor celorlali vecini, dup care ateapt ecouri de la ei; - datorit existenei ciclurilor, dou noduri i pot trimite reciproc sondaje; pentru toate sondajele n afara primului, se transmite un ecou cu o topologie nul; topologia local va fi transmis doar ca ecou la primul sondaj; - pentru recepia eventualelor sondaje primite pe durata ateptrii ecourilor, cele dou tipuri de mesaje sunt recepionate pe un acelai canal.
const sursa=i; {index initiator} type fel = enum(sonda, ecou); type tip_leg = array [1:n] of bool; tip_top = array [1:n, 1:n] of bool; chan sonda-ecou[1:n](fel, transm: int, top:tip_top); chan ecou_final(top: tip_top); Nod(p:1..n):: var leg: tip_leg := vecinii_lui_p; var top: tip_top := ([n*n] false); top[p, 1:n] := leg;

144

var top_nou: tip_top; var prim: int; {nodul de la care s-a primit prima sonda} var k:fel, transm:int; var nr_ecouri: int := numar_vecini - 1; receive sonda-ecou[p](k, prim, top_nou); {transmite sondaje celorlalte noduri vecine, copiii lui p} fa q := 1 to n st leg[q] and (q<>prim) -> send sonda-ecou[q](sonda, p, O); {topologie nula} af; {primeste ecourile si fa reuniunea lor, sau sonde si ignora} do nr_ecouri>0 -> receive sonda-ecou[p](k, transm, top_nou); if k=sonda -> send sonda-ecou[transm](ecou, p, O); [] k=ecou -> top := top or top_nou; nr_ecouri := nr_ecouri-1; fi od; if p=sursa -> send ecou_final(top); [] p<>sursa -> send sonda-ecou[prim](ecou, p, top); fi; Initiator:: var top: tip_top; send sonda-ecou[sursa](sonda, sursa, O); receive ecou_final (top);

Procesul Nod(p) transmite un mesaj de sondaj vecinilor, ateptnd apoi ecourile. Ciclul de ateptare se ncheie cnd toi vecinii au transmis ecourile (n algoritm se face doar contorizarea ecourilor). n acest moment, canalul sonda-ecou[p] nu mai conine nici un mesaj, deoarece orice proces q transmite un eventual mesaj de sondaj nainte de ecou, sondaj ce este prelucrat naintea ecoului (ciclul de transmitere a sondajelor precede ciclul de transmitere a ecourilor). n privina numrului de mesaje, prezentul algoritm folosete un numr mai mic de mesaje dect algoritmul pulsaiilor: fiecare legtur (aparinnd arborelui de acoperire) corespunztoare primei sonde poart dou mesaje (sonda i ecoul), iar celelalte cte patru (dou sonde i dou ecouri). Transmiterea topologiei de la iniiator la noduri necesit alte n mesaje. Ca i la difuzarea mesajelor folosind listele vecinilor, i aici arborele de acoperire este stabilit dinamic, constnd din legturile de la fiecare nod la nodul prim, de la care acesta a recepionat primul mesaj de sondaj. 145

Exerciii 1) Problema mariajului stabil. Fie dou tablouri a cte n procese, B (brbai) i F (femei). Fiecare brbat clasific femeile de la 1 la n i fiecare femeie clasific brbaii de la 1 la n. Un mariaj este o coresponden unu-la-unu B-F. O mperechere este stabil dac pentru oricare doi brbai b1, b2 i pentru corespondentele lor f1 i f2 sunt satisfcute condiiile urmtoare: - b1 clasific f1 mai sus decat f2 sau f2 clasific b2 mai sus decat b1; i - b2 clasific f2 mai sus decat f1 sau f1 clasific b1 mai sus decat b2. Altfel spus, un mariaj este instabil dac exist un brbat i o femeie care prefer fiecare perechea celuilalt. O soluie a problemei este o mulime de n perechi b-f, toate stabile.Scriei un program de rezolvare a problemei mariajului stabil, n care procesele comunic doar prin mesaje asincrone. 2) Imperechere distribuit. Sunt date n procese, fiecare corespunznd unui nod dintrun graf. Fiecare nod poate comunica doar cu vecinii si. Fiecare proces ncearc s se mperecheze cu un vecin. La terminarea mperecherii, fiecare proces trebuie s fie mperecheat sau singur, dar nu trebuie s existe dou procese care sunt vecine i sunt ambele nemperecheate. 3) Arbore de acoperire. Sunt date n procese, fiecare corespunznd unui nod dintr-un graf. Fiecare nod poate comunica doar cu vecinii si. Scriei un program pentru construirea arborelui de acoperire, fr a afla mai nainte topologia. Deci, fiecare proces va decide mpreun cu vecinii si care legturi s fie puse n arbore i care nu. 4) Se dau trei procese, fiecare avand o secven de numere ntregi ordonat cresctor. Exist cel puin o valoare comun celor trei secvene. Scriei programul care gsete cea mai mic valoare comun.

146

11. Terminarea programelor distribuite Tehnica jetonului poate fi folosit cu succes la detectarea terminrii proceselor ntrun program paralel. Un program paralel se termin dac toate procesele sale se termin. Exist ns situaii n care procesele ce compun un program paralel conin cicluri infinite. Definiia anterioar nu este aplicabil n astfel de situaii, fiind necesar adoptarea unei variante mai cuprinztoare. Astfel, considerm c un program este terminat dac fiecare proces este blocat sau terminat i nu exist nici o cerere de intrare/ieire n curs de execuie. Detecia terminrii se poate face simplu n cazul cnd toate procesele se execut pe acelai procesor: coada proceselor pregtite pentru execuie este goal. n cazul unui algoritm distribuit detectarea terminrii este mai dificil, deoarece nu exist nici o cale de a "capta" starea instantanee a tuturor proceselor. Deci, chiar dac, la un moment dat, un proces termin prelucrarea, el poate fi reactivat ulterior de un mesaj primit de la un alt proces al programului. Din acest motiv, stabilirea terminrii unui program necesit comunicarea unor mesaje de control suplimentare ntre procesele sale. 11.1 Terminarea proceselor organizate ntr-un inel (tehnica jetoanelor) Pentru nceput vom analiza o variant mai simpl, n care procesele comunic ntre ele prin canale formnd un inel: P(1) trimite mesaje doar lui P(2), P(2) doar lui P(3) i aa mai departe. n general, procesul P(i) primete mesaje pe canalul ch[i] i trimite mesaje pe canalul ch[(i mod n) + 1]. Condiia de terminare a coleciei de procese este ca fiecare proces s fie liber i pe canale s nu existe mesaje n tranzit. Un proces se consider liber dac a terminat execuia sau dac se afl n ateptarea unui mesaj (receive). Un mesaj este n tranzit dac a fost transmis dar nu a fost nc recepionat. Pentru a detecta terminarea folosim un jeton pe care procesele i-l trimit pe aceleai canale pe care le folosesc pentru mesajele uzuale. Cnd procesul care deine jetonul la un moment dat se termin, el trimite jetonul mai departe, procesului urmtor. Fiecare dintre procesele urmtoare particip la transmiterea jetonului n continuare (convenim ca un proces s participe la transmiterea jetonului n algoritmul de stabilire a terminrii ntregului program, chiar dac el nu mai particip la calcule). Ca urmare, la 147

un moment dat, jetonul va ajunge napoi la iniiatorul aciunii de terminare. Poate acesta decide c programul s-a terminat? La prima vedere, da! Dar, nu trebuie uitat c iniiatorul poate primi mesaje obinuite fiind reactivat, nainte de primirea jetonului napoi. Ca urmare, pentru a decide terminarea, este nevoie de o condiie suplimentar: dup generarea jetonului de terminare, iniiatorul s nu mai primeasc alte mesaje. Pentru a putea face aceast verificare, marcm starea procesului, la transmiterea jetonului, cu albastru i i schimbm culoarea n rou dac primete un mesaj obinuit i face calcule. Dac procesul primete jetonul napoi i culoarea sa a rmas albastru atunci el poate decide terminarea programului paralel. Aceste elemente sunt cuprinse n regulile ce urmeaz, n care, pentru exprimarea predicatului RING, s-a asociat jetonului o variabil auxiliar, care numr canalele goale. Se presupune c iniiatorul terminrii este procesul P(1). {RING: P(1) este albastru => P(1),...,P(jeton+1) sunt albastre i ch[2],...,ch[(jeton mod n) + 1] sunt goale} aciunile lui P(1) cnd devine liber prima dat:
culoare[1] := albastru; jeton := 0; send ch[2](jeton);

aciunile lui P(i:1..n) la recepia unui mesaj obinuit:


culoare[i] := rosu;

aciunile lui P(i:2..n) la primirea unui jeton:


culoare[i] := albastru; jeton := jeton +1; send ch[(i mod n) + 1](jeton);

aciunile lui P(1) la recepia jetonului:


if culoare[1] = albastru -> anun terminarea i stop fi culoare[1] := albastru; jeton := 0; send ch[2](jeton);

148

11.2 Terminarea n cazul general (tehnica jetoanelor) Algoritmul se complic dac topologia reelei de procesoare este diferit de un inel. Deoarece canalele utilizate de procesele unui program paralel sunt entiti globale, o topologie de graf complet, n care fiecare proces poate comunica mesaje tuturor celorlalte, nu este exclus. Cheia algoritmului pentru topologia inel este c jetonul parcurge toate legturile posibile ntre procese, golind canalele de comunicare de mesajele uzuale. Putem extinde aceast metod la noua topologie, cernd ca jetonul s parcurg fiecare arc al grafului. Aceasta nseamn c fiecare proces este vizitat de mai multe ori. Dac la fiecare vizitare procesul se menine liber, putem decide terminarea ntregii colecii de procese. Fie c un ciclu care include toate arcele grafului i fie nc lungimea lui. Procesele pstreaz o urm a acestui ciclu, astfel c la fiecare vizitare ele aleg urmtoarea legtur pe care transmit jetonul. Ca i mai nainte, jetonul poart numrul de legturi gsite libere. Spre deosebire de cazul precedent, nu este sigur c dac la captul ciclului jetonul gsete procesul iniiator la culoarea de start, celelalte procese nu au schimbat mesaje ntre ele. Ca urmare, de data aceasta este nevoie de o regul diferit de pasare a jetonului i de o condiie diferit de decidere a terminrii. Jetonul pornete de la orice proces i are iniial valoarea 0. Cnd procesul devine liber pentru prima dat, se coloreaz n albastru i transmite jetonul prin prima legtur a ciclului c. La recepia unui jeton, un proces face urmtoarele aciuni: {GRAF: jetonul are valoarea T => ultimele T canale vizitate de jeton erau goale i toate P(i) care au transmis jetonul erau albastre cnd au transmis jetonul} aciunile lui P(i:1..n) la primirea unui mesaj uzual:
culoare[i] := rosu;

aciunile lui P(i:1..n) la recepia jetonului:


if jeton = nc -> anun terminarea i stop fi; if culoare[i] = rosu -> culoare[i] := albastru; jeton := 0 [] culoare[i] = albastru -> jeton := jeton +1 fi; seteaz j la canalul urmtor din ciclul c; send ch[j](jeton);

149

Regulile enunate asigur c GRAF este un invariant global. ndat ce jetonul atinge valoarea nc, se poate decide c toate procesele sunt libere i toate canalele sunt goale. n fapt, jetonul parcurge ciclul de dou ori pentru a decide terminarea: o dat pentru a pune procesele la culoarea albastru i a doua oar pentru a verifica pstrarea culorii de la ultima modificare. Exerciiu Extindei rezolvarea deteciei terminrii prin jetoane, de la cazul unui graf complet la cel al unui graf oarecare.

150

11.3 Detecia terminrii folosind confirmrile mesajelor Reamintim c terminarea unui program distribuit este detectat atunci cnd toate procesele sunt libere i toate canalele sunt goale. n soluiile prezentate, se folosete un singur jeton, care culege informaii despre starea tuturor canalelor folosite de program. Funcia de determinare a strii canalelor se poate mpri ntre procesele programului: fiecare proces verific acele canale pe care a transmis mesaje altor procese i care constituie, deci, canalele sale de ieire. Pentru a determina starea canalelor se folosesc dou variante. Prima este cea a confirmrilor: dac pentru fiecare mesaj transmis pe un canal, procesul primete de la receptor un semnal de confirmare, atunci canalul respectiv este gol. A doua variant folosete mesaje de marcaj, transmise pe aceleai canale cu mesajele de date. Un proces transmite un mesaj de marcaj, dup ultimul mesaj de date transmis pe o legtur. Doar marcajele sunt confirmate. Dac procesul nu transmite alte mesaje dup marcaj i primete confirmarea acestuia, atunci canalul respectiv este gol. n continuare sunt prezentate dou soluii ce folosesc aceste variante pentru detecia terminrii unei reele de procese, ale cror legturi de comunicare a datelor alctuiesc un graf oarecare. Ambele presupun existena unui proces sursa, care nu are legturi de intrare i de la care orice alt proces este accesibil pe o cale oarecare din graf (vezi figura 6.4), n care legturile arborelui de acoperire sunt marcate cu linie dubl.
+---+ +---+ +---+ | 1 |============>| 2 |===============>| 4 | +---+ +---+ +---+ | || ^ | | || | | | \/ | | | +---+ | +-------------->| 3 |<-----------------+ +---+

Figura 6.4 Prelucrarea ncepe cnd sursa trimite un mesaj pe fiecare legtur de ieire. Cnd un proces primete primul mesaj, el poate ncepe prelucararea proprie i poate transmite i recepiona alte mesaje pe legturile sale. Procesul se termin atunci cnd funcia sa este realizat complet, dar poate rencepe prelucrarea dac primete alte mesaje.

151

Algoritmul Dijkstra-Scholten se bazeaz pe transmiterea ntre procese a unor semnale de confirmare. Schema de semnalare a terminrii este separat i suplimentar fa de prelucrarea propriu-zis pe care o realizeaz procesul. Ea urmrete informarea sursei despre terminarea coleciei de procese. Procesele pot recepiona i transmite semnalele, chiar i atunci cnd sunt libere, deci au terminat prelucrarea caracteristic a datelor. Semnalele se transmit, evident, n sens invers datelor, reprezentnd confirmri ale prelurii acestora de ctre destinatar. Dac procesele ar fi organizate ntr-o reea cu topologie arborescent, algoritmul de semnalare ar fi simplu: cnd un proces frunz se termin, el anun printele su. Cnd un nod oarecare al arborelui se termin, el ateapt notificarea terminrii de la toi fiii si i apoi i anun printele. Notificrile se propag astfel pn la procesul sursa, aflat n rdcina arborelui. Acest algoritm poate fi extins la un graf dirijat aciclic de procese. Fiecrei legturi i se asociaz un numr, reprezentnd diferena dintre numrul de mesaje de date transmise i numrul de semnale de confirmare primite pe acea legtur. Numim deficit aceast diferen. Cnd un nod dorete s termine, el ateapt primirea pe legturile de ieire a datelor, a unor semnale care reduc deficitele la zero, dup care trimite pe fiecare legtur de intrare a datelor un numr de semnale egal cu deficitul. Algoritmul Dijkstra-Scholten rezolv problema n cazul general, n care sunt permise cicluri n graful proceselor. Rezolvarea se face prin generarea unui arbore de acoperire, pe parcursul transferului mesajelor de date: fiecare proces pstreaz o variabil prim a crei valoare este egal cu identificatorul procesului de la care s-a recepionat primul mesaj de date. Rezolvarea implic trei faze: - trimiterea semnalelor pe toate legturile de intrare, cu excepia celei de la prim; - recepia semnalelor pe toate legturile de ieire; - transmiterea semnalelor spre prim. Pentru recepia semnalelor pe legturile de ieire, se poate ine o eviden global, deoarece este important ca deficitele legturilor de ieire s se anuleze, neavnd importan identitatea legturilor pe care se primesc semnale. Ca urmare, o singur variabil nsemnale care s in minte suma deficitelor legturilor de ieire este suficient. 152

Algoritmul fiecrui nod este repartizat n dou procese: Prelucrare(i) realizeaz transformarea datelor; Nod(i) realizeaz gestiunea mesajelor i a semnalelor schimbate cu celelalte noduri. Prelucrare(i) are un canal chm[i] prin care primete mesajele de date. Nod(i) are un canal chs[i] prin care primete semnale de la celelalte procese, anunuri de transmitere/recepie de mesaje de date i cereri de terminare de la Prelucrare(i). Rspunsul la cererile de terminare este dat pe canalele stop[i].
chm[i] +-------------+ chm[j] --> ]]]]]]-->-|Prelucrare[i]| -----> ]]]]]]---> Prelucrare[j] +-------------+ | | <------- Nod[j] +-+ +-+ stop[i]+-+ +-+ chs[i] +-+ +-+ +-+ +------+ | +<-|Nod[i]|<-+ +------+

Figura 6.5 Topologia (virtual a) reelei de procese este pstrat n tabloul in. Fiecare element al acestuia nregistreaz existena legturii (cmpul exista) i deficitul (cmpul deficit). Procesul Prelucrare (i) are o funcionare ciclic. Dup recepia unui mesaj de date, el realizeaz prelucrrile cerute i, eventual, transmite mesaje de date altor procese. El nsui poate primi mesaje de date de la celelalte procese, pe canalele de intrare. Recepiile i transmiterile de mesaje sunt anunate procesului Nod(i). La sfritul prelucrrii, procesul trimite lui Nod(i) o cerere de terminare i ateapt recepia unei confirmri pe un canal special stop[i]. Procesul Nod(i) are o funcionare ciclic. La fiecare iteraie, el trateaz unul din mesajele primite de la procesul de prelucrare local sau de la celelalte procese Nod. Pentru un anun de recepie de date, procesul actualizeaz deficitul legturii de intrare i, eventual, prim. Un anun de transmitere determin incrementarea variabilei nsemnale. Un semnal determin decrementarea variabilei nsemnale. n fine, o cerere de terminare provoac transmiterea de semnale pe legturile de intrare. Dac nsemnale este nul, atunci se transmit semnale ctre nodul printe din arborele de acoperire (prim) i se confirm terminarea. Altfel, se transmite o infirmare a terminrii. Algoritmul are urmtoarea descriere: 153

type fel = enum(semnal, transmitere, receptie, terminare); type arc = rec (exista: bool; deficit: int;); chan chs[1:n](op: fel, id: int); chan chm[1:n](id:int, date: tip_date); chan stop[1:n](bool); Nod(i:1..n):: var in: array[1:n] of arc; var nsemnale: int :=0; var prim: int :=0; var id: int, k: fel; do true -> receive chs[i](k, id); if k = receptie -> if prim = 0 -> prim := id fi; in[id].deficit := in[id].deficit+1; [] k = transmitere -> nsemnale := nsemnale+1; [] k = semnal -> nsemnale := nsemnale-1; [] k = terminare -> fa j := 1 to n st in[j].exista and (j<>prim) -> do in[j].deficit>0 -> send chs[j](semnal, i); in[j].deficit := in[i].deficit-1; od af; if nsemnale<>0 -> send stop[i](false); [] nsemnale=0 -> if (i<>sursa) and (prim<>0) -> do in[prim].deficit>0 -> send chs[prim](semnal, i); in[prim].deficit := in[prim].deficit-1; od; fi send stop[i](true); fi od; Prelucrare(i:1..n):: var data: tip_date, id: int, term: bool; initializari; term := false; do not term ->

154

receive chm[i](id, data); send chs[i](receptie, id); realizeaza prelucrare .... send chm[j](i, data); send chs[i](transmitere, j); ... if decizie de terminare -> term := true; fi od; term :=false; do not term -> send chs[i](terminare, i); receive stop[i](term); od; stop;

De notat c dac nsemnale<>0, nu se ateapt primirea semnalelor nerezolvate i se transmite procesului de prelucrare un rspuns negativ. n varianta prezentat, procesul de prelucrare rencearc terminarea pn cnd aceasta reuete, dar, n cazul general, el poate primi mesaje care s-l repun n execuie (codul trebuie modificat corespunztor). Starea final a actualului algoritm este cea n care procesul surs raporteaz terminarea, iar n celelalte noduri, procesele au terminat prelucrrile. 11.4 Detecia terminrii folosind marcaje n cea de a doua variant, procesele transmit mesaje de marcaj al sfritului comunicaiei, urmnd s primeasc o confirmare doar pentru aceste mesaje, nu i pentru cele de date. Cnd un proces decide terminarea, el ateapt marcaje pe toate legturile de intrare i transmite un marcaj pe fiecare legtur de ieire. ndat ce procesul a primit marcaje, el trimite confirmri pe legturile de intrare corespunztoare, mai puin pe prima legtur. Apoi, el ateapt semnale pe legturile de ieire. Cnd le primete, transmite un semnal pe prima legtur. Structurile utilizate pentru cele dou categorii de arce au aceeai sintax. Ele conin cmpurile exista, activ i marcaj. De data aceasta, fiecare arc de intrare nregistreaz dac: - s-a primit un mesaj (se pune activ pe true); - s-a primit un marcaj (se pune marcaj pe true); - s-a transmis un semnal de confirmare (se pun ambele pe false). Similar, pentru fiecare arc de ieire, se nregistreaz dac: - s-a transmis un mesaj (se pune activ pe true); 155

- s-a transmis un marcaj (se pune marcaj pe true); - s-a primit un semnal de confirmare (se pun ambele pe false).
const marcaj = mesaj-special-de-marcaj-sfirsit-date; type fel = enum(semnal, transmitere, receptie, receptie-marcaj, terminare); type arc = rec (exista: bool; activ: bool; {initial false} marcaj: bool;); {initial false} chan chs[1:n](op: fel, id: int); chan chm[1:n](id:int, date: tip_date); chan stop[1:n](bool); Nod(i:1..n):: var term: bool := false; var in, out: array[1:n] of arc; var nsemnale: int :=0; {numar semnale asteptate pe out} var prim: int :=0; var nmarcaje: int; {numar marcaje asteptate pe in} var id: int, k: fel; do true -> receive chs[i](k, id); if k = receptie -> if prim = 0 -> prim := id fi; if not in[id].activ -> in[id].activ := true; nmarcaje := nmarcaje+1; fi; [] k = receptie-marcaj -> in[id].marcaj :=true; nmarcaje := nmarcaje-1; if id=prim -> term := true fi; [] k = transmitere -> if not out[id].activ -> out[id].activ := true; nsemnale := nsemnale+1; fi [] k = semnal -> out[id].activ := false; out[id].marcaj := false; nsemnale := nsemnale-1; [] k = terminare -> if not term -> send stop[i](false); [] term -> fa j := 1 to n st j<>prim and out[j].activ and not out[j].marcaj -> send chm[j](i, marcaj); out[j].marcaj := true; af; if nmarcaje <> 0 -> send stop[i](false); [] nmarcaje = 0 ->

156

fi fi fi od;

fa j := 1 to n st in[j].exista and (j<>prim) and in[j].activ -> send chs[j](semnal, i); in[j].activ := false; in[j].marcaj := false; af if nsemnale<>0 -> send stop[i](false); [] nsemnale=0 -> if (i<>sursa) and (prim<>0) -> send chs[prim](semnal, i); in[prim].activ := false; in[prim].marcaj := false; fi; send stop[i](true); fi

Prelucrare(i:1..n):: var data: tip_date, id: int, term: bool; initializari; term := false; do not term -> receive chm[i](id, data); if data=marcaj -> send chs[i](receptie-marcaj,id); [] data<>marcaj -> send chs[i](receptie, id); realizeaza prelucrare .... send chm[j](i, data); send chs[i](transmitere, j); ... if decizie de terminare -> term := true; fi od; term :=false; do not term -> send chs[i](terminare, i); receive stop[i](term); od; stop;

157

11.5 Detecia terminrii. Algoritmul lui Huang


Modelul se bazeaz pe urmtoarele: procesele pot fi active sau libere (idle) doar procesele active transmit mesaje procesele libere pot deveni active la recepia unui mesaj de "calcul" procesele active pot deveni libere n price moment terminarea: toate procesele sunt libere i nu exist mesaje de "calcul" n tranzit Ideea este urmtoarea: Un agent de control are iniial ponderea 1 Toate celelalte procese sunt libere i au iniial ponderea 0 Calculul pornete cnd agentul de control transmite un mesaj de "calcul" unui proces Un proces liber devine activ la recepia unui mesaj de "calcul" Fie: B(DW) mesajul de "calcul" cu ponderea DW. Mesajul poate fi trimis doar de agentul de control sau de de un proces activ C(DW) mesaj de control cu ponderea DW, transmis de un proces activ agentului de control cnd devine liber Ponderea curent a unui proces este W Algoritmul are urmtoarele reguli: 1. Send B(DW): Gsete W1, W2 astfel nct W1 > 0, W2 > 0, W1 + W2 = W Pune W = W1 i transmite B(W2) 2. Receive B(DW): W += DW; if liber -> devine activ 3. Send C(DW): send C(W) agentului de control devine liber 4. Receive C(DW): W += DW if W = 1, declar terminarea

158

12. Algoritmi pentru sisteme tolerante la defecte 12.1 Specificarea problemei Unul dintre motivele utilizrii paralelismului este tolerana la defecte, adic funcionarea corect sau rezonabil n prezena unor defeciuni ale sistemului. Nu orice sistem este tolerant la defecte. Algoritmii de excludere mutual prezentai mai devreme n acest capitol nu funcioneaz corect n cazul defectrii unora dintre procesoare. Arhitectura unui sistem tolerant la defecte este prezentat n figura 12.1.
+---------+ +---> proces1 ->-----+ +---------+ +---------+ +------------+ date de +---> proces2 ->-- comparator +-> rezultate intrare --- +---------+ +------------+ . . . +---------+ +---> procesn ->-----+ +---------+

Figura 12.1 Datele de intrare sunt replicate i transmise mai multor procese. Fiecare proces realizeaz aceleai prelucrri, furniznd rezultatele corespunztoare. Un comparator alege, pe principiul majoritii, rezultatul corect dintre cele obinute de la procese. Dac unul sau mai multe dintre procese funcioneaz incorect, ele nu afecteaz rezultatele, att timp ct majoritatea proceselor sunt corecte. n anumite sisteme, chiar i datele de intrare sunt produse de mai multe surse. Aceasta poate constitui un izvor suplimentar de erori. n astfel de cazuri, cerinele impuse proceselor de prelucrare sunt foarte severe. Ele trebuie s produc aceeai ieire pentru aceleai valori de intrare, dar i valori apropiate la ieire, pentru valori de intrare apropiate (este cazul frecvent al culegerii datelor prin instrumente de msur care au anumite tolerane). Aspectul comun al variantelor prezentate este acela c un proces defect poate impiedica derularea corect a calculelor nu doar prin absena unui rspuns, ci prin furnizarea unui rspuns eronat, cu anse de a perturba rezultatul final al calculului. 159

Problema pe care o discutm n continuare este cunoscut sub numele de consensul generalilor bizantini. Mai multe uniti ale armatei bizantine pregtesc o aciune mpotriva unui adversar. Fiecare unitate este comandat de un general, acetia comunicnd ntre ei prin legturi directe punct la punct (fiecare legtur identific precis transmitorul i receptorul ei). Legturile sunt fr erori (absena unui mesaj nu poate fi pus pe seama defectrii legturii) i nu interfer ntre ele (nici un general nu poate "asculta" ce comunic ali doi generali ntre ei). Generalii trebuie s cad de acord asupra continurii operaiunilor. Considerm c ei au posibilitatea de alegere dintr-o gam restrns de variante, ca: atac, retragere, atac pe flancul stng, atac pe flancul drept. O metod folosit pentru luarea unei decizii este ca fiecare general s observe inamicul i s comunice observaia sa tuturor celorlali generali. Fie v(i) informaia comunicat de generalul i. Fiecare din cei n generali ai armatei bizantine folosete o metod de a combina valorile v(1), . . ., v(n) ntr-o singur decizie. Consensul se obine dac generalii loiali folosesc aceeai metod de decizie i aceleai valori v(i), i=1,n. Dar, nu toi generalii sunt loiali. Unii generali sunt trdtori i ncearc s mpiedice generalii loiali s ajung la un consens. Pentru aceasta, un general trdtor i nu transmite aceeai valoare v(i) tuturor celorlali generali. Pentru ca generalii loiali s poat decide prin aplicarea unei metode comune, este necesar ndeplinirea urmtoarei condiii: 1. Fiecare general loial s obin aceeai informaie v(1) . . . . , v(n). Deoarece trdtorii nu transmit tuturor celorlali generali aceeai valoare, algoritmul ar trebui s permit ca un general s nu foloseasc valoarea v(i) obinut direct de la generalul i. Acesta face posibil ca valoarea v(i) folosit de un proces s fie diferit de valoarea obinut direct de la generalul i. Pe de alt parte, ar trebui ca o astfel de situaie s nu apar pentru valorile transmise de generalii loiali. De exemplu, generalii loiali nu ar trebui s-si bazeze decizia pe valori "retragere" dac toi generalii loiali au trimis valoarea "atac". Rezult condiia: 2. Dac generalul i este loial, atunci valoarea v(i) transmis de el trebuie folosit ca atare de fiecare general loial. 160

Putem rescrie condiia 1 astfel: 1'. Oricare doi generali loiali folosesc aceeai valoare a lui v(i) (indiferent dac i este loial sau nu). Condiiile 1' i 2 astfel specificate se refer la o singur valoare trimis de un general ctre ceilali. Ca urmare, putem redue problema la modul n care un singur general trimite valoarea sa celorlali generali. Convenim ca transmitorul mesajului s fie numit comandant, iar ceilali generali s fie numiti locoteneni. Problema are urmtorul enun. Problema Generilor Bizantini. Un comandant trebuie s trimit un ordin celor n-1 locoteneni ai si astfel ca: IC1. Toi locotenenii loiali se supun aceluiai ordin. IC2. Dac comandantul este loial, atunci fiecare locotenent loial se supune ordinului tranmis de el. Condiiile IC1 si IC2 se numesc consisten interactiv (interactive consistency). De notat c: - atunci cnd comandantul este loial, condiia IC1 rezult din IC2; - comandantul nu este neaprat loial. Pentru a rezolva problema original, fiecare general i trimite ordinul "folosete v(i) ca atare" folosind soluia problemei generalilor bizantini, cu ceilalti generali acionnd ca locoteneni. Pentru situaia n care un general poate transmite orice mesaj (mesaje orale), s-a demonstrat c, dac mai mult de dou treimi din generali sunt loiali, atunci exist o soluie, adic un algoritm care permite generalilor loiali s ia aceeai decizie indiferent de mesajele primite de la generalii trdtori. Dac o treime sau mai mult de o treime din generali trdeaz, problema nu admite soluie. Deci, n cazul unui singur trdtor, problema are soluie pentru patru generali (inclusiv trdtorul) i nu are soluie pentru trei generali. Analizm n continuare aceste situaii, pe baza unor scenarii. Algoritmul folosit pentru un singur trdtor este urmtorul: 1. Comandantul transmite decizia sa tuturor locotenenilor. 2. Un locotenent transmite celorlali locoteneni mesajul primit de la comandant. 161

3. Dup primirea mesajului direct de la comandant i a cpiilor acestuia de la ceilali locoteneni, un locotenent decide prin vot majoritar ce decizie trebuie s ia. Scenariul 1. Comandantul este loial, iar decizia este atac. Locotenenii loiali transmit atac, iar trdtorul transmite orice mesaj (inclusiv atac). Schema prezentat n figura 12.2 ilustreaz comunicarea ntre generali.
+--------------+ +----<----------- comandant ---->---------+ +--------------+ atac atac atac atac v atac +--------------+-------->+--------------+------->+--------------+ locotenent 1 atac locotenent 2 *** locotenent 3 +--------------+<--------+--------------+<-------+--------------+ *** +-----------------------<---------------------+ +--------------------------->-------------------------+ atac

Figura 12.2 Din scenariu, rezult c un locotenent loial primete mesajul atac att de la general ct i de la cellalt locotenent loial. Indiferent de mesajul transmis de trdtor, prin regula majoritii rezult o decizie corect. Scanariul 2. Comandantul este neloial i transmite mesaje diferite locotenentilor. Schema din figura 12.3 ilustreaz aceast situaie.
+--------------+ +----<----------- comandant ---->---------+ +--------------+ atac retrag *** atac v retrag +--------------+-------->+--------------+------->+--------------+ locotenent 1 retrag locotenent 2 *** locotenent 3 +--------------+<--------+--------------+<-------+--------------+ atac +-----------------------<-------------------+ +--------------------------->-----------------------+ ***

Figura 12.3 162

Nu conteaz ce decide comandantul, atta timp ct locotenenii loiali cad de acord asupra aciunii urmtoare. Deoarece locotenenii sunt loiali, ei trimit exact mesajele primite de la comandant. Toi trei locotenenii primesc aceleai mesaje, ca urmare ei lund aceeai decizie. Scenariul 3. Grupul conine trei generali. Cazul este prezentat n figura 12.4. Sunt prezentate dou situaii: una n care trdtorul este un locotenent (a) i alta n care trdtorul este comandantul (b). n ambele cazuri, locotenentul 1 primete aceleai mesaje de la comandant i de la al doilea locotenent. Algoritmul sau ar trebui s decid atacul n cazul (a). Deoarece algoritmul su este determinist, el ar trebui s decid acelai lucru n cazul (b), dnd mereu prioritate mesajului comandantului. Dup acelai algoritm funcioneaz i cel de al doilea locotenent. Ca urmare, n cazul (b), rezultatul este c primul locotenent atac, n timp ce al doilea se retrage. Ca urmare, algoritmul nu d o soluie corect problemei.
+-----------+ +-----------+ +-<- comandant ->+ +-<- comandant >-+ +-----------+ +-----------+ atac atac atac retrag atac atac +-----------+------>+-----------+ +-----------+------->+-----------+ locotenent1 retraglocotenent2 locotenent1 retrag locotenent2 +-----------+<------+-----------+ +-----------+<-------+-----------+ (a) (b)

Figura 12.4 Pe baza scenariilor anterioare se poate arta c nu exist o soluie pentru m trdtori i mai puin de 3m+1 generali. Demonstraia se face prin contradicie. Adoptm denumirea de generali albanezi pentru cazul general. Considerm c exist o soluie n care apar 3m sau mai puini generali albanezi i m trdtori. Din ea derivm una pentru 3 generali bizantini (despre care tim c este imposibil). Aceasta s-ar obine considernd c fiecare general bizantin simuleaz cel mult m generali albanezi: - comandantul bizantin simuleaza comandantul albanez plus cel mult m-1 locoteneni albanezi; - fiecare din cei doi generali bizantini simuleaz cel mult m locoteneni albanezi. Se obine astfel cazul cu un general bizantin trdtor (el simuleaz m albanezi) pentru un total de trei generali bizantini.

163

Din faptul ca IC1 i IC2 sunt ndeplinite pentru generalii albanezi se deduce c ele sunt ndeplinite i pentru un trdtor i trei generali bizantini, contrazicnd rezultatul anterior. 12.2 Soluia cu mesaje orale n soluionarea problemei generalilor bizantini, fiecare general transmite mesaje celorlali generali. n aceast seciune considerm mesaje orale. Un mesaj oral este unul aflat sub controlul total al transmitorului. Un transmitor trdtor poate transmite orice mesaj posibil. Mai precis, un mesaj oral indeplinete urmtoarele condiii: A1. Fiecare mesaj transmis este livrat corect. A2. Receptorul unui mesaj tie cine l-a trimis. A3. Absena unui mesaj poate fi detectat. Cu alte cuvinte, un trdtor nu poate interfera cu comunicarea ntre ali doi generali (condiiile A1 i A2) i nici nu poate influena decizia prin ne-transmiterea unui mesaj (condiia A3). Un mesaj oral corespunde tipului de mesaje pe care calculatoarele i le trimit unul altuia (punct la punct). Comportamentul este diferit pentru mesaje semnate, scrise. Pentru mesaje orale, mai mult de 2/3 din generali trebuie sa fie loiali. Ca urmare, cu mesaje orale, nu exist o soluie pentru un trdtor i doar trei generali (vezi scenariile prezentate n seciunea 12.1). Algoritmii din seciunile urmtoare cer ca fiecare general s poat comunica direct cu ceilali. Un comandant trdtor poate decide sa nu trimit un ordin. n acest caz, ordinul implicit pentru locoteneni este de "retragere". Algoritmul Oral Message, OM(n,m), cu m ntreg, ne-negativ rezolv problema generalilor bizantini pentru 3m + 1 sau mai muli generali (reprezentai de n) n prezena a cel mult m trdtori. Convenii: - se folosete expresia un locotenent "obine o valoare" i nu "se supune unui ordin" - algoritmul folosete o funcie majority cu proprietatea c dac majoritatea valorilor v(i) este v atunci valoarea funciei este v. 164

Exist dou versiuni naturale pentru valoarea funciei majority(v1, . . . , vn-1): 1. valoarea majoritar n vi dac ea exists, altfel o valoarea implicit Vdef (de exemplu, RETREAT); 2. Mediana valorilor vi, presupunnd c valorile sunt dintr-o mulime ordonat. Algoritmul UM(n,0). (1) Comandantul trimite valoarea sa fiecrui locotenent. (2) Fiecare locotenent folosete valoarea primit de la comandant, sau folosete Vdef dac nu primete nici o valoare. Algoritmul UM(n,m), m > 0. (1) Comandantul trimite valoarea sa fiecrui locotenent. (2) For each Locotenent i, fie vi valoarea primit de la comandant, sau Vdef dac nu primete nici o valoare. Locotenentul i acioneaz drept comandant i trimite valoarea vi fiecruia din ceilali n - 2 locoteneni folosind UM(n - 1,m - 1) (3) For each i and each j <> i fie vj valoarea pe care Locotenentul i o primete de la Locotenentul j n pasul (2) (folosind Algoritmul UM(n - 1, m - 1)), sau Vdef dac nu primete nici o valoare. Locotenentul i folosete valoarea majority (v1 . . . . . vn-1 ). Exemplu pentru m = 1, n = 4, Locotenentul 3 este trdtor (Figura 12.5).

Figura 12.5 Pas 1 UM(4,1) - comandantul trimite v tuturor locotenentilor. Pas 2 UM(4,1) - L1 trimite valoarea v celorlali locoteneni folosind UM(0) - L2 trimite valoarea v celorlali locoteneni folosind UM(0) - L3 trimite alte valori (x, y) folosind OM(0) Pas 3 UM(4,1) - L1 calculeaz majority(v, v, x) = v 165

- L2 calculeaz majority(v, v, y) = v

Exemplu pentru m = 1, n = 4, Comandantul este trdtor (Figura 12.6).

Figura 12.6 Pas 1 UM(4,1) - comandantul trimite x, y i nimic locotenentilor. Pas 2 UM(4,1) - L1 trimite valoarea x celorlali locoteneni folosind UM(0) - L2 trimite valoarea y celorlali locoteneni folosind UM(0) - L3 trimite valoarea Vdef celorlali locoteneni folosind UM(0) Pas 3 UM(4,1) - L1, L2 i L3 calculeaz majority(x, y, Vdef) obinnd aceeai valoare. Algoritmul recursiv UM(n,m) transmite n-1 mesaje n primul pas i invoc n-1 execuii separate ale algoritmului OM(n-1,m - 1); fiecare din acestea trimite n-2 mesaje i invoc n-2 execuii ale algoritmului OM(n-2,m - 2). n pasul 2 se transmit deci n total (n-1)(n-2) mesaje. n pasul m+1 se transmit (n-1)(n-2)...(n-m-1) mesaje deci numrul total de mesaje este O(nm+1). Pentru m > 1, un locotenent trimite mai multe mesaje separate fiecruia din ceilali locoteneni. Pentru a distinge ntre aceste mesaje, fiecare locotenent i prefixeaz numrul i la valoarea vi pe care o trimite n pasul (2). Pe msur ce recursia progreseaz, algoritmul UM(n-k,m-k) va trimite o valoare prefixat de o secven de k numere ale locotenenilor. Pentru a proba corectitudinea algoritmului UM(n,m), probm mai nti urmtoarea: LEMA 1. Pentru orice m i k, UM(n,m) satisface IC2 dac numrul n de generali este mai mare de 2k+m i sunt cel mult k trdtori. 166

Demonstraia este prin inducie dup m. IC2 spune ce se ntmpl cnd comandantul este loial (fiecare locotenent loial se supune ordinului transmis de el). Pentru m=0, UM(n,0) satisface IC2, deoarece fiecare mesaj transmis este livrat corect (proprietatea A1). Presupunem c proprietatea este adevrat pentru m-1, m>0 i o probm pentru m. n pasul (1), comandantul loial trimite o valoare v celor n-1 locoteneni. n pasul (2), fiecare locotenent loial aplic UM(n-1,m-1) cu n-1 generali. Deoarece prin ipotez n > 2k + m, avem n - 1 > 2k + (m - 1), deci conform ipotezei de inducie fiecare locotenent loial obine vj = v pentru fiecare locotenent loial j. Deoarece sunt cel mult k trdtori i n - 1 > 2k + (m - 1) >= 2k, o majoritate de n-1 locoteneni sunt loiali. Deci, fiecare locotenent loial obine o majoritate de valori vj = v, astfel c n pasul (3) se obine majority(v1 . . . . , vn-1) = v. Aceasta probeaz IC2. Probm apoi c UM(n,m) rezolv problema generalilor bizantini: TEOREMA 1. Pentru orice m, algoritmul UM(n,m) satisface condiiile IC1 i IC2 dac numrul de generali n este mai mare de 3m i sunt cel mult m trdtori. Demonstraia este prin inducie dup m. Pentru m=0 (nu sunt trdtori), este uor de vzut c UM(n,m) satisface IC1 (toi locotenenii loiali se supun aceluiai ordin) i IC2 (cnd comandantul este loial fiecare locotenent loial se supune ordinului transmis de el). Presupunem c teorema este adevrat pentru m-1 i probm c este ndeplinit pentru m > 0. Cnd comandantul este loial, punnd k=m n Lema 1, rezult c UM(n,m) satisface IC2, iar IC1 rezult din IC2. Rmne de demonstrat IC1 cnd comandantul este trdtor. Sunt cel mult m trdtori i comandantul este unul din ei. Deci, cel mult m-1 locoteneni sunt trdtori. Deoarece sunt mai mult de 3m generali, avem mai mult de 3m-1 locoteneni. Deoarece 3m-1 > 3(m - 1), putem aplica ipoteza de inducie i obinem c UM(n-1,m1) satisface satisface condiiile IC1 i IC2. Deci, pentru fiecare j, oricare doi locoteneni loiali obin aceeai valoare vj n pasul (3). Deci, oricare doi locoteneni loiali obin aceleai valori vl . . . . . vn-1 i aceeai valoare majority(vl . . . . . vn-1) n pasul (3), probnd astfel IC1.

167

12.3 Soluia cu mesaje semnate n cazul mesajelor semnate, se adaug condiia urmtoare: A4 (a) Semntura unui general loial nu poate fi falsificat i orice alterare a coninutului mesajului semnat poate fi detectat (b) Oricine poate verifica autenticitatea semnturii unui general. n schimb, semntura unui trdtor poate fi falsificat de un alt trdtor. Algoritmul prezentat n continuare funcioneaz pentru orice numr de generali (evident mai mare dect m+2 pentru m trdtori). In algoritm: - comandantul trimite un ordin semnat fiecarui locotenent; - fiecare locotenent adaug semntura sa la ordin i-l transmite celorlali care adaug semnturile lor i l transmit mai departe .a.m.d. Algoritmul folosete o funcie choice care se aplic unei mulimi de ordine pentru a obine un singur ordin. Cerine: 1. Dac mulimea V const dintr-un singur element v, atunci choice(V) = v. 2. choice() = RETREAT, unde este multimea vid. O definiie posibil este ca choice(V) sa fie elementul median al lui V, presupunnd c exist o ordine a elementelor.

Notaii: x:i este valoarea x semnat de generalul i x:j:i este valoarea x semnat de j, apoi valoarea x:j semnat de i generalul 0 este comandantul locotenentul i pstreaz mulimea Vi a ordinelor bine semnate primite (dac comandantul este loial, Vi ar trebui s conin doar un element).

Algoritmul SM (m). Iniial Vi = . (1) Comandantul semneaz i trimite valoarea sa fiecrui locotenent. (2) For each i: (A) If Locotenent i primete un mesaj de forma v: 0 de la comandant i nu a primit nc nici un ordin then (i) Vi := {v}; (ii) transmite mesajul v:0:i fiecruia din ceilali locoteneni. 168

(B) If Locotenent i primete un mesaj de forma v:0:jl: :jk i v nu este n Vi then (i) adaug v la Vi; (ii) if k < m then trimite mesaj v:0:jl: . . . :jk:i fiecrui locotenent diferit de jl . . . jk. (3) For each i: when Locotenent i nu mai primete mesaje el execut ordinul choice(Vi). Observaii Pas (2) - Locotenentul i ignor orice mesaj coninnd un ordin v aflat deja in Vi. Pas (3) detectare oprire mesaje pentru fiecare secven de locoteneni j1, ... , jk, k<=m, un locotenent poate primi cel mult un mesaj de forma v:0:j1: :jk n pasul (2). Putem cere ca locotenentul k sa trimit acest mesaj sau s trimit un mesaj special care s raporteze c nu va trimite un astfel de mesaj alternativ, se poate folosi un timer pentru a detecta cnd nu vor mai sosi mesaje.

Figura 12.7 Figura 12.7 ilustreaz algoritmul SM(1) pentru cazul a trei generali cnd comandantul este trdtor. Comandantul transmite un ordin "attack" unuia din locoteneni i un ordin "retreat" celuilalt. Locotenenii primesc cele dou ordine n pasul (2); deci dup (2) V1 = V2 = {"attack", "retreat"}, i ambii se supun ordinului choice({"attack", "retreat"} ).

169

De menionat c aici, spre deosebire de situaia din figura 12.6, locotenenii tiu c comandantul este trdtor deoarece semntura lui apare n dou ordine diferite i A4 spune c doar el ar fi putut genera aceste semnturi. Pentru probarea corectitudinii, demonstrm TEOREMA 2. Pentru orice m, Algoritmul SM(m) rezolv problema generalilor bizantini dac exist cel mult m trdtori. Probm mai nti IC2. Cnd comandantul este loial, el trimite ordinul semnat v:0 fiecrui locotenent n pasul (1). Fiecare locotenent loial primete ordinul v n pasul (2)(A). Deoarece nici un locotenent neloial nu poate falsifica vereun mesaj de forma v':0, un locotenent loial nu poate primi un alt ordin n pasul (2)(B). Ca urmare, setul Vi obinut n pasul (2) are un singur ordin v, cruia i se va supune conform funciei choice. Aceasta probeaz IC2, iar IC1 rezult direct din acesta. Rmne de probat IC1 cnd comandantul este trdtor. Artm c dac locotenentul loial i pune un ordin v n Vi n pasul (2) atunci j va pune acelai ordin v n Vj n pasul (2). Dac i primete ordinul v n pasul (2)(A), atunci el l transmite lui j n pasul (2)(A)(ii); j l primete (conform proprietii A1). Dac i adaug ordinul la Vi n pasul (2)(B), atunci el trebuie s fi primit un mesaj de forma v:0:jl: . . . :jk. Dac j este unul dintre jr, atunci (conform A4) el trebuie s fi primit deja ordinul v. Dac nu, considerm dou cazuri: 1. k < m. n acest caz, i trimite mesajul v:0:j l: . . . :jk:i to j ; deci j trebuie s primeasc ordinul v. 2. k = m. Deoarece comandantul este trdtor, cel mult m - 1 dintre locoteneni sunt trdtori. Deci, cel puin unul dintre locotenenii jl, . . . , jm este loial. Acest locotenent loial trebuie s fi trimis lui j valoarea v atunci cnd a primit-o prima dat, deci j trebuie s fi primit aceast valoare. Bibliografie LESLIE LAMPORT, ROBERT SHOSTAK, and MARSHALL PEASE SRI International The Byzantine Generals Problem ACM Transactions on Programming Languages and Systems, Vol. 4, No. 3, July 1982, Pages 382-401.

170

15. Algoritmi genetici 15.1. Generaliti Algoritmii genetici - AG reprezint o soluie a problemelor de optimizare, bazat pe mecanisme mprumutate din genetic. Un algoritm genetic menine o populaie de indivizi, fiecare individ reprezentnd o soluie potenial a unei probleme de rezolvat. AG ncearc s amelioreze populaia i s gseasc astfel o soluie ct mai apropiat de cea optim, printr-un proces iterativ care implic realizarea, n fiecare etap, a urmtoarelor operaii: evaluarea populaiei curente selecia celor mai buni indivizi transformarea populaiei folosind operatori genetici de ncruciare i mutaie. AG furnizeaz o metod de optimizare mai bun dect soluiile clasice cunoscute, ca hill climbing sau simulated annealing. AG reprezint instrumente eficace i eficiente potrivite implementrii n medii distribuite. Domeniile de aplicare a algoritmiloor genetici sunt foarte diferite: optimizarea parametrilor control optim transport optimizare combinatorial desenare de grafuri nvare inductiv a regulilor de decizie stabilirea cablajelor planificarea jocuri, modelarea cognitiv optimizarea interogrii bazelor de date. Rezolvarea unei probleme poate fi perceput ca o cutare n spaiul soluiilor poteniale. Aflarea celei mai bune soluii transform rezolvarea ntr-un proces de cutare. Pentru un spaiu de soluii redus se pot folosi metodele clasice exhaustive. Pentru un spaiu de soluii mare, se pot folosi tehnici de inteligen artificial, de exemplu algorimii genetici. Acetia sunt algoritmi stochastici ale cror metode de cutare imit fenomenele naturale: motenirea genetic, lupta pentru supravieuire / selecia natural.

Algoritmii genetici mprumut vocabularul geneticii: soluiile sunt indivizi, mulimea soluiilor poteniale reprezint o populaie, n reprezentarea soluiilor apar gene (caractere). Un AG are urmtoarele componente: o reprezentare genetic a soluiilor o cale de generare a primei populaii o funcie de evaluare a calitii soluiilor operatori genetici valori pentru parametri - dimensiunea populaiei, probabilitatea aplicrii operatorilor genetici. 15.2. Metode clasice de optimizare Rezolvarea problemelor de optimizare se poate face folosind mai multe tehnici, dintre care vom trece pe scurt n revist doua abordari. Problema pe care o ilustram este cautarea intr-un spatiu de siruri binare de 30 de biti, cu functia obiectiv f(v) = | 11*one(v)-150| unde one(v) este numarul de unitati din vectorul binar v. Functia f(v) are un maxim global pentru vg = (1 1 1 1 1), pentru care f(vg) = 180 si un maxim local pentru vl = (0 0 0 0), pengtru care f(vl) = 150. 15.2.1. Algoritmul hill climbing Procedeul crrii (hillclimbing) aplic urmtorul algoritm: procedure hillclimber begin t := 0 do t < MAX -> local := false selecteaz aleator sirul curent Vc evalueaza Vc do not local -> gaseste Vn dintre vecinii cu cea mai mare valoare a functiei obiectiv F if F(Vc) < F(Vn) -> Vc := Vn

[] F(Vc) >= F(Vn) -> local := true fi od t := t+1 od end Algoritmul se bazeaz pe alegerea aleatoare a unui punct de pornire n spaiul soluiilor i pe ncercarea de a mbunti treptat soluia prin micri pozitive spre punctele vecine soluiei curente. Cutarea se oprete cnd astfel de micri nu mai sunt posibile. Algoritmul prelucreaz la un moment dat un singur punct din spaiul strilor. Pentru a mri ansa de gsire a unei soluii bune, algoritmul se aplic repetat, pentru alte puncte de plecare alese aleator. Rezultatul este puternic dependent de irul iniial. Exist o probabilitate mic de a gsi optimul global. Pentru problema specificata la inceputul sectiunii, daca sirul de pornire are un numar de unitati mai mic sau egal cu 13 atunci se gaseste intotdeauna maximul local. 15.2.2. Algoritmul simulated annealing Acest algoritm a fost inspirat de mecanica statistica si de anumite procedee de imbunatatire a calitatii unor materiale prin incalzirea lor la o temperatura ridicata urmata de racirea lor controlata, pentru a permite o aranjare favorabila la nivel molecular. El reprezinta un puternic instrument in rezolvarea unor probleme de optimizare. Principala forta a acestui algoritm este posibilitatea de a sari peste anumite optime locale nefavorabile, fiind permise nu doar "coborasuri" spre solutii ci si "urcusuri" (controlate de o anumita probabilitate) care departeaza cautarea de optimul cel mai apropiat. Parametrii importanti ai acestui tip de algoritm sunt temperatura initiala T, conditia de echilibru termic si temperatura de racire in care se desfasoara experimentul. Algoritmul poate utiliza o functie de penalizare a solutiilor intermediare deficitare. Metoda simulated annealing utilizeaz urmtorul algoritm: procedure simulated-annealing begin t := 0 initializeaza temperatura T selecteaza aleator sirul curent Vc evalueaza Vc

do not cond-stop -> do not cond-terminare -> selecteaza un nou sir Vn vecin cu Vc if F(Vc) < F(Vn) -> Vc := Vn [] F(Vc) >= F(Vn) -> if random[0,1) < exp((F(Vn)-F(Vc))/T) -> Vc := Vn fi fi od T := g(T,t) t := t+1 od end Condiia de terminare verific atingerea unui echilibru termic adic a situaiei n care distribuia probabilitilor noilor iruri selectate se apropie de distribuia Bolzmann. ntr-un caz mai simplu, bucla se repet de K ori, unde K este un parametru. Deoarece g(T,t) < T, condiia de stop echivaleaz cu atingerea de ctre T a unei anumite valori limit inferioar. Ca i metoda precedent, simulated annealing urmrete mbuntirea unei soluii aleas aleator. De data aceasta sunt acceptate i mutri negative, spre soluii mai proaste. Acceptarea se face cu o probabilitate care descrete n timp. Mutrile negative permit algoritmului s scape din capcana unor maxime locale i s exploreze mai bine spaiul soluiilor. Pentru problema sirurilor binare mentionata mai inainte, daca avem un sir v12 cu 12 unitati obtinem: f(v12) = |11*12 150| = 18 f(v13) = |11*13 150! = 7 Algoritmul accepta o noua solutie cu 13 unitati cu probabilitatea p = exp((f(Vn)-f(Vc))/T) = exp((7-18)/T) = 0.576 > 0.5, pentru T=20.

15.3. Algoritmi genetici Spre deosebire de metodele prezentate anterior, AG pstreaz o populaie de soluii poteniale. Ca urmare, sunt pstrate i soluii mai slabe, dar care prin ncruciare pot produce descendeni mult mai puternici. AG realizeaz un echilibru ntre explorarea ct mai bun a spaiului de cutare i gsira ct mai rapid a celor mai bune soluii. n schimb, reprezentarea soluiilor este uneori dificil, ca n exemplul comis-voiajorului, iar funcia de evaluare nu este mereu simpl (de exemplu n dilema prizonierului). Conceptul de algoritm genetic este relativ recent, fiind folosit prima data in 1976 de John Holland, pentru o clasa de algoritmi care incearca sa imite procesul de evolutie naturala al unui grup indivizi, de-a lungul mai multor generatii. Odata cu dezvoltarea geneticii, s-au putut cunoaste anumite fenomene care au demonstrat ca proprietatile "exterioare" ale unei fiinte vii sunt datorate unor codificari interne, realizate prin intermediul cromozomilor, entitati organice elementare. Se accepta ideea ca o fiinta este creata (se dezvolta) si pe baza unui proces de decodificare a informatiei primare din cromozomi. Desi nu s-au explicat in totalitate aceste procedee de codificare decodificare, se accepta ca evolutia se produce prin modificarea zestrei genetice (a calitatii cromozomilor detinuti), proces care are loc prin reproducere. Astfel, prin mutatie por apare la copii cromozomi diferiti de cei ai parintilor biologici, o alta posibilitate fiind recombinarea materialului genetic al parintilor biologici. De asemenea, procesul acesta al evolutiei nu are memorie, adica se pastreaza doar informatia "curenta" a unui individ, fara stocarea anumitor informatii despre generatiile anterioare. Acest proces evolutiv care duce la adaptarea continua la conditiile de mediu l-a facut pe Holland sa incerce "copierea" lui cu scopul rezolvarii anumitor probleme dificile. Primii algoritmi genetici lucrau pe siruri de numere binare (0 si 1), care formau cromozomii. Un grup de cromozomi forma o populatie, materialul genetic existent intr-o populatie era "amestecat" prin reproducere, intr-o maniera nepreferentiala si fara nici un fel de informatie asupra problemei reale de rezolvat. Pentru a dirija oarecum evolutia s-a folosit o functie de evaluare a cromozomilor, pentru a permite selectionarea celor mai buni care sa participe apoi la procesul de reproducere. Cu astfel de algoritmi care nu faceau altceva decat sa manipuleze cromozomi, avand mecanisme simple de codificare si reproducere el a reusit rezolvarea unor probleme complicate. Evident, de atunci acesti algoritmi au fost studiati si imbunatatiti substantial, ajungand o alternativa deosebit de atractiva pentru solutionarea anumitor probleme. Desi s-a studiat mult pe aceasta tema nu s-au obtinut rezultate care sa revolutioneze domeniul care a inspirat acesti algoritmi, genetica. Acelasi lucru s-a intamplat insa si cu alte clase de algoritmi care au la baza procese naturale, si anume retelele neuronale si simulated annealing.

Pentru a rezolva o problema folosind algoritmi genetici trebuie facuta o legatura intre problema reala si lumea cromozomilor. In principal aceasta se face codificarea solutiei in cromozomi si prin gasirea unei functii de evaluare a cromozomilor, pentru a avea o masura a calitatii fiecarui cromozom. Tehnica codificarii solutiei in algoritmi variaza foarte mult de la problema la problema, neexistand o regula in acest sens. Prima codificare, folosita de Holland si colaboratorii sai utiliza siruri de biti, insa de atunci au fost folosite numeroase altele. Deoarece nu toate aceste tehnici dau aceleasi rezultate in rezolvarea aceleiasi probleme, se cere o anumita experienta in alegerea modalitatii optime de reprezentare. Functia de evaluare a cromozomilor face legatura cu problema reala, fiind pe post de mediu natural, ea intorcand ca rezultat o masura a performantelor cromozomilor. Pe baza acesteia se stabileste potrivirea ("conditia fizica" a) cromozomului, care va fi luata in considerare in procesul de reproducere. Descrierea generala a unui algortim genetic este prezentat n continuare. procedure algoritm_genetic begin t := 0; creaza o populatie initiala de cromozomi P(t); evalueaza fiecare cromozom al populatiei initiale. do t < MAX ot not conditie de terminare -> t := t+1; selecteaza parintii pentru reproducere; creaza noi cromozomi prin imperechere si mutatie; inlocuieste anumiti membri ai populatiei cu cei noi; evalueaza cromozomii din noua populatie od end n cele ce urmeaz, analizm diferitele etape ale algoritmilor genetici. Analiza este nsoit de un exemplu referitor la partiionarea grafurilor. Problema are urmtorul enun: dat fiind graful G = (V, E) s se gseasc o partiionare a sa n dou subgrafuri avnd acelai numr de noduri, prin eliminarea unui numr minim de muchii. Problema este NP complet, astfel c abordrile practice vizeaz gsirea unor soluii aproximative ct mai bune. Fiecare soluie este reprezentat ca un vector cu elemente binare, de dimensiune egal cu numrul nodurilor din graf. Un cromozom codific o posibil partiionare a grafului, o gen fiind corespunztoare unui nod. Valoarea 1 sau 0 a genei arat dac

nodul respectiv aparine primei partiii sau celei de a doua. O populaie poate fi reprezentat printr-un tablou de cromozomi. 15.3.1. Evaluarea Deoarece problema cere partiionarea grafului prin eliminarea numrului minim de muchii, funcia de evaluare este definit ca: eval(x) = cutsize(x) unde cutsize(x) este numrul de muchii avnd un capt n partiia 1 i cellalt n partiia 2. Ca urmare, problema partiionrii grafului se reduce la una de cutare a minimului. 15.3.2. Generarea populaiei iniiale Asa cum s-a mai spus anterior, modalitatea de reprezentare considerata este cea binara, fiecare cromozom fiind format dintr-un sir de biti al cror numr depinde de numrul de noduri ale grafului. Populatia initiala se poate forma aleator, prin generarea la intamplare a sirurilor de biti reprezentand cromozomii. Pentru a reprezenta soluii valide, cromozomii sunt supui unor transformri al cror rezultat este egalizarea numrului de noduri din cele dou partiii. La acest aspect ne referim n alt seciune a prezentrii. 15.3.3. Selecia parintilor pentru reproducere Selecia prinilor este fcut n conformitate cu strategia ruletei. Aceasta acord indivizilor mai buni anse mai mari de a fi selectai pentru reproducere. Fiecrui individ i se aloc un sector de rulet, al crui unghi la centru este proporional cu calitatea individului. Construcia ruletei se face prin urmtorii pai: calculeaz eval(xi) pentru fiecare cromozom i = 1..pop-size sorteaz populatia n ordinea cresctoare a valorilor eval asociaz cu fiecare cromozom o valoare de potrivire f(xi) = max-fit - eval(xi) astfel c f(xi) > 0 pentru orice i = 1..pop-size calculeaz valorile de potrivire cumulative cf(xi) = SUMA f(xj), j = 1..i Fie cf-max potrivirea cumulativ a ultimului cromozom. Selecia se face astfel: genereaz un numr aleator rand n intervalul [o, cf-max] if rand < cf(x1) -> alege primul cromozom x1 fi

if cf(xi-1) < rand < cf (xi) -> alege xi fi Desi acest algoritm asigura alegerea aleatoarea a unui cromozom, sansa fiecaruia de a fi ales fiind direct proportionala cu valoarea sa, se poate intampla sa fie ales cel mai putin valoros cromozom. Acest lucru nu este deranjant daca nu se intampla foarte des, deoarece asigura realizarea unei diversitati in cadrul populatiei. Pentru aceasta este bine ca generatorul de numere aleatoare folosit sa fie cat mai sigur (perioada mare de repetabilitate), iar suplimentar se poate opta pentru ordonarea descrescatoarea a cromozomilor. Singura restrictie care se aplica cere ca potrivirile sa fie exprimate prin numere pozitive. Un exemplu de functionare pentru o populatie nesortata este cel prezentat in Figura 1. Exemplu selectie cromozomi Cromozom 1 2 3 4 5 6 Potrivire 8 2 17 7 2 12 Potrivire cumulata 8 10 27 34 36 48 Numar aleator Cromozom ales 23 3 49 7 76 10 13 3 1 1 27 3 7 11 59 57 7 8 7 66 9 3 69 10 7 76

Figura 1. Exemplu de folosire a algoritmului ruletei In figura 1 primul tabel prezinta modul in care sunt distribuiti cromozomii in cadrul unei populatii, impreuna cu numerele reprezentand potrivirile acestora. A treia linie contine valorile cumulate ale potrivirilor. Al doilea tabel prezinta numere generate aleator si cromozomul ales in fiecare caz. Se observa ca de fiecare data este ales cromozomul a carui potrivire cumulata depaseste numarul generat aleator (intre 0 si 76). 15.3.4. Reproducia Reproducia este bazat pe operatorii genetici de mutatie si ncruciare (crossover), fiecare avand probabilitati proprii de activare. Acesti doi operatori pot constitui impreuna un meta-operator, sau, cum e mai natural, vor forma doua entitati distincte. Procesul de reproducere consta in alegerea a doi cromozomi-parinti, asupra carora se vor aplica operatorii genetici pentru a da nastere unor cromozomi-copii. Se poate intampla ca cei doi copii sa difere de parintii lor, aducand elemente noi, asa cum la fel de bine ei pot fi identici cu parintii lor. Aceasta din urma situatie (care intuitiv reduce viteza de evolutie) poate apare in urmatoarele situatii: daca parintii si-au atins maximul valorii lor;

prin jocul probabilitatilor de aplicare pentru operatorii genetici; datorita structurii momentane a parintilor, legata de alegerea unor operatori genetici deficitari.

Dupa generarea numarului stabilit de generatii algoritmul se va opri, furnizand ca rezultat cel mai bine cotat cromozom. 15.3.4.1. Operatorul mutation

Aplicarea acestui operator asupra unui cromozom (sir de biti) presupune parcurgerea acestuia si inlocuirea fiecarui bit cu unul ales aleator, daca un anume test de probabilitate este indeplinit. Probabilitatea de aplicare trebuie sa aiba o valoare scazuta, care trebuie determinata prin incercari. Anumite variante de operatori ar putea sa interschimbe doi biti intre ei, in acest caz probabilitatea reala fiind dublul celei folosite pentru test. Modul de functionare al acestui operator este ilustrat in figura 2. Aplicarea operatorului mutation pentru 0.08 Cromozom vechi 1 0 1 0 1 1 Probabilitate 0.80 0.11 0.27 0.45 0.12 0.05 Cromozom nou 1 0 1 0 1 0 Figura 2. Operatorul mutation. 15.3.4.2. Operatorul de ncruciare (crossover) 0 0.15 0 0 0.03 1

Acest operator este necesar deoarece doar cu selectia si mutatia nu s-ar putea realiza o evolutie a cromozomilor. Se poate considera ca daca se elimina acest operator, algoritmul nu mai poate fi considerat un algoritm genetic. Ideea acestui operator este recombinarea genelor a doi parinti, cu scopul obtinerii unor indivizi diferiti. Asa cum nici operatorul mutation nu poate garanta ca noul individ va fi mai valoros, fiind bazat pe numere aleatoare, nici operatorul crossover nu poate face acest lucru. Cei doi operatori realizeaza doar cadrul pentru diversitate, selectia fiind cea care va alege cei mai valorosi indivizi. Exista mai multe variante ale acestui operator. Prima, numita crossover intr-un punct alege aleator o pozitie in cromozom, pozitie care va imparti fiecare cromozom in doua sectiuni A si B. In continuare se interschimba incrucisat cele doua sectiuni din fiecare cromozom: Sectiunea A din primul impreuna cu sectiunea B din al doilea vor forma un descendent, in timp ce sectiunea B din primul si sectiunea A din al doilea vor forma al doilea descendent. Un exemplu de aplicare al acestui operator este prezentat in figura 3.

Aplicarea operatorului crossover pentru pozitia 6 Primul parinte 1 1 1 1 1 1 Al doilea parinte 0 0 0 0 0 0 Primul fiu Al doilea fiu 1 0 1 0 1 0 1 0 1 0 1 0

1 0 0 1

1 0 0 1

Figura 3. Operatorul crossover Aplicarea acestui operator poate duce la obtinerea unor descendenti total diferiti de parintii folositi, insa la fel de bine acestia pot fi identici. De exemplu, daca pe pozitiile care trebuie interschimbate cei doi parinti au aceleasi valori, nu se va intampla practic nimic. Studiile intreprinse de Holland au demonstrat ca operatorul crossover are o importanta mai mare, corespunzator va avea si o probabilitate de producere mai mare decat cea a operatorului mutation. Aceleasi studii au aratat ca se poate considera ca un cromozom contine anumite portiuni - scheme - care, daca reprezinta proprietati de valoare ar trebui pastrate de acest operator. Operatorul de selectie si cel de recombinare trebui sa asigure proliferarea schemelor mai avantajoase, in defavoarea celorlalte. Pentru a creste sansele de a obtine caracteristici noi la urmasi este indicat sa nu se permita combinarea a doi indivizi identici. 15.3.5. Corecia soluiilor Operatorii genetici pot produce cromozomi care s nu aib nici o semnificaie pentru problema de rezolvat, din cauza folosirii ntmplrii n obinerea acestor cromozomi noi. De aceea, dac aceast situaie poate apare, este necesar folosirea unor operatori de corecie, care s readuc un cromozom alterat la o form consistent. De exemplu, n cazul problemei partiionrii grafului, un cromozom poate fi reprezentat printr-un ir de cifre binare, fiecare indicnd partiia din care face parte un anumit nod. Este evident c diferena ntre numrul de zerouri i numrul de uniti trebuie s fie zero (numr par de noduri n graf) sau unu (numr impar de noduri n graf). n urma aplicrii operatorilor genetici, echilibrul acesta ntre numrul de zerouri i numrul de uniti se poate strica, aprnd partiii inegale. Acest fenomen trebuie corectat prin folosirea unui operator care s echilibreze cele dou partiii. Corecia poate fi fcut aleator, caz n care potrivirea cromozomului poate s scad, sau ntr-o manier care s in cont de problema de rezolvat, realizndu-se astfel i o optimizare, dac e posibil.

15.3.6. mbunatatirea algoritmului genetic Performantele algoritmului genetic prezentat pot fi puternic imbunatatite pe mai multe cai, ce urmeaza a fi prezentate in continuare. Prima modificare trebuie facuta in legatura cu functia de evaluare. Daca valorile intoarse de aceasta functie sunt foarte apropiate, nu se va mai putea face o separatie neta intre indivizi. Si deoarece functia de evaluare depinde de problema reala, nu se poate forta totdeauna felul rezultatelor intoarse. Pentru functia de evaluare urmtoare

f 6 ( x, y ) = 0.5

(sin x 2 + y 2 ) 2 1.0 + 0.001 * ( x 2 + y 2 ) 2

care are valori n intervalul [0,1], o usoara modificare, ce nu ii modifica mai deloc comportamentul, poate duce la degradarea drastica a proprietatilor algoritmului genetic:
f 6 = 999.5 f 6
'

Pentru a inlatura acest neajuns, este necesara folosirea unei functii de potrivire diferite de functia de evaluare, insa care sa se bazeze pe aceasta. Exista doua moduri de rezolvare acestei probleme: Prin ferestre: Se afla valoarea minima a functiei de evaluare, apoi se asigneaza fiecarui cromozom cantitatea cu care evaluarea sa depaseste valoarea minima gasita. Pentru a asigura o sansa si celui mai slab cromozom, se poate lasa un prag astfel incat nici unui cromozom sa nu i se asigneze valoarea zero. Prin normalizare liniara: Se ordoneaza cromozomii in ordinea descrescatoare a evaluarii lor. Apoi se asigneaza valori descrescatoare, pornind de la o constanta, la fiecare nou cromozom sau noua valoare scazandu-se o valoare fixa. Bineinteles, se evita acordarea valorilor negative, care sunt contraindicate la folosirea metodei ruletei pentru selectie. Valoarea initiala de la care se porneste si valoarea care se scade reprezinta parametrii acestui procedeu. Asigurand o diferentiere neta intre cromozomi diferiti, cresc sansele cromozomilor mai valorosi.

O alta modificare priveste modul de inlocuire a unei generatii cu generatia urmatoare. Prin inlocuirea completa a tuturor indivizilor se pot pierde indivizi valorosi, purtatori de scheme pretioase. Deci ar fi indicata folosirea unei tehnici elitiste, care sa pastreze de la o generatie la alta indivizii mai valorosi. Evident numarul indivizilor pastrati de la o generatie la alta constituie un parametru important. Aceasta strategie elitista poate duce rapid la aparitia unui super - individ care sa domine competitia, insa la echilibru

se constata o imbunatatire a performantelor algoritmului genetic. Insa chiar si cu aceasta strategie elitista pot exista indivizi valorosi care sa nu participe la reproducere, lucru ce poate cauza pierderea genelor lor pretioase. De asemenea, operatorii genetici pot deteriora proprietatile bune ale unor cromozomi. Solutia pentru preintampinarea acestor neajunsuri ar fi ca la reproducere sa se inlocuiasca doar un numar mic de indivizi (1 sau 2), acesta constituind dealtfel un parametru important. Un aspect important care trebuie analizat este modul in care se trateaza duplicatele, adica acei cromozomi noi care au o structura genetica deja existenta. Evident, exista doua posibilitati: se elimina duplicatele sau li se permite "supravietuirea". In a doua situatie exista riscul aparitiei unei populatii "plate", putin diverse, in care sansele de evolutie sunt mai reduse. Deci ar fi de folosit prima metoda, care asigura aparitia unor indivizi diferiti de cei care exista deja, fapt ce duce la o mai eficienta explorare a spatiului solutiilor. Aceasta explorare mai buna se face pe seama cresterii timpului afectat unui experiment, din cauza verificarilor suplimentare care se fac si care cuprind intreaga populatie (care poate fi numeroasa). Incercarea de a realiza un algoritm genetic cat mai eficient inseamna de multe ori specializarea lui, dependenta foarte stransa de problema reala pe care o rezolva. Astfel trebuie facuta o alegere: se doreste realizarea unui algoritm cat mai general, care sa fie aplicabil cat mai multor probleme, si care evident nu va fi foarte performant, sau se doreste rezolvarea cat mai eficienta a unei anumite probleme. Modificari esentiale pot aduce operatorii genetici folositi. Primul aspect asupra caruia se poate interveni este modul de alegere al operatorilor genetici. Astfel, se poate folosi binecunoscuta metoda a ruletei la selectia unui operator dintr-o lista de operatori posibili. Astfel, pentru cazul clasic al utilizarii a doi operatori (mutation si crossover) se poate atasa fiecaruia un factor de potrivire (de exemplu 80% pentru crossover si 20% pentru mutation) care va fi folosit la alegere. Insa aceasta metoda nu precizeaza care este numarul de cromozomi - copii generati, putandu-se spune ca circa 80% vor fi rezultati prin aplicarea operatorului crossover, iar ceilalti 20% prin aplicarea operatorului mutation. Adica in 4 cazuri din 5 vor rezulta cate 2 cromozomi - copii, in timp ce intr-un caz din 5 va rezulta un singur cromozom descendent. Insa principalelele modificari asupra operatorilor vizeaza modul de functionare al acestora. Astfel, prima observatie asupra operatorului crossover este aceea ca se pot alege doua puncte semnificative intre care sa se faca interschimbarea, asa cum se arata in figura 4:

Aplicarea operatorului crossover pentru pozitiile 3 si 6 Primul parinte 1 1 1 1 1 1 1 Al doilea parinte 0 0 0 0 0 0 0 Primul fiu Al doilea fiu 0 1 0 1 0 1 1 0 1 0 1 0 0 1

1 0 0 1

Figura 4. Operatorul crossover in doua puncte Desi folosirea acestui din urma tip de operator crossover duce la imbunatatirea performantelor algoritmului genetic, totusi, exista o mare sansa ca anumite scheme utile sa dispara. De aceea se poate recurge la generalizarea procedeului, adica alegerea unui numar de k puncte semnificative si interschimbarea alternativa a portiunilor din cromozomii - parinti cuprinse intre doua astfel de puncte. Insa nici aceasta generalizare nu conduce la remedierea tuturor deficientelor, solutia numindu-se crossover uniform. Acest algoritm functioneaza astfel: pentru fiecare pozitie din cei doi parinti selectati se verifica un test de probabilitate, valoarea acestuia (0 sau 1) hotarand care este parintele a carui gena va participa la formarea primului cromozom - copil. Al doilea cromozom - copil se va forma din genele parintelui care nu a trecut testul de probabilitate. Aceasta functionare este ilustrata in figura 5:
Aplicarea operatorului crossover uniform Primul parinte 1 1 1 1 1 1 Al doilea parinte 0 0 0 0 0 0 Probabilitati Primul fiu Al doilea fiu 1 1 0 0 0 1 0 0 1 1 1 0 0 0 1 0 0 1

1 0 0 0 1

1 0 1 1 0

Figura 5. Operatorul crossover uniform Prin aceasta modificare pozitia unei scheme in cadrul cromozomului nu mai are nici o importanta pentru operatorul genetic, disparand posibilitatea ca unele scheme sa fie favorizate sau impiedicate sa prolifereze. In cele discutate pana acum s-a considerat ca toti parametrii care intervin in algoritmul genetic au valori constante in timp. Daca valorile acestora se modifica in timp (au valori diferite pentru generatiile de la inceputul experimentului si pentru cel de la sfarsitul acestuia) atunci se pot influenta performantele algoritmului genetic.

Evident, va fi necesar un studiu comparativ pentru a stabili felul variatiei. Suportul teoretic al acestei variatii este dat de efectele operatorilor. Spre exemplu, operatorul crossover realizeaza "amestecarea" unor caracteristici valoroase existente in parinti, in timp ce operatorul mutation realizeaza "explorarea locala", in jurul unui singur individ. De aceea apare ca naturala acordarea unor sanse mai mari pentru crossover la inceputul experimentului, pentru a initia combinarea schemelor existente in populatia initiala (aleatoare!), in aceasta perioada operatorul mutation fiind mai putin utilizat. Corespunzator, spre sfarsitul experimentului, cand evolutia a condus spre obtinerea unor indivizi mai dotati, e de preferat explorarea in vecinatatea acestora, acordand sanse mai mari operatorului mutation, deoarece crossover ar putea strica prin combinare indivizi valorosi. Se vor specifica valorile de inceput si de sfarsit pentru probabilitatile de activare a operatorilor genetici, pasul sau numarul de generatii dupa care se vor modifica valorile acestora. In fine, o ultima modalitate de a obtine rezultate mai bune este folosirea unui operator suplimentar, heuristic. Acesta va trebui sa actioneze cunoscand problema concreta de rezolvat, aducand modificari cromozomului asupra caruia se aplica doar daca acestea ii sunt benefice cromozomului. In caz contrar, cromozomul nu va fi modificat. Datorita necesitatii verificarii fiecarui cromozom, operatie care poate consuma timp util, fara sa aduca un castig sigur, se recomanda folosirea acestui operator doar in prima parte a experimentului, cand exista mai multi indivizi cu potential neexplorat. Alegerea operatorului heuristic este puternic dependenta de problema rezolvata, putand fi folositi mai multi astfel de operatori, selectia celui care se va aplica fiind facuta printr-un mecanism de tip ruleta. Ca in cazul multor alti algoritmi, o buna ridicare a nivelului de performanta poate fi obtinut daca se opteaza pentru paralelizarea algoritmilor genetici.
15.3.7. Justificarea funcionrii algoritmilor genetici 15.3.7.1. Schema

Fundamentarea teoretic a algoritmilor paraleli se bazeaz pe noiunea de schem. O schem este un ir construit cu simbolurile 0, 1 i * (don't care). Schema permite studierea similitudinilor ntre cromozomi. Schema are urmtoarele caracterristici: o schem reprezint toate irurile care coincid cu ea n poziiile diferite de * o schem cu r simboluri * are drept corespondente 2r iruri un ir de lungime m poate fi pus n coresponden cu 2m scheme exist 3m scheme posibile de lungime m

intr-o populaie de dimensiune n pot fi reprezentate ntre 2m i n2m scheme.


15.3.7.2. Proprietile schemelor

Ordinul unei scheme S, notat o(S) este numrul de poziii fixe (0 sau 1) ale schemei. De el depinde probabilitatea de supravieuire a schemei la mutaii. Exemplu: schema S1 = (010***11***1) are o(S1) = 6. Lungimea caracteristic a unei scheme S, notat (S), este distana ntre prima i ultima poziie fix a schemei. De ea depinde probabilitatea de supravieuire a schemei la ncruciri. Exemplu: (S1) = 11.

15.3.7.3.

Evoluia

Studiem evoluia schemelor n operaiile de selecie, ncruciare i mutaie. Selecia Fie pop_size dimensiunea populaiei, m lungimea unui ir i p = (S,t) numrul de iruri din populaia la momentul t avnd schema S. Ne intereseaz (S,t+1). Pentru aceasta considerm potrivirea schemei S la momentul t, eval(S,t) definit ca media potrivirilor irurilor din populaia reprezentat de S. Fie p=(S,t) numrul acestora. p eval (v ) ij Atunci: eval ( S , t ) = . Dac la o selecie irul vi are probabilitatea p j =1

pi =

eval (vi ) de a fi selectat, unde F (t ) = F (t )

pop size i =1

eval (v ) este potrivirea total, atunci:


i

Un ir care corespunde schemei S are probabilitatea de selecie egal cu eval ( S , t ) . F (t )


Numrul de iruri care corespund schemei S este (S,t). Numrul de selecii este pop_size.

Rezult:

( S , t + 1) = ( S , t ) * pop _ size *
eval ( S , t )

eval ( S , t ) , F (t )

adic

( S , t + 1) = ( S , t ) *

(ecuaia 1). n ecuaia 1, numit ecuaia creterii F (t ) este protrivirea medie a populaiei. O pop _ size

F (t )

schemei reproductive, F (t ) =

schem "peste medie" are

eval ( S , t )

> 1 i primete un numr mai mare de indivizi n


____

F (t )

noua populaie. Deci, dac eval ( S , t ) = F (t )(1 + ) avem ( S , t + 1) = ( S , t ) * (1 + ) sau ( S , t ) = ( S ,0) * (1 + ) t , adic numrul de indivizi este n cretere conform unei progresii geometrice. ncruciarea
Fie irul (1110111101001) i dou scheme care-i corespund: S0=(****111******), ( S0)=2 S1=(111********01), ( S1)=12 Dac irul este selectat pentru ncruciare i poziia de tiere este 10, schema S0 se regsete ntr-unul din fii, n timp ce schema S1 are anse foarte reduse de reproducere. Este clar c lungimea caracteristic joac un rol important n reproductibilitatea schemei la ncruciare. Avem urmtoarele: Locul de ncruciare este selectat uniform ntre m-1 posibiliti; rezult c (S ) probabilitatea de distrugere a schemei S este p d ( S ) = iar probabilitatea de m 1 (S ) supravieuire p s ( S ) = 1 . Considernd i probabilitatea pc de selecie pentru m 1 (S ) ncruciare, avem de fapt p s ( S ) = 1 p c * . Deoarece se pot combina indivizi m 1 aparinnd unor scheme comune formula trebuie modificat astfel: (S ) . p s ( S ) 1 pc * m 1

Efectul combinat al seleciei i ncrucirii este reprezentat de urmtoarea form a ecuaiei de cretere a schemelor reproductibile: (S ) eval ( S , t ) ( S , t + 1) ( S , t ) * * (1 p c * ) (ecuaia 2). m 1 F (t )
Mutaia

Mutaia afecteaz o schem S dac modific una din poziiile sale fixe, n numt de o(S). Deoarece probabilitatea mutaiei unui singur bit este pm, probabilitatea

nemodificrii sale este (1- pm). Mutaia unui bit fiind independent de celelalte, probabilitate ca o schem S s supravieuiasc unei mutaii este p s ( S ) = (1 p m ) o ( S ) ; deoarece pm<<1 rezult p s ( S ) 1 p m * o( S ) . Efectul combinat al seleciei, ncrucirii i mutaiei este dat de ecuaia 3:

( S , t + 1) ( S , t ) *
(ecuaia 3)

eval ( S , t )

F (t )

* (1 p c *

(S )
m 1

p m * o( S ))

care corespunde urmtorului enun


Teorema schemei. Schemele scurte, de ordin sczut i peste medie cresc exponenial de-a lungul generaiilor unui algoritm genetic.

Consecina imediat este c un algoritm genetic exploreaz spaiul soluiilor prin scheme scurte, de ordin sczut, care ulterior sunt folosite pentru schimb de informaii prin ncruciare.
Ipoteza blocurilor constructive. Un algoritm genetic atinge performae aproape optime prin juxtapunerea unor scheme scurte, de ordin sczut, de mare performa, numite blocuri constructive.

Pentru anumite probleme ipoteza este violat. De exemplu, schemele S1=(111********) S2=(*********11) sunt peste medie, dar combinaia lor S3=(111******11) este mai puin potrivit ca S4=(000******00) Un algoritm genetic poate avea dificulti s convearg spre un optim ca S0=(11111111111) i poate cdea pe soluii suboptime care se potrivesc cu S4. Fenomenul se numete falsificare (deception).
15.3.8. Considerarea constrngerilor n algoritmii genetici

n unele situaii, aplicarea operatorilor genetici conduce la obinerea unor indivizi care nu corespund soluiilor poteniale ale problemei de rezolvat. De exemplu, n cazul problemei partiionrii grafurilor, indivizii pentru care diferena dintre numrul de

zerouri i numrul de uniti este mai mare de unu nu corespund unei soluii corecte, deoarece problema cere mprirea nodurilor n dou grupuri de dimensiuni egale. Tratarea acestor situaii, n care indivizii nu respect constrngerile impuse de problem, se poate face prin urmtoarele metode: transformarea problemei ntr-una fr constrngeri, prin aplicarea unor penalizri indivizilor care nu respect constrngerile impuse de problem eliminarea soluiilor necorespunztoare aplicarea unor algoritmi de corecie.

S considerm problema rucsacului. Enunul problemei este urmtorul: date fiind o mulime de ponderi W, profiturile asociate P i capacitatea C a rucsacului, se cere s se gseasc un vector binar X = <x1, x2, ..., xn> astfel c i = 1,n xi * wi <= C i P(X) = i = 1,n xi * pi este maxim. 15.3.8.1.
Algoritm bazat pe penalizri

n acest caz, funcia de evaluare a unei soluii are forma eval(X) = i = 1,n xi * pi - Pen(X) unde Pen(X) = 0 pentru soluiile fezabile i Pen(X) 0 pentru soluiile nefezabile. Pentru funcia de penalizare se poate alege una din urmtoarele variante: logaritmic, Pen1(X) = log2 (1 + ( i = 1,n xi * wi - C)) liniar, ptratic, Pen2(X) = ( i = 1,n xi * wi - C) Pen3(X) = [ ( i = 1,n xi * wi - C)]2

unde = MAX i = 1,n { pi / wi} Algoritmul bazat pe corecia soluiei folosete pentru evaluare formula eval(X) = i = 1,n x'i * pi unde X este versiunea corectat a lui X.
procedure corectie (X) begin depasire := false X := X

if i = 1,n xi * wi > C -> depasire := true fi do depasire -> i := selecteaza un element din sac scoate elementul xi := 0 if i = 1,n xi * wi <= C -> depasire := false fi od end

Variantele de corecie sunt incluse n selecteaza. Putem avea o alegere aleatoare sau un algoritm greedy, n care elementele sunt sortate n ordinea descresctoare a rapoartelor pi / wi i se alege ntotdeauna ultimul element. S-a constatat experimental c nlocuirea cromozomilor originali cu cromozomi reparai ntr-o proporie de 5% conduce la performane mai bune dect pentru orice alt proporie (regula 5%). 15.3.8.2.
Algoritmul bazat pe decodificatori

Acest algoritm adopt o reprezentare pentru care orice combinaie rezultat n urma operaiilor genetice reprezint o soluie valid. Un cromozom este interpretat ca o strategie de a incorpora elemente ntr-o soluie. Fiecare cromozom este un vector de n ntregi. Componenta i a vectorului este un ntreg din domeniul 1..n-i+1 i indic poziia unui element al unei liste L, din care elementele selectate sunt eliminate pe msura seleciei. De exemplu, fie L = (1,2,3,4,5,6). Vectorul <4,3,4,1,1,1> este decodificat ca secvena 4, 3, 6 (deoarece 6 este al 4-lea element dup eliminarea lui 4 i a lui 3), 1, 2, 5. Ca efect, la mutaie, gena i poate lua orice valoare ntre 1 i n-i+1, iar ncruciarea aplicat unor prini coreci produce mereu descendeni coreci. Algoritmul de decodificare este urmtorul:
procedure decode (X) begin construieste o lista de elemente L i := 1 suma-ponderi := 0 suma-profit := 0 do i <= n -> j := xi

elimina elementul cu numarul de ordine j din L if suma-ponderi + wj <= C -> suma-ponderi := suma-ponderi + wj suma-profit := suma-profit + pj fi i := i+1
od end

Variantele pentru construieste sunt: aleatoare, cnd ordinea elementelor din list corespunde ordinii elementelor din fiierul de intrare (care este aleatoare)
greedy, cnd procedura creeaz o list L punnd elementele n ordinea descresctoare a rapoartelor pi / wi; decodificarea lui X se face pe baza secvenei sortate.

15.4. Algoritmi genetici paraleli

Doua au fost conditiile care au favorizat aparitia acetui tip de algoritmi: pe de o parte necesitatea de a putea rezolva cat mai rapid probleme foarte complexe (in care sa intervina populatii formate dintr-un numar mare de indivizi), iar pe de alta parte aparitia unor calculatoare paralele relativ ieftine si deci accesibile. Un algoritm genetic paralel poate fi obtinut dintr-unul secvential folosind mai multe cai de transformare, insa indiferent de metoda aleasa apar o serie de aspecte noi legate in special de necesitatea comunicarii intre diversele entitati care evolueaza in paralel; este foarte important ca aceasta comunicare sa nu consume mult timp si sa nu apara puncte de gatuire care sa determine cresterea suplimentara a timpului de executie. Indeplinirea acestor conditii va duce la realizarea unei implementari optime si la posibilitatea realizarii unor experimente deosebit de flexibile si in timp scurt. Sa presupunem ca pe o masina paralela exista P procesoare disponibile. Prima idee ar fi paralelizarea operatiilor efectuate in cadrul rularii unui experiment. Daca admitem ca un procesor este necesar pentru a controla paralelismul celorlalte, inseamna ca raman P - 1 procesoare care pot alege in paralel P - 1 perechi de parinti pentru a le aplica tot in paralel (acelasi) operator crossover, iar apoi, dupa aplicarea (evident tot in paralel) a operatorului mutation se vor putea evalua in paralel cromozomii - copii rezultati. In acest fel durata in care o generatie este procesata se va reduce considerabil daca se foloseste un numar mare de procesoare. Factorii care ar putea

degrada performantele unui astfel de algoritm sunt posibilul overhead introdus de comunicatie si mecanismul de selectie folosit (exista o singura populatie la care fac acces cele P - 1 procesoare, deci un posibil punct de gatuire!). O varianta ar putea fi cea in care procesorul coordonator (cel care de fapt supervizeaza intreaga populatie) realizeaza selectia si trimite candidatii spre celelalte procesoare, care dupa aplicarea operatorilor trimit inapoi spre "centru" noii indivizi si eventual alte informatii. Aceasta abordare are mai putin sprijin teoretic, deoarece in viata reala o astfel de populatie izolata nu ofera mari sanse de evolutie. De aceea este natural sa se opteze spre utilizarea unei populatii distribuite. Aceasta poate fi realizata fie prin existenta unei unice populatii in care fiecare individ interactioneaza doar cu cativa dintre vecinii sai, sau prin crearea mai multor subpopulatii (independente una fata de alta sau care pot interactiona intre ele). Procesoarele pot schimba intre ele cele mai bune solutii obtinute, comunicatia avand la baza o structura topologica spatiala. Pe baza acesteia se poate vorbi de granularitatea algoritmului genetic paralel. O granularitate mare corespunde unei "lumi" formate din mai multe subpopulatii similare, asupra carora se aplica in paralel acelasi algoritm genetic. La anumite momente de timp unii indivizi vor putea trece de la o subpopulatie la alta, rostul acestor migratori fiind acela al cresterii gradului de diversitate. In functie de numarul de migratori si de populatiile spre care migreaza se pot obtine diferite variante de algoritmi. De asemea este importanta si frecventa cu care migratorii se pun in miscare si modul in care ei sunt selectati. Este recomandat ca numarul si frecventa acestor migratori sa nu fie mari pentru ca fiecare subpopulatie sa exploreze alta portiune din spatiul solutiilor (se presupune ca populatiile initiale sunt distincte iar un schimb exagerat de informatie genetica intre ele le-ar apropia foarte mult, scazand capacitatile algoritmului). Cea mai folosita topoplogie este cea de inel, insa se pot utiliza si altele (de exemplu tor). Un algoritm de granularitate fina presupune ca in fiecare procesor se pastreaza un individ; acesta va putea interactiona cu cei din vecinatatea sa pentru recombinari. Aspectele importante in acest caz vor dimensiunea vecinatatii, topologia deconectarea a procesoarelor, procedeul folosit pentru inlocuirea generatiei curente. Spre exemplu pentru o topologie de tip tor bidimensional, cel mai valoros dintre cei 4 vecini ai elementului curent va fi ales pentru recombinare; daca elementul obtinut va fi mai bun il va inlocui pe cel curent. Ca un rezumat al celor afirmate pana acum, iata o posibila clasificare a metodelor ce pot fi utilizate la rezolvarea unor probleme de cautare si optimizare folosind algoritmi genetici paraleli: varianta de procesare independenta si identica (Identical, Independent Processing - IIP) in care acelasi algoritm genetic se executa pe procesoare

diferite, pornind de la populatii initiale diferite si fara nici o interactiune intre populatii; cel mai bun rezultat obtinut in toate experimentele fiind considerat solutia problemei; varianta Master-Slave in care procesul Master dirijeaza evolutia algoritmului, in timp ce procesele Slave executa doar calculele de evaluare a fiecarui individ; varianta Parallel Genetic Algorithm, in care se ruleaza acelasi algoritm genetic pe sub-populatii diferite, aseamanator cu IIP, cu deosebirea ca anumiti indivizi (cei mai buni) migreaza cu o anumita frecventa de la populatia in care au aparut spre alte populatii; varianta celulara, fiecare procesor se ocupa de un singur individ: operatorul mutation va fi strict local, in timp ce crossover va implica o colaborare intre doua procesoare vecine; migrarea poate fi introdusa ca o modalitate de a accelera difuzarea indivizilor mai performanti.

In timp ce primele trei variante se preteaza arhitecturilor MIMD, ultima e caracteristica masinilor SIMD, in care fiecare procesor executa la un moment dat aceeasi operatie asupra datelor existente in memorie. Dintre acestea, varianta a treia, numita Parallel Genetic Algorithm, pare a oferi mai multa flexibilitate. Astfel caracteristicile globale ale populatiior nu trebuie sa fie aceleasi: numarul de indivizi din fiecare populatie poate fi altul si poate varia in timp; metoda de selectie a parintilor poate fi diferita si se poate modifica pe parcursul evolutiei; probabilitatile de activare a operatorilor genetici pot fi diferite si variabile in timp, se pot folosi operatori genetici diferiti pentru fiecare populatie; varianta de inlocuire a unei generatii cu una noua poate fi specifica unei populatii; modul de selectie al migratorilor poate fi altul de la o populatie la alta (se poate alege cel mai bun cromozom, cel mai slab, unul la intamplare, etc.). La modul general adaptarea acestor parametri poate fi facuta la diferite nivele: individ, subpopulatie, populatie. De asemenea poate fi luat un exemplu des intalnit in lumea vie, acela al unor grupuri de indivizi care concureaza (lupta) pentru obtinerea acelorasi resurse vitale. In acest caz este evident ca nu se va mai face schimb de migratori, fiecare populatie luptand pentru sine, cautand sa gaseasca strategia optima de adaptare. Aceasta presupune ca dupa aparitia unei noi generatii intreaga subpopulatie va fi evaluata (ca un intreg), fiind favorizata in cazul in care este mai valoroasa decat cea pe care o va inlocui. Astfel, o populatie de dimensiune fixa poate fi impartita in grupuri de dimensiuni variabile, care trebuie sa simuleze lupta unor specii similare pentru hrana. Va fi nevoie de un criteriu de selectie bazat pe cel mai un individ din grup (sau pe cei mai buni indivizi din ultimele k generatii). Pe baza lui va

functiona criteriul calitate, care va determina cresterea dimensiunii grupului cu cea mai buna strategie si reducerea numarului membrilor celorlalte grupuri. Alti algoritmi genetici care pot fi utilizati de populatiile implicate sunt urmatorii: CHC: Caracteristica acestuia este modul in care se formeaza generatia noua, la aceasta participand atat generatia curenta (curenta cu o parte din indivizi), cat si generatia intermediara de indivizi noi, care completeaza noua generatie. Partile de participare sunt stabilite de regula la 50%, luandu-se de regula indivizii cei mai buni. Alegerea parintilor pentru reproducere se face cu evitarea incestului, pe baza distantei Hamming.
Genitor: Se bazeaza pe mentinerea unei populatii sortate. Exista insa si posibilitatea de a renunta la sortarea populatiei, fapt care ar aduce substantial un castig de timp: in urma unei selectii de tip turneu se aleg doi parinti care vor da nastere unui urmas; acesta va inlocui ultimul individ (cel mai slab) al populatiei.

Primul pas consta in realizarea unei treceri de la problema reala de optimizat la reprezentarea folosita de regula de un algoritm genetic. Adica va trebui de fapt sa gasim o codificare a solutiei pe care o cautam (cum va arata un cromozom). Varianta de operator de ncruciare cea mai convenabil este crossover uniform, in care pentru obtinerea copiilor se genereaza aleator o masca binara, de lungime egala cu dimensiunea cromozomilor. Fiecare parinte va copia in succesorul corespunzator pozitiile cu zero in masca binara si va completa celelalte pozitii cu valoarea de pe aceeasi pozitie din celalalt parinte. Operatorul crossover are asociata o probabilitate de activare pc. Daca testul de probabilitate este trecut se activeaza operatorul, care pe baza unei masti binare generate aleator va construi noii cromozomi. Dupa construire acesti cromozomi vor fi corectati daca este cazul. Daca testul de probabilitate nu a fost trecut, atunci cromozomii - copii se vor obtine prin simpla copiere a cromozomilor parinti.

Parinte 1 Parinte 2 Masca aleatoare Copil 1 Copil 2 Copil 1 dupa corectie Copil 2 dupa corectie

1 0 0 1 0 1 1

0 0

0 1

1 1

1 0 0 1 0 1 0

1 1

0 1

0 0 0 0 0 0 0

1
0 0 0 0

1
1 0

1
1 1

1
1 1 1 1

1
1 0 1 0

0 1

0 1

Figura 6. Operatorul crossover Operatorul mutation mai des folosit schimba genele unui cromozom dintr-un interval generat aleator. Daca un test de probabilitate (cu o valoare pm) este trecut, gena corespunzatoare din intervalul ales este modificat.
Interval Parinte Probabilitati generate (0.32 = limita) Copil dupa mutation Copil dupa corectie

1 .3

1 .5 1 1

0 .7 0 1

1 .1

0 1

0 0

0 0

0 0

1 1

0 0

Figura 7. Operatorul mutation


15.5. Programe evolutive

Un program evolutiv este un algoritm iterativ probabilist care menine o populaie de indivizi, notat P(t) = {x1t, x2t, ..., xnt } pentru iteraia t. Fiecare individ reprezint o soluie potenial a unei probleme de rezolvat, fiind reprezentat ca o structur de date S, orict de complex. Structura unui program evolutiv este urmtoarea:
procedure program-evolutiv begin t := 0

initializeaza P(t) evalueaz P(t) do not coditie-de-terminare -> t := t+1 selecteaza P(t) din P(t-1) modifica P(t) evalueaza P(t) od end Evaluarea lui P(t) nseamn evaluarea fiecrei soluii xit obinndu-se o msur a potrivirii sale. n pasul de selecie, cei mai valoroi indivizi formeaz o nou populaie. Prin aplicarea operatorilor genetici, acestei populaii i sunt adugai noi indivizi. Operatorii genetici sunt: unari, de tip mutaie n-ari, de tip ncruciare.

Dup un numr de generaii, programul converge. Cei mai buni indivizi reprezint soluiile apropiate de optim. Ideea programelor evolutive se bazeaz pe cea a algoritmilor genetici, dar: folosete un set mai bogat de structuri de date (n timp ce AG clasici folosesc iruri binare de lungime fix) folosete un set extins de operatori genetici (n timp ce AG folosesc mutaia binar i ncruciarea binar).

Un algoritm genetic clasic cere aducerea problemei la o form potrivit prin gsirea unor corespondene ntre soluiile potaniale i reprezentrile binare, aplicarea coreciilor necesare pentru respectarea constrngerilor problemi etc.
Problem Algoritm genetic

Problem modificat

Figura 8. Algoritm genetic Un program evolutiv las problema nemodificat, dar adapteaz operatorii genetici la reprezentrile cele mai potrivite ale soluiilor.

Problema

Algoritm genetic - AG

Program evolutiv

Figura 9. Program evolutiv


Un avantaj al algoritmilor genetici este independenta de domeniul specific problemei. Totusi, atunci cand intervin constrangeri complicatre, functiile de decodificare si de corectie a sirurilor de biti transforma algoritmul genetic intr-o metoda dependenta de problema. Pe de alta parte, programele evolutive ar putea deveni independente de problema daca s-ar crea structuri de date cat mai diverse si functii de evaluare corespunzatoare. Rezolvarea unei probleme s-ar transforma in cautarea structurilor potrivite problemei si aplicarea lor.

15.5.1. Un exemplu - Problema transportului 15.5.1.1. Enuntul problemei Se cere sa se stabileasca un plan de transport cu cost minim pentru un singur gen de marfa, de la un numar de surse la un numar de destinatari, in urmatoarele conditii: o destinatie poate primi marfa de la mai multe surse costul unei rute este proportional cu cantitatea transportata (problema este lineara).
Fie: n surse k destinatari sour[i] cantitatea furnizata de sursa i dest[j] cantitatea ceruta de destinatia j cost[i,j] costul unitar de transport intre I si j x[i,j] cantitatea transportata intre i si j Se cere sa se minimizeze cost[i,j]*x[i,j] pentru i=1,n; j=1,k cu constrangerile j=1,k x[i,j] <= sour[i] i=1,n x[i,j] >= dest[j] x[i][j] >= 0 pentru i=1,n; j=1,k

Problema este balansata atunci cand totalul furnizat de surse egaleaza totalul cerut de destinatari: cantitatea ceruta = cantitatea furnizata Cand sour[i] si dest[j] sunt intregi avem x[i,j] intregi si cel mult n+k-1 sunt pozitivi.

Exemplu n = 3; sour = [15,25,5] k = 4; dest = [5,15,15,10]

Matricea de cost este urmatoarea: 10 12 0 0 7 14 20 9 16 11 20 18

Matricea X corespunzatoare planului optim de transport este urmatoarea (in reprezentare au fost adaugate: o coloana corespunzatoare vectorului sour si o linie corespunzatoare vectorului dest) sour \ dest 15 25 5 5 0 0 5 15 5 10 0 15 0 15 0 10 10 0 0

Solutia are un cost total egal cu 315.

15.5.1.2.

AG clasic

Fiecare solutie reprezentata ca un sir agregat de biti v1,v2,,vp unde p = n*k si vi sir binar de forma vi = wi0,,wis vi reprezinta un element x[j,m] asociat cu linia j coloana m ale matricei X, unde indecsii j si m sunt legati de pozitia i prin urmatoarele relatii (rezultate din procedeul de liniarizare a matricei X): j = inf [(i-1)/k+1] m = (i-1) mod k +1 iar s este ales ca sa se poata reprezenta intregul maxim din problema. Consecinta acestei solutii este ca nu exista o definitie simpla si naturala a operatorilor genetici, producerea unor solutii care sa satisfaca constrangerile necesitand corectii complicate. De exemplu, mutatia inseamna modificarea unui singur bit al unei singure valori vi; ea atrage dupa sine alte modificari asupra valorilor vj (ji) cerute de respectarea constrangerilor problemei. Toate modificarile trebuie "judecate" pe liniile si coloanele matricei X desi in rezolvare se foloseste o reprezentare lineara in forma sirului agregat de biti v1,v2,,vp.

15.5.1.3.

Reprezentare vectoriala

O solutie a problemei este reprezentata ca un vector (sir) de p=n*k numere intregi cu valori in domeniul 1..p. Ea este interpretata ca o strategie de a incorpora elemente n soluie, conform abordarii bazate pe codificatori. De data aceasta, fiecare numar indica o pozitie in matricea X considerand o linearizare pe linii, iar intregul vectorul arata ordinea in care trebuie completate elementele acestei matrice. De exemplu, operatia corespunzatoare primei pozitii a vectorului {7,....}este modificarea elementului din linia 2 coloana 3 a matricei X cu valoarea minima dintre sour[2] si dest[3], adica 15 urmata de diminuarea cu aceeasi valoare a elementelor sour[2] si dest[3]. 15 25 (-15=10) 5 5 0 0 0 15 0 0 0 15 (-15=0) 0 15 0 10 0 0 0

Procedura de decodificare a unei solutii vecrotiale este urmatoarea:

procedure initialization; begin seteaza ca nevizitate numerele de la 1 la p; do not toate nodurile vizitate -> select urmatorul numar q si marcheaza vizitat; {calc nr linie i si coloana j corespunzatoare} i = (q-1)/k+1; j=(q-1) mod k +1; val = min(sour[i], dest[j]); v[i][j] = val; sour[i] = sour[i]-val; dest[j] = dest[j] val od end
Solutia optima pentru problema de transport specificata anterior este produsa de secventa {7,9,4,2,6, *,*,*,*,*,*,*}.

15 25 5

5 0 0 5

15 5 10 0

15 0 15 0

10 10 0 0

Observatii orice permutare de numere cu valori intre 1 si p produce o solutie unica ce satisface constrangerile; operatorii genetici sunt simplu de realizat, dupa cum urmeaza. Mutatia se face prin interschimbarea a doua numere din sir. Pentru Incrucisare, se ia un subsir de numere (cele subliniate in exemplul de mai jos) din primul cromozom pastrandu-se pozitia lor, iar restul numerelor se pun in celelalte pozitii, in ordinea din al doilea cromozom. De exemplu, pentru perechea {1,2,3,4,5,6,7,8,9,10,11,12} {7,3,1,11,4,12,5,2,10,9,6,8} rezulta prin incrucisare {3,1,11, 4,5,6,7,12,2,10,9,8} Evaluarea Dintr-o reprezentare vectoriala (permutare) se obtine usor matricea x[i][j] corespunzatoare (conform procedurii initialization). Apoi, din matricea x[i][j] se calculeaza simplu costul total, dupa formula:
cost[i,j]*x[i,j] pentru i=1,n; j=1,k

15.5.1.4.

Reprezentarea matriceala

O alta varianta este de a reprezenta o solutie chiar in forma originala a problemei, ca matricea X = (x[i][j])i=1,k; j=1,n Satisfacerea restrictiilor problemei si evaluarea se realizeaza foarte simplu. Pentru operatorii genetici sunt posibile urmatoarele variante.

Mutatia Pentru matricea X urmatoare (corespunzatoare unei probleme cu 4 surse si 5 destinatii) in care nu au mai fost reprezentati vectorii sour si dest,

0 0 0 3

0 4 0 1

5 0 5 0

0 0 7 0

3 0 0 2

se selecteaza o submatrice W care corespunde unui anumit subset de linii si unui anumit subset de coloane (de exemplu, liniile 2,4 si coloanele 2,3,5); 4 0 0 1 0 2 se calculeaza W' astfel incat sumele pe linii si coloane sa ramana aceleasi cu sumele corespunzatoare din W; 2 3 0 0 2 0

se inlocuieste W cu W' in X si se obtine o noua matrice: 0 0 0 3 0 2 0 3 5 0 5 0 0 0 7 0 3 2 0 0

Incrucisarea Fie X1 si X2 doua matrice selectate ca parinti. X1


1 0 2 0 0 4 1 0 0 4 0 1 0 0 4 6 5 0 5 0 7 0 0 0 0 0 7 0 0 0 5 0 3 0 0 2

X2
0 0 0 3

Algoritmul de incrucisare are urmatorii pasi.

Se creeaza matricile DIV si REM astfel incat: DIV[i,j] = inf ((X1[i,j] + X2[i,l])/2) REM[i,j] = (X1[i,j] + X2[i,j]) mod 2.

DIV (media)
0 0 1 1 0 4 0 0 2 0 4 3 3 0 3 0 1 0 2 1

REM (restul)
1 0 0 1 0 0 1 1 1 0 1 0 1 0 1 0 1 0 1 0

Se deriveaza din REM doua matrice REM1 si REM2 astfel incat

REM = REM1 + REM2 si


sour REM1[i] = sour REM2[i] = sour REM[i]/2, pentru i = 1..k dest REM1[j] = dest REM2[j] = dest REM[j]/2, pentru j = 1..n

REM1
0 0 0 1 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0

REM2
1 0 0 0 0 0 0 1 0 0 1 0 1 0 0 0 0 0 1 0

Calculeaza cei doi fii V3 si V4 astfel ca:

V3 = DIV + REM1
0 0 1 2 0 4 1 0 3 0 4 3 3 0 4 0 2 0 2 1

V4 = DIV+REM2
1 0 1 1 0 4 0 1 2 0 5 3 4 0 3 0 1 0 3 1

15.6. Alta probleme de optimizare - Dilema prizonierului 15.6.1. Subiectul problemei


Problema cunoscuta sub numele de dilema prizonierului are urmatorul enunt. Doi prizonieri sunt tinuti in celule separate, fara posibilitatea de comunicare. Fiecare prizonier trebuie sa intreprinda una din urmatoarele actiuni, indepedent de celalalt: cooperare sau evadare. Daca doar un prizonier evadeaza, atunci este recompensat, iar celalalt este pedepsit. Daca nici unul nu evadeaza, atunci amandoi sunt rasplatiti foarte modest. Daca amandoi evadeaza, atunci ei sunt pedepsiti. Dilema prizonierului este de a decide sa coopereze sau sa evadeze. Dilema prizonierului se poate juca in doi, fiecare jucator fiind un prizonier si trebuind sa ia o decizie. Scorul jocului poate fi dat de urmatorul punctaj, in functie de deciziile celor doi:

Jucatorul 1 Jucatorul 2 P1 P2 1 1 Evadeaza Evadeaza 0 5 Coopereaza Evadeaza 5 0 Coopereaza Evadeaza 3 3 Coopereaza Coopereaza Algoritmii genetici pot fi folositi pentru a problema a prizonierului.

Comentariu pedeapsa pentru evadare simultana rasplata evadarii / pedeapsa cooperarii pedeapsa cooperarii / rasplata evadarii rasplata cooperarii invata strategii de joc pentru aceasta

15.6.2. Proiectarea algoritmului


Pentru reprezentarea cromozomilor se considera ca decizia curenta se face dupa trei mutari anterioare. Deoarece sunt patru alternative pentru fiecare mutare, sunt in total 43 = 64 cazuri posibile pentru cele trei mutari. Reprezentarea lor se poate face cu un numar de 6 biti (26 = 64). Pentru fiecare caz (fiecare istorie de trei mutari anterioare) sunt posibile doua mutari (Evadare sau Cooperare) care pot fi reprezentate ca valori binare. Daca un bit are valoarea 0, inseamna ca decizia jucatorului este de a Evada; pentru valoarea 1, decizia este de a Coopera. Rezulta 64 de biti pentru reprezentarea tuturor mutarilor curente posibile, in functie de cele trei mutari anterioare. In total, un cromozom are 70 = 6+64 biti si reprezinta o strategie de efectuare a mutarii curente in functie de trei mutari anterioare. Un algoritm genetic are nevoie de o functie de evaluare pentru a selecta indivizii cei mai buni ai unei populatii. In cazul dilemei prizonierului, toti indivizii sunt pusi sa faca un numar de jocuri si se calculeaza o medie, impartind punctajul total obtinut la numarul de jocuri. Functia de evaluare a unui cromozom intoarce aceasta medie. Se considera ca un individ este mai bun decat altul daca are o medie mai mare, adica deciziile sale au fost mai bune. Pasii algoritmului genetic sunt urmatorii: Se considera o populatie initiala, in care fiecare jucator este reprezentat de un sir de 70 de biti generati aleator.

Se evalueaza strategia fiecarui jucator, prin calculul scorului mediu obtinut intrun numar de jocuri stabilit Se face selectia jucatorilor pentru inmultire. Pentru asta, jucatorului cu un scor mijlociu i se acorda dreptul la o imperechere, celui cu scor superior dreptul la doua imperecheri, iar celui cu scor inferior nici un drept Se face imperecherea jucatorilor selectati aplicandu-se operatiile de incrucisare si mutatie. In final, se obtine o noua populatie si se reia ciclul

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