openmp
Loop parallelism i OpenMP
Sök…
parametrar
Klausul | Parameter |
---|---|
private | Kommaseparerad lista över privata variabler |
firstprivate | Som private , men initialiserat till värdet på variabeln innan du går in i slingan |
lastprivate | Som private , men variabeln får värdet som motsvarar den sista iterationen av slingan vid utgången |
reduction | reduktionsoperatör : kommaseparerad lista över motsvarande reduktionsvariabler |
schedule | static , dynamic , guided , auto eller runtime med valfri storleksstorlek efter koma för de 3 tidigare |
collapse | Antal perfekt kapslade öglor för att kollapsa och parallellisera tillsammans |
ordered | Berättar att vissa delar av slingan måste hållas i ordning (dessa delar identifieras specifikt med vissa ordered klausuler inuti slingkroppen) |
nowait | Ta bort den implicita barriären som finns i slutet av slingkonstruktionen |
Anmärkningar
Betydelsen av schedule
är följande:
-
static[,chunk]
: Fördela statiskt (vilket innebär att fördelningen görs före inträdet i slinga) sling iterationer i satsvis avchunk
storlek i en round-robin-sätt. Omchunk
inte anges, då bitar är så jämn som möjligt och varje tråd får högst en av dem. -
dynamic[,chunk]
: Fördela sling iterationer bland trådarna genom satser avchunk
storlek med en först till kvarn-först mala ordning, tills inga sats lämningar. Om det inte anges ärchunk
inställd på 1 -
guided[,chunk]
: Somdynamic
men med partier vilka storlekar blir mindre och mindre, ner till 1 -
auto
: Låt kompilatorn och / eller körtidsbiblioteket bestämma vad som passar bäst -
runtime
: Avlägsna beslutet vid körning med hjälp avOMP_SCHEDULE
miljövariabeln. Om miljövariabeln inte är definierad vid körtid kommer standard schemaläggning att användas
Standard för schedule
är implementeringsdefiniera . I många miljöer är den static
, men kan också vara dynamic
eller mycket väl kunna vara auto
. Var därför försiktig så att din implementering inte implicit förlitar sig på den utan att uttryckligen ställa in den.
I ovanstående exempel använde vi den smälta formen parallel for
eller parallel do
. Men slingkonstruktionen kan användas utan att smälta den med parallel
, i form av ett #pragma omp for [...]
eller !$omp do [...]
fristående direktiv inom ett parallel
område.
Endast för Fortran-versionen är loopindexvariabeln (-erna) för den / de parallella slingan (er) alltid private
standard. Det finns därför inget behov av att uttryckligen förklara dem private
(även om det inte är något fel).
För C- och C ++ -versionen är loopindexen precis som alla andra variabler. Därför, om deras räckvidd sträcker sig utanför de / de parallella slingorna (vilket betyder att de inte deklareras som for ( int i = ...)
utan snarare som int i; ... for ( i = ... )
måste förklaras private
.
Typiska exempel i C
#include <stdio.h>
#include <math.h>
#include <omp.h>
#define N 1000000
int main() {
double sum = 0;
double tbegin = omp_get_wtime();
#pragma omp parallel for reduction( +: sum )
for ( int i = 0; i < N; i++ ) {
sum += cos( i );
}
double wtime = omp_get_wtime() - tbegin;
printf( "Computing %d cosines and summing them with %d threads took %fs\n",
N, omp_get_max_threads(), wtime );
return sum;
}
I det här exemplet beräknar vi bara 1 miljon kosinus och summerar deras värden parallellt. Vi tar också tid på utförandet för att se om parallelliseringen har någon effekt på prestandan. Slutligen, eftersom vi mäter tiden måste vi se till att kompilatorn inte optimerar bort det arbete vi gjort, så vi låtsas använda resultatet genom att bara returnera det.
Samma exempel i Fortran
program typical_loop
use omp_lib
implicit none
integer, parameter :: N = 1000000, kd = kind( 1.d0 )
real( kind = kd ) :: sum, tbegin, wtime
integer :: i
sum = 0
tbegin = omp_get_wtime()
!$omp parallel do reduction( +: sum )
do i = 1, N
sum = sum + cos( 1.d0 * i )
end do
!$omp end parallel do
wtime = omp_get_wtime() - tbegin
print "( 'Computing ', i7, ' cosines and summing them with ', i2, &
& ' threads took ', f6.4,'s' )", N, omp_get_max_threads(), wtime
if ( sum > N ) then
print *, "we only pretend using sum"
end if
end program typical_loop
Även här beräknar vi och samlar en miljon kosinus. Vi tid på slingan och för att undvika oönskad kompilatoroptimering bort, låtsas vi använda resultatet.
Samla och köra exemplen
På en 8-kärnors Linux-maskin med GCC version 4.4 kan C-koderna sammanställas och köras på följande sätt:
$ gcc -std=c99 -O3 -fopenmp loop.c -o loopc -lm
$ OMP_NUM_THREADS=1 ./loopc
Computing 1000000 cosines and summing them with 1 threads took 0.095832s
$ OMP_NUM_THREADS=2 ./loopc
Computing 1000000 cosines and summing them with 2 threads took 0.047637s
$ OMP_NUM_THREADS=4 ./loopc
Computing 1000000 cosines and summing them with 4 threads took 0.024498s
$ OMP_NUM_THREADS=8 ./loopc
Computing 1000000 cosines and summing them with 8 threads took 0.011785s
För Fortran-versionen ger den:
$ gfortran -O3 -fopenmp loop.f90 -o loopf
$ OMP_NUM_THREADS=1 ./loopf
Computing 1000000 cosines and summing them with 1 threads took 0.0915s
$ OMP_NUM_THREADS=2 ./loopf
Computing 1000000 cosines and summing them with 2 threads took 0.0472s
$ OMP_NUM_THREADS=4 ./loopf
Computing 1000000 cosines and summing them with 4 threads took 0.0236s
$ OMP_NUM_THREADS=8 ./loopf
Computing 1000000 cosines and summing them with 8 threads took 0.0118s
Tillsats av två vektorer med hjälp av OpenMP parallellt för konstruktion
void parallelAddition (unsigned N, const double *A, const double *B, double *C)
{
unsigned i;
#pragma omp parallel for shared (A,B,C,N) private(i) schedule(static)
for (i = 0; i < N; ++i)
{
C[i] = A[i] + B[i];
}
}
Detta exempel lägger till två vektor ( A
och B
i C
) genom att leka ett team av trådar (specificerat av OMP_NUM_THREADS
miljövariabel, till exempel) och tilldela varje tråd en bit av arbete (i det här exemplet, tilldelat statiskt genom schedule(static)
uttryck).
Se kommentaravsnittet med avseende på den private(i)
optionen.