OpenMP - OpenMP

OpenMP
OpenMP-Logo
Originalautor(en) OpenMP Architecture Review Board
Entwickler OpenMP Architecture Review Board
Stabile Version
5.1 / 13. November 2020 ; vor 9 Monaten ( 2020-11-13 )
Betriebssystem Plattformübergreifend
Plattform Plattformübergreifend
Typ Erweiterung auf C , C++ und Fortran ; API
Lizenz Verschieden
Webseite openmp .org

OpenMP ( Open Multi-Processing ) ist eine Anwendungsprogrammierschnittstelle (API), die Multi-Plattform- Shared-Memory- Multiprocessing- Programmierung in C , C++ und Fortran auf vielen Plattformen, Befehlssatzarchitekturen und Betriebssystemen , einschließlich Solaris , AIX , unterstützt. HP-UX , Linux , macOS und Windows . Es besteht aus einer Reihe von Compiler-Direktiven , Bibliotheksroutinen und Umgebungsvariablen , die das Laufzeitverhalten beeinflussen.

OpenMP wird von dem verwalteten Non - Profit - Technologie Konsortium OpenMP Architecture Review Board (oder OpenMP ARB ), die gemeinsam von einem breiten Schneise der führenden Computer - Hardware und Software - Anbieter definiert, einschließlich Arm , AMD , IBM , Intel , Cray , HP , Fujitsu , Nvidia , NEC , Red Hat , Texas Instruments und Oracle Corporation .

OpenMP verwendet ein tragbares , skalierbares Modell, das Programmierern eine einfache und flexible Schnittstelle zur Entwicklung paralleler Anwendungen für Plattformen bietet, die vom Standard- Desktop-Computer bis zum Supercomputer reichen .

Eine mit dem Hybridmodell der parallelen Programmierung erstellte Anwendung kann auf einem Computercluster unter Verwendung von OpenMP und Message Passing Interface (MPI) ausgeführt werden, sodass OpenMP für Parallelität innerhalb eines (Mehrkern-)Knotens verwendet wird, während MPI für Parallelität zwischen Knoten verwendet wird . Es gab auch Bemühungen, OpenMP auf Software-verteilten Shared-Memory- Systemen auszuführen , OpenMP in MPI zu übersetzen und OpenMP für Non-Shared-Memory-Systeme zu erweitern.

Entwurf

Eine Illustration von Multithreading, bei der der primäre Thread eine Reihe von Threads abzweigt, die Codeblöcke parallel ausführen.

OpenMP ist eine Implementierung von Multithreading wird ein Verfahren zum Parallelisieren wobei ein Primärfaden (eine Reihe von Befehlen nacheinander ausgeführt) gabelt eine bestimmte Anzahl von Unter -threads und Das System teilt unter ihnen eine Aufgabe. Die Threads werden dann gleichzeitig ausgeführt , wobei die Laufzeitumgebung Threads verschiedenen Prozessoren zuweist.

Der Codeabschnitt, der parallel ausgeführt werden soll, wird entsprechend mit einer Compiler-Direktive gekennzeichnet, die bewirkt, dass sich die Threads bilden, bevor der Abschnitt ausgeführt wird. Jedem Thread ist eine ID zugeordnet , die mit einer Funktion (genannt omp_get_thread_num()) abgerufen werden kann . Die Thread-ID ist eine ganze Zahl und der primäre Thread hat die ID 0 . Nach der Ausführung des parallelisierten Code, die Fäden verbinden zurück in den primären Thread, der weiter zum Ende des Programms fortgesetzt wird .

Standardmäßig führt jeder Thread den parallelisierten Codeabschnitt unabhängig aus. Arbeitsteilungskonstrukte können verwendet werden, um eine Aufgabe auf die Threads aufzuteilen, sodass jeder Thread seinen zugewiesenen Teil des Codes ausführt. Auf diese Weise kann mit OpenMP sowohl Aufgabenparallelität als auch Datenparallelität erreicht werden.

Die Laufzeitumgebung ordnet den Prozessoren Threads je nach Nutzung, Maschinenlast und anderen Faktoren zu. Die Laufzeitumgebung kann die Anzahl der Threads basierend auf Umgebungsvariablen zuweisen oder der Code kann dies mithilfe von Funktionen tun. Die OpenMP-Funktionen sind in einer Header-Datei mit der Bezeichnung omp.h in C / C++ enthalten .

Geschichte

Das OpenMP Architecture Review Board (ARB) veröffentlichte im Oktober 1997 seine ersten API-Spezifikationen, OpenMP für Fortran 1.0. Im Oktober des folgenden Jahres veröffentlichten sie den C/C++-Standard. Im Jahr 2000 wurde Version 2.0 der Fortran-Spezifikationen veröffentlicht, während Version 2.0 der C/C++-Spezifikationen 2002 veröffentlicht wurde. Version 2.5 ist eine kombinierte C/C++/Fortran-Spezifikation, die 2005 veröffentlicht wurde.

Bis Version 2.0 spezifizierte OpenMP in erster Linie Möglichkeiten zur Parallelisierung hochregulärer Schleifen, wie sie in der matrixorientierten numerischen Programmierung vorkommen , bei der die Anzahl der Iterationen der Schleife zum Eintrittszeitpunkt bekannt ist. Dies wurde als Einschränkung erkannt und den Implementierungen wurden verschiedene aufgabenparallele Erweiterungen hinzugefügt. Im Jahr 2005 wurde eine Anstrengung zur Standardisierung der Aufgabenparallelität gegründet, die 2007 einen Vorschlag veröffentlichte, der sich von den Funktionen der Aufgabenparallelität in Cilk , X10 und Chapel inspirieren ließ .

Version 3.0 wurde im Mai 2008 veröffentlicht. Zu den neuen Funktionen in 3.0 gehören das Konzept der Aufgaben und das Aufgabenkonstrukt , wodurch der Anwendungsbereich von OpenMP deutlich über die parallelen Schleifenkonstrukte hinaus erweitert wird, die den Großteil von OpenMP 2.0 ausmachten.

Version 4.0 der Spezifikation wurde im Juli 2013 veröffentlicht. Sie fügt die folgenden Funktionen hinzu oder verbessert sie: Unterstützung für Beschleuniger ; Atome ; Fehlerbehandlung; Fadenaffinität ; Tasking-Erweiterungen; benutzerdefinierte Reduzierung ; SIMD- Unterstützung; Fortran 2003- Unterstützung.

Die aktuelle Version ist 5.1, veröffentlicht im November 2020.

Beachten Sie, dass nicht alle Compiler (und Betriebssysteme) den vollen Funktionsumfang der neuesten Version/en unterstützen.

Kernelemente

Diagramm der OpenMP-Konstrukte

Die Kernelemente von OpenMP sind die Konstrukte zur Thread-Erstellung, Workload-Verteilung (Worksharing), Daten-Umgebungs-Management, Thread-Synchronisation, Laufzeitroutinen auf Benutzerebene und Umgebungsvariablen.

In C/C++ verwendet OpenMP #pragmas . Die OpenMP-spezifischen Pragmas sind unten aufgeführt.

Thread-Erstellung

Das Pragma omp parallel wird verwendet, um zusätzliche Fäden abzuzweigen , um die im Konstrukt eingeschlossene Arbeit parallel auszuführen. Der ursprüngliche Thread wird als Master-Thread mit der Thread-ID 0 bezeichnet.

Beispiel (C-Programm): Anzeige "Hallo Welt." mehrere Threads verwenden.

#include <stdio.h>
#include <omp.h>

int main(void)
{
    #pragma omp parallel
    printf("Hello, world.\n");
    return 0;
}

Verwenden Sie Flag -fopenmp, um mit GCC zu kompilieren:

$ gcc -fopenmp hello.c -o hello

Ausgabe auf einem Computer mit zwei Kernen und damit zwei Threads:

Hello, world.
Hello, world.

Jedoch kann die Ausgabe auch wegen der verstümmelt werden Race - Bedingung von den zwei Threads verursacht den Austausch von Standardausgabe .

Hello, wHello, woorld.
rld.

(Ob printfThread-sicher ist, hängt von der Implementierung ab. C++ std::couthingegen ist immer Thread-sicher.)

Arbeitsteilungskonstrukte

Wird verwendet, um anzugeben, wie einem oder allen Threads unabhängige Arbeit zugewiesen wird.

  • omp for oder omp do : wird verwendet, um Schleifeniterationen auf die Threads aufzuteilen , auch Schleifenkonstrukte genannt.
  • Abschnitte : Zuweisen aufeinanderfolgender, aber unabhängiger Codeblöcke zu verschiedenen Threads
  • single : Angabe eines Codeblocks, der nur von einem Thread ausgeführt wird, wird am Ende eine Barriere impliziert
  • master : ähnlich single, aber der Codeblock wird nur vom Master-Thread ausgeführt und am Ende wird keine Barriere impliziert.

Beispiel: Initialisieren Sie den Wert eines großen Arrays parallel und verwenden Sie jeden Thread, um einen Teil der Arbeit zu erledigen

int main(int argc, char **argv)
{
    int a[100000];

    #pragma omp parallel for
    for (int i = 0; i < 100000; i++) {
        a[i] = 2 * i;
    }

    return 0;
}

Dieses Beispiel ist peinlich parallel und hängt nur vom Wert von i ab . Das OpenMP- Flag parallel for weist das OpenMP-System an, diese Aufgabe auf seine Arbeitsthreads aufzuteilen. Die Threads erhalten jeweils eine eindeutige und private Version der Variablen. Bei zwei Worker-Threads könnte beispielsweise einem Thread eine Version von i übergeben werden , die von 0 bis 49999 läuft, während der zweite eine Version von 50000 bis 99999 erhält.

Variantenrichtlinien

Variantendirektiven sind eine der wichtigsten Funktionen, die in der OpenMP 5.0-Spezifikation eingeführt wurden, um Programmierern die Verbesserung der Leistungsportabilität zu erleichtern. Sie ermöglichen die Anpassung von OpenMP-Pragmas und Benutzercode zur Kompilierzeit. Die Spezifikation definiert Merkmale zur Beschreibung aktiver OpenMP-Konstrukte, Ausführungsgeräte und Funktionalität, die von einer Implementierung bereitgestellt werden, Kontextselektoren basierend auf den Merkmalen und benutzerdefinierten Bedingungen sowie metadirektive und deklarierende Direktiven für Benutzer, um denselben Codebereich mit Variantendirektiven zu programmieren.

  • Die Metadirektive ist eine ausführbare Direktive, die zur Kompilierzeit bedingt in eine andere Direktive aufgelöst wird, indem aus mehreren Direktivenvarianten basierend auf Merkmalen ausgewählt wird, die eine OpenMP-Bedingung oder einen OpenMP-Kontext definieren.
  • Die Direktive deklarieren von Varianten hat eine ähnliche Funktionalität wie die Metadirektive , wählt jedoch eine Funktionsvariante an der Aufrufstelle basierend auf Kontext oder benutzerdefinierten Bedingungen aus.

Der von den beiden Variantendirektiven bereitgestellte Mechanismus zur Auswahl von Varianten ist bequemer zu verwenden als die C/C++-Vorverarbeitung, da er die Variantenauswahl in OpenMP direkt unterstützt und es einem OpenMP-Compiler ermöglicht, die endgültige Direktive aus Varianten und Kontext zu analysieren und zu bestimmen.

// code adaptation using preprocessing directives

int v1[N], v2[N], v3[N];
#if defined(nvptx)     
 #pragma omp target teams distribute parallel loop map(to:v1,v2) map(from:v3)
  for (int i= 0; i< N; i++) 
     v3[i] = v1[i] * v2[i];  
#else 
 #pragma omp target parallel loop map(to:v1,v2) map(from:v3)
  for (int i= 0; i< N; i++) 
     v3[i] = v1[i] * v2[i];  
#endif


// code adaptation using metadirective in OpenMP 5.0

int v1[N], v2[N], v3[N];
#pragma omp target map(to:v1,v2) map(from:v3)
  #pragma omp metadirective \
     when(device={arch(nvptx)}: target teams distribute parallel loop)\
     default(target parallel loop)
  for (int i= 0; i< N; i++) 
     v3[i] = v1[i] * v2[i];

Klauseln

Da OpenMP ein Programmiermodell mit gemeinsam genutztem Speicher ist, sind die meisten Variablen im OpenMP-Code standardmäßig für alle Threads sichtbar. Aber manchmal private Variablen notwendig sind , um zu vermeiden , Race Conditions und es besteht ein Bedarf Wert zwischen dem sequentiellen Teil passieren und dem parallelen Bereich (der Codeblock parallel ausgeführt), so dass die Daten Umweltmanagement als eingeführt Datenattribut Klauseln teilt durch Anhänge von ihnen die OpenMP-Direktive. Die verschiedenen Arten von Klauseln sind:

Klauseln für Datenfreigabeattribute
  • shared : Die außerhalb einer parallelen Region deklarierten Daten werden gemeinsam genutzt, was bedeutet, dass alle Threads gleichzeitig sichtbar und zugänglich sind. Standardmäßig werden alle Variablen in der Arbeitsteilungsregion gemeinsam genutzt, mit Ausnahme des Schleifeniterationszählers.
  • private : Die in einem parallelen Bereich deklarierten Daten sind für jeden Thread privat, was bedeutet, dass jeder Thread eine lokale Kopie hat und diese als temporäre Variable verwendet. Eine private Variable wird nicht initialisiert und der Wert wird nicht für die Verwendung außerhalb des parallelen Bereichs beibehalten. Standardmäßig sind die Schleifeniterationszähler in den OpenMP-Schleifenkonstrukten privat.
  • default : erlaubt dem Programmierer anzugeben , dass der Standard-Datenbereich innerhalb einer parallelen Region entweder shared oder none für C/C++ oder shared , firstprivate , private oder none für Fortran ist. Die Option none zwingt den Programmierer, jede Variable im parallelen Bereich unter Verwendung der Attributklauseln für die gemeinsame Nutzung von Daten zu deklarieren.
  • firstprivate : wie private, außer dass auf den ursprünglichen Wert initialisiert.
  • lastprivate : wie private, außer dass der ursprüngliche Wert nach dem Konstrukt aktualisiert wird.
  • Reduzierung : eine sichere Art der Verbindung von allen Fäden nach der Konstruktion.
Synchronisationsklauseln
  • kritisch : Der eingeschlossene Codeblock wird jeweils nur von einem Thread ausgeführt und nicht gleichzeitig von mehreren Threads. Es wird häufig verwendet, um gemeinsam genutzte Daten vor Race-Bedingungen zu schützen .
  • atomar : Die Speicheraktualisierung (Schreiben oder Lesen-Modifizieren-Schreiben) im nächsten Befehl wird atomar ausgeführt. Es macht nicht die gesamte Anweisung atomar; nur die Speicheraktualisierung ist atomar. Ein Compiler verwendet möglicherweise spezielle Hardwareanweisungen für eine bessere Leistung als bei der Verwendung von kritischen .
  • ordered : Der strukturierte Block wird in der Reihenfolge ausgeführt, in der Iterationen in einer sequentiellen Schleife ausgeführt würden
  • barrier : Jeder Thread wartet, bis alle anderen Threads eines Teams diesen Punkt erreicht haben. Ein Arbeitsteilungskonstrukt hat am Ende eine implizite Barrieresynchronisation.
  • nowait : Gibt an, dass Threads, die zugewiesene Arbeiten abschließen, fortgesetzt werden können, ohne darauf zu warten, dass alle Threads im Team fertig sind. Fehlt diese Klausel, treffen Threads am Ende des Arbeitsteilungskonstrukts auf eine Barrieresynchronisation.
Fahrplanklauseln
  • schedule (type, chunk) : Dies ist nützlich, wenn das Arbeitsteilungskonstrukt eine Do-Schleife oder eine For-Schleife ist. Die Iterationen im Arbeitsteilungskonstrukt werden Threads gemäß der durch diese Klausel definierten Scheduling-Methode zugewiesen. Die drei Arten der Terminplanung sind:
  1. static : Hier werden allen Threads Iterationen zugewiesen, bevor sie die Schleifeniterationen ausführen. Die Iterationen werden standardmäßig gleichmäßig auf die Threads aufgeteilt. Wenn Sie jedoch eine ganze Zahl für den Parameter chunk angeben, wird einem bestimmten Thread die Chunk-Anzahl zusammenhängender Iterationen zugewiesen.
  2. dynamic : Hier werden einige Iterationen einer kleineren Anzahl von Threads zugewiesen. Sobald ein bestimmter Thread seine zugewiesene Iteration beendet hat, kehrt er zurück, um einen anderen aus den verbleibenden Iterationen zu holen. Der Parameter chunk definiert die Anzahl zusammenhängender Iterationen, die einem Thread gleichzeitig zugewiesen werden.
  3. geführt : Ein großer Teil zusammenhängender Iterationen wird jedem Thread dynamisch zugewiesen (wie oben). Die Chunk-Größe nimmt mit jeder weiteren Zuweisung exponentiell auf eine im Parameter chunk angegebene Mindestgröße ab
ZF-Steuerung
  • if : Dies bewirkt, dass die Threads die Aufgabe nur dann parallelisieren, wenn eine Bedingung erfüllt ist. Andernfalls wird der Codeblock seriell ausgeführt.
Initialisierung
  • firstprivate : Die Daten sind für jeden Thread privat, werden jedoch mit dem Wert der Variablen mit demselben Namen aus dem Master-Thread initialisiert.
  • lastprivate : Die Daten sind für jeden Thread privat. Der Wert dieser privaten Daten wird in eine globale Variable mit demselben Namen außerhalb des parallelen Bereichs kopiert, wenn die aktuelle Iteration die letzte Iteration in der parallelisierten Schleife ist. Eine Variable kann sowohl firstprivate als auch lastprivate sein .
  • threadprivate : Die Daten sind globale Daten, aber sie sind während der Laufzeit in jeder parallelen Region privat. Der Unterschied zwischen threadprivate und private ist der globale Gültigkeitsbereich, der threadprivate zugeordnet ist, und der beibehaltene Wert über parallele Regionen hinweg.
Daten kopieren
  • copyin : Ähnlich wie firstprivate für private Variablen werden threadprivate- Variablen nicht initialisiert, es sei denn, sie verwenden copyin , um den Wert von den entsprechenden globalen Variablen zu übergeben. Es ist kein Copyout erforderlich, da der Wert einer threadprivate-Variablen während der gesamten Ausführung des gesamten Programms beibehalten wird.
  • copyprivate : Wird mit single verwendet , um das Kopieren von Datenwerten von privaten Objekten in einem Thread (dem einzelnen Thread) in die entsprechenden Objekte in anderen Threads im Team zu unterstützen.
Die Ermäßigung
  • Reduktion (operator | intrinsisch : Liste) : Die Variable hat eine lokale Kopie in jedem Thread, aber die Werte der lokalen Kopien werden in einer globalen gemeinsamen Variablen zusammengefasst (reduziert). Dies ist sehr nützlich, wenn eine bestimmte Operation (im Operator für diese bestimmte Klausel angegeben) für eine Variable iterativ ausgeführt wird, sodass ihr Wert bei einer bestimmten Iteration von ihrem Wert bei einer vorherigen Iteration abhängt. Die Schritte, die zum Betriebsinkrement führen, werden parallelisiert, aber die Threads aktualisieren die globale Variable auf Thread-sichere Weise. Dies wäre beispielsweise bei der Parallelisierung der numerischen Integration von Funktionen und Differentialgleichungen erforderlich .
Andere
  • flush : Der Wert dieser Variablen wird aus dem Register in den Speicher zurückgeschrieben, um diesen Wert außerhalb eines parallelen Teils zu verwenden
  • master : Wird nur vom Master-Thread ausgeführt (der Thread, der alle anderen während der Ausführung der OpenMP-Direktive abgespalten hat). Keine implizite Barriere; andere Teammitglieder (Threads), die nicht zu erreichen sind.

Laufzeitroutinen auf Benutzerebene

Wird verwendet, um die Anzahl der Threads zu ändern/zu überprüfen, zu erkennen, ob sich der Ausführungskontext in einem parallelen Bereich befindet, wie viele Prozessoren im aktuellen System vorhanden sind, Sperren zu setzen/aufzuheben, Timing-Funktionen usw

Umgebungsvariablen

Eine Methode zum Ändern der Ausführungsfunktionen von OpenMP-Anwendungen. Wird verwendet, um das Scheduling von Schleifeniterationen, die Standardanzahl von Threads usw. zu steuern. OMP_NUM_THREADS wird beispielsweise verwendet, um die Anzahl von Threads für eine Anwendung anzugeben.

Implementierungen

OpenMP wurde in vielen kommerziellen Compilern implementiert. Visual C++ 2005, 2008, 2010, 2012 und 2013 unterstützen es beispielsweise (OpenMP 2.0, in den Editionen Professional, Team System, Premium und Ultimate) sowie Intel Parallel Studio für verschiedene Prozessoren. Die Compiler und Tools von Oracle Solaris Studio unterstützen die neuesten OpenMP-Spezifikationen mit Produktivitätsverbesserungen für Solaris OS (UltraSPARC und x86/x64) und Linux-Plattformen. Die Fortran-, C- und C++-Compiler von The Portland Group unterstützen auch OpenMP 2.5. GCC unterstützt seit Version 4.2 auch OpenMP.

Compiler mit einer Implementierung von OpenMP 3.0:

  • GCC 4.3.1
  • Mercurium-Compiler
  • Intel Fortran- und C/C++-Compiler der Versionen 11.0 und 11.1, Intel C/C++ und Fortran Composer XE 2011 und Intel Parallel Studio.
  • IBM XL-Compiler
  • Sun Studio 12 Update 1 enthält eine vollständige Implementierung von OpenMP 3.0
  • Multiprozessor-Computing ( "MPC" .)

Mehrere Compiler unterstützen OpenMP 3.1:

  • GCC 4.7
  • Intel Fortran- und C/C++-Compiler 12.1
  • IBM XL C/C++ Compiler für AIX und Linux, V13.1 & IBM XL Fortran Compiler für AIX und Linux, V14.1
  • LLVM/Klang 3.7
  • Absoft Fortran Compiler v. 19 für Windows, Mac OS X und Linux

Compiler, die OpenMP 4.0 unterstützen:

  • GCC 4.9.0 für C/C++, GCC 4.9.1 für Fortran
  • Intel Fortran- und C/C++-Compiler 15.0
  • IBM XL C/C++ für Linux, V13.1 (teilweise) & XL Fortran für Linux, V15.1 (teilweise)
  • LLVM/Clang 3.7 (teilweise)

Mehrere Compiler, die OpenMP 4.5 unterstützen:

  • GCC 6 für C/C++
  • Intel Fortran- und C/C++-Compiler 17.0, 18.0, 19.0
  • LLVM/Klang 12

Teilweise Unterstützung für OpenMP 5.0:

  • GCC 9 für C/C++
  • Intel Fortran- und C/C++-Compiler 19.1
  • LLVM/Klang 12

Automatisch parallelisierende Compiler, die Quellcode generieren, der mit OpenMP-Direktiven annotiert ist:

Mehrere Profiler und Debugger unterstützen ausdrücklich OpenMP:

  • Intel VTune Profiler - ein Profiler für die x86 - CPU und X e GPU - Architekturen
  • Intel Advisor - ein Designunterstützungs- und Analysetool für OpenMP- und MPI-Codes
  • Allinea Distributed Debugging Tool (DDT) – Debugger für OpenMP- und MPI-Codes
  • Allinea MAP – Profiler für OpenMP- und MPI-Codes
  • TotalView - Debugger von Rogue Wave Software für OpenMP, MPI und serielle Codes
  • ompP – Profiler für OpenMP
  • VAMPIR – Profiler für OpenMP- und MPI-Code

Vor-und Nachteile

Vorteile:

  • Tragbarer Multithreading-Code (in C/C++ und anderen Sprachen muss man normalerweise plattformspezifische Primitive aufrufen, um Multithreading zu erhalten).
  • Ganz einfach: Sie müssen sich nicht wie bei MPI mit der Nachrichtenweitergabe befassen .
  • Datenlayout und -zerlegung werden automatisch durch Direktiven gehandhabt.
  • Skalierbarkeit vergleichbar mit MPI auf Shared-Memory-Systemen.
  • Inkrementelle Parallelität: Kann an einem Teil des Programms gleichzeitig arbeiten, es sind keine dramatischen Änderungen am Code erforderlich.
  • Einheitlicher Code für serielle und parallele Anwendungen: OpenMP-Konstrukte werden als Kommentare behandelt, wenn sequentielle Compiler verwendet werden.
  • Originale (serielle) Code-Anweisungen müssen bei der Parallelisierung mit OpenMP im Allgemeinen nicht modifiziert werden. Dies verringert die Wahrscheinlichkeit, dass versehentlich Fehler eingeführt werden.
  • Es sind sowohl grobkörnige als auch feinkörnige Parallelitäten möglich.
  • In unregelmäßigen Multi-Physik-Anwendungen, die sich nicht ausschließlich an den SPMD- Berechnungsmodus halten, wie es in eng gekoppelten Fluid-Partikel-Systemen angetroffen wird, kann die Flexibilität von OpenMP einen großen Leistungsvorteil gegenüber MPI haben .
  • Kann auf verschiedenen Beschleunigern wie GPGPU und FPGAs verwendet werden .

Nachteile:

  • Risiko der Einführung von schwer zu debuggenden Synchronisierungsfehlern und Racebedingungen .
  • Läuft ab 2017 nur noch effizient in Shared-Memory-Multiprozessor-Plattformen (siehe jedoch Intels Cluster OpenMP und andere verteilte Shared-Memory- Plattformen).
  • Erfordert einen Compiler, der OpenMP unterstützt.
  • Die Skalierbarkeit wird durch die Speicherarchitektur begrenzt.
  • Keine Unterstützung für Compare-and-Swap .
  • Zuverlässige Fehlerbehandlung fehlt.
  • Es fehlen fein abgestimmte Mechanismen zur Steuerung der Thread-Prozessor-Zuordnung.
  • Hohe Wahrscheinlichkeit, versehentlich falschen Freigabecode zu schreiben .

Leistungserwartungen

Man könnte erwarten, eine N- fache Geschwindigkeit zu erhalten, wenn ein mit OpenMP parallelisiertes Programm auf einer N- Prozessorplattform ausgeführt wird. Dies geschieht jedoch selten aus folgenden Gründen:

  • Wenn eine Abhängigkeit besteht, muss ein Prozess warten, bis die Daten, von denen er abhängt, berechnet wurden.
  • Wenn mehrere Prozesse eine nicht parallele Prüfressource (wie eine Datei zum Schreiben) gemeinsam nutzen, werden ihre Anforderungen sequentiell ausgeführt. Daher muss jeder Thread warten, bis der andere Thread die Ressource freigibt.
  • Ein Großteil des Programms darf von OpenMP nicht parallelisiert werden, was bedeutet, dass die theoretische Obergrenze der Beschleunigung nach dem Amdahl-Gesetz begrenzt ist .
  • N Prozessoren in einem symmetrischen Multiprocessing (SMP) können die N-fache Rechenleistung haben, aber die Speicherbandbreite skaliert normalerweise nicht N-fach. Ziemlich oft wird der ursprüngliche Speicherpfad von mehreren Prozessoren gemeinsam genutzt und es kann zu Leistungseinbußen kommen, wenn sie um die gemeinsam genutzte Speicherbandbreite konkurrieren.
  • Viele andere häufige Probleme, die die endgültige Geschwindigkeit beim parallelen Rechnen beeinträchtigen, gelten auch für OpenMP, wie zum Beispiel Lastausgleich und Synchronisations-Overhead.
  • Die Compiler-Optimierung ist beim Aufrufen von OpenMP möglicherweise nicht so effektiv. Dies kann häufig dazu führen, dass ein Single-Thread-OpenMP-Programm langsamer läuft als derselbe Code, der ohne ein OpenMP-Flag kompiliert wurde (das vollständig seriell ist).

Thread-Affinität

Einige Anbieter empfehlen, die Prozessoraffinität für OpenMP-Threads festzulegen, um sie bestimmten Prozessorkernen zuzuordnen. Dies minimiert die Kosten für die Thread-Migration und den Kontextwechsel zwischen den Kernen. Es verbessert auch die Datenlokalität und reduziert den Cache-Kohärenzverkehr zwischen den Kernen (oder Prozessoren).

Benchmarks

Es wurden verschiedene Benchmarks entwickelt, um die Verwendung von OpenMP zu demonstrieren, seine Leistung zu testen und die Korrektheit zu bewerten.

Einfache Beispiele

Leistungsbenchmarks umfassen:

Korrektheits-Benchmarks umfassen:

Siehe auch

Verweise

Weiterlesen

Externe Links