Differences

This shows you the differences between two versions of the page.

Link to this comparison view

app:laboratoare:03 [2022/10/23 14:05]
florin.mihalache [Exerciții]
app:laboratoare:03 [2024/10/22 11:06] (current)
alexandru.bala [Tasks (opțional)]
Line 1: Line 1:
-===== Laboratorul 3 - Advanced OpenMP ===== +====== Laboratorul 3 - Advanced OpenMP ​====== 
-==== Sections ==== +===== Sections ​===== 
 Uneori dorim să distribuim ca thread-uri diferite să execute task-uri diferite în același timp. În această privință ne vine de ajutor conceptul de sections, prin care două sau mai multe thread-uri execută două sau mai multe sections corespunzătoare acestora (adică thread-urilor,​ fiecare thread cu un section). Uneori dorim să distribuim ca thread-uri diferite să execute task-uri diferite în același timp. În această privință ne vine de ajutor conceptul de sections, prin care două sau mai multe thread-uri execută două sau mai multe sections corespunzătoare acestora (adică thread-urilor,​ fiecare thread cu un section).
  
Line 56: Line 56:
 {{ :​app:​laboratoare:​sections.png?​400 |}} {{ :​app:​laboratoare:​sections.png?​400 |}}
  
-==== Single ====+===== Single ​=====
 Dacă dorim ca o secvență de cod (dintr-o bucată de cod paralelizat) să fie executat doar de un singur thread, folosim directiva ''​SINGLE''​. Aceasta este folosită, de regulă, în operații I/O. Dacă dorim ca o secvență de cod (dintr-o bucată de cod paralelizat) să fie executat doar de un singur thread, folosim directiva ''​SINGLE''​. Aceasta este folosită, de regulă, în operații I/O.
  
Line 70: Line 70:
 </​code>​ </​code>​
  
-=== Master ===+==== Master ​====
 Directiva ''​MASTER''​ este o particularizare a directivei ''​SINGLE'',​ unde codul din zona paralelizată este executat de thread-ul master (cel cu id-ul 0). Directiva ''​MASTER''​ este o particularizare a directivei ''​SINGLE'',​ unde codul din zona paralelizată este executat de thread-ul master (cel cu id-ul 0).
 <code c> <code c>
Line 82: Line 82:
 </​code>​ </​code>​
  
-==== Construcții de sincronizare ==== +===== Construcții de sincronizare ​===== 
-=== Mutex ===+==== Mutex ====
 Pentru zonele critice, unde avem operații de read-write, folosim directiva ''#​pragma omp critical'',​ care reprezintă un mutex, echivalentul lui ''​pthread_mutex_t''​ din pthreads, care asigură faptul că un singur thread accesează zona critică la un moment dat, thread-ul deținând lock-ul pe zona critică în momentul respectiv, și că celelalte thread-uri care nu au intrat încă în zona critică așteaptă eliberarea lock-ului de către thread-ul aflat în zona critică în acel moment. Pentru zonele critice, unde avem operații de read-write, folosim directiva ''#​pragma omp critical'',​ care reprezintă un mutex, echivalentul lui ''​pthread_mutex_t''​ din pthreads, care asigură faptul că un singur thread accesează zona critică la un moment dat, thread-ul deținând lock-ul pe zona critică în momentul respectiv, și că celelalte thread-uri care nu au intrat încă în zona critică așteaptă eliberarea lock-ului de către thread-ul aflat în zona critică în acel moment.
  
Line 105: Line 105:
 </​code>​ </​code>​
  
-=== Barieră === +==== Barieră ​==== 
-Un alt element de sincronizare reprezintă bariera, care asigură faptul că niciun thread gestionat de barieră nu trece mai departe de aceasta decât atunci cand toate thread-urile gestionate de barieră au ajuns la punctul unde se află bariera.+Un alt element de sincronizare ​îl reprezintă bariera, care asigură faptul că niciun thread gestionat de barieră nu trece mai departe de aceasta decât atunci cand toate thread-urile gestionate de barieră au ajuns la punctul unde se află bariera.
  
 În OpenMP, pentru barieră avem directiva ''#​pragma omp barrier'',​ echivalent cu ''​pthread_barrier_t''​ din pthreads. În OpenMP, pentru barieră avem directiva ''#​pragma omp barrier'',​ echivalent cu ''​pthread_barrier_t''​ din pthreads.
Line 127: Line 127:
 </​code>​ </​code>​
  
-=== Reduction ===+==== Reduction ​====
 ''​reduction''​ este o directivă folosită pentru operații de tip reduce / fold pe arrays / colecții sau simple însumări / înmulțiri în cadrul unui loop. Mai precis, elementele dintr-un array sau indecșii unui loop sunt "​acumulați"​ într-o singură variabilă, cu ajutorul unei operații, al cărui semn este precizat. ''​reduction''​ este o directivă folosită pentru operații de tip reduce / fold pe arrays / colecții sau simple însumări / înmulțiri în cadrul unui loop. Mai precis, elementele dintr-un array sau indecșii unui loop sunt "​acumulați"​ într-o singură variabilă, cu ajutorul unei operații, al cărui semn este precizat.
  
 Tipar: ''​reduction(operator_operatie:​variabila_in_care_se_acumuleaza)''​ Tipar: ''​reduction(operator_operatie:​variabila_in_care_se_acumuleaza)''​
  
-Exemplu de reduction: ''​reduction(+:​sum)'',​ unde se însumează ​elementele ​unui array în variabila sum+Exemplu de reduction: ''​reduction(+:​sum)'',​ unde se însumează ​indecșii ​unui loop în variabila sum
  
 Exemplu de folosire de reduction: Exemplu de folosire de reduction:
Line 144: Line 144:
 </​code>​ </​code>​
  
-=== Atomic ===+==== Atomic ​====
 Directiva ''​ATOMIC''​ permite executarea unor instrucțiuni în mod atomic, instrucțiuni care provoacă race conditions între thread-uri, problemă pe care această directivă o rezolvă. Directiva ''​ATOMIC''​ permite executarea unor instrucțiuni în mod atomic, instrucțiuni care provoacă race conditions între thread-uri, problemă pe care această directivă o rezolvă.
  
Line 166: Line 166:
 </​code>​ </​code>​
  
-=== Ordered === +==== Ordered ​==== 
-Directiva ''​ORDERED''​ este folosit în for-uri cu scopul de a distribui în ordine iterațiile către thread-uri.+Directiva ''​ORDERED''​ este folosită în for-uri cu scopul de a distribui în ordine iterațiile către thread-uri.
  
 Exemplu: Exemplu:
Line 202: Line 202:
   * ''​COPYIN''​ - asignarea unei variabile ''​THREADPRIVATE''​ este vizibilă tuturor thread-urilor   * ''​COPYIN''​ - asignarea unei variabile ''​THREADPRIVATE''​ este vizibilă tuturor thread-urilor
  
-==== Tasks (opțional) ​==== +===== Tasks ===== 
-Task-urile în OpenMP reprezintă un concept prin care putem să avem thread pools pentru paralelizarea de soluții ale căror dimensiune nu o știm (echivalent cu ExecutorService din Java). Un task este executat la un moment dat de către un thread din thread pool.+Task-urile în OpenMP reprezintă un concept prin care putem să avem thread pools pentru paralelizarea de soluții ale căror dimensiune nu o știm (echivalent cu ''​ExecutorService'' ​din Java). Un task este executat la un moment dat de către un thread din thread pool.
  
-Pentru crearea unui task se folosește directiva TASK:+Pentru crearea unui task se folosește directiva ​''​TASK''​:
 <code c> <code c>
 #pragma omp task [clause1 [[,] clause2, ...]] #pragma omp task [clause1 [[,] clause2, ...]]
 </​code>​ </​code>​
-Pentru sincronizarea task-urilor (în sensul să așteptăm toate rezultatele task-urilor,​ în stilul barierei), se folosește directiva TASKWAIT (exemplu de folosire în exemplul Fibonacci de mai jos).+Pentru sincronizarea task-urilor (în sensul să așteptăm toate rezultatele task-urilor,​ în stilul barierei), se folosește directiva ​''​TASKWAIT'' ​(exemplu de folosire în exemplul Fibonacci de mai jos).
  
 În privința variabilelor dintr-un task, aici avem trei variante de variabile: În privința variabilelor dintr-un task, aici avem trei variante de variabile:
  
-  * shared - toate task-urile au acces la aceeași adresă a unei variabile, o modificare asupra variabilei din partea unui task va fi vizibilă către toate task-urile (uneori putem avea potențial de erori în acest caz). +  * ''​shared'' ​- toate task-urile au acces la aceeași adresă a unei variabile, o modificare asupra variabilei din partea unui task va fi vizibilă către toate task-urile (uneori putem avea potențial de erori în acest caz). 
-  * firstprivate - fiecare task va avea o copie a unei variabile inițializate cu o valoare înainte de crearea task-ului respectiv. +  * ''​firstprivate'' ​- fiecare task va avea o copie a unei variabile inițializate cu o valoare înainte de crearea task-ului respectiv. 
-  * private - aici putem să avem variabile care nu sunt inițializate înainte de crearea task-ului și care să fie inițializate în cadrul task-ului.+  * ''​private'' ​- aici putem să avem variabile care nu sunt inițializate înainte de crearea task-ului și care să fie inițializate în cadrul task-ului.
  
 <code c> <code c>
Line 276: Line 276:
   * la sections putem avea overhead și load balancing slab   * la sections putem avea overhead și load balancing slab
  
-==== Exerciții ==== +===== Exerciții ​===== 
-1) Paralelizați fișierul ''​main.c''​ din [[https://​github.com/​cs-pub-ro/​app-labs/​tree/​master/​lab3/​skel | schelet]], unde se citește un fișier, unde pe prima linie se află numărul de elemente pentru un array și pe următoarea linie se află array-ul respectiv, se face suma numerelor (aici faceți în trei moduri, separat, cu ''​reduction'',​ cu ''​atomic''​ și cu ''​critical'',​ unde veți măsura timpii de execuție - hint, folosiți directiva master ca un singur thread să facă măsurătorile),​ iar la final, cu ajutorul ''​sections'',​ scrieți timpii de execuție în trei fișiere (este deja implementată funcția de scriere în fișier).+  ​* ​Paralelizați fișierul ''​main.c''​ din [[https://​github.com/​cs-pub-ro/​app-labs/​tree/​master/​lab3/​skel | schelet]], unde se citește un fișier, unde pe prima linie se află numărul de elemente pentru un array și pe următoarea linie se află array-ul respectiv, se face suma numerelor (aici faceți în trei moduri, separat, cu ''​reduction'',​ cu ''​atomic''​ și cu ''​critical'',​ unde veți măsura timpii de execuție - hint, folosiți directiva master ca un singur thread să facă măsurătorile),​ iar la final, cu ajutorul ''​sections'',​ scrieți timpii de execuție în trei fișiere (este deja implementată funcția de scriere în fișier).
  
 <note tip>O să aveți nevoie de barieră la citire și înainte de scrierea în fișiere.</​note>​ <note tip>O să aveți nevoie de barieră la citire și înainte de scrierea în fișiere.</​note>​
Line 283: Line 283:
 <​note>​De probă, încercați să puneți ORDERED la for-urile paralelizate,​ pentru a vedea cum este afectată performanța.</​note>​ <​note>​De probă, încercați să puneți ORDERED la for-urile paralelizate,​ pentru a vedea cum este afectată performanța.</​note>​
  
-2) **(opțional)** Paralelizați folosind task-uri codul din [[https://​github.com/​cs-pub-ro/​app-labs/​blob/​master/​lab3/​skel/​tree.c | tree.c]] (folosiți task-uri în funcțiile ''​preorder''​ și ''​height''​ - la ultima trebuie să folosiți ''​taskwait''​).+  ​* Paralelizați folosind task-uri codul din [[https://​github.com/​cs-pub-ro/​app-labs/​blob/​master/​lab3/​skel/​tree.c | tree.c]] (folosiți task-uri în funcțiile ''​preorder''​ și ''​height''​ - la ultima trebuie să folosiți ''​taskwait''​).
  
-==== Resurse ==== +===== Resurse ​===== 
-[[https://icl.cs.utk.edu/classes/cosc462/2017/ | Cursuri de OpenMP, MPI, CUDA - COSC462]]+ 
 +  - [[https://stackoverflow.com/​questions/​18669296/​c-openmp-parallel-for-loop-alternatives-to-stdvector | User-defined OpenMP Reduction]] 
 +  - [[https://​stackoverflow.com/​questions/​18022133/​difference-between-openmp-threadprivate-and-private |Difference between OpenMP threadprivate and private]] 
 +  - [[https://​learn.microsoft.com/en-us/cpp/parallel/openmp/​reference/​openmp-clauses?​view=msvc-170 ​| OpenMP ​Clauses]]
app/laboratoare/03.1666523112.txt.gz · Last modified: 2022/10/23 14:05 by florin.mihalache
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0