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