SFB 382
Teilprojekt C6
Verfahren zur Parallelisierung
physikalischer Prozesse mit objektorientierten Methoden
Leiter:
Prof. W. Rosenstiel
Prof. H. Ruder
Prof. H. Yserentant
Mitarbeiter:
Dipl.-inform. Marcus Ritt
Dipl.-phys. Michael Hipp
Dipl.-phys. Sven Ganzenmüller
Dipl.-phys. Simon Pinkenburg
Dipl.-phys. Steffen Holtwick
Projektübersicht
TPO++
sph2000
Veröffentlichungen
Proseminar SS 3
Seminar WS 3/4
Seminar SS 04
Studien- und Diplomarbeiten
Ältere Lehrveranstaltungen
|
|
Motivation
MPI ist als Standard in mit Message-Passing parallelisierten
Programmen heute weitverbreitet, und hat andere Systeme, wie
beipielsweise PVM, weitgehend abgelöst. Gleichzeitig gewinnen C++ und
objektorientierte Systeme zunehmend Akzeptanz in wissenschaftlichen
Programmen, da auch hier Wartbarkeit und Wiederverwendung aufgrund
immer umfangreicherer Codes wichtiger werden. MPI definiert zwar
sogenannte C++-Bindungen, diese orientiert sich jedoch an der
C-Schnittstelle und ist nicht objektorientiert. Die Kommunikation von
Objekten ist somit schwierig und unkomfortabel. Neue Techniken und
Konzepte von C++ werden nicht unterstützt. Hier ist insbesondere die
Standard Template Library (STL) zur generischen Programmierung zu
nennen. Weiterhin ist die C++-Schnittstelle von MPI nicht typsicher,
was zu einer höheren Fehleranfälligkeit führt.
Message-Passing-Systeme wie OOMPI und Para++ versuchen zwar eine
bessere Einbindung objektorientierter Konzepte zu erreichen,
unterstützen aber ebenfalls nicht die STL.
Entwurfsziele
Ein objektorientiertes Message-Passing-System für C++ soll sich
möglichst nahtlos in die Sprache integrieren und dem Anwender eine
komfortable, leicht zu handhabende Schnittstelle zur Verfügung stellen.
Dazu gehört die volle Unterstützung objektorientierter Konzepte und
damit die Möglichkeit Objekte direkt und einfach zwischen den
beteiligten Kommunikationspartnern austauschen zu können. Die
Schnittstellen sollen dabei natürlich typsicher sein, um mittels
statischer Typanalyse eine große Anzahl potenzieller Fehler schon zur
Übersetzungszeit ausschliessen zu können.
Weiterhin sollen fortschrittliche Konzepte aus C++, wie die STL und
Exception-Handling möglichst gut integriert sein, sowohl was die
üblichen Konventionen (Iteratoren etc.) betrifft, als auch in Bezug
auf die Performance. Dabei sollen bekannte Konzepte und Verfahren aus MPI,
soweit im objektorientierten Rahmen sinnvoll, erhalten bleiben, um die
Lernkurve für den Anwender möglichst flach zu halten und die
Portierung bestehender Programme zu erleichtern.
Ein weiterer Punkt ist die Einbeziehung absehbarer zukünftiger
Entwicklungen, wie kombinierter Parallelisierung mit Message-Passing
und Threads und damit Threadsicherheit.
Nicht zuletzt darf die Effizienz des Systems trotz höherer Abstraktion
und komfortabler Programmierung nicht oder nur minimal hinter der von
MPI zurückliegen.
Architektur und Beispiele
Das hier vorgestellte System TPO++ (Tübingen Parallel Objects) setzt
die oben genannten Ziele um. Es baut dabei auf eine
Standard-MPI-Implementierung auf, und ist somit auf alle Plattformen
portabel, die MPI anbieten, und kann auch von optimierten
MPI-Varianten für spezielle Rechnerarchitekturen profitieren. Die
Implementierung der Punkt-zu-Punkt Kommunikation ist fertiggestellt,
die Implementierung kollektiver Kommunikationmechanismen ist
weitgehend abgeschlossen. Dabei werden alle von MPI vorgesehenen
Übertragungsmodi (asynchrone Kommunikation etc.)
unterstützt. Interkommunikatoren sind derzeit noch nicht implementiert.
Die Basisstruktur von TPO++ folgt den C++-Bindungen von MPI. Alle
grundlegenden MPI-Objekte, wie Kommunikatoren, Gruppen, etc. sind in
eigenen Klassen implementiert. Die wichtigsten Erweiterungen finden
sich in der Kommunikationsschnittstelle, der Unterstützung
von Standardbibliotheks- und benutzerdefinierten Klassen und in der
Fehlerbehandlung.
Übertragung vordefinierter Typen
Basistypen von C++ können direkt übertragen werden. Die vordefinierten
Containerklassen der STL können direkt übertragen werden, wenn die
enthaltenen Objekte übertragen werden können. Die Schnittstellen für
die Übertragung von Containern, folgen den Konventionen der STL. So
ist es möglich auch Bereiche (Ranges) aus Datencontainern zu
verschicken.
Senden und Empfangen eines primitiven Datentyps.
double d;
CommWorld.send(d, dest_rank); //Sender
Status status;
status=CommWorld.recv(d); //Empfänger
Senden und Empfangen eines STL-Containers. Beim Empfang wird
vorausgesetzt, dass der Zielcontainer ausreichend Platz
bereitstellt.
vector vd;
CommWorld.send(vd.begin(), vd.end(), dest_rank); //Sender
vector vd1(x);
CommWorld.recv(vd1.begin()); //Empfänger
Empfang mit dynamischer Erweiterung des Zielcontainers.
vector vd2;
CommWorld.recv(tpo_back_insert_iterator(vd2));
Übertragung benutzerdefinierter Typen
Die Schnittstellen für die Übertragung benutzerdefinierter Klassen
entsprechen denen aus dem
vorhergehenden Kapitel. Benutzerdefinierte Klassen
müssen jedoch für die Übertragung vorbereitet werden. Für Datentypen
mit trivialem Speicherlayout reicht es dazu diese Datentypen TPO++
mittels bekannt zu machen. So erfolgt auch eine optimierte
Übertragung. Datentypen mit nichttrivialem Speicherlayout müssen
Marshalling-Funktionen bereitstellen.
Eine triviale benutzerdefinierte Klasse - Diese durch das Makro
TPO_TRIVIAL dem System bekannt gemacht.
class Point {
public:
Point() : x(0), y(0) {}
private:
int x, y;
};
TPO_TRIVIAL(Point);
Dynamische benutzerdefinierte Klasse mit Übertragungsfunktionen. Hier
wird der Typ mit dem Makro TPO_MARSHALL dem System
bekanntgemacht. Der Benutzer muss in diesem Fall die
Übertragungsfunktionen serialize zum Verschicken und
deserialize zum Empfang der Klasse definieren.
class Circle {
public:
Circle(): radius(0.0)
{ center = new Point;}
~Circle() { delete center;}
void serialize(Message_data& m) const
{
m.insert(*center);
m.insert(radius);
}
void deserialize(Message_data& m)
{
m.extract(*center);
m.extract(radius);
}
private:
Point* center;
double radius;
};
TPO_MARSHALL(Circle);
Fehlerbehandlung
Die Fehlerbehandlung von TPO++ basiert auf C++-Exceptions gemäß den
MPI-C++-Bindungen. Um ausufernde Catch/Try-Blöcke zu vermeiden, können
auch globale Fehlerbehandlungsroutinen spezifiziert werden. TPO
verwendet hier im Gegensatz zu MPI eine eigene Klasse, die von der
Anwendung spezialisiert werden kann.
Vergleich mit MPI
TPO++ wurde auf Workstations unter Solaris 2.7 und MPICH ab
Version 1.1.2 entwickelt. Die Bibliothek läuft auch auf einer Cray
T3E (512 Knoten / 450 MHz) mit der Cray MPI-Implementierung. Eine
Version für Linux existiert ebenfalls.
Die folgenden Messungen erfolgten mit einem einfachen Ping-Pong-Test.
Abbildung 1:
Vergleich der Bandbreiten und Latenzzeiten von MPI
(durchgezogene Linien) und TPO++ (gestrichelte Linien). Oben:
Messungen auf der Cary T3E. Unten: Messungen im 100 Mbit LAN
|
|
Die Messungen in Bild 1 zeigen, dass TPO++ auf der Cray T3E
für Übertragungsgrößen ab ca. 16 KB die selbe Bandbreite wie MPI
erreicht. Der Verlust an Bandbreite für kleinere Übertragungsgrößen
resultiert hauptsächlich aus der erhöhten Latenzzeit (rechts oben).
Für kleine Übertragungsgrößen zeigt TPO++ eine konstante Latenz von
verglichen mit von MPI. Wie die Messungen zeigen
kann der Overhead von TPO++ im LAN vernachlässigt werden.
Zusammenfassung
TPO ist ein Message-Passing-System, das objektorientierte und
generische Programmierkonzepte unterstützt. Das System erlaubt
einfache, komfortable und sichere Kommunikation auch von komplexen und
dynamischen Objekten. Einmal geschriebener Code zur
Objektkommunikation kann vererbt und somit wiederverwendet werden. Die
Semantik und die Konventionen von MPI werden dabei soweit möglich
beibehalten. Durch fortschrittliche Abstraktionstechniken werden
Optimierungsmöglichkeiten des Compilers unterstützt, so dass eine hohe
Effizienz des generierten Codes erreicht wird.
Download
Die aktuelle Version 0.3dp1 (Juli 2003), getestet unter Solaris/mpich, Unicos/mpt, Linux/mpich gibt es hier .
Version 0.4 wird demnächst 0.3 ablösen, hier findet man den aktuellen release candidate.
|