This shows you the differences between two versions of the page.
asc:teme:tema2 [2020/04/10 17:13] vlad.spoiala [Enunț] |
asc:teme:tema2 [2024/05/08 17:49] (current) costin.carabas [Tema 2 - Implementarea CUDA a algoritmului de consens Proof of Work din cadrul Bitcoin] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Tema 2 ====== | + | ====== Tema 2 - Implementarea CUDA a algoritmului de consens Proof of Work din cadrul Bitcoin ====== |
- | * **Deadline soft:** 19 aprilie 2020, ora 23:55. Primiți un bonus de 10% din punctajul obtinut pentru trimiterea temei cu 3 zile înaintea acestui termen, adică înainte de 16 aprilie 2020, ora 23:55. | + | |
- | * **Deadline hard:** 26 aprilie 2020, ora 23:55. Veți primi o depunctare de 10% din punctajul maxim al temei pentru fiecare zi de întârziere, până la maxim 7 zile, adică până pe 26 aprilie 2020, ora 23:55. | + | <note important> |
+ | * **Soft deadline:** **<del>8 Mai 2024</del> 10 Mai 2024**. Primiți un bonus de 10% din punctajul obtinut pentru trimiterea temei înainte de **30 aprilie 2024, ora 23:55**. | ||
+ | * **Hard deadline:** **<del>12 Mai 2024</del> 14 Mai 2024**. Veți primi o depunctare de 10% din punctajul maxim al temei pentru fiecare zi de întârziere. | ||
+ | * **Responsabili:** [[tudor.calafeteanu@stud.acs.upb.ro |Tudor Calafeteanu]], [[costin.carabas@gmail.com|Costin Carabaș ]] | ||
+ | </note> | ||
+ | |||
+ | <note tip> | ||
+ | * Dată publicare: 22 Aprilie 2024 | ||
+ | * Dată actualizare: 7 Mai 2024 | ||
+ | </note> | ||
===== Enunț ===== | ===== Enunț ===== | ||
- | Se dă următoarea operație cu matrice: | + | Implementarea unui algoritm de consens distribuit Proof of Work pe blockchain folosind programare pe GPU în CUDA. |
- | $$ C = B \times A^t + A^2 \times B $$ | + | <note important>**Disclaimer**: Această temă a pornit de la algoritmul Bitcoin descris în [[https://bitcoin.org/bitcoin.pdf|whitepaper]] , însă nu replică în totalitate algoritmul și structurile de date.</note> |
- | unde: | + | ===== Introducere ===== |
- | * $A$ si $B$ sunt matrice patratice de double de dimensiune N x N | + | |
- | * $A$ este o matrice superior triunghiulara | + | |
- | * $A^t$ este transpusa lui $A$ | + | |
- | * $\times$ este operația de înmulțire | + | |
- | * $+$ este operatia de adunare | + | |
- | * $A^2$ este $A$ ridicat la patrat | + | |
- | Se dorește implementarea operației de mai sus in C/C++ în 5 moduri: | + | Blockchain-ul este o tehnologie care a devenit cunoscută odată cu apariția criptomonedelor, precum Bitcoin-ul, Ethereum, etc. Este o formă de înregistrare descentralizată și distribuită a tranzacțiilor și datelor, care funcționează pe baza unui lanț de blocuri. Fiecare bloc înregistrează o serie de tranzacții și este legat de blocurile anterioare printr-un proces de criptare și verificare, cunoscut sub numele de "hashing". |
- | * **blas** - o variantă care folosește una sau mai multe functii din [[http://www.netlib.org/blas/ | BLAS Atlas]] pentru realizarea operatiilor de inmultire de matrice. Adunarea matricelor poate fi facuta "de mana". Aceasta implementare va tine cont de faptul ca A este o matrice superior triunghiulara. | + | |
- | * **neopt** - o variantă "de mână" fără îmbunătățiri. Aceasta implementare va tine cont de faptul ca A este o matrice superior triunghiulara. | + | |
- | * **opt_m** - o variantă îmbunătățită a versiunii **neopt**. Îmbunătățirea are în vedere exclusiv modificarea codului pentru a obține performanțe mai bune. | + | |
- | * **opt_f** - o variantă îmbunătățită obținută prin compilarea codului de la varianta **neopt** cu flag-ul -O3 | + | |
- | * **opt_f_extra** - o variantă îmbunătățită obținută prin compilarea codului de la varianta **neopt** cu flag-ul -O3 si alte [[https://gcc.gnu.org/onlinedocs/gcc-5.4.0/gcc/Optimize-Options.html|flag-uri de optimizare specifice]] ce nu sunt incluse in -O3. Se vor avea in vedere flag-uri care actioneaza asupra unei singure optimizari, nu flag-uri care actioneaza asupra unui grup de optimizari. | + | |
- | ===== Rulare și testare ===== | + | {{:asc:teme:blockchain.jpg?700|}} |
- | Pentru testarea temei vă este oferit un schelet de cod pe care trebuie să-l completați cu | + | **Descentralizare**: Datele sunt stocate și gestionate de o rețea descentralizată de noduri, eliminând astfel nevoia de o autoritate centrală. |
- | implementarile pentru cele 4 variante menționate mai sus. Scheletul de cod este structurat astfel: | + | |
- | * **main.c** - conține funcția main, precum și alte funcții folosite pentru citirea fișierului cu descrierea testelor, scrierea matricei rezultat într-un fișier, generarea datelor de intrare și rularea unui test. __Acest fișier va fi suprascris în timpul corectării și nu trebuie modificat__. | + | |
- | * **utils.h** - fișier header. __Acest fișier va fi suprascris în timpul corectării și nu trebuie modificat__. | + | |
- | * **solver_blas.c** - în acest fișier trebuie să adaugați implementarea variantei **blas**. | + | |
- | * **solver_neopt.c** - în acest fișier trebuie să adaugați implementarea variantei **neopt**. | + | |
- | * **solver_opt.c** - în acest fișier trebuie să adaugați implementarea variantei **opt_m**. | + | |
- | * **Makefile** - Makefile folosit la compilarea cu gcc. | + | |
- | * **input** - fișierul de input care contine 3 teste pentru urmatoarele valori ale lui N: 400, 800, 1200 | + | |
- | * **compare.c** - utilitar ce poate fi folosit pentru a compara doua fisiere rezultat. __Acest fișier va fi suprascris în timpul corectării și nu trebuie modificat__. | + | |
- | <note important>Puteți aduce orice modificare scheletului de cod exceptând cele 3 fișiere menționate mai sus.</note> | + | **Imutabilitate**: Datele înregistrate în blocurile blockchain-ului sunt imutabile și nu pot fi modificate sau șterse ulterior. |
- | În urma rulării comenzii **make** cu oricare din cele 2 Makefile-uri vor rezulta 5 fișere binare, **tema2_blas**, **tema2_neopt**, **tema2_opt_m**, **tema2_opt_f** si **tema2_opt_f_extra** corespunzătoare celor 5 variante care trebuie implementate. | + | **Transparență**: Tranzacțiile și înregistrările sunt publice și transparente, iar oricine poate să le verifice. |
- | <note tip>Rularea se va realiza astfel: | + | **Securitate**: Criptografia și algoritmii de consens asigură securitatea și integritatea datelor stocate în blockchain. |
- | <code>./tema2_<mod> input </code> | + | |
- | unde: | + | |
- | * mod este unul din modurile **blas**, **neopt**, **opt_m**, **opt_f** sau **opt_f_extra**. | + | |
- | * input este fișierul ce contine descrierea testelor. | + | ===== Obiectivele temei ===== |
- | | + | În cadrul acestei teme veți participa ca nod într-un blockchain, unde execuția tranzacțiilor se va face pe GPU. |
+ | Obiectivele temei: | ||
+ | * Înțelegerea conceptelor de bază ale blockchain-ului; | ||
+ | * Înțelegerea algoritmului de consens distribuit; | ||
+ | * Participarea la algoritmul de consens din perspectiva unui nod; | ||
+ | * Programarea pe GPU și folosirea limbajului CUDA; | ||
+ | |||
+ | ===== Algoritmul de consens ===== | ||
+ | Calculatoarele participante la consens se numesc noduri (sau mineri în cazul PoW). Aceste noduri nu se cunosc și nu au încredere unele în altele. | ||
+ | Scopul unui mecanism de consens este de a aduce toate nodurile în acord, adică de a avea încredere unul în celălalt, într-un mediu în care nodurile nu au încredere unul în celălalt. | ||
+ | |||
+ | * Minerii (aceștia veți fi voi) efectuează lucrări de calcul în rezolvarea unei probleme matematice complexe. Demonstrarea rezolvării problemei aduce de la sine și încredere. | ||
+ | * Problema matematică poate deveni mai complexă, în funcție de numărul de participanți la consens. | ||
+ | |||
+ | Minerul care a rezolvat primul problema, va propaga răspunsul în rețea, iar acest va fi validat de către ceilalți participanți la rețea. Astfel, problema are 2 proprietăți: | ||
+ | * Este greu de calculat răspunsul; | ||
+ | * Este ușor de verificat răspunsul. | ||
+ | |||
+ | Minerul care a rezolvat primul problema va fi recompensat. În cazul vostru, veți primi punctaj 😁 | ||
+ | |||
+ | ==== Structura unui bloc ==== | ||
+ | |||
+ | Un bloc este format din: | ||
+ | * Hash-ul blocului anterior - o valoare predefinită; | ||
+ | * Root hash-ul tranzacțiilor - o valoare calculată de host, tranzactiile avand valori predefinite; | ||
+ | * Nonce (Number used only once) - un număr întreg random, pozitiv, pe 32 biți, pe care minerii încearcă să îl găsească, astfel încât hash-ul block-ului rezultat să fie mai mic decât o dificultate threshold (un alt hash, ales în funcție de numărul de 0-uri consecutive din prefix). Acest număr trebuie să îl găsiți, prin metoda trial-and-error. | ||
+ | |||
+ | |||
+ | |||
+ | {{:asc:teme:merkle.png?300|}} | ||
+ | |||
+ | |||
+ | |||
+ | Hash-ul rezultat al blocului se va folosi în continuare pentru crearea unui alt bloc. De aici vine denumirea de blockchain: se creează un lanț de blocuri, iar fiecare bloc depinde de cel anterior. | ||
+ | |||
+ | |||
+ | {{:asc:teme:block.png?400|}} | ||
+ | |||
+ | |||
+ | ==== Rezolvarea problemei ==== | ||
+ | |||
+ | Problema de rezolvat este găsirea unei nonce care, atunci când se aplică o funcție hash, cum ar fi SHA-256, hash-ul începe cu un număr de zero biți. Munca medie necesară este exponențială în funcție de numărul de biți zero necesari și poate fi verificată prin executarea unui singur hash. | ||
+ | |||
+ | De exemplu, pornim de la “Hello world” și trebuie să găsim un nonce astfel încât hash-ul să înceapă cu un 0. | ||
+ | Pentru nonce = 4, aplicând sha256(“Hello world4”) obținem un hash ce începe cu un 0: | ||
+ | |||
+ | "//Hello world4//" -> **0**9b044fe014a500edc4358d55e4b59d595b7a2c9d01143ae37c577d1f68378e4 | ||
+ | |||
+ | Considerăm această problemă ca având **dificultatea = 1**. | ||
+ | Pentru o problemă cu **dificultatea = 3**, hash-ul rezultat va începe cu trei de 0: “**000**”. | ||
+ | |||
+ | |||
+ | ===== Cerințe ale temei ===== | ||
+ | |||
+ | |||
+ | ==== Înțelegerea algoritmului de consens pe CPU ==== | ||
+ | |||
+ | * Veți porni de la directorul **cpu_miner**, ce conține implementarea deja făcută pe CPU. Acesta **nu** face parte din rezolvarea temei. Scopul codului este de a înțelege funcționalitatea pe CPU, ca apoi să optimizați căutarea nonce-ului pe GPU, folosind CUDA. | ||
+ | * Acesta conține 5 teste: | ||
+ | * 4 pentru a vă familiariza cu funcțiile folosite. | ||
+ | * al 5-lea este efectiv implementarea miner-ului pe CPU | ||
+ | * Căutarea nonce-ului din testul 5 ar trebui să dureze ~2s pe xl, pentru o dificultate de 5 leading 0s. | ||
+ | * Aceasta este o abordare simplistă a calculării unui block hash, cu complexitate redusă. Nu reflectă implementarea reală a algoritmilor de consens POW, având scop pur educativ. | ||
+ | * Pași pentru rulare: | ||
+ | * To compile: make | ||
+ | * To run: make run | ||
+ | * To clean: make clean | ||
+ | |||
+ | ==== Implementarea algoritmului de consens pe GPU ==== | ||
+ | * Veți porni de la directorul **gpu_miner**, în care veți realiza implementarea în CUDA a logicii din //cpu_miner//. | ||
+ | * Veți implementa funcția device //findNonce//, care va paraleliza căutarea nonce-ului, folosind CUDA Threads. Aceasta trebuie implementată astfel încât să caute prin toate numerele de la 1 la MAX_NONCE. | ||
+ | * Pentru a va ajută, aveți deja implementate funcții ajutătoare în //utils.cu//. Vă recomandăm să va folosiți de ele în implementarea voastră. | ||
+ | * Nonce-ul găsit, hash-ul block-ului, precum și timpul rulării kernel-ului, vor fi scrise într-un fișier //results.csv//, în urmă apelarii funcției //printResult// din //utils.cu//. | ||
+ | * Pași pentru rulare: | ||
+ | * To compile: make | ||
+ | * To run: make run | ||
+ | * To clean: make clean | ||
+ | |||
+ | ==== Evaluarea performanței ==== | ||
+ | |||
+ | * Punctajul se va acorda în funcție de durata rulării kernel-ului //findNonce//. Pentru a testa eficiența implementării, în cazul valorilor predefinte în //utils// (previous block hash și cele 4 tranzacții, pentru o dificultate de 5 zero-uri), timpii rezultați sunt considerați: | ||
+ | * 100% pct implementare: //t// < 1s. | ||
+ | * 75% pct implementare: //t// < 1.5s. | ||
+ | * 50% pct implementare: //t// < 2s (durata rulării pe CPU). | ||
+ | * 0% pct implementare: //t// >= 2s SAU Nonce/Block hash incorect. | ||
+ | Unde //t// este timpul //minim// înregistrat în urma a 5 rulări succesive. Motivul pentru care rulăm de mai multe ori este că timpul poate fi diferit cu câteva zecimi de la o rulare la alta. | ||
+ | <note important>Această abordare o vom folosi și în testarea noastră, folosind teste **private**, pentru a vă oferi punctajul. Pentru a testa tema cu testele private, folositi submisia pe [[https://curs.upb.ro/2023/mod/assign/view.php?id=166059|Moodle]].</note> | ||
+ | |||
+ | ===== Observații ===== | ||
+ | * Compilarea si rularea temei se vor face **EXCLUSIV** pe coada //xl//. Nu este nevoie să modificăți nimic în //Makefile//, regulile sunt deja făcute. Tot ce trebuie să faceți este să apelați //make//, //make run// și //make clean//, ca la laborator. | ||
+ | * Veți modifica **DOAR** fișierul //gpu_miner.cu//. Celelate fișiere din directorul //gpu_miner// se vor suprascrie la testarea automată. | ||
+ | * Deși nonce-ul este un număr întreg, pozitiv, pe 32 biți, MAX_NONCE pe GPU este setat cu valoarea 1e8, în loc de UINT32_MAX (~4.29 * 1e9). Motivul este de a reduce timpul și de a nu întâmpină bottleneck-uri când sunt trimise multe job-uri, în același timp, de la mai mulți studenți, pe coada xl. | ||
+ | |||
+ | <note warning> | ||
+ | Temele vor fi testate împotriva plagiatului. Orice tentativă de copiere va fi depunctată conform [[asc:regulament|regulamentului]]. | ||
+ | Rezultatele notării automate este orientativă și poate fi afectată de corectarea manuală. | ||
</note> | </note> | ||
- | Fișierul **input** este structurat astfel: | + | ===== Notare ===== |
- | * pe prima linie numărul de teste. | + | Toate modificările vor fi aduse fișierului **gpu_miner.cu**. Acest fișier îl veți submite pentru a fi evaluat și notat. |
- | * pe următoarele linii descrierea fiecarui test: | + | |
- | * valoarea lui N. | + | |
- | * seed-ul folosit la generarea datelor. | + | |
- | * calea către fișierul de ieșire ce conține matricea rezultat. | + | |
- | Rularea se va face pe coada **ibm-nehalem.q**. Compilarea se va face folosind **gcc-5.4.0** din modulul **compilers/gnu-5.4.0**. Pentru a incarca modulul pentru GCC trebuie sa dati pe una din masinile din coada ibm-nehalem.q urmatoarea comanda: <code> module load compilers/gnu-5.4.0 </code> | + | Punctajul maxim este de 100 pct distribuite astfel: |
- | Pentru variantele **blas**, **neopt** si **opt_m** nu vor fi utilizate flag-uri de optimizare pentru compilare (va fi utilizat -O0). | + | 20 pct EXPLICAȚII |
- | Pentru linkarea cu BLAS Atlas se va folosi versiunea single-threaded **libsatlas.so.3.10** de pe masinile din coada ibm-nehalem.q | + | * Implementare descrisă în README, alături de rezultate și o discuție asupra lor. |
- | disponibile in directorul <code>/usr/lib64/atlas</code> | + | * Programul compilează, codul nu are disfuncționalități majore. |
- | Fișierele output referință le găsiți aici: | + | 80 pct IMPLEMENTARE |
- | <code> /export/asc/tema2/</code> | + | * Punctaj dat de vmchecker. |
- | ===== Punctaj ===== | + | Arhiva temei va fi încărcată pe [[https://curs.upb.ro/2023/mod/assign/view.php?id=166059|Moodle]]. Aceasta va cuprinde obligatoriu: |
+ | * gpu_miner.cu | ||
+ | * README | ||
- | Punctajul este impărțit astfel: | + | ===== Bonus ===== |
- | * **15p** pentru implementarea variantei **blas** dintre care: | + | Pentru a primi un punctaj bonus de maxim 10 pct, va trebui să schimbați realizarea Merkle Tree-ului din metoda secvențială, pe CPU, într-una paralelă, pe GPU. |
- | * 12p daca implementarea obtine rezultate corecte | + | Cerințe: |
- | * 3p pentru descrierea implementarii in README | + | * Puteți observa că Merkle Tree-ul se poate realiza într-un mod paralel, față de cel secvențial implementat deja. |
- | * **15p** pentru implementarea variantei **neopt** dintre care: | + | * Va trebui să vă creați un fișier de intrare //inputs.txt//, din care să citiți //n// tranzacții, //n// >= 1000. Este la latitudinea voastră dacă folosiți același previous block hash folosit deja în cod, sau citiți unul nou. |
- | * 12p daca implementarea obtine rezultate corecte | + | * Veți defini o altă funcție kernel //merkleTree//, care va realiza în mod paralel crearea top hash-ului, folosind CUDA Threads. |
- | * 3p pentru descrierea implementarii in README | + | * Punctajul se va da pe o abordare corectă și eficient paralelă a generării top hash-ului, în care să arătați speedup-ul obținut de la trecerea secvențială pe CPU, la cea paralelă pe GPU. Timpul nu va fi luat în considerare, însă nu trebuie să dureze rularea job-ului mai mult decât valoarea predefinită în RUN_TIME. |
- | * **20p** pentru implementarea variantei **opt_m** dintre care: | + | |
- | * 15p daca implementarea obtine rezultate corecte si timpul de calcul este cu cel putin 30% mai mic decat cel al variantei **neopt** pentru testul cu N = 1200 | + | |
- | * 5p pentru descrierea implementarii in README | + | |
- | * **20p** pentru implementarea variantei **opt_f_extra** dintre care: | + | |
- | * 10p daca implementarea obtine rezultate corecte si timpul de calcul este cu cel putin 5% mai mic decat cel al variantei **opt_f** pentru testul cu N = 1200 | + | |
- | * 10p pentru explicatii legate de alegerea flag-urilor si impactul flag-urilor asupra performantei | + | |
- | * **30p** pentru o analiza comparativa a performantei pentru cele 5 variante: | + | |
- | * 15p pentru realizarea unor grafice relevante bazate pe rularea a cel putin 5 teste (5 valori diferite ale lui N: adica inca cel putin doua valori diferite de 400, 800 si 1200 pentru N) | + | |
- | * 15p pentru explicatii oferite in README | + | |
- | * **(Bonus)** | + | |
- | * 20p daca timpul de calcul al variantei **opt_m** pentru testul cu N = 1200 este cel mult 4 secunde sau | + | |
- | * 10p daca timpul de calcul al variantei **opt_m** pentru testul cu N = 1200 este intre 4 si 8 secunde | + | |
- | * Bonusurile se calculeaza doar pe coada ibm-nehalem.q | + | |
- | <note important>Pentru a fi luată în considerare la punctaj, implementarea trebuie să producă rezultate corecte pe cele 3 teste din fisierul **input**.</note> | + | ===== Resurse necesare realizării temei ===== |
- | ===== Precizări și recomandări ===== | + | Pentru a clona [[https://gitlab.cs.pub.ro/asc/asc-public | repo-ul]] și a accesa resursele temei 2: |
- | <note warning>Timpul maxim pentru rularea celor 3 teste folosind oricare din cele 5 variante este de 2 minute. Această limită de timp se referă la rularea întregului program, nu doar la partea intensiv computațională.</note> | + | <code bash> |
+ | student@asc:~$ git clone https://gitlab.cs.pub.ro/asc/asc-public.git | ||
+ | student@asc:~$ cd asc-public/assignments/2-cuda_proof_of_work | ||
+ | </code> | ||
- | * Pentru a simplifica implementarea puteți presupune că N este multiplu de 40 și că este mai mic sau egal cu 1600. | + | ===== Suport, întrebări și clarificări ===== |
- | * În compararea rezultatelor se va permite o eroare absolută de maxim $10^{-3}$. | + | |
- | * În cazul variantei **opt_m** complexitatea trebuie să fie aceeași cu cea din varianta **neopt**. | + | |
- | * Formatul arhivei trebuie să fie **zip**. | + | |
- | Pentru a vedea ce optimizari sunt prezente in fiecare nivel de optimizare puteti folosi comanda: | + | Pentru întrebări sau nelămuriri legate de temă folosiți [[https://curs.upb.ro/2023/mod/forum/view.php?id=166058|forumul temei]]. |
- | <code> gcc -Q -Olevel --help=optimizers </code> | + | |
- | <note tip>Pentru a evita aglomerarea cozii se recomanda rularea de teste pentru valori ale lui N mai mici sau egale cu 1600.</note> | + | <note important> |
+ | Orice intrebare e recomandat să conțină o descriere cât mai clară a eventualei probleme. Întrebări de forma: "Nu merge X. De ce?" fără o descriere mai amănunțită vor primi un răspuns mai greu. | ||
- | <note> Se recomandă ștergerea fișierelor coredump în cazul rulărilor care se termină cu eroare pentru a evita problemele cu spațiul de stocare.</note> | + | **ATENȚIE** să nu postați imagini cu părți din soluția voastră pe forumul pus la dispoziție sau orice alt canal public de comunicație. Dacă veți face acest lucru, vă asumați răspunderea dacă veți primi copiat pe temă. |
- | <note> În cazul în care job-urile vă rămân "agățate", va recomandam să utilizați de pe fep.grid.pub.ro, comanda <code> qstat </code> pentru a vedea câte job-uri aveți pornite, și apoi să utilizați comanda <code>qdel -f <id-sesiune> </code> unde <id-sesiune> sunt primele cifre din stânga, rezultate după comanda **qstat**. | ||
</note> | </note> | ||
- | <note warning> Sesiunile interactive deschise prin qlogin nu sunt permise pe coada ibm-nehalem.q. Va trebui sa utilizati qsub pentru a folosi aceasta coada. </note> | + | |
- | ===== Resurse ===== | + | |
- | * {{:asc:resurse:cluster-cheat-sheet.pdf| Cluster cheat sheet}} | + | |
- | * {{:asc:tema2:skel1.0.zip| Schelet de cod}} | + |