Parallele Programmierung. Parallele Programmierung Memory-Rechner mit OpenMP

Ähnliche Dokumente
Beispiel: Schleifenparallelisierung

Master-Thread führt Programm aus, bis durch die Direktive

Threads und OpenMP. Frank Mietke Cluster- & Gridcomputing Frank Mietke 7/4/04

6. Der OpenMP Standard. Direktiven-basiertes API zur Programmierung von Parallelrechnern mit gemeinsamem Speicher für FORTRAN, C und C++

1. Einführung in OpenMP

OpenMP - Threading- Spracherweiterung für C/C++ Matthias Klein, Michael Pötz Systemprogrammierung 15. Juni 2009

Vorlesung Parallelrechner und Parallelprogrammierung, SoSe 2016

Parallele Programmierung mit OpenMP

OpenMP. Viktor Styrbul

Praktikum: Paralleles Programmieren für Geowissenschaftler

Parallele Programmierung mit OpenMP

Einige Grundlagen zu OpenMP

Konzepte der parallelen Programmierung

Programmieren mit OpenMP

Parallele Programmierung mit OpenMP

Automatische Parallelisierung

Anleitung für zwei Fortran-Openmp-Beispiele auf der NWZSuperdome

4. Parallelprogrammierung

der RWTH Aachen Konfiguration und parallele Programmierung Dieter an Mey

Parallelisierung der Vektoraddition 149

Lehrstuhl für Datenverarbeitung. Technische Universität München. Leistungskurs C++ Multithreading

ÜBUNGS-BLOCK 7 LÖSUNGEN

Syntax und Kontrollstrukturen

4. Parallelprogrammierung. AlDaBi Praktikum

4. Parallelprogrammierung

Repetitorium Programmieren I + II


Algorithmen und Datenstrukturen

Parallele Programmierung in C++ mit OpenMP

Shared-Memory Parallelisierung von C++ Programmen

Paralleles Programmieren mit OpenMP und MPI OpenMP-Übungsaufgaben Steinbuch Centre for Computing

2 Teil 2: Nassi-Schneiderman

2 Dieter an Mey, SunHPC 2002, Einleitung 10000, , ,000 10,000 1,000 0,100 0,010. 0,001 Cyber 175 Cyber 205

Betriebssysteme Teil 3: Laufzeitsystem für Programme

Multicore Parallelismus! in modernen CPUs

Evaluation. Einleitung. Implementierung Integration. Zusammenfassung Ausblick

1.4. Funktionen. Objektorientierte Programmierung mit C++

Kurzeinführung in C99

Einleitung Entwicklung in C Hello-World! Konstrukte in C Zusammenfassung Literatur. Grundlagen von C. Jonas Gresens

2Binden 3. und Bibliotheken

Einführung Programmierpraktikum C Michael Zwick

Einstieg in die Informatik mit Java

Zum Aufwärmen nocheinmal grundlegende Tatsachen zum Rechnen mit reelen Zahlen auf dem Computer. Das Rechnen mit Gleitkommazahlen wird durch den IEEE

Threads. Netzwerk - Programmierung. Alexander Sczyrba Jan Krüger

Gedächtnis. Während der Abarbeitung eines Algorithmus müssen sich Dinge gemerkt werden bzw. auf Dingen wird gerechnet. Zugriff.

Systemprogrammierung

Einstieg in die Informatik mit Java

Multi- und Many-Core

Programmieren in C. Funktionen mit Zeigern und Adressen. Prof. Dr. Nikolaus Wulff

Angewandte Mathematik und Programmierung

Propädeutikum. Dipl.-Inf. Frank Güttler

Einführung in den Einsatz von Objekt-Orientierung mit C++ I

Programmiersprachen Einführung in C

Wintersemester Maschinenbau und Kunststofftechnik. Informatik. Tobias Wolf Seite 1 von 29

RO-Tutorien 15 und 16

Programmiertechnik. Teil 4. C++ Funktionen: Prototypen Overloading Parameter. C++ Funktionen: Eigenschaften

C++ Teil 2. Sven Groß. 16. Apr IGPM, RWTH Aachen. Sven Groß (IGPM, RWTH Aachen) C++ Teil Apr / 22

Memory Models Frederik Zipp

Transkript:

Parallele Programmierung für Shared-Memory Memory-Rechner mit OpenMP Dieter an Mey Rechen- und Kommunikationszentrum der RWTH Aachen 21. Januar 2002 anmey@rz rz.rwth-aachen.de http://www www.rz.rwth-aachen.de [/hpc hpc] http://www www.rz.rwth-aachen.de/.de/sw/prog/openmpopenmp 1 OpenMP-Kurs Dieter an Mey 21.01.2002 Parallele Programmierung für Shared-Memory Memory-Rechner mit OpenMP Einleitung Automatische Parallelisierung Explizite Parallelisierung mit OpenMP Debugging mit Assure und TotalView Performance Tools GuideView, WorkShop Hybride Parallelisierung 2 OpenMP-Kurs Dieter an Mey 21.01.2002

Mehrprozessorsystem mit Shared Memory Uniform Memory Access (UMA) Memory (interleaved) Crossbar / Bus Cache Cache Cache Cache Proc Proc Proc Proc 3 OpenMP-Kurs Dieter an Mey 21.01.2002 SMP-Compute Server mit OpenMP sunc00 sunc15 - Sun Fire 6800 SMP-Cluster Cluster, 24 Prozessoren, US-III, 750/900 MHz (UMA) 1H2002: sunc16 sunc19 - Sun Fire 15K SMP-Cluster Cluster, 72 Prozessoren, US-III, 900 MHz (ccnuma( ccnuma) hpc4 - HP V-ClassV Class,, 16 Prozessoren, PA 8200, 240 MHz (UMA) hpc6 - HP J-ClassJ Class,, 4 Prozessoren, PA 8500, 440 MHz (UMA) sgic3 - SGI Origin 200, 4 Prozessoren, MIPS R10000, 180 MHz (ccnuma( ccnuma) sgic5 - SGI Origin 200, 2 Prozessoren, MIPS R10000, 180 MHz (UMA) hpcline - SMP-Cluster aus 16 PIII, 800 MHz Doppelprozessoren linuxcxx- PIII Doppelprozessoren unterschiedlicher Taktung 4 OpenMP-Kurs Dieter an Mey 21.01.2002

Was heißt Shared-Memory Memory-Parallelisierung? Prozessoren do i = 1, 100 a(i) = b(i) + c(i) do i = 1, 25 a(i) = b(i) + c(i) do i = 26, 50 a(i) = b(i) + c(i) do i = 51, 75 a(i) = b(i) + c(i) do i = 76, 100 a(i) = b(i) + c(i) Speicher A(1)... A(100) B(1)... B(100) C(1)... C(100) 5 OpenMP-Kurs Dieter an Mey 21.01.2002 Und was nun? do i = 1, 100 s = s + a(i) Prozessoren Arbeitsteilung (worksharing) do i = 1, 25 s = s + a(i) do i = 26, 50 s = s + a(i) do i = 51, 75 s = s + a(i) do i = 76, 100 s = s + a(i) Speicher S A(1)... A(100) Alle Prozessoren wollen gleichzeitig S lesen und schreiben! 6 OpenMP-Kurs Dieter an Mey 21.01.2002

Parallele Programmierung für Shared-Memory Memory-Rechner mit OpenMP Automatische Parallelisierung Explizite Parallelisierung mit OpenMP Debugging mit Assure und TotalView Performance Tools GuideView, WorkShop Hybride Parallelisierung 7 OpenMP-Kurs Dieter an Mey 21.01.2002 Automatische Parallelisierung Sun (Forte Developer 6 U2 = WorkShop 6 U2) Übersetzen und Binden f90 / f95 / f77 -autopar abkürzend für -xautopar depend xo3 bzw. cc -xautopar xdepend xo4 Parallelisierung von Reduktionen unter Zulassen der Vertauschung der arithmetischen Reihenfolge durch -reduction bzw. -xreduction Ausgabe von Compilerinformationen zur Parallelisierung: -loopinfo bzw. -xloopinfo Angabe der Prozessorzahl bei Ausführung export OMP_NUM_THREADS=n 8 OpenMP-Kurs Dieter an Mey 21.01.2002

Automatische Parallelisierung Linux (PGI-Compiler) Übersetzen und Binden pgf90 / pgf77 / pgcc / pgcc -O2 -Mconcur[=option,option,] Unbedingte parallele Ausführung oder in Abhängigkeit von der Schleifendurchlaufzahl (alternate coding) -Mconcur=altcode:n -Mconcur= noaltcode Verteilung der Schleifenindizes auf die Prozessoren -Mconcur=dist:block -Mconcur=dist: cyclic Keine Vertauschung der arithmetischen Reihenfolge (Reduktionen!) -Mconcur=noassoc Ausgabe von Compilerinformationen: -Minfo -Mneginfo=concur Angabe der Prozessorzahl bei Ausführung export NCPUS=n Steuerung der Parallelisierung durch Direktiven!PGI$<scope> NODEPCHK #pragma <scope> nodepchk scope: g r l scope: global routine loop 9 OpenMP-Kurs Dieter an Mey 21.01.2002 Automatische Parallelisierung HP Übersetzen und Binden f90 / c89 / acc +DA2.0 +DS2.0 +Odataprefetch +O3 +O[no]parallel Unbedingte parallele Ausführung oder in Abhängigkeit von der Schleifendurchlaufzahl +O[no]dynsel Schalten der Automatischen Parallelisierung +O[no]autopar Keine Vertauschung der arithmetischen Reihenfolge (Reduktionen!) +Ofltacc Ausgabe von Compilerinformationen: +O[no]info +O[no]report Angabe der Prozessorzahl bei Ausführung export MP_NUMBER_OF_THREADS=n ( MLIB_NUMBER_OF_THREADS bei Verwendung der MathLIBrary) Steuerung der Parallelisierung durch Direktiven!$DIR PREFER_PARALLEL #pragma _CNX prefer_parallel!$dir NO_LOOP_DEPENDENCE[(arraylist)] 10 OpenMP-Kurs Dieter an Mey 21.01.2002

Automatische Parallelisierung SGI (MIPSpro( MIPSpro-Compiler) Übersetzen und Binden f90 / f77 / cc / CC -n32 -mips4 -O3 -apo -mp Verteilung der Schleifenindizes auf die Prozessoren -mp_schedtype=dynamic GSS INTERLEAVE RUNTIME SIMPLE Ausgabe von mit OpenMP-Direktiven angereichertem Programm: -apo -mp list Angabe der Prozessorzahl bei Ausführung export OMP_NUM_THREADS=n Steuerung der Parallelisierung durch Direktiven!*$*ASSERT DO (CONCURRENT) #pragma prefer concurrent manual pages pe_environ environ 11 OpenMP-Kurs Dieter an Mey 21.01.2002 Automatische Parallelisierung Visual KAP for OpenMP (NT) Präprozesor /kai/vkomp36/bin/vkapomp.exe -WKkeep -WKonly -WK,-fuse -WK, -fuselevel=1 -WK,-noarclimit -WK,-conc -WK,-so=0 -WK,-o=3 -WK,-r=3 -WK,-noparallelrtl -WKonly -WK,-heap=64 -WK,-nointl -WK,-suppress=w -WK,-lo=lkopst -WK,-mc=0 simpeq.f Steuerung der Parallelisierung durch Direktiven!*$*concurrentize 12 OpenMP-Kurs Dieter an Mey 21.01.2002

Visual KAP for OpenMP (NT) Fortran90 Präprozessor Auto-parallelization, gererating OpenMP directives no unrolling 13 OpenMP-Kurs Dieter an Mey 21.01.2002 Bedingungen für die automatische Parallelisierung (Sun) Kandidaten für die Parallelisierung: Explizite DO-Schleifen oder implizite Schleifen (IF-Schleifen, Feldsyntax) Bedingungen für die Parallelisierung (Auswahl): Es dürfen in einer Iteration keine Feldkomponenten geändert werden, die in einer anderen Iteration benötigt (gelesen oder geschrieben) werden. (Auch nicht in Unterprogrammen, die in der Schleife gerufen werden.) Es dürfen keine skalaren Variablen geändert werden, die nach der Schleife noch gelesen werden. Es dürfen in einer Iteration keine skalaren Variablen geändert werden, die in einer anderen Iteration benötigt (gelesen oder geschrieben) werden. Der Overhead der Parallelisierung darf im Vergleich zur Rechenarbeit in der Schleife nicht zu hoch sein. 14 OpenMP-Kurs Dieter an Mey 21.01.2002

Problemfälle der (automatischen) Parallelisierung do i = ilow, ihigh! Abhängigkeit der Feldelemente von A a(i) = a(i+k) + b(i)! zwischen verschiedenen Iterationen! (Bei positivem k ist Vektorisierung möglich) do i = 1, n a(ind(i)) = b(i)! Ist nur dann parallelisierbar, wenn alle! ind(1:n) paarweise verschieden sind. t = x do i = 1, n! Die skalare Variable t wird in einer a(i) = t + b(i)! Iteration geschrieben und in t = c(i)! einer anderen (der folgenden) gelesen y = t! Die skalare Variable t wird nach der Schleife gelesen 15 OpenMP-Kurs Dieter an Mey 21.01.2002 Parallele Programmierung für Shared-Memory Memory-Rechner mit OpenMP Automatische Parallelisierung Explizite Parallelisierung mit OpenMP Debugging mit Assure und TotalView Performance Tools GuideView, PerView, CXperf,, Puma Hybride Parallelisierung 16 OpenMP-Kurs Dieter an Mey 21.01.2002

OpenMP - Gliederung Einleitung: Geschichte, Compiler, OpenMP-Struktur Einführung in OpenMP Format der Direktiven Laufzeitfunktionen Parallele Regionen Arbeitsteilung (worksharing) Verwaisen (orphaning) Daten-Geltungsbereiche (data scope) Synchronisation Überblick über alle Kompontenten von OpenMP Ein Beispiel (Berechnung von Pi) Strategien, Performance Klassifizierung von Variablen Parallelisierung auf Schleifenebene Grobgranulare Arbeitsteilung SPMD OpenMP versus MPI Anwendungsbeispiele Jacobi, Panta 17 OpenMP-Kurs Dieter an Mey 21.01.2002 OpenMP - Geschichte http://www www.openmp.org http://www www.compunity.org 1997: OpenMP Version 1.0 für Fortran Standard für die Shared-Memory Memory-Programmierung inzwischen für alle namhaften SMP-Rechner verfügbar löst im techn.-wiss. Rechnen die proprietären Direktiven und die unmittelbare Verwendung der [p]threads ab 1998: OpenMP V1.0 für C und C++ 1999: OpenMP V1.1 für Fortran (Fehler korrigiert, Erläuterungen eingearbeitet) 2000: OpenMP V2.0 für Fortran (Unterstützung von Fortran90-Modules) 2001: OpenMP V2.0 für C und C++ Draft 18 OpenMP-Kurs Dieter an Mey 21.01.2002

Compiler für OpenMP SUN: f77 / f90 / f95 openmp [ -R/ R/usr/lib/lwp lwp ] cc xopenmp [ -R/ R/usr/lib/lwplwp ] guidef77 / guidef90 / guidecc / guidec++ Linux: pgf77 / pgf90 / pgcc / pgcc mp guidecc / guidec++ HP: f90 openmp guidef77 / guidef90 / guidecc / guidec++ SGI: f77 / f90 / cc / CC mp 19 OpenMP-Kurs Dieter an Mey 21.01.2002 Die Komponenten von OpenMP (Fortran) Umgebungsvariable, Direktiven, Laufzeitbibliothek #!/bin/ksh # Shell-Script f90 openmp test.f90 export OMP_NUM_THREADS=4 a.out Umgebungsvariable Direktiven (besondere Kommentarzeilen) Laufzeitbibliothek! Source file test.f90 program main integer omp_get_thread_num!$omp parallel print *, 'me: ', omp_get_thread_num()!$omp end parallel end program me: 0 me: 3 me: 2 me: 1 20 OpenMP-Kurs Dieter an Mey 21.01.2002

Die Komponenten von OpenMP (C) Umgebungsvariable, Direktiven, Laufzeitbibliothek #!/bin/csh # Shell-Script cc xopenmp test.f90 setenv OMP_NUM_THREADS 4 a.out /* Source file test.c */ #include <stdio.h> #include <omp.h> Umgebungsvariable Direktiven (besondere Kommentarzeilen) Laufzeitbibliothek int main(void) { #pragma omp parallel { printf("me: %d\n",omp_get_thread_num()); me: 0 me: 3 me: 2 me: 1 21 OpenMP-Kurs Dieter an Mey 21.01.2002 Die Komponenten von OpenMP - schematisch Nutzer Shell OpenMP-Programm Umgebungsvariablen Direktiven Laufzeitfunktionen OpenMP-Laufzeitsystem Betriebsystem - Threads 22 OpenMP-Kurs Dieter an Mey 21.01.2002

OpenMP - Gliederung Einleitung: Geschichte, Compiler, OpenMP-Struktur Einführung in OpenMP Format der Direktiven Laufzeitfunktionen Parallele Regionen Arbeitsteilung (worksharing( worksharing) Verwaisen (orphaning( orphaning) Daten-Geltungsbereiche (data( scope) Synchronisation Überblick über alle Kompontenten von OpenMP Ein Beispiel (Berechnung von Pi) Strategien, Performance Klassifizierung von Variablen Parallelisierung auf Schleifenebene Grobgranulare Arbeitsteilung SPMD OpenMP versus MPI Anwendungsbeispiele Jacobi, Panta 23 OpenMP-Kurs Dieter an Mey 21.01.2002 Format der Direktiven Fortran77: C*** OpenMP-Direktive C$OMP directive [clause[[,] clause ] ] **** OpenMP-Direktive *$OMP directive [clause[[,] clause ] ] C*** OpenMP-Direktive mit Fortsetzungzeile C$OMP directive clause clause C$OMP+clause Fortran90:!*** OpenMP-Direktive!$OMP directive [clause[,]]!*** OpenMP-Direktive mit Fortsetzungzeile!$OMP directive clause clause &!$OMP& clause C: /*** OpenMP-Direktive */ #pragma omp directive [clause..]!*** OpenMP-Direktive mit Fortsetzungzeile #pragma omp directive clause \ clause 24 OpenMP-Kurs Dieter an Mey 21.01.2002

Verschiedenes Bedingte Übersetzung Äquivalent: C23456789 C$ wird ersetzt durch 2 Blanks C$ 10 IAM = OMP_GET_THREAD_NUM()+ C$ & INDEX #ifdef _OPENMP 10 IAM = OMP_GET_THREAD_NUM()+ & INDEX #endif #ifdef _OPENMP iam=omp_get_thread_num()+index; #endif!$ wird ersetzt durch 2 Blanks!$ IAM = OMP_GET_THREAD_NUM()+ &!$ INDEX 25 OpenMP-Kurs Dieter an Mey 21.01.2002 Laufzeitfunktionen program simple implicit integer (a-z) logical omp_in_parallel Serielle Region export OMP_NUM_THREADS=3 write (*,*) "inside parallel region? ", omp_in_parallel() write (*,*) "number of available processors ", omp_get_num_procs() write (*,*) "maximum number of threads ", omp_get_max_threads() call omp_set_num_threads ( max(1,omp_get_max_threads()-1) )!$omp parallel Parallele write (*,*) "inside parallel region? ", omp_in_parallel() write (*,*) "number of threads in the team ", omp_get_num_threads() Region write (*,*) "my thread id ", omp_get_thread_num()!$omp end parallel end program inside parallel region? F number of available processors 16 maximum number of threads 3 Redundante Ausführung! inside parallel region? T number of threads in the team 2 my thread id 0 inside parallel region? T number of threads in the team 2 26 OpenMP-Kurs Dieter an Mey my thread id 21.01.2002 1

Serielle Region Parallele Regionen (1) program simple implicit integer (a-z) write (*,*) Region A: ", omp_get_thread_num() export OMP_NUM_THREADS=4 Parallele!$omp parallel write (*,*) Region B: ", omp_get_thread_num() Region!$omp end parallel write (*,*) Region C: ", omp_get_thread_num() Serielle Region call omp_set_num_threads(2) Parallele!$omp parallel write (*,*) Region D: ", omp_get_thread_num() Region!$omp end parallel Serielle Region write (*,*) Region E: ", omp_get_thread_num() Parallele!$omp parallel num_threads(3) Region write (*,*) Region F: ", omp_get_thread_num()!$omp end parallel Serielle Region write (*,*) Region G: ", omp_get_thread_num() end program Region A: 0 Region B: 0 Region B: 3 Region B: 1 Region B: 2 Region C: 0 Region D: 1 Region D: 0 Region E: 0 Region F: 2 Region F: 0 Region F: 1 Region G: 0 27 OpenMP-Kurs Dieter an Mey 21.01.2002 Parallele Regionen (2) Master Thread Slave Threads Slave Threads Slave Threads Parallele Region Serielle Region Das OpenMP-Program Program beginnt wie ein serielles : single threaded Region A: 0 Am Anfang der Parallelen Region B: 0 Region B: 3 Region werden die Slave Region B: 1 Threads gestartet. Sie bilden Region B: 2 mit dem Master ein Team. Region C: 0 Zwischen den Parallelen Regionen schlafen die Slave Threads. Region D: 1 Region D: 0 Region E: 0 Region F: 2 Region F: 0 Region F: 1 Region G: 0 28 OpenMP-Kurs Dieter an Mey 21.01.2002

Parallele Regionen (3) - Sun Master Thread Slave Threads Slave Threads Slave Threads Parallele Region Serielle Region Zwischen den Parallelen Regionen schlafen die Slave Threads. Die Tiefe des Schlafes kann durch die Umgebungsvariable SUMW_MP_THR_IDLE beeinflusst werden: SUMW_MP_THR_IDLE=spin (default) busy waiting die schlafenden Threads geben ihre CPU nicht ab SUMW_MP_THR_IDLE=sleep idle waiting die schlafenden Threads geben ihre CPU nicht ab SUMW_MP_THR_IDLE=ns s (Sekunden) SUMW_MP_THR_IDLE=nms (Millisekunden) Kompromiss die schlafenden Threads geben ihre CPU nach einer gewissen Zeit ab 29 OpenMP-Kurs Dieter an Mey 21.01.2002 Arbeitsteilung (1) - Prinzip Prozessoren do i = 1, 100 a(i) = b(i) + c(i) Arbeitsteilung (worksharing) do i = 1, 25 a(i) = b(i) + c(i) do i = 26, 50 a(i) = b(i) + c(i) do i = 51, 75 a(i) = b(i) + c(i) do i = 76, 100 a(i) = b(i) + c(i) Speicher A(1)... A(100) B(1)... B(100) C(1)... C(100) 30 OpenMP-Kurs Dieter an Mey 21.01.2002

Arbeitsteilung (2) mit omp_get get_thread_num C Fortran77 C$omp parallel if ( omp_get_thread_num() == 0 ) do i = 1, 25 a(i) = b(i) + c(i)! Fortran 90!$omp parallel else if ( omp_get_thread_num() == 1 ) select case ( omp_get_thread_num() ) do i = 26, 50 case ( 0 ) a(i) = b(i) + c(i) a(1:25) = b(1:25) + c(1:25) case (1) else if ( omp_get_thread_num() == 2 ) a(26:50) = b(26:50) + c(26:50) do i = 51, 75 case(2) a(i) = b(i) + c(i) a(51:75) = b(51:75) + c(51:75) case (3) else if ( omp_get_thread_num() == 3 ) a(76:100) = b(76:100) + c(76:100) do i = 76, 100 end select a(i) = b(i) + c(i)!$omp end parallel end if C$omp end parallel 31 OpenMP-Kurs Dieter an Mey 21.01.2002 Arbeitsteilung (3) parallel sections C Fortran77 C$omp parallel C$omp sections C$omp section do i = 1, 25 a(i) = b(i) + c(i) Die end Kurzschreibweise do ist C$omp nur möglich, section wenn in der Parallelen do i = 26, Region 50 nur das Parallel a(i) = b(i) Sections + c(i) Worksharing Construct /* C, verkürzte Schreibweise */ #pragma omp parallel sections for ( i=1; i<25; i++ ) { a[i] = b[i] + c[i] ; #pragma omp section for ( i=26; i<50; i++ ) { a[i] = b[i] + c[i] ; #pragma omp section for ( i=51; i<75; i++ ) { a[i] = b[i] + c[i] ; #pragma omp section for ( i=76; i<100; i++ ) { a[i] = b[i] + c[i] ; #pragma omp end parallel sections C$omp enthalten section ist.! Fortran 90, verkürzte Schreibweise do i = 51, 75!$omp parallel sections a(i) = b(i) + c(i) a(1:25) = b(1:25) + c(1:25)!$omp section C$omp section a(26:50) = b(26:50) + c(26:50) do i = 76, 100!$omp section a(i) = b(i) + c(i) a(51:75) = b(51:75) + c(51:75)!$omp section C$omp end sections a(76:100) = b(76:100) + c(76:100) C$omp 32 end parallel OpenMP-Kurs!$omp Dieter an end Mey parallel sections 21.01.2002

Arbeitsteilung (4) parallel do C Fortran77 C$omp parallel C$omp do do i = 1, 100 a(i) = b(i) + c(i) C$omp C$omp end Die parallel Kurzschreibweise ist nur möglich, wenn in der /* C */ Parallelen Region nur das #pragma omp parallel Parallel Sections Do { Worksharing Construct #pragma omp enthalten for ist. { for ( i=1; i<100; i++ ) { a[i] = b[i] + c[i] ;! Fortran90, verkürzte Schreibweise!$omp parallel do do i = 1, 100 a(i) = b(i) + c(i) /* C, verkürzte Schreibweise */ #pragma omp parallel for for ( i=1; i<100; i++ ) { a[i] = b[i] + c[i] ; 33 OpenMP-Kurs Dieter an Mey 21.01.2002 Arbeitsteilung (5) parallel workshare neu in OpenMP V2.0! Nur in Fortran90!$omp parallel!$omp workshare a(1:100) = b(1:100) + c(1:100) d(2:99) = a(1:98) + a(3:100)!$omp end workshare!$omp end parallel! Nur in Fortran90, Kurzschreibweise!$omp parallel workshare a(1:100) = b(1:100) + c(1:100) d(2:99) = a(1:98) + a(3:100)!$omp end parallel workshare Achtung: versteckte Barrieren 34 OpenMP-Kurs Dieter an Mey 21.01.2002

Arbeitsteilung? single!$omp parallel!$omp single print *, nur einer!$omp end single!$omp end parallel #pragma omp parallel { #pragma omp single { printf nur einer\n ; 35 OpenMP-Kurs Dieter an Mey 21.01.2002 Verwaisen orphaning!$omp parallel call work ( 100, a, b, c )!$omp end parallel call work ( 100, a, b, c ) subroutine work ( n, a, b, c ) real a(n), b(n), c(n)!$omp do do i = 1, 100 a(i) = b(i) + c(i)!$omp return end subroutine work Statischer Bereich der Parallelen Region (static/lexical extent) Die Direktiven, die zu einer Parallelen Region gehören, müssen nicht in ein und dynamischer Bereich demselben Programmmodul der Parallelen Region stehen. (dynamic extent) Wird hier das Unterprogramm in der Parallelen Region aufgerufen, so wirkt das Verwaiste worksharing-konstrukt, (orphaned) anderenfalls wird es ignoriert. Direktive 36 OpenMP-Kurs Dieter an Mey 21.01.2002

Geltungsbereich der Variablen (0) Intro shared private global local Gültig für alle Threads und in allen Modulen Gültig für alle Threads aber lokal im jeweiligen Modul Privat für alle Threads aber gültig in allen Modulen Privat für alle Threads und gültig im jeweiligen Modulen 37 OpenMP-Kurs Dieter an Mey 21.01.2002 Geltungsbereich der Variablen (1) data scope do i = 1, 100 a(i) = b(i) + c(i)!$omp parallel do!$omp& default(none) private(i) shared(a,b,c) do i = 1, 100 a(i) = b(i) + c(i)!$omp end parallel do #pragma omp parallel for \ default(none) private(i) shared(a,b,c) { for ( i=1; i<100; i++ ) { a[i] = b[i] + c[i] ; Normalerweise sind alle Variablen (im statischen Bereich der Parallelen Region) von allen Threads gleichermaßen zugänglich, sie sind shared. Eine Ausnahme bilden die Laufindizes der parallelisierten Schleifen, sie sind standardmäßig private. Die Voreinstellung kann geändert werden durch: default (shared private none) Die default-klausel wirkt nur auf die Variablen des Statischen Bereiches! 38 OpenMP-Kurs Dieter an Mey 21.01.2002

Geltungsbereich der Variablen (2) defaults Das Shared-Memory-Programmiermodell: Normalerweise sind alle Variablen shared. Globale Variablen sind shared: Fortran: common-blöcke Fortran: Variable mit dem save-attribute Fortran: Modul-Variable falls sie nicht als threadprivate vereinbart sind C: Variable, deren Geltungsbereich sich auf die ganze Quelldatei erstreckt C: Variable mit dem static oder extern Attribut Ausnahme: Die Schleifenindizes von parallelisierten Zählschleifen sind private. ACHTUNG: Variablen in Unterprogrammen, die in einer Parallelen Region gerufen werden, und auf dem Stack abgelegt werden (Normalfall!) sind private. Variablen in Unterprogrammen, die in einer Parallelen Region gerufen werden und das save-attribut (C: static) haben, sind shared. 39 OpenMP-Kurs Dieter an Mey 21.01.2002 Geltungsbereich der Variablen (3) defaults program main integer n common / comblk / n double precision pi!$omp parallel do call calc_pi ( pi )!$omp end parallel end program Main shared subroutine calc_pi ( pi ) integer :: i, n common / comblk / n double precision, save :: sum, h double precision :: a,x,f, pi pi = private return end subroutine calc_pi 40 OpenMP-Kurs Dieter an Mey 21.01.2002

Geltungsbereich der Variablen (4) private #include <stdio.h> #include <omp.h> eine nicht initialisierte Kopie wird für jeden Thread angelegt int main(void) { int i; i = 42; printf( before parallel region: i=%d\n", i); # pragma omp parallel private(i) { printf("(%d): i=%d\n",omp_get_thread_num(),i); i += omp_get_thread_num(); printf("(%d): i:%d\n",omp_get_thread_num(),i); printf( after parallel region: i=%d\n", i); Output: before PR: i=42 (1): i=0 (3): i=0 (1): i: 1 (2): i=0 (3): i: 3 (0): i=0 (0): i: 0 (2): i: 2 after PR: i=42 return 1; 41 OpenMP-Kurs Dieter an Mey 21.01.2002 Geltungsbereich der Variablen (5) firstprivate #include <stdio.h> #include <omp.h> int main(void) { int i; i = 42; printf( before parallel region: i=%d\n", i); # pragma omp parallel firstprivate(i) { Die private Kopie wird mit dem Originalwert initialisiert printf("(%d): i=%d\n",omp_get_thread_num(),i); i += omp_get_thread_num(); printf("(%d): i:%d\n",omp_get_thread_num(),i); printf( after parallel region: i=%d\n", i); Output: before PR: i=42 (1): i=42 (3): i=42 (1): i: 43 (2): i=42 (3): i: 45 (0): i=42 (0): i: 42 (2): i: 44 after PR: i=42 return 1; 42 OpenMP-Kurs Dieter an Mey 21.01.2002

Lastprivate - Beispiel!$omp parallel default(none) shared(a,b,c)!$omp do lastprivate(i) do i = 1, 100 a(i) = b(i) + c(i)!$omp!$omp end parallel print *, i! 101 i erhält den Wert des letzten (seriellen) Schleifendurchlaufs 43 OpenMP-Kurs Dieter an Mey 21.01.2002 Geltungsbereich der Variablen (5) threadprivate #include <stdio.h> #include <omp.h> int t_private; #pragma omp threadprivate(t_private) void foo(void) { printf("(foo) thread(%d): t_private=%d\n", omp_get_thread_num(),t_private); main(){ int priv; #pragma omp parallel { t_private = omp_get_thread_num(); foo(); Output: (foo) thread(0): t_private=0 (foo) thread(3): t_private=3 (foo) thread(2): t_private=2 (foo) thread(1): t_private=1 Globale Daten werden durch die threadprivate-direktive privatisiert. Sie können durch die copyin-klausel initialisiert werden. 44 OpenMP-Kurs Dieter an Mey 21.01.2002

Geltungsbereich der Variablen (6) Übersicht shared private global local (static extend) F: common F: module + use C: file scope default shared-klausel Die Verwaltung des Heap muss synchronisiert F: common werden. + threadprivate Das F: häufige module Anlegen + use + von threadprivate dynamischen Variablen C: file mit scope malloc/new + threadprivate kann daher zu Performance-Einbußen führen. Verbesserung durch binden mit private-klausel cc xopenmp -lmtalloc local (dynamic extend) F: save C: static, extern C: heap (malloc, new) der Pointer kann auch private sein. default (f90 stackvar ) C: automatic variables 45 OpenMP-Kurs Dieter an Mey 21.01.2002 Kritische Region (1) do i = 1, 100 s = s + a(i) Prozessoren Arbeitsteilung (worksharing) do i = 1, 25 s = s + a(i) do i = 26, 50 s = s + a(i) do i = 51, 75 s = s + a(i) do i = 76, 100 s = s + a(i) Speicher S A(1)... A(100) Alle Prozessoren wollen gleichzeitig S lesen und schreiben! 46 OpenMP-Kurs Dieter an Mey 21.01.2002

Kritische Region (2) do i = 1, 100 s = s + a(i) Prozessoren Arbeitsteilung (worksharing) do i = 1, 25 s = s + a(i) do i = 26, 50 s = s + a(i) do i = 51, 75 s = s + a(i) do i = 76, 100 s = s + a(i) Speicher S A(1)... A(100) Zu einer Zeit darf nur ein Prozessor die kritische Region betreten => Performance? 47 OpenMP-Kurs Dieter an Mey 21.01.2002 Kritische Region (3) critical / end critical do i = 1, 100 s = s + a(i)!$omp parallel do private(i) do i = 1, 100!$omp critical s = s + a(i)!$omp end critical!$omp end parallel do #pragma omp parallel for private(i) { for ( i=1; i<100; i++ ) { #pragma omp critical { s += a[i]; Die Kritischen Regionen dürfen zu einer Zeit nur von einem Thread ausgeführt werden. Da hier die Schleifenkörper nur noch aus der kritischen Region bestehen, wird das Programm drastisch langsamer. 48 OpenMP-Kurs Dieter an Mey 21.01.2002

Kritische Region (4) do i = 1, 100 s = s + a(i) Prozessoren Die Kritische Arbeitsteilung Region wird (worksharing) aus der Schleife herausgezogen => Performance? do i = 1, 25 s1 = s1 + a(i) s = s + s1 do i = 26, 50 s2 = s2 + a(i) s = s + s2 do i = 51, 75 s3 = s3 + a(i) s = s + s3 do i = 76, 100 s4 = s4 + a(i) s = s + s4 Speicher S A(1)... A(100) S1 S3 S2 S4 49 OpenMP-Kurs Dieter an Mey 21.01.2002 Kritische Region (5) critical / end critical!$omp parallel private(i,s_local) s_local = 0.0!$omp do do i = 1, 100 s_local = s_local + a(i)!$omp!$omp critical s = s + s_local!$omp end critical!$omp end parallel #pragma omp parallel private(i,s_local) { s_local = 0.0; #pragma omp for { for ( i=1; i<100; i++ ) { s_local += a[i]; #pragma omp critical { s += s_local; 50 OpenMP-Kurs Dieter an Mey 21.01.2002 Jetzt werden die Teilsummen parallel berechnet. Die Kritischen Regionen wird nur noch einmal von jedem Thread durchlaufen.

Kritische Region (6) named critical region!$omp parallel private(i,s_local) s_local = 0.0!$omp do do i = 1, 100 s_local = s_local + a(i)!$omp!$omp critical (sum) s = s + s_local!$omp end critical (sum)!$omp end parallel #pragma omp parallel private(i,s_local) { s_local = 0.0; #pragma omp for { for ( i=1; i<100; i++ ) { s_local += a[i]; #pragma omp critical (sum) { s += s_local; 51 OpenMP-Kurs Dieter an Mey 21.01.2002 Kritische Regionen können benannt werden. Das ist dann von Vorteil, wenn in einer Parallelen Region mehrere Kritische Regionen auftreten. Der Namen ist eine globale Größe. Kritische Region (7) atomic!$omp parallel private(i,s_local) s_local = 0.0!$omp do do i = 1, 100 s_local = s_local + a(i)!$omp!$omp atomic s = s + s_local!$omp end parallel #pragma omp parallel for private(i,s_local) { s_local = 0.0; #pragma omp for { for ( i=1; i<100; i++ ) { s_local += a[i]; #pragma omp atomic { s += s_local; 52 OpenMP-Kurs Dieter an Mey 21.01.2002 Wenn die Kritischen Region nur aus einem Statement mit einfacher Struktur besteht var = var op expression oder var = intrinsic ( var,expression ) bzw. var binop= expression; oder var++; var--; ++var;--var so kann ist die atomic-direktive verwendet werden, die auf schnelle Hardware-Mechanismen abgebildet werden kann.

Reduktionen reduction clause do i = 1, 100 s = s + a(i)!$omp parallel do private(i) reduction(+:s) do i = 1, 100 s = s + a(i)!$omp end parallel do #pragma omp parallel for private(i) \ reduction(+:s) { for ( i=1; i<100; i++ ) { s += a[i]; Genau für diesen häufig auftretenden Fall gibt es die Reduktionsklausel. reduction({op intrinsic:list) mit op = { + * -.and..or..eqv..neqv. oder intrinsic = { max, min, iand, ior, ieor bzw. op = { + * - & ^ && list ist eine Komma-separierte Liste von Variablen 53 OpenMP-Kurs Dieter an Mey 21.01.2002 Reduktionen unterschiedliche Rundungsfehler Bei der Parallelisierung von solchen Rekursionen ist mit einer Änderung des Rundungsfehlerverhaltens zu rechnen Unterschiedliche Rundungsfehler: seriell seriell (verschiedene Compileroptionen) seriell parallel (OpenMP oder Autoparallel) parallel parallel (aufeinanderfolgende Rechenläufe) parallel parallel (Unterschiedliche Prozessorzahl) Abhilfe: Reduzierung der seriellen Optimierung: -fsimple=0 -xnolibmopt Partielle Parallelisierung Autoparallelisierung mit noreduction 54 OpenMP-Kurs Dieter an Mey 21.01.2002!$omp parallel do reduction(+:s) do i = 1, 100 s = s + a(i) * b(i) / c(i)!$omp end parallel do!$omp parallel do do i = 1, 100 tmp(i) = a(i) * b(i) / c(i)!$omp end parallel do do i = 1, 100 s = s + tmp(i)

Synchronisation barrier Jeder Thread wartet an der Barriere, bis alle Threads des Teams diese Barriere erreicht haben!$omp parallel print *, bin schon da \n ;!$omp barrier print *, gemeinsam geht s weiter ;!$omp end parallel #pragma omp parallel { printf bin schon da \n ; #pragma omp barrier printf gemeinsam geht s weiter\n ; Folgende Konstrukte haben eine implizite Barriere, falls diese nicht durch eine nowait Klausel abgeschaltet wird: end parallel end sections end single end workshare 55 OpenMP-Kurs Dieter an Mey 21.01.2002 Synchronisation master Nur der Master-Thread führt diese Programmsegment durch, alle anderen überspringen es.!$omp parallel!$omp master print *, nur der Meister! ;!$omp end master!$omp end parallel!$omp parallel if ( omp_get_thread_num() == 0 ) print *, so geht s auch. der Meister! ;!$omp end parallel #pragma omp parallel { #pragma omp master printf nur der Meister!\n ; Im Gegensatz zur single-direktive: Keine implizite Barriere am Ende! 56 OpenMP-Kurs Dieter an Mey 21.01.2002

Synchronisation nowait Mit der nowait-klausel können überflüssige Barrieren eingespart werden. Barrieren sind die wesentlichen Bremsen, die den Speedup reduzieren.!$omp parallel!$omp do schedule(static) do i = 1, 100 a(i) =!$omp nowait!$omp do schedule(static) do i = 1, 100 b(i) = a(i) **2!$omp nowait ACHTUNG: bei schedule(dynamic) kann es schief gehen!!$omp end parallel 57 OpenMP-Kurs Dieter an Mey 21.01.2002 program main implicit integer (a-z)!$omp parallel Synchonisation - ordered!$omp do do i = 1, omp_get_num_threads()!$omp print *, 'me: ', omp_get_thread_num(), ' i: ', i!$omp do ordered do i = 1, omp_get_num_threads()!$omp ordered!$omp end ordered!$omp!$omp end parallel end print *, 'me: ', omp_get_thread_num(), ' i: ', i 58 OpenMP-Kurs Dieter an Mey 21.01.2002 me: 0 i: 1 me: 3 i: 4 me: 2 i: 3 me: 1 i: 2 me: 1 i: 1 me: 0 i: 2 me: 2 i: 3 me: 3 i: 4

Synchronisation - flush!$omp flush [(list)] Die flush-direktive sorgt dafür, dass alle Speicheroperationen [ bzgl. der angegebenen Liste der Variablen ] abgeschlossen werden, und anschließend bei Bedarf wieder aus dem Speicher geladen werden. Betroffen sind shared Variablen. Folgende Konstrukte implizieren eine flush-direktive: barrier critical und end critical ABER: Kein implizites flush bei do end sections master und end master end single sections end workshare single ordered und end ordered workshare parallel und end parallel end {do sections single nowait 59 OpenMP-Kurs Dieter an Mey 21.01.2002 Geordnete Ausgabe ohne ordered-klausel - flush program ordered integer me, ticket, omp_get_thread_num!$omp parallel private(me) shared(ticket) me = omp_get_thread_num()!$omp single ticket = 0!$OMP end single do while ( ticket < me )!$OMP flush(ticket) Warteschleife call work(me)! do ordered work here ticket = ticket + 1!$OMP flush(ticket) write (*,*) me!$omp end parallel end program flush 60 OpenMP-Kurs Dieter an Mey 21.01.2002

OpenMP - Gliederung Einleitung: Geschichte, Compiler, OpenMP-Struktur Einführung in OpenMP Format der Direktiven Laufzeitfunktionen Parallele Regionen Arbeitsteilung (worksharing( worksharing) Verwaisen (orphaning( orphaning) Daten-Geltungsbereiche (data( scope) Synchronisation Überblick über alle Kompontenten von OpenMP Ein Beispiel (Berechnung von Pi) Strategien, Performance Klassifizierung von Variablen Parallelisierung auf Schleifenebene Grobgranulare Arbeitsteilung SPMD OpenMP versus MPI Anwendungsbeispiele Jacobi, Panta 61 OpenMP-Kurs Dieter an Mey 21.01.2002 OpenMP Directives Runtime Library Binding Conditional Compilation Nesting Environment Variables Control Constructs Parallel Region Data Constructs ThreadPrivate Synchonization Constructs Master Work Sharing Do Sections Schedule Ordered Data Scope Shared Private Reduction FirstPrivate LastPrivate Copyin Single Default 62 OpenMP-Kurs Dieter an Mey 21.01.2002 Critical Barrier Atomic Ordered Flush

OpenMP Directives Environment Variables OMP_SCHEDULE OMP_NUM_THREADS OMP_DYNAMIC OMP_NESTED Lock Functions Runtime Library Environment Functions OMP_GET/SET_NUM_THREADS OMP_GET_MAX_THREADS OMP_GET_THREAD_NUM OMP_GET_NUM_PROCS OMP_IN_PARALLEL OMP_GET/SET_DYNAMIC OMP_GET/SET_NESTED OMP_INIT_LOCK OMP_DESTROY_LOCK OMP_[UN]SET_LOCK OMP_TEST_LOCK 63 OpenMP-Kurs Dieter an Mey 21.01.2002 Direktiven Parallel Region Construct!$omp parallel [clause[[,] clause] ] block!$omp end parallel mit clause aus private (list) shared (list) default ( private shared none ) firstprivate (list) reduction ({op intrinsic:list) copyin (list) if ( logexp ) num_threads ( intexp ) neu in OpenMP V2.0 Parallele Ausführung des Programmsegmentes block Der (Master-) Thread, der auf die Parallele Region trifft, spaltet ein Team von (Slave-)Threads ab, die alle dasselbe Programmsegment ausführen. Die Anzahl der Threads (Master + Slaves) wird durch die Umgebungsvariable OMP_NUM_THREADS oder durch die Laufzeitfunktion omp_set_num_threads oder durch die num_threads-klausel spezifiziert, es sei denn, dass dem Laufzeitsystem explizit die dynamische Steuerung der Threadzahl durch die Umgebungsvariable OMP_DYNAMIC oder die Laufzeitfunktion omp_set_dynamic überlassen wurde. Wenn die if-klausel den Wert.FALSE. besitzt, so wird block seriell ausgeführt. Die end parallel-direktive enthält implizit eine Barriere. 64 OpenMP-Kurs Dieter an Mey 21.01.2002

Direktiven Work-sharing Constructs - do!$omp do [clause[[,] clause] ] do_loop!$omp [nowait] mit clause aus private (list) firstprivate (list) lastprivate (list) reduction ({op intrinsic:list) schedule (type[,chunk] ) ordered Die Ausführung der Zählschleife, die unmittelbar der do-direktive folgt wird auf die beteiligten Threads aufgeteilt, so wie durch die schedule-klausel angegeben. Die ordered-klausel muss hinzugefügt werden, wenn innerhalb der Zählschleife eine ordered-direktive verwendet werden soll. Die -Direktive enthält implizit eine Barriere, falls nicht die nowait-klausel hinzugefügt wird. 65 OpenMP-Kurs Dieter an Mey 21.01.2002 Direktiven Work-sharing Constructs do - scheduling schedule (static[,chunk]) Die Iterationen werden gleichmäßig in Blöcken (chunks) der Größe chunk reihum auf die Threads aufgeteilt. Wird chunk nicht angegeben, so ist die Blockgröße gleich der Anzahl der Iterationen dividiert durch die Anzahl der Threads. schedule (dynamic [,chunk]) Die Iterationen werden in Blöcken (chunks) der Größe chunk auf die Threads aufgeteilt. Der Thread, der seinen Block abgearbeitet hat, bekommt einen neuen zugewiesen. Wird chunk nicht angegeben, so ist die Blockgröße gleich 1. schedule (guided [,chunk]) Die Iterationen werden in Blöcken (chunks) auf die Threads aufgeteilt, deren Größe exponentiell abnimmt. Der Thread, der seinen Block abgearbeitet hat, bekommt einen neuen zugewiesen. Mit chunk wird die minimale Blockgröße angegeben. Wird chunk nicht angegeben, so ist die minimale Blockgröße gleich 1. schedule (runtime) Das Schleifen-Scheduling kann zur Laufzeit durch die Umgebungsvariable OMP_SCHEDULE festgelegt werden. Die Voreinstellungen sind implementationsabhängig. Meist ist schedule (static) voreingestellt 66 OpenMP-Kurs Dieter an Mey 21.01.2002

Direktiven Work-sharing Constructs - sections!$omp sections [clause[[,] clause] ] [!$omp section] block [!$omp section block]!$omp end sections [nowait] Die Ausführung der einzelnen Programmsegmente block, wird auf die Threads verteilt. Die end sections-direktive enthält implizit eine Barriere, falls nicht die nowait-klausel hinzugefügt wird. mit clause aus private (list) firstprivate (list) lastprivate (list) reduction ({op intrinsic:list) 67 OpenMP-Kurs Dieter an Mey 21.01.2002 Direktiven Work-sharing Constructs - single!$omp single [clause[[,] clause] ] block!$omp end single { [nowait] [copyprivate (list)] mit clause aus private (list) firstprivate (list) neu in OpenMP V2.0 Das Programmsegment block wird nur von einem Thread des Teams ausgeführt. Die end single-direktive enthält implizit eine Barriere, falls nicht die nowait-klausel hinzugefügt wird. Dort warten ggfls. alle anderen Threads. Mit der copyprivate-klausel können private Variablen an die anderen Threads weitergegeben werden (broadcast, z.b. nach einer Eingabe in block.) copyprivate und nowait schließen einander aus. 68 OpenMP-Kurs Dieter an Mey 21.01.2002

Direktiven Work-sharing Constructs - workshare neu in OpenMP V2.0 (nur Fortran90)!$omp workshare block!$omp end workshare [nowait] Die Ausführung Fortran90-Feldzuweisungen, wird auf die beteiligten Threads aufgeteilt. Zwischen den Statements werden u.u. implizite Barrieren eingefügt Die end workshare-direktive enthält implizit eine Barriere, falls nicht die nowait-klausel hinzugefügt wird. 69 OpenMP-Kurs Dieter an Mey 21.01.2002 Direktiven Besonderheiten von C / C++ #pragma omp parallel [clause[ clause] ] { structured block #pragma omp for [clause[ clause] ] { for-loop #pragma omp sections [clause[[,] clause] ] { [#pragma omp section] { structured block [#pragma omp section { structured block ] Die default-klausel kann nur die Werte shared oder none enthalten. Das for-statement muss einfach sein. Der Verzicht auf die Barriere am Ende des for-work-sharing-konstruktes wird durch eine nowait-klausel bei dem for-pragma spezifiziert. Der Verzicht auf die Barriere am Ende des sections-work-sharing-konstruktes wird durch eine nowait-klausel bei dem sections-pragma spezifiziert. 70 OpenMP-Kurs Dieter an Mey 21.01.2002

Direktiven Kombinierte Parallel Work-sharing Constructs!$omp parallel do [clause[[,] clause] ] do_loop!$omp end parallel do!$omp parallel sections [clause[[,] clause] ] [!$omp section] block [!$omp section block]!$omp end parallel sections Abkürzende Schreibweisen für Parallele Regionen, die nur ein Work-sharing-Konstrukt beinhalten. Es können alle die Klauseln verwendet werden, die zu der parallel-direktive oder zu dem Work-sharing-Konstrukt gehören.!$omp parallel workshare [clause[[,] clause] ] block neu in OpenMP V2.0 (Fortran90)!$omp end parallel workshare 71 OpenMP-Kurs Dieter an Mey 21.01.2002 Direktiven Synchronization Constructs!$omp master block!$omp end master!$omp critical [(name)] block!$omp end critical [(name)]!$omp barrier!$omp atomic!$omp flush [(list)]!$omp ordered block!$omp end ordered Das Programmsegment block wird nur vom Master-Thread ausgeführt. Das Konstrukt enthält keine implizite Barriere! Kritische Bereiche (block) mit gleichem Namen werden zu einer Zeit nur von einem Thread des Teams ausgeführt. Das Konstrukt enthält keine implizite Barriere! Die Barriere synchronisiert alle Threads eines Teams. Jeder Thread wartet, bis alle anderen Threads des Teams diesen Punkt erreicht haben. Die atomic-direktive stellt sicher, dass eine Speicherzelle atomar, d.h. ungestört von anderen schreibenden Zugriffen geändert werden kann. Die (explizite oder implizite) flush-direktive sorgt dafür, dass alle Threads ein konsistentes Bild von allen oder einer Liste list von Variablen besitzen. Das Programmsegment block wird in der Reihenfolge ausgeführt, in der es im seriellen Fall ausgeführt würde. Die zugehörge do-direktive muß die ordered-klausel besitzen. Es wird zu einer Zeit nur von einem Thread des Teams durchlaufen. 72 OpenMP-Kurs Dieter an Mey 21.01.2002

threadprivate (list) Direktiven Data Scope Die threadprivate-direktive privatisiert benannte common-blöcke oder Variablen, globalisiert sie aber innerhalb eines jeden Threads. ( In C / C++: externe/globale Variable) Diese Direktive gehört überall dort in den Anweisungsteil wo auch die common-blöcke bzw. die Variablen deklariert werden. In den seriellen Regionen und den master-bereichen werden auf die common-blöcke bzw. die Variablen des Master-Threads zugegriffen. Am Anfang der ersten Parallelen Region, werden die als threadprivate vereinbarten Variablen bzw. common-blöcke angelegt. Werden sie in einer copyin-klausel einer parallel-direktive aufgeführt, so werden sie initialisiert mit dem Inhalt der entsprechenden Variablen bzw. des entsprechenden common-blocks des Master-Threads. Wird die Anzahl der Threads nicht dynamischen gesteuert, so bleiben Inhalte und Zustände zwischen Parallelen Regionen erhalten. 73 OpenMP-Kurs Dieter an Mey 21.01.2002 Klauseln Data Scope (1) private (list) shared (list) Für jeden Thread werden neue private Objekte angelegt, deren Inhalte anfangs nicht definiert sind. Die entsprechenden (shared) Objekte haben am Ende des Konstuktes keinen wohl definierten Wert. Alle Threads greifen auf denselben Speicherbereich zu. Aufgrund der Verwendung von Registern und Caches werden Änderungen durch einen Thread nicht sofort bei den anderen Threads wahrgenommen, es sei denn eine flush-direktive wird verwendet. default ( private shared none ) Die standardmäßige Voreinstellung des Datengeltungsbereiches auf shared kann verändert werden firstprivate (list) lastprivate (list) Wie mit der private-direktive werden private Objekte für jeden Thread erzeugt. Diese werden zusätzlich mit dem Wert des entsprechenden ursprünglichen Objektes initialisiert. Wie mit der private-direktive werden private Objekte für jeden Thread erzeugt. Zusätzlich werd die Werte der seriell letzten Iteration bzw. der lexikalisch letzten section auf die entsprechenden ursprünglichen Objekte übertragen. 74 OpenMP-Kurs Dieter an Mey 21.01.2002

Klauseln Data Scope (2) reduction ({op intrinsic:list) Es wird eine Reduktion mit dem Operator op intrinsic auf die Variablen in der Liste list ausgeführt. ACHTUNG: Die Reihenfolge der Berechnungen ist zufällig, daher treten unterschiedliche Rundungsfehlereinflüsse auf! Die Variablen der Liste müssen im umgebenden Kontext shared sein. Es wird dann eine private Kopie für die Zwischenergebnisse angelegt, die in Abhängigkeit von der gewählten Operation sinnvoll initialisiert wird. Das Endergebnis der Reduktion steht erst nach der nächsten Barriere zur Verfügung (bei Verwendung von nowait) Fortran: op = { + * -.and..or..eqv..neqv. intrinsic = { max, min, iand, ior, ieor. C / C++: op = { + * - & ^ && list ist eine Komma-separierte Liste von Variablen 75 OpenMP-Kurs Dieter an Mey 21.01.2002 Klauseln Data Scope (3) copyin (list) Variablen, common-blöcke oder Variablen in common-blöcken, die als threadprivate deklariert wurden, können am Anfang einer Parallelen Region initialisiert werden, in dem sie den Wert des entsprechenden Objektes des Master-Threads erhalten. neu in OpenMP V2.0 : copyprivate (list) Mit dieser Klausel der end critical-direktive kann der Wert einer privaten Variablen an die anderen Threads übermittelt werden (broadcast) 76 OpenMP-Kurs Dieter an Mey 21.01.2002

Laufzeitroutinen integer function omp_get_num_threads () subroutine omp_set_num_threads ( intexp ) integer function omp_get_max_threads () integer function omp_get_thread_num () integer function omp_get_num_procs () logical function omp_in_parallel () logical function omp_get_dynamic () subroutine omp_set_dynamic ( logexp ) logical function omp_get_nested () subroutine omp_set_nested ( logexp ) neu in OpenMP V2.0: double precision function omp_get_wtime () double precision function omp_get_wtick () Setzen / Abfragen der Threadanzahl Abfragen der maximalen Threadzahl Abfragen der aktuellen Threadzahl Abfragen der Anzahl der Prozessoren (HW) In einer Parallelen Region? Abfragen / Setzen des Dynamisches Schleifen-Schedulings Abfragen / Setzen der geschachtelten Parallelisierung Echtzeit in Sekunden Abstand zwischen zwei Ticks in Sekunden 77 OpenMP-Kurs Dieter an Mey 21.01.2002 Laufzeitfunktionen - locks integer (kind=omp_lock_kind) :: svar subroutine omp_init_lock (svar) subroutine omp_destroy_lock (svar) subroutine omp_set_lock (svar) subroutine omp_unset_lock (svar) subroutine omp_test_lock (svar) neu im OpenMP Fortran API V2.0, im OpenMP C / C++ API V1.0 schon enthalten : integer (kind=omp_nest_lock_kind) :: nvar subroutine omp_init_nest_lock (nvar) subroutine omp_destroy_ nest_ lock (nvar) subroutine omp_set_ nest_ lock (nvar) subroutine omp_unset_ nest_ lock (nvar) subroutine omp_test_ nest_ lock (nvar) 78 OpenMP-Kurs Dieter an Mey 21.01.2002 integer*4/*8 bei 32-/ 64-Bit Adressierung Anmelden Abmelden Setzen (ggfls. nach Warten) Freigeben Testen und Setzen eines Locks mit dem Namen svar Nestable Locks können von einem Thread mehrfach gesperrt werden

Umgebungsvariablen OMP_SCHEDULE = { static dynamic guided [,chunk] OMP_NUM_THREADS = int OMP_DYNAMIC = {FALSE TRUE Spezifizieren der Aufteilung der Schleifendurchläufe auf die Threads, falls in der do-direktive die Klausel schedule(runtime) angegeben wurde. Spezifizieren der Anzahl der zu verwendenden Threads, falls diese nicht explizit durch die Laufzeitfunktion omp_set_num_threads oder die num_threads-klausel der parallel-direktive gesetzt wird. Bei dynamischem Schleifen- Scheduling ist dies das Maximum der Threadzahl Default: Sun-Compiler: 1, Guide: max Ein-/Ausschalten der dynamischen Einstellung der Threadzahl durch das Laufzeitsystem im Abhängigkeit von der aktuellen Maschinenauslastung Default: Sun-Compiler: TRUE, Guide: FALSE OMP_NESTED = {FALSE TRUE Ein-/Ausschalten der geschachtelten (nested) Parallelisierung. Parallele Regionen innerhalb von Parallelen Regionen werden durch die derzeitigen OpenMP-Compiler serialisiert. 79 OpenMP-Kurs Dieter an Mey 21.01.2002 OpenMP - Gliederung Einleitung: Geschichte, Compiler, OpenMP-Struktur Einführung in OpenMP Format der Direktiven Laufzeitfunktionen Parallele Regionen Arbeitsteilung (worksharing( worksharing) Verwaisen (orphaning( orphaning) Daten-Geltungsbereiche (data( scope) Synchronisation Überblick über alle Kompontenten von OpenMP Ein Beispiel (Berechnung von Pi) Strategien, Performance Klassifizierung von Variablen Parallelisierung auf Schleifenebene Grobgranulare Arbeitsteilung SPMD OpenMP versus MPI Anwendungsbeispiele Jacobi, Panta 80 OpenMP-Kurs Dieter an Mey 21.01.2002

Problemstellung und C-ProgrammkernC Die Kreiszahl π kann berechnet werden als Integral: 1 π = f(x)dx, mit f(x) = 4 /(1 + x 2 ) 0 Dieses Integral kann numerisch mit einer Quadraturformel (Mittelpunktsregel) angenähert werden: n π 1/n f(x i ), mit x i = (i-½)/ n für i=1,,n i=1 double f(double x) { return (double)4.0/(1.0+(x*x)); h = 1.0/(double)n; sum = 0.0; for(i=1;i<=n;i++) { x = h*((double)i - 0.5); /* Stützstelle */ sum += f(x); pi = h*sum; 81 OpenMP-Kurs Dieter an Mey 21.01.2002 Serielles Fortran90-Programm program main integer :: i,n double precision,parameter :: pi25dt=3.141592653589793238462643d0 double precision :: a,h,pi,sum,x double precision :: f f(a) = 4.d0 / (1.d0+a*a)! statement function do read (5,10001) n; if (n <= 0) exit h = 1.0d0 / n sum = 0.0d0 do i = 1, n x = h * (DBLE(i)-0.5d0) sum = sum + f(x) pi = h * sum write (6,10002) pi, ABS(pi-pi25dt) end program main 82 OpenMP-Kurs Dieter an Mey 21.01.2002

OpenMP-Programm Programm 1. Version in Fortran90 (Auszug) do read (5,10001) n if (n <= 0) exit allocate (fx(n),stat=ierror) h = 1.0d0 / n sum = 0.0d0!$omp parallel private(i,x) shared(h,fx)!$omp do do i = 1,n x = h * (DBLE(i)-0.5d0) fx(i) = f(x)!$omp!$omp end parallel do i = 1,n sum = sum + fx(i) pi = h * sum write (6,10002) pi, ABS(pi-pi25dt) deallocate (fx) 83 OpenMP-Kurs Dieter an Mey 21.01.2002 OpenMP-Programm Programm 2. Version in Fortran90 (Auszug) do read (5,10001) n if (n <= 0) exit sum = 0.0d0!$omp parallel!$omp do private(i,x) do i = 1,n x = h * (DBLE(i)-0.5d0)!$omp critical sum = sum + f(x)!$omp end critical!$omp!$omp end parallel pi = h * sum write (6,10002) pi, ABS(pi-pi25dt) 84 OpenMP-Kurs Dieter an Mey 21.01.2002

OpenMP-Programm Programm 3. Version in Fortran90 double precision :: sum_local do read (5,10001) n if (n <= 0) exit h = 1.0d0 / n sum = 0.0d0 sum=0!$omp parallel private(i,x,sum_local) sum_local = 0.0d0!$omp do do i = 1,n x = h * (DBLE(i)-0.5d0) sum_local = sum_local + f(x)!$omp!$omp critical sum = sum + sum_local!$omp end critical!$omp end parallel pi = h * sum write (6,10002) pi, ABS(pi-pi25dt) Thread 0 Lese n (z.b. n=6) sum_local=0 i=1 sum_local+=f(x i ) i=2 sum_local+=f(x i ) warten sum+=sum_local pi = h*sum Drucke pi Thread 1 sum_local=0 i=3 sum_local+=f(x i ) i=4 sum_local+=f(x i ) sum+=sum_local Thread 2 sum_local=0 i=5 sum_local+=f(x i ) i=6 sum_local+=f(x i ) warten warten sum+=sum_local 85 OpenMP-Kurs Dieter an Mey 21.01.2002 OpenMP-Programm Programm 4. Version in Fortran90 (Auszug) do read (5,10001) n if (n <= 0) exit h = 1.0d0 / n sum = 0.0d0!$omp parallel private(i,x)!$omp do parallel reduction(+:sum) do private(i,x) reduction(+:sum) do i = 1,n x = h * (DBLE(i)-0.5d0) sum = sum + f(x)!$omp!$omp end parallel pi = h * sum write (6,10002) pi, ABS(pi-pi25dt) 86 OpenMP-Kurs Dieter an Mey 21.01.2002

OpenMP-Programm Programm 5. Version in Fortran90 (Auszug)!$omp parallel private(i,x) do!$omp single read (5,10001) n!$omp end single if (n <= 0) exit h = 1.0d0 / n! Wird redundant von jedem Thread ausgeführt sum = 0.0d0! Wird redundant von jedem Thread ausgeführt!$omp barrier! Wichtig, nicht vergessen!$omp do reduction(+:sum) do i = 1,n x = h * (DBLE(i)-0.5d0) sum = sum + f(x)!$omp!$omp single pi = h * sum write (6,10002) pi, ABS(pi-pi25dt)!$omp end single!$omp end parallel 87 OpenMP-Kurs Dieter an Mey 21.01.2002 OpenMP-Programm Programm 5. Version in C (Auszug) int main(int argc, char *argv[]) { long, n, i; double h, pi, sum, x; # pragma omp parallel private (i,x) { for (;;) { # pragma omp single { printf("enter the number of intervals:(0 quits)");scanf("%u",&n); if (n==0) break; h = 1.0/(double)n; /* Wird redundant von jedem Thread ausgeführt */ sum = 0.0; /* Wird redundant von jedem Thread ausgeführt */ # pragma omp barrier /* Wichtig, nicht vergessen */ # pragma omp for reduction (+:sum) for(i=1;i<=n;i++) { x = h*((double)i-0.5); sum += f(x); # pragma omp single { pi = h*sum; printf(" ",pi,fabs(pi-pi)); 88 OpenMP-Kurs Dieter an Mey 21.01.2002

OpenMP-Programm Programm 6. Version in Fortran90 (Auszug) program main!$omp parallel do!!$omp single write (6,10000) read (5,10001) n!$omp end single if (n <= 0) exit call calc_pi (n, pi)!$omp single subroutine calc_pi (n, pi) integer, intent(in) :: n double precision, intent(out) :: pi double precision, save :: sum, h integer :: i double precision :: a,x,f f(a) = 4.d0 / (1.d0+a*a)!$omp single h = 1.0d0 / n sum = 0.0d0!$omp end single write (6,10002) pi, ABS(pi-pi25dt)!$omp do reduction(+:sum) private(i,x)!$omp end single do i = 1,n x = h * (DBLE(i)-0.5d0)!$omp end parallel sum = sum + f(x) end program Main!$omp!$omp single pi = h * sum!$omp end single return 89 OpenMP-Kurs Dieter end an subroutine Mey calc_pi 21.01.2002 OpenMP-Programm Programm 7. Version in Fortran90 (Auszug) program main!$omp parallel do!!$omp single write (6,10000) read (5,10001) n!$omp end single if (n <= 0) exit call calc_pi (n, pi)!$omp single subroutine calc_pi (n, pi) double precision, save :: sum, h integer :: omp_get_thread_num,omp_get_num_threads integer :: myid,numthreads double precision :: sum_local myid = omp_get_thread_num() numthreads = omp_get_num_threads()!$omp single h = 1.0d0 / n sum = 0.0d0!$omp end single do i = myid+1, n, numthreads write (6,10002) pi, ABS(pi-pi25dt) x = h * (DBLE(i)-0.5d0)!$omp end single!$omp end parallel end program Main sum_local = sum_local + f(x)!$omp critical sum = sum + sum_local!$omp end critical!$omp barrier!$omp single pi = h * sum!$omp end single 90 OpenMP-Kurs return Dieter an Mey 21.01.2002 end subroutine calc_pi

#include <omp.h> #define SIZE 10000 template <typename T,int size> class Array { private: T data[size]; public: Array() /* Default constructor */ { ~Array() /* Array destructor */ { Array(const T& r) /* Regular constructor */ { #pragma omp parallel for for (int i=0 ; i<size ; i++) data[i]=r; Array(const Array& rhs) /* Copy constructor end */ do { #pragma omp parallel for for (int i=0 ; i<size ; i++) data[i]=rhs[i]; // Read only and read/write subscript operators const T& operator[](int i) const { return data[i]; T& operator[](int i) { return data[i]; C++ - Beispiel Array& operator=(const Array& rhs) /* Assignment operator */ { #pragma omp parallel for for (int i=0 ; i<size ; i++) data[i]=rhs[i]; return *this; ; //-- Operators --------------------------------------------------------------- template <typename T,int size> Array<T,size> operator+(const Array<T,size>& a,const Array<T,s Array<T,size> ret; #pragma omp parallel for for (int i=0 ; i<size ; i++) ret[i] = a[i]+b[i]; return ret; void do_it(int repeat) { Array<double,SIZE> a(1.0),b(2.0), c(3.0),d(4.0),res(5.0); for (int i=0; i<repeat; i++) res = a * b - c + d;! Analoges Fortran90 Programm subroutine do_it ( repeat ) integer, intent(in) :: repeat integer, parameter :: SIZE=10000 real*8, dimension(size) :: a=1.0,b=2.0,c=3.0,d=4.0,res=5.0!$omp parallel workshare do i = 0, repeat-1 res = a * b c + d end subroutine 91 OpenMP-Kurs Dieter an Mey 21.01.2002 OpenMP - Gliederung Einleitung: Geschichte, Compiler, OpenMP-Struktur Einführung in OpenMP Format der Direktiven Laufzeitfunktionen Parallele Regionen Arbeitsteilung (worksharing( worksharing) Verwaisen (orphaning( orphaning) Daten-Geltungsbereiche (data( scope) Synchronisation Überblick über alle Kompontenten von OpenMP Ein Beispiel (Berechnung von Pi) Vertiefung, Strategien, Performance Klassifizierung von Variablen Parallelisierung auf Schleifenebene Grobgranulare Arbeitsteilung SPMD OpenMP versus MPI Anwendungsbeispiele Jacobi, Panta 92 OpenMP-Kurs Dieter an Mey 21.01.2002

Klassifizierung von Variablen (1) Beachte Zugriffsart: Variable wird nur gelesen => shared Variable wird zuerst gelesen und dann Variable wird zuerst modifiziert und dann gelesen => evtl. private Variable wird nur modifiziert => evtl. lastprivate!$omp parallel do do i = 1, n a(i) = b(i) * PI s = 0.0!$omp parallel do reduction(+:s) modifiziert => evtl. reduction, firstprivate? do i = 1, n s = s + a(i) print *, s!$omp parallel do private(t) do i = 1, n Mögliches Vorgehen: t = a(i) + b(i) c(i) = t * t einfach Work-sharing-Konstrukt einsetzen und mit Assure überprüfen diesen Vorgang wiederholen, bis Assure kein Problem mehr meldet einen möglichst kleinen Testfall aussuchen, der dennoch typisch ist. Assure benötigt viel mehr Speicherplatz und Laufzeit! 93 OpenMP-Kurs Dieter an Mey 21.01.2002 Klassifizierung von Variablen (2) Beachte Zugriffsart: Variable wird in der Parallelen Region modifiziert: Empfehlungen ohne Garantie! sie wird mit dem Index der parallelen Schleife indiziert => shared sie wird global, aber nur innerhalb der Parallelen Region benutzt => threadprivate sie wird nur temporär genutzt => private sie ist lokal in einem Unterprogramm (dynamic extend) mit dem save / static Attribut => threadprivate sonst per default => private (Sun: f90 stackvar / HP: f90 nosave ) im common-block/modul => threadprivate? Initialisierung mit copyin? anderenfalls Modifikationen in kritischen Regionen schützen Enthält ein common-block Variablen mit unterschiedlichen Eigenschaften, so muss er u.u. gespalten werden. 94 OpenMP-Kurs Dieter an Mey 21.01.2002

Welche Schleife soll parallelisiert werden? Wähle die am weitesten außen stehende Schleife (gröbst mögliche Parallelität) Ignoriere dabei Schleifen über Zeitschritte oder Iterationen (Rekursivität) Ignoriere Schleifen mit nur wenigen Iterationen Ignoriere Schleifen die nur unwichtige Unterprogramme aufrufen Vorsicht bei der Parallelisierung von Schleifen, in denen gemeinsame Daten modifiziert werden von Schleifen, die verlinkte Listen durchlaufen von Schleifen, die Ein-/Ausgabe enthalten 95 OpenMP-Kurs Dieter an Mey 21.01.2002 Was tun, bei mehreren parallelisierbaren Schleifen? Geschachtelte parallelisierbare Schleifen sind gut Obwohl die derzeitigen Compiler nested parallelism noch nicht unterstützen Wähle die am einfachsten parallelisierbare Schleife oder die mit den meisten Iterationen Achte auf Datenlokalität (False Sharing) Nutze die IF-Klausel zur dynamischen Auswahl der besten Schleife Kann die äußere Schleife zusätzlich mit MPI parallelisiert werden? Nicht geschachtelte parallelisierbare Schleifen Fasse Schleifen zusammen (Loop Fusion), Lokalität? Kann der dazwischen liegenden Code redundant ausgeführt werden? 96 OpenMP-Kurs Dieter an Mey 21.01.2002

Parallelisierung auf Schleifenebene (fein-granular granular) Vorteile: Jede einzelne Schleife wird parallel ausgeführt. Einfache schrittweise Vorgehensweise geringfügige Änderung des bestehenden Codes Nur eine Code-Version Kann ggfls. mit automatische Parallelisierung kombiniert werden Nachteile: Hoher Overhead durch häufigen Thread-Start und Synchronisierung Der Anteil an nicht parallelisiertem Code kann schnell dominieren, daher skaliert dieser Ansatz meist schlecht (Amdahl s Law). Die Datenverteilung kann sich von Schleife zu Schleife ändern (Daten wandern zwischen den Caches) 97 OpenMP-Kurs Dieter an Mey 21.01.2002 Verbesserung der Parallelisierung auf Schleifenebene Zusammenfassen mehrer Schleifen zu einer Parallele Region dadurch Verringerung des Overheads, die Schleifengrenzen für das Worksharing muss weiterhin jeweils berechnet werden Falls möglich Einsparung von Synchronisationspunkten durch NOWAIT häufig nur bei SCHEDULE(STATIC) möglich. Vergrößern der Parallelen Regionen durch Orphaning Ausführen des Codes zwischen den parallelisierbaren Schleifen in SINGLE oder MASTER Bereichen, oder redundante Ausführung mit allen Threads. 98 OpenMP-Kurs Dieter an Mey 21.01.2002

Grob-granulare Parallelisierung Gebietszerlegung Im Falle von zahlreichen ähnlichen parallelisierbaren Schleifen können die Schleifengrenzen vorher explizit berechnet werden. Allgemeinerer Ansatz: Gebietszerlegung, Jeder Thread erhält ein Teilgebiet zur Bearbeitung Erhöhter Programmieraufwand Grob-granularer Ansatz: Eine Parallele Region für das gesamte Programm Höhere Skalierbarkeit SPMD-Ansatz: Single Program, Multiple Data Alle zum Teilgebiet gehörenden Daten sind privat 99 OpenMP-Kurs Dieter an Mey 21.01.2002 Verwalten globaler Daten Globale Daten überspannen das gesamte Gebiet Felder sind meist Shared, jeder Thread nutzt ein anderes Teilfeld Änderung gemeinsamer Daten erfordert Synchronisation durch SINGLE- oder ATOMIC-Konstrukte Vereinbare private COMMON-Blöcke oder Daten mit globalem Geltungsbreich als THREADPRIVATE 100 OpenMP-Kurs Dieter an Mey 21.01.2002

SPMD-Programmierung Programmierung Vergleich von OpenMP und MPI Derselbe Algorithmus, einfachere Implementierung Die Modifikation von Shared Daten erfordert Synchronisation Keine expliziter Datentransfer, keine Notwendigkeit von Ghost Cells Die Parallelisierung kann sich auf den rechenintensiven Teil beschränken (Präund Postprosessing kann seriell bleiben) 101 OpenMP-Kurs Dieter an Mey 21.01.2002 Kombination von MPI und OpenMP auf SMP- Clustern OpenMP innerhalb eines SMP-Knotens, MPI über Knotengrenzen hinweg Mehrere MPI-Tasks können auch innerhalb eines SMP-Knotens gestartet werden. Grob-granulare Parallelisierung mit MPI und fein-granulare Parallelisierung mit OpenMP 102 OpenMP-Kurs Dieter an Mey 21.01.2002

Performance-Gesichtspunkte Bei der SPMD-Programmierung sind die meisten Daten privat: Verwende DEFAULT(PRIVATE) Common-Blöcke sind häufig THREADPRIVATE Privatisiere möglichst viele Variablen zur Vermeidung von False Sharing Vermeide unnötige Barrieren Häufig müssen nur einzelne Threads miteinander synchronisiert werden, Barrieren synchronisieren aber alle Threads 103 OpenMP-Kurs Dieter an Mey 21.01.2002 Punkt-zu zu-punkt-synchronisation Der Produzent berechnet seinen Teil des gemeinsamen Feldes und setzt anschliessend eine Flagge (entspricht dem MPI_Send beim MPI-Ansatz) Der Verbraucher benötigt einen Teil des Feldes des Produzenten und wartet auf seine Flagge (entspricht dem MPI_Receive beim MPI-Ansatz) 104 OpenMP-Kurs Dieter an Mey 21.01.2002

Gezielte Synchronisation einzelner Tasks - Flush program flush implicit integer (a-z) logical allocatable, dimension(:) :: done allocate (done(omp_get_max_threads()))!$omp parallel default(private) shared(done) me = omp_get_thread_num() if ( me > 0 ) neighbor = me - 1 done(me)=.false. $!OMP barrier call do_my_work() done(me)=.true. $!OMP flush(done) do while (.not. done(neighbor)) call do_some_more_useful_work() $!OMP flush(done) call do_synchronized_work() $!OMP end parallel end program flush 105 OpenMP-Kurs Dieter an Mey 21.01.2002 OpenMP - Gliederung Einleitung: Geschichte, Compiler, OpenMP-Struktur Einführung in OpenMP Format der Direktiven Laufzeitfunktionen Parallele Regionen Arbeitsteilung (worksharing( worksharing) Verwaisen (orphaning( orphaning) Daten-Geltungsbereiche (data( scope) Synchronisation Überblick über alle Kompontenten von OpenMP Ein Beispiel (Berechnung von Pi) Strategien, Performance Klassifizierung von Variablen Parallelisierung auf Schleifenebene Grobgranulare Arbeitsteilung SPMD OpenMP versus MPI Anwendungsbeispiele Jacobi, Panta 106 OpenMP-Kurs Dieter an Mey 21.01.2002

CFD-Programm PANTA auf HP V-ClassV Programmkern!$omp parallel do lastprivate(ine,iee,ise,isw,iww,inw,iue,iuw,ide,idw,inu,ind,isu,isd)!$omp & renbpe,resbme,resbpe,reubme,reubpe,rkdbmk,rkdbpk,rknbmk, private( & &!$omp & aece,aee,aeebe,aewbe,akck,akebk,akk,akwbk,!$omp & rknbpk,rksbmk,rksbpk,rkubmk,rkubpk,rtdbme,rtdbpe,rtnbme, &!$omp & amueec,amuegc,amuekc,amuelc,amuetc,asonsq,atce,ate,!$omp & rtnbpe,rtsbme,rtsbpe,rtubme,rtubpe,rudbme,rudbmx,rudbmy, & &!$omp & atebe,atwbe,auce,aucx,aucy,aucz,aue,auebe,!$omp & & rudbmz,rudbpe,rudbpx,rudbpy,rudbpz,runbme,runbmx,runbmy, &!$omp & auebx,aueby,auebz,auwbe,auwbx,auwby,auwbz,aux,!$omp & runbmz,runbpe,runbpx,runbpy,runbpz,rusbme,rusbmx,rusbmy, & &!$omp & auy,auz,avce,avcx,avcy,avcz,ave,avebe,!$omp & & rusbmz,rusbpe,rusbpx,rusbpy,rusbpz,ruubme,ruubmx,ruubmy, &!$omp & avebx,aveby,avebz,avwbe,avwbx,avwby,avwbz,avx,!$omp & ruubmz,ruubpe,ruubpx,ruubpy,ruubpz,rvdbme,rvdbmx,rvdbmy, & &!$omp & avy,avz,awce,awcx,awcy,awcz,awe,awebe,!$omp & & rvdbmz,rvdbpe,rvdbpx,rvdbpy,rvdbpz,rvnbme,rvnbmx,rvnbmy, &!$omp & awebx,aweby,awebz,awwbe,awwbx,awwby,awwbz,awx,!$omp & rvnbmz,rvnbpe,rvnbpx,rvnbpy,rvnbpz,rvsbme,rvsbmx,rvsbmy, & &!$omp & awy,awz,bedbe,benbe,besbe,beube,bkdbk,bknbk,!$omp & rvsbmz,rvsbpe,rvsbpx,rvsbpy,rvsbpz,rvubme,rvubmx,rvubmy, & &!$omp & bksbk,bkubk,btdbe,btnbe,btsbe,btube,budbe,budbx,!$omp & rvubmz,rvubpe,rvubpx,rvubpy,rvubpz,rwdbme,rwdbmx,rwdbmy, & &!$omp & budby,budbz,bunbe,bunbx,bunby,bunbz,busbe,busbx,!$omp & rwdbmz,rwdbpe,rwdbpx,rwdbpy,rwdbpz,rwnbme,rwnbmx,rwnbmy, & &!$omp & busby,busbz,buube,buubx,buuby,buubz,bvdbe,bvdbx,!$omp & rwnbmz,rwnbpe,rwnbpx,rwnbpy,rwnbpz,rwsbme,rwsbmx,rwsbmy, & &!$omp & bvdby,bvdbz,bvnbe,bvnbx,bvnby,bvnbz,bvsbe,bvsbx,!$omp & rwsbmz,rwsbpe,rwsbpx,rwsbpy,rwsbpz,rwubme,rwubmx,rwubmy, & &!$omp & bvsby,bvsbz,bvube,bvubx,bvuby,bvubz,bwdbe,bwdbx,!$omp & rwubmz,rwubpe,rwubpx,rwubpy,rwubpz,tc,tdb,tdbm, & &!$omp & bwdby,bwdbz,bwnbe,bwnbx,bwnby,bwnbz,bwsbe,bwsbx,!$omp & tdbp,teb,tkc,tkdb,tkdbm,tkdbp,tkeb,tknb, & &!$omp & bwsby,bwsbz,bwube,bwubx,bwuby,bwubz,caqden,dedq1,!$omp & tknbm,tknbp,tksb,tksbm,tksbp,tkub,tkubm,tkubp, & &!$omp & dedq7,diffe,diffre,diffrk,diffru,diffrv,diffrw,dkdq1,!$omp & tkwb,tnb,tnbm,tnbp,tsb,tsbm,tsbp,tub, & &!$omp & dkdq6,dmtdq6,dmtdq7,dtdq1,dtdq2,dtdq3,dtdq4,dtdq5,!$omp & tubm,tubp,twb,uc,udb,udbm,udbp,ueb, & &!$omp & dtdq6,dudq1,dudq2,dvdq1,dvdq3,dwdq1,dwdq4,ec,!$omp & unb,unbm,unbp,usb,usbm,usbp,uub,uubm, & &!$omp & edb,edbm,edbp,eeb,enb,enbm,enbp,esb,!$omp & & uubp,uwb,vc,vdb,vdbm,vdbp,veb,velosq, &!$omp & esbm,esbp,eub,eubm,eubp,ewb,gedb,genb,!$omp & & vnb,vnbm,vnbp,vsb,vsbm,vsbp,vub,vubm, &!$omp & gesb,geub,gkdb,gknb,gksb,gkub,gtdb,gtnb,!$omp & & vubp,vwb,wc,wdb,wdbm,wdbp,web,wnb, &!$omp & gtsb,gtub,gudb,gunb,gusb,guub,gvdb,gvnb,!$omp & & wnbm,wnbp,wsb,wsbm,wsbp,wub,wubm,wubp, &!$omp & gvsb,gvub,gwdb,gwnb,gwsb,gwub,lijk,omegay,!$omp & wwb,xiaxc,xiaxeb,xiaxwb,xiayc,xiayeb,xiaywb,xiazc, &!$omp & omegaz,prode,qdens,qjc,qmqc,redbme,redbpe,renbme,!$omp & xiazeb,xiazwb,xibxc,xibxnb,xibxsb,xibynb,xibysb,xibznb, & &!$omp & omegaz,prode,qdens,qjc,qmqc,redbme,redbpe,renbme,!$omp & xibzsb,xicxc,xicxdb,xicxub,xicydb,xicyub,xiczdb,xiczub) & do i = is,ie!. 1500 lines omitted 107 OpenMP-Kurs Dieter an Mey 21.01.2002 35 percent of the CPU time spent in one loop nest Attention: when parallelizing this loop do n = 1,7 recursion: RHS(l,m) this loop is usually auto-parallelized do m = 1,7 only 7 iterations many iterations! do l = LSS(itsub),LEE(itsub) (vector loop) i = IG(l) j = JG(l) k = KG(l) lijk = L2IJK(l) RHS(l,m) = RHS(l,m)- & FJAC(lijk,lm00,m,n)*DQCO(i-1,j,k,n,NB)*FM00(l) - & FJAC(lijk,lp00,m,n)*DQCO(i+1,j,k,n,NB)*FP00(l) - & FJAC(lijk,l0m0,m,n)*DQCO(i,j-1,k,n,NB)*F0M0(l) - & FJAC(lijk,l0p0,m,n)*DQCO(i,j+1,k,n,NB)*F0P0(l) - & FJAC(lijk,l00m,m,n)*DQCO(i,j,k-1,n,NB)*F00M(l) - & FJAC(lijk,l00p,m,n)*DQCO(i,j,k+1,n,NB)*F00P(l) 108 OpenMP-Kurs Dieter an Mey 21.01.2002

Visual KAP for OpenMP on WinNT (KAI) Generating OpenMP Directives!$OMP PARALLEL SHARED SHARED (ITSUB,LSS,II15,RHS,II14,L2IJK,FJAC,NB,KG,JG,IG,DQCO&!$OMP&,FM00,II13,FP00,II12,F0M0,II11,F0P0,II10,F00M,II9,F00P,LM00,LP00,L0M0&!$OMP&,L0P0,L00M,L00P,LEE,LFJ) PRIVATE PRIVATE (II2,II1,N1,M,L,II16,II4,RR1,II3,& (II2,II1,N1,M,L,II16,II4,RR1,II3,&!$OMP&I,J,K,LIJK,II17,II18,II20,II21,II22,II23,II24,II25,N,NM,II19,II32,&!$OMP&I,J,K,LIJK,II17,II18,II20,II21,II22,II23,II24,II25,N,NM,II19,II32,&!$OMP&II26,II27,II28,II29,II30,II31,II6,II5)!$OMP&II26,II27,II28,II29,II30,II31,II6,II5) DO!$OMP DO II1=LSS(ITSUB),II15,64 II2 = MIN (II15,II1+63) DO II1=LSS(ITSUB),II15,64 DO N1=1,7 DO II2 M=1,7 = MIN (II15,II1+63) long loop splitted DO N1=1,7 L=II1,II2,1 DO RHS(L,M) M=1,7 = RHS(L,M) - FJAC(L2IJK(L),II14,M,N1) * DQCO(IG(L)-1& &,JG(L),KG(L),N1,NB) * FM00(L) - FJAC(L2IJK(L),II13,M,N1) * DQCO(IG& &(L)+1,JG(L),KG(L),N1,NB) DO L=II1,II2,1 * FP00(L) - FJAC(L2IJK(L),II12,M,N1) * DQCO& &(IG(L),JG(L)-1,KG(L),N1,NB) RHS(L,M) = RHS(L,M) *-F0M0(L) FJAC(L2IJK(L),II14,M,N1) - FJAC(L2IJK(L),II11,M,N1) * DQCO(IG(L)-1& & &* &,JG(L),KG(L),N1,NB) DQCO(IG(L),JG(L)+1,KG(L),N1,NB) * FM00(L) * -F0P0(L) FJAC(L2IJK(L),II13,M,N1) - FJAC(L2IJK(L),II10,& * DQCO(IG& &M,N1) * DQCO(IG(L),JG(L),KG(L)-1,N1,NB) * F00M(L) - FJAC(L2IJK(L)& &(L)+1,JG(L),KG(L),N1,NB) * FP00(L) - FJAC(L2IJK(L),II12,M,N1) * DQCO& &,II9,M,N1) * DQCO(IG(L),JG(L),KG(L)+1,N1,NB) * F00P(L) &(IG(L),JG(L)-1,KG(L),N1,NB) END DO * F0M0(L) - FJAC(L2IJK(L),II11,M,N1) & &* END DQCO(IG(L),JG(L)+1,KG(L),N1,NB) DO * F0P0(L) - FJAC(L2IJK(L),II10,& &M,N1) END DO * DQCO(IG(L),JG(L),KG(L)-1,N1,NB) * F00M(L) - FJAC(L2IJK(L)& END DO!$OMP END &,II9,M,N1) DO NOWAIT * DQCO(IG(L),JG(L),KG(L)+1,N1,NB) * F00P(L)!$OMP BARRIER END DO END DO END DO END DO!$OMP 109 END DO NOWAIT OpenMP-Kurs Dieter an Mey 21.01.2002!$OMP BARRIER Visual KAP for OpenMP on WinNT (KAI) Detailled Listing 1 2 5 6 LR NV SO INF +------- 42 do n = 1,7 1 2 3 LR NV SO NVS NC:+------ 43 do m = 1,7 1 2 4 7 8 LR NV SO NVS :!+----- 44 do l = LSS(itsub),LEE(itsub) Abbreviations Used :!: :!: 45 46 i = IG(l) j = JG(l) STD standardized :!: 47 k = KG(l) NO not optimized :!: 48 lijk = L2IJK(l) SO :!: 49 RHS(l,m) = & LR loop reordering :!: 50 RHS(l,m) - FJAC(lijk,lm00,m,n)*DQCO(i-1, NV not vectorized :!: 51 FJAC(lijk,lp00,m,n)*DQCO(i+1,j,k,n,NB)*F SO scalar optimization :!: 52 FJAC(lijk,l0m0,m,n)*DQCO(i,j-1,k,n,NB)*F NVS non-vector-stmt :!: 53 FJAC(lijk,l0p0,m,n)*DQCO(i,j+1,k,n,NB)*F :!: 54 FJAC(lijk,l00m,m,n)*DQCO(i,j,k-1,n,NB)*F INF informational :!: 55 FJAC(lijk,l00p,m,n)*DQCO(i,j,k+1,n,NB)*F C 1 concurrentized SO :!: 56 NC not concurrentized :! 57 : 58 Footnote List 1: scalar optimization Statement deleted because of scalar optimization. 2: not vectorized Not an inner loop. 3: not concurrentized Too little concurrentizable code. 4: informational Unrolling of this loop was not done because heuristic says size is o 5: scalar optimization Loop is empty or is zero-trip. 6: informational Unrolling of this loop was not done because no executable statements 7: scalar optimization Strip loop for strip mining with block size 64. 8: scalar optimization Block loop for strip mining with block size 64. 110 OpenMP-Kurs Dieter an Mey 21.01.2002

Manual Parallelization with OpenMP Compilation with the guidef90 Preprocessor (KAI)!$omp parallel private(n,m,l,i,j,k,lijk) do n = 1,7 do m = 1,7!$omp do do l = LSS(itsub),LEE(itsub) partitioning the long loop i = IG(l) j = JG(l) k = KG(l) lijk = L2IJK(l) RHS(l,m) = RHS(l,m)- & FJAC(lijk,lm00,m,n)*DQCO(i-1,j,k,n,NB)*FM00(l) - & FJAC(lijk,lp00,m,n)*DQCO(i+1,j,k,n,NB)*FP00(l) - & FJAC(lijk,l0m0,m,n)*DQCO(i,j-1,k,n,NB)*F0M0(l) - & FJAC(lijk,l0p0,m,n)*DQCO(i,j+1,k,n,NB)*F0P0(l) - & FJAC(lijk,l00m,m,n)*DQCO(i,j,k-1,n,NB)*F00M(l) - & FJAC(lijk,l00p,m,n)*DQCO(i,j,k+1,n,NB)*F00P(l)!$omp do nowait!omp end parallel no barrier, no overhead 111 OpenMP-Kurs Dieter an Mey 21.01.2002 Paralleler Speedup des Programmkernes (HP V Class) 16 12 OMP parallel inner loop without barrier OMP splitting loop over l (VisKAP) AUTO parallel over m speedup 8 4 2 CPUs out of 16 busy 0 0 4 8 12 16 processors 112 OpenMP-Kurs Dieter an Mey 21.01.2002

Finites Differenzenverfahren Zur Lösung der zweidimensionalen Helmholtzdifferentialgleichung u + κu = f mit homogenen Dirichlet-Randbedingungen dient ein Finites Differenzenverfahren. Bei der Diskretisierung des Laplace-Operators mit dem zentralen 5-Punkte-Differenzenstern entsteht ein lineares Gleichunssystem mit Bandstruktur, daß mit dem Jacobi- oder Gesamtschrittverfahren iterativ gelöst werden kann. Das Jacobi-Verfahren ist einfach parallelisierbar und auch vektorisierbar. 113 OpenMP-Kurs Dieter an Mey 21.01.2002 Jacobi-Verfahren - Gebietszerlegung P1 P2 Shared Memory Parallelisierung 114 OpenMP-Kurs Dieter an Mey 21.01.2002

Jacobi-Verfahren - Gebietszerlegung P1 P2 Shared Memory Parallelisierung P1 Überlappbereiche P2 Distributed Memory Parallelisierung 115 OpenMP-Kurs Dieter an Mey 21.01.2002 Jacobi-Verfahren - 1. OpenMP Version k = 1 do while (k.le.maxit.and. error.gt. tol) error = 0.0!$omp parallel do do j=1,m do i=1,n; uold(i,j) = u(i,j); enddo enddo!$omp end parallel do!$omp parallel do private(resid) reduction(+:error) do j = 2,m-1 do i = 2,n-1 resid = (ax*(uold(i-1,j) + uold(i+1,j) u(i,j) = uold(i,j) - omega * resid error = error + resid*resid enddo!$omp end parallel do k = k + 1 error = sqrt(error)/dble(n*m) enddo 116 OpenMP-Kurs Dieter an Mey 21.01.2002

Jacobi-Verfahren - 2. OpenMP Version k = 1 do while (k.le.maxit.and. error.gt. tol) error = 0.0!$omp parallel!$omp do do j=1,m do i=1,n; uold(i,j) = u(i,j); enddo enddo!$omp!$omp do private(resid) reduction(+:error) do j = 2,m-1 do i = 2,n-1 resid = (ax*(uold(i-1,j) + uold(i+1,j) u(i,j) = uold(i,j) - omega * resid error = error + resid*resid enddo!$omp nowait!$omp end parallel k = k + 1 error = sqrt(error)/dble(n*m) enddo 117 OpenMP-Kurs Dieter an Mey 21.01.2002 Jacobi-Verfahren - 3. OpenMP Version!$omp parallel private(resid,k_local) k_local = 1 do while (k_local.le.maxit.and. error.gt.tol)!$omp do do j=1,m; do i=1,n; uold(i,j) = u(i,j); enddo; enddo!$omp single error = 0.0!$omp end single!$omp do reduction(+:error) do j..;do i..;resid=..;u(i,j)=..;error=..;enddo;enddo!$omp single error = sqrt(error)/dble(n*m)!$omp end single k_local = k_local + 1 enddo!$omp master k = k_local!$omp end master!$omp end parallel 118 OpenMP-Kurs Dieter an Mey 21.01.2002

Jacobi-Verfahren Parallelisierung mit Visual KAP for OpenMP DO WHILE ( K.LE. MAXIT.AND. ERROR.GT. TOL ) ERROR = 0D0 C$OMP PARALLEL IF (M.GT. 83) SHARED (M,N,UOLD,U) PRIVATE (J,I) C$OMP DO DO J=1,M; DO I=1,N; UOLD(I,J) = U(I,J); END DO; END DO C$OMP END DO NOWAIT C$OMP END PARALLEL II1 = II3; IF (II1.GT. 0) THEN; II2 = M - 2; IF (II2.GT. 0) THEN; DD2 = 1 / B C$OMP PARALLEL SHARED (M,DD2,N,AX,UOLD,F,AY,B,U,OMEGA,ERROR) PRIVATE ( C$OMP& DD1,J,I,RESID,ERROR1) ERROR1 = 0D0 C$OMP DO DO J=2,M-1; DD1 = DD2; DO I=2,N-1 RESID = U(I,J) = UOLD(I,J) - OMEGA * RESID ERROR1 = ERROR1 + RESID * RESID END DO; END DO C$OMP END DO NOWAIT C$OMP CRITICAL (II4) ERROR = ERROR + ERROR1 C$OMP END CRITICAL (II4) C$OMP END PARALLEL END IF; END IF K = K + 1; ERROR = SQRT (ERROR) * DD3 END DO 119 OpenMP-Kurs Dieter an Mey 21.01.2002 Jacobi-Verfahren Automatische Parallelisierung (Linux( Linux-PGI) Übersetzen mit automatischer Parallelisierung und Erzeugen einer Ausgabeliste (in jacobi.w2f.f): pgf90 -Mlist -Mconcur -Minfo -Mneginfo=concur -fast jacobi.f90 jacobi: 43, Loop not parallelized: multiple exits 49, Parallel code for non-innermost loop generated; block distribution 50, Loop unrolled 10 times 57, Parallel code for non-innermost loop generated; block distribution 120 OpenMP-Kurs Dieter an Mey 21.01.2002

Parallele Programmierung für Shared-Memory Memory-Rechner mit OpenMP Automatische Parallelisierung Explizite Parallelisierung mit OpenMP Debugging mit Assure und TotalView Performance Tools GuideView, PerView, CXperf,, Puma Hybride Parallelisierung 121 OpenMP-Kurs Dieter an Mey 21.01.2002 Debugging OpenMP Programs - The Error!$omp parallel private(resid,k_local) k_local = 1 do while (k_local.le.maxit.and. error.gt.tol)!$omp do do j=1,m; do i=1,n; uold(i,j) = u(i,j); enddo; enddo!$omp single error = 0.0!$omp end single!$omp do reduction(+:error) do j..;do i..;resid=..;u(i,j)=..;error=..;enddo;enddo!$omp single error = sqrt(error)/dble(n*m)!$omp end single k_local = k_local + 1 enddo!$omp master k = k_local!$omp end master!$omp end parallel 122 OpenMP-Kurs Dieter an Mey 21.01.2002

Debugging OpenMP Programs - The Error!$omp parallel private(resid,k_local) k_local = 1 do while (k_local.le.maxit.and. error.gt.tol)!$omp do do j=1,m; do i=1,n; uold(i,j) = u(i,j); enddo; enddo error = 0.0!$omp do reduction(+:error) do j..;do i..;resid=..;u(i,j)=..;error=..;enddo;enddo!$omp single error = sqrt(error)/dble(n*m)!$omp end single k_local = k_local + 1 enddo!$omp master k = k_local!$omp end master!$omp end parallel 123 OpenMP-Kurs Dieter an Mey 21.01.2002 Debugging OpenMP Programs - ASSURE 124 OpenMP-Kurs Dieter an Mey 21.01.2002

Debugging OpenMP Programs - ASSURE 125 OpenMP-Kurs Dieter an Mey 21.01.2002 Debugging von OpenMP-Programmen Programmen mit TotalView (1) - generell Zum Verständnis (vgl. TotalView User s Guide): Jede Parallele Region wird in (mindestens) eine Routine ausgelagert ert (outlining) Die Namen der ausgelagerten Routinen basieren auf dem Namen der ursprünlichen Routine Normalerweise werden die globalen (shared( shared) ) Variablen in der Originalroutine verwaltet und die privaten in der ausgelagerten. Wenn der Master-Thread die Parallele Region betritt, werden die Slave- Threads generiert Beim Debugging kann man nicht schrittweise (s) die Parallele Region betreten, sondern nur in dem man auf einen zuvor gesetzten Breakpoint läuft (g) Beim Setzen des Breakpoints sollten man in der Regel in dem erscheinenden Dialog-Fenster All und OK anklicken. 126 OpenMP-Kurs Dieter an Mey 21.01.2002

Debugging von OpenMP-Programmen Programmen mit TotalView (2) - Sun TotalView unterstützt derzeit nur Forte Developer 6 U1 Im Parallel Mode schalten die Sun-Compiler automatisch die Optimierungsstufe 3 ein, so dass ein Debugging nicht mehr möglich ist: Ausweg: Guide #!/bin/ksh. Forte61.init. totalview.init guidef90 c WG,-cmpo=i g prog.f90 guidef90 o a.out WG,-cmpo=i g prog.o export OMP_NUM_THREADS=2 totalview a.out 127 OpenMP-Kurs Dieter an Mey 21.01.2002 Parallele Programmierung für Shared-Memory Memory-Rechner mit OpenMP Automatische Parallelisierung Explizite Parallelisierung mit OpenMP Debugging mit Assure und TotalView Performance Tools GuideView, WorkShop Hybride Parallelisierung 128 OpenMP-Kurs Dieter an Mey 21.01.2002

Jacobi-Algorithm - Guide Runtime Statistics Barrier 1 Barrier 2 Barrier 3 Barrier 4!$omp parallel private(resid,k_local) k_local = 1 do while (k_local.le.maxit.and. error.gt.tol)!$omp do do j=1,m; do i=1,n; uold(i,j) = u(i,j); enddo; enddo!$omp single error = 0.0!$omp end single!$omp do reduction(+:error) do j..;do i..;resid=..;u(i,j)=..;error=..;enddo;enddo!$omp single error = sqrt(error)/dble(n*m)!$omp end single k_local = k_local + 1 enddo!$omp master k = k_local!$omp end master!$omp end parallel 129 OpenMP-Kurs Dieter an Mey 21.01.2002 Jacobi-Algorithm - Guide Runtime Statistics Barrier 1 Barrier 2 Barrier 3 Barrier 4!$omp parallel private(re k_local = 1 do while (k_local.l!$omp do do j=1,m; do i=1!$omp single error = 0.0!$omp end single!$omp do reduction(+:erro do j..;do i..;resi!$omp single error = sqrt(err!$omp end single k_local = k_loca enddo!$omp master k = k_local!$omp end master!$omp end parallel 130 OpenMP-Kurs Dieter an Mey 21.01.2002

Parallele Programmierung für Shared-Memory Memory-Rechner mit OpenMP Automatische Parallelisierung Explizite Parallelisierung mit OpenMP Debugging mit Assure und TotalView Performance Tools GuideView, PerView, CXperf,, Puma Hybride Parallelisierung 131 OpenMP-Kurs Dieter an Mey 21.01.2002 Übersetzen, Binden und Starten von hybriden Programmen auf Sun mpf90 -c -openmp driver_mpi.f90 mpf90 -c openmp jacobi_mpi_omp.f90 mpf90 -o openmp jacobi.exe \ driver_mpi.o jacobi_mpi_omp.o lmpi_mt export OMP_NUM_THREADS=2 echo "200,200\n0.8\n1.0\n1e-7\n1000" mprun -np 2 jacobi.exe # Oder mit Guide : guidef90 WGcompiler=mpf90 -c driver_mpi.f90 guidef90 WGcompiler=mpf90 -c jacobi_mpi_omp.f90 guidef90 WGcompiler=mpf90 -o jacobi.exe \ driver_mpi.o jacobi_mpi_omp.o lmpi_mt export OMP_NUM_THREADS=2 echo "200,200\n0.8\n1.0\n1e-7\n1000" mprun -np 2 jacobi.exe 132 OpenMP-Kurs Dieter an Mey 21.01.2002

Übersetzen, Binden und Starten von hybriden Programmen auf HP guidef90 -c -I/opt/mpi/include +O3 +Odataprefetch +DS2.0 \ +DA2.0 driver_mpi.f90 guidef90 -c -I/opt/mpi/include +O3 +Odataprefetch +DS2.0 \ +DA2.0 jacobi_mpi_omp.f90 guidef90 -o jacobi.exe driver_mpi.o jacobi_mpi_omp.o \ +DA2.0 -L/opt/mpi/lib/pa1.1 lmtmpi export OMP_NUM_THREADS=2 echo "200,200\n0.8\n1.0\n1e-7\n1000" \ mpirun -np 2 jacobi.exe 133 OpenMP-Kurs Dieter an Mey 21.01.2002 Pi: Hybrid-Programm in Fortran90 (Auszug) call MPI_INIT( ierr ) call MPI_COMM_RANK( MPI_COMM_WORLD, myid, ierr ) call MPI_COMM_SIZE( MPI_COMM_WORLD, numprocs, ierr ) do if ( myid.eq. 0 ) read (5,10001) n call MPI_BCAST(n,1,MPI_INTEGER,0,MPI_COMM_WORLD,ierr) if (n <= 0) exit h = 1.0d0 / n sum = 0.0d0!$omp parallel do reduction(+:sum) private(i,x) do i = myid+1, n, numprocs x = h * (DBLE(i)-0.5d0) sum = sum + f(x) mypi = h * sum call MPI_REDUCE(mypi,pi,1,MPI_DOUBLE_PRECISION,MPI_SUM,0, ) if (myid.eq. 0) write (6,10002) pi, ABS(pi-pi25dt) 134 call MPI_FINALIZE(ierr) OpenMP-Kurs Dieter an Mey 21.01.2002

Jacobi-Verfahren: MPI-Version (1) #include "mpif.h" integer reqcnt,reqary(4),reqstat(mpi_status_size,4),status(mpi_status_size) double precision u(n,mlo:mhi),f(n,mlo:mhi) do while (k.le.maxit.and. error.gt. tol) * Copy new solution into old reqcnt = 0 if ( me.ne. 0 ) then * receive stripe mlo from left neighbour blocking reqcnt = reqcnt + 1 call MPI_IRECV( uold(1,mlo), n,, me-1,,reqary(reqcnt),ierr) end if if ( me.ne. np-1 ) then * receive stripe mhi from right neighbour blocking reqcnt = reqcnt + 1 call MPI_IRECV( uold(1,mhi), n,, me+1,.,reqary(reqcnt),ierr) end if if ( me.ne. np-1 ) then * send stripe mhi-1 to right neighbour async reqcnt = reqcnt + 1 call MPI_ISEND ( u(1,mhi-1), n,, me+1,,reqary(reqcnt),ierr) end if if ( me.ne. 0 ) then * send stripe mlo+1 to left neighbour async reqcnt = reqcnt + 1 call MPI_ISEND ( u(1,mlo+1), n,., reqary(reqcnt),ierr) end if do j=mlo+1,mhi-1; do i=1,n; uold(i,j) = u(i,j); enddo; enddo 135 OpenMP-Kurs Dieter an Mey 21.01.2002 call MPI_WAITALL ( reqcnt, reqary, reqstat, ierr) Jacobi-Verfahren: MPI-Version (2) * Compute stencil, residual, & update do j = mlo+1,mhi-1 do i = 2,n-1 * Evaluate residual resid = (ax*(uold(i-1,j) + uold(i+1,j)) & + ay*(uold(i,j-1) + uold(i,j+1)) & + b * uold(i,j) - f(i,j))/b * Update solution u(i,j) = uold(i,j) - omega * resid * Accumulate residual error error = error + resid*resid enddo error_local = error call MPI_ALLREDUCE ( error_local, error,1,,mpi_sum,) * Error check k = k + 1 error = sqrt(error)/dble(n*m) * enddo! End iteration loop 136 OpenMP-Kurs Dieter an Mey 21.01.2002

Jacobi-Verfahren: hybride OpenMP+MPI-Version do while (k.le.maxit.and. error.gt. tol) error = 0.0 * Copy new solution into old call MPI_IRECV call MPI_IRECV call MPI_ISEND call MPI_ISEND!$omp do parallel do j=mlo+1,mhi-1; do i=1,n; uold(i,j) = u(i,j); enddo; enddo call MPI_WAITALL * Compute stencil, residual, & update!$omp parallel!$omp do private(resid) reduction(+:error) do j = mlo+1,mhi-1; do i = 2,n-1 resid = u(i,j) = uold(i,j) - omega * resid error = error + resid*resid ; enddo!$omp nowait!$omp end parallel error_local = error call MPI_ALLREDUCE ( error_local, error,1,,mpi_sum,) * k = k + 1 error = sqrt(error)/dble(n*m) enddo! End iteration loop 137 OpenMP-Kurs Dieter an Mey 21.01.2002 Vielteilchenproblem AIXCCAD auf hpcline (16 Rechenknoten mit je 2 Prozessoren) 138 OpenMP-Kurs Dieter an Mey 21.01.2002

TFS auf HP V-Class V (16 Shared-Memory Memory-Prozessoren) 139 OpenMP-Kurs Dieter an Mey 21.01.2002 OpenMP - Informationen Das OpenMP-Standardisierungsgremium Fortran und C Application Program Interfaces (APIs( APIs) www.openmp openmp.orgorg The Community of OpenMP Users, Researchers,, Tool Developers and Providers www.compunity compunity.orgorg OpenMP-Kurse im Netz Tutorial by the OPENMP ARB at SC1998 http://www.openmp.org/presentations/index.cgi?sc98_tutorial University of Minnesota http://www.msi.umn.edu/tutorials/shared_tutorials/openmp/ Boston University http://scv.bu.edu/scv/tutorials/openmp/ OpenMP hier: www.rz rz.rwth-aachen.de/.de/sw/prog/openmp/ Vortragsfolien: www.rz.rwth-aachen.de/hpc/talks/sunhpc_2002/openmp.html Literatur: Rohit Chandra,, et.al. Parallel Programming in OpenMP Morgan Kaufmann, ISBN 1-558601 55860-671-8 140 OpenMP-Kurs Dieter an Mey 21.01.2002