Nahajate se tukaj

Programiranje z deljenim spominom v OpenMP

OpenMP je način paralelnega programiranja v načinu, ko je več proceorjev priklopljeno na skupen spomin. Glavna prednost takega programiranja je enoten naslovni prostor preko celotnega spominskega sistema

  • vsak procesor lahko bere in piše na vse spominske lokacije
  • eden logičen spominski prostor
  • vsi procesorji naslavjlajo spomin z istim naslovom

 

Težave pri OpenMP so, da idealna struktura pri večjih sistemi ni mogoča in običajno obstaja naslednja oblika z hierarhičnim načinom povezave procesorjev in spomina preko hitre mreže.

Komunikacija je lahko problematična in zato je pomembno, kako se uporablja vmesni in lokalni spomin (cache).

Programiranje z deljenim spominom (shared memory) je enostavno. Pri standardizaciji se je najbolj uveljavil OpenMP, ki upravlja z nitmi na način predprocesorskih direktiv, kar napišemo kot direktivo, ki se normalno ne prevaja

  • Fortran:
    !$OMP (ali C$OMP ali *$OMP za F77)
    
  • C/C++:
     #pragma omp

Osnova vzporednega programiranja je območje parallel, ki definira področje programa.

Skupni in zasebni podatki

  • Znotraj področja parallel so spremenljivke lahko deljene oz. skupne (shared) ali zasebne (private)
  • Vse niti vidijo isto kopijo skupnih spremenljivk
  • Vse niti lahko berejo ali pišejo v skupne spremenljivke
  • Vsaka nit ima svojo kopijo zasebnih spremenljivk. Te se nevidne za druge niti
  • Zasebna spremenljivka se lahko bere ali piše le v niti, ki si jo lasti
  • Zasebne spremenljivke nimajo začetne vrednosti in jih je potrebno inicializirati na začetku paralelnega območja
  • Skupne spremenljivke, ki jih uporabljamo le za branje lahko prosto uporabljamo v vseh paralelnih območjih
do i = 1, 100
  a(i) = a(i) + b(i)
end do

Za sinhronizacijo pisanja in branja deljenih spremenljivk skrbi OpenMP. Če sinhronizacija blokira računanje niti je bolje uporabiti delno izračunavanje, ki se združi na koncu z redukcijo v eno samo spremenljivko, kar je uporabno za veliko računskih operacij. Naslednji primer je primeren za redukcijo

b = 0;
for (i=0; i++; i<N)
  b += i;

Za prevajanje z OpenMP uporabimo direktivo -mp, kar je odvisno tudi od pevajalnika in jezika

  • GNU Fortran: f95 -mp -o prog prog.f
  • GNU C: gcc -mp -o prog prog.c
  • Intel Fortran: ifort -openmp -o prog prog.f
  • Intel C: icc -openmp -o prog prog.c

Gnezdenje in posvojitve

Gnezdenje zank (nesting) je dovoljeno v OpenMP kar se vključi s sistemsko spremenljivko OMP_NESTED ali klicem podprograma OMP_SET_NESTED. Če je vklopljeno, potem se bo pri vsaki direktivi PARALLEL vzpostavila nova množica niti.

Posvojitve (orphaned directives) so aktivne v dinamičnem pogledu, kar omogoča modularno programiranje s podprogrami. Primer

!$OMP PARALLEL
    call fred()
!$OMP END PARALLEL

subroutine fred()
!$OMP DO
  do i = 1,n
    a(i) = a(i) + 23.5
   end do
  return
end

v katerem se podprogram fred kIiče vzporedno; vendar se zanka razdeli na niti dinamično in ne samo leksično. Podprogram fred() se je tako posvojil in vsaka nit izračunava le del deljenega polja a(i).

Druge značilnosti OpenMP

  • Na nekaterih sistemih je mogoče uporabiti dinamični paralelizem, ki omogoča sistemu, da sam izbere število niti. Število niti bo enako ali manjše tistim, ki jih je nastavil uporabnik. Vkopi se z rutino OMP_SET_DYNAMIC ali sistemsko spremenljivko OMP_DYNAMIC.
  • Lokalne kopije globalnih spremenljivk so včasih uporabne. Določa se jih z direktivo THREADPRIVATE.
  • Stavek COPYIN prav zaprav klopira podatkeTHREADPRIVATE  za posamezne niti iz glavne niti.
    • common /junk/ nx
       common /stuff/ a,b,c
      !$OMP THREADPRIVATE (/JUNK/,/STUFF/)
        nx = 32
        c = 17.9
        . . .
      !$OMP PARALLEL PRIVATE(NX2,CSQ) COPYIN(/JUNK/,C)
        nx2 = nx * 2
        csq = c*c
  • Lokalne spremenljivke lahko kopiramo tudi nazaj v glavno nit z direktivo COPYPRIVATE
    • !$OMP PARALLEL PRIVATE(A,B)
      ...
      !$OMP SINGLE
         READ(24) A
      !$OMP END SINGLE COPYPRIVATE(A)
         B = A*A
         ...
      !$OMP END PARALLEL
  •  Pogojno prevajanje je uporabno za pisanje programov, ki se lahko prevedejo z različnimi prevajalniki. Tudi tisitmi, ki OpenMP nimajo in lahko kodo, ki ima klicanje OpenMP podprogramov še vedno prevedemo serijsko.
  • Vhod/izhod. Lahko predpostavimo, da je pisanje in branje večnitno varno. Možna pa so prepletanja niti, kar povzroča nesinhronizirano pisanje v datoteko. Ni pa možno, da vi imele posamezne niti zasebna mesta za pisanje. Možno pa je, da imajo posamezne niti zasebne datoteke v katere pišejo ali berejo.

Zmogljivost in slabosti OpenMP

Obstaja pet glavnih vzrokov za slabšo zmogljivost programov z deljenim spominom:

  • sekvenčna koda
  • komunikacija
  • neuravnovešenost dela posameznih niti
  • sinhronizacija
  • slaba optimizacija s strani prevajalnika

OpenMP in MPI

V novejšem času se uporabljajo arhitekture sestavov (cluster) kar predstavlja tudi možnost za kombiniranje OpenMP in MPI.

 

Motivacija z skupno programiranje OpenMP in MPI je lahko v

  • Prenašanje podatkov z MPI je lahko veliko
  • Slabo skaliranje MPI kode
  • Omejeno število MPI procesov zaradi knjižnic ali velikega števila procesov in s tem komunikacije.
  • MPI implementacija ni primerna za SMP sestave