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
\scalebox {1.0}{
\scalebox{0.3}{\includegraphics{CRAY_BB.eps}}%
\vspace*{1cm}%
\scalebox{0.3}{\includegraphics{CRAY_LL.eps}}
}
\scalebox {1.0}{
\scalebox{0.3}{\includegraphics{LAN_BB.eps}}%
\vspace*{1cm}%
\scalebox{0.3}{\includegraphics{LAN_LL.eps}}
}

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 $30 \mu s$ verglichen mit $15 \mu s$ 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.