Sunteți pe pagina 1din 7

Algoritmi Paraleli i Distribuiti 2011 2012

Laborator nr. 1

Introducere n OpenMP
1. Prezentare general Acronim: Open Multi-Processing OpenMP reprezint un API (Application Program Interface) prin intermediul cruia se pot dezvolta aplicaii paralele (multi-threaded) bazate pe memorie partajat. Se ofer suport att pentru paralelism la nivel de task, ct i la nivel de bucl.

Fig. 1. Modelul aplicaiilor OpenMP (figura este preluat din [1]) API-ul OpenMP este alctuit din 3 componente importante: directive pentru compilator, librrii runtime, variabile de mediu, i este implementat pentru limbajele C/C++ i Fortran, fiind portat pe majoritatea sistemelor de operare (Unix/Linux, Max OS, Windows). Aplicaiile dezvoltate utiliznd acest API sunt portabile n sensul ca un cod surs recompilat pentru o alt platform se va comporta similar platformei originale (ATENIE: SIMILAR nu IDENTIC!!!). Avantajul OpenMP este acela de a putea combina ntr-o maniera relativ uoar codul secvenial cu cel paralel, fr a fi n general nevoie de a gestiona firele de execuie ale aplicaiei. Caracteristici ale programelor dezvoltate utiliznd OpenMP: toate firele de execuie au acces la aceeai zon partajat de memorie (vezi fig. 1); datele pot fi partajate (n cadrul aceleiai zone comune de memorie) sau private; datele partajate sunt accesibile fiecrui thread din mulimea de lucru; datele private pot fi accesate doar de thread-ul proprietar; transferul datelor se realizeaz ntr-un mod transparent pentru programator; n cadrul oricarei execuii este prezent cel puin un mecanism de sincronizare.

Algoritmi Paraleli i Distribuiti 2011 2012

Laborator nr. 1

Modelul de programare OpenMP [2]: este un model bazat pe memorie partajat, paralelismul fiind bazat pe fire de execuie; paralelismul este explicit, n sensul c se ofer programatorului mecanisme de control pentru gestiunea complet a paralelizrii; este un model de tip fork/join vezi fig. 2: toate programele OpenMP ncep cu un singur fir de execuie denumit thread master; thread-ul master se execut secvenial pn la ntlnirea unui constructor al unei regiuni paralele;

Fig. 2. Modelul de execuie


(figura este preluat din [2])

n momentul ntlnirii unui astfel de constructor, thread-ul master creaz o echip de thread-uri worker prin intermediul unor apeluri de tip fork; secvena de cod prezent ntr-o regiune paralel este executat n paralel de ctre fiecare fir de execuie n parte (inclusiv de ctre thread-ul master); la finalul execuiei secvenei paralele are loc o operaie de sincronizare a thread-urilor (inclusiv masterul), urmat de un set de operaii de tip join n urma carora aplicaia revine doar la firul de execuie master; paralelismul OpenMP se obine de cele mai multe ori prin intermediul directivelor compilator; API-ul OpenMP ofer suport: pentru regiuni paralele de tip nested: regiune paralel construit n cadrul altei regiuni paralele; pentru gestiunea dinamic a numrului de fire de execuie ce sunt utilizate pentru execuia diferitelor regiuni paralele.

Cu toate c OpenMP reprezint un API performant pentru programarea paralel, este important s se cunoasc limitrile acestuia: API-ul nu se adreseaz sistemelor paralele cu memorie partajat distribuit; nu este implementat identic de ctre toi productorii; nu se garanteaz ntotdeauna o utilizare eficient a memoriei comune; nu ofer mecanisme de verificare a accesului datelor partajate: nu verific interdependeele dintre date, nu verific eventualele conflicte ce pot aprea ntre variabile, nu verific dac modificarea unei variabile partajate este realizat sau nu de un singur thread, nu verific blocajele ce pot aprea n cadrul unor programe paralele; nu acoper alte directive specifice compilatoarelor, directive ce pot asista n dezvoltarea unei paralelizri eficiente; nu a fost dezvoltat astfel nct s acopere sincronizarea operaiilor de intrare/ieire.

Algoritmi Paraleli i Distribuiti 2011 2012


2. Componentele OpenMP Directivele compilator sunt n general utilizate pentru construirea regiunilor paralele; sintaxa general (C/C++):
#pragma omp construct [clause [clause] ]

Laborator nr. 1

prin intermediul acestora se poate specifica: modalitatea de partiionare a volumului de lucru ntre thread-uri; modalitatea de sincronizare a thread-urilor; vizibilitatea variabilelor (variabile private, partajate, etc.). Variabilele de mediu specific numrul de thread-uri ce pot fi lansate n executie ($OMP_NUM_THREADS); specific tipul de schedul-er ce poate fi utilizat; specific modurile de ajustare dinamic a thread-urilor n timpul execuiei unui program OpenMP. Librriile runtime sunt reprezentate de un set de funcii necesare interogrii i/sau setarea mediului de lucru (aflarea numrului de procesoare de pe maina de lucru, aflarea numrului total de threaduri ce execut o anumit seciune paralel, etc); au prototipurile funciilor define n <omp.h> (pentru C/C++). programelor OpenMP. Directive compilator de baz.

3. Structura general a Vizibilitatea variabilelor


#include <omp.h>

main () { int var1, var2, *var3; //Serial code . . //Beginning of parallel section. Fork a team of threads. #pragma omp construct [clause [clause]] { int var4, var5; //Parallel section executed by all threads . . //All threads join master thread and disband } //Resume serial code . . }

Cod 1: Structura generala a programelor OpenMP Conceptul fundamental pe care se bazeaz OpenMP n stabilirea zonelor paralele este acela de bloc structurat (eng: structured block). Un bloc structurat reprezint o secven de cod pentru care exist un singur punct de intrare, marcat de inceputul secvenei, i, respectiv, un singur punct de ieire, marcat de terminarea secvenei. Singura excepie admis de la aceast regul este apelarea funciei exit() (n C/C++).

Algoritmi Paraleli i Distribuiti 2011 2012


Exemplu de blocuri structurate i nestructurate [3]:
#pragma omp construct { int id = omp_get_thread_num(); more: res[id] = do_big_job (id); if (conv (res[id]) goto more; } printf (All done\n);

Laborator nr. 1

if (go_now()) goto more; #pragma omp construct { int id = omp_get_thread_num(); more: res[id] = do_big_job(id); if (conv (res[id]) goto done; goto more; } done: if (!really_done()) goto more;

Bloc structurat Bloc nestructurat Cod 2: Exemplu de bloc structurat vs. bloc nestructurat Directivele de baz ale API-ului OpenMP omp parallel Declararea unei regiuni paralele simple (sub forma de bloc structurat) se realizeaz prin intermediul directivei pragma omp parallel.

#pragma omp parallel { //instructiuni } //sfarsitul regiunii paralele

Sintaxa complet a directivei este:


#pragma omp parallel [clause ...] newline if (scalar_expression) private (list) shared (list) default (shared | none) firstprivate (list) reduction (operator: list) copyin (list) num_threads (integer-expression) structured_block

Exemplu de program:
1 2 3 4 5 6 7 8 9 10 #include <stdio.h> int main(void) { printf ("Master thread before omp par\n\n"); #pragma omp parallel { printf ("Hello from team thread\n"); } printf ("\nMaster thread after omp par\n"); return 0; }

Cod 3: Hello OpenMP Nota: Compilarea i rularea programelor ce utilizeaz OpenMP se realizeaz adaugnd opiunea -fopenmp pentru compilatorul standard Linux:
gcc -fopenmp sursa.c -o fila.bin

sau
g++ -fopenmp sursa.cpp -o fila.bin

Algoritmi Paraleli i Distribuiti 2011 2012

Laborator nr. 1

omp for Declararea unui for paralel (sub forma unui bloc structurat) se realizeaz prin intermediul directivei pragma omp for.
#pragma omp parallel { #pragma omp for for (i=0; i<MAX; i++) { res[i] = huge(); } } #pragma omp parallel for for (i=0;i< MAX; i++) { res[i] = huge(); }

Cod 4: Declararea unei bucle for Sintaxa complet a directivei este:


#pragma omp for [clause ...] newline schedule (type [,chunk]) ordered private (list) firstprivate (list) lastprivate (list) shared (list) reduction (operator: list) collapse (n) nowait for_loop

Modul general de operare a unei bucle omp for este descris schematic n exemplul urmtor:
#define N 12 [...] #pragma omp parallel #pragma omp for for(i = 1, i < N+1, i++) c[i] = a[i] + b[i];

Cod 5: Exemplu omp for

Fig. 3. Shema de functionare [3]

Algoritmi Paraleli i Distribuiti 2011 2012


Vizibilitatea variabilelor

Laborator nr. 1

O variabil declarat n exteriorul unui bloc paralel este n mod implicit variabil partajat (vezi n Cod 1 variabilele var1, var2, var3). O variabil declarat n interiorul unui bloc paralel este n mod implicit variabil privat a thread-ului care o declar (vezi n Cod 1 variabilele var4, var5). O prim modificare a vizibilitii variabilelor poate fi realizat prin intermediul clauzelor shared i private. clauza shared (lista de variabile) Dac aceast clauz este prezent n cadrul unei directive pragma omp, atunci toate variabilele prezente n list vor fi partajate ntre firele de execuie lansate de master. API-ul OpenMP asigur mecanisme de gestionare a accesului acestor variabile, dar NU realizeaz nici un fel de sincronizare n mod implicit.

clauza private (lista de variabile) Dac aceast clauz este prezent n cadrul unei directive pragma omp, atunci toate variabilele prezente n lista ataat sunt marcate ca fiind private pentru fiecare thread n parte. Acest lucru nseamn c fiecare variabil din list va fi redeclarat n spaiul de memorie privat ataat fiecrui thread (se menine ca nume i tip de dat), dar NU se vor copia valorile acestor variabile din spaiul de memorie partajat. Modificrile operate asupra variabilelor de tip private sunt vizibile numai n cadrul thread-ului, nu i n exterior.

4. Funcii pentru interogarea/setarea mediului de lucru

int omp_get_thread_num(void)

Funcia returneaz ID-ul thread-ului n cadrul mulimii de thread-uri. Dac este apelat n cadrul unei regiuni secveniale, atunci funcia va returna ntotdeauna valoarea 0, altfel, dac este apelat ntr-o regiune paralel, va returna o valoarea cuprins ntre 0 i n-1, unde n reprezint numrul total de thread-uri alocat pentru regiunea paralel. Thread-ul master va avea ntotdeauna ID-ul 0.

int omp_get_num_threads(void)

Funcia returneaz numrul total de thread-uri lansate n cadrul unei regiuni paralele. Dac funcia este apelat n afara unei regiuni paralele, atunci va returna ntotdeauna valoarea 1.

void omp_set_num_threads(int)

Functia poate fi utilizata pentru a seta numarul de thread-uri ce vor fi lansate in executie pentru urmatoarea regiune paralela. Valoarea transmisa trebuie sa fie strict pozitiva. Functia nu are sens in cazul in care directiva compilator include clauza num_threads si actioneaza independent de variabila de mediu OMP_NUM_THREADS.

int omp_get_num_procs(void)

Funcia poate fi utilizat pentru a determina numrul de procesoare active din sistem. Comportamentul funciei este acelai indiferent de regiunea n care este apelat.

5. Probleme 1. Implemenati exemplul descris n Cod 3, compilai i lansai n execuie. Testai comportarea funciilor descrise n cadrul paragrafului 4. 2. Implementai o aplicaie OpenMP care s realizeze produsul dintre o matrice de dimensiune NxN i un vector de dimensiune N. Se va considera N=1000 (cel puin) i se va varia numarul de thread-uri al aplicaiei. Pentru fiecare rulare se vor msura timpii implicai.

Algoritmi Paraleli i Distribuiti 2011 2012

Laborator nr. 1

3. Implementai o aplicaie OpenMP care s realizeze ridicarea la ptrat a unei matrici de dimensiune NxN. Se va considera N=500 (cel puin) i se va varia numrul de thread-uri al aplicaiei. Pentru fiecare rulare se vor msura timpii implicai. Bibliografie: 1. Ruud van der Pas, An Introduction Into OpenMP, IWOMP 2005 University of Oregon, Eugene, Oregon, USA June 1-4, 2005 2. Blaise Barney, OpenMP, Lawrence Livermore National Laboratory,
https://computing.llnl.gov/tutorials/openMP/

3. Intel Software College, Programming with OpenMP 4. http://gcc.gnu.org/onlinedocs/libgomp/Runtime-Library-Routines.html#Runtime-Library-Routines