Documente Academic
Documente Profesional
Documente Cultură
Cuprins
Cerint, ă 2
Paradigma Map-Reduce 2
Detalii tehnice 2
Operat, iile de tip Map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Operat, iile de tip Reduce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Execut, ie 3
Exemplu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Notare 7
Bonus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Testare 8
Docker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Link-uri utile 12
Pentru paralelizarea procesării documentelor de intrare, se va folosi modelul Map-Reduce. Fis, ierele de
intrare vor fi ı̂mpărt, ite (ı̂n mod dinamic) cât mai echilibrat la nis, te thread-uri care le vor parsa s, i vor verifica
ce numere mai mari decât 0 sunt puteri perfecte (operat, iunea de Map), rezultând astfel liste part, iale pentru
fiecare exponent (ex., liste pentru pătratele perfecte, liste pentru cuburile perfecte, etc.). Pasul următor ı̂l
reprezintă combinarea listelor part, iale (operat, iunea de Reduce) ı̂n urma căreia se vor obt, ine liste agregate
pentru fiecare exponent ı̂n parte. Pentru fiecare astfel de listă, se vor număra ı̂n paralel valorile unice,
rezultatele fiind apoi scrise ı̂n nis, te fis, iere de ies, ire.
Paradigma Map-Reduce
Pentru rezolvarea temei, se va folosi un model Map-Reduce similar cu cel folosit la Google pentru procesarea
unor seturi mari de documente ı̂n sisteme distribuite. Acest articol prezintă modelul Map-Reduce folosit
de Google s, i o parte dintre aplicat, iile lui (mai importante pentru ı̂nt, elegerea modelului sunt primele 4 pagini).
Map-Reduce este un model (s, i o implementare asociată) de programare paralelă pentru procesarea unor
seturi imense de date, folosind sute sau mii de procesoare. În majoritatea cazurilor, Map-Reduce este folosit
ı̂ntr-un context distribuit, fiind, de fapt, un model de programare care poate fi adaptat pentru ambele situat, ii.
Cea mai cunoscută implementare este Apache Hadoop, dezvoltat init, ial de către Doug Cutting s, i Mike Ca-
farella. Modelul permite paralelizarea s, i distribuirea automată a task-urilor. Paradigma Map-Reduce se
bazează pe existent, a a două funct, ii care ı̂i dau s, i numele: Map s, i Reduce. Funct, ia Map primes, te ca input o
funct, ie f s, i o listă de elemente, s, i returnează o nouă listă de elemente rezultată ı̂n urma aplicării funct, iei f
asupra fiecărui element din lista init, ială. Funct, ia Reduce combină rezultatele obt, inute anterior.
• această cerere este adresată unui proces (sau fir de execut, ie) coordonator
• coordonatorul asignează documentele unor procese (sau fire de execut, ie) de tip Mapper1
• un Mapper va analiza fis, ierele de care este responsabil s, i va genera nis, te rezultate part, iale, având ı̂n
general forma unor perechi de tip {cheie, valoare}
• după ce operat, iile Map au fost executate, alte procese (sau fire de execut, ie) de tip Reducer combină
rezultatele part, iale s, i generează solut, ia finală.
Detalii tehnice
Dându-se un set de N documente, să se numere valorile unice mai mari decât 0 de tip putere perfectă pentru
fiecare exponent E folosind Map-Reduce. În implementarea temei, vor exista thread-uri care pot fi de două
tipuri, Mapper sau Reducer, toate fiind pornite ı̂mpreună la ı̂nceputul rulării.
• deschide fis, ierul s, i ı̂l parcurge linie cu linie (pe fiecare linie fiind câte o valoare numerică de tip ı̂ntreg)
• pentru fiecare ı̂ntreg citit, verifică dacă este o putere perfectă a lui 2, 3, 4, etc. mai mare decât 0
(exponentul maxim până la care verifică este dat de numărul de thread-uri Reducer, as, a cum se va
explica mai târziu)
• fiecare valoare mai mare decât 0 care este o putere perfectă cu un exponent E este salvată ı̂ntr-o listă
part, ială (dacă o valoare este putere perfectă pentru mai mult, i exponent, i E - de exemplu, 81 poate fi
scris ca 34 sau 92 - aceasta va fi plasată ı̂n mai multe liste part, iale)
• când s-a terminat de procesat un fis, ier, Mapper-ul ı̂l ı̂nchide.
Atent, ie! Pentru verificarea dacă un număr este putere perfectă, NU folosit, i funct, ia pow (sau orice funct, ie
similară de ridicat la putere) cu exponent subunitar. Din cauza operat, iilor ı̂n virgulă mobilă, este posibil
să ratat, i anumite valori sau să luat, i ı̂n considerare valori incorecte.
• combină listele part, iale pentru exponentul E de care este responsabil ı̂ntr-o listă agregată (etapa de
combinare)
• numără valorile unice din lista agregată s, i scrie rezultatul ı̂ntr-un fis, ier (etapa de procesare).
Atent, ie! Înainte să ı̂ncepet, i operat, iile de tip Reduce, trebuie să vă asigurat, i că toate operat, iile de tip Map
s-au finalizat.
Execut, ie
Programul se va rula ı̂n felul următor:
./tema1 <numar_mapperi> <numar_reduceri> <fisier_intrare>
Atent, ie! Trebuie să pornit, i toate thread-urile (atât cele Mapper, cât s, i cele Reducer) ı̂ntr-o singură iterat, ie
a thread-ului principal. Nu se acceptă mai multe perechi de pthread create/pthread join ı̂n cod, acest lucru
ducând la un punctaj de 0 pe ı̂ntreaga temă.
Aceste fis, iere trebuie ı̂mpărt, ite cât mai echilibrat thread-urilor Mapper, fără să existe fis, iere neprocesate de
niciun Mapper sau fis, iere procesate de mai multe thread-uri Mapper.
Atent, ie! O ı̂mpărt, ire echilibrată a fis, ierelor de procesat nu ı̂nseamnă neapărat că fiecare thread Map-
per va avea câte un număr aproximativ egal de fis, iere, deoarece acestea pot avea dimensiuni foarte diferite.
De exemplu, dacă există trei thread-uri Mapper care au de procesat 6 fis, iere de dimensiuni 5 MB, 5 MB, 1
MB, 1 MB, 1 MB, 1 MB, este mai eficient ca primele două thread-uri Mapper să proceseze câte un fis, ier de
5 MB s, i al treilea Mapper să proceseze cele patru fis, iere de câte 1 MB, decât să se aloce câte două fis, iere
fiecărui Mapper. Acest lucru se poate face static (ı̂naintea de pornirea thread-urilor Mapper) sau dinamic
(fiecare Mapper care termină de procesat un fis, ier vede dacă mai sunt fis, iere disponibile). O ı̂mpărt, ire ine-
ficientă poate afecta scalabilitatea temei s, i implicit punctajul obt, inut.
În funct, ie de numărul de thread-uri Reducer, se va calcula s, i exponentul maxim E până la care se verifică
puterile perfecte mai mari decât 0. De exemplu, dacă se rulează cu trei thread-uri Reducer, E va fi 4 (se
verifică pătratele perfecte, cuburile perfecte, s, i numerele care sunt puteri perfecte cu exponentul 4). Progra-
mul va avea câte un fis, ier de ies, ire pentru fiecare Reducer, care se va numi outE.txt, unde E este exponentul
de care este responsabil fiecare Reducer. Un fis, ier de ies, ire va cont, ine o singură valoare de tip ı̂ntreg, adică
numărul de valori unice mai mari decât 0 care sunt puteri perfecte cu exponentul E.
Exemplu
Se dă următorul fis, ier de intrare:
$ cat test.txt
4
in1.txt
in2.txt
in3.txt
in4.txt
$ cat in2.txt
6
81
$ cat in3.txt
6
9
27
9
81
9
53
$ cat in4.txt
5
243
243
243
1
0
As, adar, există trei thread-uri Mapper (la care se ı̂mpart cele patru fis, iere) s, i cinci thread-uri Reducer (deci
se vor verifica puterile perfecte pentru exponent, ii 2, 3, 4, 5 s, i 6).
Cele patru fis, iere de intrare se pot ı̂mpărt, i la cele trei thread-uri Mapper astfel:
• M0 → in1.txt
• M1 → in2.txt
• M2 → in3.txt, in4.txt
Conform operat, iei de Map, fiecare Mapper verifică toate numerele din fis, ierele asignate lui s, i salvează liste
part, iale cu puterile perfecte mai mari decât 0. Pentru exemplul de mai sus, operat, iile de Map duc la
următoarele rezultate (unde prima listă de la fiecare Mapper reprezintă pătratele perfecte, a doua listă
cuburile perfecte, etc.):
• M0 → {9, 81}, {27}, {81}, {243, 243, 243}, {}
• M1 → {81, 9}, {27, 27, 27}, {81}, {243}, {}
• M2 → {9, 9, 81, 9, 1}, {27, 1}, {81, 1}, {243, 243, 243, 1}, {1}
Fiecare Mapper are câte cinci liste part, iale, una pentru fiecare exponent. Se poate observa că numerele care
sunt puteri perfecte pentru mai mult, i exponent, i E apar ı̂n mai multe liste part, iale de la acelas, i Mapper. De
asemenea, se poate observa s, i faptul că 1 este considerat putere perfectă pentru orice exponent, dar 0 nu se
ia ı̂n considerare (pentru că se cer valorile perfecte mai mari decât 0).
Odată ce toate operat, iile de Map s-au terminat, thread-urile Reducer se apucă de combinare s, i procesare.
Conform rulării, ı̂n acest exemplu sunt cinci astfel de thread-uri, fiecare din ele responsabil de un exponent.
Astfel, fiecare Reducer ia toate listele part, iale pentru exponentul său (care vor fi ı̂n număr de trei, câte una
per Mapper) s, i le agregă, ajungând la următorul set de liste agregate:
$ cat out3.txt
2
$ cat out4.txt
2
$ cat out5.txt
2
$ cat out6.txt
1
O reprezentare grafică a rulării de Map-Reduce pe exemplul precedent se poate observa ı̂n figura de mai jos.
• Makefile - cu directiva build care compilează tema voastră (fără flag-uri de optimizare) s, i generează
un executabil numit tema1 aflat ı̂n rădăcina arhivei, s, i directiva clean care s, terge executabilul
• README - fis, ier text ı̂n care să se descrie pe scurt implementarea temei
• README BONUS (opt, ional) - fis, ier text ı̂n care să se descrie pe scurt implementarea bonusului, doar
dacă l-at, i realizat (as, a cum se detaliază mai jos).
• -150p - utilizarea funct, iei pow (sau oricărei funct, ii similare de ridicat la putere) cu exponent subunitar
(ı̂n rest, putet, i folosi această funct, ie cât timp exponentul este mai mare decât 1)
• -20p - utilizarea variabilelor globale (solut, ia pentru a evita variabile globale este să trimitet, i variabile
s, i referint, e la variabile prin argumentele funct, iei pe care o dat, i la crearea firelor de execut, ie).
Atent, ie! Checker-ul vă dă cele 120 de puncte pentru scalabilitate s, i corectitudinea rezultatelor, dar acela nu
este punctajul final (dacă, de exemplu, temă vă scalează s, i dă rezultate corecte, dar nu at, i urmat paradigma
Map-Reduce, vet, i avea nota finală 0).
2 Acest punctaj este conditionat de scalabilitate. O solutie secventială, desi functionează corect si dă rezultate bune, nu se
, , , , , ,
va puncta.
Adoptarea diverselor framework-uri de programare paralelă s, i distribuită cum sunt Apache Hadoop sau
Apache Spark pe scară largă nu se datorează doar faptului că au o performant, ă bună, dar s, i pentru că
interfet, ele expuse de acestea sunt generice s, i adesea funct, ionale din punct de vedere al paradigmei de pro-
gramare. Pentru a vă reaminti ce ı̂nseamnă genericitatea ı̂n C/C++, putet, i să vă uitat, i aici.
Atent, ie! Dacă implementat, i bonusul, este necesar să adăugat, i ı̂n arhivă s, i un fis, ier README BONUS
ı̂n care descriet, i ce at, i făcut.
Testare
Pentru a vă putea testa tema, găsit, i ı̂n repository-ul temei un set de fis, iere de intrare de test, precum s, i
un script Bash (numit test.sh) pe care ı̂l putet, i rula pentru a vă verifica implementarea. Acest script va fi
folosit s, i pentru testarea automată3 .
Pentru a putea rula scriptul as, a cum este, trebuie să avet, i următoatoarea structură de fis, iere:
$ tree
.
+-- Makefile
+-- [...] (sursele voastre)
+-- README
+-- test.sh
+-- test0
| +-- [...] (fisierele testului)
+-- test1
| +-- [...] (fisierele testului)
+-- test2
| +-- [...] (fisierele testului)
+-- test3
| +-- [...] (fisierele testului)
+-- test4
+-- [...] (fisierele testului)
1. compilează programul
2. pentru cinci seturi de teste, execută următoarele operat, ii:
(a) rulează varianta etalon cu 1 thread Mapper s, i 4 thread-uri Reducer s, i verifică dacă rezultatele
sunt corecte
(b) rulează variante cu 2/4 thread-uri Mapper s, i 4 thread-uri Reducer s, i verifică dacă rezultatele sunt
corecte
3 Nota obt, inută ı̂n urma rulării automate poate fi scăzută pe baza elementelor de depunctare descrise mai sus.
Scriptul necesită existent, a următoarelor utilitare: awk, bc, diff, sed, time, timeout, xargs.
Atent, ie! Dacă avet, i un calculator cu două core-uri fizice (cu sau fără hyper-threading), va trebui să
modificat, i măsurarea accelerat, iei să nu ia ı̂n considerare s, i testele cu 4 thread-uri, pentru că implementarea
paralelă nu va scala.
Vă recomandăm să vă apucat, i de implementat tema s, i să ı̂ncercat, i să o facet, i să funct, ioneze pe fis, ierele
de input din directorul test0, care este fix exemplul prezentat mai sus. Când at, i obt, inut rezultate corecte pe
acest test, putet, i ı̂ncerca să rulat, i s, i celelalte teste s, i să verificat, i scalabilitatea.
Docker
Pentru a avea un mediu uniform de testare, sau pentru a putea rula scriptul de test mai us, or de pe Windows
sau MacOS (s, i cu mai put, ine resurse consumate decât dintr-o mas, ină virtuală), vă sugerăm să folosit, i Docker.
În repository-ul temei, găsit, i un director numit Docker. Dacă avet, i Docker instalat s, i rulat, i scriptul start.sh,
vi se va da acces de shell ı̂ntr-un container care are montat sistemul local de fis, iere la calea /tema1/, de unde
putet, i apoi rula scriptul de testare automată. De ment, ionat că, dacă descărcat, i de pe Git pe Windows, va
trebui să schimbat, i sfârs, itul liniilor din “CRLF” ı̂n “LF” s, i să mai rulat, i următoarea comandă ı̂n container,
pentru a da drepturi de execut, ie pe script: chmod a+x /tema1/test.sh.
1. la compilare, folosit, i flag-urile -Wall s, i -Werror; -Wall vă afis, ează toate avertismentele la compilare,
iar -Werror vă tratează avertismentele ca erori; aceste flag-uri vă ajută să preı̂ntâmpinat, i erori cum
ar fi variabile neinit, ializate, care se pot propaga us, or
2. folosit, i un repository privat de Git s, i dat, i commit-uri frecvent; vă ajută să vedet, i diferent, e ı̂ntre iterat, ii
de scris cod s, i vă asigură că avet, i undeva sigur codul ca să-l putet, i recupera ı̂n cazul ı̂n care l-at, i s, ters
din gres, eală sau mas, ina pe care lucrat, i nu mai funct, ionează
3. citit, i paginile de manual pentru funct, ile din biblioteca Pthreads s, i verificat, i valorile returnate de acestea;
dacă aceste valori corespund unor erori descrise acolo, vă putet, i da seama us, or dacă folosit, i gres, it
funct, iile sau structurile din bibliotecă
4. dacă lucrat, i pe Windows, vă recomandăm să folosit, i WSL2 sau Docker (ı̂n loc de o mas, ină virtuală)
pentru dezvoltare ı̂n Linux, deoarece sunt solut, ii care necesită mai put, ine resurse, iar performant, a e
mai aproape de cea a unui sistem de operare Linux care rulează direct pe mas, inile voastre
5. folosit, i un IDE precum CLion sau Visual Studio Code; pe lângă completarea automată a codului, avet, i
posibiliatea de a rula s, i a face debug pe cod.
În continure, avet, i un exemplu de cum putet, i să facet, i debug ı̂n Visual Studio Code. În primul rând, trebuie
să instalat, i plugin-ul pentru C/C++.
Ca să facet, i build s, i să rulat, i codul, trebuie să avet, i un director .vscode ı̂n care să avet, i două fis, iere, launch.json
s, i tasks.json. În tasks.json, definit, i ce act, iuni trebuie realizate pentru a se face build. În imaginea de mai
jos, avet, i un exemplu de cum trebuie să arate acest fis, ier. Trebuie să specificat, i unde se face build, care sunt
argumentele pentru make, precum s, i un label pentru a identifica act, iunea de build.
După ce au fost create aceste fis, iere, putet, i să rulat, i executabilul de debug, să adăugat, i breakpoints s, i să
navigat, i prin execut, ia programului. Putet, i să mai vedet, i variabilele locale s, i să evaluat, i expresii simple.
Link-uri utile
1. The Anatomy of a Large-Scale Hypertextual Web Search Engine