Documente Academic
Documente Profesional
Documente Cultură
Combine PDF
Combine PDF
distribuiți
1. Introducere
Cristian Mihăescu
cristian.mihaescu@edu.ucv.ro
Cuprins
• Aspecte fundamentale
• Introducere în calculul parallel si sistemele distribuite
• Platforme pentru calculul paralel
• Principii de proiectare ale algoritmilor paraleli
• Modelarea programelor paralele
• Programarea cu ajutorul trimiterii de mesaje
• Programarea cu ajutorul memoriei partajate
• Algoritmi paraleli/distribuiți
• Sortări, Căutări
• Algoritmi pe matrici dense
• Algoritmi pe grafuri, Programare dinamică
• Algoritmul *bakery*, problema generalilor bizantini, map-reduce
Motivația
• Paralelismul/distributivitatea reprezintă un pas înainte in ceea ce priveste
programarea calculatoarelor:
• Trecere de la gândirea algoritmică secvențială (en. Algorithmic thinking) la
gândirea paralelă (en. Parallel thinking).
• Multe calculatoare actuale au deja chip-uri multicore
• Utilizarea adecvată a calculatoarelor paralele este utilă în inginerie, știință,
afaceri, etc.
• Provocare intelectuală mare în zona CS: modele, limbaje de programare,
algoritmi, HW
• Multe probleme practice au solutii algoritmice paralelizabile. Acest fapt
permite accelerarea!
• Exemple: Prognoza vremii, mișcarea astrelor, genetică.
Domenii de aplicație care necesită APD
• Sănătate
• Inginerie
• Cercetare spațială
• Planificare urbană
• Finanțe și afaceri: Bitcoin
https://builtin.com/hardware/high-performance-computing-applications
Mae Rice, November 4, 2019, Updated: April 6, 2020
Tipuri de sisteme
• Calculatoare personale
• Nu sunt distribuite dar in prezent sunt multiprocesor
• Sisteme embedded
• Rulează pe un singur procesor sau pe un grup integrat de procesoare
• Sisteme distribuite
• Aplicația rulează pe un gup de sisteme cuplate/integrate slab (en., loosely
coupled/integrated) care cooperează cu ajutorul unei rețele.
Multicore
chip
Facts: 55th Anniversary of Moore's Law
https://www.infoq.com/news/2020/04/Moores-law-55
/
Moore’s
Law
https://en.wikipedia.org/wiki/Transistor_count
Elementele calculului paralel
• Hardware
• Mai multe procesoare
• Mai multe memorii
• Retea de interconectare de mare viteză
• Sistem de operare
• Sistem de operare care permite calcul paralel
• Elemente de programare care permit exprimarea/orchestrarea concurenței
• Aplicații software
• Biblioteci/sisteme care permit paralelizare/distribuție
SCOP: Utilizarea Hardware, Sistem de operare si Aplicațiilor software pentru:
1) obținerea accelerării (en., speedup)
2) rezolvarea de probleme care necesită o cantitate mare de memorie
Platforma de calcul paralel
• Organizarea logică
• Modul în care utilizatorul vede mașina prin intermediul sistemului de operare
• Organizarea fizică
• Arhitectura fizică a sistemului
Parallel Computing Laboratory at UC Berkeley: “Writing programs that scale with increasing numbers of
cores should be as easy as writing programs for sequential computers”
https://www.appentra.com/parallware-method-assisted-parallelism-discover-parallel-patterns/
Dificultăți în procesarea paralelă
• Depanarea (en., debugging)
• Dificultatea apare din cauza greutății cu care putem replica situatia apărută.
Refacerea/simularea contextului în care a aparut o eroare este în multe situații o
operatie dificil de realizat. Acest lucru se datorează intrețeserii (en., interleaving).
• Corectitudinea
• Demonstrarea corectitudinii unui algoritm paralel este o provocare.
• Incorectitudinea poate conduce la *undefined behaviour* iar depanarea este de
obicei dificilă.
• Benchmark
• Evaluarea performațelor (i.e., accelerarea) prin rulari/simulari este aspectul
principal. La programarea secventuală (mai ales pe input-uri mici) acest aspect este
de multe ori (incorect!) ignorat.
Dificultăți în procesarea paralelă (cont.)
• Comunicarea între procesoare
• Dificultatea abordarii paralele a algoritmului/procesării și ulterior dezvoltarea,
testarea si implementarea soluției.
• Dintre soluții:
• Proiectarea optimă și integrată a procesoarelor/memoriilor.
• Apariția și dezvoltarea microchip-urilor multiprocesor.
• Apariția de modele standard de programare paralela si comunicare in diverse limbaje de
programare la diverse nivele:
• Limbaje de programare: C/C++, Java, C#, etc.
• Sisteme de programare: OpenMP, MPI
• Sisteme pentru GPU: CUDA, OpenCL, OpenACC
• Folosirea HW comun si standardizarea SW
• NU este o buna practică:
• Utilizarea sistemelor paralele pe aplicații secvențiale.
• Paralelizarea aplicațiilor fară să avem sisteme paralele la dispoziție.
Contributori
• Dijkstra, Edsger W. (1972 ACM Turing Award) and C.S. Scholten, Predicate
Calculus and Program Semantics, Texts and Monographs in Computer
Science. Springer-Verlag, 1989.
• Susține “calculational proof style” pentru argumentarea matematică. A utilizat
metoda propusă în geometrie, algebră liniară, teoria grafurilor, proiectarea
programelor secvențiale si distribuite.
https://amturing.acm.org/award_winners/dijkstra_1053701.cfm
• Hoare, Antony C. (1980 ACM Turing Award)
- Propune limbajul CSP în care interacțiunea dintre programe era limitată de
comunicații prestabilite. CSP devine ulterior aplicație si apoi transputer
(https://en.wikipedia.org/wiki/Transputer ).
- Transputer = serie de microprocesoare din anii 1980 care are memorie si
comunicare serială proiectată în vederea calculului paralel.
https://amturing.acm.org/award_winners/hoare_4622167.cfm
Contributori
• Dennis M. Ritchie (1983 ACM Turing Award) : A proiectat sistemul de
operare distribuit Inferno și limbajul de programare Limbo în 1995. Inferno
a fost proiectat pentru cutiile de cabluri ale televizoarelor (en., television
set-top boxes) și pentru telefoanele avansate.
https://amturing.acm.org/award_winners/ritchie_1506389.cfm
• Fernando Corbato (1983 ACM Turing Award): ” For his pioneering work
organizing the concepts and leading the development of the
general-purpose, large-scale, time-sharing and resource-sharing computer
systems, CTSS and Multics.”
https://amturing.acm.org/award_winners/corbato_1009471.cfm
Contributori
• Milner Robin Arthur (1991 ACM Turing Award):
CCS: Teoria generală a concurenței
Milner, R., A Calculus for Communicating Systems, Lecture Notes in
Computer Science, Vol. 92, Springer, 1980.
https://amturing.acm.org/award_winners/milner_1569367.cfm
• Butler Lampson (1992 ACM Turing Award):
”For contributions to the development of distributed, personal
computing environments and the technology for their implementation:
workstations, networks, operating systems, programming systems, displays,
security and document publishing.”
https://amturing.acm.org/award_winners/lampson_1142421.cfm
Contributori
• Vinton G. Cerf și Robert E. Kahn (2004 ACM Turing Award):
”led the design and implementation of the Transmission Control
Protocol and Internet Protocol (TCP/IP) that are the basis for the
current internet. ”
In 1983, Kahn a propus ”ARPA’s Strategic Computing Initiative”
unprogram de cercetare de 1mld USD care includea proiectarea de
chip-uri, arhitecturi de calcul paralel, si inteligență artificială.
https://amturing.acm.org/award_winners/cerf_1083211.cfm
Contributori
• Barbara Liskov (2008 ACM Turing Award):
” For contributions to practical and theoretical foundations of programming
language and system design, especially related to data abstraction, fault
tolerance, and distributed computing. ”
https://amturing.acm.org/award_winners/liskov_1108679.cfm
• Leslie Vailant (2010 ACM Turing Award):
” For transformative contributions to the theory of computation, including
the theory of probably approximately correct (PAC) learning, the complexity
of enumeration and of algebraic computation, and the theory of parallel and
distributed computing.”
https://amturing.acm.org/award_winners/valiant_2612174.cfm
Contributori
• Leslie Lamport (2013 ACM Turing Award):
” For fundamental contributions to the theory and practice of distributed and
concurrent systems, notably the invention of concepts such as causality and
logical clocks, safety and liveness, replicated state machines, and sequential
consistency. ”
https://amturing.acm.org/award_winners/lamport_1205376.cfm
Contribuții:
- Algoritmul Bakery
- Bazele programării concurente: "loop freedom”, consistența secvențială, registri atomici.
- Bazele sistemelor distribuite: ceasuri logice, înțelegerea Bizantină (en., Byzantine
Agreement), Replicarea masinilor cu stări (State Machine Replication )
- Verificarea și specificarea formală a programelor
- LaTeX
Contributori [alte domenii]
• 2014: Michael Stonebraker: ”... modern database systems”
• 2015: Diffie Whitfield: ” asymmetric public-key cryptography, ...
digital signatures, and a practical cryptographic key-exchange
method”
• 2016: Barnes-Lee-Tim: ”For inventing the World Wide Web”
• 2018: Bengio, Hinton, LeCun: ”deep neural networks a critical
component of computing”
• 2019: Catmull, Hanrahan: ” 3D computer graphics, and the impact of
computer-generated imagery (CGI) in filmmaking”
Cine si ce?
• https://top500.org/ oferă statistici despre sistemele paralele
existente: producători, utilizatori, locații, aplicații, etc.
Evaluare
• Laborator: 40% [minim nota 5]
• MPI: http://software.ucv.ro/~cpoteras/pda/index.html
• Paralelism in C++ : Threads / STL Paralel
• Ștefan Popescu (4sg.) + Renato Ivănescu (2sg.)
• Proiect: 30% : Rezolvă o problema folosind:
1) Limbaje de programare:
- POSIX Threads, Pthreads library for C ; C++ : Java-Style Synchronization ; C++ Threads, Parallel STL C++ algorithms; Java:
Threads, synchronized methods, external locks, java.util.concurrent; python parallel computing; C# parallel computing
2) Sisteme/Frameworks de programare (en., programming system)
-OpenMP; MS-MPI (https://docs.microsoft.com/en-us/message-passing-interface/microsoft-mpi ) ; MPI-3, AdaptiveMPI, Charm++
; MPJ Express (http://mpj-express.org); PVM.
3) Sisteme/Frameworks de programare cu GPU
- CUDA/OpenACC/OpenCL
4) Alte tehnologii/unelte: Blockchain, Hadoop.
• Examen oral: 30% [minim nota 5]
- exmen partial la mijlocul semestrului
Evaluare: Proiect [30%]
• S1->S3 [2 sapt.] – Stabilirea temei: enunț, limbaje de programare,
frameworks utilizate.
• S3->S12 [10 sapt.]: Dezvoltarea soluțiilor
• Cerințe minime:
• soluție secvențială
• 2-3 abordări paralele: limbaje de programare, sisteme, etc.
• Comparatii ale accelerării în funție de dimensiunea intrării, limbaj, sistem, etc.
• Minim 3 prezentări intermediare (S6, S8, S10)
• S12->S14[2 sapt.]: Evaluarea proiectelor
• În cadrul laboratorului/cursului
Exemple de probleme
• Probleme cu matrici: inmultirea unui vector cu o matrice, inmultirea
matricelor, rezolvarea sistemelor de ecuatii liniare
• Probleme pe grafuri: arbori partiali de cost minim, drumuri minime
(SSSP, APSP), componente conexe, etc.
• Sortări
• Căutări
• Geometrie: înfășurătoarea convexă (en., convex hull), cele mai
apropiate două puncte în plan (en., closest pair of points).
• ETC...
Referințe
• Computer Science Curricula 2013, Parallel and Distributed Computing (PD),
https://www.acm.org/binaries/content/assets/education/cs2013_web_final.pdf
• Curriculum Initiative on Parallel and Distributed Computing - Core Topics
for Undergraduates, http://tcpp.cs.gsu.edu/curriculum/
• Lynch, N. A. (1996). Distributed algorithms. Elsevier.
• Grama, Ananth, Vipin Kumar, Anshul Gupta, and George
Karypis. Introduction to parallel computing. Pearson Education, 2003.
https://www-users.cs.umn.edu/~karypis/parbook/
• Designing and Building Parallel Programs, by Ian Foster
https://www.mcs.anl.gov/~itf/dbpp/
• Livermore Computing Center Training Materials
• https://hpc.llnl.gov/training/tutorials
Algoritmi paraleli si
distribuiți
Tipuri și nivele de paralelism
+POSIX
Tipuri de procesări paralele
Taxonomia lui Flynn:
• SISD – Single Instruction stream, Single Data stream
• SIMD - Single Instruction stream, Multiple Data stream
• MISD - Multiple Instruction stream, Single Data stream
• MIMD - Multiple Instruction stream, Multiple Data stream
• Dinamice
• Rețea indirectă: rețeaua constă din elemente la care se atașează procesoarele.
• Sunt folosite pentru a conecta procesoarele cu memoria: sisteme cu memorie partajată.
Rețea de conectare statică/dinamică
Metrici de evaluare pentru rețelele de
interconectare
• Diametrul [cu cât mai mic cu atât mai bine]
• Lungimea maximă dintre oricare două noduri.
• Conectivitatea [cu cât mai mare cu atât mai bine]
• Numărul minim de conexiuni care trebuie distruse pentru a obține două
componente conexe din rețeaua inițială.
• Determină numărul de căi multiple.
• Lățimea bisecțiunii (en., bisection width) [cu cât mai mare cu atât mai
bine]
• Numărul minim de conexiuni care trebuie distruse pentru a obține două
componente conexe de dimensiune egală.
Metrici de evaluare pentru rețelele de
interconectare (cont.)
• Lățimea de bandă a bisecțiunii (en., bisection band width) [cu cât mai
mare cu atât mai bine]
• Se aplică pentru rețele ponderate (en., weighted). Ponderile corespund lățimii
de bandă, adică reprezintă cantitatea de date care poate fi transferată prin
acea legătură/muchie.
• Volumul minim de date care pot fi transferate între oricare două jumătăți ale
rețelei.
• Costul [cu cât mai mic cu atât mai bine]
• Numărul de legături (i.e., arce) din rețea.
- Care algoritmi de grafuri adresează aceste probleme?
Metrici în rețelele
dinamice
• Lățimea bisecțiunii într-o rețea dinamică se
determină prin examinarea mai multor tăieturi
care împart rețeaua în două mulțimi egale de
noduri.
• Lațimea bisecțiunii este numărul minim de muchii
care traversează taietura.
• În figura alăturată:
• Toate tăieturile sunt traversate de 4 muchii.
• Lățimea bisecțiunii acestul graf este 4.
Topologiile rețelelor
•Topologii carteziene:
•Liniare
•2-D
•3-D
Topologiile
rețelelor
- Hipercuburi
Topologiile rețelelor: structuri arborescente
Organizarea fizică
• Coerența cache-urilor în sistemele cu memorie partajată
• Un anumit nivel de consistență trebuie asigurat atunci când avem mai multe
copii ale acelorași date.
• Este necesară pentru a asigura execuția corectă a programului
• Serializarea datelor
• Sunt folosite două protocoale pentru a asigura coerența cache-urilor
• Invalidarea
• Update-ul
Organizarea fizică
T com_m = Ts + Tw * m
• https://man7.org/linux/man-pages/man3/pthread_create.3.html
• https://man7.org/linux/man-pages/man3/pthread_join.3.html
Primitive de sincronizare
• Accesul la variabilele partajate trebuie controlat pentru a înlătura situațiile de concurență
(en., race conditions) astfel încât să se asigure rularea semantic/logic secvențială și în
consecință determinismul programului.
/*fiecrae fir încearcă să modifice variabila best_cost astfel*/
if (my_cost < best_cost)
best_cost = my_cost;
- Presupunem că avem două fire de execuție
- Valoarea înițială pentru best_cost este 100.
- Valorile pentru my_cost sunt 50 și 75 în firele t1 și t2, respectiv.
- Dacă ambele fire execută if-ul concurent atunci amandouă vor executa ramura then. În
funcție de care fir se va executa primul valoarea best_cost va fi fie 50, fie 75.
- Problemă importantă:
- Natura nedeterministă a rezultatului! Rulări diferite pe acelasi input produc rezultate diferite! ☹
Lacăte (en. locks) pentru excludere mutuală
• O variabila specială denumită mutex poate fi folosită pentru a
gestiona secțiunile critice dintr-un program
• Un fir de execuție dobândește lacătul înainte să execute secțiunea critică și îl
eliberează după ce execută secțiunea critică.
• Dacă lacătul este deja în proprietatea altui fir, atunci firul se blochează până
când lacatul este eliberat.
• Lacătul reprezintă modalitatea prin care se realizează rularea
secvențială, astfel încât utilizarea unui număr prea mare conduce la
degradarea performanței.
Lacăte pentru excludere mutuală (cont.)
Funcția pthread_mutex_unlock deschide lacătul astfel încat unul dintre firele blocate care
așteaptă va intra în secțiunea critică prin închiderea lacătului. Determinarea firului care
inchide lacătul și rulează se face cu ajutorul unei politici de planificare (en. schedule policy).
Lacăte pentru excludere mutuală (cont.)
a = 3; b = a;
Nu, execuția paralelă conduce la nedeterminism sau comportament nedefinit.
a = f(x); b = g(x);
Nu putem spune fără să cunoaștem funcțiile f și g.
Se poate întâmpla ca instrucțini din f și g să modifice aceleași variabile.
Paralelism explicit: nivele
• Nivelul hardware
• Prin sistemul și organizarea sa fizică.
• Prin rețeaua de comunicare.
• Organizarea logică
• Modul în care programatorul vede platforma pe care va rula aplicația
paralelă.
4 3 5 1 8 11 2 9
7 (p0) 6 (p1) 19 (p2) 11 (p3)
13 (p0) 30 (p2)
43 (p0)
Descompunerea exploratorie
• Se folosește atunci când descompunem/împărțim spațiul soluțiilor în mulțimi
disjuncte și pentru fiecare muțime creăm câte un Task.
• Poate fi folosită pentru probleme specifice (ex., problema puzzel-ului cu 15
piese, https://en.wikipedia.org/wiki/15_puzzle)
• Poate prezenta anomalii ale accelerării: accelerare supraliniară
Descompunerea speculativă
• Se folosește pentru a obține concurența atunci când următorul *pas*
este unul din multe posibilități și se poate determina numai după ce
task-ul curent se termină.
• Acest tip de descompunere presupune un anumit rezultat/răspuns al
task-ului curent și execută câțiva din pașii următori.
• Mecanismul este asemănător cu execuția speculativă la nivel de
microprocesor.
• Dacă predicțiile sunt greșite
• Rezultatele execuției speculative devin inutile și sunt pierdute/aruncate
• Totuși, se poate întâmpla ca aceasta să fie singura modalitate de a
obține concurența.
Alocarea task-urilor
• De ce este important modul în care alocăm task-urile?
• Nu putem să alocăm aleator tak-urile procesoarelor disponibile?
• Alocarea este o operație critică ce trebuie să minimizeze costurile
suplimentare (en., overhead) care apar în urma paralelizării.
• To = p*Tp + Ts // Ts = timpul de execuție serială, Tp este timpul de execuție
// paralelă pe p procesoare
• Surse ale costurilor suplimentare
• Încărcarea dezechilibrată a procesoarelor
• Comunicarea între procese
• Coordonare/sincronizare/partajarea datelor
Alocarea task-urilor
• Alocările eficiente încearcă să:
• Maximizeze concurența prin alocarea de task-uri independente la procesoare
diferite.
• Minimizeze tipul total de execuție prin asigurarea faptului că task-urile care
se găsesc pe calea critică sunt cele care sunt executate cât mai devreme
posibil.
• Cum putem determina calea critică?
• Aloce task-urile care au grad mare de interacține între ele aceluiași proces.
• Cum putem determina mulțimile de task-uri care au grad mare de interacțiune între ele?
• Ce algoritmi din teoria grafurilor (nod – task; muchie = interacțiune) putem folosi?
Dificultatea alocării task-urilor
• Trebuie avute în vedere dependințele dintre task-uri și graful de
interacțiuni/dependințe dintre task-uri
• Sunt task-urile disponibile apriori?
• Crearea/generarea task-urior poate fi statică sau dinamică.
• Care sunt cerințele task-urilor în ceea ce privește necesitățile de calcul?
• Sunt ele uniforme? ... Aceleași pentru toate task-urile?
• Sunt ele cunoscute apriori?
• Ce cantitate de date este asociată cu fiecare task?
• Care sunt șabloanele de intaracțiune dintre task-uri?
• Statice sau dinamice?
• Le cunoaștem apriori?
• Depind de datele prelucrate?
• Sunt read-only sau read-write?
Tehnici de alocare pentru echilibrarea
încărcării
• Alocare statică
• Task-urile sunt alocate procesoarelor înainte de execuție.
• Se aplică task-urilor care sunt generate static sau au necesități de calcul
cunoscute sau uniforme.
• Este potrivită pentru algoritmii care folosesc descompunerea datelor sau
prelucrează date (input/date intermediare/output) sub forma tablourilor.
• Alocare dinamică
• Task-urile sunt distribuite procesoarelor în timul execuției programului
• Se aplică task-urilor care
• Sunt generate dinamic
• Nu li se conoaște apriori necesitatea de calcul
Metode de echilibrare dinamică a încărcării
• Metode centralizate
• Anumite procesoare sunt responsabile pentru procesări
• Modelul client-server
• Metode distribuite
• Încărcarea poate fi transferată de la un procesor la altul
• Probleme
• Cum detrminăm perechile de procesoare care își deleagă încărcarea
• Cine inițiază transferul? push vs.pull
• Cat de multă încărcare este transferată?
Alocările trebuie să minimizeze costurile
suplimentare generate de interacțiuni
• Maximizarea localizării datelor
• Minimizarea volumului de date schimbat
• Minimizarea frecvenței interacțiunilor
• Minimizarea disputelor
• Suprapunerea interacțiunilor cu efectuarea de calcule
• Replicarea selectivă a datelor și calculelor
Obs: Obținerea mecanismului optim se realizează iterativ și depinde de
interacțiunea dintre descompunere și alocare.
Modele de calcul paralel
• Cu memorie partajată
• Cu fire de execuție
• Cu transmitere de mesaje
• Cu paralelizarea datelor
• Hibride
int main() {
std::thread t1(print, 5, „One thread");
t1.join(); //se oprește rularea programului principal până la
// terminarea firului t1
return 0;
}
Fire de execuție în C++
• Multithreading
std::vector<std::thread> threads;
for (int i = 0; i < s.size(); i++) {
threads.push_back(std::thread(print, i, s[i]));
}
https://www.modernescpp.com/index.php/c-17-new-algorithm-of-the-standard-template-library
STL Parallel: Pași de urmat
1. Găsiți un algoritm pe care doriți sa-l paralelizați în aplicația
secvențială. De exemplu, algorimii care necesită mai mult de O(n)
timp (ex., sort) sunt candidati foarte buni. De asemenea, trebuie ca
aceștia să fie printre cei mai mari consumatori de timp din aplicație.
2. Verificați dacă ceea ce doriți să paralelizați este sigur d.p.d.v. al
consistenței. Paralelizarea trebuie să nu permită comportamente
nedefinite (en., undefined behaviour) sau să conducă la
nedeterminism.
3. Alegeți o politică de execuție paralelă.
STL Parallel: Pași de urmat (cont.)
4. #include <execution> pentru a face politicile de execuție paralelă
disponibile.
5. Adăugați una dintre politicile de execuție paralelă ca prim parametru
al apelului la algoritmului paralel.
6. Rulați/experimentați și realizați un benckmark ar rezultatului pentru
a vă asigura că versiuena paraleă este mai rapidă.
Obs:
- Paraleizarea NU este întotdeauna mai rapidă! Mai ales pentru
iteratorii care nu au acces aleator (en., non-random-access iterators),
atunci când dimensiunea datelor de intare este mică, sau atunci când
paralelismul detrmină blocarea pentru accesul la alte resurse (ex., un
disk).
STL Parallel
• Algoritmii paraleli depind de diponibilitatea paralelismului HW
• Nu trebuie foarte multe procesoare pentru a demonstar accelerarea.
• Mulți algoritmi sunt de tip divide et impera care nu vor scala perfect
cu numărul de fire, dar se vor executa mai repede.
• Algoritmii sunt paralelizabili în siguranță dacă funcțiile de acces ale
elementelor (ex., operașii cu iteratori, predicate, sau alt cod necesar)
respectă regulile de acces la date (i.e, data race), adică putem avea
oricâte citiri ale aceleiași variabile dar nu putem avea decât o scriere.
STL Parallel: politici de execuție
• Standardul include următoarele politici:
Politica secvențială: std::execution::seq
Politica paralelă (dar nu vectorizată): std::execution::par
Politica paralelă și vectorizată: std::execution::par_unseq
Politica vectorizată (dar nu paralelă) [din C++20]: std::execution::unseq
În plus față de cerințele necesare policii paralele, politica paralelă și
vectorială necesită ca funcțiile de acces la elemente să accepte
progresul/rularea aplicației cu constrângeri mai slabe (ex., nu necesită
și nu folosesc lacăte (en., locks) pentru acces la memorie). Mai mult
decât atât, trebuie ca CPU și sistemul de operare să suporte
instrucțiuni SIMD.
Efortul depus pentru paralelizare este minim = adăugarea unui
parametru!
STL Parallel: politici de execuție (cont.)
• Biblioteca poate ignora complet politica de execuție specificată
• Adică poate recurge la execuția serială
• Politica de execuție specificată reprezintă o indicație (en., hint)
pentru bibliotecă referitor la nivelul maxim de
paralelixare/vectorizare acceptat.
• Limitări: Biblioteca realizează paralelizarea algoritmului, NU
concurența!
• Concurența este o problemă de proiectare! VS. Paralelismul adresează
eficiența la rulare.
• Rob Pike, Concurrency Is Not Parallelism,
https://www.youtube.com/watch?v=oV9rvDllKEg
STL Parallel: politici de execuție (cont.)
• Limitări (cont.):
• Nu este permisă/posibilă proiectarea concurentă globală a aplicației.
• Sunt permise doar optimizări locale prin paralelizarea unor apeluri.
• Concluzie gresită: Folosim STL paralel și nu mai trebuie să acordăm atenție
problemelor cauzate de concunență deoarece biblioteca s-a ocupat de acest
lucru!
• Scopul bibliotecii NU este să rezolve probolemele de concurență, ci să rezolve
probleme locale de eficiență.
STL Parallel
• Paralelizare are și costuri suplimentare (en., overhead) și va conduce
la ineficiență (i.e., timp mai mare de execuție decât varianta
secvențială) pentru valori suficient de mici ale lui N (i.e., numarul de
numere pe care le sortăm).
• Atunci când se folosește o politică de execuție în paralel este
responsabilitatea programatorului să evite situațiile de *data race*
sau de blocare (en., deadlocks).
STL Parallel
• În timpul execuției unui algortm paralel care foloseste oricare dintre
politicile de paralelizare, dacă apelarea unei funcții de acces la un
element se finalizează printr-o excepție netratată atunci
std::terminate este apelat automat.
• Implementările client pot defini alte politici de execuție care să
trateze excepțiile în mod proprie/particular.
• Aruncarea (și tratarea excepțiilor) este recomandată!
STL Parallel: Exemplu
• Filtrarea elementelor dintr-un container
• Se dă un container A cu elemente. Scrieți un program care copiază
elementele care corespund unui predicat în containerul B, și returnați
containerul B.
• Funcția filter are urmatoarea semnătură:
https://bit-tech.net/reviews/tech/cpus/intel-core-i7-970-review/1/
• 6 core-uri, 2-way multithread, 4-wide SIMD (pe 3 din cele 6
pipeline-uri)
• Coerență cache MESIF (https://en.wikipedia.org/wiki/MESIF_protocol )
• Ierarhia chache-ului face ca procesoare diferite să aibă costuri
diferite de acces la zone diferite de memorie => NUMA!
Sisteme paralele cu memorie distribuită
Distribuția memoriei
• Avantaje
• Memoria scalează cu numărul de procesoare. Creșterea numărului de
procesoare este direct proporțională cu creșterea dimenisunii memoriei.
• Fiecare procesor accesează rapid memoria proprie fără să interfereze și fără
costuri suplimentare necesare pentru meținerea coerenței cache-ului.
• Cost mic: putem folosi procesoare comune + rețea
• Dezavantaje
• Programatorul este responsabil de modul în care se realizează comunicația
între procesoare.
• Poate fi dificil de alocat structuri de date existente într-o memorie globala pe
o organizare distribuită.
• Timpi NUMA (Non-uniform Memory Access)
Comparație între arhitecturile cu memorie
partajată și distribută
Arhitectură CC-UMA CC-NUMA Distribuită
Exemple SMP Bull NovaScale Cray T3E
Sun Vexx SGI Origin Maspar
DEC/Compaq Sequent IBM SP2
SGI Challenge HP Exemplar IBM BlueGene
IBM POWER3 DEC/Compaq
IBM POWER4 (MCM)
Comunicație MPI MPI MPI
Threads Threads
OpenMP OpenMP
shmem Shmem
Scalabilitate x10 de procesoare X100 de procesoare X1000 de procesoare
Limitări Lățimea de bandă Lățimea de bandă Admimistraea și
Memorie-CPU Memorie-CPU șu NUMA programarea sunt dificil de
dezvoltat și întreținut
Disponibilitate SW Mii de ISVs Mii de ISVs Sute de ISVs
IBM BlueGene
(https://en.wikipedia.org/wiki/IBM_Blue_Gene )
• 3 generații care au condus în
https://www.top500.org/ :
• BG/L: Feb 1999
• BG/P: June 2007
• BG/Q: Nov 2011
• 2015 s-a oprit dezvoltarea
• 15 instalări
• Aplicații
• Jocul de șah
• Simularea a 1% din cortex (1.6 bn de neuroni cu
approx. 9 tn de conexiuni)
Arhitecturi hibride de memorie
• Cele mai mari și mai rapide sisteme din
lume folosesc atât memoria partajată cât
si cea distribuită.
• Componentele cu memorie partajată sunt
mașini CC-SMP (cache coherent symetric
multiprocessor); procesoarele accesează
memoria componentei în mod global.
• Memoria distribuită este obținută prin conectarea în rețea a mai multor SMP-
uri. Deoarece fiecare SMP are acces direct numai la memoria sa (NU la
memoria altui SMP), este nevoie de comunicație de date pentru a transfera
date de la un SMP la altul.
• Trend-ul actual arată că aceste sisteme sunt cele vor domina domeniul HPC.
• Avantajele si dezavantajele: aspectele comune pentru arhitecturile cu memorie
parajată și distribuită.
Multicalculatoare (Message-Passing MIMDs)
• Procesoarele sunt conectate în rețea
• Poate fi conexiune Etherner sau o magistrală.
• Fiecare procesor are memorie locală si poate accesa doar memoria
locală.
• Datele sunt transmise între procesoare prin mesaje, asa cum este
specificat în aplicație printr-un limbaj adecvat (e.g., MPI, PVM).
• Problema este împărțită in task-uri care se execută concurent pe
procesoare.
• Unui procesor îi pot fi alocate mai multe task-uri.
Dezavantaje ale multicalculatoarelor
Sunt derivate din dezavantajele transmiterii de mesaje:
• Programatorul trebuie să apeleze explicit codul care transmite
mesajul.
• Programarea de nivel jos (i.e., explicită) predispune la erori
• Datele nu sunt partajate ci sunt copiate, ceea ce duce la creșterea
dimeniunii totale a datelor administrate.
• Integritatea datelor: este dificil de menținut corectitudinea datelor
atunci când administrăm mai multe copii ale aceleiași unități de
memorie
Avantaje ale multicalculatoarelor
• Ușurința accesului la date
• Permite ca sisteme diferite să proceseze aceleași date în mod
independent
• Permite updrade ușor al sistemelor atunci când avem la dispoziție
procesoare mai rapide.
• Arhitecturile hibride (cluster de SMP-uri) sunt o soluție la îndemână
• Asigură în același timp partajarea și distribuția.
Rolul arhitecturii de calcul paralel/distribuit
• Proiectarea și implementarea unei arhitecturii de calcul
paralel/distribuit este să maximizeze performanța și programabilitatea
(i.e., usurința de dezvoltare/testare/depanare/intreținere) sistemului
în limitele impuse de tehnologie și cost.
• Paralelismul arhitectural
• Se poate aplica la toate nivelel unui sistem
• Oferă o persepctivă deosebită asupra arhitecturii unui sistem
• Tradițional, elementele sistemului (procesoare și memorii) sunt colocalizate
• Creșterea lărgimii de bandă permite paralelism la distanțe mai mari.
Tendințe tehnologice
• Tehnologiile actuale continuă să crească densitatea chip-urilor
• Frecvența de lucru pentru arhitecturile single-core necesită prea
multă energie
• Unitilizarea tehnologiilor/sistemelor obișnuite (en., comodity) sau
gata de utilizat (en., off-the-shelf) necesită costuri scăzute.
• Microprocesoarele multi-core (i.e., AMD, IBM, Intel) sunt comune.
• Lățimea de bandă mare (i.e., 10GB Ethernet) este în general
disponibilă
Tendințe arhitecturale
• Împachetarea soluțiilor paralele
în *șasiuri* comune IBM BladeCenter S Chassis
• Servere Blade (i.e., IBM, Dell, HP, etc.)
• SW
• Windows Compute Cluster Server 2003 apărut în 2006 este prima tehnologie
HPC oferită de Microsoft.
• In prezent avem Windows Server 2019 care permite sistemelor server să luceze
împreună ca un cluster.
D.p.d.v. economic
• Reducerea costurilor serverelor cu bandă largă de interconectare
determină din ce în ce mai multe aplicații să devină paralelizabile.
• Micropucesoarece comune sunt rapide și ieftine
• Dezvoltarea lor costă zeci de milioane de USD
• DAR, se vand în cantități foarte mari, mult mai mari decât supercalculatoarele.
• Standardizarea face ca SMP-urile să devină un lucru comun
• Sistemele desktop
• Mai multe procesoare mai mici, sau unul mai mare?
• Arhitectură multiprocesor pe un singur chip.
Exemplu: Blade server
• 14 Blades intr-un 9U Chassis Form Factor
• IBM BladeCenter HS22 7870 2x QC Xeon X5560
2.8GHz 24GB costa approx. 200 euro.
• Rețea de înaltă performanță
• 4 surse de 2900W
• Descriere IBM BladeCenter H Chassis
• https://lenovopress.com/tips0996-bladecenter-h
Prezentare generală BladeCenter
CPU
Blade
CPU
Blade
CPU
Blade
CPU
Blade
CPU
Blade
Switch
CPU
Module
Blade
CPU
Blade
CPU
Switch
Blade Module
CPU
Blade
.
.
.
Mgmt
Module
Mgmt
Module
Prezentare generală BladeCenter H
I/O Bridge
HS Switch 1
• Switch de mare viteză
Blade 1
• Ethernet
HS Switch 2
• 4x (16 wire) blade links
Blade 2
4x (16 wire) bridge links
I/O Bridge
•
I/O Bridge 3/ SM3
• 1x (4 wire) Mgmt links
.. HS Switch 3
• Uplinks: Up to 12x links for
. HS Switch 4 IB and at least four 10Gb
I/O Bridge 4 / SM4
links for Ethernet
Switch Module 1
• I/O Bridge
Switch Module 2 • Ethernet, Fible Channel
Blade 14
• Dual 4x (16 wire) cablare
internă către fiecare HSSM
Mgmt Mod 1
Mgmt Mod 2
Arhitectura sistemelor distribuite
• Arhitecturi de tip client-server
• Arhitecturi cu obiecte distribuite
• CORBA: ORB (Object request brokers)
• Arhitecturi peer-to-peer și service-oriented
FABRICĂ ȘANTIER
• Abordare practică: mai multe drumuri, mai multe mașini, mai multe puncte
de lucru pe șantier, etc.
Descompunerea și alocarea: Metodologia Foster
• Concepte și terminologie
• Comunicare = schimbul de date între task-uri care se execută în paralel
• Necesită timp
• Sincronizare = coordonarea în timp real a task-urilor paralele
• Conduce la așteptări și întârzieri
• Granularitate
• Mare => comunicare puțină, calcule/funcții mari
• Mică => comunicare multă, calcule/funcții mici
• Costurile suplimentare apar datorită
• Sincronizărilor și schimburilor de date
• Compilatorului, bibliotecilor, uneltelor, SO, etc.
Descompunerea
• Este primul pas în proiectarea/dezvoltarea aplicațiilor paralele
• Constă în identificarea task-urilor care pot fi executate concurent
• Inițial, numărul de task-uri trebuie să fie cât mai mare (granularitate fină)
• Granularitatea fină oferă cea mai mare flexibilitate în ceea ce privește proiectarea
unui algoritm paralel.
• Ulterior evaluarea cerințelor de comunicare, arhitectura sistemului pe care va rula
aplicația sau aspectelele legate de proiectarea software vor definiexact modul de
paralelizare
• Task-urile pot fi identice, diferite sau de dimensiune necunoscută la rulare
• Descompunerea se poate reprezenta printr-un graf de dependințe și
interacțiuni ale task-urilor.
Descompunerea (cont.)
• O descompunere de bună calitate împarte atât logica de calcul
necesară, cât și datele care trebuie prelucrate.
• Primul pas se referă intotdeauna la descompunerea datelor.
• Apoi, trebuie determinat modul în care sunt efectuate procesările pe datele
descompuse
• Obs: Acest mod de descompunere este denumit descompunere de domeniu.
• Descompunerea funcțională are în vedere mai întâi descompunerea
procesării care trebuie efectuată, apoi are loc descompunerea
datelor.
• Obs. Aceste două modalități de descompunere sunt complementare,
dar pot fi aplicate la module diferile ale aceleiași probleme, sau pot fi
aplicate la aceeași problemă pentru a obține algoritmi alternativi.
Descompunerea (cont.)
• Scopul principal al descompunerii este să evite replicarea procesărilor
sau a datelor.
• Descompunerea fină (en. fine-grained) oferă cea mai mare flexibilitate în ceea
ce provește potențialul de paralelizare a algoritmului serial.
• Descompunerea domeniului (a datelor)
• Ideal ar fi să putem împărți datele în părți egale
• Apoi, împărțim calculele care trebuie efectuate prin alocarea fiecărei părți de
calcul a datelor necesare pe care lucrează. Astfel se obțin task-uri
• Task = datele si operațiile care trebuie efectuate pe acele date.
• O operație poate necesita rezultate/date de la mai multe task-uri => nevoia de
comunicare
Descompunerea domeniului
• Subarborii obținuți prin divide and conquer determină task-uri mai mari.
• Proiectarea este abstractă deoarece problema alocării task-urilor la procesoare rămâne
nerezolvată
• Soluție: definim cate un task pentru fiecare procesor.
• Scopurile aglomerării: (1) reducerea comunicării; (2) păstrarea flexibilității în ceea
ce privește scalabilitatea și alocarea task-urilor; (3) reducerea costurilor de
dezvoltare software.
Aglomerarea: Structura fluture (en.,
butterfly)
• log N nivele;
• fiecare task primește date de
la două task-uri, efectuază o
singură operație de adunare
și transmite rezultatul către
doup taskuri aflate la nivelul
superior
• Suma celor N valori este
efectuată în log N pași.
• Suma completă este
determinată de fiecare task
al nivelului superior.
Aglomerarea: Verificarea corectitudinii
proiectării
• S-au redus costurile de comunicare prin creșterea localizării?
• Dacă nu, trebuie adaptată strategia de aglomerare.
• Au apărut procesări replicate?
• Dacă da, beneficiile replicarii sunt mai mari decât costurile? Care este influența
dimensiunii problemei și a numărului de procesoare?
• Trebuiesc replicate date?
• Dacă da, este compromisă scalabilitatea algoritmului prin limitarea dimensiunii
problemei sau a numărului de procesoare?
• Am obținut task-uri cu costuri similare de procesare și comunicare?
• Cu cât sunt mai mari task-urile definite cu atat trebuie sa fie mai similare.
• Dacă avem un task per procesor atunci acestea trebuie să aibă costuri aproximativ
identice.
Aglomerarea: Verificarea corectitudinii
proiectării (cont.)
• Numărul de task-uri scalează cu dimensiunea problemei?
• Dacă nu, atunci algoritmul nu va putea rezolva probleme mai mari pe sisteme cu
mai multe procesoare.
• Au fost eliminate posibilități de execuție concurentă?
• Un algoritm cu concurență insuficientă poate deveni cel mai eficient dacă ceilalți
algoritmi au costuri excesiv de mari de comunicare.
• Alegerea se face prin evaluarea performanțelor.
• Mai poate fi redus numărul de task-uri fără a produce dezechilibrarea
încărcării, creșterea costurilor de dezvoltare sau reducerea scalabilității?
• Care sunt costurile de modificare a versiunii secvențiale pentru obținerea
paralelismului?
Alocarea
• Cel de-al 4-lea si ultimul pas al proiectării
• Specifică unde se execută fiecare task
• Nu nu are sens în sistemele cu un singur procesor sau pe sistemele cu
memorie partajată. Acestea au mecanisme automate de planificarea
(en., schedule).
• Este o problemă dificilă care trebuie adresată explicit în procesul de
proiectare al algoritmilor paraleli.
• Are ca scop minimizarea timpului total de execuție.
Alocarea (cont.)
• Există două strategii pentru minimizarea timpului total de execuție
• Alocăm task-urile care se pot executa concurent pe procesoare diferite .
• scopul este concurența crescută.
• Alocăm task-urile care comunică frecvent pe același procesor
• scopul este localizarea crescută.
• Aceste strategii pot intra în conflict!
• Si atunci este nevoie de compromis.
• Mai mult, resursele limitate pot diminua numărul de task-uri care se pot aloca
unui singur procesor.
Alocarea (cont.)
• Problema alocarii este NP-complete, adică nu există un algoritm
polinomial (i.e., en. computationally tractable) care să evalueze
compromisurile pe caz general.
• Totuși:
• Există strategii specializate, euristici și clase de probleme care conduc la
performanță.
Alocarea
Context: număr fix de task-uri; task-uri de dimensiune
egală; comunicare structurată locală și globală.
Alocarea eficientă este directă: alocăm task-urile astfel
încât să minimizăm comunicarea între procese.
- Avem 6 procesoare
- Se alocă fiecărui procesor aceeași cantitate de procesat
- Se minimizează comunicarea între procesoare.
Alocarea
• Dacă avem dimensiuni variabile/diferite ale nevoilor de procesare, și/sau
comunicare nestructurată atunci alocarea poate să nu fie evidentă.
• În această situație este nevoie de algoritmi pentru balansarea încărcării care să
determine alocarea eficientă. De obicei, determinarea este euristică.
• Timpul necesar rulării acestor algoritmi trebuie luat în calcul.
• Algoritmii probabilistici de balansare aduc de multe ori costuri suplimentare mai
mici decât cei care se bazează e structura inițială a soluției.
• Algoritmii dinamici de balansare sunt utili atunci când numarul de task-uri,
dimensiunea procesării necesare sau cenesitățile de comunicare se schimbă dinamic
în timpul execuției.
• Algoritmii de programare a task-urilor (en. Task scheduling) sunt folositi în situațiile
descompunerii funcționale, când multe task-uri mici necesită coordonare la
începutul și la sfârșitul execuției.
Alocarea: Algoritmi de echilibrare a încărcării
• Mai sunt cunoscuți ca algoritmi de partiționare.
• Tehnica bisecțiunii recursive (en. recursive bisection)
• Partiționează un domeniu (ex., un grid finit) în subdomenii de cost aproximativ egal,
încercând să minimizeze costurile de comunicare (i.e., canalele de comunicare care
traversează granițele).
• Abordarea clasică este divide and conquer
• O primă partiționare divide domeniul în două subdomenii
• Partiționarea recursivă continuă până când numărul de subdomenii este egal cu nbumărul de
task-uri dorit.
• Tehnica bisecțiunii recursive coordonate se aplică gridurilor neregulate
• Tehnica bisecțiunii recursive de tip graf se aplică grid-urilor cu structură graf.
• Se identifică două extremități ale grafului
• Fiecare nod este alocat extremității apropiate
Alocarea: Algoritmi de echilibrare a încărcării
(cont.)
• Algoritmi locali
• Tehnicile anterioare necesită conoașterea stării globale a stării în care se află
procesarea
• Algoritmii locali de echilibrare folosesc numai informațiile obținute de un
număr mic de procesoare vecine (i.e., abordare greedy).
• Ex. Dacă procesoarele sunt organizate intr-un mesh (i.e., plasă) acestea
compară starea de încărcare cu cea a vecinilor și decid să tranfere execuția de
task-uri dacă diferența dintre încărcări depășește un anumit prag (en.,
threshold).
• Cum putem detrmina pragul optim? Experimental!
Alocarea: Algoritmi de echilibrare a încărcării
(cont.)
• Algoritmi probabilistici
• Abordare simplă care alocă task-urile în mod aleator procesoarelor.
• Dacă numarul de task-uri este mare atunci fiecare procesor va avea alocată
aproximativ aceeași catitate de procesare.
• Avantaje: cost mic și scalabilitate.
• Dezavantaje: este nevoie de comunicare, iar echilibrarea devine acceptabilă
dacă numărul de task-uri este mult mai mare decât numarul de procesoare.
• Strategia este bună atunci când avem nevoie de puțină comunicare între
task-uri.
Alocarea: Algoritmi de programare a
task-urilor (en., scheduling)
• Sunt utili atunci când descompunerea funcțională produce multe task-uri,
fiecare dintre aceste având cerințe mici/slabe de localizare.
• O mulțime (en., pool) distribuită/centralizată de task-uri este creată și
administrată.
• Aici este adăugat un task nou.
• De aici este luat un task pentru a fi alocat unui procesor.
• Task-urile devin structuri de date reprezentând ”problemele” care trebuie rezolvate
de o mulțime de procesoare.
• Strategia de alocare/programare reprezintă un compromis între cerințe
conflictuale ale task-urilor (acestea doresc rularea independentă pentru a
reduce costurile de comunicare) și starea generală a procesării (necesară
balansării).
Alocarea: Algoritmi de programare a task-urilor
• Structura manager/worker
• Worker = face cereri repetate
și rezolvă probleme alocate
de manager.
• Poate trimite managerului
task-uri noi! ... Iar managerul
le va aloca altor worker-i.
• Manager = gestionează o
mulțime de probleme (p) și
răspunde cererilor venite de
la worker-i.
Alocarea: Algoritmi de programare a
task-urilor
• Structura ierarhizată manager/worker
• Împarte worker-i în mulțimi disjuncte, fiecare cu un sub-manager
• Worker-ii cer task-uri de la sub-manageri, care comunică regulat cu
managerul și cu alți sub-manageri pentru a balansa încărcarea procesoarelor
de care răspund.
• Structuri descentralizate
• Nu există manager. Fiecare procesor administrează o mulțime separată de
task-uri.
• Practic, mulțimea de task-uri devine o structură de date distribuită care poate
fi accesată de task-uri diferite în mod asincron.
• Politici de acces
• Un worker poate face o cerere la un număr limitat predefinit de ”vecini”
Alocarea: Verificarea corectitudinii proiectării
• Ați luat în considerare un algoritm de alocare bazat pe crearea și
distrugerea dinamică a task-urilor?
• Algoritmul poate fi simplu dar demonstrarea performanței este dificilă.
• În situația în care utilizați o metodă de balansare centralizată, ati verificat
ca managerul nu reprezintă el însuși o gâtuire (en., bottleneck)?
• Puteți reduce costurile de comunicare prin transmiterea de pointeri către task-uri,
în loc să transmiteți task-ul însuși (sau toate datele) către manager.
• În situația în care utilizați o metodă de balansare dinamică, ati evaluat mai
multe strategii/variante?
• Variantele probabilistice sunt simple si trebuie avute în vedere.
• În situația în care utilizați o metodă de balansare probabilistică, aveti un
număr suficient de mare de task-uri pentru a asigura o balansare adecvată?
• De obicei, trebuie sa aveți de 10 ori mai multe task-uri decât procesoare.
Concluzii
• Descompunerea
• NU depinde de arhitectura sistemului
• Trebuie să permită concurența.
• Aglomerarea
• NU depinde de arhitectura sistemului.
• Trebuie să echilibreze încărcarea și să limiteze comunicarea.
• Alocarea
• Depinde de arhitectura sistemului.
• Grupează procesele care au legătură între ele pe procesoare.
• Exploatează localizarea în situația unei rețele.
• Orchestrarea generală a aplicației [NU depinde de arhitectura sistemului]
• Reduce comunicarea prin localizare
• Reduce serializarea rezurselor partajate
• Planifică task-urile pentru a satisface dependințele cât mai din timp.
Concluzii (cont.)
• Orchestrarea generală a aplicației
• Memoria partajată
• Datele private și partajate sunt explicit declarate/separate
• Sincronizarea se realizează prin operații atomice asupra datelor partajate
• Sincronizarea este explicită și distincă față de comunicare
• Transmiterea mesajelor
• Are nevoie de distribuirea datelor între memoriile locale
• Nu există date explicit partajate
• Comunicarea este explicită
• Sincronizarea este asigurată implicit de comunicare.
Open MP
• Este o mulțime de
directive compilator
și funcții de biblotecă
pentru programarea
paralelă.
• Simplifică
dezvoltarea
aplicațiilor cu fire de
execuție îm
C/C++/Fortran
Sintaxa OpenMP
• Cele mai multe constructe în OpenMP sunt directive compilator
#pragma omp construct [clause [clause]…]
Pas 1. Schimbă
Comparator crescător
Comparator descrescător
Proiectarea rețelei de sortare
• Sortarea se realizează în etape (i.e., pe nivele)
• Comparatoarele sunt conectate în rețea
• Raspunsul ultimului nivel
este lista sortată
• Timpul este O(log 2n)
Sortarea bitonică (en., bitonic sort)
• Secvență bitonică
• Are elementele {a0, a1, …, an-1} unde
• {a0, a1, …, ai} sunt în ordine crescătoare
• {ai, ai+1, …, an-1} sunt în ordine descrescătoare
Demonstrație:
- cu ajutorul lemei de sortare 0-1.
Lema de sortare 0-1
Fie M(n,m) o matrice numai cu valori de 0 sau 1.
Există 3 tipuri de rânduri: numai cu 0, numai cu 1, și mixed (și 0 și 1).
Obs: Inițial, matricea M poate conține (în cazul cel mai defavorabil) n
rânduri mixed.
Matricea răspuns (sortată șerpuit) conține cel mult un rând mixed.
Propoziție:
După fiecare etapă (iterație din for = o fază rânduri și o fază
coloane) numărul de rânduri mixed se reduce cu jumătate.
Lema de sortare 0-1
Lemă: Dacă un algoritm de tipul compară-schimbă reușește să sorteze
secvențe de elemente care au numai valorișe 0 sau 1, atunci acest algoritm
va reuși să sorteze și secvențe de elemente de valori oarecare.
Demonstrație:
Fie algoritmul A și un input de dimensiune N.
Presupunem că A este corect pe orice input cu valorile 0 și 1.
Presupunem că A nu rezolvă input-ul [x1, x2, …, xN] cu răspunsul [y1, y2, …,
yN]. Asta înseamnă că y1 ≤ y2 ≤ ... ≤ym > ym+1pentru un anumit m.
Fie funcția F cu F(x) = 0 dacă x < ym , altfel F(x) = 1.
Deoarece F păstrează ordinea ≤, răspunsul algoritmului A pentru [F(x1), …,
F(xN)] este [F(y1), …, F(yN)] , și este de forma […, 1, 0, …] deoarece ym > ym+1.
Contradicție.
Lema de sortare 0-1.
Comportamentul algortmului.
Lema de sortare 0-1.
Comportamentul algortmului.
• Dacă avem N rânduri mixed atunci vom avea mai puțin de N/2 rânduri
mixed după primul pas al sortării coloanelor.
• Fiecare pereche de rânduri mixed detrmină prin sortare cel puțin un
rând pur (numai 0 sau numai 1)
Bubble sort paralel
• Ușor paralelizabilă pentru algoritmul clasic de complexitate O(n2)
• Bubble sort secvențial
• O(n) timp pentru fiecare parcurgere
• O(n) parcurgeri
• Putem să o paralelizăm?
• Bubble sort în paralel = Sortarea odd-even (i.e., par-impar)
• Compară și schimbă perechile de indecși pari și impari
• După n parcurgeri elementele sunt sortate
• Putem să o paralelizăm?
Sortarea odd-even: Exemplu
index 1 2 3 4 5 6 7 8
Valoare 3 2 3 8 5 6 4 1 //odd
2 3 3 8 5 6 1 4 //even
2 3 3 5 8 1 6 4 //odd
2 3 3 5 1 8 4 6 //even
...
1 2 3 3 4 5 6 8 //even
// secvența sortată
Sortarea odd-even: Algoritm
1. procedure ODD-EVEN PARALEL(n)
2. begin
3. id := process’s label
4. for i := 1 to n do
5. begin
6. if i is odd then
7. if id is odd then
8. compare-exchange min(id + 1);
9. else
10. compare-exchange max(id - 1);
11. if i is even then
12. if id is even then
13. compare-exchange min(id + 1);
14. else
15. compare-exchange max(id - 1);
16. end for
17. end ODD-EVEN PARALEL
Sortarea odd-even: Complexitate
• Optimizare (asemeănătoare ca la varianta secvențială)
• Se defineste variabila partajată sorted (i.e., un flag), care este inițializată cu
valoarea true la începutul fiecărei iterații (formată din cele două faze)
• Daca un singur procesor trebuie să efectueze un swap atunci sorted := false.
• În interiorul buclei principale
• Faza odd utilizează/necesită n/2 procesoare/comparații
• Faza even utilizează necesită n/2 procesoare/comparații
• Bucla principală for conține n pași.
• Complexitatea rulării în paralel este O(n).
• Quicksort secvențial are complexitatea O(n log n)
Algoritmul Quicksort
• Complexitatea medie este O(n log n)
• Strategia: divide-and-conquer
• Împarte șirul în subsecvențe astfel încât fiecare element din din prima
subsecvență este mai mic sau egal cu fiecare element din cea de-a doua
subsecvență.
• Pentru împărțirea secvenței se folosește un pivot.
• Pasul combine (i.e., conquer) aplică recursiv algoritmul.
• Putem sa paralelizăm algoritmul?
Quicksort secvențial
Algoritmul are concurență intrinsecă, deci
reprezintă un candidat bun pentru paralelizare:
• - Listele cu valori mai mici și mai mari pot fi
sortate în paralel.
Algoritmul Quicksort secvențial
1. procedure QUICKSORT (A, q, r )// q este pozitia pivotului si r este dimensiunea lui A
2. begin
3. if q < r then
4. begin
5. x := A[q]; // x este valoarea pivotului
6. s := q; // s este poziția pivotului
7. for i := q + 1 to r do // determinăm s, poziția finală a pivotului
8. if A[i] ≤ x then
9. begin
10. s := s + 1;
11. swap(A[s], A[i ]);
12. end if
13. swap(A[q], A[s]); //plasăm pivotul pe poziția finală
14. QUICKSORT (A, q, s);
15. QUICKSORT (A, s + 1, r );
16. end if
17. end QUICKSORT
Quicksort paralel
• Presupunem că ne aflăm în cazul unui sistem cu memorie distribuită
• Fiecare proces gestionează un segment din lista nesortată
• Lista nesortată este distribuită în mod egal între procese
• Rezultatul algoritmului:
• Fiecare listă a fiecărui proces este sortată
• Ultimul element lin lista procesului i este mai mic decât primul element al
listei procesului i+1
Quicksort paralel cu memorie distribuită
• Alegem aleator un pivot de la unul dintre procese și îl transmitem către toate
celelalte procese (en., broadcast).
• Fiecare proces împarte lista sa nesortată în două subliste:
• Cu valori mai mici sau egale cu pivotul și cu valori mai mari decât pivotul.
• Fiecare proces din prima jumătate a proceselor trimite sublista cu valori mici către un
proces partener tot din prima jumătate a proceselor și primește la schimb sublista cu
valori mai mari.
• Astfel, sublistele cu valori mari au valori mai mari decât pivotul, oar sublistele cu valori mici au
numai valori mai mici decât pivotul.
• Procesele se împart iar în două grupuri și algoritmul continuă recursiv.
• După log P apeluri recursive, fiecare proces deține o listă nesortată de valori complet
disjuncte de valorile deținute de celelalte procese.
• Cea mai mare valoare a procesului i este mai mică decât cea mai mică valoare a procesului i+1.
• Fiecare proces folosește quicksort secvențial pentru a sorta lista
Exemplificare
intuitivă și analiză
Balansarea încărcării este dificil de
realizat
- Dacă pivotul nu este ales
convenabil (i.e., valoarea
mediană) atunci lista nu se va
împărți în subliste de aceeași
dimensiune.
- Determinarea valorii mediane
are complexitate mare în
sostemele distribuite.
- Soluția este să alegem ca pivot o
valoare cât mai apropiată de
valoarea mediană.
Quicksort paralel cu memorie partajată
Pasul 1:
Selectarea pivotului
După
rearanjarea locală
După
rearanjarea globală
Quicksort paralel cu memorie partajată
(cont.)
Pasul 2:
Selectarea pivotului
După
rearanjarea locală
După
rearanjarea globală
Quicksort paralel cu memorie partajată
(cont.)
Pasul 3:
Selectarea pivotului
După
rearanjarea locală
După
rearanjarea globală
Quicksort paralel cu memorie partajată
(cont.)
Pasul 4:
După
rearanjarea locală
Soluția:
Sample Sort
• Algoritmul Sample sort este util atunci când elementele (valorile) NU sunt
uniform distribuite într-un interval.
• Creăm m buckets și sortăm fiecare bucket cu quicksort.
• Extragem un eșantion de dimensiune s
• Sortăm eșantioanele și alegem m-1 elemente ca splitters.
• Împărțim elementele în m buckets și apelăm quicksort
• Dacă elementele (valorile) sunt uniform distribuite într-un interval atunci
putem folosi algoritmul Bucket sort
• Se crează m buckets (= cu numărul de valori distincte) și se plasează elementele în
bucket-ul corespunzător
• Complexitatea este O(n log (n/m))
• Dacă m=n, folosim valoarea ca index pentru a obține timp O(n)
Algoritmul Sample Sort paralel
Pas 1. Se împarte lista inițială nesortată în P segmente egale. Fiecare segment
se sortează cu ajuorul quicksort. Din fiecare segment se selectează elementele
care se află la pozițiile 0, n/P2, 2n/P2, ..., (P-1)n/P2
Aceste valori reprezintă eșantionul reprezentativ al segmentelor sortate local.
Pas 2. Se soretază eșantionul obținut la pasul anterior. La acest pas selectăm
P-1 valori pivot din eșantionul reprezentativ. Cele P-1 valori sunt transmise
către toate procesele/segmentele. Fiecare proces împarte lista sa sortată în P
subliste disjuncte corespunzătoare valorilor pivor primite.
Pas 3. Fiecare proces i păstrează partiția sa i și transmite partiția j procesului j
pentru toate valorile j diferite de i.
Pas 4. Fiecare proces combină cele P partiții pentru a obține lista ordonată.
Sample Sort paralel: exemplu
Valorile inițiale
Sortarea eșantionului
Selectarea spliter-ului
global
Atribuirea finală
Merge Sort
• Strategia este divide-and-conquer
• Împarte (en., divide) vectorul de elemente în două părți
• Aplică aceeași strategie pentru fiecare parte definită anterior
• Atunci când două părți ajung sa fie ordonate ele trebuie unite (en., merge,
conquer) într-un vector ordonat care contine elementele celor două părți.
• Complexitatea medie O(n log n)
• T(n) = b pentru n=1
2T (n/2) + b*n pentru n>1 //Rezolvați relatia de recurență!
Sp = N3 / (N3/p) = p
Ep = N3 / p(N3/p) = 1
Sp = N3 / (N3/p) = p
Ep = N3 / p(N3/p) = 1
C3,0 = A3,3* B3,0 ; C3,1 = A3,3* B3,1; C3,2 = A3,3* B3,2; C3,3 = A3,3* B3,3
Algoritmul lui Fox: Exemplificare intuitivă
(cont.)
Pasul 1: Se transmit urmatoarele elemente din A (i.e., cele din A01
dreapta diagonalei principale) către procesoarele corespunzătoare, B10 B11 B12 B13
coloanele din B sunt shiftate cu o poziție în sus, si se realizează A12
înmulțirea. B20 B21 B22 B23
C0,0 += A0,1* B1,0; C0,1 += A0,1* B1,1; C0,2 += A0,1* B1,2; C0,3 += A0,1* B1,3 A23
B30 B31 B32 B33
A30
C1,0 += A1,2* B2,0 ; C1,1 += A1,2* B2,1; C1,2 += A1,2* B2,2; C1,3 += A1,2* B2,3 B00 B01 B02 B03
C2,0 += A2,3* B3,0 ; C2,1 += A2,3* B3,1; C2,2 += A2,3* B3,2; C2,3 += A2,3* B3,3
C3,0 += A3,0* B0,0 ; C3,1 += A3,0* B0,1; C3,2 += A3,0* B0,2; C3,3 += A3,0* B0,3
Algoritmul lui Fox: Exemplificare intuitivă
(cont.)
Pasul 2: Se transmit urmatoarele elemente din A către procesoarele A02
corespunzătoare, coloanele din B sunt shiftate cu o poziție în sus, si B20 B21 B22 B23
se realizează înmulțirea. A13
C0,0 += A0,2* B2,0; C0,1 += A0,2* B2,1; C0,2 += A0,2* B2,2; C0,3 += A0,2* B2,3 B30 B31 B32 B33
A20
B00 B01 B02 B03
C1,0 += A1,3* B3,0 ; C1,1 += A1,3* B3,1; C1,2 += A1,3* B3,2; C1,3 += A1,3* B3,3 A31
B10 B11 B12 B13
C2,0 += A2,0* B0,0 ; C2,1 += A2,0* B0,1; C2,2 += A2,0* B0,2; C2,3 += A2,0* B0,3
C3,0 += A3,1* B1,0 ; C3,1 += A3,1* B1,1; C3,2 += A3,1* B1,2; C3,3 += A3,1* B1,3
Algoritmul lui Fox: Exemplificare intuitivă
(cont.)
Pasul 3: Se transmit urmatoarele elemente din A către procesoarele A03
corespunzătoare, coloanele din B sunt shiftate cu o poziție în sus, si B30 B31 B32 B33
se realizează înmulțirea. A10
C0,0 += A0,3* B3,0; C0,1 += A0,3* B3,1; C0,2 += A0,3* B3,2; C0,3 += A0,3* B3,3 B00 B01 B02 B03
A21
B10 B11 B12 B13
C1,0 += A1,0* B0,0 ; C1,1 += A1,0* B0,1; C1,2 += A1,0* B0,2; C1,3 += A1,0* B0,3 A32
B20 B21 B22 B23
C2,0 += A2,1* B1,0 ; C2,1 += A2,1* B1,1; C2,2 += A2,1* B1,2; C2,3 += A2,1* B1,3
C3,0 += A3,2* B2,0 ; C3,1 += A3,2* B2,1; C3,2 += A3,2* B2,2; C3,3 += A3,2* B2,3
Algoritmul lui Fox: Complexitate
• Algoritmul lui Fox este efficient d.p.d.v. al memoriei necesare
• Totuși, costurile suplimentare apărute din cauza comunicării sunt mai
mari decât cele necesare Algoritmului lui Cannon.
• Scalarea și distribuirea/alocarea subtask-uriloe pe procesoare
• Dimeniunile matricelor pot fi alese astfel încât numărul de subtask-uri este
același cu numprul de procesoare.
• Execuția cea mai eficientă pentru rularea în paralel se obține atunci când
topologia rețelei este un grid 2D. Astfel, subtask-ul (i,j) este alocat
procesorului pij . In această situație, accelerarea și eficiența sunt ideale
Sp = n2 / (n2/p) = p, si Ep=n2/(p*(n2/p)) = 1
fără a lua în calcul costurile suplimentare cu comunicarea și memoria
Algoritmul SUMMA (en., Scalable Universal
Matrix Multiplication Algorithm)
• Fie A[m x n] * B[k x n] = C[m x n]
Inmulțirea naivă: Dacă schimbăm ordinea?
For i = 0 to n For k = 0 to n
For j = 0 to n For i = 0 to n
For k = 0 to n For j = 0 to n
C[i,j] += A[i,k] * B[k,j] C[i,j] += A[i,k]*B[k,j]
Calculăm n2 valori (en., inner products) Calculăm n valori (en., outer products)
C[i,j] = A[i,:]*B[:,j]
Algoritmul SUMMA
• Presupunem ca avem procesoarele distribute într-un grig, P(i,j)
• Exemplu de grid 2 x 2
A B C
Dacă A[mxk] si B[kxn] => C[mxn]
- Fiecare processor va realiza k înmulțiri
Q: Cum administrăm/tratăm/realizăm comunicația?
Algoritmul SUMMA
Fiecare proces P(i,j) execută
• Pentru k = 0 la n-1
• Se transmite (broadcast) coloana k din A (a_i) rândului i [1]
• Se transmite (broadcast) rândul k din B (b_j) coloanei j [2]
• C += a_i x b_j;// outer product [3]
do i=1,n
Kernel #2
a(i) = b(i) + c(i)
end do
!$acc end kernels
OpenACC: Exemplu (cont.)
• Construirea de Kernels in C
#pragma acc kernels [clause …]
{ structured block }
Clauses:
if( condition )
async( expression )
// clauze care se referă la date
OpenACC: Exemplu (cont.)
• Cuvântul cheie restrict
• Reprezintă declararea intenției programatorului către compilator
• Ex., aplicat la un pointer float *restrict ptr;
• Înseamnă: ”pe durata de viață a variabilei ptr , numai aceasta sau o valoare
obținută din aceasta (ex., ptr+1) va putea fi folosită pentru a accesa
obiectul către care pointează variabila”.
• Implicații:
• Se limitează efectele de pointer aliasing.
• Compilatoarele OpenACC necesită desori folosirea cuvântului cheie restrict
pentru a determina independența
• În caz contrar compilatorul nu poate paraleliza buclele care accesează ptr.
• Dacă programatorul nu definesc corect independența => *undefined behaviour*
int main(int argc, char **argv)
OpenACC: Exemplu (cont.) {
Variabila y nu va int N = 1<<20; // 1 million floats
fi un pointer alias if (argc > 1)
#include <stdlib.h> pentru x. N = atoi(argv[1]);
void saxpy(int n, float a, float *x = (float*)malloc(N * sizeof(float));
float *x, float *restrict y) float *y = (float*)malloc(N * sizeof(float));
{ for (int i = 0; i < N; ++i) {
#pragma acc kernels x[i] = 2.0f;
y[i] = 1.0f;
for (int i = 0; i < n; ++i)
}
y[i] = a*x[i] + y[i]; saxpy(N, 3.0f, x, y);
} return 0;
}
OpenACC: Exemplu (cont.)
• Compilare și rulare în C:
pgcc –acc [-Minfo=accel] –o saxpy_acc saxpy.c
saxpy:
8, Generating copyin(x[:n-1])
Generating copy(y[:n-1])
Generating compute capability 1.0 binary
Generating compute capability 2.0 binary
9, Loop is parallelizable
Accelerator kernel generated
9, #pragma acc loop worker, vector(256) /* blockIdx.x threadIdx.x */
CC 1.0 : 4 registers; 52 shared, 4 constant, 0 local memory bytes; 100% occupancy
CC 2.0 : 8 registers; 4 shared, 64 constant, 0 local memory bytes; 100% occupancy
OpenACC: Exemplu (cont.)
• Clauze pentru date
copy ( list ) : Alocă memorie pe GPU și copiază date care se află pe
sistemul gazdă pe GPU atunci când se intră în porțiunea paralelizată, și
transferă datele înapoi pe sistemul gazdă la ieșire din zona paralelizată.
copyin ( list ) Alocă memorie pe GPU și copiază date care se află pe
sistemul gazdă pe GPU atunci când se intră în porțiunea paralelizată.
copyout ( list ) Alocă memorie pe GPU și copiază date din GPU pe
sistemul gazdă când se iese în porțiunea paralelizată.
create ( list ) Alocă memorie pe GPU dar nu copiază date.
present ( list ) Datele sunt deja prezente pe GPU.
OpenACC: alte clauze și directive
• Array shaping: atunci când nu se poate determina dimensiunea unui
array.
• Update: #pragma acc update [clause …]
Clauze:
host( list ) if( expression )
device( list ) async( expression )
• Pentru a updata date după ce o copie a acestora a fost modificată (ex.,
updatarea copiei din GPU dupa ce copia de pe sistemul gazdă a fost
modificată).
• Pentru mutarea datelor între GPU și gazda.
OpenACC: Determinarea oportunitătilor de
paralelizare
• Buclele încuibate (en., nested for loops)
• Corpurile buclelor trebuie să fie independente unele de altele
• Compilatorul poate fi ajutat cu restrict sau clauza independent
• Compilatorul trebuie să poată determina dimensiuena datelor
utilizate în procesare.
• Se pot folosi directive care controlează explicit dimensiunea
• Aritmetica pointerilor trebuie evitată
• Folosiți accesarea cu indecși în loc de cea cu pointeri.
• Funcțiile apelate în cadrul secțiunii accelerate trebuie sa fie inline.
Algoritmi paraleli si
distribuiți
9. Algoritmi pe grafuri (I): BFS, SSSP cu ∆−𝑠𝑡𝑒𝑝𝑝𝑖𝑛𝑔
+OpenCL
Aplicații
• Determinarea drumului cel mai scurt într-o hartă
• De la 15 secunde (implementare naivă) la 10 microsecunde
Bast, H., Funke, S., Sanders, P., & Schultes, D. (2007). Fast routing in road networks
with transit nodes. Science, 316(5824), 566-566.
• Internet-ul si WWW
• WWW poate fi reprezentat ca un graf direcționat
• Căutarea și parcurgerea (en., crawl): traversarea grafurilor
• Analiza hiperlegăturilor (en., links) și ordonarea (en., ranking): algoritmii page rank si HITS
• Clasificarea paginilor/documentelor și clustering
• Topologia Internet-ului (i.e., rețeaua de routere) are natural structura unui graf.
• Aplicațiile software
• Dependințele de bibliotecă sunt de obicei un graf direcționat aciclic: sortare
topologică
Aplicații (cont.)
• Calcul științific
• Structuri de date pentru exploatarea eficientă a sparsității
• Colorarea grafurilor, arbori de acoperire
• Mulțimi independente, matchings, tehnici de embedding a grafurilor
• Analiza datelor mari (en., large scale)
• Seturi de date complexe, simulari pe date mari (petascale), rețele de senzori
• Provocări: dimensiunea datelor, eterogenitatea, incertitudinea, valorile lipsă,
calitatea datelor
• Astrofizică, bioinformatică, analiza datelor din rețelele sociale
Aplicații (cont.)
• Bioinformatică
• Studierea interacțiunilor care apar între componentele care alcătuiesc un
sistem biologic
• Modelarea: predicția interacțiunilor noi
• Matching/clustering: Anotarea funcțională a unor noi proteine
• Căi/clstering: Identificarea căilor de metabolizare
• Clustering/centralitate: identificarea unor noi complexe de proteine
• Analiza datelor din rețelele sociale
• Publicitatea tintită (en., targeted advertising): clustering și centralitate
• Studierea modului în care se propagă informația
Cercetare care implică algoritmi paraleli pe
grafuri
Aplicații Metode / Probleme Algoritmi pe grafuri Arhitecturi
Analiza rețelelor Determinarea entităților centrale Parcurgeri GPUs
sociale Detectarea comunităților FPGAs
Dinamica rețelei
WWW Marketing Drumuni minime Servere X86
Căutări Conectivitate multicore
https://images.app.goo.gl/PDH5db3RZkcErC6k9
Scalarea algoritmilor
• Algoritmii clasici pe grafuri nu au imbunătățiri ale performanțelor pe
sistemele paralele actuale
• Topologiile grafurilor folosite de algorimii clasici nu corespund seturilor de
date reale.
• Strategiile actuale de paralelizare se bazează pe îmbunătățirea localizării
• Algoritmii clasici nu folosesc noile arhitecturi de calcul paralel: ierarhizarea
memoriei, eterogenitatea procesoarelor, etc.
• Adaptarea implementării pentru a minimiza costurile suplimentare de
paralelizare este dificilă
• Memoria partajată: minimizarea costurilor suplimentare ale lacătelor și barierelor.
• Memorie distribuită: limitarea dimensiunii mesajelor, gruparea convenabilă a mesajelor,
suprapunerea/întrețeserea comunicării cu efectuarea calculelor.
BFS paralel
• Strategia 1. Frontiera curentă se extinde sincron pentru câte un nivel
la un moment dat
• Abordarea este potrivită
pentru grafurile cu diametru mic.
• Necesită O(D) pași, unde D
este diametrul.
• Nodurile vecine frontierei
sunt vizitate în paralel.
BFS paralel
• Strategia 1. Îmbunățirea localizării se poate face prin reetichetarea
nodurilor
• Nodurile inițial nu au etichete, au doar proprietăți: nivel, grad, etc.
• Lipsa etichetei face problema dificilă (i.e., similar învățării nesupervizate din
machine learning).
• Reetichetarea se poate face prin:
• Clustering, daca stim numarul de clustere
• Invațare semisupervizată (topic avansat)
• Daca gradul nodului este mic atunci adiacențele sunt administrate/stocate
explicit într-un index.
• Nodurile cu grad mare sunt procesate în ordine dar si prin blocarea în cache
• Scopul este de a forma blocuri dense în jurul nodurilor cu grad mare.
BFS paralel
• Strategia 1. Optimizări. Scopul este să valorificăm cache-ul partajat și
să diminuăm lipsa informațiilor necesare din cache-ul privat sau TLB
(en., translation lookaside buffer)
http://www.cs.cmu.edu/afs/cs.cmu.edu/user/tcm/www/thesis/subsubsection2
_10_1_2_1.html
• Sortăm listele de adiacență ale fiecărui vector, astfel accesele la memorie vor
fi ordonate și se va fi diminuată lipsa informațiilor din TLB.
• Permutăm etichetele nodurilor pentru îmbunătățirea localizării spațiale
• Blocăm in cache (en., cache blocking) muchiile vizitate recent pentru a
exploata localizarea temporală.
BFS paralel
• Îmbunătățirea localizării prin blocarea cache-ului
BFS paralel
• Strategia 2. Îmbină mai multe traversări concurente1
• Abordarea este potrivită pentru grafuri cu diametru mare
• Parcurgerea muchiilor/drumurilor este gestionată/limitată de *super-noduri*
• Abordarea este asemanatoare cu APSP între *super-noduri*
1
. Ullmann, https://apps.dtic.mil/sti/pdfs/ADA250894.pdf
BFS: Optimizări specifice arhitecturii HW
• *Software prefetching* pe procesoarele Intel Core i7
• Încărcarea speculativă a indecșilor și a nodurilor vecine frontierei in cache va
reduce cantitatea de date lipsă (en., cache miss) necesară procesării.
• Alinierea listelor de adiacență (i.e., localizarea spațială) optimizează accesul la
memorie prin reducerea fragmentării.
• *Hugepage support* contribuie la reducerea semnificativă a lipsei
infomatiilor necesare din TLB
https://en.wikipedia.org/wiki/Page_(computer_memory)
• Alocarea în memoria NUMA-aware este avantajoasă pentru politica
*first-touch*
https://queue.acm.org/detail.cfm?id=2513149
Algoritmi SSSP (en., single source shortest
paths)
•
• Context SSSP (en., Single Source Shortest Paths, Dijkstra)
• G (n, m) este un graf direcționat cu n noduri si m muchii
• s este nodul sursă
• c este o funcție care atribuie ponderi nenegative reale tuturor muchiilor din G.
• Scop: determinarea costurilor minime ale drumurilor de la s la toate nodurile v în
care se poate ajunge din s.
• Soluție secventială: Algoritmul lui Dijkstra, O(n logn +m) cu movile.
• Bellman-Ford: permite muchii de cost negativ, consideră nodurile în paralel, dar este ineficient
(O(nm)) față de Dijkstra.
• Abordare paralelă: Algoritmul ∆−𝑠𝑡𝑒𝑝𝑝𝑖𝑛𝑔
• Meyer, U., & Sanders, P. (1998, August). δ-stepping: A parallel single source shortest
path algorithm. In European symposium on algorithms (pp. 393-404). Springer, Berlin,
Heidelberg. https://www.cs.utexas.edu/~pingali/CS395T/2012sp/papers/delta-stepping.pdf
• Meyer, U., & Sanders, P. (2003). Δ-stepping: a parallelizable shortest path
algorithm. Journal of Algorithms, 49(1), 114-152.
• https://www.sciencedirect.com/science/article/pii/S0196677403000762
• Notații și constrângeri
• d = gradul maxim din graf
• L = costul celui mai lung drum din graf
• Costul unui drum este egal cu suma costurilor muchiilor care fac parte din acel drum
• Lungimea unui drum este egala cu numarul de muchii parcurse
• d/n probabilitatea ca între două noduri să avem muchie (en., edge probability)
• Modelul G(n, p), unde p=d/n
• Pentru d<1, fiecare componentă conexă este mică
• Pentru d>1, există o componentă conexă mare care conține un anumit procent din noduri. Cu
cât d este mai mare cu atât componenta are mai multe noduri.
• Ex. Nodes = persoane, edge = relatia de prietenie
p = d/n este probabilitatea ca două persoane să se întâlnească și să devină prietene.
Această valoare este statictic independentă de toate celelalte relații de prietenie
existente.
d = numărul de prieteni pe care poate să-l aibă cineva.
Cunoscând valorile lui d și n, cât de mari sunt componentele conexe?
•
•
• Ștergerea și relaxarea unui nod dintr-un bucket se poate realiza în
paralel și în orice ordine atâta timp cât relaxarea este implementată
ca o operație atomică (i.e., relaxările pentru același sunt efectuate
secvențial).
• Ca abordare alternativă, toate relaxările unui nod se pot combina într-o
singură relaxare a nodului cu cea mai mică distanță.
•
•
•
•
•
•
• Parelalismul se obține prin scoaterea concurentă a tuturor nodurilor din
primul buchet care nu este gol (i.e., bucket-ul curent) și relaxarea
muchiilor ușoare într-un singură fază.
• Dacă un nod v este scos din bucket-ul B[i] (costul determinat la acest
moment NU este final!) acesta poate fi analizat într-o fază ulterioară,
atunci cand poate fi reinserat în bucket-ul B[i], iar muchiile ușoare care
ies din v vor fi relaxate încă o dată.
• Muchiile grele rămase (care ies din toate nodurile scoase până acum
din B[i]) sunt relaxate o singură dată atunci când B[i] se golește.
• Scopul algoritmului este să caute bucket-uri care mai au muchii ușoare
și să le relaxeze în paralel. La final, toate muchiile grele sunt relaxate
într-o singură fază.
•
•
Performanța depinde de alegerea valorii lui ∆ în funcție de
caracteristicile grafului.
Analiza complexității [varianta secvențială]
• Pentru ponderi aleatoare uniform distribuite în [0,1] costurile
suplimentare pentru re-inserări și re-relaxări sunt maxim O(n+m)
pentru △=Θ(1/𝑑) .
• Dacă L este costul maxim al celui mai scurt drum atunci timpul
mediu devine O(n + m + d*L)
• Pentru d*L = O(n+m) timpul mediu este liniar in raport cu n si m, adică
O(n+m).
Obs: Acesta este cazul grafurilor direcționate cu grad cunoscut și limitat.
•
Exemplu de rulare intuitiv:
https://cs.iupui.edu/~fgsong/LearnHPC/sssp/deltaStep.html
Gazda trimite comenzi către dispozitive: 1) pentru a transfera date între memoria
gazdei li memoria dispozitivelor si 2) pentru a executa cod pe dispozitiv(e).
Anatomia unei aplicații OpenCL (cont.)
• Codul serial este executat pe un singur fir al sistemului gazdă (CPU)
• Codul paralel este executat pe mai multe fire pe dispozitive (GPU)
Modelul de execuție OpenCL:
- Aplicațiile rulează pe sistemul gazdă care trimite cereri către dispozitive în
vederea execuției de sarcini (en., work).
- Sarcina (en., work item) = ceea ce trebuie executat pe dispozitiv
- Kernel = codul C care trebuie executat în cadrul sarcinii.
- Program = colecție de kernele (si eventual alte functii) administrare de sistemul
gazdă
- Context = mediul în care se execută sarcinile: dispozitivele cu memoria lor și coada
de comenzi.
- Coada de comenzi = O coadă folosită de aplicația gazdă pentru a trimite sarcini unui
dispozitiv.
Execuția kernel-urilor
• O sarcină (en., work-item) este executată de un element de calcul
(en., compute element)
• Fiecare grup de sarcini (en., work-group) este executat pe o unitate
de calcul (en., compute unit).
• Mai multe grupuri de sarcini concurente se pot găsi pe o unitate de calcul în
funcție de necesarul de memorie și de resursele unității de calcul.
• Fiecare kernel este executat pe un dispozitiv (en., compute device)
Beneficiile utilizării grupurilor de sarcini (en.,
work-group)
• Scalabilitatea automată peste dispozitive cu numar diferit de unități
de calcul
• Grupurile de sarcini se pot executa în orice ordine, concurent sau secvențial.
• Cooperare eficientă între sarcininile din cadrul aceluiași grup de
sarcini
• Memorie partajată rapidă și sincronizată
• Independența dintre grupurile de sarcini oferă scalabilitate
• Un kernel se poate scala/rula pe orice număr de unități de calcul.
Memoria în OpenCL
• Spațiul de adrese este:
• Privat: Acces R/W numai la nivel de sarcina (i.e., work-item).
• Local: Acces R/W numai la nivel de grup de sarcini (en., work-group) .
• Global/constant: vizibil către toate grupurile de sarcini.
• Al gazdei: accesibil de CPU.
• Sincronizarea
• Toate sincronizările necesare pentru acces la memorie trebuie realizate
explicit.
Obs: Administrarea memoriei se face explicit: Datele trebuie mutate pe ruta
gazdă->global->local … și înapoi.
Dezvoltarea de aplicații cu OpenCL
• Limbajul OpenCL si API necesar
• API la nivel de platformă (apelabil din sistemul gazdă)
• Abstractizarea accesului la resursele de calcul
• Interogarea, selectarea si inițializarea dispozitivelor
• Crearea de contexte de calcu și a cozilor de lucru
• API la rulare (apelat de gazdă)
• Executa kernel-uri
• Stabilirea configurației de execuție a kernel-ului
• Administrarea planificarilor, calculelor și a resurselor de memorie
• Limbajul OpenCL
• Kernel-urile sunt scrise în C
• Sit disponibile multe funcții
• Compilarea se poate face JIT/online sau offline
Limbajul OpenCL
• Calificarea funcțiilor
• Calificatorul __kernel declara o funcție ca și kernel.
• Calificarea spatiului de momorie
• __global, __local, __constant, __private
• Funcții pentru lucrul cu sarcinile
• get_work_dim(), get_global_id(), get_local_size()
• Funcții pentru lucrul cu imaginile
• Imaginile pot fi accesate prin funcții built-in
• Funcții pentru sincronizare
• Barierele: toate sarcinile dintr-un grup trebuie să execute funcția barieră înainte ca
orice sarcină din grup să poată fi executată.
Tipuri de obiecte în OpenCL
• cl_platform_id: identificator pentru o anumită platformă
• cl_device_id: identificator pentru un anumit dispozitiv
• cl_context: handle pentru un context de calcul
• cl_command_queue: handle pentru o coadă de comenzi (a unui dispozitiv)
• cl_mem: handle pentru o resursă de memorie (dintr-un context)
• cl_program: handle pentru un program (într-o bibliotecă de kernel-e)
• cl_kernel: handle pentru un kernel.
• Toate obiectele au numarul de referințe numărat, iar sistemul are propriul
garbage collector
• Când numărul de referințe ajunge la 0 atunci memoria obiectului este eliberată.
OpenCL C
• Derivat din ISO C99 Limitări:
- Nu sunt permise apelurile recursive
• Proprietăși adăugate limbajului - Nu sunt permiși pointerii la funcții
• Existenșa sarcinilor si a grupurilor - Sunt permisi pointerii la pointeri dar
de sarcini intr-un kernel, nu ca parametri.
• Tipul vector - Nu sunt permise array-uri sau
• Sincronizare structuri de dimensiune variabilă.
• Functii build-in pentru - Etc..
• Lucrul cu imagini
• Lucrul cu sarcini
• Funcții matematice
Algoritmi paraleli si
distribuiți
10. Algoritmi pe grafuri (II): Prim, Kruskal, APSP (n x Dijkstra, Roy-Floyd),
componente conexe, SSSP pe grafuri rare.
+ Neo4j
Arbore parţial de cost minim (APM)
(en., MST = Minimum cost spanning tree)
• Arborele de acoperire pentru un graf nedirecționat G(V, E) este un
subgraf al lui G care este un arbore care conține toate nodurile din G.
• Subgraf = submultime de muchii din E
• Arbore = graf (nedirecționat) fără cicluri
• De acoperire = conține toate nodurile din G
• APM pentru un graf ponderat este arborele de acoperire cu cost
minim.
• Costul = suma costurilor muchiilor din APM
• Algoritmi care rezolvă aceasta problemă
• Prim, Kruskal, Boruvka
Algoritmul lui Prim pentru APM
• Este greedy și iterativ
• Alege un nod de start oarecare
• Alege un nou nod (ca Dijkstra) care este inclus in APM
• Timp O(n2)
Scopul paralelizării:
- Obținerea accelerării în urma rulării pe mai multe procesoare
- Procesarea de grafuri mari care nu pot fi rezolvate de un singur
procesor
Algoritmul lui Prim: formulare paralelă
•
Algoritmul lui Prim: formulare paralelă
(cont.)
•
Algoritmul lui Prim: formulare paralelă
(cont.) Contextul problemei
- Reprezentarea grafului: matrice de adiacență
Algoritm paralel referință - Graful este distribuit catre procesoare
- Nodul 0 este adăugat în APM (i.e., soluție) - V este împărțită în submulțimi
- Fiecare procesor se ocupă de o submulțime
- Fiecare procesor pi de noduri si toate muchiile acestora.
- Determină cel mai apropiat nod de APM-ul curent
- La primul pas APM-ul este alcătuit doar din nodul 0
- Transmite muchia de cost minim către procesul părinte
- Reducerea MIN (executată in procesul părinte)
- Procesul părinte determină minimul global. Acest pas are ca rezultat
determinarea/cucerirea uni nod care este adaugat la APM.
- Nodul nou adăugat/cucerit este transmis (en. , broadcast) către toate prosoarele.
- Procesoarele fac update in partea de graf gestionată.
- Acești pași se repetă până când APM-ul contine toate nodurile din V.
Algoritmul lui Prim: formulare paralelă
(cont.)
• Limitări ale variantei paralele de referință
• Pe grafurile mici (<10K de noduri) accelerarea este minimală
• Pe grafuri mari (25K-100K de noduri) costurile suplimetare (en., overhead)
generate de comunicare domină timpul necesar procesărilor ceea ce conduce
la lipsa accelerării.
• Posibile îmbunătățiri ale performanței
• Utilizarea mobilelor binome sau Fibonacci pentru determinarea minimului
• Utilizarea listei de adiacență pentru reprezentarea grafului
Algoritmul lui Kruskal
• Algoritmul lui Kruskal construiește o multime de APM în paralel.
• Inițial, fiecare nod este un arbore separat.
• Se sortează muchiile în ordine crescătoare a costurilor.
• Muchiile sunt analizate in ordinea costurilor
• Dacă muchia conectează doi arbori distincți atunci acestia sunt uniti
• Dacă muchia uneste două noduri ale aceluiași arbore atunci ea face un ciclu și deci
este ignorată.
• Algoritmul se termină când
• Nu mai avem muchii
• Avem un singur arbore, care este APM-ul căutat.
• Obs: Implementarea clasică este cu Union-Find.
Algoritmul lui Kruskal: formulare paralelă
• Varianta 1. Prin paralelizarea sortării
Având in vedere că algoritmul are două faze (i.e., Sortare si Parcurgere)
o primă opțiune este paralelizarea operației de sortare urmată de
parcurgere în mod asemănător ca în varianta secvențială.
Algoritmul lui Kruskal: formulare paralelă
(cont.)
•
Algoritmul lui Kruskal: formulare paralelă
(cont.)
•
Algoritmul lui Dijkstra: formulare paralelă
• Utilizează aceeași abordare ca algoritmul lui Prim pentru APM.
• Pas 1. Matricea de adiacență este partiționată pe coloane (i.e., subgraf cu o
submulțime de noduri si tote muchiile acestora)
• Pas 2. Fiecare proces selectează local nodul cel mai apropiat de nodul sursă.
Procesul părinte analizează toate soluțiile/propunerile locale și decide nodul
cucerit.
• Pas 3. Nodul cucerit este transmis (i.e., broadcast) către toate procesoarele
pentru ca vectorul de distanșe să fie actualizat.
• Ca și în algoritmul lui Dijkstra secvențial, algoritmul se termină atunci
când toate nodurile au fost cucerite (i.e., li s-a calculat costul minim)
• Presupunem că graful constă din noduri la care se poate ajunge din nodul
sursă.
Algoritmul lui Dijkstra pentru APSP
(en., All-Pairs Shortest Paths)
• Variantă secvențială
• Rezolvăm problema APSP prin n execuții ale algoritmului lui Dijkstra, cate una
din fiecare nod al grafului.
• Limitări:
• Algoritmul nu funcționează corect pentru costuri negative.
• Complexitatea este O(n3log n ) pentru grafuri dense.
• Pentru costuri negative (i.e., trebuie Bellman-Ford) complexitatea devine O(n4)
• Variantă paralelă
• Se partiționează sursele: fiecare apel de SSSP (Dijkstra/Bellman-Ford) se
execută pe câte un procesor separat.
• Se paralelizează SSSP pentru cresterea concurenței.
APSP cu Dijkstra: paralelizare cu
partiționarea surselor
• Fiecare procesor Pi determină un SSSP de la nodul vi la toate celelalte
noduri prin executarea algoritmului lui Dijkstra secvențial.
+ Nu apar costuri suplimentare cu comunicația, daca graful este replicat pe
toate procesoarele.
- Putem folosi maxim n procesoare.
Tp = O(n2) O(n2) , ca il cazul algoritmului lui Prim.
+ Paralelizarea SSSP face posibilă utilizarea a n2 procesoare.
APSP: Algoritmul Roy-Floyd: varianta paralelă
•
APSP: Algoritmul Roy-Floyd: varianta paralelă
•
APSP: Algoritmul Roy-Floyd: varianta paralelă
Folosim RDBMS atunci când avem: Folosim BD graf atunci când avem:
• Structură bine cunoscută și • Structură dinamică în care topologia
detrminată care nu se schimbă datelor este greu de evaluat.
frecvent • Relațiile dintre date (instanțe) au
înțeles și valoare
De la RDBMS la BD Graf
(dezvoltare/administrare)
Componentele unei baze de date graf
• Nodurile
• Sunt obiecte în graf
• Pot fi descrise de proprietăți de tipul nume-valoare
• Pot avea etichete
• Relațiile
• Leagă nodurile în funcție de tip și direcție
• Pot fi descrise de proprietăți de tipul nume-valoare
Avantaje ale utilizării BD graf
Modelul relațional vs. Modelul graf
• Intuitivitate
• Viteză
• Interogările sql din
bazele de date
relationale devin
cypher. Fără indexare!
Cypher (i.e., sql in bazele de date relationale)
• Crearea datelor (i.e, noduri și muchii)
CREATE(:Person{name:”Ann”}) – [:LOVES]-> (:Person{name:”Ann”})
• Noduri :Person{name:”Ann”}, where Person is label and name:”Ann” este o
proprietate.
• LOVES: este eticheta relației (i.e., atributul muchiei care leagă )
• Reprezentarea/crearea muchiilor bidirecționate/nedirecționate
MATCH(:Person{name:”Ann”}) – [:FB_FRIENDS]-> (:Person{name:”Dan”})
MATCH(:Person{name:”Ann”}) – [:FB_FRIENDS]- (:Person{name:”Dan”})
Cypher (cont)
• Cum ar arăta interogarea următoare cypher in sql?
http://www.opencypher.org/
• GQL (graph query language) este omologul sql pentru BD graf.
• Utilizarea urmează aceiași pași ca la BD relaționale
• Se crează modelul
• Se populează cu date
• Se interoghează
• Limbaje de programare
• .Net, JS, Java, Python, rubby, php
• Jetbrains IDE (https://www.jetbrains.com/products/ ) vine cu Plugin pentru
Graph Database Developers
https://neo4j.com/blog/jetbrains-ide-plugin-graph-database/
• Arhitectural
• MVC cu inlocuirea BD (relationale, NoSQL, Hadoop) cu BD graf.
Algoritmi paraleli in Neo4j
PageRank
https://neo4j.com/docs/graph-data-science/current/algorithms/page-rank/
SSSP cu ∆−𝑠𝑡𝑒𝑝𝑝𝑖𝑛𝑔
https://neo4j.com/docs/graph-data-science/current/alpha-algorithms/single-source-shorte
st-path/
APM
https://neo4j.com/docs/graph-data-science/current/alpha-algorithms/minim
um-weight-spanning-tree/
Machine Learning
https://neo4j.com/docs/graph-data-science/current/algorithms/node2vec/
https://neo4j.com/docs/graph-data-science/current/algorithms/ml-models/
Referințe:
Lončar, V., Škrbić, S., & Balaž, A. (2014). Parallelization of minimum
spanning tree algorithms using distributed memory architectures. In
Transactions on Engineering Technologies (pp. 543-554). Springer,
Dordrecht. http://www.scl.rs/papers/Loncar-TET-Springer.pdf
Katsigiannis, A., Anastopoulos, N., Nikas, K., & Koziris, N. (2012, May).
An approach to parallelize Kruskal's algorithm using helper threads. In
2012 IEEE 26th International Parallel and Distributed Processing
Symposium Workshops & PhD Forum (pp. 1601-1610). IEEE.
http://www.cslab.ntua.gr/~anastop/files/papers/mtaap12kruskal.pdf
Algoritmi paraleli si
distribuiți
11. Algoritmi distribuiți: Alegerea liderului, Map-Reduce
+ Hadoop
Alegerea liderului
• Context
• Avem un sitem distribuit, de exemplu procese într-o rețea
• Scop
• Procesele trebuie să aleagă un lider, adică un proces *principal*
• Procesul lider ales:
• Va fi organizatorul unui task distribuit, de exemplu
• Rădăcina unui APM pentru rețea
• Inițiatorul unui algoritm de reconstruire a token-ului pierdut intr-o rețea inel.
• Constrângeri referitoare la procesul de alegere
• Se pornește de la situația în care procesele nu au nici o intuiție referitoare la
procesul care va deveni lider
• Siguranță (en., safety): Doar un singur proces este ales ca lider
• Liveness: în cel mai rău caz trebuie ales un lider
Alegerea liderului (cont.)
• Algoritmul de alegere trebuie să fie descentralizat
• Inițiatorii pot fi mulțimi nevide de procese
• Toate procesele trebuie să execute același algoritm
• Se preîntâmpină astfel situația în care un proces decide unilateral ca ”Eu sunt liderul!”
• Procesele au ID-uri distincte și formază o mulțime total ordonată.
• Unicitatea ID-ului este esențială pentru ca algoritmul de alegere sa te termine
întotdeauna.
• Algoritmii sunt exemplificați in rețele de tip inel orientat
• Procesele stiu ce este in sânga (i.e., in sesul acelor ce ceas) și în dreapta (i.e.,
in sesul invers acelor de ceas.)
Rețea inel
1 = stânga = in sesul acelor ce ceas
2 = dreapta = in sesul invers acelor ce ceas
• HDFS
• Hadoop Distributed File System: *a self-healing high-bandwidth clustered
storage*
• Hadoop MapReduce:
• Un model de programare pentru procesarea de date mari
Folosiți unealta potrivită pentru task-ul avut
Baze de date relaționale Vs Hadoop
Se folosesc atunci când:
- Procesarea interactivă OLAP* (<1sec) - Avem sau nu date structurate
(flexibilitate)
- Avem tranzacții ACID - Scalabilitate a procesărilor și a
dimensiunii datelor procesare
- Interogările sunt 100% SQL conforme - Procesarea datelor complexe
OLAP = Online analytical processing
Stocarea datelor
• Avem două tipuri de noduri: de date și de procesare
• Abordarea:
• La rulare, datele sunt copiate în nodurile de procesare: acest mod de lucru
este viabil numao când lucrăm cu cantități relativ mici de date.
• Ce înseamnă mult?
• Facebook (500 TB pe zi); Yahoo (peste 170 PB); eBay (peste 6 PB)
• Aducerea de date la procesoare devine un bottleneck!
Cerințe pentru Hadoop:
• Trebuie să gestioneze defecțiunile (en., failure) unor componente
astfel încât să nu fie pierdute date
• Rezultatul final nu trebuie sa fie afectat
• MapReduce : Caracteristici
• Paralelizare și distribuție automată
• Toleranță la erori/defecțiuni (en., Fault-Tolerance)
• Oferă o mod de lucru abstract pe care programatorii îl pot utiliza cu ușurință
The Mapper
• Datele se citesc ca perechi cheie/valoare
• La cheie de obicei se renunță
• Răspunsul este sub forma perechilor cheie/valoare