Friday, July 5, 2019

programare paralela exercitii

APD - Lab1
2007

programare (impartire problema in subprobleme)
Firele de executie se creeaza in cadrul unui proces si se creeaza mai repede decat procesele.

Algoritmi paraleli si distribuiti, curs an 5
Corina Stratan: corina@cs.pub.ro
Limbaje pentru prelucrare paralela: SR, Paralaxis, biblioteci pentru programe C
Ex:
- OpenMP: creare de fire de executie; OpenMP e portabil (pthreads din C e specific Linux)
- MPI: message passing interface: pe sisteme distribuite, intre care se schimba mesaje
- Java: suporta nativ fire de executie
Comunicarea se poare face:
- In fire de executie separate, cu resurse partajate
Prin mesaje, intre procese, eventual chiar intre
masini separate
-
Open MP
Compilator: Omni Open MP
Comanda: ompcc (similar gcc): ex "ompcc -o program program.c"
De inclus header: #include <omp.h>
De setat o variabila de mediu: "export OMPC_NUM_PROCS = 5"
Numarul de fire de executie nu trebuie sa fie fix, depinzand
de masina pe care ruleaza. Open MP incearca sa aloce
automat firele de executie.
Program OpenMP: fork-join
Pretate la cicluri mari.
Fork la creare de fire, join la terminarea calculelor.
Directive pragma: pentru compilator, optiuni specifice date de programator; compilatorul ce nu
recunoaste pragma-urile le ignora
Directivele actioneaza asupra unei regiuni de cod, intre {}.
Pentru o linie de cod sau o singura instructiune compusa nu e nevoie de {}.
#pragma omp <directiva> [clauze]
Directiva de creare a unei regiuni paralele:
#pragma omp parallel
//cod
{
}
#pragma omp parallel num_threads(5)
Sau:
Apelata inaintea crearii regiunii paralele. La directiva parallel se creeaza automat 5
threaduri.
omp_set_num_threads(5);
1: dinamic, 0: static
Setarea din variabila de mediu il face sa considere automat ca are atatea procesoare cate
s-au specificat, nu mai e nevoie de dynamic
omp_set_dynamic(0);
Cate threaduri sunt in mod curent
Rulat in regiune paralela, arata cate threaduri ruleaza acolo; in afara regiunii paralele (ar
trebui sa arate) numarul definit la set_num_threads()
int omp_get_num_threads();
Ce id are thradul curent
int omp_get_thread_num();
Program OpenMP de adunare a doi vectori:
Primul thread aduna primele x elemente, al doilea urmatoarele y, etc… vectorul A+B=C
#pragma omp parallel
Int id, I, Nthreads, istart, iend; //indici intre care ruleaza fiecare thread
Id = omp_get_thread_num();
Nthreads = omp_get_num_threads();
Istart = id * N / Nthreads;
Iend = (id+1) * N / Nthreads;
c[i]=a[i]+b[i];
For(i=istart, i<iend;i++)
{
}
Clauze: optiuni la directive
Va incepe sa execute in paralel cu toate threadurile
disponibile zona de cod.
Forteaza 5 threaduri.
De fapt va aloca atatea threaduri cate procesoare are, deci
poate sa aloca mai putine (5 e un maxim).
a
b
c
N elemente
Pot fi impartite
in mod egal intre
threaduri
istart iend
A
Alta directiva, for, generaaza threadurile automat:
#pragma omp parallel
#pragma omp for
c[i]=a[i]+b[i];
For(i=0, i<N, i++)
Race condition: rezultat nedeterminist
Diferenta fata de cod in afara "parallel": executata de mai multe
threaduri, dar nu simultan
Codul din afara "parallel" este executat o singura data doar de
threadul master.
Regiune critica: secventa de cod care nu poate fi executata la un
moment dat decat de un singur thread
La sfarsitul regiunii paralele este o bariera implicita; nu se iese din
directiva parallel sau for pana cand n-au ajuns toate threadurile
acolo
Bariera: punct In program la care se asteapta toate threadurile sa
ajunga inainte de a se trece mai departe
#pragma omp critical
{
{
#pragma omp barrier
{
}
Obs:
#pragma omp parallel for
Iterativ:
#include<stdio.h>
#include<stdlib.h>
#include <omp.h>
static long num_steps = 10000;
double step;
void main()
int I;
double x,pi,sum=0.0;
step = 1.0/(double)num_steps;
for(i=1;i<num_steps;i++)
x=(i-0.5)*step;
sum=sum+4.0/(1.0+x*x);
{
}
pi=step*sum;
{
}
pentru paralelizare, s-ar putea pune sum= intr-o regiune critica
altfel,
un vector de sume si fiecare thread calculeaza suma lui
sau,
ce operatie se face la reducere (adunare) si cu ce variabila (sum)
#pragma parallel for reduction(+:sum)
Reducere = operatia de reunire a threadurilor
Paralelizare:
(in shell: ) export OMPC_NUM_PROCS=4
(fara export-ul de mai sus, programul da eroare la rulare
spunand ca nu poate aloca 4 threaduri, conform lui
opm_set_num_threads(), ci doar unul)
#include<stdio.h>
#include<stdlib.h>
#include <omp.h>
static long num_steps = 10000;
double step;
int main()
int i;
double x,pi,sum=0.0;
step = 1.0/(double)num_steps;
omp_set_num_threads(4)
{
#pragma omp parallel for reduction (+:sum)
for(i=1;i<num_steps;i++)
x=(i-0.5)*step;
sum=sum+4.0/(1.0+x*x);
{
}
{
pi=step*sum;
}
}


....................................





Salut, am nevoie de putin ajutor cu un program in C. Am scris varianta secventiala si acum vreau sa il fac in paralel cu openmp. Codul arata ceva de genul.Am nevoie de o marire dependenta de numarul de threaduri, spre ex pt 2 threaduri sa ruleze de 2 ori mai repede,cum e si normal. Aceasta este doar bucata de cod din main care conteaza , mai sus am doar declaratii si citire din fisier. Daca se pricepe cineva si ma poate ajuta cu scrierea lui corecta, nu ma pricep asa bine cu openmp.Thx

Cod:
int an_curent=1;
#pragma omp parallel shared(resurse,preturi,buget,cost_minim,costres_minim) private(i,j,k,l)
 while(an_curent <= nr_ani){
  //resetare valori ce tin costul,contorii resurselor
  for(i=0;i<nr_ani;i++){
    resurseA[i]=0;
    resurseB[i]=0;
    pretmaxA[i]=0;
    pretmaxB[i]=0;
  }
 
  for(i=0;i<n;i++)
   for(j=0;j<n;j++){
    cost_minim[i][j]=50000;
    costres_minim[i][j]=50000;
   }
  //activitati anuale
#pragma omp for 
  for(i=0;i<n;i++)
   for(j=0;j<n;j++){
    //int cost_minim=100; //pastrez costul cel mai mic al resurselor complementare gasite
    int cost_curent=0; //costul resursei gasite la pasul curent
    int resursa_complement;
    if(resurse[i][j] == 0)
     resursa_complement=1;
    if(resurse[i][j] == 1)
     resursa_complement=0;
    //caut printre colonisti cine are resursa de tipul resursa_complement
    for(k=0;k<n;k++)
     for(l=0;l<n;l++){
      //caut cost complementar minim
      if(resurse[k][l] == resursa_complement){ //am gasit un colonist cu resursa necesara
       cost_curent=preturi[k][l] + dist(i,k,j,l);
       if(cost_curent < cost_minim[i][j]){
        //printf("fost cost=%d,nou cost=%d\n",cost_minim,cost_curent);
        cost_minim[i][j]=cost_curent;
       }
      }
      //caut costRes minim
      if(resurse[k][l] ==(1- resursa_complement)){ //am gasit un colonist cu resursa necesara
       cost_curent=preturi[k][l] + dist(i,k,j,l);
       if(cost_curent < costres_minim[i][j]){
        //printf("fost cost=%d,nou cost=%d\n",cost_minim,cost_curent);
        costres_minim[i][j]=cost_curent;
       }
      }
     }//end for k    
   }//end for i

  //verific cost vs buget pentru colonistul curent
#pragma omp for
  for(i=0;i<n;i++)
   for(j=0;j<n;j++){
    int buget_curent=buget[i][j];
    if(cost_minim[i][j] > buget_curent){
     preturi[i][j]=preturi[i][j]+cost_minim[i][j] - buget[i][j];
     buget[i][j]=cost_minim[i][j];
     if(preturi[i][j] > pmax){
      resurse[i][j]=1-resurse[i][j];
      buget[i][j]=pmax;
      preturi[i][j]=(pmin + pmax)/2;
     }
    }
    if(cost_minim[i][j] < buget_curent){
     preturi[i][j]+=(cost_minim[i][j]-buget[i][j])/2;
     buget[i][j]=cost_minim[i][j];
     if(preturi[i][j] < pmin)
      preturi[i][j] = pmin;
     
     
    }
    if(cost_minim[i][j] == buget_curent){
     preturi[i][j]=costres_minim[i][j]+1;
     if(preturi[i][j] > pmax){
      resurse[i][j]=1-resurse[i][j];
      buget[i][j]=pmax;
      preturi[i][j]=(pmin + pmax)/2;
     } 
    }
   }
  //numar colonistii cu resurseA ,resp resurseB
#pragma omp for
  for(i=0;i<n;i++)
   for(j=0;j<n;j++){
    if(resurse[i][j] == 0){
#pragma omp atomic
     resurseA[an_curent-1]+=1;
    }
    if(resurse[i][j] == 1)
#pragma omp atomic
     resurseB[an_curent-1]+=1;
   }
  //caut pretul maxim al resursei A resp al resurseiB
#pragma omp for
  for(i=0;i<n;i++)
   for(j=0;j<n;j++){
    if(resurse[i][j] == 0){
     if(preturi[i][j] > pretmaxA[an_curent-1])
      pretmaxA[an_curent-1]=preturi[i][j];
    }
    if(resurse[i][j] == 1){
     if(preturi[i][j] > pretmaxB[an_curent-1])
      pretmaxB[an_curent-1]=preturi[i][j];
    } 
   }
  char line[128];
  sprintf(line,"%d %d %d %d\n",resurseA[an_curent-1],pretmaxA[an_curent-1],resurseB[an_curent-1],pretmaxB[an_curent-1]);
  writeToFile(out,line);
  if(an_curent==nr_ani)
#pragma omp for
   for(i=0;i<n;i++){
    for(j=0;j<n;j++){
     sprintf(line,"(%d,%d,%d) ",resurse[i][j],preturi[i][j],buget[i][j]);
     writeToFile(out,line);
    }
    writeToFile(out,"\n");
   }
  an_curent++;
 }
ansin este deconectat
Răspunde cu citat Top
Necitit 03.11.2012, 22:45#2
Avatarul lui Caesar
Senior Member
Locație: Iasi
Posturi: 430
Putere Rep: 12 
Reputație: 351
Caesar are multe de care să fie mândruCaesar are multe de care să fie mândruCaesar are multe de care să fie mândruCaesar are multe de care să fie mândru
Nou
Ok, să-ți scriu câteva idei. Începem cu începutul, și anume:

1. Executarea în paralel a unui set de operații pe n thread-uri nu va fi niciodată de n ori mai rapidă; aceasta findcă crearea acestor thread-uri consumă și ea timp. Astfel, un spor de performanță se poate observa doar pentru thread-uri cu un număr mare/foarte mare de pași. În cazul în care se crează tread-uri separate pentru un număr mic de operații, se vor înregistra scăderi de performanță.

2. Codul de mai sus... nu e foarte ordonat; iar variabilele nu au nume foarte sugestive. Încearcă, în primul rând, să-l grupezi în câteva funcții separate; e destul de greu datorită operațiilor și for-urilor paralele, dar măcar pașii principali ai algoritmului.

3. Strâns legat de (2), cred că tu scrii cod C, iar în exemplul tău ai câteva artificii care sunt permise doar în C++, și anume declararea unor variabile locale în corpul funcției, dar nu la începutul acesteia.

4. Ne-ar ajuta enunțul problemei (cel puțin pentru a înțelege denumirile variabilelor).

De obicei funcționează varianta cu rezolvarea problemei inițial secvențial și-apoi modificare în paralel.

1. Nu prea ajută creare de operații paralele în interiorul altor operații paralele; trebuie ținut oarecum cont și de faptul că un procesor are un număr limitat de nuclee și thread-uri (fizice). Astfel un număr foarte mare de thread-uri în paralel nu prea ajută; mai mult, trebuiesc evitate operațiile de creare și distrugere ale acestora.
Ca și obiectiv/mod de rezolvare: atunci când ai un număr de câteva for-uri (sau alte instrucțiuni repetitive) imbricate, trebuie să-ncerci să faci paralel doar for-ul de la exterior (sau cât mai la exterior posibil, în funcție de algoritm).

2. Trebuiesc identificate resursele (variabilele) folosite în operațiile executate în paralel și clasificarea acestora în funcție de modul în care acestea sunt folosite:
- resurse folosite individual (private) pe fiecare thread în parte, de exemplu contorii (ij) folositi pentru parcurgerea unui tablou;
- resurse comune (de obicei shared) pe mai multe thread-uri, de exemplu un tablou parcurs în paralel.

3. Se pune întrebarea: rezultatele obținute pe un thread sunt direct influențabile de operațiile executate pe alt thread? Se pot obține astfel rezultate false?
Mi-e greu să fac această întrebare clară. Ține în primul rând de variabilele shared; dacă acestea sunt modificate pe un thread, rezultatele calculelor efectuate pe un al doilea thread vor mai fi corecte, presupunând că acesta a luat valorile modificate?
În plus, dacă nu se specifică (prin niște directive mai pompoase) ordinea în care se vor executa thread-urile, aceasta va fi aleatoare/necunoscută.

* De menționat că este de preferat folosirea #parallel for în locul unui simplu #parallel, acolo unde este posibil; în cazul #parallel for, contorul din interiorul forului este implicit variabilă private.


Sunt sigur că am menționat mai multe lucruri pe care, de voie, de nevoie, le știai deja, dar e bine să le ai notate undeva, să fie clare, să nu le uiți.
__________________
HARDWARE = Parte a unui calculator pe care o lovesti cand apar probleme de software.

No comments:

Post a Comment