Universität Karlsruhe (TH) OpenMP

Transcription

Universität Karlsruhe (TH) OpenMP
Universität Karlsruhe (TH)
Forschungsuniversität · gegründet 1825
OpenMP-Programmierung Teil II
Multikern-Praktikum Wintersemester 06-07
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Inhalt
• Was ist OpenMP?
• Parallele Regionen
• Konstrukte zur Arbeitsteilung
• Sichtbarkeit / Schutz privater Daten
• Konstrukte zur Synchronisation
• Ablaufplanung bei Schleifen
• Andere nützliche Konstrukte
• Überlegungen zur Performanz
• Clauses / Directives- Zusammenfassung
• Umgebungsvariabeln
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
2
Institut für Program
Beispiel: Skalarprodukt (1)
float dot_prod(float* a, float* b, int N)
{
float sum = 0.0;
#pragma omp parallel for shared(sum)
for(int i=0; i<N; i++) {
sum += a[i] * b[i];
}
return sum;
}
Was ist falsch?
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
3
Institut für Program
Beispiel: Skalarprodukt (2)
• Der Zugriff auf gemeinsam genutzte,
veränderliche Daten muss geschützt werden:
float dot_prod(float* a, float* b, int N)
{
float sum = 0.0;
#pragma omp parallel for shared(sum)
for(int i=0; i<N; i++) {
#pragma omp critical
sum += a[i] * b[i];
}
return sum;
}
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
4
Institut für Program
kritische Abschnitte
#pragma omp critical [(Name der Sperre)]
definiert einen kritischen Abschnitt.
Kontrollfäden müssen
warten, bis sie an der Reihe
sind. consum() wird immer
nur von einem Faden
gleichzeitig aufgerufen.
Die Angabe eines Namens
für die Sperre des kritischen
Abschnitts ist optional.
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
float RES;
#pragma omp parallel
{ float B;
#pragma omp for
for(int i=0; i<niters; i++){
B = big_job(i);
#pragma omp critical (RES_lock)
consum (B, RES);
}
}
5
Institut für Program
„Single“ Direktive
• In einer parallelen Region kann Code vorkommen, der nur von einem
Faden ausgeführt werden soll (z.B. für E/A-Operationen).
• Dieser Codebereich kann mit eine single-Region eingeklammert werden.
• Es wird der erste Faden ausgewählt, der diese Stelle erreicht.
• Implizite Barriere am Ende (es sei, denn „nowait“ wurde angegeben).
#pragma omp parallel
{
DoManyThings();
#pragma omp single
{
ExchangeBoundaries();
} // andere Fäden warten hier
DoManyMoreThings();
}
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
6
Institut für Program
„Master“ Direktive
• Markiert einen Code-Block, der nur vom
Hauptfaden ausgeführt werden soll.
• Keine implizite Barriere am Ende.
#pragma omp parallel
{
DoManyThings();
#pragma omp master
{
// springe weiter falls nicht Master
ExchangeBoundaries();
}
DoManyMoreThings();
}
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
7
Institut für Program
Barriere
• Explizite Barrierensynchronisation.
• Jeder Faden wartet, bis alle anderen Fäden die
Barriere erreichen.
#pragma omp parallel shared (A, B, C)
{
DoSomeWork(A,B);
printf(“Processed A into B\n”);
#pragma omp barrier
DoSomeWork(B,C);
printf(“Processed B into C\n”);
}
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
8
Institut für Program
Implizite Barrieren
• Einige OpenMP-Konstrukte beinhalten implizite
Barrieren:
• parallel
• for
• single
• Unnötige Barrieren beeinträchtigen die Leistung
• Wartende Kontrollfäden erledigen keine Arbeit!
• Man kann unnötige Barrieren (auf eigene
Gefahr!) mit der nowait Direktive unterdrücken.
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
9
Institut für Program
„Nowait“ Direktive
#pragma omp for nowait
for(...)
{...};
#pragma single nowait
{ [...] }
• Verwendung beispielsweise wenn die Fäden zwischen
unabhängigen Berechnungen warten müssten:
#pragma omp for schedule(dynamic,1) nowait
for(int i=0; i<n; i++)
a[i] = bigFunc1(i);
#pragma omp for schedule(dynamic,1)
for(int j=0; j<m; j++)
b[j] = bigFunc2(j);
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für10
Program
Konditionale Schleifen
• Die for-Schleife wird solange ausgeführt, bis die
bestimmte Bedingung zutrifft:
#pragma omp for schedule(dynamic,1) if
(n>100)
for(int i=0; i<n; i++)
a[i] = bigFunc1(i);
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für11
Program
Beispiel: „for & nowait“
#include <omp.h>
#define CHUNKSIZE 100
#define N 1000
main () {
int i, chunk;
float a[N], b[N], c[N];
/* Some initializations */
for (i=0; i < N; i++)
a[i] = b[i] = i * 1.0;
chunk = CHUNKSIZE;
#pragma omp parallel shared(a,b,c,chunk) private(i)
{
#pragma omp for schedule(dynamic,chunk) nowait
for (i=0; i < N; i++)
c[i] = a[i] + b[i];
} /* end of parallel section */
}
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für12
Program
„Atomic“ Direktive
• Spezialfall eines kritischen Abschnitts.
• Wirkt nur für die eine einfache Aktualisierung einer
Speicherstelle (d.h. eine Zuweisung).
#pragma omp parallel for shared(x, y, index, n)
for (i = 0; i < n; i++) {
#pragma omp atomic
x[index[i]] += work1(i);
y[i] += work2(i);
}
• nur die (schreibenden) Zugriffe auf dasselbe Element von
x[] werden serialisiert, Zugriffe auf unterschiedliche
Elemente von x[] können weiterhin parallel ausgeführt
werden.
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für13
Program
„Ordered“ Direktive
• zulässig nur innerhalb einer for-Schleife
• ordered: Legt fest, dass die Reihenfolge der Ausführung
der Iterationen des betreffenden Blocks die gleiche wie
bei serieller Programmausführung sein muss
• Nur ein Thread kann jeweils den Code des mit „ordered“
markierten Bereiches ausführen.
• In jeder Schleifeniteration wird der „ordered“ Bereich nur einmal
ausgeführt und es darf auch nur einen solchen Bereich geben
• Die Verwendung von #pragma omp ordered muss durch das
Schlüsselwort „ordered“ in #pragma omp for angekündigt werden:
#pragma omp for ordered
{...};
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für14
Program
„Flush“ Direktive
• Sorgt für eine konsistente Sicht auf den Speicher.
• Threadlokale Variablen und die ihnen zugeordneten Speicherbereiche
haben danach identischen Inhalt.
#pragma omp flush(list)newline
• Die FLUSH Direktive ist implizit in den folgenden Direktiven enthalten :
•
•
•
•
•
•
•
barrier
parallel - upon entry and exit
critical - upon entry and exit
ordered - upon entry and exit
for - upon exit
sections - upon exit
single - upon exit
• Die Direktive ist nicht implizit falls NOWAIT verwendet wurde.
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für15
Program
Inhalt
• Was ist OpenMP?
• Parallele Regionen
• Konstrukte zur Arbeitsteilung
• Sichtbarkeit / Schutz privater Daten
• Konstrukte zur Synchronisation
• Ablaufplanung bei Schleifen
• Andere nützliche Konstrukte
• Überlegungen zur Performanz
• Clauses / Directives- Zusammenfassung
• Umgebungsvariabeln
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für16
Program
Aufteilung von
Schleifendurchläufen (1)
• Mit der „schedule“ Direktive kann festgelegt werden, wie die
Iterationen auf die verfügbaren Kontrollfäden verteilt werden sollen.
schedule(static [,chunk])
• Weist reihum Blöcke von Iterationen (der Größe „chunk“) zu.
• Round-robin Verteilung
schedule(dynamic[,chunk])
• Weist Blöcke der Größe „chunk“ zu.
• Fäden fordern einen neuen Block an, wenn sie mit dem alten Block fertig sind
schedule(guided[,chunk])
• Dynamische Verteilung von Blöcken wie bei „dynamic“.
• Startet mit großen Blöcken, Blöcke werden immer kleiner, aber nicht kleiner
als „chunk“
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für17
Program
Aufteilung von
Schleifendurchläufen (2)
schedule(runtime)
• Verlagert die Entscheidung über die Verteilstrategie auf die Laufzeit
• Scheduling-typ und chunk werden während der Laufzeit spezifiziert
(Umgebungsvariable: OMP_SCHEDULE)
• Beispiel: set OMP_SCHEDULE "guided, 4"
• Anwendung (in C/C++) nur auf „parallel for“
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für18
Program
Beispiel :Ablaufplanung
• Schleifen-Scheduling:
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für19
Program
Welche Strategie ist zu wählen?
Ablaufstrategie
STATIC
Einsatz
Vorhersagbare, gleich
verteilte Menge an
Arbeit pro Durchlauf
DYNAMIC
Unvorhersagbare, stark
schwankend Menge an
Arbeit pro Durchlauf
GUIDED
Spezialfall von „dynamic“
mit geringerem
Overhead.
• STATIC
• Weniger Overhead und bessere Datenlokalität
• DYNAMIC und GUIDED:
• Bessere Lastbalancierung
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für20
Program
Beispiel für die Ablaufplanung
#pragma omp parallel for schedule (static, 8)
for( int i = start; i <= end; i += 2 )
{
if ( TestForPrime(i) ) gPrimesFound++;
}
• Schleifendurchläufe werden in Blöcken zu je acht
Durchläufen verteilt.
Wenn start = 3 ist, besteht der erste Block aus den
Durchläufen für i={3,5,7,9,11,13,15,17}.
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für21
Program
Statische Verteilung
(„von Hand“)
• Vorgegeben:
• Anzahl der Fäden (Nthrds)
• Nummer des jeweiligen Fadens (id)
• Berechnung der Start- und Endwerte der Iteration:
#pragma omp parallel
{
int i, istart, iend;
istart = id * N / Nthrds;
iend = (id+1) * N / Nthrds;
for(i=istart;i<iend;i++){
c[i] = a[i] + b[i];}
}
• Mit OpenMP ist eine solche „händische“ Aufteilung
normalerweise nicht nötig, aber möglich.
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für22
Program
Beispiel: „reduction & schedule“
#include <omp.h>
main () {
int i, n, chunk;
float a[100], b[100], result;
/* Some initializations */
n = 100;
chunk = 10;
result = 0.0;
for (i=0; i < n; i++) {
a[i] = i * 1.0;
b[i] = i * 2.0;
}
#pragma omp parallel for default(shared) private(i) schedule(static,chunk) \
reduction(+:result)
for (i=0; i < n; i++)
result = result + (a[i] * b[i]);
}
printf("Final
result=
Fakultät
für Informatik
Lehrstuhl für Programmiersysteme
%f\n",result);
Ali Jannesari
Institut für23
Program
Beispiel: Scheduling (Bubble
Sort Performance)
4
3.5
3
no scheduling
seconds
2.5
static
static,100
2
static,1000
dynamic,100
dynamic,1000
1.5
guided,1000
1
0.5
0
1
2
3
4
5
threads
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
6
7
8
Rechner: Quad PIII Xeon (500Mhz 2 GB RAM)
Source: www.tc.cornel.edu
Parallele Abschnitte
• Unabhängige Code-Abschnitte
können parallel ausgeführt werden.
#pragma omp parallel sections
{
#pragma omp section
phase1();
#pragma omp section
phase2();
#pragma omp section
phase3();
}
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Seriell
Parallel
Institut für25
Program
Inhalt
• Was ist OpenMP?
• Parallele Regionen
• Konstrukte zur Arbeitsteilung
• Sichtbarkeit / Schutz privater Daten
• Konstrukte zur Synchronisation
• Ablaufplanung bei Schleifen
• Andere nützliche Konstrukte
• Überlegungen zur Performanz
• Clauses / Directives- Zusammenfassung
• Umgebungsvariabeln
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für26
Program
„Firstprivate“ Direktive
• Kennzeichnet private Variable, aber im Gegensatz zu
„private“ ist die Variable nicht uninitialisiert, sondern wird
mit dem Wert der gemeinsamen Variable aus dem
umgebenden Block initialisiert.
• C++ Objects werden mit dem Copy-Konstruktor erzeugt.
incr=0;
#pragma omp parallel for firstprivate(incr)
for (I=0;I<=MAX;I++) {
if ((I%2)==0) incr++;
A(I)=incr;
}
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für27
Program
„Lastprivate“ Direktive
• Die gemeinsame (äußere) Variable wird mit dem
Wert aus dem sequentiell letzten Schleifendurchlauf
(letzter Iterationsindex) aktualisiert, wenn alle Fäden
die Barriere erreicht haben.
• In C++ geschieht dies per Zuweisungsoperator.
void sq2(int n, double *lastterm)
{
double x; int i;
#pragma omp parallel
#pragma omp for lastprivate(x)
for (i = 0; i < n; i++){
x = a[i]*a[i] + b[i]*b[i];
b[i] = sqrt(x);
}
lastterm = x;
}
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für28
Program
Noch ein Beispiel zu „lastprivate“
void a30 (int n, float *a, float *b)
{
int i;
#pragma omp parallel
{
#pragma omp for lastprivate(i)
for (i=0; i<n-1; i++)
a[i] = b[i] + b[i+1];
}
a[i]=b[i]; /* i == n-1 here */
}
• „i“ verhält sich wie private, aber kopiert den Wert aus
dem letzten Schleifendurchlauf.
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für29
Program
„Threadprivate“ Direktive
• Globale Lebensdauer für fadenlokale Variablen.
• Nur erlaubt für Variablen mit File- oder Namespace-
Scope.
• Mittels „copyin“ kann mit dem Wert der Variable im
Hauptfaden initialisiert werden.
struct Astruct A;
#pragma omp threadprivate(A)
…
#pragma omp parallel copyin(A)
do_something_to(&A);
…
Private Kopien von “A”
bleiben zwischen den
parallelen Regionen
erhalten.
#pragma omp parallel
do_something_else_to(&A);
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für30
Program
Beispiel: „Threadprivate“
#include <omp.h>
int a, b, i, tid;
float x;
#pragma omp threadprivate(a, x)
main () {
/* Explicitly turn off dynamic threads */
omp_set_dynamic(0);
printf("1st Parallel Region:\n");
#pragma omp parallel private(b,tid)
{
tid = omp_get_thread_num();
a = tid;
b = tid;
x = 1.1 * tid +1.0;
printf("Thread %d: a,b,x= %d %d %f\n",tid,a,b,x);
} /* end of parallel section */
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für31
Program
Beispiel: „Threadprivate“
printf("************************************\n");
printf("Master thread doing serial work here\n");
printf("************************************\n");
printf("2nd Parallel Region:\n");
#pragma omp parallel private(tid)
{
tid = omp_get_thread_num();
printf("Thread %d: a,b,x= %d %d %f\n",tid,a,b,x);
} /* end of parallel section */
}
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für32
Program
Beispiel: „Threadprivate“
Output:
1st Parallel Region:
Thread 0: a,b,x= 0 0 1.000000
Thread 2: a,b,x= 2 2 3.200000
Thread 3: a,b,x= 3 3 4.300000
Thread 1: a,b,x= 1 1 2.100000
************************************
Master thread doing serial work here
************************************
2nd Parallel Region:
Thread 0: a,b,x= 0 0 1.000000
Thread 3: a,b,x= 3 0 4.300000
Thread 1: a,b,x= 1 0 2.100000
Thread 2: a,b,x= 2 0 3.200000
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für33
Program
OpenMP Bibliotheksfunktionen (1)
• Normalerweise für OpenMP Programme nicht benötigt.
• Kann zu Code führen, der nicht seriell konsistent ist.
• Sinnvoll z.B. bei der Fehlersuche.
int omp_get_num_threads(void):
• Anzahl der parallelen Threads
• nur >1 in parallelen Abschnitten
int omp_get_thread_num(void):
• gibt den Rang diese Threads zurück
• immer 0 für den Master Thread
int omp_get_num_procs(void):
• Anzahl der CPUs, die dem Programm zur Verfügung stehen
• Einbinden der OpenMP Deklarationsdatei erforderlich:
#include <omp.h>
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für34
Program
OpenMP Bibliotheksfunktionen (2)
• OMP_SET_NUM_THREADS
• OMP_GET_NUM_THREADS
• OMP_GET_MAX_THREADS
• Gibt Maximum wert der Funktion OMP_GET_NUM_THREADS zurück
• OMP_GET_THREAD_NUM
• OMP_GET_NUM_PROCS
• OMP_IN_PARALLEL
• Bestimmt ob dieses Teil der Ausführende Code parallel ist oder nicht
• OMP_SET_DYNAMIC
• Aktiviert oder deaktiviert die dynamische Anpassung der Anzahl des Threads
• OMP_GET_DYNAMIC
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für35
Program
OpenMP Bibliotheksfunktionen (3)
• OMP_SET_NESTED
• Aktiviert oder deaktiviert verschachtelte Parallelismus.
• OMP_GET_NESTED
• OMP_INIT_LOCK
• Initialisiert ein Lock assoziiert mit Lock Variable.
• Beispiel: void omp_init_lock (omp_lock_t *lock)
• OMP_DESTROY_LOCK
• OMP_SET_LOCK
• Die Ausführende Thread wartet (blockiert), bis das bestimmte lock
verfügbar ist.
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für36
Program
OpenMP Bibliotheksfunktionen (4)
• OMP_UNSET_LOCK : Das Lock wird von Thread freigegeben
• OMP_TEST_LOCK : Wie OMP_SET_LOCK, aber das Thread wird nicht
blockiert falls das lock nicht verfügbar ist.
• OMP_GET_WTIME : Bietet portable Wall Clock timing routine (zeit zwischen
zwei Punkten im Programm in double-precision floating point Format)
#include <omp.h>
double start;
double end;
start = omp_get_wtime();
... work to be timed ...
end = omp_get_wtime();
printf("Work took %f sec. time.\n", end-start);
• OMP_GET_WTICK : Zeit zwischen Processor clock ticks.
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für37
Program
OpenMP Bibliotheksfunktionen (5)
• OMP_SET_NUM_THREADS
• OMP_SET_NESTED
• OMP_GET_NUM_THREADS
• OMP_GET_NESTED
• OMP_GET_MAX_THREADS
• OMP_INIT_LOCK
• OMP_GET_THREAD_NUM
• OMP_DESTROY_LOCK
• OMP_GET_NUM_PROCS
• OMP_SET_LOCK
• OMP_IN_PARALLEL
• OMP_UNSET_LOCK
• OMP_SET_DYNAMIC
• OMP_TEST_LOCK
• OMP_GET_DYNAMIC
• OMP_GET_WTIME
• OMP_GET_WTICK
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für38
Program
Buckup Slides
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Ali Jannesari
Institut für39
Program
Aufgabe 2: Bucket Sort
• Elements are distributed among bins :
• Then, elements are sorted within each bin
Fakultät für Informatik
Lehrstuhl für Programmiersysteme