459

[X.systems.press] Cluster Computing ||

  • Upload
    vandiep

  • View
    292

  • Download
    26

Embed Size (px)

Citation preview

Page 1: [X.systems.press] Cluster Computing ||
Page 2: [X.systems.press] Cluster Computing ||

.presssyst semX.

X.systems.press ist eine praxisorientierteReihe zur Entwicklung und Administration von

Betriebssystemen, Netzwerken und Datenbanken.

Page 3: [X.systems.press] Cluster Computing ||

Heiko Bauke · Stephan Mertens

Cluster ComputingPraktische Einführung in dasHochleistungsrechnen auf Linux-Clustern

Mit 85 Abbildungen

123

Page 4: [X.systems.press] Cluster Computing ||

Heiko BaukeStephan MertensInstitut für Theoretische PhysikOtto-von-Guericke-Universität MagdeburgUniversitätsplatz 239106 [email protected]

Bibliografische Information der Deutschen BibliothekDie Deutsche Bibliothek verzeichnet diese Publikation in der DeutschenNationalbibliografie; detaillierte bibliografische Daten sind im Internet überhttp://dnb.ddb.de abrufbar.

ISSN 1614-5216ISBN-10 3-540-42299-4 Springer Berlin Heidelberg New YorkISBN-13 978-3-540-42299-0 Springer Berlin Heidelberg New York

Dieses Werk ist urheberrechtlich geschützt. Die dadurch begründeten Rechte, insbesonderedie der Übersetzung, des Nachdrucks, des Vortrags, der Entnahme von Abbildungen undTabellen, der Funksendung, der Mikroverfilmung oder der Vervielfältigung auf anderen We-gen und der Speicherung in Datenverarbeitungsanlagen, bleiben, auch bei nur auszugsweiserVerwertung, vorbehalten. Eine Vervielfältigung dieses Werkes oder von Teilen dieses Werkesist auch im Einzelfall nur in den Grenzen der gesetzlichen Bestimmungen des Urheberrechts-gesetzes der Bundesrepublik Deutschland vom 9. September 1965 in der jeweils geltendenFassung zulässig. Sie ist grundsätzlich vergütungspflichtig. Zuwiderhandlungen unterliegenden Strafbestimmungen des Urheberrechtsgesetzes.

Springer ist ein Unternehmen von Springer Science+Business Media

springer.de

© Springer-Verlag Berlin Heidelberg 2006Printed in Germany

Die Wiedergabe von Gebrauchsnamen, Handelsnamen, Warenbezeichnungen usw. in diesemWerk berechtigt auch ohne besondere Kennzeichnung nicht zu der Annahme, dass solcheNamen im Sinne der Warenzeichen- und Markenschutz-Gesetzgebung als frei zu betrachtenwären und daher von jedermann benutzt werden dürften. Text und Abbildungen wurdenmit größter Sorgfalt erarbeitet. Verlag und Autor können jedoch für eventuell verbliebenefehlerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch irgendeineHaftung übernehmen.

Satz: Druckfertige Daten der AutorenHerstellung: LE-TEX, Jelonek, Schmidt & Vöckler GbR, LeipzigUmschlaggestaltung: KünkelLopka Werbeagentur, HeidelbergGedruckt auf säurefreiem Papier 33/3142 YL – 5 4 3 2 1 0

Page 5: [X.systems.press] Cluster Computing ||

Vorwort

Oxford Advanced Learner’s Dictionary of Current English.

Cluster Computing ist dabei, die Welt des wissenschaftlichen Rechnens zu revolu-tionieren. Dabei ist die Idee bestechend einfach: man nehme eine Handvoll Rechner,verbinde sie mit handelsublicher Netztechnik und installiere frei verfugbare Softwa-re, die aus den vernetzten Rechnern einen Parallelrechner macht. Damit haben Sieein System, das fur ein Minimum an Kosten ein Maximum an Rechenleistung bietet.

Dass diese Idee auch in der Praxis funktioniert beweisen die zahlreichen Clus-ter, die bereits an Universitaten, Forschungsinstituten und in der Industrie entstandensind. Dort modellieren sie das globale Klima und die Entstehung von Galaxien, sieanalysieren Gensequenzen und sie stecken hinter den atemberaubenden Spezialeffek-ten aus Hollywood. Die großten Cluster bestehen aus tausenden von Einzelrechnernund gehoren zu den schnellsten Computern der Welt.

Cluster Computing ist attraktiv, und immer mehr Leute entschließen sich, selbsteinen Cluster zu betreiben. Das praktische Cluster Computing ist leider nicht ganzso einfach wie die Idee dahinter. Dieses Buch wird Ihnen helfen, Ihren Cluster zuplanen, zu bauen und zu betreiben.

Unser Leitfaden zum Cluster Computing ist in vier Teile gegliedert. Teil I (Grund-lagen) befasst sich mit den Prinzipien des parallelen Rechnens. Hier erfahren sie et-was uber parallele Leistungsmetriken, Rechnerarchitekturen und die verschiedenenMoglichkeiten des parallelen Programmierens. Teil II (Technik) enthalt die Dinge,die Sie wissen mussen, um einen Cluster zu planen und aufzubauen. Das reicht vonder Auswahl der Hardware uber die Konfiguration des Netzwerks bis zur Installationder Cluster-Software. Dabei konzentrieren wir uns auf die kanonische (und preis-werteste) Art, einen Cluster zu bauen, namlich mit Standardkomponenten aus demPC-Bereich und Linux als Betriebssystem. Unsere Empfehlungen und Anregungenlassen sich aber ohne große Probleme auch auf abweichende Ansatze ubertragen.Teil III (MPI) behandelt das parallele Programmieren mit dem Message Passing In-terface, dem Standard fur paralleles Programmieren uberhaupt. MPI-Anwendungen

Page 6: [X.systems.press] Cluster Computing ||

VI Vorwort

laufen auf großen und kleinen Clustern, auf klassischen big iron Supercomputern undsogar auf ihrem Laptop. In Teil IV (Praxis) diskutieren wir den Umgang mit Fehlernim Programm (Debugging) und im Betrieb (Checkpointing) und stellen Ihnen einigeparallele Bibliotheken vor. Hier verraten wir Ihnen auch, wie Sie mit Ihrem Clusterin die Top 500 der schnellsten Computer der Welt kommen.

Zu diesem Buch gibt es eine Webseite. Unter http://www.clustercomputing.definden Sie alle Beispielprogramme sowie Verweise zu anderen Webseiten rund umdas Cluster Computing.

Bedanken mochten wir uns an dieser Stelle bei Jurgen Gretzschel, Andreas Her-zog, Karsten Petersen, Alexander Schinner, Jeff Squyres und Sebastian Wohner furihre Beitrage zum Gelingen dieses Buches. Dank gebuhrt auch dem Rechenzentrumder Otto-von-Guericke Universitat Magdeburg, das uns stets auf unkomplizierte Wei-se bei unseren Cluster-Projekten unterstutzt hat.

Seit wir vor ein paar Jahren mit dem Cluster Computing begannen, sind wir vonder Idee begeistert. Wir hoffen, mit diesem Buch unsere Begeisterung an Sie weiter-geben zu konnen.

Magdeburg im Juni 2005

Heiko Bauke, Stephan Mertens

Page 7: [X.systems.press] Cluster Computing ||

Inhaltsverzeichnis

Teil I Grundlagen

1 Von Megahertz zu Gigaflops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.1 Ochsen oder Huhner? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2 Rechenleistung im Takt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51.3 Von-Neumann-Flaschenhals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71.4 Benchmarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81.5 Amdahls Gesetz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101.6 Granularitat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131.7 Parallele Leistungsmetriken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161.8 Notizen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

2 Parallelrechner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212.1 Gemeinsamer oder verteilter Speicher . . . . . . . . . . . . . . . . . . . . . . . . . 212.2 Verbindungsnetzwerke . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242.3 Cluster-Computer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

2.3.1 Das Beowulf-Projekt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272.3.2 Standard-Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282.3.3 Linux, freie Software und offene Standards . . . . . . . . . . . . . . 302.3.4 Anwendungsgebiete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

2.4 SETI@home und Grid-Computing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322.5 Notizen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

3 Programmieransatze . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373.1 Datenparallelitat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373.2 Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393.3 Nachrichtentransfer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443.4 Notizen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

Page 8: [X.systems.press] Cluster Computing ||

VIII Inhaltsverzeichnis

Teil II Technik

4 Cluster-Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514.1 Grundlegende Komponenten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514.2 Anforderungen an einen High-Performance-Cluster . . . . . . . . . . . . . . 524.3 Netzwerktechnik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

4.3.1 Netzwerkhardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544.3.2 Netzwerktechnologien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

4.4 CPU-Architektur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 614.5 Arbeitsspeicher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 624.6 Massenspeicher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

4.6.1 Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 634.6.2 Clusterdateisysteme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

4.7 Diskless nodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 654.8 Hardware-Monitoring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 664.9 Unterbringung, Klima und Kuhlung . . . . . . . . . . . . . . . . . . . . . . . . . . . 674.10 Cluster now! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 694.11 Besonderheiten von Knoten-Hardware . . . . . . . . . . . . . . . . . . . . . . . . . 704.12 Schrauben oder kaufen? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

4.12.1 Do it your self . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 724.12.2 Schlusselfertig . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

4.13 Notizen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

5 PCs vernetzen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 755.1 TCP/IP-Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 775.2 Calculus – Der Beispiel-Cluster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 805.3 Erstinstallation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

5.3.1 Hardwareaufbau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 815.3.2 Linux-Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 825.3.3 Kernel-Anpassungen und Hardware-Monitoring . . . . . . . . . . 845.3.4 Hardware-Monitoring per Init-Skript starten . . . . . . . . . . . . . . 89

5.4 Netzwerk-Basiskonfiguration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905.4.1 Netzwerkkartentreiber laden . . . . . . . . . . . . . . . . . . . . . . . . . . . 905.4.2 IP-Adresse zuweisen und Gateway einrichten . . . . . . . . . . . . . 915.4.3 Dauerhafte Speicherung der Netzwerkkonfiguration . . . . . . . 925.4.4 Namensauflosung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 945.4.5 Tuning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

5.5 SystemImager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 975.5.1 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 975.5.2 Vollautomatische Installation . . . . . . . . . . . . . . . . . . . . . . . . . . 985.5.3 Updates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1025.5.4 Sicherheit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1035.5.5 Einschrankungen und Alternativen . . . . . . . . . . . . . . . . . . . . . . 104

5.6 Wichtige Netzdienste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104

Page 9: [X.systems.press] Cluster Computing ||

Inhaltsverzeichnis IX

5.6.1 Network File System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1055.6.2 Network Information Service . . . . . . . . . . . . . . . . . . . . . . . . . . 1085.6.3 Berkeley-r-Kommandos und die Secure Shell . . . . . . . . . . . . . 1125.6.4 Network Time Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1165.6.5 Network Address Translation . . . . . . . . . . . . . . . . . . . . . . . . . . 1185.6.6 Dynamic Host Configuration Protocol . . . . . . . . . . . . . . . . . . . 121

5.7 Channel bonding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1255.8 Diskless nodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129

5.8.1 Uberblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1295.8.2 Booten uber das Netzwerk mit PXE . . . . . . . . . . . . . . . . . . . . . 1305.8.3 Kernelkonfiguration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1315.8.4 Server-Konfiguration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1315.8.5 Alternativen und weitere Quellen . . . . . . . . . . . . . . . . . . . . . . . 139

5.9 Notizen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140

6 Cluster-Dienste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1436.1 LAM/MPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143

6.1.1 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1456.1.2 MPI-Programme kompilieren und starten . . . . . . . . . . . . . . . . 147

6.2 Jobverwaltung und Batch-Systeme . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1516.2.1 Funktionsweise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1516.2.2 Scheduling-Strategien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1526.2.3 Checkpointing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1536.2.4 Batch-Systeme im Uberblick . . . . . . . . . . . . . . . . . . . . . . . . . . 1546.2.5 Anwendungsbeispiel: Sun Grid Engine . . . . . . . . . . . . . . . . . . 157

6.3 Cluster-Management-Systeme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1606.3.1 OSCAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1626.3.2 Rocks Cluster Distribution . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163

6.4 Notizen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163

Teil III MPI

7 Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1677.1 Das Minimalgerust . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1677.2 Senden und Empfangen von Nachrichten . . . . . . . . . . . . . . . . . . . . . . . 1707.3 Kollektive Kommunikation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173

7.3.1 Daten verteilen mit MPI Bcast . . . . . . . . . . . . . . . . . . . . . . . 1737.3.2 Synchronisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1757.3.3 Kollektive Varianten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1777.3.4 Mehr Variabilitat mit v . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1797.3.5 Daten zusammenfassen mit MPI Reduce . . . . . . . . . . . . . . . 182

7.4 Anatomie der Nachrichtenubertragung . . . . . . . . . . . . . . . . . . . . . . . . . 1897.4.1 Blockierender Nachrichtentransfer . . . . . . . . . . . . . . . . . . . . . . 1907.4.2 Laufzeitmessungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194

Page 10: [X.systems.press] Cluster Computing ||

X Inhaltsverzeichnis

7.4.3 Deadlocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1977.4.4 Fairness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201

7.5 Nicht blockierender Nachrichtentransfer . . . . . . . . . . . . . . . . . . . . . . . 2057.5.1 Rechnen statt Warten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2057.5.2 Zeitlicher Ablauf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2077.5.3 Flexibles Warten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2097.5.4 Persistente Kommunikation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210

7.6 Der MPI-Standard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2137.6.1 MPI-1 und MPI-2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2137.6.2 FORTRAN-Schnittstelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2157.6.3 C++-Schnittstelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2167.6.4 Profiling-Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2177.6.5 Dynamische Prozesserzeugung . . . . . . . . . . . . . . . . . . . . . . . . . 2187.6.6 Einseitige Kommunikation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219

7.7 Notizen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220

8 Fortgeschrittene Techniken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2238.1 Kommunikator- und Gruppenmanagement . . . . . . . . . . . . . . . . . . . . . . 223

8.1.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2238.1.2 Undurchsichtige Objekte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2238.1.3 Kommunikatoren kopieren und teilen . . . . . . . . . . . . . . . . . . . 2258.1.4 Prozessgruppen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226

8.2 Fehlerbehandlung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2308.3 Nutzerspezifische Datentypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234

8.3.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2348.3.2 Der Aufbau von MPI-Datentypen . . . . . . . . . . . . . . . . . . . . . . . 2358.3.3 MPI-Funktionen fur nutzerspezifische Datentypen . . . . . . . . . 2368.3.4 Senden und Empfangen von nutzerspezifischen Datentypen . 2388.3.5 Beispiele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240

8.4 Parallele Ein- und Ausgabe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2448.4.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2448.4.2 Definitionen und Konzepte . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2458.4.3 Grundfunktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2468.4.4 Schreib- und Leseoperationen . . . . . . . . . . . . . . . . . . . . . . . . . . 2498.4.5 Fehlerbehandlung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253

8.5 Notizen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256

9 Parallelisierungstechniken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2599.1 Perfekte Parallelisierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259

9.1.1 Peinliche und weniger peinliche Probleme . . . . . . . . . . . . . . . 2599.1.2 Statische Lastverteilung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2609.1.3 Dynamische Lastverteilung, Master-Worker-Schema . . . . . . 2659.1.4 Eine Master-Worker-Bibliothek . . . . . . . . . . . . . . . . . . . . . . . . 2679.1.5 Kombinatorische Probleme . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275

9.2 Geometrische Parallelisierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289

Page 11: [X.systems.press] Cluster Computing ||

Inhaltsverzeichnis XI

9.2.1 Probleme auf Gittern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2899.2.2 Gebietszerlegung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2909.2.3 Schwingende Saite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2919.2.4 Kommunikatoren und Topologien . . . . . . . . . . . . . . . . . . . . . . 2989.2.5 Zellulare Automaten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302

9.3 Notizen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309

Teil IV Praxis

10 Debuggingmethoden und Entwicklungswerkzeuge fur MPI-Programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31310.1 Kontrollausgaben . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31310.2 Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31710.3 Profiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32210.4 XMPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32410.5 Namen fur MPI-Objekte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32810.6 Notizen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330

11 Bibliotheken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33311.1 Uberblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334

11.1.1 Allgemeines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33411.1.2 Lineare Algebra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33511.1.3 Differentialgleichungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33911.1.4 Hydrodynamik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34111.1.5 N-Korperprobleme und Molekulardynamik . . . . . . . . . . . . . . 34211.1.6 Fouriertransformation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34311.1.7 Optimierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34411.1.8 Pseudozufallszahlen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34511.1.9 Visualisierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346

11.2 APPSPACK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34611.2.1 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34611.2.2 Das Thomson-Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34611.2.3 APPSPACK als Bibliothek . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350

11.3 FFTW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35111.3.1 Schnelle Fouriertransformation . . . . . . . . . . . . . . . . . . . . . . . . . 35111.3.2 Eindimensionale Transformationen . . . . . . . . . . . . . . . . . . . . . 35211.3.3 Multidimensionale Transformationen . . . . . . . . . . . . . . . . . . . 35611.3.4 Rucktransformation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356

11.4 Tina’s Random Number Generator Library . . . . . . . . . . . . . . . . . . . . . 35611.4.1 Pseudozufallszahlen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35611.4.2 Die TRNG-Bibliothek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35911.4.3 Selbstvermeidende Zufallswege . . . . . . . . . . . . . . . . . . . . . . . . 361

11.5 Notizen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366

Page 12: [X.systems.press] Cluster Computing ||

XII Inhaltsverzeichnis

12 Benchmarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36712.1 Highly-Parallel LINPACK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367

12.1.1 Algorithmus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36812.1.2 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37212.1.3 Konfiguration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37512.1.4 Optimierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37912.1.5 Ergebnisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380

12.2 Intel MPI Benchmarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38512.2.1 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38512.2.2 MPI-1-Benchmarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387

12.3 Notizen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392

13 Checkpoint-Restart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39313.1 Uberblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393

13.1.1 Anforderungen an Checkpoint-Restart-Systeme . . . . . . . . . . . 39313.1.2 Implementationen von Checkpoint-Restart-Systeme . . . . . . . 395

13.2 Ckpt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39713.3 Berkeley Lab Checkpoint/Restart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401

13.3.1 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40213.3.2 Anwendung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40313.3.3 Checkpointing von Multithread- und MPI-Programmen . . . . 405

13.4 Notizen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408

Teil V Anhang

14 Die C-Schnittstelle des MPI-Standards . . . . . . . . . . . . . . . . . . . . . . . . . . 41114.1 Konstanten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41114.2 MPI-Umgebung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41314.3 Blockierende Punkt-zu-Punkt-Kommunikation . . . . . . . . . . . . . . . . . . 41514.4 Nicht blockierende Punkt-zu-Punkt-Kommunikation . . . . . . . . . . . . . 41714.5 Persistente Kommunikation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42014.6 Abgeleitete Datentypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42014.7 Kollektive Kommunikation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42414.8 Einfache Gruppen, Kontexte und Kommunikatoren . . . . . . . . . . . . . . 43114.9 Kommunikatoren mit Topologie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437

15 Argumente aus der Kommandozeile einlesen . . . . . . . . . . . . . . . . . . . . . 439

Literaturverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443

Sachverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449

Page 13: [X.systems.press] Cluster Computing ||

Teil I

Grundlagen

Page 14: [X.systems.press] Cluster Computing ||

1

Von Megahertz zu Gigaflops

If you were plowing a field, what would you rather use? Twostrong oxen or 1024 chickens?

Seymour Cray (1925–1996)

To pull a bigger wagon, it is easier to add more oxen than togrow a gigantic ox.

W. Gropp, E. Lusk, A. Skjellum [57]

1.1 Ochsen oder Huhner?

Cluster Computing ist alter Wein in neuen Schlauchen. Der ”alte Wein“ heißt paral-leles Rechnen auf Systemen mit verteiltem Speicher und war jahrzehntelang ein eherrandstandiges Gebiet der Computerwissenschaft. Seit den 90er Jahren des letztenJahrhunderts ruckt das parallele Rechnen jedoch mehr und mehr in den Blickpunktvon Anwendern und Computerwissenschaftlern. Daran sind einerseits die ”neuenSchlauche“ in Form preiswerter Hardware (PCs aus der Massenproduktion) und frei-er Software schuld, andererseits erfordern viele Anwendungen in Industrie und For-schung inzwischen Rechenleistungen, die mit keiner anderen Technologie erreichtwerden konnen.

Das klassische Beispiel fur eine Applikation, die den Einsatz von Parallelrech-nern geradezu erzwingt, ist die Wettervorhersage, d. h. die numerische Simulationder Atmosphare1. Dazu wird die Lufthulle diskretisiert und durch ein dreidimen-sionales Gitter reprasentiert. An jedem Punkt des Gitters werden atmospharischeParameter wie Temperatur, Windgeschwindigkeit, Luftdruck usw. berechnet. Auchdie Zeit wird diskretisiert: in einem Zeitschritt werden die Parameter an jedem Git-terpunkt in Abhangigkeit der Parameter der Nachbarpunkte neu berechnet. Fur dieWetterentwicklung in Deutschland ist das Azoren-Hoch genauso wichtig wie dasKontinentalklima in Russland. Darum muss eine verlassliche Wettervorhersage eingroßes Gebiet umfassen, am besten naturlich die ganze Erde. Andererseits sollte dieMaschenweite des verwendeten Gitters moglichst klein sein, um wesentliche atmo-spharischer Prozesse auflosen zu konnen. Beide Forderungen zusammen fuhren zueiner großen Anzahl von Gitterpunkten. Ein Gitter mit einer Maschenweite von 1 km,

1Das folgende Beispiel wurde leicht modifiziert aus [130] ubernommen.

Page 15: [X.systems.press] Cluster Computing ||

4 1 Von Megahertz zu Gigaflops

das die gesamte Erdatmosphare bis in eine Hohe von 20 km darstellt, besteht aus un-gefahr 1010 Gitterpunkten. Die zeitliche Auflosung muss der raumlichen angepasstsein und betragt fur eine Maschenweite von 1 km ungefahr zehn Sekunden. Fur ei-ne dreitagige Wettervorhersage bedeutet das, dass die Parameter an jedem der 1010

Gitterpunkte rund 26 000 mal aktualisiert werden mussen. Nehmen wir an, dass dieAktualisierung eines Gitterpunktes 100 Rechenoperationen erfordert, so ergibt das2,6× 1016 Operationen fur die gesamte Simulation. Ein aktueller PC vom freundli-chen Computerhandler nebenan schafft ungefahr 109 (eine Milliarde!) Rechenopera-tionen pro Sekunde. Damit wurde unsere Wettersimulation 300 Tage benotigen, warealso um einen Faktor 100 langsamer als das wirkliche Wetter draußen vor der Tur.

Mit einem Rechner, der 1012 (eine Billion) Rechenoperationen pro Sekundeschafft, ware unsere globale Drei-Tage-Wettervorhersage in weniger als acht Stun-den machbar. Ein solcher Rechner hatte allerdings ein grundsatzliches Problem. ZumRechnen braucht er Daten, und die konnen bei diesem Tempo nicht mehr schnellgenug herangeschafft werden. Nehmen wir an, dass fur jede Rechenoperation min-destens ein Datenelement aus dem Speicher zur CPU transportiert werden muss. In10−12 Sekunden kann selbst das Licht nur 0,3 mm zurucklegen. Die Laufzeiten wer-den minimiert, wenn man den Speicher auf einer Kreisflache mit Radius 0,3 mmanordnet, in deren Mitte man den Prozessor setzt. Auf dieser Kreisflache mussen wirdie Daten unserer Simulation unterbringen, pro Gitterpunkt also ca. 20 Zahlen furTemperatur, Windgeschwindigkeit etc., jede Zahl hat 32 Bit, macht fur alle 1010 Git-terpunkte 6,4× 1012 Bit. Damit bleibt fur jedes Bit im Speicher eine kreisformigeFlache mit Radius 10−10 m. Das ist der Durchmesser eines Atoms.

Eine Speicherdichte von einem Bit pro Atom ist jenseits aller technischen Mog-lichkeiten. Trotzdem sind Rechner, die mehr als eine Billiarde Rechenoperationenpro Sekunde leisten, heute schon Realitat. Diese Rechner sind allerdings massiv par-allele Systeme, gebaut nach dem Prinzip: wenn die Daten nicht schnell genug zu ei-nem Prozessor kommen konnen, mussen eben viele Prozessoren zu den Daten gehen.Die Grundidee ist einfach. Statt eines Prozessors mit 1012 Operationen pro Sekundenehmen wir 1000 langsamere Prozessoren mit 109 Operationen pro Sekunde. JederProzessor kummert sich um einen kleinen Ausschnitt der Atmosphare, genauer umein Tausendstel oder 107 Gitterpunkte. Bedingt durch die niedrigere Geschwindig-keit der Prozessoren konnen deren Daten jetzt bis zu 300 mm vom Prozessor entferntsein. Dank Arbeitsteilung mussen auf der großeren Speicherflache auch weniger Da-ten untergebracht werden, namlich 6,4× 109 Bit oder 800 MByte. Das gelingt aberselbst mit dem preiswerten PC vom freundlichen Computerhandler um die Ecke.

Derartige Abschatzungen sind naturlich grob vereinfachend und konnen ausvielen Richtungen kritisiert werden. So konnte man das Speicherproblem dadurchentscharfen, dass man die Daten dreidimensional statt nur in der Flache anordnet.Und neue Technologien wie die Quanten-Computer erlauben eines Tages vielleichtauch Speicherdichten von einem Bit pro Atom. In solchen Uberlegungen steckt vielSpekulation. Was heute dagegen sicher ist und in naherer Zukunft richtig bleibenwird, ist dies: Rechenleistungen von mehr als ein paar Billionen Operationen proSekunde konnen nur von parallelen Systemen erbracht werden.

Page 16: [X.systems.press] Cluster Computing ||

1.2 Rechenleistung im Takt 5

Skeptiker wie Seymour Cray hatten bei ihrer Kritik (Zitat auf Seite 3) immer dasProblem vor Augen, massiv parallele Ablaufe zu koordinieren. In der Tat sind Betriebund Nutzung eines massiv parallelen Rechners mit einigem Mehraufwand verbun-den, ein Mehraufwand, der sich zur Glanzzeit der Cray-Supercomputer nicht lohnte.Zu groß war damals der Unterschied zwischen den ”Huhnern“ (billigen Prozessorenfur die Parallelrechner) und den ”Ochsen“ (hochgezuchteten Spezialprozessoren furdie Supercomputer). Zwei Ochsen waren tatsachlich so stark wie 1000 Huhner abereinfacher zu dirigieren. Heute ist der Leistungsunterschied zwischen den preiswer-ten Prozessoren aus der Massenfertigung und teuren Spezialprozessoren dagegen soklein, dass die meisten Supercomputer mit denselben Prozessoren arbeiten wie derPC auf Ihrem Schreibtisch. Aus den Huhnern von damals sind Ochsen geworden.

1.2 Rechenleistung im Takt

Die Leistung eines Rechners lasst sich nicht so einfach angeben wie die Leistungeiner Pumpe, was naturlich daran liegt, dass ein Rechner mehr kann als eine Pumpe.Im technisch-wissenschaftlichen Bereich ist es die Fließkommaleistung, die noch amehesten einer Pumpleistung entspricht. Darunter versteht man die Anzahl der Fließ-kommaoperationen, die ein Rechner pro Sekunde ausfuhren kann. Angegeben wirddiese Leistung in Fließkommaoperationen pro Sekunde (Flops), mit den ublichenVorfaktoren M(ega) (106), G(iga) (109) und T(era) (1012). Fließkommazahlen sinddie Computer-Version der reellen Zahlen und entsprechen in der Programmierspra-che C den Datentypen float und double. Es ist nicht eindeutig definiert, welcheFließkommaoperationen bei einer Leistungsangabe in MFlops berucksichtigt wer-den. Moglich sind neben den elementaren arithmetischen Operationen (Addition,Subtraktion, Multiplikation und Division) auch Zuweisungen, Vergleiche und Typ-Konversionen. Komplexere Funktionen wie die Berechnung der Quadratwurzel oderdes Logarithmus zahlen meist nicht dazu. Bei Prozessoren, die Fließkommaarithme-tik hardwaremaßig unterstutzen, gelten alle Operationen, die im Befehlssatz der FPU(floating point unit) enthalten sind, als Fließkommaoperationen.

Wenn eine Fließkommaoperation vom Prozessor mit einem einzigen Befehl er-ledigt werden kann, sollte die Fließkommaleistung dann nicht der Taktfrequenz desProzessors entsprechen? Also ”GFlops = GHz“? So einfach ist es leider nicht. Be-trachten wir dazu ein einfaches Beispiel, die Summierung der Elemente eines Vek-tors:

#define N 1000000unsigned long l;double a[N], sum=0.0;...for (l=0; l<N; ++l)

sum=sum+a[l];

Der Compiler macht aus diesem Code-Segment eine Liste von Befehlen fur denProzessor. Diese Befehlsliste befindet sich genau wie die Daten im Hauptspeicher

Page 17: [X.systems.press] Cluster Computing ||

6 1 Von Megahertz zu Gigaflops

M

P

Abb. 1.1. Sequentieller Rechner mit Prozessor P und Speicher M.

des Rechners (Abb. 1.1). Der Prozessor selbst verfugt nur uber wenige Speicher-zellen, die sog. Register, und Rechenoperationen kann er nur auf diesen Registernausfuhren. Zum Rechnen muss der Prozessor Befehl und Daten aus dem Speicherholen und in seinen Registern unterbringen. Diese vereinfachte Darstellung heißtdas von-Neumann-Modell eines Rechners. Bei einer einzigen Iteration der Schleifeoben durchlauft der Prozessor dann in etwa diese Schritte:

• Hole nachsten Befehl aus dem Speicher in das Befehlsregister.• Interpretiere diesen Befehl.• Lade erstes Argument (sum) aus dem Speicher in ein Register.• Lade zweites Argument (a[l]) aus dem Speicher in ein anderes Register.• Fuhre den Befehl aus und schreibe Ergebnis in ein drittes Register.• Schreibe das Ergebnis (sum) zuruck in den Speicher.

Sie sehen: selbst die Addition, die der Prozessor mit einem einzigen Befehl ausfuhrenkann, benotigt mehrere Taktzyklen. Ist dann die Fließkommaleistung ein konstanterBruchteil der Taktfrequenz? Auch falsch! Moderne Prozessoren sind wahre Wun-derwerke der Technik. Sie haben fur viele Aufgaben eigene Abteilungen, die un-abhangig voneinander arbeiten konnen. So kann eine Abteilung einen gerade gela-denen Befehl interpretieren, wahrend eine andere Abteilung zur selben Zeit bereitsden nachsten Befehl ladt. Das funktioniert genau wie die Produktion am Fließband,wo an jeder Station eine Teilarbeit erledigt wird. Zu jedem Zeitpunkt befinden sichviele unfertige Produkte auf dem Band, aber mit jedem Weiterrucken des Bandesfallt am Ende ein fertiges Produkt heraus. Bei den Prozessoren heißt das FließbandPipeline, und wenn die Pipeline immer schon voll ist, wird bei jedem Taktzyklusein kompletter Befehl wie sum=sum+a[i] fertig. In diesem Fall ist tatsachlich

”MFlops = MHz“. Die superskalaren Prozessoren haben mehrere Pipelines, so dassin einem einzigen Taktzyklus jede dieser Pipelines ein fertiges Fließkommaresul-tat liefert. Vektorprozessoren verfugen uber spezielle Instruktionen, um eine Fließ-kommaoperationen gleichzeitig auf mehreren ihrer Register durchfuhren zu konnen.Bei superskalaren oder vektoriellen Prozessoren ware die Fließkommaleistung dannsogar ein Vielfaches der Taktfrequenz. Die MFlops-Werte in den Prospekten derHardware-Hersteller stammen oft aus solchen Uberlegungen. Diese sog. peak per-formance (siehe Tabelle 1.1) kann allerdings nur unter optimalen Bedingungen er-reicht werden. In praktischen Anwendungen liegt die Fließkommaleistung zum Teildeutlich darunter.

Page 18: [X.systems.press] Cluster Computing ||

1.3 Von-Neumann-Flaschenhals 7

1.3 Von-Neumann-Flaschenhals

Haupthindernis auf dem Weg zur peak-performance ist der Hauptspeicher. Die ubli-cherweise verwendete Speichertechnologie (DRAM [171], dynamic random accessmemory) erlaubt Zugriffszeiten von ungefahr 10 ns. Das entspricht einer Frequenzvon 100 MHz, also nur einem Bruchteil der Taktfrequenz moderner Prozessoren. InAnlehnung an das von-Neumann-Modell heißt diese Diskrepanz auch von-Neumann-Flaschenhals. Eine treffende Bezeichnung, denn wenn der Prozessor jeden Befehlund jedes Datenelement aus dem Hauptspeicher holen musste, wurde sich sein Takteffektiv auf den Speichertakt reduzieren.

Um die Auswirkungen des von-Neumann-Flaschenhalses zu mindern, schal-tet man zwischen Prozessor und Hauptspeicher einen Zwischenspeicher, den sog.Cache. Der Cache enthalt eine Kopie von Teilen des Hauptspeichers. Er bestehtim Gegensatz zum Hauptspeicher aus SRAM (static random access memory) undermoglicht Zugriffsgeschwindigkeiten, die der Taktfrequenz der Prozessoren nahekommen. Zugriffe auf Daten im Cache verlangsamen die Rechnung also nicht. Da-durch, dass SRAM sehr viel teurer als DRAM ist und der Cache heute meist im Chipdes Prozessors integriert wird, ist die Große des Caches beschrankt. Ublich sind Ca-chegroßen von weniger als einem MByte, bei Spitzen-CPUs wie Intels Itanium 2auch schon mal bis zu 9 MByte. Der Anteil der cache misses, also der Zugriffe aufBefehle und Daten, die nicht im Cache liegen, wird zum bestimmenden Faktor furdie effektive Fließkommaleistung.

Vom Effekt des Caches auf die Fließkommaleistung konnen Sie sich in einemkleinen Experiment selbst uberzeugen. Auf der begleitenden Webseite [7] finden Siedas Programm cachesize.c, welches nichts weiter macht, als die Ausfuhrungs-zeit der Schleife

for (l=0; l<N; ++l)sum=sum+a[l];

fur verschiedene Werte von N zu messen, in MFlops umzurechnen und das Ergebnisauszugeben. Eine ubliche Cache-Strategie ist es, stets die zuletzt benotigten Spei-cherelemente im Cache vorzuhalten. Wenn N also klein genug ist, sind alle Vektor-elemente al spatestens nach dem ersten Durchlauf komplett im Cache. Jeder erneuteSchleifendurchlauf sollte dann weitgehend ohne die teuren Speicherzugriffe auskom-men. Ist N dagegen so groß, dass die Vektorelemente nicht alle in den Cache passen,sollten die nun erforderlichen Zugriffe auf den Hauptspeicher die Rechenleistungvermindern.

Abbildung 1.2 zeigt diesen Effekt deutlich. Gemessen wurde mit cachesize.cauf zwei Rechnern: einem PC mit AMD Athlon Prozessor (1,4 GHz) und einerSun Workstation mit UltraSPARC II Prozessor (300 MHz). Der PC hat einen Ca-che von 256 KByte, bei der Sun Workstation ist der Cache 2 MByte groß. In bei-den Fallen nimmt die effektive Rechenleistung genau bei diesen Werten drastischab, beim PC um den Faktor drei, bei der Workstation sogar um den Faktor vier. DieAbbildung zeigt daruberhinaus, dass auch der Compiler einen erheblichen Einflussauf die Ausnutzung des Caches haben kann. Bei den oberen beiden Kurven wurde

Page 19: [X.systems.press] Cluster Computing ||

8 1 Von Megahertz zu Gigaflops

0

50

100

150

200

250

300

350

400

16384409610242566416

MFl

ops

Vektorlänge in KByte

UltraSparc II, 300 MHzdito, ohne Optimierung

Athlon 1,4 GHzdito, ohne Optimierung

Abb. 1.2. Rechenleistung bei der Aufsummierung von Vektorelementen.

cachesize.c mit allerlei Optimierungs-Optionen des Compilers ubersetzt, beiden unteren Kurven wurde dagegen vollig auf Compiler-Optimierungen verzichtet.

1.4 Benchmarks

In welchem Umfang sich Cachegroße und die Fahigkeiten des Compilers auf dieFließkommaleistung auswirken, hangt stark vom betrachteten Algorithmus und des-sen Implementierung ab. Um trotzdem aussagefahige Leistungsmaße zu erhalten,werden gewohnlich sog. Benchmark-Tests durchgefuhrt. Das sind mehr oder we-niger standardisierte Programme, die unter kontrollierten Bedingungen ubersetztund ausgefuhrt werden. Deren Ausfuhrungszeiten gelten dann als Maß fur die Re-chengeschwindigkeit. Fur die Aussagefahigkeit dieser Methode ist es wichtig, dassdie Benchmark-Programme in ihrer Struktur moglichst den ”typischen“ Anwendun-gen entsprechen. Das kann man auf zweierlei Arten erreichen: entweder mitteltman uber einen ganzen Satz tatsachlicher Anwendungen (Benchmark-Suite), oderman misst zentrale Bausteine, die in sehr vielen Anwendungen vorkommen (Kernel-Benchmark).

Die erste Strategie wird z. B. von der Standard Performance Evaluation Corpora-tion (SPEC) verfolgt, einem Zusammenschluss diverser Hardware-Hersteller [154].Ihr aktueller Benchmark SPEC CFP2000 zur Ermittlung der Fließkommaleistungbesteht aus 14 Programmen (in FORTRAN 77, FORTRAN 90 und C), die realisti-schen Anwendungen aus Bereichen wie Zahlentheorie, Finite Elemente, Crash Si-mulation, numerische Stromungsmechanik, Bildverarbeitung usw. entsprechen. DerSPEC-Benchmark mittelt die Laufzeit uber alle 14 Anwendungen. Das Resultat ist

Page 20: [X.systems.press] Cluster Computing ||

1.4 Benchmarks 9

allerdings kein MFlops-Wert, sondern die Leistung relativ zu einer Referenzmaschi-ne.

Der beruhmteste Vertreter der zweiten Kategorie ist der Linpack-Benchmark[95]. Linpack ist eigentlich eine Sammlung von FORTRAN-Unterprogrammen zurLosung von linearen Gleichungssystemen. Linpack stutzt sich dabei auf BLAS (Ba-sic Linear Algebra Subroutines), einer Sammlung von Unterprogrammen fur die ele-mentaren arithmetischen Operationen der linearen Algebra, also das Matrix-Vektor-Produkt, das Skalarprodukt usw. [90]. Der Linpack-Benchmark misst im Wesentli-chen die Performance dieser Routinen. Das ist naheliegend, denn im technisch-wis-senschaftlichen Umfeld hantieren sehr viele Anwendungen mit Matrizen und Vekto-ren und verbringen einen großen Teil der Laufzeit mit BLAS-artigen Berechnungen.

Im Linpack-Benchmark werden die BLAS-Routinen verwendet, um ein linea-res Gleichungssystem mit dem Gauß’schen Eliminiationsverfahren [136] zu losen.Die Zahl der dazu erforderlichen Fließkommaoperationen ist genau bekannt, d. h.,man kann aus der Laufzeit direkt die Leistung in MFlops ausrechnen. Den Linpack-Benchmark gibt es in drei Versionen, die sich in ihren Regeln unterscheiden:

• Beim 100 × 100 Linpack hat das Gleichungssystem 100 Unbekannte und derQuellcode darf nicht verandert werden. Nur automatische Optimierungen durchden Compiler sind erlaubt.

• Beim 1000×1000 Linpack hat das Gleichungssystem 1000 Unbekannte und derQuellcode darf beliebig verandert werden, allerdings muss sowohl der zugrunde-liegende Algorithmus (Gauß’sches Eliminationsverfahren) als auch die Gesamt-zahl der Fließkommaoperationen bewahrt bleiben.

• Beim High-Performance Linpack gelten die Regeln des 1000× 1000 Linpacks,nur darf jetzt auch die Zahl der Unbekannten gewahlt werden.

Tabelle 1.1. Resultate des 100×100 Linpack mit einfacher Genauigkeit.

CPU Taktfrequenz Peakperf. Linpack

UltraSPARC I 140 MHz 280 MFlops 35 MFlops1

UltraSPARC II 200 MHz 400 MFlops 50 MFlops1

UltraSPARC II 400 MHz 800 MFlops 94 MFlops1

Pentium II 333 MHz 333 MFlops 85 MFlops2

Pentium III 800 MHz 800 MFlops 300 MFlops2

AMD Athlon 1400 MHz 2800 MFlops 635 MFlops2

Pentium M 1600 MHz 3200 MFlops 1100 MFlops3

Pentium 4 2400 MHz 4800 MFlops 820 MFlops2

1320 MFlops4

Xeon 3060 MHz 6120 MFlops 1800 MFlops4

1 Sun Workshop Compiler 5.02 GCC 2.95.4 mit Option -O33 ICC 8.1 mit Optionen -O3 -xB4 ICC 8.1 mit Optionen -O3 -xN

Page 21: [X.systems.press] Cluster Computing ||

10 1 Von Megahertz zu Gigaflops

Der Linpack-Benchmark hat daruberhinaus den Vorteil, dass er frei verfugbar ist.Auf der begleitenden Webseite finden Sie die Datei linpack.c, eine C-Versiondes 100×100-Linpack, bei dem die Große der Matrix allerdings per Kommandozeilemodifiziert werden kann.

Tabelle 1.1 zeigt die Resultate dieses einfachen Linpack-Benchmarks fur eini-ge Prozessoren. Die MFlops-Werte steigen wie erwartet mit der Taktfrequenz an.Die genauen Zahlen hangen von einer ganzen Reihe weiterer Hardware-Parameter(Große des Cache, Taktfrequenz des Speichers), den Fahigkeiten des Compilers undder Große des verwendeten Gleichungssystems ab. Sie sollten sich nicht wundern,wenn Sie bei eigenen Messungen oder in der Literatur abweichende Werte finden.Fur moderne Prozessoren liefert die Gleichung ”GFlops = GHz“ zumindest die richti-ge Großenordnung der Fließkommaleistung. Das zeigt ubrigens auch Jack DongarrasListe [31] der Linpack-Resultate fur mehr als 1000 Ein-Prozessor-Maschinen, vomkleinen Palm Pilot III (1,69 KFlops) bis hin zum Xeon mit 3,2 GHz (5,4 GFlops).

1.5 Amdahls Gesetz

Kann man mit 1000 Prozessoren, die jeweils ein 1 GFlops leisten, in den Bereich desTeraflop-Computings vorstoßen? Im Prinzip ja, aber . . .

Massive Parallelitat hat prinzipielle Beschrankungen, von den technischen Pro-blemen ganz zu schweigen (die besprechen wir spater). Die erste Beschrankung:nicht alle Teile eines Programms lassen sich parallelisieren. Sei σ die Zeit, dieein Programm mit nicht parallelisierbaren Anweisungen verbringt, und sei π dieAusfuhrungszeit der parallelisierbaren Anweisungen. Dann ist die Laufzeit auf ei-nem System mit p Prozessoren gegeben durch

T (p) = σ +πp

, (1.1)

wobei wir idealerweise davon ausgegangen sind sind, dass sich der parallelisierbareAnteil gleichmaßig auf gleich schnelle Prozessoren verteilen lasst. Der Speedup

S(p) =T (1)

T (p)(1.2)

gibt an, um wieviel schneller das Programm durch die Verwendung von p Prozesso-ren im Vergleich zur sequentiellen Ausfuhrung wird. Im Idealfall erreicht man einenlinearen Speedup, S(p) = p. Mit einem relativen Anteil

f =σ

σ +π(1.3)

nicht parallelisierbarer Anweidungen wird daraus jedoch

S(p) =1

f +(1− f )/p≤ 1

f. (1.4)

Page 22: [X.systems.press] Cluster Computing ||

1.5 Amdahls Gesetz 11

Durch massive Parallelitat konnen wir die Ausfuhrungszeit des parallelisierbaren An-teils beliebig klein machen, der sequentielle Anteil bleibt davon aber unberuhrt. Beieinem Anteil von nur 1 % nicht parallelisierbarer Anweisungen ist der maximaleSpeedup gleich 100, egal wieviele Prozessoren wir einsetzen. Dieses Argument wur-de 1967 von Gene Amdahl publiziert [2], und (1.4) heißt seitdem Amdahls Gesetz.Herr Amdahl und nach ihm viele andere zogen daraus den Schluss, dass sich massiveParallelitat nicht lohne.

Der sequentielle Anteil ist noch nicht einmal die einzige Beschrankung paralle-ler Effizienz. In (1.1) sind wir davon ausgegangen, dass sich der parallelisierbareAnteil eines sequentiellen Programms vollig verlustlos auf p Prozessoren verteilenlasst. In der Regel mussen die Prozessoren ihre Arbeit aber irgendwie koordinieren.Das geschieht durch den Austausch von Daten, was erstens Zeit kostet und zweitensdazu fuhrt, dass Prozessoren u. U. nicht weiterarbeiten konnen, weil sie auf das Zwi-schenergebnis eines anderen Prozessors warten. Eine weitere Quelle von Reibungs-verlusten ist eine unausgewogene Lastverteilung: einige Prozessoren erledigen ihreTeilaufgaben u. U. schneller als andere und warten dann untatig bis zum Ende dergesamten Rechnung. Auch die Verwaltung der Teilaufgaben selbst kann Zeit kosten,die mit der eigentlichen Problembearbeitung nichts zu tun hat. Wir subsumieren al-le diese Effekte in einer zusatzlichen, durch die Parallelisierung bedingten LaufzeitTc(p). Aus (1.1) wird so

T (p) = σ +πp

+Tc(p) . (1.5)

Im Allgemeinen wird Tc(p) monoton mit der Zahl der Prozessoren ansteigen, wasjeder, der Erfahrung mit Teamarbeit hat, sofort einsieht. Nehmen wir der Einfachheithalber an, dass die Prozessoren immer gleichmaßig ausgelastet sind und Tc(p) nurvon der Zeit fur die Kommunikation zwischen den Prozessoren bestimmt wird. Wirwerden spater noch sehen, dass das in vielen Fallen eine recht gute Annahme ist. Ineinem typischen Szenario paralleler Anwendungen (Abschnitt 9.1.3) kontrolliert einProzess (der Master) alle anderen (die Worker). Kommunikation findet nur zwischenMaster und Worker statt, niemals zwischen Workern. Dann sollte Tc(p) eine lineareFunktion von p sein:

Tc(p) = Tc(2)(p−1) . (1.6)

Ein Prozessor allein fuhrt keine Selbstgesprache, also ist Tc(2) die minimale Zeit, dieKommunikation uberhaupt kosten kann. Aus unserem Speedup wird jetzt

S(p) =1

f − r +(1− f )/p+ rp, (1.7)

wobei

r =Tc(2)

T (1)(1.8)

das Verhaltnis zwischen der minimalen Kommunikationszeit und der sequentiellenRechenzeit angibt.

Durch die Berucksichtigung der Kommunikationskosten fallt der Speedup furgroße Werte von p jetzt sogar ab (Abb. 1.3), d. h., massive Parallelitat kann kontra-produktiv sein. Der Speedup erreicht sein Maximum

Page 23: [X.systems.press] Cluster Computing ||

12 1 Von Megahertz zu Gigaflops

1

10

100

1 10 100 1000 10000

Spee

dup

S

idealAmdahlAmdahl mit Kommunikation

1,0

0,8

0,6

0,4

0,2

0,0 1 10 100 1000 10000

Eff

izie

nzε

Zahl der Prozessoren p

Abb. 1.3. Speedup und Effizienz paralleler Programme gemaß Amdahls Gesetz (mit f =0,005) und bei zusatzlicher Berucksichtigung eines linearen Kommunikationsaufwandes (mitr = 0,0001).

S(p∗) =1

f − r +2√

(1− f )r(1.9)

bei

p∗ =

√1− f

r. (1.10)

Nur fur p � p∗ ist S(p) = p, d. h. nur in diesem Bereich zahlt sich Parallelitat aus.Ein vom Speedup S(p) abgeleitetes Maß fur die Gute einer parallelen Anwen-

dung ist die Effizienz

ε(p) =T (1)

pT (p)=

S(p)

p. (1.11)

Sie gibt den Anteil der Zeit an, die jeder Prozessor mit nutzlicher Arbeit verbringt.Ein Wert von ε(100) = 0,40 wie im Beispiel der Abb. 1.3 bedeutet, dass jeder der 100Prozesse 60 % der Zeit damit verbringt, auf Daten von anderen Prozesse zu wartenoder Daten zu verschicken. Ideal ist naturlich eine Effizienz ε(p) = 1, aber sequenti-eller Anteil und Kommunikationsverluste sorgen fur einen Abfall fur großere Wertevon p (siehe Abb. 1.3 unten).

Page 24: [X.systems.press] Cluster Computing ||

1.6 Granularitat 13

Listing 1.1. Die Funktion pintegral in pintegral.c berechnet Partialsummen fur dieparallele numerische Integration.

/ * b e r e c h n e t I n t e g r a l u be r f von a b i s b mi t M i t t e l p u n k t s r e g e l an nS t u t z s t e l l e n . L i e f e r t d i e k−t e P a r t i a l s u m m e (0<=k<t a s k s ) zu r u ck . * /

double pintegral(double (*f)(double), double a, double b,long n, int k, int tasks) {

double result=0.0;double h=(b-a)/n;long l;a=a+h/2;for (l=k; l<n; l+=tasks)

result+=f(a+l*h);return h*result;

}

1.6 Granularitat

Stellen Sie sich einen Maler vor, der fur das Tapezieren eines Zimmers eine Stundebenotigt. Dass zwei Maler dieses Zimmer in einer halben Stunde schaffen, ist nichtunplausibel. Kein Mensch kame jedoch auf die Idee, dass 60 Maler ein Zimmer ineiner Minute tapezieren konnten. Sie wurden sich derart im Weg stehen oder umdie wenigen Ressourcen (Tapeziertisch, Leiter) streiten, dass sie vermutlich sogarlanger als eine Stunde brauchten. Diese Alltagsversion des Amdahl’schen Gesetzesverdeutlicht den Schwachpunkt der zugrundeliegenden Pramisse, mit immer mehrProzessoren ein gegebenes Problem immer schneller losen zu wollen. Mit 60 Malernlasst sich ein einzelnes Zimmer nicht 60 mal so schnell tapezieren, wohl aber einHotel mit 60 Zimmern. Dazu muss man nur die Maler gleichmaßig auf die Zimmerdes Hotels verteilen. Auf Parallelrechner ubertragen heißt das, dass mit zunehmen-der Zahl von Prozessoren auch die Problemgroße wachsen sollte, um ein effizientesArbeiten zu gewahrleisten. Man sagt, dass Problem muss mit der Zahl der Prozes-soren skalieren. Diese Erkenntnis erscheint banal, und doch setzte sie sich in derInformatik erst 1988 durch, 21 Jahre nach Amdahls Gesetz (Notiz 1.8)2.

Betrachten wir als Beispiel die numerische Integration. Dabei wird das Integraleiner Funktion f dadurch berechnet, dass man f an n Stutzstellen xi im Integrations-intervall [a,b] auswertet. In der primitivsten Version (Mittelpunktsregel) wahlt manaquidistante Stutzstellen im Abstand h = (b− a)/n und approximiert das Integraldurch ∫ b

af (x)dx ≈ h ·

n−1

∑i=0

f (xi) mit xi = a+

(i+

12

)h . (1.12)

Die Approximation ist naturlich umso genauer, je großer n ist.Mit der Funktion pintegral (Listing 1.1) konnen wir die Integration parallel

auf p Prozessoren durchfuhren lassen (Abb. 1.4). Dazu nummerieren wir die Prozes-soren von 0 bis p−1 und lassen den k-ten Prozessor den Wert

2Am Ende eines jeden Kapitels finden Sie einige Notizen und Hinweise, die unserwahnenswert erschienen, die aber im laufenden Text leider keinen Platz fanden.

Page 25: [X.systems.press] Cluster Computing ||

14 1 Von Megahertz zu Gigaflops

f(x)

a bx

Prozess 2Prozess 1Prozess 0

Abb. 1.4. Parallele numerische Integration mit drei Prozessoren.

mysum=pintegral(f, a, b, n, k, P);

ausrechnen. Danach mussen die Teilsummen mysum der einzelnen Prozessoren nurnoch addiert werden. Wir werden in Kapitel 3 sehen, wie man das praktisch macht.

Der parallelisierbare Anteil diese Verfahrens (die Berechnung der Teilsummen)wachst linear mit n, wahrend der sequentielle Anteil (Berechnung von h etc.) un-abhangig ist von n. Der relative Anteil der nicht parallelisierbaren Anweisungenist daher proportional zu 1/n, nimmt also mit wachsender Problemgroße ab. DerKommunikationsaufwand ist auch unabhangig von der Problemgroße, denn am Endehat jeder Prozessor nur seine Teilsumme, d. h. eine einzige Zahl zu versenden. Alsonimmt auch der relative Parallelisierungsverlust mit zunehmender Problemgroße ab.Solange also p � n ist, konnen wir einen idealen Speedup S(p) ≈ p erwarten.

Parallele Algorithmen sollten so organisiert sein, dass der relative Anteil derinharent sequentiellen Anweisungen und der durch die Parallelisierung erforderli-chen Synchronisations- und Kommunikationszeiten mit wachsender Problemgroßeabnimmt. Die inharent sequentiellen Teile eines Algorithmus erfullen diese Bedin-gung in den meisten Fallen automatisch. Synchronisation und Kommunikation ska-lierbar zu gestalten, ist in der Regel etwas schwieriger.

Betrachten wir unter diesem Gesichtspunkt das Eingangsbeispiel, die Klimasi-mulation. In der parallelen Variante hatten wir jedem Prozessor eine Teilmenge derGitterpunkte zugeordnet. Um die erforderliche Kommunikation zwischen den Pro-zessoren moglichst gering zu halten, sollten die Gitterpunkte eines Prozessors allebenachbart sein. Dann kann jeder Prozessor fast alle Gitterpunkte seines Bereichesaktualisieren, ohne auf die Daten anderer Prozessoren angewiesen zu sein. Nur furdie Neuberechnung der Punkte, die am Rand seines Gebietes liegen, muss ein Pro-zessor Daten mit anderen austauschen. Der Kommunikationsaufwand wachst daherwie die Oberflache aneinander angrenzender Teilvolumina (Abb. 1.5). Bei einemd-dimensionalen Gitter mit Maschenweite ∆ also wie ∆−(d−1). Der Rechenaufwandwachst dagegen wie ∆−d , d. h., der relative Anteil der Kommunikation skaliert wie ∆ .Je feinmaschiger das Diskretisierungsgitter, umso weniger fallt der Datenaustauschder Prozessoren ins Gewicht. Dieser angenehme Oberflachen-versus-Volumen-Effekt

Page 26: [X.systems.press] Cluster Computing ||

1.6 Granularitat 15

Abb. 1.5. Beim Ubergang von einem groben (links) zu einem feinen Gitter (rechts) steigt dieRechenlast (Faktor vier) schneller als der Kommunikationsaufwand (Faktor zwei). Probleme,die sich auf Gittern mit lokalen Datenflussen abbilden lassen, eignen sich deshalb hervorra-gend fur Parallelrechner.

tritt bei allen Problemen auf, die sich auf Gitter mit lokalen Datenflussen abbilden las-sen, und das sind eine ganze Menge, sehr wichtiger Probleme (siehe Abschnitt 9.2.1).

Wann ist das Gitter groß genug fur eine effiziente Behandlung auf einem Parallel-rechner mit p Prozessoren? Offensichtlich dann, wenn ein Prozessor lange (nutzlich)rechnen kann, bevor er auf einen Datenaustausch angewiesen ist. Man nennt die An-zahl der Rechenschritte, die von einem Prozessor zwischen zwei Kommunikations-vorgangen ausgefuhrt werden kann, Granularitat oder Kornigkeit. Wunschenswertist eine grobe Kornigkeit. Feingranulare Programme verbringen zu viel Zeit mit derKommunikation und fuhren schnell auf den absteigenden Ast der Speedup-KurveS(p). Die Situation gleicht dem von-Neumann-Flaschenhals. Dieser fuhrt zu Leis-tungseinbußen bei Zugriff auf den langsamen Hauptspeicher, eine feine Granularitatfuhrt zu Verlusten bei Zugriffen auf die Daten anderer Prozessoren.

Da die Granularitat einen erheblichen Einfluss auf die Effizienz paralleler Pro-gramme hat, ist es vorteilhaft, wenn man sie leicht verandern und damit den Gege-benheiten anpassen kann. Bei der Klimamodellierung gelingt das durch die Wahlder Maschenweite des Gitters. Beim Losen linearer Gleichungssysteme ist es dieAnzahl der Unbekannten, die sich positiv auf die Granularitat auswirkt. Deshalbdarf bei der HPC-Variante des Linpack-Benchmarks die Zahl der Unbekannten be-liebig gewahlt werden. Die Details des parallelisierten Gauß’schen Eliminationsver-fahrens sind kompliziert, aber es ist ganz offensichtlich unvernunftig, ein Systemmit nur 1000 Unbekannten auf einem Parallelrechner mit mehreren tausend Prozes-soren losen zu wollen. Mit 32768 Prozessoren wahlt man z. B. ein Gleichungssys-tem mit rund einer Million Unbekannten. Damit erreicht man im HPC-Linpack dann70 720 GFlops und den ersten Platz in der Liste der 500 schnellsten Computer derWelt (Stand: November 2004, siehe [166]).

Page 27: [X.systems.press] Cluster Computing ||

16 1 Von Megahertz zu Gigaflops

)f p

pf )/

sequentiell

parallel (1 −

(1 −1 − f

1 − f

f f

f f

Abb. 1.6. Die Lange der Balken entspricht der Laufzeit, der Speedup ist das Verhaltnis derLangen. Amdahls Sichtweise (links) bzw. skalierter Speedup nach Gustafson (rechts).

1.7 Parallele Leistungsmetriken

Amdahls Gesetz beruht auf dem Ansatz, ein Problem fester Große durch Paralleli-sierung schneller zu losen. Die Betrachtungen des letzten Abschnitts haben dage-gen gezeigt, dass man mit zunehmender Parallelisierung eher großere Probleme beigleichbleibender Laufzeit lost.

Ein einfacher Ansatz, der dies berucksichtigt, verwendet die parallele Laufzeitals Basisgroße und vergleicht diese mit der Laufzeit auf einem sequentiellen Rechner.Bei Amdahls Gesetz ist es genau umgekehrt (Abb. 1.6). Sei also T (p) die Laufzeitauf einem parallelen Systems mit p Prozessoren. Ein Anteil f dieser Laufzeit werdedabei mit inharent sequentiellem Code verbracht. Die entsprechende Laufzeit aufeinem sequentiellen Rechner ware daher T (1) = f T (p)+ p(1− f )T (p), und fur denSpeedup S(p) = T (1)/T (p) ergibt sich

S(p) = f + p(1− f ) = p+(1− p) f . (1.13)

Gleichung (1.13) heißt Gustafsons Gesetz [60], der so definierte Speedup heißt ska-lierter Speedup. Der Unterschied zwischen unskaliertem (1.4) und skaliertem Spee-dup (1.13) ist offensichtlich. Bei gegebener Problemgroße (d. h. bei gegebener Lauf-zeit auf einem sequentiellen Rechner) konnen wir die Laufzeit des parallelisierba-ren Anteils durch viele Prozessoren quasi auf Null reduzieren, behalten aber denunvermeidbaren sequentiellen Anteil. Bei gegebener skalierter Problemgroße (d. h.bei gegebener Laufzeit auf einem Parallelrechner) steigt die hypothetische Laufzeitauf einem sequentiellen Rechner dagegen linear mit p an. Die sequentielle Laufzeitist dabei hypothetisch, weil das skalierte Problem durchaus so groß sein kann, dasses auf einem sequentiellen Rechner gar nicht mehr ausfuhrbar ist, wie das Problemder globalen Wettervorhersage aus dem Eingangskapitel zeigt.

Gustafsons Gesetz vernachlassigt genau wie Amdahls Gesetz den Overhead, derdurch die Parallelisierung ins Spiel kommt. Der skalierte Speedup ist daher als Leis-tungsmetrik nur bedingt aussagefahig. Besser geeignet ist die Karp-Flatt-Metrik [77].Deren zentrale Idee ist es, den Speedup S(p) = T (1)/T (p) fur mehrere Werte von pexperimentell zu bestimmen. Das nach f aufgeloste Amdahlsche Gesetz

f =1/S(p)−1/p

1−1/p(1.14)

erlaubt dann die Berechnung des empirischen sequentiellen Anteils f . Das ist dieKarp-Flatt-Metrik. Wenn (wie in Amdahls Gesetz angenommen) die Verluste durch

Page 28: [X.systems.press] Cluster Computing ||

1.7 Parallele Leistungsmetriken 17

Kommunikation und ungleiche Lastverteilung keine Rolle spielen, sollte f unab-hangig von p sein. Ein paralleler Overhead fuhrt dazu, dass S(p) mit wachsendem plangsamer als von Amdahls Gesetz vorhergesagt zunimmt. Das empirische f wird indiesem Fall mit p zunehmen. Die Karp-Flatt-Metrik zeigt also an, ob die Effizienzeines parallelen Programms durch den inharent sequentiellen Anteil oder durch dieparallelen Reibungsverluste dominiert wird. Aus der genauen Abhangigkeit der Karp-Flatt-Metrik von der Anzahl der Prozessoren kann man weitergehende Schlusse zie-hen, z. B. ob die Effizienz von einer ungleichen Lastverteilung limitiert wird oder vonden Verlusten, die durch die Kommunikation verursacht werden. In Abschnitt 7.3werden wir die Karp-Flatt-Metrik am Beispiel der parallelen numerischen Integrati-on diskutieren.

Im Allgemeinen wird die Effizienz (1.11) einer parallelen Anwendung mit wach-sender Anzahl p von Prozessoren abnehmen, mit steigender Problemgroße n dage-gen zunehmen. Die Isoeffizienz-Funktion [55] gibt an, wie stark die Problemgroßewachsen muss, um bei zunehmendem Parallelisierungsgrad die Effizienz konstant zuhalten. Ausgangspunkt ist (1.5), wobei wir jetzt auch die Abhangigkeit aller Zeitenvon der Problemgroße n berucksichtigen:

T (n, p) = σ(n)+π(n)

p+Tc(n, p) . (1.15)

Die Effizienz ε(n, p) = T (n,1)/(pT (n, p)) lasst sich dann mit

T0(n, p) = (p−1)σ(n)+ pTc(n, p) (1.16)

als

ε(n, p) =σ(n)+π(n)

pσ(n)+π(n)+ pTc(n, p)=

σ(n)+π(n)

σ(n)+π(n)+T0(n, p)(1.17)

schreiben. T0(n, p) ist die Summe aller Zeiten, die die Prozessoren mit Arbeit verbrin-gen, die im sequentiellen Ablauf nicht vorhanden ware. Der erste Term in T0(n, p)steht fur die redundante Ausfuhrung des sequentiellen Codes auf mehr als einemProzessor bzw. die Zeit des Wartens, bis ein Prozessor diesen Code ausgefuhrt hat.Der zweite Term fasst die globalen Verluste durch Kommunikation und ungleicheLastverteilung zusammen. Berucksichtigt man nun noch, dass

T (n,1) = σ(n)+π(n) (1.18)

die sequentielle Laufzeit als Funktion von n angibt, so folgt aus (1.17)

T (n,1) =ε(n, p)

1− ε(n, p)T0(n, p) . (1.19)

Konstante Effizienz ε(n, p) bedeutet

T (n,1) = C T0(n, p) , (1.20)

Page 29: [X.systems.press] Cluster Computing ||

18 1 Von Megahertz zu Gigaflops

d. h., die Problemgroße n muss (mindestens) so schnell wachsen, dass die sequentiel-le Laufzeit genauso schnell wachst wie die Gesamtlaufzeit des parallelen Overheads.Gleichung (1.20) ist die Isoeffizienz-Funktion.

Betrachten wir dazu das Beispiel der numerischen Wettervorhersage. Hier ist ndie Anzahl der Gitterpunkte und T (n,1) ∝ n. Jeder Prozessor verwaltet ein Teilgit-ter aus n/p Gitterpunkten, dessen Oberflache (n/p)2/3 Gitterpunkte enthalt. Diesemussen bei jeder Iteration mit den Prozessoren ausgetauscht werden, die die sechsbenachbarten Teilgitter verwalten. Das fuhrt zu T0(n, p) ∼ p(n/p)2/3, wobei wir an-genommen haben, dass der inharent sequentielle Teil σ von n unabhangig und damitfur große n vernachlassigbar ist. Die Isoeffizienz-Relation ergibt in diesem Fall n∼ p.Um die Effizienz zu erhalten, sollte darum bei einer Verdoppelung der Prozessorzahlauch die Anzahl der Gitterpunkte verdoppelt werden.

1.8 Notizen

1.1 Wettervorhersage. Unsere Uberlegungen zur numerischen Wettervorhersagesind nur eine Karikatur der Verfahren, mit denen der tagliche Wetterbericht erstelltwird. Der Deutsche Wetterdienst benutzt zum Beispiel mehrere Modelle. Beim globa-len Modell betragt die Maschenweite 60 km. Darin eingebettet ist das lokale Modell,das mit einer Maschenweite von 7 km Mitteleuropa abdeckt. Eine 48-stundige Wet-tervorhersage fur das lokale Modell (325× 325 Gitter in 35 vertikalen Schichten,Zeitauflosung 40 Sekunden) kann auf einer IBM RS/6000 SP mit 160 Prozessorenin weniger als einer Stunde erstellt werden [26].

1.2 Grand Challenges. Die hochauflosende, globale Wettersimulation ist nur einevon vielen großen Herausforderungen (grand challenges) die den Einsatz massivparalleler Rechnersysteme erfordern. Weitere Beispiele sind die Proteinfaltung, dernumerische Windkanal oder die Genom-Analyse. Eine etwas angestaubte, aber nochimmer lesenwerte Darstellung einiger grand challenges finden Sie in [78]. Der Be-griff ”Grand Challenge“ wurde 1989 von K. G. Wilson gepragt [173]. In der Phy-sik zahlen die Quantenchromodynamik und die Simulation der Kollision schwarzerLocher zu den großen Herausforderungen. Fur letztere betragt der Rechenaufwandetwa 1017 Fließkommaoperationen pro Simulation [5], d. h. mehr als drei Jahre aufeinem 1 GFlops-Rechner, weniger als zwei Tage auf einem 1 TFlops-Rechner.

1.3 Google. Nicht nur die klassischen numerischen Probleme erfordern massiv par-allele Rechner. Eine einzige Anfrage bei der Suchmaschine Google erfordert dieVerarbeitung von mehreren 100 MByte an Daten und mehr als 10 Milliarden Rechen-operationen. In Spitzenzeiten wickelt Google tausende Anfragen pro Sekunde ab,jede davon in erstaunlich kurzer Zeit, wie wir alle wissen. Die dafur benotigte Re-chenleistung bezieht Google keineswegs aus einem oder wenigen Supercomputern,sondern aus sehr vielen (mehr als 15 000) Standard-PCs, die in geografischen undfunktionalen Clustern organisiert sind [6].

Page 30: [X.systems.press] Cluster Computing ||

1.8 Notizen 19

1.4 Das Moore’sche Gesetz. Im Jahre 1964 bemerkte der Halbleiter-Ingenieur Gor-don Moore, dass sich die Packungsdichte der Schaltelemente auf Silizium-Chips je-des Jahr verdoppelt. Die Datenbasis, aus der Moore diesen Schluss zog, bestand ausnur sieben Datenpunkten, aber seine Hypothese, inzwischen als Moore’sches Gesetzbekannt, blieb auch in den folgenden Jahren gultig. Gordon Moore grundete im Jahre1968 die Firma Intel, die maßgeblich dazu beitrug, dass seine Hypothese bis heutewahr blieb. Ende der siebziger Jahre verlangsamte sich der Fortschritt etwas, dennseitdem verdoppelt sich die Packungsdichte ”nur noch“ alle 18 Monate. Extrapoliertman die gegenwartige Rate, so wurde ca. im Jahr 2020 jedes Schaltelement aus nurnoch einem einzigen Atom bestehen. Die Geschwindigkeit der Prozessoren zeigt ei-ne vergleichbare exponentielle Wachstumsrate. Die Zugriffszeiten der Speicherbau-steine halbieren sich dagegen nur alle sieben Jahre, was den von-Neumann-Flaschen-hals immer enger werden lasst.

1.5 Linpack. Die Optimierungsfahigkeiten des Compilers haben einen erheblichenEinfluss auf die Ergebnisse. Fur die Messungen auf Pentium- bzw. AMD-Systemenhaben wir den gcc, Version 2.95 verwendet. Auf den Suns kam der Sun WorkshopCompiler Version 5.0 zum Einsatz. Lasst man die Optimierungs-Optionen einfachweg, erhalt man deutlich schlechtere Resultate, z. B. 187 MFlops statt 752 MFlopsfur den Athlon-Prozessor. Auf einer Sun unter Solaris gibt Ihnen das Programmfpversion ubrigens nicht nur interessante Informationen uber die Cachegroße,den CPU- und den Speichertakt, sondern auch die Compiler-Optionen fur eine opti-male Ausnutzung des Caches.

1.6 HPC Challenge. Neben dem Linpack gibt es eine ganze Reihe von weiterenBenchmarks die fur numerischen Rechnungen interessant sind. Jack Dongarra, ei-ner der ”Vater“ des Linpack-Benchmarks und der Top-500 Liste der schnellstenComputer der Welt [166], hat einige davon in einer High Performance ComputingBenchmark-Suite zusammengefasst. Darin enthalten sind nebem dem Linpack z. B.auch Benchmarks, die explizit die Speicherzugriffszeit ausmessen oder die die Ge-schwindigkeit des Datentransfers in Verbindungsnetzwerken von Parallelrechnernermitteln. Der HPC Challenge ist frei erhaltlich, siehe [67].

1.7 Code-Effizienz. Effizienten Code zu schreiben, ist schon fur sequentielle An-wendungen eine hohe Kunst. Falls Sie diese Kunst erlernen mochten, sollten Sie dasBuch von Kevin Dowd und Charles R. Severance [32] studieren. Darin und im Web[8] finden Sie auch eine ausfuhrliche Diskussion verschiedener Benchmarks.

1.8 Amdahls Gesetz. Ganze 21 Jahre lang wurden massiv parallele Systeme durchAmdahls Gesetz in eine unbedeutende Nische verbannt. Dann zeigten Gustafson,Montry und Brenner [61], dass man auf einem Parallelrechner mit 1024 Prozesso-ren fur eine ganze Reihe von Anwendungen, wenn man die Probleme nur groß ge-nug macht, einen Speedup von uber 1000 erreicht. Dafur erhielten die Autoren denGordon-Bell-Award 1987. Gustafson schreibt dazu [60]: ”We feel that it is import-ant for the computing research community to overcome the ‘mental block’ againstmassive parallelism imposed by a misuse of Amdahl’s speedup formula . . .“.

Page 31: [X.systems.press] Cluster Computing ||

20 1 Von Megahertz zu Gigaflops

1.9 Superlinearer Speedup. Ein superlinearer Speedup S(p) > p bzw. eine Effizienzε(p) > 1 sind theoretisch nicht moglich. Praktisch misst man so etwas gelegentlichdoch. Ursache dafur ist meistens der Cache: wenn durch Parallelisierung die Da-tenmenge pro Prozessor kleiner wird (wie bei der Wettersimulation), passen immergroßere Teile davon in den Cache, was die Ausfuhrungszeit auf den einzelnen Pro-zessoren beschleunigt. Wenn dieser Effekt nicht durch die Kommunikationsverlusteaufgefressen wird, erhalt man einen superlinearen Speedup.

Page 32: [X.systems.press] Cluster Computing ||

2

Parallelrechner

Die Supercomputer von heute sind zu langsam fur dieWissenschaft von morgen, und das trotz der rasantentechnischen Entwicklung.

Thomas Sterling [157]

If you have a big problem to solve, recruiting a few percent ofthe CPUs on the Net would gain you more raw power thanany supercomputer on earth.

Brian Hayes [66]

2.1 Gemeinsamer oder verteilter Speicher

Auf der Abstraktionsebene des von-Neumann-Modells besteht ein sequentieller Rech-ner aus einem Prozessor und einem Speicher. Bei Parallelrechnern gibt es auf dieserAbstraktionsebene zwei grundsatzlich verschiedene Varianten: Bei Systemen mit ge-meinsamem Speicher teilen sich alle Prozessoren einen Speicher, bei Systemen mitverteiltem Speicher verfugt jeder Prozessor uber einen separaten, nur ihm zugeord-neten Speicher. In beiden Fallen mussen die Prozessoren naturlich in der Lage sein,Daten miteinander auszutauschen. Im ersten Fall geht das uber die Daten im gemein-samen Speicher, im zweiten Fall ist ein Verbindungsnetzwerk erforderlich.

Bei Rechnern mit gemeinsamem Speicher (shared memory) stellen mehrere Spei-chermodule einen einheitlichen Adressraum dar, auf den alle Prozessoren zugreifenkonnen (Abb. 2.1). Der Zugriff auf die Speichermodule erfolgt uber einen sog. Inter-connect. Rechner mit gemeinsamem Speicher werden Multiprozessoren genannt.

Die Probleme des von-Neumann-Flaschenhalses gewinnen bei Multiprozessorenan Gewicht, denn die Speicherzugriffe mussen jetzt zusatzlich zwischen mehrerenProzessoren koordiniert werden. Gleichzeitige Schreibzugriffe mehrerer Prozesso-ren auf ein Speicherelement mussen entweder verhindert oder durch ein geeignetesProtokoll konsistent gregelt werden. Ein weiteres Problem ist die Koharenz der Pro-zessor-Caches. Wenn eine Speicherzelle in mehreren Caches dupliziert wurde, mussjede Veranderung dieser Zelle in einem Cache sofort an alle anderen weitergereichtwerden.

Trotz dieser Schwierigkeiten bleibt die Geschwindigkeit des Speicherzugriffsfur eine einzelne Transaktion bei Multiprozessoren in der gleichen Großenordnungwie bei Einprozessorsystemen, und dieselbe Geschwindigkeit gilt naherungswei-

Page 33: [X.systems.press] Cluster Computing ||

22 2 Parallelrechner

M M

P P P

MM

PP

Interconnect

Speichermodule

Prozessoren

Abb. 2.1. Parallelrechner mit gemeinsamem Speicher (shared memory). Abstraktes Modell(oben) und realer Rechner (unten, Dual-Prozessor Board der Firma Gigabyte mit zwei IntelPIII Prozessoren).

se auch fur den Datenaustausch zwischen den Prozessoren. Mit speziellen Cache-Koharenz-Protokollen kann auch bei der Verwendung gemeinsamer Daten der Haupt-speicher umgangen werden. Die Geschwindigkeit der Interprozessorkommunikationentspricht dann im gunstigsten Fall der Geschwindigkeit des Cache-Zugriffs. Damiteignen sich Multiprozessoren auch fur feingranulare Probleme.

Eine besondere Variante von Rechnern mit gemeinsamem Speicher sind die sym-metrischen Multiprozessoren, kurz SMP genannt. Das sind Maschinen, in denen alleProzessoren die gleiche Sicht auf das Gesamtsystem haben, d. h. insbesondere mitgleicher Geschwindigkeit auf den Speicher zugreifen. In preiswerten SMPs ist derInterconnect ein Bus. Hier kann zu jedem Zeitpunkt nur einer der Prozessoren aufden Speicher zugreifen. Die Dual- und Quad-Prozessor-Systeme im PC-Bereich sindbusbasierte SMPs. Teurere Multiprozessor-Maschinen verwenden einen Crossbar alsInterconnect. Dieser erlaubt zu jedem Zeitpunkt mehreren Prozessoren den Zugriffauf den Speicher, solange nicht zwei CPUs gleichzeitig auf dasselbe Speichermodulzugreifen. Ist die Zugriffsgeschwindigkeit dabei unabhangig vom Speichermodul, sospricht man von uniform memory access (UMA). Im Gegensatz dazu hangt beimnon uniform memory access (NUMA) die Zugriffsgeschwindigkeit vom Speicher-modul ab. Ublicherweise werden in NUMA-Systemen die Module einzelnen CPUszugeordnet, so dass jede CPU auf ”ihre“ Module schneller zugreifen kann als auf die

Page 34: [X.systems.press] Cluster Computing ||

2.1 Gemeinsamer oder verteilter Speicher 23

P

M

P

M

P

M

P

M

Interconnect

Knoten

Abb. 2.2. Parallelrechner mit verteiltem Speicher (distributed memory).

Module der anderen CPUs. Die Dual-Opteron Boards der Firma AMD sind Beispielefur NUMA-Systeme.

Multitasking-Betriebssysteme wie Unix verteilen per definitionem mehrere Pro-zesse auf einer CPU. Dank der homogenen Struktur der SMP-Architektur bedarfes keines großen Aufwands, diese Verteilung auf mehrere Prozessoren auszudeh-nen. Folglich unterstutzt Linux ebenso wie die meisten kommerziellen Unix-Varian-ten das symmetrische Multiprocessing. SMP-Maschinen bieten so einen insgesamthoheren Durchsatz, auch wenn die einzelnen Anwendungen ganz gewohnliche se-quentielle Programme sind.

Der ungebremste Zugriff auf den gemeinsamen Speicher (und andere gemein-sam genutzte Komponenten) erfordert eine aufwandige Elektronik, und der Aufwandsteigt schnell mit der Anzahl der Prozessoren. Ein PC mit vier Prozessoren kostetdeutlich mehr als vier PCs mit je einem Prozessor, bei sonst gleicher Ausstattung.SMP-Maschinen enthalten daher selten mehr als 64 Prozessoren, und Systeme die-ser Großenordnung sind sehr teuer. Multiprozessoren kommen deshalb fur massivparallele Anwenungen nicht in Frage.

Viel mehr Prozessoren kann man miteinander verbinden, wenn man auf den ge-meinsamen Speicher verzichtet. Bei Systemen mit verteiltem Speicher (distributedmemory), kann jeder Prozessor nur auf seinen eigenen, lokalen Speicher zugreifen.Die Kommunikation zwischen den Prozessoren erfolgt uber ein Verbindungsnetz-werk (Abb. 2.2). Der Datentransport uber Verbindungsnetzwerke ist in der Regel viellangsamer als der Datentransport zwischen CPU und Speicher. Das Missverhaltniszwischen Kommunikations- und Rechenleistung ist deshalb in verteilten Systemenbesonders hoch, was diese Systeme fur feingranulare Parallelisierungen ineffizientmacht. Je ein Prozessor und sein lokaler Speicher bilden einen Knoten des Paral-lelrechners. Der Name ruhrt daher, dass an einem einzelnen Knoten (engl. node)mehrere Leitungen eines Verbindungsnetzwerkes zusammentreffen (Abb. 2.3). Daein Knoten im von-Neumann’schen Sinne ein vollstandiger Computer ist, nennt manSysteme mit verteiltem Speicher auch Multicomputer.

Page 35: [X.systems.press] Cluster Computing ||

24 2 Parallelrechner

2.2 Verbindungsnetzwerke

Bei Systemen mit verteiltem Speicher wird das Verbindungsnetzwerk zu einer leis-tungsbestimmenden Große. Charakteristische Parameter sind dabei Bandbreite, La-tenz und Topologie des Netzwerkes.

Die Bandbreite (bandwidth) B gibt die Rate an, mit der Daten von einem Knotenzu einem anderen ubertragen werden konnen. Die Angabe erfolgt in Bit/s oder Byte/smit den ublichen Vorsilben. Die Latenz (latency) TL ist die Zeit, die vergeht, bisdas erste Bit vom Empfanger zum Sender gelangt. Die effektive Laufzeit Teff einesDatenpaketes der Große P ist darum

Teff = TL +PB

. (2.1)

Fur große Datenpakete, genauer fur P � BTL, bestimmt die Bandbreite die Ubertra-gungsgeschwindigkeit, bei kleinen Datenpaketen, d. h. fur P � BTL ist die Latenz-zeit TL der limitierende Faktor. Das bei der PC-Vernetzung dominierende Ethernethat Bandbreiten von 100 MBit/s (Fast Ethernet) bzw. 1000 MBit/s (Gigabit Ethernet).Die Latenzzeiten betragen hier ca. 70 µs. Tabelle 4.1 auf Seite 59 zeigt die entspre-chenden Daten fur andere Netztechnologien. Fast alle Verbindungsnetze erreichenlediglich eine Bandbreite, die nur einen Bruchteil der Rate betragt, mit denen Datenin shared memory Systemen ausgetauscht werden konnen.

Die Angaben von Latenz und Bandbreite beziehen sich in der Regel auf das theo-retische Optimum bei einer direkten Punkt-zu-Punkt-Verbindung. Bei einer große-ren Anzahl von Knoten ist es jedoch schwierig bis unmoglich, jeden Knoten mitjedem anderen direkt zu verbinden. Denn die Anzahl der Verbindungen wachst qua-dratisch mit der Anzahl der Knoten. Alternativ verbindet man nur wenige Knotendirekt miteinander, aber so, dass ein zusammenhangendes Verbindungsnetzwerk ent-steht, in dem jeder Knoten jeden anderen noch erreichen kann, notfalls uber mehrereZwischenstationen. Abbildung 2.3 zeigt einige dieser Netzwerktopologien. Da beiTopologien wie kartesische Gitter, Tori oder Sterne die Anzahl der Verbindungenhochstens linear mit der Anzahl der Knoten wachst, erlauben sie auch den Aufbaugroßerer Netze. Der Nachteil solcher Verbindungsnetze ist die nur noch indirekteVerbindung zwischen den meisten Knotenpaaren. Bei einer indirekten Verbindungverschlechtern sich in der Regel sowohl die Latenz als auch die Bandbreite mit derAnzahl der Zwischenstationen, die ein Datenpaket unterwegs passieren muss. DieAnzahl der Zwischenstationen auf dem kurzesten Weg zwischen zwei Punkten defi-niert die Entfernung der Knoten im Netzwerk, die Knoten mit der maximalen Entfer-nung definieren den Durchmesser des Netzes. Die Topologie eines Hyperkubus hatgegenuber kartesischen Gittern, Tori oder Sternen den großen Vorteil, dass bei ihrder Durchmesser nur logarithmisch mit der Zahl der Knoten wachst, diese schoneEigenschaft erkauft man sich aber durch mehr Verbindungen. Ihre Zahl betragt mitp der Anzahl der Knoten p/2 · log2 p.

Wenn es mehrere mogliche Pfade zwischen zwei Knoten gibt, was bei den meis-ten Topologien der Fall ist, mussen Routing-Algorithmen in den Knoten fur einemoglichst gunstige Auswahl, d. h. einen moglichst kurzen Weg sorgen. Am besten

Page 36: [X.systems.press] Cluster Computing ||

2.2 Verbindungsnetzwerke 25

Stern

= 1d

= 0d

= 3d

= 1d d = 2 = 3d

= 2d

= 1d = 2d

= 4d

Bus

Switch

Kartesische Gitter

Tori

Hyperkuben

Ring

Abb. 2.3. Topologien fur Verbindungsnetzwerke.

Page 37: [X.systems.press] Cluster Computing ||

26 2 Parallelrechner

fahrt man naturlich mit einer Topologie, die dem Kommunikationsmuster der An-wendung entspricht. Zur numerischen Behandlung dreidimensionaler Systeme wiebei der Wettervorhersage passt z. B. ein dreidimensionales kartesisches Verbindungs-netzwerk (Abb. 2.2), denn hier findet der Datenaustausch hauptsachlich zwischendirekt miteinander verbundenen Knoten statt.

Fur Anwendungen, deren Kommunikationsmuster auf keine einfache, konstan-te Topologie passt, stellen Verbindungsnetzwerke mit eingeschrankten Direktverbin-dungen keine optimale Losung dar. Gleiches gilt fur Parallelrechner, auf denen ver-schiedene Anwendungen laufen sollen. Hier mochte man nur ungern auf die Vorteileeiner kompletten Vernetzung verzichten ohne jedoch den damit verbundenen Verka-belungsaufwand betreiben zu mussen. Dafur gibt es in der Tat Losungen in Formspezieller Netzarchitekturen: dem Bus und der sternformigen Vernetzung mit einemSwitch (Abb. 2.3). Bei einem Bus hangen alle Knoten an einem gemeinsamen Netz-kabel. Ein Datenpaket, das von einem Knoten ausgesandt wird, erreicht grundsatz-lich alle anderen Knoten, die an den Bus angeschlossen sind. Alle Knoten mussendas Datenpaket inspizieren und anhand der darin enthaltenen Empfangeraddresseentscheiden, ob es fur sie bestimmt ist oder nicht. Ein Bus hat neben der einfachen,preisgunstigen Verkabelung den Vorteil, dass es zwischen allen Knoten eine direkteVerbindung gibt. Der große Nachteil dieser Topologie besteht darin, dass sich al-le Knoten diese Verbindung (und damit die Bandbreite) teilen mussen. Wenn zweioder mehr Knoten gleichzeitig Daten verschicken, kommt zu einer Datenkollisionauf dem Bus, die beide Datenpakete zerstort. Die Knoten mussen uber die Fahig-keit verfugen, eine solche Kollision zu entdecken und ihr Datenpaket gegebenenfallserneut zu senden. Mit ausgeklugelten Protokollen mussen die Knoten dafur sorgen,dass Kollisionen nur zu einer kleinen Verzogerung des Datentransportes fuhren, undnicht etwas zu einem Stau auf der ”Datenautobahn“. Es ist allerdings anschaulichklar, dass die Kollisionen und die damit einhergehenden Verzogerungen mit der An-zahl der angeschlossenen Knoten und dem Datenaufkommen zunehmen. Alte oderpreiswerte Installationen von Ethernet haben eine Bustopologie.

Bei der Vernetzung mit einem Switch umgeht man das Problem der quadratischanwachsenden Zahl von Verbindungen dadurch, dass man die Vollvernetzung ge-wissermaßen elektronisch simuliert. Der Switch ist direkt mit jedem der Knotenverbunden, d. h., die Zahl der Leitungen wachst linear mit der Zahl der Knoten.Ein auf einer Leitung ankommendes Datenpaket wird vom Switch inspiziert und anden Empfangerknoten weitergeleitet. Die anderen Verbindungsleitungen bleiben vondiesem Vorgang unberuhrt. Dies fuhrt dazu, dass mehrere disjunkte Knoten-Paaregleichzeitig mit der vollen Bandbreite kommunizieren konnen. Der Switch selbst ver-ursacht dabei nur eine geringe Erhohung der Latenzzeit (fur das Lesen der Empfange-radresse), kann aber die Zahl der Kollisionen auf einem Kabel durch geeignetes,kurzzeitiges Zuruckhalten von Paketen drastisch reduzieren. Die Anschlussmoglich-keiten fur Knoten an einem Switch heißen Ports, und der Aufwand der Paketverarbei-tung steigt offensichtlich mit der Anzahl Ports. Im ungunstigsten Fall laufen auf ei-ner Halfte der Ports gleichzeitig Datenpakete fur die andere Halfte der Ports ein. DieBandbreite, die ein Switch fur diesen Fall insgesamt vorhalten muss, heißt Bisektions-bandbreite. Sie betragt bei der sternformigen Verkabelung mit einem Switch pB/2,

Page 38: [X.systems.press] Cluster Computing ||

2.3 Cluster-Computer 27

wobei p die Anzahl der Ports ist und B die Bandbreite der Direktverbindung an-gibt. Ein Switch mit vielen Ports bietet oft nur einen Bruchteil der vollen Bisektions-Bandbreite. In einem solchen Switch sind die Ports uberbucht. Eine vierfache Uber-buchung bedeutet beispielsweise, dass die Bandbreite der Switch-Elektronik nur einViertel der vollen Bisektionsbandbreite betragt, maximal also nur ein Viertel der Kno-tenpaare gleichzeitig mit der vollen Bandbreite kommunizieren konnen. Selbst swit-ched networks mit uberbuchten Ports bilden eine sehr gute Annaherung an die vollvernetzte Topologie, denn in vielen Anwendungen werden Daten zwischen beliebi-gen Knoten ausgetauscht, aber selten gleichzeitig. Die meisten modernen lokalenVernetzungen von PCs sind switched Ethernets, ganz gleich, ob es sich dabei um dasNetz handelt, das Burocomputer mit dem Abteilungsdrucker verbindet oder um dasNetz, das aus einem Haufen Workstations einen parallelen Supercomputer macht.

2.3 Cluster-Computer

Die Cluster-Computer, um die es in diesem Buch geht, sind naturlich Parallelrechnermit verteiltem Speicher. Oberflachlich betrachtet ist ein Cluster lediglich eine An-sammlung von Standard-PCs. Eine lose Ansammlung von PCs allein ist aber nochnicht sehr nutzlich. Werden die PCs jedoch noch durch ein Netzwerk untereinanderverbunden und mit spezieller Cluster-Software ausgestattet, so wird daraus ein Paral-lelcomputer von Supercomputerformat. Dass die Bezeichnung Supercomputer keineUbertreibung ist, zeigt ein Blick in die aktuelle Top 500 [166] der schnellsten Com-puter der Welt. Unter den schnellsten zehn Computern sind gleich mehrere Cluster-Computer vertreten.

Es gab in der Vergangenheit zahlreiche Ansatze fur Parallelcomputer. Nur weni-ge haben sich langfristig durchgesetzt. Cluster-Computer jedoch sind mehr als nurein weiterer Typ von Parallelcomputern. Entscheidend fur die weite Verbreitung vonCluster-Computern waren zwei Punkte, in denen sie sich von anderen verteilten Sys-temen unterscheiden: zum einen die konsequente Beschrankung auf handelsublicheStandard-Hardware (commodity off the shelf ) fur Knoten und Netzwerk und zumanderen der Einsatz freier Software mit offenen Standards.

2.3.1 Das Beowulf-Projekt

Der erste Cluster mit diesen Merkmalen wurde 1994 von den NASA Wissenschaft-lern Thomas Sterling und Donald J. Becker am Goddard Space Flight Center in Be-trieb genommen [158]. Ihr Cluster bestand aus sechzehn Linux-PCs mit 100 MHzIntel DX4 Prozessoren, die via Ethernet miteinander vernetzt waren. Als Spezialsoft-ware zum Datenaustausch zwischen den Knoten verwendeten sie das frei verfugbarePVM (Notiz 3.6). In mehreren Benchmarks erreichte der Cluster eindrucksvolle Re-sultate. Ein Programm zur numerischen Behandlung zweidimensionaler kompressi-bler Stromungen, das auf einem Knoten mit 4,5 MFlops lief, erreichte auf den sech-zehn Knoten 60 MFlops. Was einem Speedup von 13,33 bzw. einer Effizienz von83 % entspricht. Mit diesen Leistungsdaten spielte der Selbstbaurechner der NASA

Page 39: [X.systems.press] Cluster Computing ||

28 2 Parallelrechner

Wissenschaftler in der gleichen Liga wie die Supercomputer von IBM und Co., aller-dings mit einem Bruchteil der Kosten dieser big iron Maschinen.

Becker und Sterling nannten ihr Projekt Beowulf nach der Hauptfigur aus demgleichnamigen englischen Heldenepos. Der Beowulf-Cluster von Becker und Ster-ling stand am Anfang einer sturmischen Entwicklung, denn ihr erfolgreiches Projektfand viele Nachahmer. Heute gibt es kaum eine Universitat oder Forschungseinrich-tung, die nicht mindestens einen Beowulf-Cluster betreibt. Auch im kommerziel-len Umfeld nimmt die Zahl der Beowulf-Cluster rapide zu. Waren es am Anfanghauptsachlich Spezialisten und Hacker, die den Bau solcher Systeme vorantrieben,so sind es heute dank einfach zu installierender Software auch technisch wenigerversierte Nutzer, die ihren Hunger nach Rechenleistung auf preiswerte Art mit ei-nem Beowulf-Cluster stillen. Mittlerweile ist auch die Computerindustrie auf denZug aufgesprungen und bietet schlusselfertige Beowulf-Cluster an. Es ist keine be-sonders mutige Prognose, wenn man behauptet, dass die PC-Cluster in absehbarerZeit den Markt fur Supercomputer beherrschen werden.

2.3.2 Standard-Hardware

Die Grundidee des Cluster-Computings schaut auf dem ersten Blick ausgesprochensimpel aus: Man nehme einige billige Standard-PCs, vernetze diese und schon hatman einen Supercomputer zum Schnappchen-Preis. Bedenkt man aber, dass es seitAnfang der 1980er einen Massenmarkt fur Computer gibt, der erste Cluster-Compu-ter aber erst 1994 von Donald J. Becker und Thomas Sterling entwickelt wurde, sodrangt sich die Frage auf, warum Cluster-Computing nicht schon viel langer betrie-ben wird.

Dass gerade Mitte der 1990er die ersten Cluster-Computer auftauchten, liegt zumTeil daran, dass zu diesem Zeitpunkt Standard-PCs zum ersten Mal so leistungsfahigwaren, dass sie es immerhin mit Supercomputern fruherer Generationen aufnehmenkonnten. Zum anderen existierte mit Ethernet erstmals auch fur PCs eine recht leis-tungsfahige und preiswerte Netzwerktechnik. Diese leistungsfahige Netzwerktech-nik ist, wie wir in Abschnitt 2.2 gesehen haben, ganz entscheidend fur Computer mitverteiltem Speicher. Erst durch ein Netzwerk ausreichender Bandbreite, wird aus ei-nem Haufen PCs ein Cluster-Computer.

Cluster-Computer haben die Welt der Supercomputer dramatisch verandert, dennsie haben die Einstiegshurde zum Super-Computing drastisch herabgesetzt, wennnicht sogar abgeschafft. Vor dem Cluster-Computer-Zeitalter gab es im WesentlichenComputer in zwei Leistungsklassen. Zum einen waren da billige aber leistungsschwa-che Standard-PCs und zum anderen hochgezuchtete Supercomputer, die meist so teu-er waren, dass diese nur in wenigen Forschungseinrichtungen zu finden waren. Mitauf Standard-Komponenten basierenden Cluster-Computern verwischen diese Gren-zen. Ein Cluster-Computer aus 16 PCs kostet kaum mehr als ein Mittelklassewagenund ist somit ein wirklicher Supercomputer fur jedermann. Cluster-Computer mitmehreren tausend Knoten konnen sich zwar wieder nur einige Großforschungsein-richtungen leisten, jedoch reicht ihre Rechenleistung fur einen Platz in den Top 500.

Page 40: [X.systems.press] Cluster Computing ||

2.3 Cluster-Computer 29

Abb. 2.4. Kein Abstellraum, sondern ein Hochleistungsrechner: Beowulf-Cluster aus ausran-gierten Burocomputern am Oak Ridge National Laboratory, Tennessee [64]. (Quelle: ORNL)

Zwischen diesen beiden Extremen gibt es Cluster-Computer aller Großenordnungenund Preisklassen.

Besonders deutlich wird das unschlagbare Preis-Leistungs-Verhaltnis bei Beo-wulf-Clustern, die aus ausrangierten (und damit kostenlosen) Burocomputern beste-hen (Abb. 2.4). Selbst wenn man fur die Hardware eines Clusters brandneue PC- undNetztechnik einkauft und auch noch Geld fur einen soliden mechanischen Aufbauausgibt (Abb. 2.5), halten sich die Kosten in Grenzen.

Mit der zunehmenden Verbreitung der Beowulf-Cluster traten Unternehmen aufden Plan, die den Cluster-Markt fur sich entdeckten. Etablierte Computerfirmen wieIBM und HP nahmen schlusselfertige Linux-Cluster in ihr Programm auf, und eini-ge PC-Handler wie die Megware GmbH aus Chemnitz entwickelten sich zu Cluster-Spezialisten. Resultat waren z. B. neue, kompakte Bauformen fur PC Boards, mitdenen sich Cluster hoher Baudichte aufbauen lassen (Abb. 4.7). Andere Firmen ent-wickelten spezielle Netztechnologien, die den Flaschenhals des Cluster-Computings

Abb. 2.5. 80 PCs, ordentlich gestapelt in 19-Zoll-Industrieschranken: der Beowulf-ClusterTina [165] des Instituts fur Theoretische Physik der Universitat Magdeburg.

Page 41: [X.systems.press] Cluster Computing ||

30 2 Parallelrechner

(hohe Latenz und niedrige Bandbreite der Vernetzung) etwas erweitern (siehe Ab-schnitt 4.3). Bei diesen Entwicklungen kann man nicht mehr unbedingt von ”Mas-senware“ sprechen, allerdings ist der Markt fur Cluster selbst inzwischen so großgeworden, dass auch solche Speziallosungen fur kleine Institute und Unternehmenerschwinglich bleiben.

2.3.3 Linux, freie Software und offene Standards

Die Verwendung freier Software (insbesondere Linux) ist das zweite Geheimnis hin-ter dem Erfolg von Cluster-Computern. Fast alle Cluster-Computer laufen mit demfreien Betriebsystem Linux. Frei bezieht sich hier nicht nur auf den Preis. Viel wich-tiger ist die Freiheit, den Quellcode von Programmen einsehen und modifizieren zukonnen.

Wie wichtig diese Freiheit ist, zeigte schon der erste Cluster-Computer von Do-nald J. Becker und Thomas Sterling. Die Ethernet-Technik, die Becker und Sterlingdamals einsetzten, war noch vergleichsweise langsam. Jedoch bestuckten sie jeden ih-rer Computer mit mehren Netzwerkkarten und erweiterten das Linux-Betriebssystemum eine Funktion, die alle Netzwerkkarten auf eine logische Netzwerkkarte abbildet(channel bonding, siehe Abschnitt 5.7). Mit einem properitaren Betriebssystem wareso etwas nie moglich gewesen. Heute gibt es neben den channel bonding Treibernvon Donald Becker eine ganze Fulle freier Softwarepakete, die das Arbeiten mitClustern unterstutzt. Wir werden einige der wichtigsten in diesem Buch vorstellen.

Weitere Grunde, die fur Linux sprechen, sind die Stabilitat und die Portabilitatvon Linux. Linux-Cluster laufen nicht selten uber viele Monate ohne Unterbrechung.Wenn ein Linux-Cluster uberhaupt rebootet wird, so hat dies oft außere Grunde(Stromausfall, Wartungsaufgaben). Aufgrund seiner hohen Portabilitat lauft Linuxauf fast allen wichtigen Hardwarearchitekturen. Fur neue Architekturen lasst sich Li-nux meist leicht anpassen. Dagegen, dass Ihre Hardware veraltet, konnen Sie nichtsmachen. Entwickeln Sie Ihre Software unter Linux, so wird diese aber auch noch aufeinem Cluster der nachsten Generation laufen.

Eine weitere Antwort auf die Frage ”Warum Linux?“ konnte ”Weil jeder Linuxbenutzt.“ lauten. Diese Antwort mag auf den ersten Blick ignorant oder gar dummklingen. Jedoch impliziert sie auch, dass Sie bei Problemen auf die Erfahrungen tau-sender anderer Cluster-Betreiber zuruckgreifen konnen. Diese Erfahrungen schlagensich z. B. in uber das Internet vertriebene HowTos oder Bucher wie diesem nieder.Wenn Sie stattdessen einen Cluster mit einem properitaren Betriebssystem betreibenwollen (was prinzipiell durchaus machbar ist), stehen Sie mit Ihren Problemen rechteinsam da.

Ein großer Nachteil alterer Parallelcomputer war gerade ihre Einzigartigkeit unddadurch bedingte Inkompatibilitat zu anderen Supercomputern. Programme musstenmit Werkzeugen oder gar Sprachen entwickelt werden, die ganz spezifisch fur den je-weiligen Parallelcomputer waren. Eine Portierung eines Programms von einem Paral-lelcomputer zu einem anderen lief nicht selten auf eine Neuentwicklung hinaus. Mitoffenen Standards wie Parallel Virtual Machine (PVM) oder dem Message PassingInterface (MPI) konnen heute aber portable Programme geschrieben werden, die auf

Page 42: [X.systems.press] Cluster Computing ||

2.3 Cluster-Computer 31

einer Vielzahl von Parallelcomputern laufen. Im Idealfall beschrankt sich nun einePortierung auf ein erneutes Ubersetzten des Quellcodes. Das Message Passing Inter-face werden wir Ihnen im Teil III genauer vorstellen.

2.3.4 Anwendungsgebiete

Cluster-Computer kommen in zwei ganz unterschiedlichen Anwendungsgebietenzum Einsatz. Dies sind high availability computing und high performance compu-ting. Im high availability computing werden mittels Cluster-Computer ausfallsichereDienste realisiert. Dies konnen z. B. hochverfugbare Datei-, Datenbank- oder Web-Server sein. Da die Knoten eines Clusters relativ unabhangig voneinander sind, istder vom Cluster bereitgestellte Dienst auch noch verfugbar, wenn einzelne Knotenausgefallen sind. Die noch intakten Knoten mussen lediglich die Arbeit der ausgefal-lenen Knoten ubernehmen.

In diesem Buch beschaftigen wir uns aber mit Cluster-Computern fur das highperformance computing. Dies war das Anwendungsfeld der allerersten Cluster undhier finden sich auch die großten und leistungsfahigsten Cluster. High-Performance-Cluster stellen fur relativ wenig Geld eine sehr große Leistung zur Verfugung. Ho-he Rechenleistungen werden z. B. von Anwendungen benotigt, die Ergebnisse inner-halb eines gewissen Zeitrahmens liefern mussen. Dazu gehoren die Wettervorhersageoder Prognosen an Finanzmarkten, aber auch die Analyse von experimentellen Da-ten. Große Teilchenbeschleuniger-Experimente liefern heute so riesige Datenmen-gen, dass es unmoglich ist, diese vollstandig zu speichern oder gar zu analysieren.Andererseits ist die Mehrzahl dieser Daten vollkommen uninteressant, weil sie phy-sikalische Prozesse beschreiben, die langst gut verstanden sind. Cluster-Computerfuhren hier eine erste grobe Analyse der experimentellen Daten durch und entschei-den, welche Daten interessant genug sind, um sie abzuspeichern und spater noch ein-mal genauer zu analysieren. Dazu muss der Cluster die Daten mindestens so schnellanalysieren konnen, wie sie von den Messgeraten erzeugt werden.

Viele technisch-wissenschaftlichen Berechnungen sind so aufwendig, dass sienicht in vertretbarer Zeit auf einem Einzel-Computer durchzufuhren sind. Ein Par-allel-Computer kann die Laufzeit solcher Rechnungen von mehreren Monaten aufeinige Tage drucken. Cluster werden aber nicht nur als Parallelrechner eingesetzt.Sie dienen auch als Plattform fur die schnelle Bearbeitung einer großen Zahl vonsequentiellen Programmen, die sich oft nur durch ihre Eingabeparameter unterschei-den (high throughput computing). Dazu wird auf dem Cluster eine spezielle Softwa-re installiert, ein sog. Queuing- oder Batch-System. Nutzer starten ihre sequentiel-len Programme nicht direkt, sondern erteilen einen entsprechenden Auftrag an dasBatch-System. Dieses verwaltet eine (oder mehrere) Warteschlangen mit Auftragenund uberwacht zugleich die Last der einzelnen Knoten. Sobald ein Knoten ohne Lastist, startet das Batch-System auf diesem Knoten den nachsten Auftrag aus der War-teschlange. Auf diese Weise wird der Custer gleichmaßig ausgelastet und der Durch-satz an abgearbeiteten Auftragen skaliert im optimalen Fall linear mit der Zahl derKnoten. Batch-Systeme konnen auch parallele Anwendungen verwalten. In diesem

Page 43: [X.systems.press] Cluster Computing ||

32 2 Parallelrechner

Fall gehort zu jedem Auftrag auch die Angabe, auf wievielen Knoten die Anwen-dung laufen soll. Das Batch-System startet den Auftrag erst dann, wenn mindestensdie angegebene Anzahl von Knoten im Cluster ohne Last sind. Im Abschnitt 6.2betrachten wir Batch-Systeme etwas ausfuhrlicher.

Neben einer großen Rechenleistung zeichnet sich ein Cluster-Computer durcheinen großen Arbeitsspeicher aus. Manche Anwendungen (z. B. Datamining) benoti-gen soviel Speicher, dass nur ein Cluster-Computer einen genugend großen Speicherzur Verfugung stellen kann. Will ein Knoten auf Daten im Speicher eines anderenKnoten zugreifen, so mussen diese Daten, wegen der verteilter Speicherarchitektureines Clusters, erst uber das Netzwerk transportiert werden. Im Vergleich zu loka-len Speicherzugriffen sind externe Speicherzugriffe um Großenordnungen langsa-mer. Darum gehoren Programme mit haufigen externen Speicherzugriffen zu denAnwendungen, die nicht oder nur eingeschrankt fur Cluster-Computer geeignet sind.Diese Anwendungen werden zu stark durch das Netzwerk ausgebremst.

Auch wenn wir eingangs high availability computing und high performance com-puting unterschieden, so lassen sich nicht alle Cluster eindeutig einer dieser Katego-rien zuordnen. Ein gutes Beispiel ist hier die Schmaschine Google. Hinter Googleverbirgt sich ein Cluster mit uber 15 000 Knoten (Notiz 1.3). So viele Knoten wer-den in erster Linie benotigt, um die Vielzahl von Suchanfragen in angemessener Zeitbeantworten zu konnen. Hier kommt also der High-Performance-Aspekt zum Tra-gen. Zum anderen erhoht die Verteilte Architektur der Suchmaschiene naturlich dieVerfugbarkeit von Google. Ausfalle einzelner Knoten beeintrachtigen die Funktiona-litat der Suchmaschine praktisch gar nicht.

2.4 SETI@home und Grid-Computing

Cluster Computing ist die Idee, vernetzte Computer als leistungsstarken Parallel-rechner zu betreiben. Wenn man diese Idee konsequent zu Ende denkt, landetman zwangslaufig beim großten Computernetzwerk uberhaupt: dem Internet. Die-ses ”Netz der Netze“ verbindet einige hundert Millionen Rechner miteinander (No-tiz 2.6), und viele dieser Rechner sind nicht ausgelastet. Nehmen Sie z. B. einentypischen Schreibtischrechner der 1-GFlops-Klasse: Textverarbeitung, E-Mail oderdas Surfen im Web belasten den Prozessor praktisch gar nicht. Den großten Teil derZeit verbringt die CPU damit, auf den nachsten Tastendruck des Nutzers zu war-ten. Uber das Internet konnten die ungenutzten CPU-Zyklen mit sinnvoller Arbeitversorgt werden, ohne den normalen Rechnerbetrieb zu storen. Das ist die Idee desverteilten Rechnens (distributed computing) [66]. Selbst wenn nur ein kleiner Teilder Internet-Rechner jeweils nur einen kleinen Teil ihrer verfugbaren CPU-Leistungfur ein gemeinsames Projekt aufbringt, so kann uber die schiere Anzahl doch einebetrachtliche Rechenleistung zusammenkommen.

Das bekannteste Projekt des verteilten Rechnens ist sicherlich SETI@home [88].SETI steht fur search for extraterrestrial intelligence. Aufgabe des Projektes ist es,in den Daten von Radioteleskopen nach Signalen von außerirdischen Zivilisationen

Page 44: [X.systems.press] Cluster Computing ||

2.4 SETI@home und Grid-Computing 33

zu suchen. Ein einzelner Computer ware angesichts der Datenfulle und der aufwandi-gen Analyse damit uberfordert. Das brachte die SETI-Leute auf die Idee, uber dasInternet um Unterstutzung zu bitten. Wer helfen mochte, kann von der Webseite desProjektes SETI@home [149] eine Software, den SETI@home-Client, herunterladenund auf seinem Rechner starten. Der Client nimmt uber das Internet Kontakt mitdem Server des SETI@home Projektes auf, holt sich ein paar Teleskopdaten undanalysiert diese. Nach der Analyse wird der Server erneut kontaktiert, das Ergebnisabgeliefert und gegebenenfalls ein neuer Datensatz zur Analyse abgeholt.

Das Projekt SETI@home lauft seit 1999. In dieser Zeit haben mehr als funfMillionen Menschen Rechenzeit gespendet, die meisten davon regelmaßig. Die per-manent verfugbare Rechenleistung betragt momentan (April 2005) rund 60 TFlops.Zum Vergleich: der zu diesem Zeitpunkt schnellste Rechner der Welt bringt es auf70,7 TFlops, der zweitschnellste auf 51,8 TFlops [166]. Um Rechenleistung in dieserGroßenordnung uber das Internet einzusammeln, musste SETI@home eine Reihevon Eigenschaften haben:

Granularitat. Das Internet ist ein sehr heterogenes Netz. Bandbreiten schwankenzwischen einigen GBit/s (nationale Backbones) bis hin zu 56 KBit/s (analogerTelefonanschluss). Die Datenpakete, die der SETI-Server verschickt, haben eineGroße von 340 KByte. Die Ubertragung eines solchen Pakets dauert selbst ubereine Telefon-Anbindung mit 56 KBit/s weniger als eine Minute. Die Analysedieses Pakets lauft dagegen auf einem modernen PC mehrere Stunden. Die grobeGranularitat sorgt fur eine hohe Effizienz der Parallelisierung.

Diversitat. Die teilnehmenden Rechner sind sehr unterschiedlich. Um Windows-PCs, Macintosh-Rechner und diverse Unix-Maschinen nicht auszuschließen,mussen die Projektbetreiber fur jede dieser Plattformen die passende Client-Soft-ware bereitstellen. Zur Zeit bietet SETI@home-Clients fur ca. 60 verschiedeneKombinationen von CPU und Betriebssystem an.

Robustheit. Die Client-Rechner unterliegen nicht der Kontrolle des Projektes. Manmuss damit rechnen, dass ubernommene Auftrage nicht bearbeitet werden oderzuruckgelieferte Resultate falsch sind. Selbst Sabotage kann nicht ausgeschlos-sen werden. Der Server vergibt deshalb einige Teilaufgaben mehrfach an ver-schiedene Clients. Zur Uberprufung erhalten Clients außerdem regelmaßig Auf-gaben, deren Resultate bekannt sind. Zur Robustheit gehort auch, dass die Client-Software ein vorzeitiges Abschalten des Rechners ”uberlebt“ und nach dem Ein-schalten dort weitermacht, wo sie unterbrochen wurde.

Attraktivitat. Die Client-Software stort den normalen Rechnerbetrieb nicht. AufUnix-Maschinen lauft sie mit niedriger Prioritat im Hintergrund, fur WindowsRechner ist eine Bildschirmschoner-Variante erhaltlich. Unterstutzer mussen al-lerdings sowohl Zeit (Installation) als auch Geld (Online-Kosten) investieren. Da-zu sind die Leute umso eher bereit, je attraktiver das Projekt erscheint. Die Suchenach außerirdischer Intelligenz ist fur viele Menschen per se schon attraktiv, aberdie Spendenbereitschaft lasst sich durch allerelei Marketing-Maßnahmen nocherhohen. Dazu tragen regelmaßige Rankings (”Wer hat in den letzten 24 Stundendie meisten Daten analysiert?“) ebenso bei wie das Versprechen, bei der Entde-

Page 45: [X.systems.press] Cluster Computing ||

34 2 Parallelrechner

ckung außerirdischer Signale den Spender der entscheidenden CPU-Zyklen alsCo-Autor mit auf die weltbewegende Publikation zu nehmen.

SETI@home ist nicht das einzige Projekt, in dem das Internet die Rolle eines globa-len Supercomputers ubernimmt. Andere Projekte beschaftigen sich mit der Berech-nung von Proteinstrukturen (Folding@home [42]), der Suche von großen Primzahlen(GIMPS, the giant Internet Mersenne prime search [50]) oder dem Aufspuren vonGravitationswellen (Einstein@home [34]). Die Webseiten von Kirk Pearson [133]und Michael Keppler [141] bieten einen Uberblick uber viele dieser Projekte.

Das verteilte Rechnen ”auf Spendenbasis“ ist nicht fur alle Projekte geeignet. DasSpendenaufkommen ist unkalkulierbar, und die meisten Projektthemen sind nicht at-traktiv genug, um eine ausreichende Anzahl von Unterstutzern zu mobilisieren. Au-ßerdem ist die dazugehorige Infrastruktur (Projektserver, Datenbank der Unterstutzer,Client- und Serversoftware) recht aufwandig zu erstellen. Dennoch ist die im Netzbrachliegende Rechenleistung zu kostbar, um sie ungenutzt zu lassen. Die Situati-on ist vergleichbar mit dem Stromnetz. Auf der einen Seite stellen Großkraftwerke,Windkraftanlagen, Blockheizkraftwerke und Solaranlagen elektrische Leistung zuVerfugung. Auf der anderen Seite wollen die Verbraucher uberall im Netz je nachBedarf kleine oder große Leistungen abfordern. Das Stromnetz sorgt fur die Vertei-lung und die Abrechnung der Leistung. Beim verteilten Rechnen stellen die vielenangeschlossenen Rechner mit freien CPU-Zyklen die Rechenkraftwerke dar, derenLeistung nur irgendwie zu den Menschen mit Rechenbedarf transportiert werdenmuss. Im Idealfall sollte die Rechenleistung aus der ”Internet-Dose“ kommen, sowie heute schon der Strom aus der Steckdose kommt, inklusive der Abrechnungder bezogenen Leistung. Das Gewebe aus Protokollen, Soft- und Hardware, das die-sen Traum verwirklichen soll, heißt Grid in Anlehnung an das englische Wort furStromnetz (power grid) [17]. Grid-Computing ist zur Zeit noch eine Vision und Ge-genstand aktiver Forschung [43]. Man darf gespannt sein, ob eines Tages tatsachlichRechenleistung nach Bedarf von jedem Netzanschluss abrufbar sein wird.

2.5 Notizen

2.1 MIMD und SIMD. Jedes Computerprogramm besteht aus einer Abfolge vonBefehlen (instructions), die auf einer Abfolge von Daten operieren. Ein Parallelrech-ner, der dieselbe Befehlsfolge gleichzeitig auf verschiedenen Datenfolgen anwendet,heißt in der Flynn’schen Klassifikation [41] SIMD-Rechner (single instruction, multi-ple data). Vektorrechner fallen z. B. in diese Klasse. Etwas universeller sind die Rech-ner der Kategorie MIMD (multiple instructions, multiple data), in der Befehls- undDatenstrome verschieden sein konnen. Die anderen beiden Kombinationen beschrei-ben sehr exotische Parallelrechner (MISD) oder den sequentiellen Rechner (SISD).Die Flynn’sche Klassifikation ist sehr akademisch, fur praktische Aspekte ist die Un-terscheidung zwischen shared und distributed memory viel wichtiger. Sowohl SMPsals auch Cluster sind im Flynn’schen Sinne MIMD-Maschinen.

Page 46: [X.systems.press] Cluster Computing ||

2.5 Notizen 35

2.2 PRAM. Fur den Entwurf und die Analyse von Algorithmen benotigt man ein ab-straktes Rechnermodell. Bei parallelen Algorithmen verwendet man meistens PRAM,die parallel random access machine. In diesem Modell haben alle Prozessoren unein-geschrankten, gleichmaßig effizienten Zugriff auf den gesamten Speicher. Symmetri-sche Multiprozessoren kommen diesem Modell noch am nachsten, Rechner mit ver-teiltem Speicher und insbesondere Cluster entsprechen nicht diesem Modell. SeienSie also auf der Hut, wenn Ihnen jemand einen effizienten parallelen Algorithmus an-preist. Effizienz im PRAM-Modell bedeutet noch lange nicht, dass ein Algorithmusfur einen Cluster geeignet ist.

2.3 Rechnerarchitekturen. Unsere Diskussion der Parallelrechner musste sich aufdie zwei grundlegenden Typen beschranken: gemeinsamer oder verteilter Speicher.Es gibt naturlich weit mehr Typen von Parallelrechnern. So kann man physisch ver-teilten Speicher per Software durchaus als einen Speicher mit globalem Adressraumbehandeln. Fur den Anwendungsprogrammierer stellt sich ein solcher Rechner alsshared memory System dar, allerdings hangt Zugriffsgeschwindigkeit auf den Spei-cher dann von der Speicheradresse ab. Das nennt man NUMA fur non uniform me-mory access. Mehr zur Architektur von Parallelrechnern finden Sie in [139, 170].

2.4 Beowulf. Beowulf [9] ist ein altenglisches Heldengedicht, das fruheste erhaltenegermanische Buchepos. Der Held, Beowulf, erschlagt im Laufe der 3182 Stabreim-verse das Ungeheuer Grendel. Der von Donald J. Becker und Thomas Sterling 1994gebaute ”Ur-Cluster“ hieß Wiglaf, nach einer anderen Figur aus dem Beowulf Epos.Das ganze Projekt, in dessen Rahmen Wiglaf entwickelt wurde, bekam jedoch denNamen Beowulf, der damit zum Gattungsnamen fur alle Nachfolgeprojekte wurde.Die Webseite des Beowulf-Projektes [10] ist immer noch eine erste Adresse fur dasCluster-Computing.

2.5 Feierabend-Supercomputer. In den meisten Unternehmen und Universitatengibt es eine betrachtliche Anzahl vernetzter PCs, die tagsuber zur Erledigung ty-pischer Buroarbeiten verwendet werden. Anstatt diese Rechner zum Feierband ab-zuschalten, kann man sie neu booten (unter Linux) und die ganze Nacht lang alsBeowulf-Cluster rechnen lassen. Solche supercomputer at night (SAN) bilden denwohl preiswertesten Zugang zu mehr Rechenleistung [172].

2.6 Internet. Wieviele Rechner sind uber das Internet miteinander vernetzt? DieseFrage ist nicht serios zu beantworten, da das Internet nicht zentral verwaltet wird undsich eine Menge Rechner nur temporar in das Internet einwahlen. Der Antwort amnachsten kommt der Internet Domain Survey, der regelmassig die Gesamtzahl derEintrage im weltweiten Domain Name Service (DNS) ermittelt, siehe [74]. Da nichtjeder Internet-Rechner einen DNS-Eintrag hat und hinter einem DNS-Eintrag vieleRechner stecken konnen, liefert diese Zahlung zumindest eine untere Schranke. DerInternet Domain Survey vom Januar 2005 ergab 317 646 084 DNS Eintrage.

Page 47: [X.systems.press] Cluster Computing ||

3

Programmieransatze

Fast, fat computers breed slow, lazy programmers.

Robert Hummel

Wie programmiert man parallel? Die Antwort auf diese Frage hangt von mehrerenFaktoren ab, z. B. von der anvisierten Hardware-Plattform und von der Struktur IhresProblems. In der Praxis haben sich vier prinzipielle Herangehensweisen etabliert:

• Datenparallelitat,• Threads,• Nachrichtentransfer (message passing) sowie• Client-Server-Programmierung.

Die ersten beiden Methoden eignen sich dabei ausschließlich fur Multiprozessor-Systeme. Die letzten beiden Techniken funktionieren auch auf Systemen mit verteil-tem Speicher, wobei Message-Passing die Methode der Wahl fur das Cluster-Compu-ting ist. Client-Server-Programmierung ist in erster Linie fur distributed computinga la SETI@home geeignet.

3.1 Datenparallelitat

Viele mathematische Operationen sind inharent parallel. Denken Sie nur an die Addi-tion zweier Vektoren, c = a+b. Jedes der Elemente des Vektors c kann unabhangigvon allen anderen, d. h. parallel berechnet werden. Ein anderes Beispiel ist die Matrix-Multiplikation. Jedes Element der Produktmatrix kann unabhangig von allen anderenberechnet werden. Man spricht hier von Datenparallelitat: eine Operation wird aufviele unabhangige Datenelementen angewandt.

In den meisten Programmiersprachen werden datenparallele Operationen durchSchleifen ausgedruckt, z. B. die Vektoraddition in FORTRAN 77:

DO 100 I=1, NC(I)=A(I)+B(I)

100 CONTINUE

An solche Schleifen hat man sich schon so gewohnt, dass man sie nicht mehr inFrage stellt. Aber genaugenommen sind sie oft unnaturlich, denn sie schreiben eine

Page 48: [X.systems.press] Cluster Computing ||

38 3 Programmieransatze

feste Reihenfolge vor: C(3) darf erst berechnet werden, nachdem C(1) und C(2)bereits berechnet wurden. FORTRAN 90 erlaubt dagegen eine Syntax, die der ma-thematischen Notation viel naher kommt:

C=A+B

Dieser Ausdruck bedeutet elementweise Addition und ist damit aquivalent zumSchleifen-Konstrukt, allerdings wird hier keine Reihenfolge vorgeschrieben. Dasmacht diese Schreibweise nicht nur kurzer und asthetischer, sondern ermoglichtdaruberhinaus dem Compiler, automatisch parallelen Code zu erzeugen. Ein guterFORTRAN 90 Compiler wird daraus Code machen, der zur Laufzeit feststellt, wie-viele Prozessoren vorhanden sind, um dann die Berechnung der Elemente von Cgleichmaßig auf diese Prozessoren zu verteilen.

Ihre Programme werden kurzer, lesbarer und auch noch vollautomatisch paral-lelisiert. Das ist naturlich zu schon, um wahr zu sein. In der Praxis gibt es einigeEinschrankungen. So lassen sich viele einfache Schleifen nicht als rein datenparal-lele Operationen darstellen. Nehmen Sie als Beispiel die Berechnung der Hilbert-Matrix:

DO 100 I=1, NDO 200 J=1, N

A(I, J)=1.0/REAL(I*J)200 CONTINUE100 CONTINUE

Auch diese Berechnung ist naturlich parallelisierbar, aber wir konnen das demCompiler nicht mehr durch eine indexfreie Notation signalisieren, denn die Indizessind hier Bestandteil der Rechnung. Fur solche Falle wurde in High PerformanceFORTRAN (HPF) und FORTRAN 95 (beides Erweiterungen von FORTRAN 90)ein neues Schleifenkonstrukt eingefuhrt:

FORALL(I=1:N, J=1:N)A(I, J)=1.0/REAL(I+J)

END FORALL

Mit FORALL wird ausgedruckt, dass die Reihenfolge der Schleifendurchlaufe belie-big ist.

Auch Schleifen wie die folgende zur Berechnung des Skalarproduktes zweierVektoren passen nicht so recht in das Schema der Datenparallelitat, da alle Operatio-nen auf eine einzige Variable wirken.

SUM = 0.0DO 100 I=1, N

SUM = SUM + A(I)*B(I)100 CONTINUE

In FORTRAN 95 mussten wir die Schleife kunstlich aufbrechen, um dem Compilereine Chance zur Paralleliserung zu geben, etwa so:

FORALL(K=1:P)S(K)=0.0DO I=K, N, P

Page 49: [X.systems.press] Cluster Computing ||

3.2 Threads 39

S(K)=S(K)+A(I)*B(I)END DO

END FORALLSUM=0.0DO K=1, P

SUM=SUM+S(K)END DO

Jetzt kann die Berechnung der Teilsummen S(1) bis S(P) vom Compiler paralleli-siert werden, aber elegant ist das nicht mehr. Außerdem haben Sie als Programmiererdurch die Wahl von P Verantwortung fur die Granularitat der Parallelisierung uber-nommen.

Unser kleiner Ausflug in die Datenparallelitat hat Sie hoffentlich davon uber-zeugt, dass dies eine elegante Methode mit einem sehr engen Anwendungsbereichist. Algorithmen, die nicht direkt auf regelmaßigen Datenstrukturen mit unabhangi-gen Elementen operieren, lassen sich damit nur sehr umstandlich darstellen. Die au-tomatische Parallelisierung durch den Compiler funktioniert daruberhinaus nur dort,wo alle Prozessoren Zugriff auf alle Daten haben, also auf Systemen mit gemeinsa-mem Speicher, und selbst hier muss der Programmierer zur optimalen Ausnutzungder Caches die Aufteilung der Daten manuell regeln. FORTRAN 95 stellt fur diesenZweck einen ganzen Satz von Compiler-Direktiven zur Verfugung.

3.2 Threads

Datenparallelitat orientiert sich an den Daten. Komplementar dazu kann man sichan den Funktionen oder Kontrollflussen innerhalb eines Programms orientieren. DerKontrollfluss ist gewissermaßen das, was Sie mit ihrem Finger verfolgen, wenn Sieuber einem Ausdruck Ihres Quelltextes sitzen und dabei murmeln ”Jetzt ist er hier,und weil x < 0 ist, geht er hierhin . . .“. Die Grundidee bei der Funktionsparallelitatist, dass sich an einer Stelle im Programm Ihr Finger verdoppelt und sich auf einmalzwei Finger unabhangig voneinander durch das Programm bewegen (Abb. 3.1).

Die nebenlaufigen Verarbeitungsstrange innerhalb eines Programms werdenThreads (”Faden“) genannt. Um zu verstehen, wie sich ein Programm in mehrereThreads aufspalten und wieder vereinen lassen kann, mussen wir uns genauer an-schauen, was bei der Ausfuhrung eines Programms eigentlich passiert.

Ein Computerprogramm besteht aus einer Folge von Anweisungen. Diese Folgeist in einer Datei auf der Festplatte abgespeichert und wird beim Start des Programmsin den Hauptspeicher Ihres Rechners geladen. Dadurch wird Ihr Programm zu einemProzess. Zu diesem Prozess gehoren verschiedene Speicherbereiche.

Codesegment. Der Speicher in dem die Anweisungen des Programms liegen, heißtCodesegment.

Datensegment. Dies ist der Speicherbereich fur die globalen Variablen eines Pro-gramms.

Stack. Auf dem Stack werden die lokalen Variablen gespeichert, die nur beim Auf-ruf einer Funktion benotigt werden, nach Beendigung des Funktionsaufrufs abernicht mehr (automatische Variablen).

Page 50: [X.systems.press] Cluster Computing ||

40 3 Programmieransatze

thr_create thr_join

Zeit

Abb. 3.1. Parallelitat durch die Erzeugung nebenlaufiger Verarbeitungsstrange (Threads).

Heap. Hier wird der explizit und dynamisch vom Programm angeforderte Speicherbereitgestellt. In C ist es die malloc-Funktion, mit der sich ein Programm Teilevom Heap reservieren kann, in C++ dient hierzu der new-Operator.

Daneben gehoren zu einem Prozess eine Reihe von Tabellen, in denen z. B. uber offe-ne Dateien oder bestehende Netzwerkverbindungen buchgefuhrt wird. Auch die Re-gisterinhalte des Prozessors gehoren zu einem Prozess. Ein besonders wichtiges Re-gister ist der Befehlszeiger (instruction pointer), der die Speicheradresse der nachs-ten auszufuhrenden Anweisung enthalt (quasi der oben erwahnte Finger).

Ein Prozess ist etwas dynamisches: wahrend seiner Ausfuhrung andern sich diezum Prozess gehorenden Speicherbereiche, die Tabellen und die Registerinhalte. Zujedem Zeitpunkt enthalten die Prozessdaten eine Momentaufnahme der Programm-ausfuhrung. Man kann einen Prozesses jederzeit suspendieren und zu einem spaterenZeitpunkt wieder fortsetzen, solange man sich zwischendurch nur die komplettenProzessdaten merkt.

In einem Multi-Tasking-Betriebssystem wie Unix passiert dies einige hundertMal in jeder Sekunde. Ein Prozess wird fur ein paar Millisekunden ausgefuhrt, dannsuspendiert und durch einen anderen Prozess ersetzt. Ein besonderer Prozess, dersog. Scheduler, wacht daruber, dass alle suspendierten Prozesse haufig genug fur ei-ne kurze ”Zeitscheibe“ reaktiviert werden, um uns die Illusion einer kontinuierlichen,parallelen Bearbeitung mehrerer Prozesse zu geben. Auf SMP-Maschinen verteiltder Scheduler die wartenden Prozesse auf mehrere Prozessoren, was den Durchsatzsolcher Maschinen naturlich erhoht. Es liegt nahe, diese Art der Parallelitat fur eige-ne Anwendungen auszunutzen. Das ist im Prinzip moglich, und zwar dank zweierbesonderer Fahigkeiten von Prozessen:

• Ein Prozess kann andere Prozesse erzeugen.• Zwei Prozesse konnen miteinander kommunizieren.

Auf diesen Fahigkeiten basiert das komplette Unix-Betriebssystem. Beim Hochfah-ren eines Unix-Systems wird nur ein einziger Prozess namens init gestartet. DieserProzess existiert solange bis das System wieder heruntergefahren wird. Hauptaufga-be von init ist es, andere wichtige Prozesse zu starten, die wiederum andere Prozes-se starten usw., bis Sie schließlich Ihren Login-Bildschirm erhalten. init ist quasidie Mutter aller Prozesse.

Die Erzeugung eines Prozesses unter Unix geschieht mit dem fork-Befehl. Die-ser Befehl konnte genausogut clone heißen (Notiz 3.4), denn der damit erzeugteKindprozess ist eine identische Kopie des Elternprozesses zum Zeitpunkt des fork-

Page 51: [X.systems.press] Cluster Computing ||

3.2 Threads 41

Aufrufes: die Speicherbereiche des Elternprozesses (Code, globale Daten, Stack,Heap) werden ebenso kopiert wie die Tabellen und Registerinhalte. Eltern- und Kind-prozess fuhren ab der fork-Anweisung deshalb das gleiche Programm aus. Da bei-de Prozesse jedoch vom Betriebssystem unterschiedliche Prozessnummern zugeteiltbekommen, konnen sie in Abhangigkeit dieser Nummer verzweigen und unterschied-liche Anweisungen ausfuhren. Der Elternprozess kann außerdem mit dem wait-Befehl an geeigneter Stelle auf die Beendung des Kindprozesses warten. Im Prin-zip kann man also mit dem fork-wait-Mechanismus nebenlaufige Verarbeitungs-strange wie in Abb. 3.1 erzeugen. Das ware allerdings aus folgenden Grunden nichtsehr effizient:

• Das Kopieren der kompletten Prozessdaten (Code, globale Daten, Heap etc.) kos-tet Zeit und macht fork damit zu einem teuren Befehl (Notiz 3.2).

• Eltern- und Kindprozess verfugen nicht uber gemeinsame Variablen. Der Daten-austausch zwischen Prozessen muss daher explizit erfolgen. Die dazu verfugba-ren Methoden (Pipes, Sockets, etc.) sind vergleichweise langsam.

Der fork-Befehl erzeugt einen kompletten Prozess, und das ist mehr, als wir ei-gentlich wollen. Um nur einen ”zweiten Finger“ durch unseren Code laufen zu las-sen, brauchen wir nur eigene Register (insbesondere einen eigenen Befehlszeiger)und einen eigenen Stack (fur die Funktionsaufrufe). Ein derart abgespeckter Prozessheißt Leichtgewichtsprozess oder Thread (Faden). Ein Thread ist allein nicht ”le-bensfahig“, denn er benotigt immer den Code, den globalen Speicher, den Heap unddie Tabellen eines ausgewachsenen Prozesses.

Ein Prozess kann Threads erzeugen und damit nebenlaufige Anweisungsstrangeschaffen wie in Abb. 3.1. Die Erzeugung von Threads ist dabei ein schneller Vorgang,da nur neue Registerinhalte und Platz fur einen neuen Stack angelegt werden mussen.Es ist daher nicht unublich, dass ein Prozess hunderte von Threads erzeugt, wie z. B.bei Webservern, die fur jede Anfrage einen Thread erzeugen, der diese Anfrage be-arbeitet. Threads kommunizieren miteinander und mit dem Elternprozess durch dieVariablen im gemeinsamen Speicherbereich (Heap und globale Daten). Auf Multi-prozessoren kann das Betriebssystem jedem Thread einen eigenen Prozessor zuteilenund damit echte Parallelverarbeitung herstellen.

Fur die praktische Programmierung mit Threads gibt es eine standardisierte Pro-grammierschnittstelle namens PThreads. Das ”P“ steht dabei fur POSIX, PortableOperating Systems Interface, einer Sammlung definierter Programmierschnittstellenzu den Betriebssystem-Funktionen. Die meisten Unix-Implementierungen sind PO-SIX-konform und enthalten damit die PThreads-Schnittstelle.

Wir stellen Ihnen die Programmierung mit POSIX-Threads am Beispiel der nu-merischen Integration vor. Listing 3.1 berechnet mit der schon erwahnten Mittel-punktsregel (1.12) das Integral

∫ 1

0

√1− x2 dx =

π4

. (3.1)

Dazu soll unser Programm p Threads erzeugen, die wir mit 0,1, . . . , p− 1 durchnu-merieren. Der Thread mit der Nummer k ist dann fur die Aufsummierung an den

Page 52: [X.systems.press] Cluster Computing ||

42 3 Programmieransatze

Stutzstellen xk,xk+P,xk+2P, . . . zustandig (Abb. 1.4). Die Teilsummen aller Threadsergeben zusammen das gewunschte Integral.

Die Aufgabe der main-Routine besteht im Wesentlichen darin, die Threads zuerzeugen und dann auf die Beendigung der Threads zu warten. Erzeugt werden dieThreads in Zeile 47 mit

pthread_create(&tid, &attr, integral, (void *)k);

Im ersten Parameter liefert die Funktion pthread create eine Referenz auf denerzeugten Thread zuruck, die wir spater noch brauchen, um auf die Beendigung desThreads zu warten. Mit dem zweiten Parameter konnen Eigenschaften des Threadsfestgelegt werden. Die restlichen beiden Parameter bestimmen, was der Thread ma-chen soll: der erste dieser Parameter gibt die Startfunktion an. Das ist die Funktion,mit deren Ausfuhrung der Thread beginnt. Hier kann Zeiger auf eine beliebige Funk-tion mit dem Prototyp

void * start_routine(void *arg)

stehen. In unserem Fall ist das calculate, die die eigentliche Integration ausfuhrt.Der letzte Parameter von pthread create enthalt einen Pointer auf das Argu-ment fur die Startfunktion. In unserem Fall ist das die laufende Nummer des Threads,damit die die Integrationsroutine weiß, fur welche Stutzstellen sie zustandig ist.

Mit pthread create wird also ein neuer Verarbeitungsstrang gestartet, dermit der Ausfuhrung von integrate beginnt. Der Thread endet, wenn die Start-funktion endet. Mit

pthread_join(tid, NULL);

kann an anderer Stelle auf die Beendigung des Threads tid gewartet werden. Derzweite Parameter von pthread join dient dazu, den Ruckgabewert der Startfunk-tion abzufragen. Davon machen wir hier allerdings keinen Gebrauch, deshalb dieNULL.

Die erzeugten Threads fuhren parallel die Funktion calculate aus und berech-nen dabei jeweils eine Teilsumme. Am Ende von integral wird die Teilsummeauf die globale Variable resultat addiert, die nach Beendigung aller Threads dasEndergebnis enthalt. Hierbei muss man ausschließen, dass zwei Threads die globaleVariable gleichzeitig beschreiben, denn das Ergebnis einer uberlappenden Schreib-operation ist undefiniert. Wir mussen also sicherstellen, dass der Schreibbefehl in Zei-le 24 zu jedem Zeitpunkt von nur einem Thread ausgefuhrt wird. Code-Abschnitte,die nur von einem Thread ”betreten“ werden durfen, nennt man kritische Abschnit-te. Geschutzt werden kritische Abschnitte durch die sog. Mutex-Variablen. Mutexsteht fur mutual exclusive, und eine Mutex-Variable funktioniert wie ein Turschlossmit einem Schlussel. Nur wer den Schlussel hat, kann den Raum betreten. Mit derFunktion pthread mutex lock versucht ein Thread, den Schlussel zu bekom-men. Diese Funktion stellt sicher, dass nur ein Thread den Schlussel hat. Nach Been-digung des kritischen Abschnittes muss der Thread mit pthread mutex unlockden Schlussel aber wieder abgeben, sonst warten die anderen Threads ewig. Eine

Page 53: [X.systems.press] Cluster Computing ||

3.2 Threads 43

Listing 3.1. Das Programm threadint.c, parallele numerische Integrations mit Threads.

#include <stdio.h>#include <stdlib.h>#include <math.h>#include <pthread.h>

5 #include <sys/time.h>#define MAX_THREAD 100

double pintegral(double (*f)(double), double a, double b,long n, int k, int tasks); / * s i e h e p i n t e g r a l . c * /

10long n; / * Zahl d e r S t u t z s t e l l e n * /int p; / * Zahl d e r a k t i v e n Threads * /double resultat; / * n u m e r i s c h e r Wert des I n t e g r a l s * /pthread_mutex_t my_mutex; / * s c h u t z t r e s u l t a t * /

15double f(double x) {

return sqrt(1.0-x*x);}

20 void * calculate(void *parm) {int me=*((int *)parm);double x=pintegral(f, 0.0, 1.0, n, me, p);pthread_mutex_lock(&my_mutex); / * Beginn seq . A b s c h n i t t * /resultat+=x;

25 pthread_mutex_unlock(&my_mutex); / * Ende seq . A b s c h n i t t * /return NULL;

}

int main(int argc, char *argv[]) {30 int thread_k[MAX_THREAD], k;

double T;struct timeval tv;pthread_t thread_id[MAX_THREAD], tid;pthread_attr_t attr;

35p=1; n=1000000; / * D e f a u l t w e r t e * /if (argc>=2) n=atol(argv[1]);if (argc>=3) p=atoi(argv[2]); p=p>MAX_THREAD ? MAX_THREAD : p;pthread_attr_init(&attr); / * E i g e n s c h a f t e n d e r Threads * /

40 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);gettimeofday(&tv, NULL);T=tv.tv_sec+tv.tv_usec/1000000.0;resultat=0.0;pthread_mutex_init(&my_mutex, NULL);

45 for (k=0; k<p; ++k) { / * p Threads e r z e u g e n * /thread_k[k]=k;pthread_create(&tid, &attr, calculate, &thread_k[k]);thread_id[k]=tid;

}50 for (k=0; k<p; ++k) / * war te , b i s a l l e Threads b e e n d e t wurden * /

pthread_join(thread_id[k], NULL);gettimeofday(&tv, NULL);T=tv.tv_sec+tv.tv_usec/1000000.0-T;printf(” I n t . = %15.12g : %d Threads , %6.4g Sek .\ n ”, resultat, p, T);

55 return EXIT_SUCCESS;}

Page 54: [X.systems.press] Cluster Computing ||

44 3 Programmieransatze

Terminal Session 3.1. Resultat von threadint.c auf einer SMP-Maschine mit vier CPUsund 225 Stutzstellen.bauke@rhea:˜$ for p in ‘seq 1 8‘; do ./threadint 33554432 $p; doneInt. = 0.785398163398: 1 Threads, 12.1017 Sek.Int. = 0.785398163398: 2 Threads, 6.0553 Sek.Int. = 0.785398163398: 3 Threads, 4.0636 Sek.Int. = 0.785398163398: 4 Threads, 3.1678 Sek.Int. = 0.785398163398: 5 Threads, 3.4551 Sek.Int. = 0.785398163398: 6 Threads, 3.3155 Sek.Int. = 0.785398163398: 7 Threads, 3.2324 Sek.Int. = 0.785398163398: 8 Threads, 3.2616 Sek.

derartige Koordinierung ist bei reinen Lesezugriffen auf globale Variable nicht notig,calculate verwendet Variable wie p und n ungeschutzt.

Die Anzahl der Stutzstellen sowie die Anzahl der Threads werden dem Pro-gramm threadint.c uber die Kommandozeile mitgegeben. Terminal Session 3.1zeigt das Resultat auf einer Vier-Prozessor-SMP-Maschine. Mit zwei Threads betragtdie Laufzeit nur 50 % der sequentiellen Laufzeit, bei drei Threads sind es 33,6 %, undvier Threads reduzieren die Laufzeit gar auf 26 %. Das ist ein nahezu idealer Spee-dup. Wie zu erwarten, bringen mehr als vier Threads keinen weiteren Gewinn.

Wenn Sie selbst mit threadint.c experimentieren wollen, sollten Sie beimLinken -lpthread (die POSIX-Threads-Bibliothek) und -lm (die Mathematik-Bibliothek fur die Quadratwurzel) angeben.

Unser Beispiel konnte Ihnen naturlich nur einen kleinen Eindruck von der Thread-Programmierung vermitteln. Wenn Sie mehr erfahren mochten, sollten Sie die ein-schlagige Literatur [116] konsultieren. Ihnen ist aber hoffentlich klar geworden, dassSie bei der Thread-Programmierung als Programmierer mehr Verantwortung tragenals bei der Programmierung mit FORTRAN 95 oder HPF. Sie sind nicht nur dafur ver-antwortlich, kritische Code-Abschnitte zu schutzen und die Mutex-Variablen nachGebrauch freizugeben. Sie mussen auch die Parallelisierung explizit programmie-ren und dabei z. B. die Granularitat selbst festlegen. Die POSIX-Threads-Bibliothekbietet dazu allerlei Unterstutzung, z. B. die Moglichkeit, zur Laufzeit die Zahl derverfugbaren Prozessoren zu ermitteln, aber Sie mussen diese Information explizitverarbeiten.

Belohnt werden Sie fur diese Muhen mit einem Mechanismus, der sehr flexibelist. Mit Threads konnen Sie jeden parallelen Algorithmus effizient implementieren.Dadurch, dass die Thread-Erzeugung und die Kommunikation uber gemeinsame Va-riable sehr schnell sind, eignen sich Threads auch fur feingranulare Parallelitat, al-lerdings nur auf Systemen mit gemeinsamem Speicher. Fur lose gekoppelte Systememit verteiltem Speicher mussen wir ein anderes Programmiermodell diskutieren.

3.3 Nachrichtentransfer

Bei der Thread-Programmierung stand die Parallelisierung des Kontrollflusses imMittelpunkt. Der Datenaustausch zwischen den Threads wurde dagegen en passantdurch gemeinsame Variable erledigt. Bis auf die Koordinierung von Schreibzugriffenmussten wir nicht viel dafur tun.

Page 55: [X.systems.press] Cluster Computing ||

3.3 Nachrichtentransfer 45

M P

P

M

P

M

P

M

P M

M

P

M

P

M

P

Interconnect

Abb. 3.2. Nachrichtentransfer als Programmiermodell fur Cluster.

Das andert sich, wenn wir Systeme mit verteiltem Speicher programmieren.Auch hier wird der Kontrollfluss explizit parallelisiert, die Verarbeitungsstrange wer-den aber nicht mehr durch kleine flinke Threads realisiert sondern durch ausgewach-sene Prozesse, die im Falle von Clustern sogar auf unterschiedlichen Rechnern lau-fen. In einer solchen Umgebung steht der Datenaustausch zwischen den Prozessenim Mittelpunkt des Interesses.

Das Programmiermodell fur Systeme mit verteiltem Speicher basiert auf der Vor-stellung, dass Prozesse untereinander Nachrichten verschicken (Abb. 3.2). Die grund-legenden Kommandos werden also Sende- und Empfangsbefehle sein. Wie bei derThread-Programmierung sind auch hier die Kommandos als Bibliotheksroutinen im-plementiert, die uber eine Programmierschnittstelle von C-, C++- oder FORTRAN-Programmen aus aufgerufen werden konnen. Als Standard hat sich hier das MessagePassing Interface (MPI) etabliert [59]. Implementierungen dieses Standards sind freiverfugbar (siehe Abschnitt 6.1).

Listing 3.2 zeigt das Beispiel der parallelen numerischen Integration, diesmalmit MPI statt mit POSIX-Threads. Die MPI-Funktionen erkennt man an dem PrefixMPI . Die genaue Bedeutung dieser Befehle diskutieren wir spater im Kapitel 7, hiersoll es zunachst nur um den groben Ablauf gehen.

Das Programm mpiint.c wird ubersetzt und gegen die MPI-Bibliothekengelinkt. Teil jeder MPI-Implementierung ist ein Laufzeitsystem, das den gleich-zeitigen Start des ubersetzten Programmes auf mehreren Knoten eines Clustersermoglicht. Wie das genau funktioniert, steht in Abschitt 6.1. Wir gehen davon aus,dass mehrere Prozesse des Programms mpiint.c auf verschiedenen Knoten unse-res Clusters laufen.

Jeder Prozess stellt zunachst mittels MPI Comm size fest, wieviele Prozes-se insgesamt gestartet wurden (nprocs). Danach wird der eigene Rang ermittelt

Page 56: [X.systems.press] Cluster Computing ||

46 3 Programmieransatze

Listing 3.2. Das Programm mpiint.c zeigt die auf Nachrichtentransfer basierende parallelenumerische Integrations mit MPI.

#include <stdio.h>#include <stdlib.h>#include <math.h>#include ” mpi . h ”

5double pintegral(double (*f)(double), double a, double b,

long n, int k, int tasks); / * s i e h e p i n t e g r a l . c * /

double f(double x) {10 return sqrt(1.0-x*x);

}

int main (int argc, char *argv[]) {int myrank, nprocs, src;

15 MPI_Status status;double result, x, T;long n=1000000;

MPI_Init(&argc, &argv);20 MPI_Comm_size(MPI_COMM_WORLD, &nprocs);

MPI_Comm_rank(MPI_COMM_WORLD, &myrank);if (argc==2)

n=atol(argv[1]);T=MPI_Wtime();

25 result=pintegral(f, 0.0, 1.0, n, myrank, nprocs);if (myrank>0)

MPI_Send(&result, 1, MPI_DOUBLE, 0, 99, MPI_COMM_WORLD);else {

for (src=1; src<nprocs; ++src) {30 MPI_Recv(&x, 1, MPI_DOUBLE, src, 99, MPI_COMM_WORLD, &status);

result+=x;}T=MPI_Wtime()-T;printf(”%l d S t u e t z s t . , %d Proz . Z e i t %6.4g Sek , E r g e b n i s %15.12g\n ”,

35 n, nprocs, T, result);}MPI_Finalize();return EXIT_SUCCESS;

}

(MPI Comm rank liefert myrank). Mit dem Rang werden alle gestarteten Prozes-se bei null beginnend durchnummeriert. Der Rang dient der Identifizierung und derAdressierung eines Prozesses.

Der eigene Rang und die Gesamtzahl der gestarteten Prozesse reichen aus, umjedem Prozess die Berechnung seiner Teilsumme zu ermoglichen (pintegral).Danach mussen diese Teilsummen nur noch zusammengefasst werden. Dazu sendenalle Prozesse mit einem Rang großer null ihr Teilergebnis mit dem Befehl MPISend an den Prozess mit Rang null. Prozess null sendet nichts, sondern durchlauftstattdessen eine Schleife, in der die Teilergebnisse aller anderen Prozesse empfangen(MPI Recv) und zum eigenen Ergebnis addiert werden. Prozess null ist dann alseinziger im Besitz des Ergebnisses und gibt dieses aus.

Page 57: [X.systems.press] Cluster Computing ||

3.4 Notizen 47

Dieses einfache Beispiel verdeutlicht einige besondere Merkmale der MPI-Pro-grammierung. Bei der Parallelisierung durch Threads wurde ein Prozess gestartet,der daraufhin selbst mehrere (Leichtgewichts-)Prozesse erzeugte und am Ende wie-der ”einsammelte“. Bei der MPI-Version ist dagegen die Anzahl der laufenden Pro-zesse uber die gesamte Laufzeit konstant. Zwar bietet MPI auch die Moglichkeit, dieZahl der Prozesse dynamisch, d. h. wahrend der Laufzeit den Erfordernissen anzu-passen, aber in typischen MPI-Anwendungen ist die Menge der Prozesse statisch.Typisch (aber nicht zwingend) ist es auch, dass alle Prozesse aus ein und demsel-ben Programm erzeugt werden. Das unterschiedliche Verhalten der Prozesse wirddabei einzig durch Verzweigung an Hand des Ranges verursacht. In Anlehnung andie Flynn’sche Terminologie (Notiz 2.1) nennt man diese Variante SPMD, singleprogram, multiple data.

3.4 Notizen

3.1 Parallele Programmiersprachen. Falls Sie sich fragen, wo die dediziert paral-lelen Programmiersprachen geblieben sind: Es gibt sie, oder besser gesagt, es gabsie. Anfang der 1990er Jahre erreichte die Forschung auf diesem Gebiet ihren Hohe-punkt. Zu den Ergebnissen zahlten Sprachen wie Occam, Linda, Sisal, um nur einigezu nennen. Keine dieser Sprachen wird heute in nennenswertem Umfang benutzt,und es durfte schwierig sein, einen entsprechenden Compiler aufzutreiben. Uber dieGrunde fur die mangelnde Akzeptanz kann man nur spekulieren, aber eine wichti-ge Rolle spielen sicher die unzahligen Zeilen von Code in etablierten Sprachen wieFORTRAN und C, die bereits existieren und auf parallele Systeme portiert werden.Das scheint mit Bibliotheken (MPI, PThreads) oder mit kompatiblen Spracherweite-rungen (FORTRAN 90) einfacher zu sein als eine komplette Neucodierung in eineranderen Sprache.

3.2 Prozesserzeugung. Der fork-Befehl, mit dem ein Prozess eine Kopie von sichselbst erzeugen kann, dient in der Regel der Erzeugung verschiedener Prozesse. Da-zu fuhrt der Kind-Prozess unmittelbar nach fork den Befehl exec aus, der dieeigenen Prozessdaten durch die einer ausfuhrbaren Datei ersetzt und diesen neuenProzess startet. Wenn der Kindprozess aber durch einen neuen Prozess ersetzt wird,macht es keinen Sinn, vorher noch die kompletten Prozessdaten vom Elternprozessauf den Kindprozess zu ubertragen. Unter Unix werden die Speicherbereiche desElternprozesse deshalb zunachst vom Kindprozess mitbenutzt und erst beim erstenschreibenden Zugriff wirklich kopiert (copy-on-write). Beim fork-exec Mechanis-mus muss dann nur sehr wenig kopiert werden und die Prozess-Erzeugung ist rechteffizient.

3.3 Threads auf Uniprozessoren. Thread-Programmierung lohnt sich auch fur Sys-teme mit nur einem Prozessor. Das gilt zwar nicht unbedingt fur die typischen tech-nisch-wissenschaftlichen Anwendungen mit ihrer CPU-Lastigkeit, aber Anwendun-gen, die haufig auf andere Hardware-Komponenten wie Festplatten, CDROM oderNetzwerkkarte zugreifen. Diese Peripherie-Gerate sind viel langsamer als die CPU.

Page 58: [X.systems.press] Cluster Computing ||

48 3 Programmieransatze

Anstatt nun bei einem Dateizugriff lange tatenlos darauf zu warten, bis die Festplattedie gewunschten Daten gefunden hat, kann ein Programm den Dateizugriff an einenThread delegieren und in der Zwischenzeit etwas Nutzliches machen.

3.4 fork und clone. Unter Linux gibt es tatsachlich einen Befehl namens clone,der ahnlich wie fork eine Kopie des aufrufenden Prozesses erzeugt. Anders als beifork teilt sich der Kindprozess Teile des Ausfuhrungskontextes wie Speicher undDateideskriptoren mit dem Elternprozess. Außerdem erlaubt clone die Angabe ei-ner Funktion, mit deren Aufruf der Kindprozess startet. Das ist schon fast die Funk-tionalitat von pthread create, und clone wurde tatsachlich zur Programmie-rung von Threads eingefuhrt. Da die clone-Systemfunktion aber nur unter Linuxverfugbar ist, sollten Sie aus Grunden der Portabilitat darauf verzichten.

3.5 OpenMP. Eine etwas andere Art der Thread-Programmierung bietet OpenMP,ebenfalls eine standardisierte Programmierschnittstelle [123]. Hier uberlasst man dasErzeugen und Zusammenfugen von Threads weitgehend dem Compiler, ahnlich wiebei den datenparallelen Erweiterungen in FORTRAN 90, FORTRAN 95 und HPF.Der Compiler enthalt die Informationen uber zu parallelisierende Abschnitte durchCompiler-Direktiven (pragmas). Im Gegensatz zu reinen Bibliotheken wie POSIX-Threads erfordert eine Unterstutzung von OpenMP betrachtliche Eingriffe in denCompiler. Wohl deshalb wird OpenMP vom gcc, dem wichtigsten freien Compilerin der Linux-Beowulf-Welt, (noch) nicht unterstutzt. Fur uns Grund genug, OpenMPnur in den Anmerkungen zu erwahnen. Wenn Sie OpenMP dennoch ausprobierenwollen: der fur Linux kostenlos erhaltliche C/C++-Compiler von Intel unterstutztOpenMP.

3.6 PVM. Das Message Passing Interface (MPI) hat sich als Standard fur das nach-richtenbasierte parallele Programmieren etabliert. Vorganger von MPI ist die ParallelVirtual Machine, kurz PVM. Genau wie MPI bietet auch PVM eine Bibliothek zumNachrichtentransfer sowie eine Laufzeitumgebung zur Verwaltung von Prozessen.PVM wird augenscheinlich nicht mehr weiterentwickelt, die letzte Version stammtvom September 2001, siehe [137].

Page 59: [X.systems.press] Cluster Computing ||

Teil II

Technik

Page 60: [X.systems.press] Cluster Computing ||

4

Cluster-Design

Speed, quality, price. Pick any two.

James M. Wallace

Computers in the future may weigh no more than 1.5 tons.

aus ”Popular Mechanics“, 1949

Bevor Sie sich in das Abenteuer Cluster-Computing sturzen und einen Linux-Clusterbauen oder kaufen, mussen Sie einige wichtige Desingentscheidungen treffen. Dennein Cluster ist kein Produkt von der Stange, er sollte auf die individuellen Bedurf-nisse seiner Nutzer zugeschnitten werden. Andernfalls kann sich ein Cluster bald alsteure Fehlinvestition herausstellen. Wenn Sie dieses Kapitel gelesen haben, wissenSie, worauf Sie beim Entwurf Ihres Clusters achten mussen. Allerdings entwickeltsich die Hardware so schnell, dass Sie von gedruckten Ratgebern wie dem vorliegen-den Buch nur eine erste Orientierung erwarten durfen.

4.1 Grundlegende Komponenten

Auch wenn kein Cluster-Computer einem anderen gleicht, so bestehen doch alleCluster aus den gleichen Grundkomponenten. Ein Cluster ist eine Ansammlungvon Standard-PCs. Im Cluster-Jargon heißen diese auch Knoten oder englisch no-des. Samtliche Knoten werden durch ein Hochgeschwindigkeitsnetzwerk verbunden.Meistens kommt ein switched network mit sternformiger Topologie zum Einsatz,siehe Abb. 4.1 und Abschnitt 2.2. Netzwerke dieser Topologie sind wegen ihrer Fle-xibilitat und den im Abschnitt 2.2 dargestellten Vorteilen weit verbreitet. Cluster mitanderen Topologien wie Tori sind eher die Ausnahme.

Nach ihrer Funktion unterscheidet man server nodes und compute nodes. Diecompute nodes sind die Arbeitspferde eines Clusters. Auf ihnen werden samtlicherechenintensive Probleme gelost. Die server nodes stellen dagegen die fur den Clus-terbetrieb notwendige Infrastruktur zur Verfugung.

• Server-Knoten exportieren an die compute nodes ein Netzwerkdateisystem, sodass von jedem der compute nodes auf den gleichen Datenbestand zugegriffenwerden kann.

Page 61: [X.systems.press] Cluster Computing ||

52 4 Cluster-Design

Switch

Netzwerk

compute nodes

server node

zum Campusnetz

Abb. 4.1. Grundlegender Aufbau eines kleinen Clusters.

• Mit Hilfe der Server-Knoten lasst sich das Betriebssystem eines compute nodevollautomatisch installieren.

• Server-Knoten sind die zentrale Arbeitsplattform der Cluster-Nutzer. Die Nutzerkonnen sich meist nur auf einem Server-Knoten, dem frond end node, einloggen.Hier ubersetzen sie ihre Programme und ubergeben Rechenauftrage an ein Batch-System, siehe Abschnitt 6.2.

• Daruberhinaus stellen Server-Knoten den compute nodes und den Nutzern nochweitere Dienste zur Verfugung, die wir in Kapitel 5 und 6 besprechen.

Die Bezeichnung der verschiedenen Knotentypen ist nicht ganz einheitlich. Fur diehier gebrauchten Begriffe server node bzw. compute nodes sind auch head node,frontend node oder login node bzw. working nodes gebrauchlich.

Abbildung 4.1 zeigt einen kleinen Cluster mit nur einem server node und viercompute nodes. Bei kleineren Clustern ist ein einziger server node meist ausreichend.Je mehr compute nodes ein Cluster hat, desto sinnvoller ist es jedoch, fur einzelneDienste dedizierte Server-Knoten aufzusetzen oder einzelne Server-Knoten und de-ren Dienste sogar redundant (also mehrfach) auszulegen. Bei einem Cluster mittlererGroße konnte man z. B. einen Server-Knoten fur die Interaktion mit den Nutzernreservieren, wahrend ein zweiter alle anderen Dienste ubernimmt.

4.2 Anforderungen an einen High-Performance-Cluster

Zwar ist der grundlegende Aufbau aller Cluster gleich, im Detail, z. B. der Ausstat-tung der Knoten und der Wahl der Netzwerktechnologie, ergeben sich jedoch großeGestaltungsspielraume, die Sie beim Entwurf Ihres Clusters auch nutzen sollten.

Wer einen High-Performance-Cluster plant, muss zunachst untersuchen, welcheAnforderungen die Anwendungsprogramme stellen, die spater auf dem Cluster lau-

Page 62: [X.systems.press] Cluster Computing ||

4.3 Netzwerktechnik 53

fen sollen. Denn sie bestimmen, wie verschiedene Komponenten des Clusters ausge-legt sein mussen. Ganz grob lassen sich Anwendungsprogramme in die Kategorien

• CPU-intensive Anwendungen,• speicher-intensive Anwendungen,• ein-ausgabe-intensive Anwendungen,• kommunikations-intensive Anwendungen und• Anwendungen mit anderen speziellen Anforderungen

einteilen. Naturlich gibt es auch Mischformen, z. B. Programme, die sowohl hoheAnforderungen an CPU- als auch Kommunikations-Leistung stellen. Unter Anwen-dungen mit anderen speziellen Anforderungen fallt z. B. die Echtzeitbildbearbeitung,die spezielle Videohardware zur Bildein- und -ausgabe benotigt.

Zumindest im technisch-wissenschaftlichen Umfeld fuhren praktisch alle Anwen-dungen sehr viele Fließkommaoperationen durch. Die CPUs eines Clusters mussenalso in der Summe eine hohe Fließkommaleistung erbringen. Fur einige typischeProbleme kann man die Anzahl der Fließkommaoperationen, die zu ihrer Losungbenotigt wird, einfach berechnen. So muss ein Computer z. B. ca. 2n3/3 Fließkom-maoperationen durchfuhren, um ein dicht besetztes lineares Gleichungssystem mit nUnbekannten zu losen. Soll der Cluster also je Sekunde zehn solche Gleichungssys-teme mit jeweils 1000 Unbekannten losen, so muss er eine effektive Leistung von ca.10 GFlops erbringen konnen.

In den Abschnitten 1.5 und 1.4 haben wir jedoch gesehen, dass als Gesamtleis-tung eines Clusters nicht einfach das Produkt aus der Einzelleistung eines computenode und deren Anzahl angenommen werden kann. Die Granularitat der zu losen-den Aufgabe und die Charakteristika des Netzwerkes haben einen ganz wesentlichenEinfluss auf die Gesamtleistung eines Clusters. Anwendungen, die sehr große Daten-mengen verarbeiten, stellen daruber hinaus erhohte Anforderungen an Arbeits- undMassenspeicher. Die nachsten Abschnitte sollen Ihnen helfen, eine Konfiguration derKnoten-Hardware zu finden, die optimal auf die Bedurfnisse Ihrer Anwendungen zu-geschnitten ist. Die wichtigsten Entscheidungen betreffen dabei die Fragen:

• Aus wievielen compute nodes soll der Cluster bestehen?• Haben die compute nodes nur eine CPU oder sollen SMP-Systeme eingesetzt

werden?• Welche CPU-Architektur soll verwendet werden?• Besitzen die compute nodes eine eigene Festplatte oder kommen sog. diskless

nodes zum Einsatz?• Durch welche Netzwerktechnik werden die Knoten verbunden?

4.3 Netzwerktechnik

Grundvoraussetzung dafur, dass verschiedene Einzel-PCs gemeinsam ein Problemlosen konnen, ist das Netzwerk, das sie verbindet und uber das die PCs ihre gemein-same Arbeit koordinieren. Heute sind verschiedene Netzwerktechnologien verfugbar.

Page 63: [X.systems.press] Cluster Computing ||

54 4 Cluster-Design

Sie unterscheiden sich in ihren technischen Parametern (Bandbreite, Latenz und Ska-lierbarkeit) aber auch ihren Kosten. Die Wahl der Netzwerktechnologie hat beson-ders bei kommunikationsintensiven Anwendungen großen Einfluss auf die Gesamt-leistung eines Clusters. Je schneller das Netzwerk ist, desto kommunikationsintensi-ver durfen Ihre Anwendungen sein, ohne dass sie durch das Netzwerk ausgebremstwerden. Andererseits konnen die Kosten der Netzwerktechnik einen wesentlichenBetrag der Gesamtkosten eines Clusters ausmachen. Nicht selten sind die Kosten derNetztechnik pro Knoten genauso hoch wie die der gesamten restlichen Hardware ei-nes Knotens. Haben Sie ein festes Budget, mussen Sie die fur Sie richtige Balancezwischen einem Cluster mit vielen Knoten (hohe CPU-Leistung) aber preiswertemNetzwerk (geringe Bandbreite, hohe Latenz) und einem Cluster mit wenigen Knoten(geringe CPU-Leistung) aber teurem Netzwerk (hohe Bandbreite, geringe Latenz)finden.

4.3.1 Netzwerkhardware

Die Hardware eines Computer-Netzwerkes setzt sich aus den Netzwerkkarten (inter-face), derer jeder Knoten (mindestens) eine besitzt, Kabeln (network links) und beiswitched networks einem Switch (switch oder allgemeiner network device) zusam-men.

Ein Netzwerk-Interface liest Daten aus dem Arbeitsspeicher des Computers undverschickt diese in das Netz bzw. empfangt aus dem Netz ankommende Daten undschreibt diese in den Arbeitsspeicher. Mittlerweile werden viele Motherboards be-reits mit einem Ethernet-Interface (siehe unten) ausgestattet, Hochgeschwindigkeits-Netzwerk-Interfaces hingegen findet man im PC meist als PCI-Karte. Die Bandbreiteeiner Netzwerkkarte wird einerseits durch die Bandbreite der Netzwerktechnologieandererseits aber auch durch die Geschwindigkeit des Systembuses (in der Regeleine PCI-Variante) bestimmt, auf dem die Daten zwischen Arbeitsspeicher und Netz-werkkarte hin und her kopiert werden. Fruher war der Systembus deutlich breitbandi-ger als die verwendeten Netzwerktechnologien. Mittlerweile kann aber eine Hochge-schwindigkeits-Netzwerk-Karte den Systembus schnell an seine Leistungsfahigkeitbringen. Achten Sie deshalb bei der Wahl der Knoten-Hardware darauf, dass das Mo-therboard mit einem Systembus ausgestattet ist, der sinnvoll auf die Hochgeschwin-digkeits-Netzwerk-Karte abgestimmt ist.

In der Netzwerktechnik unterscheidet man Kommunikation im Halb- und Volldu-plexmodus. Im Vollduplexmodus konnen gleichzeitig Daten empfangen und gesendetwerden, ohne dass sich ein- und ausgehende Daten gegenseitig behindern. Arbeitetein Netzwerk im Halbduplexmodus, konnen zu einem Zeitpunkt von einem interfacenur entweder Daten empfangen oder gesendet werden. Alle heute in Cluster-Compu-tern verwendeten Netzwerktechniken unterstutzen den Vollduplexmodus. Allerdingskann es bei Ethernet durch Fehlkonfiguration vorkommen, dass das Netzwerk nur imHalbduplexmodus arbeitet.

Die (physische) Topologie eines Netzwerkes wird durch die verwendete Netz-werktechnologie festgelegt. Die fur Cluster-Cumputer relevanten Netzwerktechnolo-gien verwenden meist eine sternformige Topologie mit Switch, auch switched net-

Page 64: [X.systems.press] Cluster Computing ||

4.3 Netzwerktechnik 55

work genannt, siehe Abschnitt 2.2. Diese Topologie hat gegenuber anderen Topolo-gien einige praktische Vorteile. So haben technische Storungen wie defekte Kabelmeist nur lokale Auswirkungen. Wahrend in einer Sterntopologie nur der Knoten,den das defekte Kabel mit dem Switch verbindet, betroffen ist, wirkt sich bei z. B.bei einer Bus-Topologie ein defektes Kabel auf das gesamte Netz aus. Durch diesternformige Topologie lassen sich im laufenden Betrieb neue Knoten in das Netz in-tegrieren bzw. Knoten aus dem Netz entfernen, ohne dass sich Auswirkungen auf dieanderen Knoten ergeben. Switched networks sind darum die generische Netzwerkto-pologie fur Cluster-Computer. Wir gehen in diesem Buch, wenn es nicht explizitanderes geschrieben wird, von einem switched network aus.

In den Ports eines Switch laufen die Leitungen eines Netzwerkes zusammen.Einen Switch kann man sich wie eine große Schaltstation vorstellen. Seine Aufgabebesteht darin, Nachrichten, die von einem Quellinterface an einem Port ankommen,uber einen anderen Port an das Zielinterface zu schicken. Bei Ethernet (siehe unten)werden dazu Quell- und Zielinterface uber die sog. MAC-Adresse (Media AccessControl) identifiziert. Ein Ethernet-Switch verwaltet eine Tabelle, die jeden Port desSwitches logisch mit der MAC-Adresse des an dem Port angeschlossenen Interfacesverbindet. Soll ein Datenpaket an ein Interface mit einer MAC-Adresse gesendet wer-den, die sich noch nicht in dieser Tabelle befindet, so verschickt der Switch zunachsteine Rundnachricht, ein sog. Broadcast, wobei das Paket den Switch uber alle Portsverlasst. Der Switch kann danach detektieren, an welchem Port sich ein Interfacebefindet, das die Nachricht auch tatsachlich akzeptiert hat, und mit dieser Informa-tion seine Tabelle erweitern. Das nachste an diese MAC-Adresse adressierte Paketwird dann nur uber den Port verschickt, an dem das Zielinterface hangt. Die Arbeits-weise eines Switches hangt im Detail naturlich von der Netzwerktechnologie ab undunterscheidet sich von der eines Ethernet-Switches. Aber alles Switches ist gemein,dass sie fur jedes Datenpaket zwischen Quell- und Zielinterface eine Datenleitungschalten, die exklusiv diesem Datenpaket zur Verfugung steht.

Die Datenmenge, die ein Switch innerhalb einer gewissen Zeit weiterleiten kann,heißt backplane bandwidth. Leider ist sie in den meisten Fallen beschrankt, so dassz. B. eine beliebige Halfte der Knoten eines Clusters nicht mit der anderen Halfteseiner Knoten gleichzeitig mit der vollen Netzwerkbandbreite kommunizieren kann.Hat z. B. ein Gigabit Ethernet Switch (siehe unten) eine backplane bandwidth von16 GBit/s, so konnen maximal 16 Knoten gleichzeitig mit der maximalen Bandbrei-

Switch

Abb. 4.2. Einfaches switched network.

Page 65: [X.systems.press] Cluster Computing ||

56 4 Cluster-Design

Switch A

Switch B

Abb. 4.3. Komplexes switched network mit zwei Switches und gebundelter Verbindung zwi-schen diesen beiden Switches.

te von 1 GBit/s Daten austauschen. Die Bandbreite, mit der eine beliebige Halfte vonKnoten eines Clusters mit der anderen Halfte der Knoten gleichzeitig kommunizie-ren kann, wird auch Bisektionsbandbreite (bisection bandwidth) genannt. In einfa-chen Netzwerken mit nur einem Switch (siehe Abb. 4.2) sind Bisektionsbandbreiteund backplane bandwidth identisch. In Netzen mit einer komplexeren Topologie (sie-he Abb. 4.3) wird die Bisektionsbandbreite meist durch die Bandbreite der Verbin-dungen zwischen den Switches bestimmt. Um die Bandbreite zwischen zwei Swit-ches zu erhohen, werden diese oft uber mehrere Leitungen untereinander verbunden,die sich aber logisch als eine einzige Verbindung darstellen. Man spricht hierbei vontrunking. Eine ganz ahnliche Technik ist channel bonding, siehe Abschnitt 5.7.

Auf der Idee, einzelne hoher belastete Verbindungen durch mehrfach ausgelegteLeitungen zu realisieren, basiert auch die sog. fat-tree-Topologie. In dieser Topologiewerden die Knoten eines Netzes durch eine baumartige Struktur verbunden. Leiderzeigt sich, dass in einfachen baumartige Netzen Leitungen nahe der Wurzel deutlichstarker belastet werden als die nahe der Blatter (bei den Computern). Die fat-tree-Topologie lost dieses Problem, indem Verbindungen nahe der Wurzel durch mehr-fache Leitungen oder mit Leitungen hoherer Bandbreite hergestellt werden. Mannennt einen fat tree n-ar, wenn sich die Zahl der Verbindungen benachbarter Ebenen

Switch Switch Switch Switch

SwitchSwitch

Abb. 4.4. Netzwerk aus 16 Noten mit fat-tree-Topologie.

Page 66: [X.systems.press] Cluster Computing ||

4.3 Netzwerktechnik 57

um einen Faktor n erhoht. Damit die Switches nahe der Wurzel nicht immer mehrPorts benotigen, werden einzelne Knoten der Baumtopologie meist durch mehrereSwitches realisiert. So besteht die Wurzel des 4-aren fat tree in Abb. 4.4 aus zweiSwitches. In einer fat-tree-Topologie skaliert die Bisektionsbandbreite linear mit derAnzahl der Computer. Switches einiger Netzwerktechnologien arbeiten intern miteiner fat-tree-Topologie.

4.3.2 Netzwerktechnologien

Bei den Netzwerktechnologien kann nach Hard- und Softwaretechnologien unter-schiedenen werden. Die Software definiert gewissenmaßen die Sprache, in der Datenausgetauscht werden, wahrend die Hardware als Transportmedium dient. Die linguafranca der Cluster-Computer heißt TCP/IP, deren Grundlagen wir in Abschnitt 5.1beschreiben. Hardwareseitig sind heute funf verschiedene relevante Netzwerktechno-logien am Markt. Dies sind

• Gigabit Ethernet,• Myrinet-2000,• SCI,• InfiniBand und• QsNet.

Am weitesten verbreitet ist momentan Gigabit Ethernet, gefolgt von Myrinet-2000.Die verbleibenden drei Technologien findet man in bedeutend weniger Clustern alsGigabit Ethernet und Myrinet-2000. Allerdings durfte in Zukunft die Verbreitungspeziell von InfiniBand und QsNet noch zunehmen.

Gigabit Ethernet

Ethernet [140] ist die Netzwerktechnologie im PC-Bereich. Es ist zuverlassig, robust,preiswert und relativ einfach zu installieren. Die Wurzeln von Ethernet reichen bisin die spaten 1970er zuruck. Seit dem wurde Ethernet schon mehrmals fur tot er-klart, konnte sich aber dank mehrerer ”Frischzellenkuren“ aber immer wieder gegenneuere Techniken behaupten. So entstanden im Laufe der Jahre 10 MBit-Ethernet,100 MBit-Ethernet (Fast-Ethernet), 1 GBit-Ethernet und 10 GBit-Ethernet. Innerhalbdieser Grundvarianten gibt es nocheinmal verschiedene Versionen, die sich in ers-ter Linie durch die Art der verwendeten Leitungen (Koaxialkabel, verdrillte Kup-ferleitungen oder Glasfaser) und maximal zulassigen Leitungslangen unterscheiden.10 MBit-Ethernet-, Fast-Ethernet- und Gigabit-Ethernet-Karten, die verdrillte Kup-ferleitungen verwenden, sind untereinander kompatibel.

Fur den Einsatz in Cluster-Computern kommt praktisch nur Gigabit-Ethernet inFrage. Die Preise fur Gigabit-Ethernet-Hardware sind mittlerweile so stark gefallen,dass sein deutlich langsamerer Vorganger Fast Ethernet kaum noch als Kommunika-tionsnetz bei neuen Clustern Verwendung findet. Gigabit-Ethernet-Interfaces gibt esals Einsteckkarten fur den PCI-Bus. Auf dem meisten modernen Motherboards sindjedoch bereits ein oder gar zwei Gigabit-Ethernet-Interfaces installiert. Fest auf dem

Page 67: [X.systems.press] Cluster Computing ||

58 4 Cluster-Design

Motherboard installierte Gigabit-Ethernet-Interfaces sparen Platz und haben daruber-hinaus den Vorteil, dass sie ihre Daten nicht uber den PCI-Bus zwischen Netzwerk-Interface und Speicher austauschen mussen. Stattdessen sind sie uber einen schnel-leren Spezialbus an den Speicher angebunden. Onboard-Gigabit-Ethernet-Interfacessind darum den Einsteckkarten vorzuziehen.

Die Vernetzung erfolgt bei Ethernet mittels preiswerter Kupferkabel oder beiGigabit Ethernet auch mit Glasfaserkabeln. Letztere gelten als besonders robust.Kupferkabel fur Gigabit-Ethernet durfen maximal 25 m (Gigabit-Ethernet nach IE-EE 802.3z, heute kaum noch verwendet) bzw. 100 m (Gigabit-Ethernet nach IEEE802.3ab) lang sein. Bei Multimode-Glasfaserkabeln liegt das Langenlimit bei 550 mund bei Singlemode-Glasfaserkabeln bei 5 km. Im Cluster-Bereich erfolgt eine Giga-bit-Ethernet-Vernetzung in der Regel durch achtadrige verdrillte Kupferleitungen.

Das Angebot an Ethernet-Switches ist kaum uberschaubar. Grob lassen sich Swit-ches in sog. Layer-2-Switches, Layer-3-Switches und Switches, die auf noch hoher-en Layern arbeiten, aufteilen. Als Faustregel gilt, dass Switches, die auf hoherenLayern arbeiten, mehr ”Intelligenz“ und Funktionen bieten als jene, die auf niedrige-ren Layern arbeiten. Diese zusatzlichen Funktionen verursachen tendenziell hohereVerzogerungen bei der Weiterleitung von Datenpaketen. Fur einen Cluster-Computerist ein Layer-2-Switch mit wenigen Zusatzfunktionen meist ausreichend. Allerdingssollte er eine genugend große backplane bandwidth haben.

Ethernet ist wegen seiner relativ hohen Latenz (siehe Tabelle 4.1) nicht immerdie Netzwerktechnologie der ersten Wahl. Aber selbst wenn im Cluster die Kommu-nikation uber eine andere Technik lauft, wird meist fur Servicezwecke ein weiteresauf Ethernet basierendes TCP/IP Netzwerk installiert, siehe Abschnitt5.1. Die jungs-te Ethernetvariante, 10 GBit-Ethernet, ist bisher kaum verbreitet und wird sich wegenseiner relativ großen Latenz im Cluster-Bereich wohl auch nicht durchsetzen konnen.Anwendern, denen die Bandbreite von Gigabit-Ethernet nicht genugt, setzen eine derfolgenden Techniken ein.

Myrinet-2000

Das von Myricom [110] angebotene Myrinet ist heute die dominante Hochgeschwin-digkeits-Netzwerktechnologie in Cluster-Computern. Die Ubertragungsgeschwindig-keit von Myrinet ist großer und die Latenz deutlich kleiner als bei Gigabit-Ethernet.Knoten eines Myrinet-Clusters werden durch Switches und Glasfaserkabel verbun-den. Myrinet-Switches verwenden intern eine fat-tree-Topologie. Dadurch konnensie anders als z. B. Ethernet-Switches die volle Bisektionsbandbreite bereit stellen,so dass, auch wenn viele Knoten gleichzeitig kommunizieren, sie dies noch mit dervollen Netzwerkbandbreite tun konnen.

Myrinet verwendet das properitare GM-Protokoll (grand message). Auf demGM-Protoll aufsetzend kann wie bei Ethernet auch ein TCP/IP-Netz aufgebaut wer-den. Die Firma Myricom liefert neben der Hardware auch die gesamte notwendigeSoftware wie Treiber, MPI-Implementation und Diagnosesoftware. Die Treiber un-terstutzen alle gangigen Hardwarearchitekturen und Betriebssysteme.

Page 68: [X.systems.press] Cluster Computing ||

4.3 Netzwerktechnik 59

Tabelle 4.1. Charakteristika verschiedener Netzwerktechnologien und Datenaustausch imComputer uber den Hauptspeicher im Vergleich. Alle Werte sind nur als Richtwerte zu be-trachten. Tatsachlich erreichte Bandbreiten hangen z. B. auch von Chipsatz und verwende-ten Treiber ab, Hardwarepreise verandern sich im Laufe der Zeit. Daten zum Teil aus [40]entnommen.

Bandbreite Latenz Kosten proTechnologie Typ in MByte/s in µs Knoten in US-$ Hersteller

Hauptspeicher Bus > 1000 < 0,01

Fast Ethernet switched 11 70 ca. 25 diverse

Gbit Ethernet switched 110 30 ca. 100 diverse

Myrinet-2000 switched 248 6,3 ca. 1000 Myricom

SCI point-to-point 326 2,7 1100 bis 1600 Dolphin Inter-connect Sol.

InfiniBand switched 805 7,5 ca. 1900 diverse

QsNet, QsNetII switched 340 bzw. 900 ca. 1700 bzw. 3300 Quadrics

Da ein Myrinet-Netzwerk um ca. einen Faktor zehn teurer als Gigabit Ethernet ist,sollte unbedingt durch Tests belegt werden, dass geplante Anwendungen wirklich sostark von Myrinet profitieren, dass die Mehrausgaben gerechtfertigt werden konnen.

Scalable Coherent Interconnect

Scalable Coherent Interconnect (SCI) ist ein IEEE-Standard. Diese Technik wurde ur-sprunglich zur internen Vernetzung von Großrechnern konzipiert. Die norwegischeFirma Dolphin Interconnect Solutions [29] bietet auf SCI-Technologie basierendePCI-Karten nebst Linux-Treibern an. Die Treiber unterstutzen auch TCP/IP. IhreQuellen sind frei zuganglich und unterliegen der GPL.

Anders als bei Ethernet oder Myrinet erfolgt die Kommunikation in einem SCI-Netzwerk nicht uber einen Switch sondern von Punkt zu Punkt. Das Netzwerk hatdie Topologie eines zwei- oder dreidimensionalen Torus, siehe Abb. 2.3. BesondersAnwendungen, die vorwiegend zwischen in dieser Topologie benachbarten Knotenkommunizieren, profitieren von dieser Technik. Das Skalierungsverhalten ist danndeutlich besser als das eines switched ethernet. Der wohl großte Pluspunkt von SCIist die geringe Latenz. Beim Datenaustausch zwischen benachbarten Knoten ist dieLatenz mit knapp uber einer Mikrosekunde besonders niedrig. Leider steigt die La-tenz mit der Entfernung zwischen zwei Knoten an. Praktisch wird dadurch die Großevon mit SCI realisierbaren Netzwerken begrenzt. Selten betragt ihre Ausdehnung ineiner Dimension mehr als acht Knoten.

Leider ist SCI sehr teuer und wartungsaufwendig. Besonders die schweren Kup-ferkabel erwiesen sich in der Vergangenheit als problematisch, weil sie Karten undStecker mechanisch belasten. Mittlerweile kommen auch bei SCI fast ausschließlich

Page 69: [X.systems.press] Cluster Computing ||

60 4 Cluster-Design

Glasfaserkabel zum Einsatz. SCI kann genau wie Myrinet nur von einem einzigenHersteller bezogen werden.

InfiniBand

InfiniBand ist eine noch recht junge Technik, die von einem gut hundert Firmen um-fassenden Konsortium, der InfiniBand Trade Association [70], entwickelt wird. DieInfiniBand-Architektur definiert einen Industriestandard fur ein allgemeines Hoch-geschwindigkeitsnetzwerk. Diese außerst komplexe aus vielen Schichten aufgebauteArchitektur kann sowohl innerhalb eines Computers als auch zwischen verschiede-nen Computern eingesetzt werden.

Verbindungen durch InfiniBand erfolgen Punkt zu Punkt in einem switched net-work. Im InfiniBand-Jargon heißen diese Link oder Lane. Jeder Link kann in jedeRichtung gleichzeitig 2,5 GBit/s ubertragen. Durch eine logische Bundelung von ma-ximal zwolf Lanes lassen sich Ubertragungsraten bis zu 30 GBit/s erreichen. Die In-finiBand-Architektur erlaubt einen direkten Zugriff auf den Hauptspeicher, so dassder Datentransfer erfolgt, ohne die CPU zu belasten. Das Protokoll der InfiniBand-Architektur ist bewusst schlank gehalten und zum Teil direkt in der Hardware im-plementiert. Bei InfiniBand erfolgt die physische Verbindung verschiedener Com-puter mittels Kupfer- oder Glasfaserkabel bzw. innerhalb eines Computers uber ei-ne sog. Backplane. Je nach Kabelart betragt die maximale Kabellange 17 m beiKupferkabeln, 250 m bei Multimode-Glasfaserkabeln oder 10 km bei Singlemode-Glasfaserkabeln.

InfiniBand hat sich noch nicht am Massenmarkt durchgesetzt, wird aber wohldie Netzwerktechnik fur Cluster der Zukunft sein. Das Linux InfiniBand Project [96]versucht, die verschiedenen InfiniBand-Protokolle unter Linux verfugbar zu machen.Seit der Version 2.6.11 des Linux-Kernels gibt es auch einen Open-Source-Treiberfur InfiniBand. Dieser Treiber ist ein Beitrag der Open InfiniBand Alliance [120],einem Zusammenschluss verschiedener Hardwarehersteller.

QsNet

QsNet und QsNetII sind Hochgeschwindigkeits-Netzwerktechnologien der FirmaQuadrics [138]. Sie zeichnen sich durch hohe Bandbreite und sehr niedrige Laten-zen aus und haben gute Skalierungseigenschaften. So lassen sich damit Cluster mitbis zu 1024 (QsNet) bzw. 4096 (QsNetII) Knoten bei konstanter Bisektionsbandbrei-te je Knoten aufbauen. QsNet ist bisher vor allem in den USA verbreitet und findetsich in einigen der großten Cluster der Welt, siehe auch [166].

QsNet-Interfaces sind PCI 2.1 Karten bzw. bei QsNetII PCI-X-Karten und konnenDaten zwischen Interface und Speicher transportieren, ohne dabei die CPU zu belas-ten. Ein Knoten kann mit bis zu acht QsNet-Interfaces bestuckt werden, vorausge-setzt der PCI-Bus stellt genugend Bandbreite zur Verfugung. QsNet wurde speziellauf die Verwendung in SMP-Systemen hin entwickelt. Mehrere parallele Prozessekonnen gleichzeitig auf ein Netzwerkinterface zugreifen, ohne sich dabei gegenseitig

Page 70: [X.systems.press] Cluster Computing ||

4.4 CPU-Architektur 61

zu behindern. QsNet- und QsNetII-Interfaces werden durch Switches und Kupferka-bel verbunden. Bei QsNetII konnen auch Glasfaserkabel verwendet werden, wodurchdie maximal mogliche Kabellange auf 100 m steigt. QsNet-Switches verwenden in-tern eine fat-tree-Topologie.

Quadrics liefert nicht nur die Hardware sondern auch die Software. Es werdenLinux auf Intel Xeon und Itanium sowie AMD Opteron unterstutzt. Neben den Hard-waretreibern verkauft Quadrix auch eine auf MPICH basierende MPI-1.2 Implemen-tation fur QsNet und QsNetII. Wem es nicht auf portablen Code ankommt, kann auchdie libelan genannte Kommunikationsbibliothek verwenden, die direkten Zugriff aufdie Netzwerkhardware erlaubt.

4.4 CPU-Architektur

Praktisch alle Anwendungen, die auf einem High-Performance-Cluster laufen, durs-tet es nach einer hohen CPU-Gesamt-Leistung. Diese kann meist durch eine modera-te Anzahl von Hochleistungs-CPUs erbracht werden. Aus okonomischer Sicht ist esaber oft nicht sinnvoll, die neusten, schnellsten und damit teuersten CPUs zu kaufen.In der Regel ist es ratsam, sich fur den CPU-Typ mit dem besten momentanen Preis-Leistungs-Verhaltnis zu entscheiden. Diese CPUs sind zwar nicht ganz so schnell wieaktuelle Hochleistungs-CPUs. Jedoch konnen Sie von diesen fur gleiches Geld einegroßere Anzahl mit großerer Gesamtleistung kaufen. Außerdem sind diese CPUsschon langer am Markt und dort gewissermaßen gereift, z. B. sind Kinderkrankhei-ten der Motherboards fur diese CPUs weniger haufig.

Die wichtigste Leistungskennzahl einer CPU ist sicher die peak performance inGflops, siehe Abschnitt 1.2. Jedoch sollte die Entscheidung fur eine bestimme CPU-Architektur nicht nur auf Grundlage der peak performance getroffen werden. Dennmit der Wahl fur eine bestimmte CPU werden implizit auch Entscheidungen fur ande-re Hardwarekomponenten getroffen. Davon sind insbesondere Cache, der sich zumTeil in der CPU selbst befindet, Bussysteme und Speicher betroffen.

Es gibt jedoch auch Anwendungen, die es notig machen, die schnellsten verfugba-ren und noch bezahlbaren CPUs einzusetzen. Dies sind Anwendungen, die wegenihres feingranularen Charakters schlecht mit der Anzahl der CPUs skalieren. In denAbschnitten 1.5 und 1.6 haben wir gesehen, dass hier wegen des Kommunikations-aufwandes die Rechenleistung eines Clusters deutlich langsamer als linear mit An-zahl der CPUs wachst. Dieses sublineare Wachstum wird durch das Austauschenvon Zwischenergebnissen uber ein relativ langsames Netzwerk verursacht. Fur sol-che kommunikationsintensiven Anwendungen ist eher ein Cluster mit wenigen durchein Hochleistungs-Netzwerk gekoppelte Hochleistungs-CPUs geeignet.

Besonders effizient ist die Kommunikation zwischen verschiedenen CPUs inner-halb eines Knotens, also in einem SMP-System. Darum werden in Clustern gerneSMP-Systeme mit je zwei oder vier CPUs als einzelne Knoten eingesetzt. Cluster mitSMP-Knoten konnen daruber hinaus kompakter aufgebaut werden, weil z. B. weni-ger Netzteile und Motherboards notwendig sind. Nachteilig ist allerdings der relativhohe Preis von SMP-Systemen, der superlinear mit der CPU-Zahl je Knoten wachst.

Page 71: [X.systems.press] Cluster Computing ||

62 4 Cluster-Design

Ein Beispiel aus [6] fuhrt dies drastisch vor Augen. Ein Cluster aus 176 Knoten mitje einer 2 GHz Intel Xeon CPU und insgesamt 176 GByte RAM und 7 TByte Fest-plattenspeicher hatte im Jahre 2003 ca. 278 000 $ gekostet, ein SMP-Server mit nuracht 2 GHz Intel Xeon CPUs, 64 GByte RAM und 8 TByte Festplattenspeicher warmit ca. 758 000 $ gut dreimal so teuer. Knoten mit mehr als zwei CPUs je Knotensind darum eher selten.

Vor kurzer Zeit hat sich auf dem CPU-Markt ein Wechsel von 32-Bit-Systemenzu 64-Bit-Systemen vollzogen. Die Vorteile der 64-Bit-Architekturen gegenuber den32-Bit-Systemen liegen vorallem in breiteren Adress- und Datenbussen sowie einemAdressraum, der die von 32-Bit-Systemen bekannte 4 GB-Schranke uberwindet. Diemeisten Linux-Distributionen unterstutzen mittlerweile die 64-Bit-Architekturen vonIntel und AMD, die sich aber auch in einem 32-Bit-Kompatibilitatsmodus betreibenlassen.

4.5 Arbeitsspeicher

Neben der CPU ist der Arbeitsspeicher eine weitere leistungsbeeinflussende Kom-ponente eines Cluster-Knotens. Der Speicher eines Computers ist hierarchisch struk-turiert. An oberster Stelle steht der Cache. Auf ihn kann die CPU am schnellstenzugreifen, leider umfasst er meist nur wenige Megabyte. Je mehr Operationen einProgramm auf Daten anwendet, die sich ausschließlich im Cache befinden, destomehr gewinnt es durch den Cache. Wie stark ein konkretes Programm, von einemgroßen Cache profitiert, ist a priori aber meist schwer einzuschatzen. Im Zweifelsfal-le helfen hier nur Benchmarks, siehe Abschnitt 1.4.

Der nachst langsamere aber großere Speicher ist der Hauptspeicher. Seine Großeliegt typischerweise im Bereich weniger Gigabyte, ist also um einen Faktor tausendgroßer als der Cache, jedoch dauert ein Zugriff der CPU um einige Großenordnungenlanger. Anwendungen, fur die selbst der Hauptspeicher nicht ausreicht, konnen auchDaten in den virtuellen Speicher (virtual memory) auf der Festplatte auslagern. ImVergleich zum Hauptspeicher kann virtueller Speicher wieder um Großenordnungengroßer sein, was aber wieder durch noch langere Zugriffszeiten erkauft werden muss.Fur die meisten Cluster-Anwendungen sind die Leistungseinbußen durch Zugriff aufvirtuellen Speicher so groß, dass auf ihn verzichtet wird.

Programme konnen auch ganz unterschiedliche Anforderungen an die Große desArbeitsspeichers stellen. Grundsatzlich empfiehlt es sich, bei der Bemessung des Ar-beitsspeichers nicht zu geizen. Da man typischerweise auf schnelleren Computernauch großere Probleme losen mochte, siehe Abschnitt 1.6, sollte die Große des Ar-beitsspeichers mit der CPU-Leistung wachsen. Als Faustregel kann man ein ByteArbeitsspeicher pro Fließkommaoperation pro Sekunde ansetzen. Die Große destatsachlich benotigten Arbeitsspeichers kann aber je nach Anwendung stark variie-ren.

Werden große Datenmengen bearbeitet, so wird die Leistung des Clusters oft voneinem langsamen Hauptspeicher oder zu kleinen Cache gebremst. Moderne Speicher-technologien erlauben Speicherbandbreiten von mehreren GByte/s bei Latenzen von

Page 72: [X.systems.press] Cluster Computing ||

4.6 Massenspeicher 63

unter 10 ns. Andererseits sind besonders schnelle Speichertechnologien meist deut-lich teurer als Standardspeicher. Uberlegen Sie sich also gut ob, Ihre Anwendungenbesonders schnellen Speicher benotigen.

4.6 Massenspeicher

4.6.1 Hardware

ATA-Festplatten verschiedener Auspragung kommen heute im PC-Bereich als Stan-dardmassenspeichermedium zum Einsatz. ATA steht fur Advanced Technology At-tachments. Praktisch jedes Motherboard ist heute mit zwei ATA-Controllern aus-gestattet, an denen sich insgesamt bis zu vier Festplatten anschließen lassen. DerATA-Bus erlaubt Datentransferraten bis zu 133 MByte/s. Allmahlich wird die ATA-Technik von SATA (Serial Advanced Technology Attachments) abgelost. Durch seri-elle Datenubertragung konnen mit SATA deutlich hohere Bandbreiten als bei ATAerreicht werden. Außerdem behindern die dunneren SATA-Kabel die Luftzirkulationim Knoten langst nicht so stark wie die breiten ATA-Flachband-Kabel. Ein weitererVorteil von SATA ist die Unterstutzung von hot-plugging, also dem Entfernen undEinbinden von Festplatten im laufenden Betrieb.

Noch leistungsfahiger als SATA ist die SCSI-Technik (Small Computer SystemInterface). Um in einem Computer SCSI-Gerate zu verwenden, bedarf es in der Re-gel einer extra PCI-Controller-Karte. Nur wenige sehr hochwertige Motherboardssind bereits mit einem SCSI-Controller ausgestattet. Die nicht unerheblichen Mehr-kosten fur einen SCSI-Controller (ca. 150 Euro fur einen einfachen Ultra 160 SCSI-Controller bis ca. 700 Euro fur einen Ultra 320 SCSI-Controller mit RAID-Funkti-on, Stand Mitte 2005) lohnen sich speziell fur stark belastete Server. Denn ein SCSI-Controller kann sich ganz allein um den Datentransport kummern ohne dabei auf Un-terstutzung der CPU angewiesen zu sein. Bei ATA-Systemen erzeugen Dateizugriffehingegen eine recht hohe CPU-Last.

Speziell bei Fileservern kommen nur hochwertige fur den Serverbetrieb ausgeleg-te Festplatten in Frage. Damit ein ausreichender Datendurchsatz gewahrleistet wer-den kann, sollten diese Festplatten uber ein SCSI- oder SATA-Interface verfugen. Eingroßer Datendurchsatz allein macht aber noch keinen Fileserver aus. Damit sich derFileserver nicht als ein single point of failure herausstellt, muss er uber eine gewisseRedundanz verfugen. Wie weit diese geht, hangt davon ab, wie groß der Schadenist, wenn der Fileserver und damit praktisch der ganze Cluster einmal ausfallt. Dienotwendige Datensicherheit kann z. B. durch mehrfach ausgelegte Server (fail over),ein RAID-System (Redundant Array of Inexpensive Disks) und regelmaßiges Backupgewahrleistet werden. Die Anforderungen an eine Knotenfestplatte sind nicht ganzso hoch wie an eine Serverfestplatte. Trotzdem sollten auch die Knotenfestplattenhochwertig sein. Bedenken Sie, je mehr Festplatten Ihr Cluster hat, desto großer istdie Wahrscheinlichkeit, dass innerhalb einer festen Zeit eine Festplatte ausfallt.

Page 73: [X.systems.press] Cluster Computing ||

64 4 Cluster-Design

4.6.2 Clusterdateisysteme

Haben Sie sich entschieden worauf die moglicherweise riesigen Datenmengen IhresCluster gespeichert werden, mussen Sie sich auch noch uberlegen, wie diese organi-siert werden. Grundsatzlich gibt es dazu zwei Strategien.

Zum einen konnen die Daten verteilt auf den Festplatten der Knoten liegen. DerVorteil bei diesem Ansatz ist, dass auf lokale Daten des jeweiligen Knotens sehrschnell zugegriffen werden kann. Nicht lokale Dateien mussen uber das Netzwerkbeschafft werden. Die Lokalitat der Daten verursacht jedoch einen recht hohen admi-nistrativen Aufwand und ist fur die Nutzer extrem unkomfortabel. In einem Clustermussen zahlreiche Dateien mit identischem Inhalt auf jedem Computer vorhandensein. Wenn ein Nutzer z. B. auf eine bestimmte Datei bestimmten Inhalts von jedemKnoten aus zugreifen konnen will, so muss er nach jeder Anderung der Datei die-se manuell auf alle anderen Knoten ubertragen. Ein fehlerhaftes und zeitraubendesUnterfangen.

Ein Clusterdateisystem hingegen gibt dem Nutzer eine transparente Datensicht.Dies bedeutet, dass von jedem Knoten aus auf den gleichen Datenbestand zugreifenkann, ohne dass sich der Nutzer daruber Gedanken machen muss, wo die Datei phy-sisch gespeichert ist. Wurden Anderungen an einer Datei vorgenommen, sind diesesofort von allen Knoten aus sichtbar. Clusterdateisysteme sind aber nicht nur bequem.Erst durch sie konnen parallele Anwendungen uberhaupt erst effizient Daten lesenund schreiben. Einige Clusterdateisysteme gewahrleisten daruberhinaus ein gewissesMaß an Redundanz oder besitzen weitere spezielle Funktionen.

Prinzipiell konnte man auch einen Cluster ohne ein Clusterdateisystem betreiben,jedoch leidet darunter der Nutzerkomfort sehr. Recht drastisch wird dies in einemErfahrungsbericht von Remy Evard in Kapitel 20 in [58] deutlich. Wegen der gerin-gen zu erwartenden Performance verzichteten Evard und seine Kollegen bei ihremCluster auf ein Clusterdateisystem. Aus den Erfahrungen, die er beim Betrieb diesesClusters sammelte, schließt Evard, dass ein clusterweites Dateisystem fur den Nut-zerkomfort so wichtig, dass selbst dann nicht darauf verzichtet werden sollte, wennes nur mit schlechter Performance realisiert werden kann.

Unter Linux steht gleich eine ganze Reihe verschiedener Clusterdateisysteme zurVerfugung.

NFS. Das Network File System (NFS) ist ein von Sun Microsystems entwickeltesProtokoll, das den Zugriff auf Dateien uber ein Netzwerk ermoglicht. Mit ihmkonnen Nutzer auf Dateien, die sich auf einem entfernten Rechner (dem NFS-Server) befinden, so zugreifen, als wenn sie auf ihrer lokalen Festplatte abge-speichert waren. Rechner, die ein NFS importieren, werden als NFS-Client be-zeichnet. NFS wird in kleineren Netzwerken aller Art eingesetzt und ist auchauf Clustern sehr nutzlich. Allerdings skaliert es nicht besonders gut und stoßtbei Clustern, auf denen große Datenmengen vom Dateisystem gelesen oder insDateisystem geschrieben werden, an seine Grenzen. NFS besitzt auch keiner-lei (eingebaute) Redundanz. Fallt der NFS-Server aus, konnen die Clients nichtmehr auf die Daten zugreifen. Mehr Informationen zu NFS im Allgemeinen fin-den Sie in [159] und zu NFS unter Linux in [114].

Page 74: [X.systems.press] Cluster Computing ||

4.7 Diskless nodes 65

PVFS. Das Parallel Virtual File System (PVFS) [131] ist (im Gegensatz zu NFS)ein echtes Clusterdateisystem. Bei einem Cluster mit PVFS liegen einzelne Da-teien verteilt auf mehreren Servern. Auf diese kann durch Standard-Schreib-Le-se-Funktionen der Programmiersprache C zugegriffen werden. Deutlich effizi-enter ist jedoch der parallele Dateizugriff uber spezielle PVFS-Funktionen oderdie Dateifunktionen aus MPI-2, siehe Abschnitt 8.4. Dazu mussen die MPI-2-Dateifunktionen mit der ROMIO-Bibliothek [144] implementiert worden sein.Bei LAM/MPI [89] und MPICH [107] ist dies der Fall. Da ein Parallel VirtualFile System Dateien verteilt auf mehreren Servern liegen, ist ein echter parallelerDateizugriff moglich. Greifen mehrere compute nodes gleichzeitig auf verschie-dene Teile einer Datei zu, werden sie gleichzeitig von verschiedenen Servernbedient. PVFS skaliert darum besser als NFS, wo es nur einen zentralen Servergibt. Allerdings kennt PVFS weder hard noch soft links und PVFS-Server las-sen sich nicht redundant auslegen. Eine ausfuhrlichere Beschreibung des PVFSfinden Sie in [58].

Lustre. Das Clusterdateisystem Lustre [98] wird von der amerikanischen FirmaCluster File Systems, Inc. entwickelt und unter GPL vertrieben. Ziel dieser Ent-wicklung ist ein Clusterdateisystem fur Cluster der nachsten Generation mit meh-reren 10 000 Knoten, mehreren Petabyte Daten und parallelen Zugriffsraten vonuber 100 GByte/s.

InterMezzo. Das Dateisystem InterMezzo [73] wurde speziell unter dem Gesichts-punkt der Ausfallsicherheit entwickelt und ist darum besonders fur Hochverfug-barkeits-Cluster von Interesse.

Neben diesen Dateisystemen sind noch das General Parallel File System (GPFS) [48]und OpenGFS [122] erwahnenswert. Ersteres ist ein kommerzielles Dateisystem vonIBM. OpenGFS wurde ursprunglich von RedHat entwickelt und wird gewohnlich aufeinem Storage Area Network (SAN) betrieben. Ein SAN fasst alle Datenspeicher-systeme in einem eigenen, nur zu diesem Zweck konzipierten Netzwerk zusammen.Rechner die auf solchen Speicher zugreifen, sehen diesen wie normale lokale Disks.Diese Rechner werden meist uber Fibre Channel, iSCSI oder Ethernet an das SANangeschlossen.

Egal fur welches Clusterdateisystem Sie sich entscheiden, allen ist gemeinsam,dass Dateizugriffe das Netzwerk belasten. Reicht dessen Bandbreite nicht aus, um so-wohl die Kommunikation paralleler Programme als auch Dateizugriffe abzuwickeln,so sollten beide Datenstrome auf zwei verschiedene Netzwerke verteilt werden. Da-bei konnen auch ganz verschiedene Netzwerktechniken eingesetzt werden, z. B. einEthernet-Netzwerk fur das Netzwerkdateisystem und andere Netzdienste und Myri-net-Netzwerk fur die Kommunikation der Anwendungsprogramme.

4.7 Diskless nodes

In einem Cluster mit vielen Knoten ist der Ausfall einer Festplatte leider nichts un-gewohnliches. Defekte Festplatten storen den Clusterbetrieb und das Wechseln der

Page 75: [X.systems.press] Cluster Computing ||

66 4 Cluster-Design

Festplatte eines Knotens kann (wie jeder andere Eingriff in die Knotenhardwareauch) recht zeitraubend sein. Nach der eigentlichen Hardwarereperatur muss dannauch noch das Betriebssystem eingerichtet werden, was selbst bei einer teilweisenAutomatisierung unnotige Arbeit macht. Mit festplattenlosen Knoten (diskless no-des) entfallt dieses Problem.

Hier liegen samtliche Daten auf einem zentralen Server, selbst das Betriebssys-tem. Dieses holt sich jeder Knoten beim Booten uber das Netzwerk. Dazu mussder Knoten uber eine Netzwerkkarte mit Unterstutzung fur Pre-Boot Execution En-vironment (PXE) verfugen. Fur einen Cluster mit diskless nodes spricht, dass sichdurch den Verzicht auf Festplatten sowohl die Kosten je Knoten, der administrativeAufwand, als auch Warmeentwicklung und Stromverbrauch verringern. Außerdemkonnen festplattenlose Knoten noch kompakter gebaut werden. Die Verringerung desadministrativen Aufwands zeigt sich vorallem im Betrieb. Muss ein defekter Knotenerneuert werden, so ist nach dem physischen Austausch der Hardware nichts mehranzupassen, denn die Software liegt nur auf dem Server.

Cluster mit diskless nodes sind wenig verbreitet. Die Erstinstallation ist relativaufwendig und erfordert einiges an Handarbeit. Cluster-Management-Software (sie-he Abschnitt 6.3) unterstutzt leider meist nur Knoten mit Festplatten. Die Autorendieses Buches haben aber mit solch einem Cluster exzellente Erfahrungen gemacht.Die Einrichtung eines Clusters mit diskless nodes ist Thema von Abschnitt 5.8.

4.8 Hardware-Monitoring

Moderne Motherboards besitzen eine Hardware-Monitoring-Funktion. Diese erlaubtes, Umdrehungszahl der CPU-Lufter, die Temperaturen der CPUs und wichtige Span-nungspegel zu uberwachen. Zwar hat Hardware-Monitoring keinerlei Einfluss aufdie Leistungsfahigkeit eines Cluster-Computers, trotzdem gehort sie zu seinen wich-tigsten Funktionen. Dies soll ein kleines Rechenexempel verdeutlichen. In einem mit-telgroßen Cluster mit 100 Knoten sind 200 Lufter installiert, je einer fur CPU undeiner im Netzteil. Wenn die Lebensdauer der Lufter ca. funf Jahre betragt, so liegenim Mittel zwischen zwei Lufterausfallen ca. zehn Tage. Durch Hardware-Monitoringkonnen solche Defekte fruhzeitig erkannt und Folgeschaden (z. B. uberhitzte CPUs)vermieden werden.

Damit unter Linux das Hardware-Monitoring genutzt werden kann, muss derLinux-Kernel uber spezielle Funktionen verfugen. Leider sind diese nur zum TeilBestandteil des Standard-Linux-Kernels. Das LM sensors-Projekt [63] pflegt eineSammlung von Kernel-Treibern und Anwendungsprogrammen fur das Hardware-Monitoring. Die Zahl der vom LM sensors-Projekt unterstutzten Motherboards steigtzwar stetig, jedoch funktioniert das Hardware-Monitoring bei langst nicht allen Mo-therboards auch unter Linux. Manchmal scheitert seine Aktivierung an Kleinigkeiten.So mussten wir die Erfahrung machen, dass bei nur einem von zwei Motherboardsmit identischer Typenbezeichnung aber verschiedenen BIOS-Versionen das Hard-ware-Monitoring unter Linux arbeitete. Meist erschwierigt zusatzlich die schlechteDokumentation der Motherboards die Aktivierung des Hardware-Monitorings. Es

Page 76: [X.systems.press] Cluster Computing ||

4.9 Unterbringung, Klima und Kuhlung 67

Abb. 4.5. SMP-Opteron-Board mit Wasserkuhlung. (Quelle: Megware)

kann eine echte Herausforderung sein, herauszufinden, welche Hardware-Monito-ring-Chips auf einem Motherboard verbaut wurden bzw. welcher Treiber, der geeig-nete ist. Vor dem Kauf der Cluster-Knoten sollten Sie also unbedingt abklaren, obbei ihnen das Hardware-Monitoring unter Linux funktioniert. In Abschnitt 5.3.3 er-fahren Sie im Detail, wie Sie Ihrem Computer den Puls fuhlen konnen, und auf derWebseite [104] finden Sie Dokumentationen zu zahlreichen Motherboards.

4.9 Unterbringung, Klima und Kuhlung

Wohluberlegt will auch die Unterbringung des Clusters bzw. die Wahl der Kno-tengehause sein. Bei den Gehausen hat man die Wahl zwischen konventionellenDesktop-PC-Gehausen (typischerweise im Midi-Tower-Format) in Regalen und 19-Zoll-Einschuben im Serverschrank, siehe Abb. 2.5. Auch wenn die Regalvarianteetwas preiswerter und durchaus verbreitet ist, so sollte doch einer Unterbringungin 19-Zoll-Schranken der Vorzug gegeben werden. Serverschranke im 19-Zoll-For-mat sind typischerweise 42 oder 24 Hoheneinheiten hoch. Eine Hoheneinheit be-tragt ein Zoll bzw. 2,54 cm. Knoten-Gehause sind ein, zwei oder vier Hoheneinheitenhoch und werden im 19-Zoll-Schrank ubereinander gestapelt. Zu den Vorteilen von19-Zoll-Schranken gehoren u. a., dass sie oft uber spezielle Kabelschachte verfugen,die den Kabelsalat in Grenzen halten, und sie den Austausch eines Knotens und an-dere Wartungsarbeiten erleichtern.

Knoten-Gehause mit einer Hohe von ein oder zwei Hoheneinheiten erlauben denAufbau sehr kompakter Cluster. Eine hohe Packungsdichte hat neben dem Vorteil derPlatzersparnis leider auch ihre Nachteile. Die Abfuhrung der Warme, die in einemKnoten entsteht, kann bei hoher Packungsdichte eine echte Herausforderung sein.Nehmen wir an, dass ein Knoten unter Last eine Leistung von ca. 200 W aufnimmt.Bei Gehauseabmessungen von ca. 0,5 m×0,4 m×0,025 m ergibt sich eine Leistungs-dichte von immerhin 40 kW/m3. So verwundert es nicht, dass mit Wasser gekuhlteSysteme immer starker an Bedeutung gewinnen, siehe Abb. 4.5. Diese Technik istmittlerweile ausgereift, zuverlassig und im Gegensatz zu herkommlichen Lufternfrei von mechanischem Verschleiß. Allerdings konnen bei dieser Art der KuhlungProbleme mit Kondenswasser auftreten.

Page 77: [X.systems.press] Cluster Computing ||

68 4 Cluster-Design

Abb. 4.6. Kompaktes Zwei-Hoheneinheiten-Gehause mit zwei Opteron-Boards und Was-serkuhlung. (Quelle: Megware)

Neben diesen thermischen Gesichtspunkten sind bei der Verwendung sehr flacherGehause noch einige Punkte bei der Wahl des Motherboards zu beachten, denn nichtjedes Motherboard passt in Gehause von einer Hoheneinheit. Fur so flache Gehausewurde fur Motherboards ein spezieller Formfaktor geschaffen. Bei Motherboards imLow Profile Extended Format (LPX-Format) sind praktisch alle Schnittstellen-An-schlusse auf dem Board vorhanden. Steckkarten konnen nur uber eine sog. Raiser-Karte mit dem Board verbunden werden. Durch eine Raiser-Karte liegen Steckkar-ten gegenuber der normalen Lage um 90 Grad gedreht sehr flach im Gehause. Lei-der lassen sich so selten mehr als eine Erweiterungskarte einbauen und manchmaltreten Probleme beim Zusammenspiel von Motherboard, Raiser-Karte und Erwei-terungskarte auf, was zu Leistungseinbußen oder Dysfunktionen fuhrt. Im Falle ei-nes Cluster-Knotens steckt im einzigen verfugbaren Slot die Hochgeschwindigkeits-Netzwerkkarte. Ein recht guter Kompromiss sind Gehause von zwei Hoheneinheiten,siehe Abb. 4.6. Auch mit solchen Gehausen lassen sich dicht gepackte Cluster reali-sieren, bei denen aber normale Motherboards im ATX-Format zum Einsatz kommen.Dank flacher Low-Profile-Karten konnen alle Slots durch Erweiterungskarten belegtwerden. Raiser-Karten sind hier nicht notwendig.

In letzter Zeit werden in Clustern verstarkt auch sog. Blade-Systeme eingesetzt.Ein Blade-System bestehen aus einem Einschubgehause (cage), in dem eine gewis-se Zahl einzelner Knoten (typischerweise zwischen 8 und 16) als Steckmodule ein-gefugt werden kann, siehe Abb. 4.7. Die Knotenzahl eines Clusters aus Blades istmeist ein Vielfaches dieser Zahl. Die Vernetzung erfolgt uber Steckkontakte in derRuckwand des Einschubgehauses, der backplane.

Page 78: [X.systems.press] Cluster Computing ||

4.10 Cluster now! 69

Abb. 4.7. Cluster kompakt: Jeder dieser senkrecht stehenden Einschube (blades) enthalt einenkompletten PC mit zwei Prozessoren und Festplatten. Die Vernetzung erfolgt uber Steckkon-takte in der Ruckwand des Einschubgehauses.

Der Raum, in dem der Cluster stehen soll, muss ausreichend klimatisiert undstaubarm sein. Staub ist die wichtigste Ursache fur den vorzeitigen Verschleiß vonCPU- und Netzteilluftern. CPU- und Netzteillufter mussen unbedingt fur den Dau-erbetrieb ausgelegt sein. Defekter Lufter verursachen, so sie nicht entdeckt werden,teure Folgeschaden und gehoren wohl zu den haufigsten Hardwareausfallen.

Ein Cluster besteht zwar aus kleinen PCs, wegen ihrer schieren Menge gilt esaber, in großeren Maßstaben zu denken. Cluster-Computer mit mehreren DutzendKnoten wiegen mehrere Tonnen und sind fur Fußboden und Decken eine starke Be-lastung. Die Statik des Serverraums muss dem Gewicht des Clusters gewachsen sein.Berucksichtigen Sie auch den Strombedarf Ihres Clusters. Moglicherweise benotigtIhr Serverraum einen neuen Stromanschluss. Ein Cluster mit 64 Knoten, die unterLast jeweils 200 W leisten, hat eine Gesamtleistung 12,8 kW, was einem Strom vonfast 60 A entspricht. Die Leistung wird vollstandig in Warme umgesetzt und mussuber eine Klimaanlage abgefuhrt werden. Richten Sie fur Ihren Cluster einen neuenklimatisierten Serverraum ein, so mussen die dafur notwendigen Ausgaben bei derKalkulation der Gesamtkosten des Clusters berucksichtigt werden.

4.10 Cluster now!

Manchmal ist es nicht notig oder moglich, einen Cluster-Computer neu zu erwerben.Ein Cluster kann auch sehr leicht zu geringen Kosten oder gar Nullkosten (siehe

Page 79: [X.systems.press] Cluster Computing ||

70 4 Cluster-Design

Abb. 2.4) aus vorhandener Hardware aufgebaut werden. Entweder bildet alte ausge-musterte Hardware oder vernetzte Arbeitsplatzrechner die Basis des Clusters.

Sind in Ihrem Institut oder Ihrer Firma bereits vernetzte, unter Linux laufende Ar-beitsplatzrechner vorhanden, so sind Sie bereits stolzer Besitzer eines Clusters. Daseinzige, was noch fehlt, ist die notwendige Software, die es ermoglicht, das Netz-werk von Arbeitsplatzrechnern (network of workstations, kurz NOW) als Cluster zubetreiben. Typische Arbeitsplatzrechner verbringen die meiste Rechenzeit damit, aufTastaturanschlage ihrer Nutzer zu warten oder den Bildschirm zu schonen. Mit einemNOW-Cluster wird diese brachliegende Rechenleistung sinnvoll genutzt. Auch kannein NOW-Cluster als ”Spielwiese“ dienen, auf der Sie erste Erfahrungen im Cluster-Computing sammeln.

Betreiber eines solchen NOW-Clusters mussen allerdings mit einigen kleinen Ein-schrankungen gegenuber einem dedizierten Cluster leben.

• Buronetzwerke basieren oft noch auf Fast Ethernet und sind wenig leistungsfahig.• Fahrt ein Nutzer seinen Arbeitsplatzrechner herunter, so steht dieser Rechner

dem Cluster nicht mehr zur Verfugung.• Nutzer konnen sich durch im Hintergrund laufende Programme gestort fuhlen

oder der Betrieb des NOW-Clusters steht anderweitig mit der normalen Nutzungder Arbeitsplatzrechner im Konflikt.

Ein haufig auftretendes Problem sind z. B. temperaturgeregelte Lufter, die im Be-trieb des NOW-Clusters deutlich lauter sind, da die CPU andauernd stark belastetwird. Ein anderes Problem konnte sein, dass die Arbeitsplatzrechner auf ein anderesBetriebssystem als Linux angewiesen sind. Eine Moglichkeit, einen solchen Konfliktzu losen, besteht darin, die Arbeitsplatzrechner tagsuber ausschließlich den Nutzernzur Verfugung zu stellen, wahrend nach Buroschluss auf Cluster-Betrieb umgestelltwird. In [172] wird ein solcher ”Feierabend-Cluster“ vorgestellt.

4.11 Besonderheiten von Knoten-Hardware

Wenn wir behaupten, dass die Knoten eines Cluster-Computers ganz normale PCssind, so stimmt das nur bedingt. Zu einem PC gehoren heute ganz selbstverstandlicheine Tastatur, eine Maus und ein Monitor. Bei Cluster-Knoten kann jedoch in derRegel auf solche Peripheriegerate verzichtet werden, denn die Nutzer des Clustersarbeiten schließlich nicht direkt an den Knoten. Sie greifen ausschließlich von ihremBurorechner uber das Internet auf den Cluster zu. Einzig der Administrator mussmachmal direkt am Cluster zu Tastatur und Monitor greifen.

Meist reichen fur einen ganzen Cluster eine Tastatur und ein Monitor. Moglichmacht dies ein KVM-Switch. KVM steht fur keyboard, video und mouse. Mit einemKVM-Switch konnen mehrere Computer von einer einzigen Tastatur-Monitor-Maus-Konsole aus bedient werden. Dazu lasst sich zwischen den angeschlossenen Com-putern hin- und herschalten. Tastatur, Monitor und Maus sind an den KVM-Switchangeschlossen, der wiederum uber Kabel mit den verschiedenen Computern verbun-den ist. KVM-Switches emulieren fur jeden Computer Tastatur und Maus vollstandig,

Page 80: [X.systems.press] Cluster Computing ||

4.12 Schrauben oder kaufen? 71

auch fur die gerade nicht angewahlten Computer. Das macht das Umschalten ganzeinfach und unproblematisch. Leider unterstutzen herkommliche KVM-Switches sel-ten mehr als 16 Computer. Bei großeren Clustern kann man mehrere KVM-Switcheszusammenschalten. Oft reicht es aber, wenn nur die Server am KVM-Switch hangenund die compute nodes mittels geeigneter Verlangerungskabel fur Tastatur und Mo-nitor nur bei Bedarf an den KVM-Switch angeschlossen werden. Dann mussen Siejedoch darauf achten, dass die Knoten auch ohne Tastatur booten konnen. ManchesBIOS bricht den BOOT-Vorgang ab, falls es keine Tastatur finden kann. Meist lasstsich dieses Verhalten jedoch abschalten.

Neben Tastatur, Maus und Monitor kann bei der Knoten-Hardware meist nochauf weitere Komponenten verzichtet werden. Dazu gehoren

• CD-ROM- und DVD-Laufwerke,• Floppy,• Soundkarten und• leistungsstarke Grafikkarten.

Leider kommen die meisten PCs nicht ohne Grafikkarte aus und verweigern ohne sieihren Dienst. Hier tut es dann ein einfaches Modell. Die Floppy gilt eigentlich als aus-sterbendes Medium und es gibt keinen zwingenden Grund, warum ein Cluster-Kno-ten ein Floppy-Laufwerk haben sollte. Allerdings lasst sich eine Betriebssystemin-stallation oft am einfachsten uber eine Floppy anstoßen, siehe auch Abschnitt 5.5.1.

Grundsatzlich gilt: halten Sie Ihre Knoten schlank, verzichten Sie auf unnotigeKomponenten und lassen Sie bei der Wahl der wirklich wichtigen Komponenten wieCPU oder Netztechnik besondere Sorgfalt walten.

4.12 Schrauben oder kaufen?

Wahrend die ersten Linux-Cluster hauptsachlich von Enthusiasten fur den Eigenbe-darf aufgebaut wurden, bieten heute immer mehr große und kleine Computerher-steller Cluster-Computer schlusselfertig an. Dazu gehoren auch etablierte Firmenwie IBM, HP oder Sun, die mit Linux-Clustern ihre Produktpalette in Richtungpreiswerter Super-Computer erweitern. Damit reagieren IBM und Co. nicht nur aufKundenwunsche sondern auch auf eine ganz neue Konkurrenz. Da Cluster-Compu-ter meist aus Standardkomponenten, wie sie auch in Low-End-Servern, Buro- oderHeimcomputern Verwendung finden, aufgebaut werden, ergibt sich hier erstmalsauch fur kleine Unternehmen die Moglichkeit, in den Super-Computing-Markt ein-zusteigen. Diese neue Konkurrenz durfte ein gewichtiger Beweggrund fur die eta-blierten Super-Computing-Firmen gewesen sein, auch Linux-Cluster ins Programmaufzunehmen.

Die Entscheidung, einen Cluster-Computer vollkommen in Eigenregie aufzubau-en oder schlusselfertig zu kaufen, ist von sehr grundlegender Bedeutung. Beide Op-tionen haben ihre Vor- und Nachteile.

Page 81: [X.systems.press] Cluster Computing ||

72 4 Cluster-Design

4.12.1 Do it your self

Eine wichtige Motivation fur Linux-Cluster aus Standardkomponenten ist ihr gerin-ger Preis. Da ist es nur konsequent, die finanziellen Aufwendungen auf die Hardwarezu beschranken und den Cluster selbst aufzubauen, zu vernetzen und zu administrie-ren. Fur diese muhsame Eigenleistung werden Sie nicht nur durch einen geringenPreis sondern auch noch die volle Kontrolle uber das Cluster-Design belohnt. Siekonnen die Hardwarekonfiguration des Clusters ganz genau auf Ihre individuellenBedurfnisse zuschneiden. Kein unnotiger Ballast, keine Kompromisse.

Diese Kontrolle zu haben, bedeutet aber auch, Verantwortung zu tragen. Fur jedeFehlentscheidung bei der Planung mussen Sie geradestehen. Jedes Problem mussenSie selber Losen. Diese Verantwortung sollte Sie aber nicht abschrecken. DiesesBuch soll u. a. helfen, diese Verantwortung eher als Chance zu sehen und die meistenEinstiegsprobleme zu losen.

Um einen Linux-Cluster erfolgreich in eigener Regie zu bauen, sollten Sie diesin einem kleinen Team tun. Gemeinsam geht alles besser und macht mehr Spaß.Ein oder zwei Leute Ihres Teams sollten sich in der Linux-Welt wirklich heimischfuhlen, d. h. wenigstens grundlegende Kenntnisse uber Systemadministration habenund sich nicht vor kryptischen Konfigurationsdateien furchten. Sollte sich einmal einProblem als besonders hartnackig herausstellen, so finden Sie im Web, Newsgroupsund Mailinglisten praktische Hilfestellungen. Selten ist ein Problem so exotisch, dassnicht auch schon ein anderer auf dieses gestoßen ware. Bei Schwierigkeiten mit ei-ner bestimmten Software sollten Sie sich nicht scheuen, den Autor der Software zukontaktieren oder in speziellen Mailinglisten zur betreffenden Software das Problemzu schildern.

4.12.2 Schlusselfertig

Einige Hardwarehersteller werben mittlerweile in Hochglanzbroschuren fur ihreCluster-Computer, in denen sie schlusselfertige Cluster-Losungen versprechen. DerHardwarelieferant kummert sich um Hard- und Softwareinstallation. Die Nutzerkonnen in kurzester Zeit den Cluster produktiv nutzen. Zumindest wird dies in derWerbung versprochen. Leider kann das in der Realitat etwas anders aussehen. Wersich entschließt, einen vorkonfigurierten Cluster zu kaufen, sollte einiges beachten.

Zunachst ist einmal zu berucksichtigen, dass nicht alles was unter der Bezei-chung ”Cluster“ beworben wird, auch ein Cluster zur Losung aufwendiger Berech-nungen, ein High-Performance-Cluster, ist. Oft sind die angebotenen Cluster eherdarauf ausgerichtet, z. B. einen Webserver mit Lastverteilung fur eine große Websei-te oder ausfallsichere Dienste aufzubauen. Dies ist ein ganz anderes Metier, sieheAbschnitt 2.3.4.

Durch die Entscheidung fur einen vorkonfigurierten Cluster haben Sie meist nichtmehr einen so großen Einfluss auf die Gestaltung der Hardwarekonfiguration wiebeim Selbstbau. Außerdem lasst sich der Cluster-Hersteller seine Dienstleistung gutbezahlen. Dafur konnen Sie von seinem Know-How profitieren und so leicht viele

Page 82: [X.systems.press] Cluster Computing ||

4.13 Notizen 73

Probleme umschiffen. Außerdem haben zumindest die großeren Hersteller Testinstal-lationen, auf denen Sie als Kunde vor dem Kauf untersuchen konnen, wie gut IhreAnwendungen darauf laufen. Machen Sie davon unbedingt Gebrauch.

Die herstellerseitige Vorkonfiguration des Clusters erstreckt sich meist auch aufdie Software. Hierbei handelt es sich oft um eine gangige Linux-Distribution, dieeventuell noch um spezielle Cluster-Management-Software erganzt wurde. Die Kon-figuration der Software ist sehr generisch gehalten und muss meist noch an lokaleBedurfnisse und Gegebenheiten angepasst werden. Spezielle Anwendungssoftwaremuss in den allermeisten Fallen auch selbst installiert oder gar erst entwickelt wer-den. Spatestens hier sind doch die Kenntnisse eines erfahrenen Linux-Administratorsgefragt, so dass die Vision vom Rundum-Sorglos-Cluster doch eher eine Illusion ist.Trotzdem kann die Zusammenarbeit mit einem erfahrenen Cluster-Hersteller den Ein-stieg ins Cluster-Computing deutlich erleichtern.

4.13 Notizen

4.1 Cache. Der Speicher eines Computers gliedert sich nicht nur in Cache, Hauptspei-cher und virtuellen Speicher. Meist ist der Cache nochmals in zwei oder drei Ebenenuntergliedert. Man spricht von 1st level, 2nd level und 3rd level Cache. Kapazitat undZugriffszeiten wachsen meist von Level zu Level an.

4.2 Homogene Cluster. In Artikeln zum Aufbau von Cluster-Computern wird meistdazu geraten, die Knoten des Clusters so homogen wie moglich zu halten, denn dieserleichtert die Administration des Clusters. Allein durch die Einteilung in server no-des und compute nodes erweist sich ein absolut homogener Cluster in der Praxisjedoch als ein Ideal, das sich bestenfalls naherungsweise erreichen lasst. Spatestenswenn nach einem Jahr ein Motherboard ausfallt und es gegen ein Motherboard einerneuen Modellreihe ersetzt werden muss, weil das ursprungliche Modell nicht mehrlieferbar ist, muss die Idee des homogenen Clusters aufgegeben werden.

4.3 Ersatzknoten. Es hat sich als außerst praktisch erwiesen, beim Aufbau einesClusters von vornherein einen Ersatzknoten einzuplanen. Fallt ein Knoten aus, kannder Ersatzknoten den defekten Knoten kurzfristig ersetzen und die Administratorenhaben Gelegenheit, den Defekt in Ruhe zu beheben.

4.4 Spezialhardware. Die Ausruster von Rechenzentren bieten heute eine gan-ze Reihe nutzlicher Hardwarekomponenten an, die oft auch fur Cluster-Compu-ter interessant sind. Dazu gehoren per Ethernet schaltbare Steckdosen, in 19-Zoll-Einschuben integrierte LCD-Monitore und Tastaturen und vieles mehr.

4.5 Stromverbrauch. Wenn Sie den Stromverbrauch eines Knoten ermitteln wollenund nicht uber die notwendigen Messgerate verfugen, wenden Sie sich an Ihren ort-lichen Stromversorger. Viele Stromversorger verborgen an ihre Kunden Messgerate,mit denen auch Laien den Stromverbrauch von Haushaltsgeraten oder auch Compu-ter messen konnen.

Page 83: [X.systems.press] Cluster Computing ||

5

PCs vernetzen

Der Protokollkrieg ist vorbei, und TCP/IP hat gewonnen.

Craig Hunt [69]

Nachdem die vorangegangenen Kapitel eher theoretischer Natur waren, stehen nunganz praktische Belange im Vordergrund. Dieses und das nachste Kapitel vermittelnIhnen das Wissen, das Sie benotigen, um einen Cluster oder ein network of worksta-tions aufzubauen.

Je nachdem wie Ihr Cluster in Detail aufgebaut sein soll, und Sie einen Clustervon Grund auf aufbauen, oder schon unter Linux vernetzte Burorechner als einenCluster betreiben wollen, konnen Sie einige der in den nachsten Abschnitten beschie-benen Konfigurationsschritte uberspringen. Am schnellsten kommen Sie zu einemCluster, wenn Sie unter Linux vernetzte Burorechner, auf denen schon so grundlegen-de Funktionen wie netzweite Heimatverzeichnisse und rsh (siehe Abschnitte 5.6.1und 5.6.3) installiert sind, als Cluster nutzen. In diesem Falle konnen Sie direkt zuKapitel 6 blattern und ein Batch-System und eine Message-Passing-Bibliothek instal-lieren.

Haben Sie sich jedoch dazu entschlossen, einen Cluster from scratch zu bauen, sobegleitet Sie dieses Kapitel dabei. Es beschreibt schrittweise, wie funf PCs zu einemkleinen Beispiel-Cluster mit vier compute nodes und einem Server vernetzt werden.Der Aufbau eines Clusters gliedert sich in die Schritte:

1. Installation eines minimalen Betriebssystems auf dem Server und einem Knoten,2. Installation von Netzwerkdiensten auf dem Server und einem Knoten,3. Replikation des zuvor konfigurierten Knotens auf die verbleibenden Knoten und4. die Einrichtung von Cluster-Diensten.

Zu diesen Cluster-Diensten gehoren u. a. ein Batch-System und eine Message-Pas-sing-Bibliothek. Die Reihenfolge der Installationsschitte ist naturlich kein starresDogma. In der Praxis werden Sie wohl eher einen Netzwerkdienst installieren(Schritt 2), ihn auch auf den anderen Knoten verfugbar machen (Schritt 3) und danndiese Prozedur mit weiteren Diensten wiederholen, bis alles wie gewunscht lauft. DieSchritte 1 bis 3 sind Thema dieses Kapitels, wahrend wir auf Schritt 4 im Kapitel 6naher eingehen.

Die Software, die wir in den nachsten Abschnitten beschreiben werden, kann indrei Kategorien unterteilt werden.

Page 84: [X.systems.press] Cluster Computing ||

76 5 PCs vernetzen

Administrations-Software. Damit die Administration eines Clusters mit n Knotennicht n-mal so aufwendig wird wie die Administration eines einzelnen Knotens,brauchen Sie Software, die administrative Aufgaben (z. B. die Installation unddie Aktualisierung des Betriebssystems auf jedem Knoten) automatisiert.

Cluster-Dienste. Unter Cluster-Diensten verstehen wir Programme, die einen Clus-ter erst zu einem einheitlichen Ganzen machen. Dazu zahlen u. a. ein Batch-Sys-tem, das fur eine gleichmaßige Auslastung des Clusters sorgt, oder ein Netzwerk-dateisystem, durch das jeder Nutzer von jedem Knoten aus auf die Daten seinesHeimatverzeichnisses zugreifen kann.

Programm-Bibliotheken. Den Bibliotheken zur parallelen Programmierung kommtaus Nutzersicht eine ganz besonders wichtige Rolle zu. Denn in den meis-ten Fallen mussen die Nutzer von Clustern ihre Anwendungsprogramme selbstschreiben. Dabei mussen sie auf Message-Passing-Bibliotheken wie MPI zuruck-greifen.

Sie konnen diese Programme und Dienste entweder gemaß der folgenden Abschnit-te manuell installieren oder dafur ein Cluster-Management-System verwenden. Ob-wohl sich mit einem Cluster-Management-Systeme relativ schnell und unkompliziertein funktionsfahiger Cluster aufbauen lasst, werden wir auf diese Systeme nur kurzin Abschnitt 6.3 eingehen. Stattdessen zeigen wir Ihnen, wie ein Cluster ”zu Fuß“ in-stalliert wird. Denn auch die Cluster-Management-Systeme lassen sich nur dann sinn-voll einsetzen und eventuell auftretende Probleme beheben, wenn man die Vorgangehinter dem Cluster-Management-System versteht. Darum sollten Sie die folgendenAbschnitte auch dann aufmerksam studieren, wenn Sie spater ein Cluster-Manage-ment-System verwenden wollen.

Im Detail gliedert sich dieses Kapitel wie folgt: Abschnitt 5.1 schildert zunachstdie grundlegenden Eigenschaften von TCP/IP-Netzen und in Abschnitt 5.2 stellenwir einen einfachen Beispiel-Cluster vor, an dem wir die Netzwerkkonfiguration il-lustrieren werden. Die Erstinstallation des Servers und eines compute node wird inAbschnitt 5.3 beschrieben. Dabei nehmen wir jedoch an, dass Sie uber grundlegendeKenntnisse der Systemadministration unter Linux verfugen und gehen in erster Linieauf die Besonderheiten von Cluster-Computern, die Konfiguration des Kernels unddas Hardware-Monitoring ein. Sollten Sie uber nur wenig Linux-Erfahrung verfugen,werden Sie sicher weitere Literatur wie [87] oder [46] konsultieren mussen. In Ab-schnitt 5.5 stellen wir SystemImager vor, ein nutzliches Werkzeug mit dem sich dieInstallation der compute nodes automatisieren lasst. Die Abschnitte 5.4 und 5.6 wid-men sich der Konfiguration des Netzwerkes und wichtiger Netzwerkdienste. JederNetzwerkdienst wird dabei kurz vorgestellt und wir beschreiben, wozu er gut ist undwie er konfiguriert wird. Dazu gehoren

• ein clusterweites Netzwerkdateisystem, durch das von allen Knoten auf eineneinheitlichen Datenbestand zugegriffen werden kann,

• ein Verzeichnisdienst fur die Nutzerverwaltung,• Programme, die das Einloggen von einem Knoten auf einen anderen ohne Pass-

wortabfrage ermoglichen,• Programme zur Synchronisation der Systemuhren,

Page 85: [X.systems.press] Cluster Computing ||

5.1 TCP/IP-Grundlagen 77

• NAT, das den Knoten die Kommunikation mit Computern außerhalb des Clustersermoglicht, und

• ein DHCP-Server zur zentralen Verwaltung von IP-Adressen.

Daruber hinaus zeigen wir in Abschnitt 5.8, wie ein Cluster mit festplattenlosen Kno-ten (diskless nodes) aufgebaut wird, und in Abschnitt 5.7 wie man mit channel bon-ding die Bandbreite mehrerer Netzwerkkarten bundelt. Diese beiden Techniken wer-den nicht in jedem Cluster benotigt, weshalb die entsprechenden Abschnitte beimersten Lesen auch ubersprungen werden konnen.

5.1 TCP/IP-Grundlagen

Egal ob es sich um einen dedizierten Cluster-Computer oder einen Cluster aus Ar-beitsplatzrechnern handelt, ein leistungsfahiges Netzwerk zwischen den Knoten desClusters ist unverzichtbar. Wenn Computer oder andere Gerate untereinander Datenaustauschen, so muss dies in einer standardisierten Sprache, einem sog. Protokoll,geschehen. Im Netz eines Linux-Clusters wird meist das Transmission Control Pro-tocol/Internet Protocol (kurz TCP/IP) gesprochen, darum sollen hier zunachst einigeGrundlagen von TCP/IP-Netzen dargestellt werden.

TCP/IP wurde ursprunglich dazu entwickelt, entfernte Computer untereinanderzu verbinden. Es ist das Protokoll des Internets, das wir z. B. jeden Tag benutzen, umE-Mails zu lesen oder im Web zu surfen. Zu den wichtigsten Merkmalen von TCP/IPgehort, dass es einen offenen Standard darstellt und darum auf fast allen Computer-Plattformen implementiert werden kann. Die Merkmale von TCP/IP sind jeweils ineinem Request for Comments (RFC) dokumentiert. Die RFCs sind frei im Internetunter [142] zuganglich. Die Entstehung von TCP/IP ist eng mit der Entstehung vonUnix verbunden, weshalb die Integration in unixartige Betriebssysteme wie Linux tra-ditionell besonders gut ist. TCP/IP ist relativ unabhangig von der Art der Netzwerk-Hardware. Uber ein einheitliches Adressierungsschema lasst sich jedes Netzinterfacedurch eine eindeutige Adresse ansprechen.

In TCP/IP-Netzen sind TCP und IP nur die beiden wichtigsten Protokolle. Nebendiesen werden noch weitere Protokolle verwendet, die jeweils sehr spezielle Aufga-ben in einer der vier Schichten des so genannten TCP/IP-Stack ubernehmen, sie-he Abb. 5.1. Der TCP/IP-Stack gliedert sich in Anwendungsschicht, Host-zu-Host-

Anwendungsschicht

Host−zu−Host−Transportschicht

Internetschicht

Netzzugangsschicht

Abb. 5.1. Schichtaufbau der TCP/IP-Protokoll-Familie.

Page 86: [X.systems.press] Cluster Computing ||

78 5 PCs vernetzen

Transportschicht, Internetschicht und Netzzugangsschicht. Daten werden immer nurzwischen unmittelbar benachbarten Schichten ausgetauscht. Werden also Daten voneinem Computer zu einem anderen geschickt, so laufen diese von der Anwendungs-schicht des Quellrechners durch den TCP/IP-Stack bis zur Netzwerkschicht, uberdie Netzleitungen und dann von der Netzwerkschicht durch den TCP/IP-Stack biszur Anwendungsschicht des Zielrechners.

Die Netzzugangsschicht ist die unterste Schicht der TCP/IP-Protokollhierarchie.Sie hat den unmittelbaren Zugriff auf die Netzwerkhardware. Fur die hoher liegen-den Schichten abstrahiert sie von der Hardware. Uber der Netzzugangsschicht folgtdie Internetschicht, in ihr ist das Internet Protocol implementiert. Sie bildet das Herzdes TCP/IP-Stack. Das Internet Protocol versendet Daten in Form einzelner Daten-pakete, sog. Datagramme. Es ist unzuverlassig, d. h., es existieren keine Mechanis-men, die vor dem Verlust oder der Beschadigung einzelner Datenpakete schutzen.Fehlerkorrekturmechanismen sind erst in den hoheren Schichten integriert, z. B. derHost-zu-Host-Transportschicht. Die wichtigsten Protokolle der Host-zu-Host-Trans-portschicht sind das Transmission Control Protocol (TCP) und das User DatagramProtocol (UDP). TCP besitzt Funktionen zur Fehlererkennung und -korrektur undstellt darum ein zuverlassiges Protokoll dar. In der obersten Schicht sind die Anwen-dungsprotokolle implementiert. Dazu gehoren u. a. das Hypertext Transfer Protocol,uber das Ihr Webbrowser Daten von Webservern empfangt, sowie Protokolle, die imtaglichen Cluster-Betrieb unverzichtbar sind, wie z. B. das Network File System oderdie Protokolle von Secure Shell und den r-Kommandos zum Ausfuhren von Kom-mandos auf entfernten Rechnern. In Abschnitt 5.6 werden wir auf diese Protokollegenauer eingehen.

Damit die im Netz ausgetauschten Nachrichten auch den Weg zu ihrem Ziel fin-den konnen, besitzt jedes Netzwerkinterface eine eindeutige Internet-Adresse, kurzIP-Adresse. Diese Adressen werden grundsatzlich nur an Netzwerkinterfaces verge-ben, nicht an Computer. Hat ein Computer mehrere Netzwerkinterfaces, wie z. B. derServer des Beispiel-Clusters weiter unten, so haben diese Interfaces verschiedene IP-Adressen.

IP-Adressen sind vier Byte lange Zahlen. Meist werden sie in der dot quad no-tation geschrieben. Diese Notation besteht aus vier durch Punkte getrennte Zahlenzwischen 0 und 255. Der erste Teil einer IP-Adresse codiert die Netzwerknummer,der zweite Teil die Hostnummer. Wo die Grenze zwischen Netzwerknummer undHostnummer liegt, bestimmt seit der Einfuhrung des Classless Inter-Domain Rou-ting die sog. Netzmaske. Die Netzmaske ist eine Bitmaske, die genau so lang ist wiedie IP-Adresse auf die sie angewendet wird. Jedes Bit der Netzmaske bezieht sichdeshalb auf genau ein Bit der IP-Adresse. Alle auf 1 gesetzten Bits der Netzmaskemarkieren das entsprechende Bit der IP-Adresse als Netzwerkteil, der das jeweiligeSubnetz adressiert. Die auf 0 gesetzten Bits markieren den Hostteil, mit dem jedereinzelne Computer im Subnetz adressiert wird. Auch die Notation einer Netzmaskeerfolgt meist in der dotted quad notation oder unter Angabe der Anzahl der gesetztenBits mit vorangestelltem Schragstrich. So bezeichnen 255.0.0.0 und /8 die gleicheNetzmaske. Typischerweise sind 8, 16, oder 24 Bits einer Netzmaske gesetzt.

Page 87: [X.systems.press] Cluster Computing ||

5.1 TCP/IP-Grundlagen 79

IP-Adressbereiche werden zentral vergeben. In Deutschland ist dafur das DE-NIC[24] zustandig. Es gibt allerdings IP-Adressbereiche, die ohne Registrierung in pri-vaten Netzen verwendet werden durfen. Dies sind die Adressen

• 10.0.0.0 bis 10.255.255.255 mit der Netzmaske 255.0.0.0,• 172.16.0.0 bis 172.31.255.255 mit der Netzmaske 255.255.0.0 und• 192.168.0.0 bis 192.168.255.255 mit der Netzmaske 255.255.255.0.

Die Unterteilung in Netzwerk- und Hostnummer ist notwendig, da TCP/IP-Netzehierarchisch in Subnetze aufgeteilt werden. Innerhalb eines Subnetzes konnen Com-puter auf direktem Wege Daten austauschen. Liegen Quell- und Zielrechner in ver-schiedenen Subnetzen, so lauft die Nachricht uber Router oder Gateway (auch IP-Router als bezeichnet) genannte Computer, die beide Subnetze verbinden. Im Ge-gensatz zu einem Router kann ein Gateway auch zwei Netze verschiedener Technikmiteinander verbinden, wobei ein Gateway dabei Datenpakete nicht nur weiterlei-tet sondern auch manipuliert. Trotz dieses Unterschiedes werden beide Begriffe oftsynonym verwendet.

Nicht alle moglichen IP-Adressen konnen auch einem Netzwerkinterface zu-gewiesen werden, einige haben spezielle Bedeutungen. Sind im Hostteil einer IP-Adresse alle Bits gleich null, so wird damit kein Host sondern das entsprechendeNetzwerk adressiert. Sind hingegen alle Bits im Hostteil einer IP-Adresse gleicheins, so wird die Adresse als Broadcast-Adresse bezeichnet. Durch sie werden alleHosts innerhalb eines Netzwerks angesprochen. Nachrichten, die an diese Broadcast-Adresse gesandt werden, erreichen jedes Netzwerkinterface eines Subnetz. Wegender Reservierung von Netz- und Broadcast-Adresse konnen sich in einem Netz mitder Netzmaske 255.255.255.0 also maximal 254 Netzwerkinterfaces befinden.

Auch das Netzwerk 127.xxx.xxx.xxx ist reserviert. Es dient zur Kommunikationuber TCP/IP innerhalb eines Computers. Die Adresse 127.0.0.1 wird dem Loopback-Interface zugeordnet. Anders als andere Netzwerkinterfaces bildet es keine real vor-handene Hardware ab. Daten, die in das loopback interface geschrieben werden,konnen auch aus ihm wieder herausgelesen werden, als kamen sie von einem ganzanderen Rechner.

Da numerische IP-Adressen wenig aussagekraftig und fur Menschen schwer zumerken sind, kann jeder IP-Adresse ein Hostname zugeordnet werden. Auch Host-namen setzen sich aus Host- und Netzteil zusammen. So bezeichnet z. B. der Na-me athene.our-domain.org den Computer athene im Netz our-domain.org. Wird derHostname inklusive Netzteil angegeben, spricht man auch von einem voll qualifizier-ten Namen. Die Zuordnung zwischen Hostnamen und IP-Adresse erfolgt uber dendomain network service, kurz DNS.

Die IP-Adresse weist einem Datenpaket zwar den Weg zum richtigen Compu-ter, jedoch reicht diese nicht, um das Datenpaket an sein endgultiges Ziel, demEmpfangerprogramm zu leiten. Meist laufen auf einem Computer mehrere Program-me gleichzeitig, die auf eingehende Daten warten. Darum wird jedem Paket nochzusatzlich eine Portnummer zugewiesen. Man unterscheidet Portnummern fur dieProtokolle TCP und UDP. Sie liegen jeweils zwischen 1 und 65 535 wovon die Num-

Page 88: [X.systems.press] Cluster Computing ||

80 5 PCs vernetzen

mern unter 1024 fur spezielle Dienste reserviert sind und die ab 1024 frei verwendetwerden durfen.

Wir konnten hier TCP/IP-Netze gerade soweit beschreiben, wie es fur das Ver-standnis der folgenden Abschnitte notwendig ist. Wer mehr uber TCP/IP-Netze er-fahren mochte, kann z. B. in [69] oder [160] nachlesen.

5.2 Calculus – Der Beispiel-Cluster

Der hypothetische Cluster ”Calculus“, an dem in den folgenden Abschnitten die Kon-figuration eines Cluster-Computers dargestellt werden soll, besteht aus einem Serverund vier Knoten, siehe Abb. 5.2. Der Server ist der einzige Knoten, der direkt andas Campus- oder Firmennetz angeschlossen ist, alle anderen Knoten, die computenodes, befinden sich in einem eigenen Subnetz. Der Server ist die Steuerzentrale desClusters. Er exportiert uber ein Netzwerkdateisystem die Heimatverzeichnisse derNutzer an die compute nodes, nimmt Rechenauftrage entgegen und startet diese aufden anderen Knoten. Da Programme uber ein Batch-System gestartet werden, kom-men die Nutzer mit den anderen Knoten nie in direkten Kontakt. Sie arbeiten immernur auf dem Server. Zum Beispiel konnen sie hier ihre Programme kompilieren.

Wir haben fur den Beispiel-Cluster eine recht typische Hardwarekonfigurationgewahlt. Es wird angenommen, dass alle Knoten (außer eventuell der Server-Knoten)die gleiche Hardwareausstattung haben. Der Server-Knoten und ein weiterer Knotenbenotigen in der Regel ein CD-ROM- oder DVD-Laufwerk, von dem das Betriebs-system spater installiert wird. Jeder Knoten des Beispiel-Clusters besitzt eine eigeneFestplatte und ist mit einer Ethernetkarte ausgestattet. Die vier Knoten node1, node2,node3 und node4 und der Server server bilden ein eigenstandiges Subnetz. Der Ser-ver besitzt eine zweite Netzwerkkarte. Eine Karte verbindet den Server mit dem Netzdes Clusters, die andere mit dem Campus- oder Firmennetz. Die Knoten im Bei-

192.168.0.4node4node3

192.168.0.3192.168.0.2node2

192.168.0.1node1

Switchzum Campusnetz

192.168.0.254server

123.234.20.40calculus

Abb. 5.2. Der Beispiel-Cluster ”Calculus“.

Page 89: [X.systems.press] Cluster Computing ||

5.3 Erstinstallation 81

spiel-Cluster haben die IP-Adressen 192.168.0.1 bis 192.168.0.4 und 192.168.0.254.Wir haben also Adressen aus dem fur private Anwendungen reservierten Bereich192.168.0.0 bis 192.168.255.255 gewahlt. Die IP-Adresse 192.168.0.1 ist die ersteverfugbare IP-Adresse im Subnetz 192.168.0.xxx, 192.168.0.254 die letzte. DieseAdresszuweisung ist praktisch, denn soll der Cluster spater einmal erweitert wer-den, so wird der funfte Knoten einfach node5 genannt und bekommt die IP-Adresse192.168.0.5. Wenn ein Cluster mehr als 254 Knoten hat, so mussen IP-Adressenaus den Bereichen 172.16.xxx.xxx bis 172.31.xxx.xxx verwendet werden. Die zwei-te Netzwerkkarte des Servers hat die IP-Adresse 123.234.20.40. Jede der beidenServernetzwerkkarten lasst sich uber einen eigenen Hostnamen ansprechen, der Na-me server entspricht der internen Adresse 192.168.0.254 und calculus der externenAdresse 123.234.20.40. Wenn Sie einen Cluster nach unserem Beispiel-Cluster auf-bauen, so mussen Sie naturlich eine andere Adresse wahlen. Naheres erfahren Sievon Ihrem Netzwerkadministrator.

In manchen Clustern werden getrennte Netze fur Netzwerkdienste und Kommuni-kation der Anwendungsprogramme aufgebaut. Bei einer solchen Konfiguration muss-te jeder Knoten des Beispiel-Clusters mit einer weiteren Netzwerkkarte ausgestat-tet werden und diesen Netzwerkinterfaces wurden z. B. Adressen aus dem Bereich192.168.1.xxx zugewiesen.

5.3 Erstinstallation

5.3.1 Hardwareaufbau

Der Einstieg ins Cluster-Computing gestaltet sich zunachst schweißtreibend, namlichmit dem Aufbau der Hardware. Um einigen Problemen im spateren Betrieb von vorn-herein aus dem Weg zugehen, sollten Sie dabei einige Punkte berucksichtigen.

• Achten Sie darauf, dass die Knoten sicher und fest in Racks oder Regalen mon-tiert werden.

• Da ein Cluster relativ viel Strom benotigt, muss er uber eine eigene hinreichenddimensionierte Stromzuleitungen und Sicherungen verfugen. Großere Clusterkonnen auch uber mehrere Stromanschlusse, die jeweils kleinere Knoten-Grup-pen mit Strom versorgen, verfugen. Bei der Dimensionierung von Kabeln undSicherungen kann meist eine Leistungsaufnahme von ca. 200 W bis 300 W jeKnoten angenommen werden (Notiz 4.5).

• Schatzen Sie schon vor dem Aufbau ab, wie lang die Strom- und Netzwerkka-bel sein mussen. Mit zu kurzen Kabeln geht gar nichts, zu lange Kabel werdenaber auch schnell zu einem Problem. Netzwerkkabel kann man in verschiedenenstandardisierten Langen kaufen oder individuell zuschneiden. Dazu bedarf es spe-zieller Werkzeuge (z. B. einer Crimp-Zange) und etwas Erfahrung. In der Regellohnt der Aufwand fur individuell zugeschnittene Kabel nicht.

• Achten Sie auf eine geordnete Fuhrung der Strom- und Netzwerkkabel, damit beider Vielzahl von Kabeln der Cluster nicht zu einem gordischen Kabelknoten aus-artet. Insbesondere darf durch die Kabel der zur Kuhlung notwendige Luftstrom

Page 90: [X.systems.press] Cluster Computing ||

82 5 PCs vernetzen

Abb. 5.3. Ubersichtliche Verkabelung in einem 19-Zoll-Schrank.

nicht behindert werden. Dies gilt besonders fur Flachbandkabel innerhalb vonKnoten. Bei 19-Zoll-Schranken konnen die Kabel oft in Kabelschachten verlegtoder mit Kabelbindern befestigt werden, siehe Abb. 5.3. Wenn der Cluster mehre-re funktional getrennte Netzwerke besitzt, so sollten deren Kabel auch verschie-den farblich gekennzeichnet sein. Dies hilft bei der Suche nach Hardwarefehlern.

• Bauen Sie die Knoten so in Racks oder Regale ein, dass sie fur Reparaturen leichtwieder ausgebaut werden konnen und alle Kabel und Schalter leicht zuganglichsind.

• Beschriften Sie Knoten und Kabel. Vermerken Sie auf den Knoten wichtige Da-ten wie IP-Adresse, Seriennummer sowie, falls der Cluster aus Knoten mit unter-schiedlicher Hardware bestehen, CPU-Typ und -Anzahl, Speichergroße, Festplat-tentyp und -große. Wenn Teile des Clusters uber eigene elektrische Sicherungenverfugen, kennzeichnen Sie auch, welche Sicherung welchen Teil schutzt.

5.3.2 Linux-Installation

Nachdem Sie die Hardware Ihres Cluster aufgebaut und die Knoten physisch vernetzthaben, mussen Sie auf dem Server und einem Knoten Linux aufspielen. Es ist nichtsehr wichtig, welche Linux-Distribution Sie wahlen. Wahlen Sie eine Distribution,mit der Sie vertraut sind.

Zunachst muss das Betriebssystem nur auf dem Server und auf einem der Kno-ten installiert werden. Die Software-Installation dieses Knotens wird spater auf alle

Page 91: [X.systems.press] Cluster Computing ||

5.3 Erstinstallation 83

weiteren compute nodes mittels einer Cluster-Management-Software repliziert, wiein Abschnitt 5.5 beschieben. Achten Sie bei der Erstinstallation von Linux darauf,dass Sie auf Knoten und Server ein moglichst schlankes System erhalten. InstallierenSie zunachst nur Pakete, die die Distribution zum Funktionieren unbedingt benotigt.Verzichten Sie insbesondere auf eine graphische Nutzeroberflache und alle anderenDesktop-Anwendungen. Alle Programme, die uber eine Minimalinstallation hinaus-gehen (z. B. ein Compiler), konnen spater bei Bedarf nachinstalliert werden.

Fur einen zuverlassigen Serverbetrieb sind heute Journaling-Dateisysteme un-erlasslich. Journaling-Dateisysteme protokollieren den Beginn und das Ende jederDateioperation und sorgen dafur, dass sich das Dateisystem immer in einem konsis-tenten Zustand befindet. Ohne Journaling-Dateisystem musste das Dateisystem nacheinem Absturz erst auf Fehler uberpruft werden, was bei der Große heutiger Fest-platten durchaus eine halbe Stunde und langer dauern kann. Da durch das Protokolleines Journaling-Dateisystems die Prufung auf Inkonsistenzen entfallen kann bzw.stark verkurzt wird, bootet ein Computer nach einem Absturz ohne großere Verzoge-rungen. Fur Linux gibt es mehrere, unter verschiedenen Gesichtspunkten optimierteJournaling-Dateisysteme:

Ext3. Ein um Journaling-Funktionen erweitertes Ext2.Reiser-FS. Von Hans Reiser entwickeltes Dateisystem, das fur Server mit vielen

kleinen Dateien optimiert wurde.Reiser-FS 4. Ein neues viel versprechendes von Hans Reiser entwickeltes Allzweck-

Dateisystem. Zu den spektakularsten Eigenschaften dieses Dateisystems gehorenz. B. atomare Transaktionen, die garantieren, dass Dateioperationen immer be-reits abgeschlossen oder noch gar nicht angefangen sind. Der Computer kannalso nicht mitten in einer Dateioperation absturzen und so das Dateisystem ineinem inkonsistenten Zustand hinterlassen.

XFS. Journaling-Dateisystem aus dem SGI-Betriebssystem IRIX.JFS. Journaling-Dateisystem von IBM, optimiert fur große Dateien und großen Da-

tendurchsatz.

Ext3 und Reiser-FS gelten momentan (Ende 2004) als die zuverlassigsten Journaling-Dateisysteme. XFS und JFS sind weit weniger verbreitet und noch nicht so stabil.

Der Server des Clusters sollte unbedingt mit Journaling-Dateisystemen arbeiten.Diese mussen bereits bei der Erstinstallation angelegt werden. Mit aktuellen Distri-butionen, deren Installationswerkzeuge heute meist Ext3 und Reiser-FS unterstutzen,ist das kein Problem. Ein Ext2 (das Standard-Dateisystem unter Linux) kann auchnachtraglich in ein Ext3-Dateisystem gewandelt werden, vorausgesetzt der Kernelunterstutzt Ext3. Dazu sind die Dateisystemtypen in der Datei /etc/fstab vonext2 in ext3 zu andern. Danach muss der Computer so gebootet werden, dass kei-ne der nach Ext3 zu wandelnden Partitionen eingebunden ist. Am einfachsten gehtdas mit einer von CD-ROM startbaren Linux-Distribution wie Knoppix [84]. DasProgramm tune2fs legt auf einer Partition (hier /dev/hda1) ein Ext3-Journalan.

Page 92: [X.systems.press] Cluster Computing ||

84 5 PCs vernetzen

root@tty1[/]# tune2fs -j /dev/hda1tune2fs 1.35-WIP (31-Jan-2004)Creating journal inode: doneThis filesystem will be automatically checked every 34 mounts or180 days, whichever comes first. Use tune2fs -c or -i to override.

Journaling-Dateisysteme erfordern vom Betriebssystem einen gewissen Mehr-aufwand und sind darum tendenziell langsamer als Dateisysteme ohne Journaling-Funktion. Kommt es bei den compute nodes eher auf hohen Datendurchsatz als aufVerfugbarkeit an, so kann bei ihnen auf ein Journaling-Dateisystem verzichtet wer-den.

5.3.3 Kernel-Anpassungen und Hardware-Monitoring

Fur den Anfang ist es meist nicht zwingend notwendig, einen neuen Kernel zu bauen.Die Standardkernel aktueller Linux-Distributionen unterstutzen alle gangigen Hard-warekomponenten. Sie konnen beim ersten Lesen diesen Abschnitt auch ubersprin-gen und bei Bedarf hierher zuruckkehren.

Fruher oder spater wird man aber meist doch einen speziell auf die Cluster-Hard-ware abgestimmten Kernel bauen wollen. Dafur gibt es verschiedene Grunde.

• Wollen Sie Hardware nutzen, die nicht vom Standard-Kernel unterstutzt wird, somussen Sie auf jeden Fall einen neuen Kernel bauen.

• Sollen die Knoten durch Hardware-Monitoring uberwacht werden, um defekteLufter und andere Hardwareausfalle fruhzeitig zu erkennen, so mussen Sie (wahr-scheinlich) die Kernel-Quellen modifizieren und den Kernel selbst kompilieren.

• Die Standard-Kernel unterstutzen meist nur eine CPU je Motherboard. HabenSie ein SMP-System, so mussen Sie auch einen neuen Kernel bauen.

• Ein angepasster Kernel ist meist schlanker und stabiler.

Um einen eigenen Kernel zu bauen, besorgen Sie sich zunachst von [79] die Quel-len eines aktuellen stabilen (gerade Nummer nach dem ersten Punkt der Versions-nummer) Kernels, kopieren ihn nach /usr/src/, entpacken ihn und legen einensymbolischen Link linux auf das Quellverzeichnis an.

root@server:/usr/src# tar xjvf linux-2.4.26.tar.bz2root@server:/usr/src# ln -fs linux-2.4.26 linux

Leider unterstutzt der offizielle Linux-Kernel der 2.4er-Serie kein Hardware-Monito-ring, und Kernel 2.6er-Serie beinhalten standardmaßig nur eine beschrankte Auswahlan Hardware-Monitoring-Treibern. Deswegen mussen Sie die Kernel-Quellen wahr-scheinlich noch modifizieren und die Treiber des Lm sensors-Projekts installieren.Die Quellen fur das Hardware-Monitoring erhalten Sie unter [63]. Neben den Quel-len fur das Hardware-Monitoring werden eventuell noch die Quellen einer neuerenVersion der I2C-Bustreiber benotigt. Auch diese erhalten Sie bei [63] und sollten insVerzeichnis /usr/src/ entpackt werden. Der I2C-Bus ist ein sehr einfacher Bus-typ der z. B. fur die Steuerung von Unterhaltungselektronik genutzt wird, außerdemwerden auch die Daten des Hardware-Monitorings uber diesen Bustyp ubertragen.

Page 93: [X.systems.press] Cluster Computing ||

5.3 Erstinstallation 85

root@server:/usr/src# tar xzvf i2c-2.8.7.tar.gzroot@server:/usr/src# tar xzvf lm_sensors-2.8.7.tar.gz

Die Quellen der I2C-Bustreiber und der Treiber fur das Hardware-Monitoring brin-gen jeweils ein kleines Programm mit, das die Modifizierung des Originalkernelsvornimmt. Diese Programme werden durch

root@server:/usr/src/i2c-2.8.7# mkpatch/mkpatch.pl . /usr/src/linux | \> patch -p1 -E -d /usr/src/linux

und

root@server:/usr/src/lm_sensors-2.8.7# mkpatch/mkpatch.pl \> . /usr/src/linux | patch -p1 -E -d /usr/src/linux

aufgerufen. Es mussen also keine Quellcodedateien von Hand geandert werden.Als nachstes ist der Kernel zu konfigurieren. Dabei wird festgelegt, welche Trei-

ber in den Kernel wie integriert werden. Mit

root@server:/usr/src/linux# make menuconfig

startet ein menugesteuertes Programm, mit dem alle notwendigen Einstellungen vor-genommen werden. Nehmen Sie sich dafur Zeit.

Wie diese Einstellungen konkret aussehen, hangt von der Art der verwendetenHardware ab. Darum konnen hier nur allgemeine Hinweise gegeben werden. Schau-en wir uns einige Menupunkte genauer an.

Code maturity level options. Hier werden Sie gefragt, ob auch sehr neue, noch alsexperimentell gekennzeichnete Treiber in den folgenden Menus angezeigt wer-den sollen. Wahlen Sie diese Option.

Loadable module support. Der Linux-Kernel ist modularisierbar. Dadurch konnenTreiber zur Laufzeit als Module in den Kernel geladen und entfernt werden. Diesist eine sehr nutzliche Funktion. Aktivieren Sie alle Punkte in diesem Menu.

Processor type and features. Hier konnen Sie den Prozessortyp auswahlen, fur dender Kernel optimiert wird. Außerdem sind die Punkte High Memory Supportund Symmetric multi-processing support wichtig. Wahlen Sie bei High MemorySupport• off, wenn der Knoten weniger als 1 GB Hauptspeicher hat,• 4 GB, wenn der Knoten zwischen 1 GB und 4 GB Hauptspeicher hat bzw.• 64 GB, wenn der Knoten mehr als 4 GB Hauptspeicher hat.Symmetric multi-processing support muss aktiviert werden, wenn der Knotenmehr als eine CPU hat.

General setup. Aktivieren Sie die Netzwerkunterstutzung.Multi-device support (RAID and LVM). Dieser Menupunkt ist relevant, falls auf

dem Server des Clusters ein Software-RAID-System [129] eingerichtet werdensoll. Mittels LVM [93] lasst sich eine logische Schicht zwischen Dateisystemund der Partition einer physikalischen Festplatte schieben. So ist es u. a. moglich,ein Dateisystem uber mehrere Partitionen und Festplatten zu strecken.

Page 94: [X.systems.press] Cluster Computing ||

86 5 PCs vernetzen

Networking options. Hier mussen auf jeden Fall die Punkte TCP/IP networkingund Unix domain sockets ausgewahlt werden. Sinnvoll ist auch die FunktionNetwork packet filtering. Sie wird auf dem Server benotigt, wenn ein DHCP-Server oder eine Firewall eingerichtet werden soll, siehe Abschnitt 5.6.6. Furfestplattenlose Knoten sind noch die Optionen IP: kernel level autoconfigurationund IP: DHCP support auszuwahlen, siehe Abschnitt 5.8. Unter IP: NetfilterConfiguration befinden sich diverse Firewall-Funktionen, dazu zahlt auch NAT,siehe Abschnitt 5.6.5.

ATA/IDE/MFM/RLL support. Hier finden Sie die Treiber fur ATA-Festplattenund ATAPI-CDROM-Laufwerke. Treiber fur Festplatten, von denen gebootetwird, mussen fest in den Kernel (nicht als Modul) eingebaut werden.

SCSI support. Hier finden Sie die Treiber fur SCSI-Festplatten und SCSI-CDROM-Laufwerke. Ab Kernel 2.4.27 liegen hier auch die SATA-Treiber.

Network device support. Neben den Treibern fur verschiedene Netzwerkkarten fin-den Sie hier den channel-bonding-Treiber, siehe Abschnitt 5.7.

Character devices. Hier konnen Sie meist die Voreinstellungen ubernehmen. In denUntermenus I2C support und Hardware sensors support finden Sie die Treiberfur das Hardware-Monitoring. Integrieren Sie die Treiber I2C support, I2C bit-banging interfaces, I2C device interface und I2C /proc interface als Module inden Kernel. Unter I2C mainboard interfaces mussen Sie die fur Ihr Motherboardpassenden Treiber auswahlen. Es ist meist etwas schwierig, herauszubekommen,welcher der richtige ist. Im Zweifelsfalle wahlen Sie alle als Modul aus undtesten Sie spater, welcher Treiber mit Ihrer Hardware zusammenarbeitet. UnterHardware sensors support sind die Treiber fur das eigentliche Hardware-Moni-toring auszuwahlen. Wenn Sie nicht wissen, welche Chips auf dem Motherboardverbaut sind, wahlen Sie wieder alle Treiber als Modul und testen spater, welchermit der Hardware harmoniert.

File systems. Mochten Sie den Plattenplatz, den jedem Nutzer spater zur Verfugungsteht, begrenzen, so wahlen Sie Quota support. Außerdem sind hier die Treiberfur die verwendeten Dateisysteme zu aktivieren. Dies sind meist Ext3 journal-ling file system, ISO 9660 CDROM file system, /proc file system und Secondextended fs. Unter Network File Systems wird, falls es sich um einen Kernelfur den Server handelt, NFS server support sonst NFS file system support aus-gewahlt. Fur Testzwecke kann es sinnvoll sein, auch fur einen Server-KernelNFS file system support zu aktivieren. Dann kann der NFS-Server auch Dateienan sich selbst exportieren. In Clustern, bei denen alle Knoten außer dem Server-Knoten keine eigene Festplatte haben, muss fur die festplattenlosen Knoten NFSfile system support fest in den Kernel eingebaut und zusatzlich die Option Rootfile system on NFS ausgewahlt werden, siehe Abschnitt 5.8.

Treiber in Menupunkten, die hier nicht beschrieben wurden, werden in der Regel ineinem Cluster-Knoten nicht benotigt (z. B. Treiber fur TV-Karten, ISDN-Karten undandere exotische Hardware) oder es konnen die Standardeinstellungen ubernommenwerden.

Page 95: [X.systems.press] Cluster Computing ||

5.3 Erstinstallation 87

Listing 5.1. Erganzungen fur die Datei /etc/lilo.conf.

image = /boot/vmlinuz-2.4.24 # Kernel-Dateiinitrd = /boot/initrd-2.4.24 # Initrd-Dateiroot = /dev/hda1 # Root-Devicelabel = kernel-2.4.24 # Name

5 append = "" # Kerneloptionen

Listing 5.2. Erganzungen fur die Datei /boot/grub/menu.lst.

title kernel-2.4.24kernel (hd0,0)/boot/vmlinuz-2.4.24 root=/dev/hda1initrd (hd0,0)/boot/initrd-2.4.24

Der Kernel kann nun mit den Kommandos

root@server:/usr/src/linux# make deproot@server:/usr/src/linux# make cleanroot@server:/usr/src/linux# make bzImageroot@server:/usr/src/linux# make modulesroot@server:/usr/src/linux# make modules_install

ubersetzt und die Module installiert werden. Das letzte dieser Kommandos kopiertdie Module des Kernels nach /lib/modules/ der eigentliche Kernel liegt nochunter /usr/lib/linux/arch/i386/boot/bzImage. Kopieren Sie diese Da-tei nach /boot/vmlinuz-2.4.24. Damit dieser Kernel auch gestartet werdenkann, muss noch die Konfiguration des Bootloaders angepasst werden. Falls der Boot-loader Lilo verwendet wird, so sind der Datei /etc/lilo.conf die in Listing 5.1gezeigten Zeilen hinzuzufugen und anschließend das Programm lilo auszufuhren.Im Falle des Bootloader Grub fugen Sie der Datei /boot/grub/menu.lst diein Listing 5.2 gezeigten Zeilen hinzu. Naturlich mussen Sie statt /dev/hda1 einfur Ihren Knoten passendes Root-Device angeben. Ist alles glatt gelaufen, startet derComputer nach einem Reboot mit dem neuen Kernel.

Wir haben hier beschieben, wie ein Kernel gewissermaßen zu Fuß kompiliertund installiert wird. Einige Distributionen haben Werkzeuge, die die oben gezeigtenSchritte vereinfachen, z. B. make-kpkg bei Debian. Wenn Sie mit diesen Werkzeu-gen vertraut sind, sollten Sie diese benutzen. Etwas ausfuhrlicher, als es hier moglichist, wird die Installation eines Kernels in [87, 46] beschrieben.

Nachdem der neue Kernel erfolgreich gebootet wurde, kann es an die Aktivie-rung des Hardware-Monitoring gehen. Fur das Hardware-Monitoring werden zumeinen die Kerneltreiber benotigt, die gerade erstellt wurden, und zum anderen einigeHilfsprogramme und eine Shared-Library. Diese mussen noch mit

root@server:/usr/src/lm_sensors-2.8.7# make user_install; ldconfig

ubersetzt und installiert werden. Achten Sie darauf, dass der Pfad /usr/local/lib in /etc/ld.so.conf gelistet wird, sonst wird die Lm sensors-Bibliothekspater vom dynamischen Linker nicht gefunden.

Page 96: [X.systems.press] Cluster Computing ||

88 5 PCs vernetzen

Obiges make-Kommando erstellt u. a. die Programme sensors-detect undsensors. Mit sensors-detect konnen Sie testen, welche Treiber die richtigenfur die Hardware-Monitoring-Chips Ihres Motherboards sind. Im Wesentlichen ver-sucht das Programm nacheinander alle Hardware-Monitoring-Treiber zu laden undgibt zum Schluss eine Liste der Treiber aus, die erfolgreich geladen werden konn-ten. Es liegt im Verzeichnis /usr/src/lm sensors-2.8.7/prog/detect.Wenn bekannt ist, welche Kernelmodule die fur das Hardware-Monitoring verant-wortlich sind, konnen diese nun mit modprobe geladen werden. (Bei Ihrer Hardwa-re sind wahrscheinlich andere Module zu laden.)

root@server:˜# modprobe i2c-i801; modprobe i2c-isa; modprobe it87root@server:˜# lsmodModule Size Used by Not taintedit87 9408 0 (unused)i2c-proc 5760 0 [it87]i2c-isa 768 0 (unused)i2c-i801 4268 0 (unused)i2c-core 14208 0 [it87 i2c-proc i2c-isa i2c-i801]

Ruft man das Programm sensors ohne irgendwelche Parameter auf, so zeigt esCPU-Temperatur, Umdrehungszahl der Lufter und andere Hardware-Monitoring-Da-ten an. Zuvor muss es aber einmalig mit der Option -s gestartet worden sein. DieseOption veranlasst das Programm, die Konfigurationsdatei /etc/sensors.confeinzulesen. In dieser Datei wird u. a. festgelegt, wie die Rohdaten der Hardware-Monitoring-Chips in Temperatur- und Spannungswerte umgerechnet werden. Unter/usr/src/lm sensors-2.8.7/etc/sensors.conf.eg liegt eine Datei,die als Ausgangspunkt fur eine individuelle /etc/sensors.conf-Datei dienenkann und in ihrem Kommentar den Aufbau einer Hardware-Monitoring-Konfigurati-onsdatei beschreibt. Es ist meist nicht ganz einfach herauszufinden, wie die Rohda-ten in physikalische Großen umgerechnet werden. Auf [63] finden sich eine FAQ undein Supportforum, die bei Problemen oft weiterhelfen konnen. Haben Sie die Datei/etc/sensors.conf endlich erfolgreich eingerichtet, konnen Sie Ihrer Hardwa-re den Puls fuhlen, siehe Terminal Session 5.1. Die Ausgabe wird bei Ihnen etwas an-

Terminal Session 5.1. Das Programm sensors aus dem Lm sensors-Projekt liest die Hard-ware-Monitoring-Daten aus.root@server:˜# sensors -sroot@server:˜# sensorssensorsit87-isa-0290Adapter: ISA adapterVCore: +1.52 V (min = +1.44 V, max = +1.60 V)+3.3V: +3.31 V (min = +3.14 V, max = +3.46 V)+5V: +5.06 V (min = +4.74 V, max = +5.24 V)+12V: +11.96 V (min = +11.40 V, max = +12.60 V)Stdby: +3.02 V (min = +2.85 V, max = +3.15 V)VBat: +3.06 VCPU fan: 1418 RPM (min = 998 RPM, div = 8)Sys. fan: 1687 RPM (min = 998 RPM, div = 8)Sys. temp: +25 C (low = +40 C, high = +45 C) sensor = thermistorCPU temp: +39 C (low = +60 C, high = +65 C) sensor = diode

Page 97: [X.systems.press] Cluster Computing ||

5.3 Erstinstallation 89

Listing 5.3. Beispiel-Init-Skript fur Hardware-Monitoring.

#! /bin/sh#PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/binNAME=lm-sensors

5 DESC="harware monitoring"set -ecase "$1" in

start)echo -n "Starting $DESC: "

10 modprobe i2c-i801; modprobe i2c-isa; modprobe it87/usr/local/bin/sensors -secho "$NAME.";;

stop)15 echo -n "Stopping $DESC: "

modprobe -r it87; modprobe -r i2c-i801; modprobe -r i2c-isaecho "$NAME.";;

reload)20 echo "Reloading $DESC configuration files."

sensors -s;;

restart|force-reload)echo -n "Restarting $DESC: "

25 ($0 stop) > /dev/null($0 start) > /dev/nullecho "$NAME.";;

*)30 N=/etc/init.d/$NAME

echo "Usage: $N {start|stop|restart|force-reload}" >&2exit 1;;

esac35 exit 0

ders aussehen. Zahl und Art der uberwachten Parameter variieren von Motherboardzu Motherboard.

5.3.4 Hardware-Monitoring per Init-Skript starten

Naturlich ist es viel zu umstandlich, die Module fur das Hardware-Monitoring nachjedem Systemstart wie oben gezeigt erneut zu laden. Im praktischen Betrieb uber-nimmt ein Init-Skript diese Aufgabe. Init-Skripten sind kleine Shell-Programme, diebei jedem Systemstart (genauer beim Wechsel des Runlevels) ausgefuhrt werden. Sieliegen je nach Distribution unter /etc/init.d oder /etc/rc.d/init.d. Init-Skripten konnen mit den Optionen start oder stop aufgerufen werden. Ersterestartet einen Dienst oder eine Funktion, letztere beendet einen Dienst. Manchmalgibt es noch eine reload-Funktion, die den Dienst zwingt, seine Konfigurationsda-teien erneut einzulesen, oder eine restart-Funktion, die einen Dienst beendet undwieder startet.

Page 98: [X.systems.press] Cluster Computing ||

90 5 PCs vernetzen

Listing 5.3 zeigt ein Init-Skript fur Hardware-Monitoring unter Debian GNU/Li-nux. Bei anderen Distributionen sehen Init-Skripten ahnlich aus, jedoch sind eventu-ell distributionsspezifische Besonderheiten zu beachten. Schauen Sie dazu in der Do-kumentation Ihrer Distribution oder in [87] nach. Speichern Sie das Init-Skript unter/etc/init.d/sensors bzw. /etc/rc.d/init.d/sensors. Beim Wech-sel des Runlevels werden Init-Skripten nicht direkt sondern uber eine Reihe von sym-bolischen Links aufgerufen. Diese legen Sie mit den Programmen update-rc.d(Debian), yast (SuSE) oder chkconfig (RedHat) an. Da Init-Skripten der typi-sche Startmechanismus fur Dienste aller Art sind, werden wir ihnen in den nachstenAbschnitten noch ofters begegnen.

5.4 Netzwerk-Basiskonfiguration

Die Basiskonfiguration des Netzwerks wird meist schon automatisch bei der Erst-installation von Linux durch das Installationsprogramm der Linux-Distribution vor-genommen. Falls dies doch nicht geschah oder diese Konfiguration noch nicht denBedurfnissen des Clusters entspricht, so erfahren Sie in diesem Abschnitt, wie unterLinux das Netzwerk eingerichtet wird. Leider unterscheiden sich die verschiedenenLinux-Distributionen in den Details dieser Konfiguration, so dass hier die Netzwerk-konfiguration nur in groben Zugen beschrieben werden kann. Konsultieren Sie imZweifel die Dokumentation der verwendeten Linux-Distribution.

5.4.1 Netzwerkkartentreiber laden

Damit ein Knoten uber ein Netzwerk kommunizieren kann, muss zunachst die Netz-werkkarte vom installierten Linux-Kernel unterstutzt werden. Die meisten Linux-Dis-tributionen liefern einen Kernel aus, der die gangigsten Netzwerkkarten in Form ei-nes Kernelmodules unterstutzt. Kann der installierte Kernel die Netzwerkkarte nichtansprechen, so muss ein neuer Kernel mit entsprechender Unterstutzung kompiliertwerden. Dazu wahlen Sie bei der Kernelkonfiguration unter Ethernet (10 or 100Mbit)oder Ethernet (1000Mbit) im Menu Network device support den notwendigen Trei-ber. Dieser kann entweder als fester Kernelbestandteil oder Kernelmodul kompiliertwerden. Da die Knoten eines Clusters auf eine standige Netzanbindung angewiesensind, sollte der Treiber fest in den Kernel eingebaut werden. Die Modifizierung undKompilierung eines Linux-Kernels wird in Abschnitt 5.3.3 beschrieben.

Falls der Netzwerkkartentreiber als Modul kompiliert wurde, so muss dieses mitdem Programm modprobe geladen werden. Das Programm lsmod zeigt alle mo-mentan geladenen Module an.

root@server:˜# modprobe 3c59xroot@server:˜# lsmodModule Size Used by Not tainted3c59x 25000 0 (unused)

Page 99: [X.systems.press] Cluster Computing ||

5.4 Netzwerk-Basiskonfiguration 91

Hier wurde das Modul 3c59x (fur Karten der Firma 3Com der Serien 3c59x und3c90x) geladen. Wenn Sie nicht wissen, von welchem Modul Ihre Netzwerkkarte un-terstutzt wird, schauen Sie in der Kerneldokumentation unter /usr/src/linux/Documentation/networking nach. Hier erfahren Sie auch, welche Parameterdem Modul beim Laden mit modprobe zur Beeinflussung verschiedener Funkti-onen ubergeben werden konnen.

Konnte das Kernelmodul erfolgreich geladen werden, richten Sie den Computerso ein, dass es bei jedem Systemstart automatisch geladen wird. Unter Debian GNU/-Linux ist dazu der Modulname in der Datei /etc/modules einzutragen. Verwen-den Sie SuSE bzw. RedHat, so erganzen Sie in der Datei /etc/init.d/boot.local bzw. /etc/rc.d/rc.local die folgende Zeile.

modprobe 3c59x

Schlagt das Laden eines Kernelmodules fehl, so geben die Fehlermeldungen des Pro-gramms modprobe Hinweise auf die Fehlerursache. In solch einem Fall uberprufenSie die folgenden Punkte:

• Ist das Modul im Kernel uberhaupt vorhanden? (Siehe /lib/modules.)• Wird die Netzwerkkarte wirklich vom Modul unterstutzt?• Ist die Hardware der Netzwerkkarte intakt?

5.4.2 IP-Adresse zuweisen und Gateway einrichten

Nachdem der Treiber der Netzwerkkarte geladen wurde, weiß der Kernel zwar vonder Existenz der Netzwerkkarte und kann sie ansprechen, jedoch noch keine TCP/IP-Pakete senden oder empfangen. Das Interface muss erst noch mit dem Programmifconfig konfiguriert und ihm eine IP-Adresse zugeordnet werden. Netzwerkin-terfaces identifiziert der Kernel uber verschiedene symbolische Namen. Zu diesensymbolischen Namen gehoren u. a.:

eth0 und eth1. Der Name eth0 steht fur die erste Ethernetkarte und eth1 fur zweiteEthernetkarte in einem Computer.

lo. Uber das lokale Loopback-Interface lo laufen ausschließlich Verbindungen inner-halb eines Rechners.

bond0. Dies ist das Bonding-Interface, ein Interface, das mehrere physische Netz-werkinterfaces zu einem logischen Interface zusammenfasst. Dadurch kann jenach Betriebsmodus die Netzbandbreite erhoht oder eine hochverfugbare Netz-verbindung aufgebaut werden, siehe Abschnitt 5.7.

Das folgende Kommando weist dem ersten Ethernet-Interface (eth0) die IP-Adresse192.168.0.254 und die Netzmaske 255.255.255.0 zu, danach wird diese Konfigurati-on mittels ifconfig angezeigt.

Page 100: [X.systems.press] Cluster Computing ||

92 5 PCs vernetzen

root@server:˜# ifconfig eth0 192.168.0.254 netmask 255.255.255.0 uproot@server:˜# ifconfigeth0 Link encap:Ethernet HWaddr 00:04:75:E3:9D:45

inet addr:192.168.0.254 Bcast:192.168.0.255 Mask:255.255.255.0UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1RX packets:53 errors:0 dropped:0 overruns:0 frame:0TX packets:13 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:100RX bytes:10464 (10.2 KiB) TX bytes:1035 (1.0 KiB)Interrupt:18 Base address:0xc400

Auf die gleiche Weise wird auch die zweite Ethernetkarte mit der IP-Adresse123.234.20.40 und der Netzmaske 255.0.0.0 konfiguriert.

root@server:˜# ifconfig eth1 123.234.20.40 netmask 255.0.0.0 up

Der Server kann nun mit allen Netzwerkinterfaces mit den Netzen 192.168.0.xxx und123.xxx.xxx.xxx kommunizieren. Damit ein Datenaustausch auch uber Netzwerk-grenzen hinaus erfolgen kann, dient ein Internet-Gateway (auch IP-Router genannt).Mit

root@server:˜# route add default gw 123.234.20.254

wird der Rechner mit der IP-Adresse 123.234.20.254 als Standard-Gateway ein-gerichtet. Alle IP-Pakete, die fur Rechner außerhalb der Netze 192.168.0.xxx und123.xxx.xxx.xxx bestimmt sind, werden zunachst an die Adresse 123.234.20.254 ge-schickt. Der Router leitet diese IP-Pakete dann weiter an ihr Ziel oder einen anderenRouter. Die Adressen 123.234.20.40 und 123.234.20.254 dienen hier wieder nur alsillustrierendes Beispiel. Welche Adressen Sie in Ihrem Cluster verwenden mussen,erfahren Sie bei Ihrem lokalen Netzwerkadministrator.

Die Funktion der eingerichteten Netzverbindung kann mit dem Programm pinggetestet werden. Dies sendet ein IP-Paket, genauer ein ICMP echo request, an einenentfernten Rechner, der mit einem echo response antwortet.

root@server:˜# ping -c 1 123.234.20.254PING 123.234.20.254 (123.234.20.254): 56 data bytes64 bytes from 123.234.20.254: icmp_seq=0 ttl=244 time=29.4 ms

--- 123.234.20.254 ping statistics ---1 packets transmitted, 1 packets received, 0% packet lossround-trip min/avg/max = 29.4/29.4/29.4 ms

Die Meldung 0% packet loss zeigt, dass die Konfiguration der Netzwerkkartenerfolgreich war.

5.4.3 Dauerhafte Speicherung der Netzwerkkonfiguration

Naturlich sollte die Konfiguration des Netzwerks automatisch bei jedem System-start durch ein Init-Skript erfolgen, siehe auch Abschnitt 5.3.4. Leider funktioniert

Page 101: [X.systems.press] Cluster Computing ||

5.4 Netzwerk-Basiskonfiguration 93

Listing 5.4. Netzwerkkonfigurationsdatei /etc/network/interfaces fur einen Serverunter Debian GNU/Linux.

# lo, eth0 und eth1 bei jedem Systemstart konfigurierenauto lo eth0 eth1# das Loopback-Interfaceiface lo inet loopback

5 # erste Ethernetkarteiface eth0 inet static

address 192.168.0.254netmask 255.255.255.0

iface eth1 inet static10 address 123.234.20.40

netmask 255.0.0.0gateway 123.234.20.254

Listing 5.5. Netzwerkkonfigurationsdatei /etc/network/interfaces fur den computenode node1 unter Debian GNU/Linux.

# lo und eth0 bei jedem Systemstart konfigurierenauto lo eth0# das Loopback-Interfaceiface lo inet loopback

5 # erste Ethernetkarteiface eth0 inet static

address 192.168.0.1netmask 255.255.255.0

das bei jeder Distribution etwas anders. Unter Debian und verwandten Distributio-nen wertet das Init-Skript /etc/init.d/networking die Konfigurationsdatei/etc/network/interfaces aus. Auf dem Server des Beispiel-Clusters mussdiese Datei den in Listing 5.4 gezeigten Inhalt haben. Bei RedHat liegen die Konfi-gurationsdateien im Verzeichnis /etc/sysconfig/network-scripts/ undbei SuSE stehen alle Konfigurationsdaten in /etc/rc.config. Konsultieren Sieim Zweifelsfalle das Handbuch Ihrer Distribution.

Nachdem die Netzwerkkarten des Servers konfiguriert wurden, muss auf die glei-che Weise die Netzwerkkarte des ersten Knotens eingerichtet werden, siehe auchListing 5.5. Da dieser Knoten keine Verbindung zu Rechnern außerhalb des Netzes192.168.0.xxx hat, braucht hier kein Standard-Gateway konfiguriert werden. Sollendie Knoten node1 bis node4 doch TCP/IP-Verbindungen zu entfernten Rechnern auf-bauen konnen, muss auf dem Server Network Address Translation (kurz NAT, unterLinux oft auch IP-Masquerading genannt) eingerichtet werden. Bei einer solchenNAT-Konfiguration arbeitet der Server fur die Knoten node1 bis node4 als Standard-Gateway und manipuliert ausgehende IP-Pakete dieser Knoten so, dass sie so aus-sehen, als kamen sie direkt vom Gateway. Damit haben die Pakete eine gultige IP-Adresse (im obigen Beispiel 123.234.20.40). Einkommende Antworten auf diese Pa-kete werden ihrerseits auch wieder umgeschrieben und an den internen Empfangerweiter geleitet. Abschnitt 5.6.5 beschreibt die Einrichtung und Funktionsweise vonNAT genauer.

Page 102: [X.systems.press] Cluster Computing ||

94 5 PCs vernetzen

5.4.4 Namensauflosung

Die Verwendung von IP-Adressen zur Identifikation von Interfaces ist etwas umstand-lich, deshalb wird jeder IP-Adresse ein Name zugewiesen. Außerdem hat jeder Com-puter einen Hostnamen. Besitzt er nur ein Interface, so sind der Name des Interfacesund der Hostname identisch. Hat ein Computer jedoch mehrere Interfaces (wie derServer des Beispiel-Clusters), so wahlen Sie den Namen einer seiner IP-Adressen alsHostnamen aus. In unserem Beispiel-Cluster also server oder calculus.

Den Hostnamen konnen Sie mit dem Programm hostname setzen oder abfra-gen. Dieser wird gewohnlich beim Systemstart aus einer Konfigurationsdatei (un-ter Debian GNU/Linux /etc/hostname, unter SuSE /etc/HOSTNAME, unterRedHat /etc/sysconfig/network) gelesen und festgelegt.

Aber wie werden Namen anderer Rechner in die entsprechende IP-Adresse um-gesetzt? Dazu gibt es zwei Wege.

• Auf jedem Rechner befindet sich eine Datei /etc/hosts, die eine Zuordnungzwischen Namen und IP-Adressen enthalt.

• Ein externer Rechner dient als Domain-Name-Service-Server (DNS-Server), beidem jeder Rechner IP-Adressen erfragen kann.

Welcher Dienst zur Namensauflosung verwendet wird, legt die mit hosts: begin-nende Zeile in der Datei /etc/nsswitch fest. So veranlasst der Eintrag

hosts: files dns

das Betriebssystem, zuerst in der Datei /etc/hosts nachzuschauen. Kann einName nicht durch die Datei /etc/hosts zu einer IP-Adresse aufgelost wer-den, erfolgt danach eine Anfrage an einen DNS-Server. Dazu muss in der Datei/etc/resolv.conf die IP-Adresse des DNS-Servers eingetragen werden, z. B.:

nameserver 123.234.20.254

Uber die Datei /etc/resolv.conf konnen noch weitere Einstellungen zur Na-mensauflosung festgelegt werden, genaueres steht in der Manpage resolver(5).

Die Namen und IP-Adressen im Beispiel-Cluster andern sich nur selten, weshalbwir auf einen DNS-Server verzichten und die Hostnamen statisch in /etc/hostseintragen. Diese Datei enthalt in zwei Spalten die IP-Adresse und den (kanonischen)Namen. In zusatzlichen Spalten konnen weitere Namen fur die gleiche IP-Adresse(Aliase) angegeben werden. Diese Aliase bieten die Moglichkeit, Namensanderun-gen, abweichende Schreibweisen oder abgekurzte Rechnernamen zu benutzen, sieheauch hosts(5). Das Listing 5.6 zeigt, wie die Datei /etc/hosts auf dem Beispiel-Cluster aussehen konnte. Der Domainname ist naturlich anzupassen.

5.4.5 Tuning

Nachdem Sie die Grundkonfiguration des Netzwerks vorgenommen haben, sind derserver node sowie ein compute node zwar verbunden und konnen Daten austauschen,jedoch ist diese Grundkonfiguration nicht immer auch schon optimal. Die Palette der

Page 103: [X.systems.press] Cluster Computing ||

5.4 Netzwerk-Basiskonfiguration 95

Listing 5.6. Mit den Informationen in der Datei /etc/hosts konnen Hostnamen in IP-Adressen aufgelost werden.

127.0.0.1 localhost192.168.0.1 node1.our-domain.org node1192.168.0.2 node2.our-domain.org node2192.168.0.3 node3.our-domain.org node3

5 192.168.0.4 node4.our-domain.org node4192.168.0.254 server.our-domain.org server123.234.20.40 calculus.our-domain.org calculus

Parameter, die die Netzwerkleistung (negativ) beeinflussen konnen ist lang, und fallssie hinter den Erwartungen bleibt, ist die Ursache dafur selten gleich offensichtlich.

Darum sollten Sie sich die Zeit nehmen und nicht nur die generelle Funkti-onsfahigkeit Ihres Netzwerkes testen. Am besten einmal jetzt, wo der Cluster ausnur zwei Knoten besteht, und spater ein weiteres Mal, wenn der Cluster vollstandigaufgebaut ist. Zur Messung der Latenz und der Bandbreite empfehlen wir die Pro-grammsammlung NetPIPE [113].

Haben Ihre Tests ergeben, dass die Latenz deutlich uber bzw. die Bandbreitedeutlich unter der in Tabelle 4.1 gelisteten Werte liegt, so sollten Sie zunachst ver-suchen Hardwarefehler auszuschließen. Dazu konnen z. B. fehlerhaft verlegte Kabelgehoren. Falls Sie Raiser-Karten verwenden, stellen Sie sicher, dass durch diese derTakt des PCI-Bus nicht kunstlich heruntergesetzt wird.

Großen Einfluss auf die Netzwerkleistung hat naturlich auch der Treiber der Netz-werkkarte. Die meisten Netzwerkkartentreiber lassen sich uber Kernel- bzw. Modul-parameter konfigurieren, die in der Dokumentation des Kernels beschrieben sind undsich von Treiber zu Treiber unterscheiden. Ist der Netzwerkkartentreiber fest im Ker-nel eingebaut, so sind die Parameter beim Start des Kernels zu ubergeben. Liegt derTreiber als Modul vor, so werden sie beim Laden des Moduls angegeben. Nahereserfahren Sie in der Dokumentation des Bootloaders bzw. der Manpage modprobe(8).Beachten Sie auch, dass sich bei statisch im Kernel eingebaute Treiber oft nicht alleoder gar keine Treiberparameter verandern lassen. Module sind hier flexibler. Diesgilt insbesondere fur Treiber der verbreiteten Gigabit Ethernet Karten von Intel.

Wenn Sie keine Treiberparameter spezifizieren, werden dafur Standardwerte be-nutzt. Diese Standardwerte sind meist so gewahlt, dass der Treiber in moglichst vie-len Situationen zuverlassig arbeitet. Niedrige Latenz und hohe Bandbreite stehen beider Wahl der Standardparameter nicht zwingend im Vordergrund. Fur einen Clus-ter-Computer mussen die Standardeinstellungen darum nicht unbedingt optimal sein.Bessere Treiberparameter lassen sich meist nur durch Probieren finden. Hinweise dar-auf, durch welche Parameter Sie die Netzwerkleistung beeinflussen konnen, findenSie in der Dokumentation der Netzwerkkartentreiber unter /usr/src/linux/Documentation/networking/.

Bei einigen neueren Ethernet-Karten lassen sich einige wichtige Treiberparame-ter auch durch das Programm ethtool andern bzw. anzeigen. In Computern mitmehr als einer Ethernet-Karte kann man mit diesem Programm auch herausfinden,

Page 104: [X.systems.press] Cluster Computing ||

96 5 PCs vernetzen

welcher Karte der symbolische Name eth0, eth1 usw. zugeordnet wird. So veranlasstdas Kommando

root@server:˜# ethtool -p eth1 10

die Netzwerkkarte, der der Kernel den Namen eth1 zugewiesen hat, sich zehn Sekun-den lang (z. B. durch eine blinkende Leuchtdiode) erkennen zu geben.

Falls Ihr Cluster eine Gigabit-Ethernet-Vernetzung verwendet, konnen Sie durchjumbo frames die effektive Bandbreite steigern bzw. die durch den Netzwerkverkehrhervorgerufene CPU-Last senken. Ethernet ist ein paketorientiertes Protokoll und einEthernetpaket wird auch frame genannt. Seit der Einfuhrung Ethernet in den fruhen1980ern ist ein frame maximal 1518 Byte lang, was 1500 Byte Nutzinformation ent-spricht. Die restlichen 18 Byte enthalten protokollspezifische Daten wie Sender undEmpfanger. Auf der TCP/IP-Ebene bestimmt die frame-Lange die Maximum Trans-mission Unit (MTU). Die MTU eines Interfaces gibt das großtmogliche IP-Datenpa-ket an, das ohne Fragmentierung (Aufsplittung in mehrere kleinere Pakete) uber die-ses transportiert werden kann. Bei einer frame-Lange von 1518 Byte kann die MTUmaximal 1500 Byte betragen. Die von einigen Herstellern verwendeten frames, dielanger als 1518 Byte lang sind, werden als jumbo frames bezeichnet.

Jeder eintreffende frame wird vom Empfanger bearbeitet und der Empfang ge-genuber dem Absender bestatigt, wozu der Empfanger eventuelle andere Arbeitenunterbrechen muss. Bei einer frame-Lange von 1518 Byte und einer Bandbreite von10 MBit/s treffen die Ethernetpakete im Abstand von 1,2 ms ein, bei einer Bandbreitevon 1 GBit/s sind dies jedoch schon nur noch 12 µs. Die Einfuhrung von jumbo fra-mes bewirkt eine Senkung der Anzahl der gesendeten frames, als auch der Zeit, dieEndgerate benotigen, um jeden frame im Verhaltnis zu seiner Große zu verarbeiten.Es mussen nun nicht viele kleine frames bestatigt werden, wodurch der protokollbe-dingte Netzwerkverkehr (Bestatigung der eingetroffenen Pakete) und die CPU-Lastsinken.

Jumbo frames sind nie standardisiert worden, was sich wohl auch in absehbarerZukunft nicht andern wird. De facto hat sich jedoch eine frame-Lange von 9018 Byteetabliert, was 9000 Byte Nutzinformation entspricht. Unterstutzen Netzwerkkartenund Switches jumbo frames mit einer Lange von 9018 Byte, konnen Sie die MTUder Gigabit-Ethernet-Interfaces darum auf 9000 Byte setzen. Die MTU wird durchdas Programm ifconfig gesetzt.

root@server:˜# ifconfig eth0 192.168.0.254 netmask 255.255.255.0 \> mtu 9000 up

Falls die Netzwerkkarte keine jumbo frames unterstutzt, scheitert der Versuch, dieMTU auf einen Wert großer als 1500 zu setzen, mit einer Fehlermeldung.

Da man sich mit jumbo frames jenseits des offiziellen Ethernet-Standards be-wegt, mussen Sie bei ihrer Verwendung prinzipiell mit Inkompatibilitaten zwischenverschieden Gigabit-Ethernet-Karten und Switches rechnen. Allerdings konnen mo-derne Switches und Gigabit-Ethernet-Karten auch ohne jumbo frames Transferratenvon fast 1 GBit/s erreichen.

Page 105: [X.systems.press] Cluster Computing ||

5.5 SystemImager 97

5.5 SystemImager

Wenn Sie der Installationsanleitung bis hierher gefolgt sind und die ersten beidenSchritte der Liste auf Seite 75 abgearbeitet haben, so besteht Ihr Cluster momen-tan aus einem server node und einem compute node. Der logisch nachste Schrittauf dem Wege zu einem Cluster ware, auch auf den andern Knoten das Betriebssys-tem zu installieren und die Netzwerkkarte zu konfigurieren, ganz so wie dies schonbeim ersten Knoten geschah. Fur den hier beschriebenen Beispiel-Cluster mit viercompute nodes mag das durchaus noch machbar sein. Bei großen Clustern mit hun-dert oder mehr Knoten muss die Installation und Konfiguration jedoch automatisiertwerden. Das Betriebssystem auf jedem Konten einzeln zu installieren, dauert vielzu lange und ist fehleranfallig. Die SystemImager-Programmsammlung [164] ist einweitgehend distributionsunabhangiges Werkzeug, durch das sich die Masseninstal-lation gleichartiger Computer stark vereinfacht. Es ist ideal fur Serverfarmen undCluster-Computer.

Die Grundidee hinter SystemImager besteht darin, innerhalb eines Netzes gleich-artiger Computer nur einen dieser Computer, den golden client, zu pflegen und seineInstallation mit einigen Anpassungen auf alle anderen Computer zu kopieren. Dazuwird ein Abbild der Installation des golden client erstellt und auf einen image serverkopiert. Alle anderen Knoten gleichen ihre Softwareinstallation gegen dieses Abbildauf dem image server ab.

5.5.1 Installation

Die SystemImager-Programmsammlung besteht aus mehreren Paketen. Einige dieserPakete sind spezifisch fur einen golden client bzw. einen image server, andere werdenvon beiden benotigt. Auf dem image server mussen die Pakete systemimager-boot-i386-standard und systemimager-server installiert werden, auf dem golden client nursystemimager-client. Diese Pakete konnen noch von weiteren Paketen abhangen, dienormalerweise automatisch miteingerichtet werden.

Ausgesprochen komfortabel lasst sich SystemImager auf Debian-Systemen in-stallieren. Dort muss der Konfigurationsdatei /etc/apt/sources.list nur dieZeile

deb http://download.systemimager.org/debian stable main

hinzugefugt und apt-get update aufgerufen werden. Danach lassen sich mitdem Programm apt-get die oben genannten Pakete auf dem image server und demgolden client uber das Internet installieren. Mit einem kleinen Zusatzprogramm na-mens install gestaltet sich die Installation bei auf RPM basierende Distributionen(z. B. RedHat oder SuSE) ahnlich einfach wie bei Debian. Dieses Programm erhaltenSie unter http://sisuite.org/install. Nachdem es heruntergeladen und als ausfuhrbar er-klart wurde, konnen damit die SystemImager-Pakete uber das Internet geladen undinstalliert werden, siehe Terminal Session 5.2.

Damit die Installation uber das Internet moglich ist, muss auf dem Server einNAT (siehe Abschnitt 5.6.5) eingericht sein, sonst kann der golden client, der keine

Page 106: [X.systems.press] Cluster Computing ||

98 5 PCs vernetzen

Terminal Session 5.2. Bei auf RPM basierenden Distributionen wird SystemImager mitdem Programm install aus den Internet geladen und installiert. Mit der Option --listkonnen Sie sich vorher ein Liste verfugbarer Pake anzeigen lassen.root@server:˜# wget http://sisuite.org/installroot@server:˜# chmod +x installroot@server:˜# ./install --listUsing pre-existing package list: /tmp/sis-packages/stable.listPackages available for download and/or install:

flamethrowerperl-AppConfigperl-MLDBMsystemconfiguratorsystemimager-clientsystemimager-commonsystemimager-flamethrowersystemimager-i386boot-standardsystemimager-ia64boot-standardsystemimager-ppc64-iSeriesboot-standardsystemimager-ppc64boot-standardsystemimager-serversysteminstallersysteminstaller-x11

To install packages, do a:

./install --verbose PKG1 PKG2 ...

For example:

./install --verbose systemconfigurator perl-AppConfig

root@server:˜# ./install systemimager-server \> systemimager-i386boot-standard

offizielle IP-Adresse hat, keine Verbindung zum Server download.systemimager.orgaufbauen. Alternativ konnen Sie naturlich auch zunachst alle notwendigen Paketeauf den Server laden und von da auf den golden client kopieren.

5.5.2 Vollautomatische Installation

Um ein Abbild des golden client zu erstellen, sind zwei Schritte notwendig. Zuerstwird der golden client mit dem Programm prepareclient vorbereitet. Die Opti-on --server spezifiziert den Namen des image servers.

root@node1:˜# prepareclient --server server

Das Programm sammelt einige Informationen uber den golden client, wie die Partitio-nierungsdaten der Festplatte, und legt diese im Verzeichnis /etc/systemimagerab. Außerdem startet es einen rsync-Damon. Der rsync-Damon wird benotigt, damitdas Programm getimage vom golden client das Abbild holen kann.

root@server:˜# getimage --image cluster_1 --golden-client node1

Page 107: [X.systems.press] Cluster Computing ||

5.5 SystemImager 99

getimage berucksichtigt alle unter Linux gangigen Dateisysteme. Eventuell vor-handene Netzwerkdateisysteme und virtuelle Dateisysteme (z. B. Procfs in \proc)des golden client werden nicht ubertragen. Die Optionen --golden-client und--image sind zwingend anzugeben. Erstere bestimmt den Namen des golden client,die zweite legt einen Namen fur das Abbild fest. Zum Schluss fragt das Programm:

Would you like to update the autoinstall script for this image? ([y]/n):

Beantworten Sie diese Frage ersteinmal mit n fur ”nein“. Wir werden spater dasProgramm mkautoinstallscript von Hand starten, um ein autoinstall scriptzu erstellen.

Wie kommt nun aber das Abbild des golden client auf die anderen Knoten? DieKnoten holen es sich via rsync-Damon uber das lokale Netz vom image server. ZuSystemImager gehort ein Init-Skript, das normalerweise beim Systemstart auf demimage server einen rsync-Damon startet. Falls dieser Damon noch nicht lauft, startenSie ihn jetzt.

root@server:˜# /etc/init.d/systemimager-server startStarting rsync daemon for systemimager: rsync.

Damit ist aber noch immer unklar, wie ein Knoten sich das Abbild holen soll, istdoch auf seiner Festplatte keinerlei Software installiert, die diese Aufgabe erledigenkonnte. An dieser Stelle kommt Brian’s Own Embeded Linux ins Spiel. Dabei han-delt es sich um eine Mini-Linux-Distribution, die von Diskette, CD-ROM oder uberNetzwerk geladen werden kann. Das SystemImager-System benutzt diese Distributi-on, um auf einem Knoten ein minimales Linux, das nur im Speicher des Computerslauft, zu starten. Danach wird die Netzwerkkarte des Knotens konfiguriert. Brian’sOwn Embeded Linux unterstutzt die gangigsten Ethernetkarten, sollte die von Ihnenverwendete nicht dabei sein, so konnen Sie den Kernel dieser Mini-Linux-Distributi-on entsprechend anpassen. Die Vorgehensweise dafur wird im SystemImager-Hand-buch naher beschrieben. Konnte die Netzwerkkarte erfolgreich konfiguriert werden,so holt sich der Knoten vom image server Informationen uber die Art und Anzahlder Partitionen des golden client und partitioniert und formatiert die Festlatte ent-sprechend. Danach holt ein rsync-Client vom image server das Abbild des goldenclient. Nach ein paar Minuten kann der Knoten mit dem installierten Betriebssystemgebootet werden.

Schauen wir uns eine automatische Installation mit einer Installationsdiskette ge-nauer an. Als erstes ist mit mkautoinstalldiskette eine Boot-Diskette zu er-stellen. Das Programm formatiert eine Diskette, erstellt darauf ein DOS-Dateisystemund installiert das Mini-Linux. Da alle Knoten die gleiche Hardware besitzen, kanndie Softwareinstallation von node1 fast unverandert auf die anderen Knoten uber-tragen werden. Lediglich Hostname und IP-Adresse unterscheiden sich bei jedemKnoten. Diese variablen Daten werden in der Datei local.cfg auf der Boot-Diskette abgelegt. Listing 5.7 zeigt exemplarisch eine solche Datei, wie sie furden Knoten node2 des Beispiel-Clusters notwendig ist. Fur die anderen Knotenmuss sie jeweils angepasst werden. Die Schlusselworte und deren Werte sind sicher

Page 108: [X.systems.press] Cluster Computing ||

100 5 PCs vernetzen

Listing 5.7. Die Konfigurationsdatei local.cfg auf der Bootdiskette fur Knoten node2.

HOSTNAME=node2DOMAINNAME=our-domain.orgIMAGESERVER=192.168.0.254IMAGENAME=cluster_1

5DEVICE=eth0IPADDR=192.168.0.2NETMASK=255.255.255.0NETWORK=192.168.0.0

10 BROADCAST=192.168.0.255GATEWAY=192.168.0.254GATEWAYDEV=eth0

selbsterklarend. In der SystemImager-Dokumentation findet sich eine kommentierteBeispiel-Konfigurationsdatei, in der der Aufbau der Datei local.cfg naher be-schrieben wird. Sie liegt unter /usr/share/doc/systemimager-server/examples/local.cfg.gz. Die in local.cfg genannte IP-Adresse, Hostna-me usw. sollen auch spater im regularen Betrieb verwendet werden. Dies mussSystemImager durch das mkautoinstallscript-Programm mitgeteilt werden,andernfalls versucht der Knoten spater sein Netzwerkinterface mit DHCP zu konfi-gurieren, siehe Abschnitt 5.6.6.

root@server:˜# mkautoinstallscript --image cluster_1 --force \> --ip-assignment static

Your new autoinstall script has been created:

"/var/lib/systemimager/scripts/cluster_1.master"

Erstellen Sie nun die Datei local.cfg gemaß Listing 5.7 und erzeugen Sie danachmit den in Terminal Session 5.3 gezeigten Kommandos eine Boot-Diskette.

Der Knoten node2 kann nun mit der Boot-Diskette gestartet werden. Nachdemdie Festplatte des Knotens formatiert wurde, holt er sich das Abbild vom image ser-ver. Dieser Vorgang kann einige Minuten dauern. Nach erfolgreicher Installation be-ginnt der Knoten, aufgeregt zu piepsen. Nachdem die Diskette entfernt und der Kno-ten erneut gestartet wurde, bootet er mit dem gerade installierten Betriebssystem.Wahrend der ganzen Prozedur ist keinerlei Interaktion notwendig, alles geht (fast)vollkommen automatisch. Zum Schluss sollte der rsync-Damon wieder beendet wer-den.

root@server:˜# /etc/init.d/systemimager-server stopStopping rsync daemon for systemimager: rsync.

Falls die automatische Installation zwischendurch doch abbrechen sollte, so uber-prufen Sie folgende Punkte:

• Ist der Knoten physisch richtig an das lokale Netzwerk angeschlossen?• Wird die Netzwerkkarte des Knotens von Brian’s Own Embeded Linux un-

terstutzt?

Page 109: [X.systems.press] Cluster Computing ||

5.5 SystemImager 101

Terminal Session 5.3. Eine Boot-Diskette fur eine automatische Installation erstellen.root@server:˜# mkautoinstalldiskette -floppy /dev/fd0Here is a list of available flavors:

standard

Which flavor would you like to use? [standard]:Formatting floppy as 1.44MB ...Double-sided, 80 tracks, 18 sec/track. Total capacity 1440 kB.Formatting ... doneVerifying ... doneCreating DOS filesystem on floppy...mkdosfs 2.8 (28 Feb 2001)Using "syslinux" to make floppy bootable...Creating temporary mount point...Mounting floppy...Un-mounting floppy...Removing temporary mount point...Done!root@server:˜# mount -t msdos /dev/fd0 /floppyroot@server:˜# cp local.cfg /floppyroot@server:˜# umonut /floppy

• Lauft auf dem image server ein rsync-Damon?• Stimmen die Eintrage in der local.cfg-Datei und sind alle notwendigen Ein-

trage vorhanden?

Wir haben hier die automatische Installation mit einer Boot-Diskette beschrieben. Ei-ne Installation uber eine Boot-CD funktioniert fast genauso, nur dass hier mit denProgrammen mkautoinstallcd und cdrecord eine Boot-CD erzeugt werdenmuss. Die Konfigurationsdatei local.cfg kann entweder auf der Boot-CD oder ei-ner zusatzlichen Diskette abgelegt werden. Auch eine Installation nur uber das Netz-werk ganz ohne Boot-Diskette oder Boot-CD ist moglich. Dies setzt einen DHCP-Server und einen TFTP-Server auf dem image server voraus. Außerdem mussenBIOS und Netzwerkkarte des Knotens das Pre-Boot Execution Environment (PXE)unterstutzen und das Booten uber das Netz im BIOS aktiviert sein. Der Mehraufwandfur DHCP- und TFTP-Server lohnt sich vorallem fur große Cluster, allein schon weilman sich das Wechseln der Boot-Disketten spart. IP-Adresse und Hostname werdenper DHCP zugeteilt. Nach der Installation werden dann wahlweise immer die IP-Adresse und der Hostname verwendet, die bei der Erstinstallation mit SystemImagerper DHCP zugewiesen wurden, oder der Knoten stellt bei jedem Start eine erneuteDHCP-Anfrage.

Bei dieser Installationsmethode sollten die Knoten nach der Installation automa-tisch rebooten ohne manuell auf den Resetknopf drucken zu mussen, denn es mussja keine Boot-Diskette entfernt werden. Dies wird mit

root@server:˜# mkautoinstallscript --image cluster_1 --force \> --post-install reboot

Your new autoinstall script has been created:

"/var/lib/systemimager/scripts/cluster_1.master"

Page 110: [X.systems.press] Cluster Computing ||

102 5 PCs vernetzen

erreicht. Mehr Informationen zu einer reinen Netzwerkinstallation erhalten Sie imSystemImager-Handbuch sowie im Abschnitt 5.8, wo wir beschreiben, wie derDHCP- und der TFTP-Server aufzusetzen sind.

5.5.3 Updates

SystemImager erleichtert nicht nur die Installation der Cluster-Knoten sondern mitdem Programm updateclient auch spatere Updates. Angenommen bei einemwichtigen Programm ist ein Sicherheitsproblem bekannt geworden und es soll nuneine neue Version, die dieses Problem behebt, auf allen Knoten eingespielt werden.Dann mussen Sie zunachst auf dem image server das bestehende Abbild modifizierenoder ein neues Abbild anlegen. Sie konnen entweder

• das neue Programm direkt in das Abbild auf dem image server, das unter /var/lib/systemimager/images/ liegt, einspielen,

• das neue Programm auf dem golden client einspielen und mit prepareclientund getimage das Abbild erneut vom golden client auf den image server ko-pieren oder

• das neue Programm auf dem golden client einspielen und mit prepareclientund getimage ein Abbild mit neuem Namen vom golden client auf den imageserver kopieren.

Die erste Methode ist schnell aber etwas fehleranfallig. Da keine Abbilddateien ma-nuell geandert werden mussen, ist die zweite Methode zuverlassiger als die erste undist dabei trotzdem schnell. Das Programm getimage ubertragt hier nicht das ganzeAbbild erneut zum image server, sondern nur die Anderungen zwischen den Dateienauf dem golden client und dem schon vorhandenen Abbild. Bei der dritten Methodewird hingegen vom golden client ein vollstandiges Abbild unter einem neuen Namenerstellt. Entsprechend lange dauert der Prozess und entsprechend viel Plattenspeichermuss auf dem image server vorhanden sein. Der Vorteil der dritten Methode liegt dar-in, dass mit ihr die Knoten auch wieder leicht in einen vorherigen Zustand versetztwerden konnen. Das alte Abbild liegt ja noch immer auf dem image server.

Nachdem alle gewunschten Anderungen auf dem golden client vorgenommenwurden, bereiten Sie ihn erneut darauf vor, von ihm ein Abbild zu erstellen.

root@node1:˜# prepareclient --server server --quiet

Im unserem Beispiel legen wir ein vollstandiges neues Abbild cluster 2 an, dasder image server mit

root@server:˜# getimage --image cluster_2 --golden-client node1root@server:˜# /etc/init.d/systemimager-server startStarting rsync daemon for systemimager: rsync.

vom golden client holt. Mit dem updateclient-Kommando werden die Dateieneines Knotens mit einem Abbild auf dem image server abgeglichen. Es muss aufjedem Knoten (außer dem golden client) einzeln aufgerufen werden. Das kann beieinem großen Cluster mit vielen Knoten recht aufwendig werden. Darum gehort zu

Page 111: [X.systems.press] Cluster Computing ||

5.5 SystemImager 103

SystemImager das Programm pushupdate, das dazu dient, updateclient par-allel auf mehreren Knoten zu starten. Leider funktioniert es (zumindest in Version3.2) nicht. Stattdessen kann updateclient auch zusammen mit dsh (siehe Ab-schnitt 5.6.3) verwendet werden. Das Update eines einzelnen Knotens erfolgt durch

root@node2:˜# updateclient --server server --image cluster_2

Das Programm updateclient ubertragt nicht alle Dateien eines Abbildesauf einen Knoten. Manche Dateien der Knoten durfen auf keinen Fall durch die-ses Programm mit den Dateien des Abbilds uberschrieben werden. Dazu gehorenz. B. die Datei /etc/mtab oder das Verzeichnis /var/run. Geschahe dies doch,wurden einige Programme nicht mehr korrekt arbeiten konnen. Welche Dateienund Verzeichnisse von einem Update ausgenommen werden, wird durch die Datei/etc/systemimager/updateclient.local.exclude festgelegt. Sie be-findet sich auf jedem Knoten und enthalt standardmaßig schon die wichtigsten Da-teien und Verzeichnisse. Bei Bedarf konnen Sie hier Erganzungen vornehmen. Be-achten Sie: wenn die Datei updateclient.local.exclude nicht auf allenKnoten identisch ist, muss auch sie von einem Update ausgenommen werden undselbst in updateclient.local.exclude gelistet werden.

Nachdem alle Knoten ein neues Abbild erhalten haben, sollte der rsync-Damonwieder beendet werden.

root@server:˜# /etc/init.d/systemimager-server stopStopping rsync daemon for systemimager: rsync.

5.5.4 Sicherheit

SystemImager benutzt zum Kopieren eines Abbildes einen rsync-Damon. Dies istein extrem unsicherer Dienst, denn durch ihn konnen Daten des image servers unddes golden clients von jedem Computer im Internet gelesen werden. Der rsync-Damon verwendet keine Passworter zur Authentifikation. Wegen dieser sicherheits-technisch problematischen Eigenschaft des rsync-Damons wurde er in obigen Bei-spielen auch immer nur wenn notwendig mit dem systemimager-server-Skript gestartet. Etwas entscharfen kann man das Sicherheitsproblem, wenn der Da-tei /etc/systemimager/rsyncd.conf die Zeile

hosts allow = 127.0.0.0/255.0.0.0 192.168.0.0/255.255.255.0

hinzugefugt wird. Dem Schlusselwort hosts allow folgt eine Liste aus Kombina-tionen aus IP- bzw. Netzadressen und Netzmasken von Rechnern, denen exklusiverZugriff auf den rsync-Damon gestattet wird. Eine detaillierte Beschreibung dieserKonfigurationsdatei finden Sie in der Manpage rsyncd.conf(5). In obigem Beispielkann auf den von systemimager-server gestarteten rsync-Damon nur nochvom lokalen Rechner und von Computern aus dem Subnetz 192.168.0.xxx zugegrif-fen werden.

Page 112: [X.systems.press] Cluster Computing ||

104 5 PCs vernetzen

Der durch prepareclient auf dem golden client gestartete rsync-Damon istimmer so konfiguriert, dass nur der golden client selbst und der image server auf ihnzugreifen konnen. Außerdem beendet er sich nach 15 min von selbst. Hier ist es umdie Sicherheit also etwas besser bestellt. Fur die Verwendung von SystemImager insehr unsicheren Umgebungen gibt es auch eine Variante, die alle Daten statt mit demrsync-Damon durch die Secure Shell ubertragt, siehe auch Abschnitt 5.6.3.

5.5.5 Einschrankungen und Alternativen

So praktisch SystemImager auch sein mag, mit einigen Einschrankungen gegenubereinem echten Paketmanagement a la rpm, yast oder apt-get muss man dochleben. Zu den Aufgaben eines Paketmanagement gehort nicht nur, dafur zu sorgen,dass zu installierende Dateien am richtigen Ort landen bzw. beim Deinstallieren wie-der geloscht werden, sondern es startet und beendet auch Dienste. So wird bei derInstallation eines Webservers, dieser nach der Einspielung aller Dateien auch gleichgestartet. Vor einer Deinstallation wird er automatisch beendet. SystemImager kannleider nur Dateien kopieren und loschen, es startet oder beendet keine Dienste. Wennmit updateclient ein Knoten mit dem Abbild auf dem image server abgeglichenwird, kann es daher passieren, dass die Programm- und Konfigurationsdateien einesDienstes geloscht werden, dieser Dienst aber (wenn auch fehlerhaft) weiterlauft. Dar-um sollten Dienste, die durch updateclient deinstalliert werden, vor dem Auf-ruf dieses Programms manuell beendet werden. Alternativ hilft auch ein Reboot nachupdateclient.

Fur eine automatische Installation gibt es einige distributionsspezifische Alterna-tiven zu SystemImager, z. B. fur SuSE AutoYaST [4], fur RedHat Kickstart oder furDebian FAI [44]. Diese Programme sind zwar auf die jeweilige Distribution besserals SystemImager abgestimmt, jedoch konnen sie sich trotzdem als weniger flexibelherausstellen. Das liegt daran, dass diese Programme alle paketorientiert arbeiten.Statt den Festplatteninhalt eines golden client zu kopieren, wird bei diesen Systemeneine Liste von Paketen definiert, die das Installations-System automatisch einspielt.Mochten Sie z. B., dass eine bestimmte Konfigurationsdatei einen anderen Inhalt hatals den im Paket Ihrer Distribution, dann mussen Sie das Paket anpassen, was wie-derum mit einem erhohten administrativen Aufwand verbunden ist. Manuelle Ande-rungen gehen bei Programmen wie AutoYaST oder Kickstart durch Updates wiederverloren.

5.6 Wichtige Netzdienste

Im Abschnitt 5.4 wurde die Basiskonfiguration des Netzwerks beschieben. Mit die-ser allein kann man aber noch keinen Cluster betreiben. Erst mit Hilfe weitererNetzdienste wird aus den vernetzten Computern ein Cluster. Diese Dienste sind einNetzwerkdateisystem (NFS), einen Informationsdienst (NIS), einen Dienst zur Zu-gangskontrolle (rsh oder ssh), einen Zeitdienst (NTP), einen Dienst (NAT), der denKnoten die Kommunikation mit Computern außerhalb des Clusters ermoglicht, und

Page 113: [X.systems.press] Cluster Computing ||

5.6 Wichtige Netzdienste 105

ein DHCP-Server zur zentralen Verwaltung von IP-Adressen. Im Folgenden werdendiese Dienste vorgestellt und deren Einrichtung umrissen.

5.6.1 Network File System

In einem Cluster mussen zahlreiche Dateien mit identischem Inhalt auf jedem Com-puter vorhanden sein. Diese Dateien in einem konsistenten Zustand zu halten, wirdbei großeren Clustern schnell zu einer schwierigen Aufgabe. Ein Netzwerkdateisys-tem hilft, diese Aufgabe zu bewaltigen. Das Network File System (NFS) ist das unterLinux meist verbreitete Netzwerkdateisystem. Es ist besonders fur kleine Cluster mitbis zu ca. hundert Knoten geeignet. Wenn die Knoten sehr viele Dateizugriffe uberdas Netz abwickeln, kann NFS auch schon fruher an seine Grenzen stoßen. In solcheinem Fall ist das Parallel Virtual File System (PVFS) eine leistungsfahige Alternati-ve, siehe [58] und Abschnitt 4.6.2.

NFS arbeitet nach dem Client-Server-Prinzip. Dateien, auf die im gesamten Clus-ter zugegriffen werden konnen soll, werden auf einem zentralen NFS-Server vorge-halten, der diese an die Clients exportiert. Aus Nutzersicht unterscheiden sich viaNFS eingebundene Dateisysteme (fast) nicht von lokalen Dateisystemen. Zu denVerzeichnissen, die von den Knoten eines Clusters typischerweise via NFS einge-bunden werden, gehoren die Heimatverzeichnisse (/home) und die Verzeichnisse/usr/local und /opt. Hier liegt clusterspezifische Software, die nicht von dereingesetzten Linux-Distribution stammt, z. B. kommerzielle Compiler.

Fur Linux existieren zwei verschiedene NFS-Server-Implementationen, eine, dienur aus Userspace-Programmen besteht, und eine Kernel-Implementation. Lauft derNFS-Server als Userspace-Server, so ist er lediglich ein Programm unter vielen, dasauf dem Computer lauft. Seine Rechte und Fahigkeiten sind gegenuber dem Kernel-Server leicht eingeschrankt. Wir raten darum, den Kernel-NFS-Server zu verwenden.Er erzeugt auf dem Server eine geringere CPU-Last und unterstutzt File-Locking,was beim Userspace-Server nicht implementiert ist. Durch File-Locking kann einProzess eine Datei vor dem Zugriff durch andere Prozesse schutzen. Der Kernel-NFS-Server unterstutzt NFS in den Versionen 2 und 3, die Version 4 befindet sichnoch in der Entwicklung. Zu den Hauptvorteilen der Version 3 gegenuber fruherenVersionen zahlt, dass Dateien großer als 2 GByte sein durfen. Einen ausfuhrlichenVergleich der verschiedenen NFS-Versionen finden Sie in [114].

Damit der Server des Beispiel-Clusters Verzeichnisse an die Knoten exportierenkann, muss zunachst der Kernel angepasst werden. Bei der Kernelkonfiguration istim Untermenu Network File Systems des Menus File Systems der Punkt NFS Ser-ver support auszuwahlen. Fur die Knoten ist die Wahl der Option NFS file systemsupport notwendig. Neben der Modifikation des Kernels sind noch einige Userspace-Programme notwendig. Unter Debian befinden sich diese in den Paketen nfs-common(fur Client und Server) und nfs-kernel-server (nur fur Server). Bei anderen Distribu-tionen haben die notwendigen Pakete ahnliche Namen.

Auf einem NFS-Server laufen typischerweise die Programme nfsd, portmap,rpc.mountd sowie rpc.stadt.

nfsd. Dies ist der eigentliche NFS-Damon.

Page 114: [X.systems.press] Cluster Computing ||

106 5 PCs vernetzen

Listing 5.8. Die Datei /etc/exports steuert, welche Verzeichnisse an wen via NFS expor-tiert werden.

/home 192.168.0.0/255.255.255.0(rw,root_squash,sync)/usr/local 192.168.0.0/255.255.255.0(ro,root_squash,sync)

portmap. Das Programm portmap sorgt fur die dynamische Vergabe von UDP-Ports an die NFS-Clients.

rpc.mountd. Mount-Anfragen der Clients werden durch rpc.mountd verarbei-tet.

rpc.stadt. Dieser Damon kummert sich um das File-Locking.

Haben Sie alle notwendigen Programme und einen Kernel mit NFS-(Server-)Unter-stutzung installiert, mussen Sie auf dem NFS-Server noch die Konfigurationsdateien/etc/exports sowie /etc/hosts.allow und /etc/hosts.deny anpas-sen. Die Konfigurationsdatei /etc/exports regelt was an wen unter welchen Be-dingungen exportiert wird. Jede Zeile dieser Datei beginnt mit dem Namen eineszu exportierenden Verzeichnisses gefolgt von den Namen der Rechner, an die expor-tiert werden soll, und einigen Optionen. Statt Rechnernamen konnen auch Kombi-nationen aus IP-Netzadressen und Netzmasken angegeben werden. Der Server un-seres Beispiel-Clusters exportiert die Verzeichnisse /home und /usr/local analle Rechner im Netz mit den Adressen 192.168.0.xxx. Auf Heimatverzeichnisse derNutzer soll schreibend und lesend zugegriffen werden, darum wird in der Konfigura-tionsdatei 5.8 die Option rw angegeben, auf /usr/local konnen die Clients nurlesend zugreifen (Option ro).

Mit der Option sync meldet der NFS-Server einen Schreibvorgang an einen Cli-ent erst dann als erledigt, wenn tatsachlich alle Daten auf die Festplatte geschriebenwurden. Seit der Version 1.0.1 des Kernel-NFS-Servers ist dies das Standardverhal-ten. Vorher verwendete der NFS-Server standardmaßig den mit der Option asyncverknupften Schreibmodus. Hier darf der NFS-Server seine Clients ”anlugen“ undeinen Schreibvorgang als abgeschlossen melden, sobald er alle Daten vom Clienterhalten hat. Dadurch wird zwar eine bessere Performance auf Kosten der Datensi-cherheit erzielt aber der NFS-Standard verletzt. Aufgrund des Wechsels im Standard-verhalten, gibt der NFS-Server beim Exportieren der Dateisysteme eine Warnungaus, wenn weder die Option sync noch async explizit angegeben wurde.

Neben diesen Optionen kennt der NFS-Server noch weitere. Die meisten Optio-nen legen fest, wie die Nutzer- und Gruppen-IDs auf Client- und Server-Rechneraufeinander abgebildet werden. Diese Optionen sind wichtig, weil bei NFS samtli-che Rechte uber Nutzer- und Gruppen-IDs (nicht uber Nutzer- und Gruppen-Namen)vergeben werden. Das normale Verhalten, das ein Benutzer erwarten wurde, ist, dasser auf die Dateien auf dem Server genauso zugreifen kann wie in lokalen Dateisys-temen. Dafur werden sowohl auf dem Server- als auch auf dem Client-Rechner diegleichen Nutzer- und Gruppen-IDs benotigt. Konsistente Nutzer- und Gruppen-IDsauf allen Rechnern konnen mit NIS verwaltet werden, siehe Abschnitt 5.6.2.

Page 115: [X.systems.press] Cluster Computing ||

5.6 Wichtige Netzdienste 107

Listing 5.9. Dieser Eintrag in /etc/hosts.deny sperrt den Zugriff auf alle Dienste, diedie TCP-Wrapper-Bibliothek bzw. das Programm tcpd benutzen.

ALL: ALL

Listing 5.10. Fur NFS relevanter Ausschnitt aus der Datei /etc/hosts.allow.

portmap: 192.168.0.0/255.255.255.0mountd: 192.168.0.0/255.255.255.0

Listing 5.11. Der Ausschnitt aus der Datei /etc/fstab zeigt, wie auf den Knoten ein Datei-system via NFS eingebunden wird.

server:/home /home nfs defaults,rsize=8192,wsize=8192 0 0server:/usr/local /usr/local nfs defaults,rsize=8192 0 0

Aus Sicherheitsgrunden ist es jedoch nicht wunschenswert, dass der Nutzer rootauf einem Client auf uber NFS importierte Dateien mit root-Rechten zugreifen kann.Mit der Angabe der Option root squash wird die Nutzer-ID von root in die desNutzers nobody umgewandelt, so dass ein Nutzer, der root-Rechte auf einem NFS-Client hat, noch lange nicht vom NFS-Server exportierte Dateien mit root-Rechtenandern kann. Festplattenlose Cluster-Knoten, die ihr gesamtes Dateisystem uber NFSeinbinden, benotigen unbedingt Dateizugriff mit root-Rechten. Hier ist die Optionno root squash anzugeben. Mehr uber Optionen zur Nutzer-ID-Umwandlungsteht in der Manpage exports(5).

NFS ist ein relativ unsicherer Dienst, der nur in Netzen eingesetzt werden sollte,in denen sich alle Rechner gegenseitig vertrauen. Unsichere Dienste wie portmapund rpc.mountd lassen sich zumindest teilweise durch die TCP-Wrapper-Bi-bliothek bzw. das Programm tcpd absichern. Programme, die die TCP-Wrapper-Bibliothek bzw. tcpd benutzen, steuern Zugriffe auf ihre Dienste durch die Da-teien /etc/hosts.allow und /etc/hosts.deny. Jede Zeile in diesen Da-teien legt fest, welche Rechner einen Netzdienst nutzen konnen bzw. nicht nut-zen durfen. Es ist gute Praxis, zunachst in der Datei /etc/hosts.deny alleDienste zu sperren (Listing 5.9) und in /etc/hosts.allow selektiv Dienstean fremde Rechner freizugeben. Listing 5.10 zeigt die entsprechenden Eintrage furdie Dienste portmap und rpc.mountd mit der Freigabe an alle Rechner mitder Adresse 192.168.0.xxx. Das Format der Dateien /etc/hosts.allow und/etc/hosts.deny wird in der Manpage hosts access(5) genau beschrieben.

Clientseitig ist nur die Datei /etc/fstab anzupassen. Auf den Knoten unseresBeispiel-Clusters sind die in Listing 5.11 gezeigten Zeilen enthalten. Damit werdendie Verzeichnisse /home und /usr/local vom Rechner server eingebunden. DieOptionen rsize=8192 und wsize=8192 geben die Blockgroßen zum Lesen undSchreiben an. Diese Parameter beeinflussen die Geschwindigkeit von Schreib- undLeseoperationen. Die Standardblockgroße von 1024 ist meist zu klein, weshalb Sieeine großere wie 4096 oder 8192 wahlen sollten.

Page 116: [X.systems.press] Cluster Computing ||

108 5 PCs vernetzen

Nach abgeschlossener Konfiguration muss auf dem Server nur noch der NFS-Server durch ein Init-Skript (siehe auch Abschnitt 5.3.4) gestartet werden und dieKnoten konnen die Heimatverzeichnisse mit

root@node1:˜# mount /homeroot@node1:˜# mount /usr/local

einbinden. Falls dies nicht gelingt, kann ein Blick in /var/log/syslog (sowohldem Server als auch auf einem Client) Hinweise fur die Problemursache geben. Nutz-lich sind auch die beiden Programme exportfs und showmount. Mit ersteremkonnen auf einem NFS-Server auch Verzeichnisse exportiert werden, die nicht in/etc/exports gelistet sind. Das Programm showmount gibt diverse Statusan-gaben eines entfernten NFS-Servers aus, z. B. welcher Client welches Verzeichnisvon diesem Server importiert. Noch ausfuhrlichere Auskunft daruber, mit welchenOptionen ein NFS-Server an wen was exportiert, finden Sie in /proc/fs/nfs/exports. Weitere Informationen zu NFS geben [114] und [159].

5.6.2 Network Information Service

Mit dem Network Information Service (NIS) lassen sich Verwaltungsaufgaben ineinem Netzwerk (wie z. B. das Vergeben von Nutzerkonten) zentralisieren. Diesezentrale Verwaltung vereinfacht die Administration eines Clusters, da Verwaltungs-daten einzig auf dem NIS-Server geandert werden mussen. Geanderte Daten stehenallen Clients sofort zur Verfugung. Ein NIS-Server stellt typischerweise Informatio-nen, die in Dateien im Verzeichnis /etc des NIS-Servers vorhanden sind, anderenClients bereit. Die wichtigsten dieser Dateien sind

• die Passwortdatei der Nutzer, /etc/passwd,• die Schattenpasswortdatei der Nutzer, /etc/shadow,• die Gruppenpasswortdatei, /etc/group,• die Datei zur Namensauflosung /etc/hosts und• die Datei /etc/services, die Portnummern und Netzdienste einander zuord-

net.

Die gangigen Linux-Distributionen enthalten Pakete mit allen zum Betrieb von NIS-Servern bzw. NIS-Clients notwendigen Programmen. Die Installationsprogrammerichten Client- und Server-Programme meist auch schon so ein, dass man mit ihnensinnvoll arbeiten kann. Trotzdem konnen noch einige zusatzliche Anpassungen derKonfiguration notwendig sein. Folgende Hinweise zur Einrichtung von NIS setzenein Linux auf Basis der GNU C Bibliothek der Version 2.x voraus, die in allen mo-dernen Linux-Distributionen verwendet wird.

NIS-Server und -Clients bilden eine NIS-Domane. Wahrend der Installation wer-den Sie nach einem Namen fur diese NIS-Domane gefragt. Eine NIS-Domane hatnichts mit einer DNS-Domane zu tun. Die Namen beider konnen abweichen, wer-den in der Praxis aber oft als identisch gewahlt. Die NIS-Domane des Beispiel-Clusters heißt cluster. Sollte der Name der NIS-Domane nicht wahrend der Instal-lation festgelegt worden sein, so tragen Sie ihn auf Clients und Server in /etc/

Page 117: [X.systems.press] Cluster Computing ||

5.6 Wichtige Netzdienste 109

Terminal Session 5.4. Einrichtung der NIS-Maps mit ypinit.root@server:˜# /usr/lib/yp/ypinit -m

At this point, we have to construct a list of the hosts which will run NISservers. server is in the list of NIS server hosts. Please continue toadd the names for the other hosts, one per line. When you are done withthe list, type a <control D>.

next host to add: servernext host to add:

The current list of NIS servers looks like this:

server

Is this correct? [y/n: y] yWe need some minutes to build the databases...Building /var/yp/cluster/ypservers...Running /var/yp/Makefile...make[1]: Entering directory ‘/var/yp/cluster’Updating passwd.byname...Updating passwd.byuid...Updating group.byname...Updating group.bygid...Updating hosts.byname...Updating hosts.byaddr...Updating rpc.byname...Updating rpc.bynumber...Updating services.byname...Updating services.byservicename...Updating netid.byname...Updating protocols.bynumber...Updating protocols.byname...Updating netgroup...Updating netgroup.byhost...Updating netgroup.byuser...Updating networks.byaddr...Updating networks.byname...Updating shadow.byname...make[1]: Leaving directory ‘/var/yp/cluster’

defaultdomain (bei Debian und SuSE) bzw. /etc/sysconfig/network(bei RedHat) manuell ein.

Der NIS-Server greift bei Anfragen der Clients nicht direkt auf die Dateienim Verzeichnis /etc zu. Stattdessen wird eine eigenstandige Datenbank, die NIS-Maps, gepflegt. Mit dem Programm ypinit wird diese Datenbank erstmalig an-gelegt, siehe Terminal Session 5.4. Um nach Anderungen der von NIS verwalte-ten Dateien in /etc die NIS-Maps diesen Anderungen anzupassen, muss im Ver-zeichnis /var/yp das Programm make ausgefuhrt werden. Dies gilt nicht fur mitNIS verwaltete Passworter der Nutzerkonten. Wenn Passworter mit dem Programmyppasswd geandert werden, sind diese Anderungen sofort wirksam. Passworterlassen sich sowohl von den Clients als auch vom Server aus andern. Im Makefile/var/yp/Makefile konnen Sie falls notwendig noch einige Einstellungen, diedie Erzeugung der NIS-Maps beeinflussen, anpassen, z. B. konnen bestimmte Berei-che von Nutzer-IDs von der Verwaltung mit NIS ausgenommen werden.

Page 118: [X.systems.press] Cluster Computing ||

110 5 PCs vernetzen

Listing 5.12. Die Datei /etc/ypserv.securenets lasst nur ausgewahlte Rechner aufden NIS-Server zugreifen.

# Zugriff localhost erlauben255.0.0.0 127.0.0.0# Zugriff den IP-Adressen 192.168.0.xxx erlauben255.255.255.0 192.168.0.0

Listing 5.13. Die Datei /etc/yp.config legt den vom NIS-Client verwendeten NIS-Server fest.

ypserver 192.168.0.254

Listing 5.14. Die Datei /etc/nsswitch.conf regelt, welche Inforamtionen vom NIS-Server bezogen werden.

passwd: files nisgroup: files nisshadow: files nis

5 hosts: files nis dnsnetworks: files nis

protocols: db filesservices: db files

10 ethers: db filesrpc: db files

Der NIS-Server selbst wird uber die Dateien /etc/ypserv.conf und /etc/ypserv.securenets konfiguriert. Die Datei /etc/ypserv.conf ist meistschon sinnvoll eingerichtet, falls nicht, konnen Sie das Format dieser Datei in derManpage ypserv.conf(5) nachlesen. Die Datei /etc/ypserv.securenets ent-halt Paare aus Netzmasken und IP-Adressen der Computer, denen der Zugriff aufden NIS-Server gestattet werden soll. Listing 5.12 zeigt, wie diese Datei fur unserenBeispiel-Cluster aussieht.

Die Konfiguration der NIS-Clients ist recht einfach. In der Datei /etc/yp.conf wird der Name oder die IP-Adresse des NIS-Servers eingetragen, siehe Lis-ting 5.13. Außerdem muss noch dem System auf den Client-Rechnern mitgeteiltwerden, dass die Informationen uber Nutzer-Passworter usw. vom NIS-Server be-zogen werden sollen. Die Quellen fur solche Information werden in der Datei/etc/nsswitch.conf festgehalten. Eine fur einen Cluster typische Konfigu-ration zeigt Listing 5.14. Diese Einstellungen bewirken unter anderem, dass nachPasswortern zunachst in den lokalen Dateien gesucht wird. Kann das Passwort einesNutzers dort nicht gefunden werden, erfolgt eine Anfrage an den NIS-Server. DieseEinstellung erlaubt es u. a., dass sich der Nutzer root auch noch anmelden kann, wennder NIS-Server nicht erreichbar ist, denn sein Passwort ist in der lokalen Passwort-datei gespeichert. Mit der gezeigten Konfiguration werden neben den Passwortdatenauch die Daten von zur Namensauflosung uber NIS bezogen. Das Format der Kon-

Page 119: [X.systems.press] Cluster Computing ||

5.6 Wichtige Netzdienste 111

figurationsdatei /etc/nsswitch.conf wird in der Manpage nsswitch.conf(5)oder nsswitch(5) beschrieben.

NIS-Client- und NIS-Server-Programme werden beim Systemstart durch Init-Skripten gestartet. Unter Debian heißt dieses Skript /etc/init.d/nis, in derDatei /etc/defaults/nis wird u. a. festgelegt, ob ein NIS-Client oder -Serverzu starten ist. Bei anderen Distributionen ist das Starten von NIS-Client- und NIS-Server-Programmen etwas anderes organisiert und die Init-Skripten haben andere Na-men, z. B. ypbind oder ypclient. Nach dem Start von NIS-Clients und -Serverkann z. B. mit ypwhich ein erster Funktionstest durchgefuhrt werden. Das Pro-gramm gibt den Namen des NIS-Servers aus. Mit dem Programm ypcat konnenSie erfragen, welche Informationen aus /etc/passwd und anderen Quellen vomServer an die Clients weitergegeben werden.

root@server:˜# ypwhichserver.our-domain.orgroot@server:˜# ypcat passwdnobody:x:65534:65534:nobody:/home:/bin/shmertens:x:1001:1001:Stephan Mertens,,,:/home/mertens/:/bin/bashbauke:x:1000:1000:Heiko Bauke,,,:/home/bauke:/bin/bash

Ist alles richtig konfiguriert, geben obige Befehle auf dem Server und den computenodes die gleichen Daten aus.

Sollten bei der Konfiguration von NIS-Client oder -Server Probleme auftretenoder aus sonstigen Grunden vertiefende Informationen notwendig sein, so ist [117]eine gute erste Anlaufstelle. Viele weitere Informationen zur Konfiguration von NISsind in [159] zu finden. Nach erfolgreicher NIS-Installation konnen Sie auf dem NIS-Server neue Nutzerkonten anlegen und mit einem Aufruf von make in /var/ypclusterweit bekannt machen. Ob die Nutzerdaten von NIS weitergegeben werden,lasst sich danach mit ypcat testen.

Den Nutzern ist es erlaubt, einige der in /etc/passwd hinterlegten Daten mitden Programmen passwd, chsh und chfn fur das eigene Konto zu modifizieren.Diese Programme greifen jedoch nur auf die lokale Datei /etc/passwd zu. VonNIS verwaltete Nutzerkonten werden stattdessen mit den Programmen yppasswd,ypchsh und ypchfn geandert. Um die Nutzer nicht zu sehr zu verwirren, werdenin vielen Clustern die Programme passwd, chsh und chfn durch Links auf ent-sprechenden NIS-Programme ersetzt. So konnen die Nutzer z. B. wie gewohnt mitpasswd ihr Passwort andern.

Neben NIS sind in letzter Zeit weitere Verzeichnisdienste popular geworden, diessind insbesondere NIS+ und das Lightweight Directory Access Protocol (LDAP). Ih-re Vorteile liegen u. a. in der besseren Skalierbarkeit und erhohten Sicherheit durchkryptographische Algorithmen. NIS+ wird bisher von Linux nur ansatzweise un-terstutzt, LDAP hingegen sehr gut. Sollten Sie fur Ihren Cluster fur eine Alternativezu NIS suchen, so ist LDAP wahrscheinlich die bessere Wahl, siehe [3, 99].

Page 120: [X.systems.press] Cluster Computing ||

112 5 PCs vernetzen

5.6.3 Berkeley-r-Kommandos und die Secure Shell

Dank NIS konnten sich nun die Nutzer auf jedem Knoten des Clusters einloggenund wurden auch Dank NFS uberall das gleiche Heimatverzeichnis vorfinden. Wiepraktisch. Jedoch ist zum Einloggen physischer Zugang zu einem Cluster-Knotennotwendig. Typischerweise steht ein Cluster in einem Serverraum, die Knoten habenwerder Tastatur noch Monitor und physischer Zugang zum Cluster wird nur den lo-kalen UNIX-Gurus gewahrt. Normalsterbliche Nutzer greifen uber das Internet vonihrem Burorechner auf den Cluster zu. Die Werkzeuge, die diesen Zugriff ermogli-chen, sind die Berkeley-r-Kommandos und die Secure Shell (SSH).

Die Berkeley-r-Kommandos bestehen im Wesentlichen aus den Programmenrsh, rlogin und rcp. Diese Programme sind fur Computer in kleinen abgeschot-teten Netzen mit gleichen Nutzern gedacht, also ideal fur einen Cluster. Mit ihnenkann sich ein Nutzer, hat er sich einmal auf einem der Computer im Netz eingeloggt,frei von einem Computer zum anderen bewegen ohne erneut Nutzername und Pass-wort eingeben zu mussen. Die r-Kommandos nutzen statt Nutzername und Passworteine hostbasierte Authentifizierung.

rsh. Mit diesem Werkzeug konnen Programme auf anderen Rechnern ausgefuhrtwerden. Es wird von vielen MPI-Implementationen genutzt, um MPI-Programmezu starten. Wird kein zu startendes Programm angegeben, verhalt sich rsh wiedas Programm rlogin.

rlogin. Dieses Programm dient zum Starten von Sitzungen auf anderen Rechnern.rcp. Das Programm rcp kopiert Dateien zwischen verschiedenen Rechnern hin

und her. Es ist ansonsten dem Programm cp sehr ahnlich.

Neben diesen drei Client-Programmen gehoren zu den r-Kommandos entsprechen-de Server-Programme. Installieren Sie zunachst all diese Programme mit den In-stallationwerkzeugen Ihrer Distribution. Eventuell mussen Sie dabei fur Client- undServer-Programme verschiedene Pakete anwahlen.

Die hostbasierte Authentifizierung der r-Kommandos wird uber die Datei /etc/hosts.equiv gesteuert. Sie enthalt in jeder Zeile den Namen eines entferntenComputers, dessen Nutzern Zugriff auf den lokalen Computer gestattet wird. AusSicherheitsgrunden sollten nur voll qualifizierte Namen, wie server.our-domain.org,oder IP-Adressen angegeben werden. Listing 5.15 zeigt die Konfigurationsdatei furunseren Beispiel-Cluster. Damit sich alle Computer des Clusters gegenseitigen Zu-gang gewahren, muss diese Datei so auf jedem Computer vorhanden sein. Das giltauch fur alle anderen fur die r-Kommandos relevanten Konfigurationsdateien.

Listing 5.15. Die Datei /etc/hosts.equiv listet alle vertrauenswurdingen Computer.

server.our-domain.orgnode1.our-domain.orgnode2.our-domain.orgnode3.our-domain.org

5 node4.our-domain.org

Page 121: [X.systems.press] Cluster Computing ||

5.6 Wichtige Netzdienste 113

Listing 5.16. Fur die r-Kommandos relevanter Ausschnitt aus der Konfigurationsdatei /etc/inetd.conf des Internet-Damons inetd.

shell stream tcp nowait root /usr/sbin/tcpd /usr/sbin/in.rshdlogin stream tcp nowait root /usr/sbin/tcpd /usr/sbin/in.rlogindexec stream tcp nowait root /usr/sbin/tcpd /usr/sbin/in.rexecd

Listing 5.17. Fur die r-Kommandos relevanter Ausschnitt aus der Datei /etc/hosts.allow.

in.rshd: 192.168.0.0/255.255.255.0in.rlogind: 192.168.0.0/255.255.255.0in.rexec: 192.168.0.0/255.255.255.0

Kontaktiert eines der r-Kommandos einen anderen Rechner, so wird auf die-sem durch den Internet-Damon (inetd oder xinetd) ein Server gestartet. Ver-wenden Sie in Ihrem Cluster das Programm inetd, so sind dazu die in Lis-ting 5.16 gezeigten Zeilen hinzuzufugen. Bei dieser Konfiguration wird der Zu-gang mittels r-Kommandos durch das Programm tcpd und die Konfigurationsda-tei /etc/hosts.allow auf die Computer des Clusters eingeschrankt, siehe Lis-ting 5.17. Diese Einschrankung ist besonders fur den Server des Beispiel-Clusterswichtig, denn er ist direkt mit dem Internet verbunden. Haben Sie alle Konfigurati-onsdateien angepasst und den Internet-Damon uber sein Init-Skript erneut gestartet,konnen normale Nutzer die r-Kommandos verwenden und sich mit rlogin vonserver auf node1 ohne Passwortabfrage einloggen.

bauke@server:˜$ rlogin node1Last login: Mon Jun 28 10:28:37 2004 from tux on pts/1Linux node1 2.4.19 #1 Mon Jun 21 15:14:54 CEST 2004 i686 unknown

bauke@node1:˜$

Allerdings ist dem Nutzer root standardmaßig die Benutzung der hostbasier-ten Authentifizierung nicht erlaubt. Da sich aber die tagliche Arbeit des Cluster-Administrators durch die r-Kommandos deutlich vereinfacht, soll auch ihm derenNutzung gestattet werden. Unter Linux werden praktisch alle Authentifizierungsme-thoden durch die Pluggable Authentication Modules (PAM) geregelt. Die Konfigu-ration von PAM erfolgt mit den Dateien im Verzeichnis /etc/pam.d. Damit rootin den Genuss der r-Kommandos kommt, sind die Dateien /etc/pam.d/rloginund /etc/pam.d/rsh wie in Listing 5.18 und 5.19 gezeigt zu andern. BeachtenSie dabei, dass auch die Reihenfolge der Zeilen in den beiden Dateien das Verhaltenvon PAM beeinflusst. Besonders wichtig ist jeweils die erste Zeile mit dem Zusatzhosts equiv rootok.

Der hier vorgestellte Beispiel-Cluster bildet ein eigenes von außen nicht erreich-bares Netzwerk. Sind die Knoten eines Clusters direkt mit dem Internet verbunden,so stellt die Verwendung der r-Kommandos ein Sicherheitsrisiko da. Das Secure-Shell-Protokoll (SSH-Protokoll) ist eine sichere Alternative zu den r-Kommandos.

Page 122: [X.systems.press] Cluster Computing ||

114 5 PCs vernetzen

Listing 5.18. Beispielkonfiguration der Datei /etc/pam.d/rlogin, die auch dem Nutzerroot die Verwendung von rlogin ermoglicht.

auth sufficient pam_rhosts_auth.so hosts_equiv_rootokauth requisite pam_securetty.soauth required pam_unix.so nullokauth required pam_nologin.so

5 account required pam_unix.sopassword required pam_unix.so nullok use_authtok obscure \

min=4 max=8session required pam_unix.so

Listing 5.19. Beispielkonfiguration der Datei /etc/pam.d/rsh, die auch dem Nutzer rootdie Verwendung von rsh ermoglicht.

auth required pam_rhosts_auth.so hosts_equiv_rootokauth required pam_nologin.soauth required pam_env.soaccount required pam_unix_acct.so

5 session required pam_unix_session.so

Es gibt fur Linux verschiedene Implementationen des SSH-Protokolls, meist wirdOpenSSH [125] eingesetzt. Mit OpenSSH wird die Funktionalitat der Programmersh, rlogin und rcp durch ssh, slogin und scp ersetzt.

Nachdem auf allen Computern des Clusters OpenSSH installiert und der SSH-Server durch ein Init-Skript gestartet wurde, kann man sich mit dem slogin Pro-gramm auf einem Knoten einloggen.

bauke@server:˜$ slogin node1The authenticity of host ’node1 (192.168.0.1)’ can’t be established.RSA key fingerprint is ee:05:40:23:31:3c:fa:c7:f2:15:a8:52:55:81:51:80.Are you sure you want to continue connecting (yes/no)? yesWarning: Permanently added ’node1,192.168.0.1’ (RSA) to the list of knownhosts.bauke@node1’s password:Linux node1 2.4.19 #1 Mon Jun 21 15:21:39 CEST 2004 i686 unknown

bauke@node1:˜$

Fremde Rechner mussen sich gegenuber einem SSH-Programm mittels eines offent-lichen Schlussels authentifizieren. Beim erstmaligen Einloggen auf einem Rechnerist dieser meist noch nicht bekannt. Beantworten Sie die Frage ”Are you sure youwant to continue connecting (yes/no)?“ mit ”yes“, so wird der offentliche Schlusseldes fremden Rechners in ∼/.ssh/known hosts aufgenommen und bei erneutemLogin auf denselben Rechner bleibt die Frage aus.

Sollte Ihr Versuch, sich einzuloggen, abgewiesen werden, so liegt dies wahr-scheinlich am TCP-Wrapper, der den SSH-Dienst blockiert, siehe Listing 5.9. InListing 5.20 finden Sie den Eintrag fur die Datei /etc/hosts.allow, der die Zu-griffsbschrankung aufhebt. Bei Bedarf konnen Sie eine noch liberalere Regel (z. B.sshd: ALL) verwenden.

Page 123: [X.systems.press] Cluster Computing ||

5.6 Wichtige Netzdienste 115

Listing 5.20. Dieser fur SSH relevante Ausschnitt aus der Datei /etc/hosts.allow er-laubt allen Computern unserer Domain den Zugriff via SSH.

sshd: localhost .our-domain.org

Listing 5.21. Datei hosts mit IP-Adressen und Hostnamen zur Generierung einer Listeoffentlicher Schlussel mit dem Programm ssh-keyscan.

192.168.0.254 server.our-domain.org,server,192.168.0.254192.168.0.1 node1.our-domain.org,node1,192.168.0.1192.168.0.2 node1.our-domain.org,node1,192.168.0.2192.168.0.3 node1.our-domain.org,node1,192.168.0.3

5 192.168.0.4 node1.our-domain.org,node1,192.168.0.4

Um allen Nutzern die Frage nach der Hostauthentizitat zu ersparen, kann derSystemadministrator in der Datei /etc/ssh/ssh known hosts die offentlichenSchlussel aller Knoten des Clusters ablegen. Eine Liste solcher Schlussel lasst sichauf sehr einfache Weise mit dem Programm ssh-keyscan und einer Textdatei, diealle Namen der Knoten enthalt (siehe Listing 5.21), erstellen.

root@server:˜# ssh-keyscan -t rsa,dsa -f hosts > /etc/ssh/ssh_known_hosts# 192.168.0.254 SSH-2.0-OpenSSH_3.4p1 Debian 1:3.4p1-1.woody.3# 192.168.0.254 SSH-2.0-OpenSSH_3.4p1 Debian 1:3.4p1-1.woody.3# 192.168.0.1 SSH-2.0-OpenSSH_3.4p1 Debian 1:3.4p1-1.woody.3# 192.168.0.1 SSH-2.0-OpenSSH_3.4p1 Debian 1:3.4p1-1.woody.3# 192.168.0.2 SSH-2.0-OpenSSH_3.4p1 Debian 1:3.4p1-1.woody.3# 192.168.0.2 SSH-2.0-OpenSSH_3.4p1 Debian 1:3.4p1-1.woody.3# 192.168.0.3 SSH-2.0-OpenSSH_3.4p1 Debian 1:3.4p1-1.woody.3# 192.168.0.3 SSH-2.0-OpenSSH_3.4p1 Debian 1:3.4p1-1.woody.3# 192.168.0.4 SSH-2.0-OpenSSH_3.4p1 Debian 1:3.4p1-1.woody.3# 192.168.0.4 SSH-2.0-OpenSSH_3.4p1 Debian 1:3.4p1-1.woody.3

Die Datei /etc/ssh/ssh known hosts muss (z. B. mit scp) noch auf jedenComputer im Cluster kopiert werden.

root@server:˜$ scp /etc/ssh/ssh_known_hosts node1:/etc/ssh/root@node1’s password:ssh_known_hosts 100% |*********************| 4400 00:00

Leider konnen sich die Nutzer noch immer nicht ohne Angabe eines Passworts aufandere Rechner einloggen. Durch die Option

HostbasedAuthentication yes

in den Konfigurationsdateien /etc/ssh/sshd config und /etc/ssh/sshconfig wird eine hostbasierte Authentifizierung mit OpenSSH aktiviert. Seit derVersion 3.6 von OpenSSH wird außerdem in /etc/ssh/ssh config die Option

EnableSSHKeysign yes

benotigt. Die Liste mit den vollen Namen der vertrauenswurdigen Computer ist in/etc/ssh/shosts.equiv oder /etc/hosts.equiv auf allen Computern

Page 124: [X.systems.press] Cluster Computing ||

116 5 PCs vernetzen

des Clusters einzutragen, siehe Listing 5.15. Nach einem Neustart der SSH-Damonekonnen normale Nutzer die SSH-Programme innerhalb des Clusters ohne Passwort-abfrage nutzen. Nur root muss noch auf diesen Komfort verzichten.

Fur administrative Zwecke mochte man meist auch dem Nutzer root eine hostba-sierte Authentifizierung gestatten. Aus Sicherheitsgrunden ignoriert dieser Accountdie Datei /etc/ssh/shosts.equiv, darum sind hierzu weitere Konfigurati-onsschritte notwendig. Die Computer, die root fur vertrauenswurdig halt, werdenin /root/.shosts hinterlegt. Diese Datei ist meist mit /etc/ssh/shosts.equiv identisch, wird aber standardmaßig gleichfalls ignoriert. Erst die Option

IgnoreRhosts no

in /etc/ssh/sshd config verschafft root die gewunschte Bewegungsfreiheit.Ein nutzliches Werkzeug, das direkt auf den r-Kommandos bzw. SSH aufsetzt, ist

die Distributed Shell [28]. Mit der Distributed Shell konnen Shell-Kommandos nach-einander auf ganzen Gruppen von Computern ausgefuhrt werden. Dies ist besondersbei der Cluster-Administration recht hilfreich. Von den zahlreichen Optionen, die dasProgramm dsh kennt, sind -m und -r die beiden wichtigsten. Erstere legt fest, aufwelchen Knoten das Kommando gestartet werden soll, die zweite bestimmt, ob diesmit rsh oder ssh geschieht. Das Kommando

root@server:˜# dsh -m node1 -m node3 -r rsh -- datenode1: Mon Jul 5 16:06:24 CEST 2004node3: Mon Jul 5 16:06:25 CEST 2004

ist aquivalent zu

root@server:˜# for n in node1 node3; do rsh $n date; done

Mit der Option -awird ein Kommando auf allen in /etc/dsh/machines.listoder in ∼/.dsh/machines.list angegeben Knoten ausgefuhrt. Alle anderenOptionen werden in der Manpage dsh(1) beschrieben.

5.6.4 Network Time Protocol

Die Bedeutung des Network Time Protocol (NTP) wird leicht unterschatzt. Dabei istes durchaus wichtig, dass die Uhren der Computer in einem Cluster synchron laufen.Geht z. B. die Uhr eines NFS-Client nach, so konnen Dateien ein Anderungsdatumhaben, das aus Sicht des Clients in der Zukunft liegt. Dies fuhrt zu z. B. Problemenbei der Verwendung von Makefiles und bei der Erstellung Backups.

Damit die Computer des Beispiel-Clusters nicht aus den Gleichtakt geraten, wirdauf dem Server ein NTP-Server installiert, der die aktuelle Zeit an die Knoten wei-terleitet. Aber woher kennt der Server die aktuelle Zeit? Als genaue Zeitquellenkommen andere frei zugangliche Zeitserver im Internet, GPS-Empfanger oder einDCF77-Empfanger in Frage. Die Physikalisch-Technische Bundesanstalt (PTB) inBraunschweig betreibt eine hochgenaue Atomuhr. Auf Basis dieser Atomuhr ver-breitet sie uber den DCF77-Langwellensender ein Zeitsignal, das in Deutschlanddie gesetzliche Zeit darstellt. Dieser Sender kann in ganz Mitteleuropa empfangen

Page 125: [X.systems.press] Cluster Computing ||

5.6 Wichtige Netzdienste 117

werden. Außerdem kann das Zeitsignal der PTB auch durch Telefon und Satellitempfangen werden. Wollen Sie einen Zeitserver auf Basis eines DCF77-Empfangersaufbauen, so finden Sie in [23] die notwendigen Informationen. In unserem Beispielsoll das Zeitsignal von einem Zeitserver aus dem Internet (z. B. ptbtime1.ptb.de undptbtime2.ptb.de, also denen der PTB) bezogen werden.

Die Synchronisation des Servers geschieht zweistufig. Beim Bootvorgang wirddurch ein Init-Skript (meist /etc/init.d/ntpdate) das Programm ntpdateausgefuhrt. Falls die von Ihnen verwendete Distribution kein solches Init-Skriptenthalt, mussen Sie es selbst schreiben. Wird darin das Programm in der Form

ntpdate -u -b -s time1.our-domain.org time2.our-domain.org

aufgerufen, so stellt der Computer seine Uhr nach dem Zeitsignal von den Zeit-servern time1.our-domain.org und time2.our-domain.org. Da die beiden Server derPTB stark belastet sind, ist es sinnvoll wie in diesem Beispiel auf andere Server aus-zuweichen. Falls Ihr Rechenzentrum keinen eigenen Zeitserver betreibt, wahlen Siegeeignete NTP-Server aus der Liste unter [118]. Hier sind auch weitere ausfuhrlicheDokumentationen und Infos rund um NTP zu finden.

Damit die Systemzeit nicht wieder aus dem Ruder lauft, muss sie immer wiederneu abgeglichen werden. Diese Aufgabe ubernimmt der Damon ntpd. Die Konfi-gurationsmoglichkeiten dieses Damons sind erstaunlich komplex. Listing 5.22 zeigteine minimale Konfiguration fur unseren Server. Mit dieser holt sich der ntpd vonzwei Zeitservern die Zeit und arbeitet andererseits auch als Server fur alle Compu-ter mit den IP-Adressen 192.168.0.xxx. In dem sog. Driftfile legt der NTP-DamonInformationen uber die Ganggenauigkeit der im Computer eingebauten Uhr ab.

Auch der ntpd wird mit einem Init-Skript gestartet. Danach kann dieser Servermit ntpdate abgefragt werden.

Listing 5.22. Mit dieser Konfigurationsdatei /etc/ntp.conf fur den Server wird die Zeitvon NTP-Servern aus dem Internet geholt und an die Knoten des internen Netzes weitergelei-tet.

# Driftfile anlegendriftfile /var/lib/ntp/ntp.drift# einige Logfiles anlegenstatsdir /var/log/ntpstats/

5 statistics loopstats peerstats clockstatsfilegen loopstats file loopstats type day enablefilegen peerstats file peerstats type day enablefilegen clockstats file clockstats type day enable# Zeitquellen

10 server time1.our-domain.orgserver time2.our-domain.org# Zeit an niemanden weiterleitenrestrict default notrust nomodify nopeer# Zeit an sich selbst weiterleiten

15 restrict 127.0.0.1# Zeit an IP-Adressen 192.168.0.xxx weiterleitenrestrict 192.168.0.0 mask 255.255.255.0

Page 126: [X.systems.press] Cluster Computing ||

118 5 PCs vernetzen

Listing 5.23. Konfigurationsdatei /etc/ntp.conf fur die Knoten.

# Driftfile anlegendriftfile /var/lib/ntp/ntp.drift# einige Logfiles anlegenstatsdir /var/log/ntpstats/

5 statistics loopstats peerstats clockstatsfilegen loopstats file loopstats type day enablefilegen peerstats file peerstats type day enablefilegen clockstats file clockstats type day enable# Zeitquelle

10 server server.our-domain.org# Zeit an niemanden weiterleitenrestrict default notrust nomodify nopeer# Zeit an sich selbst weiterleitenrestrict 127.0.0.1

root@server:˜# /etc/init.d/ntpdate startroot@server:˜# ntpdate -q serverserver 192.168.0.254, stratum 16, offset 0.000001, delay 0.025651 Jul 10:55:26 ntpdate[2958]: no server suitable for synchronizationfound

Die Meldung stratum 16 deutet darauf hin, dass die Synchronisierung mit dementfernten NTP-Server noch nicht optimal gelungen ist. Diese dauert normalerweiseeinige Minuten. Geht die Uhr des NTP-Server genauer, verringert sich auch seinStratum.

root@server:˜# ntpdate -q serverserver 192.168.0.254, stratum 3, offset 0.000002, delay 0.025651 Jul 11:27:59 ntpdate[3109]: adjust time server 192.168.0.245 offset0.000002 sec

Das Stratum eines NTP-Servers gibt an, wieviele Schritte zwischen ihm und einemServer mit primarer Zeitquelle (Atomuhr, GPS-Empfanger) liegen. Ein Computer,der wie der Server unseres Beispiel-Clusters die Zeit von einem NTP-Server mit Stra-tum zwei bezieht, hat ein Stratum von drei. Das großtmogliche Stratum betragt 16.

Die Einrichtung der NTP-Programme auf den Knoten lauft fast genau wie aufdem Server, nur mit dem Unterschied, dass die Knoten die Zeit vom gerade einge-richteten lokalen NTP-Server beziehen. Listing 5.23 zeigt die entsprechende Konfi-gurationsdatei. Vom Erfolg der Konfiguration uberzeugen Sie sich auch hier mit demProgramm ntpdate.

root@node1:˜# ntpdate -q node1server 192.168.0.1, stratum 4, offset 0.000002, delay 0.025631 Jul 11:37:55 ntpdate[756]: adjust time server 192.168.0.1 offset0.000002 sec

5.6.5 Network Address Translation

In unserem Beispiel-Cluster ist nur der Server direkt an das Internet angebunden.Die anderen Knoten haben keine offizielle IP-Adresse und konnen nur mit Com-

Page 127: [X.systems.press] Cluster Computing ||

5.6 Wichtige Netzdienste 119

putern innerhalb ihres Subnetzes kommunizieren. Computer außerhalb des Cluster-Subnetzes sind fur die compute nodes unerreichbar. Mit Network Address Transla-tion (kurz NAT) konnen Sie diese Einschrankung uberwinden. NAT wird nicht injedem Cluster gebraucht. Motive, NAT doch einzurichten, sind:

• Mit NAT konnen Sicherheits-Updates (auch ohne Cluster-Managementsoftwarewie SystemImager) von einem Server im Internet auf die compute nodes einge-spielt werden.

• Wenn auf dem Cluster Programme laufen sollen, die Daten von Servern außer-halb des Clusters holen oder an sie senden, so ist NAT notwendig.

Die hier beschriebene Vorgehensweise setzt einen Kernel mit auf iptables basie-renden Paketfiltern (z. B. Kernel der Version 2.4.x oder 2.6.x) und eine noch nichtkonfigurierte Firewall voraus.

NAT funktioniert folgendermaßen: Auf einem Knoten ohne direkten Internetzu-gang ist der Server des Clusters, der eine offizielle IP-Adresse hat, als Gateway zukonfigurieren. Dadurch werden alle IP-Pakete, die nicht fur einen Knoten im lokalenNetz bestimmt sind, an den Server gesandt. Der Server leitet diese Pakete (eventuellnoch uber weitere Computer) an den Zielrechner. Jedoch darf er die Pakete nicht ein-fach unverandert weiterleiten, sie enthalten ja als Absenderadresse eine nicht-offentli-che IP-Adresse. Der Gateway tauscht die interne Adresse einfach gegen seine offent-liche IP-Adresse aus und das Datenpaket hat somit eine gultige Absenderadresse.

Nach einer gewissen Zeit wird der Zielrechner antworten. Seine Antwort kann eraber nicht direkt an den internen Knoten schicken. Der Zielrechner hat von diesemKnoten gar keine Kenntnis. Fur ihn sieht es so aus, als ware er direkt vom Gatewaykontaktiert worden und an diesen schickt er auch seine Antwort. Der Gateway-Rech-ner erkennt, dass das IP-Paket gar nicht fur ihn sondern fur einen internen Knotenbestimmt ist. Er ersetzt die Zieladresse gegen die des internen Knotens und sendetdas Paket an ihn weiter. Bleibt noch zu klaren, wie das Gateway das Kunststuckfertig bringt, zu erkennen, welche eingehenden Pakete fur ihn selbst bestimmt sindund welche an interne Knoten weitergeleitet werden mussen. Dies gelingt ihm, weilnicht nur die Absenderadresse weitergeleiteter Pakete verandert wird sondern auchdie Portnummer. Jeder Netzwerkverbindung zwischen einem internen Knoten undeinem externen Computer wird eine eindeutige Portnummer zugeordnet.

Um NAT auf unserem Beispiel-Cluster einzurichten, mussen Sie sowohl auf deninternen Knoten als auch dem Server, der als Gateway dient, die Netzwerkkonfigura-tion anpassen. Richten Sie die Netzwerkkonfiguration der internen Knoten so wie inAbschnitt 5.4 gezeigt ein, aber konfigurieren Sie zusatzlich den Server (IP-Adresse192.168.0.254) als deren Gateway. Da interne Knoten durch NAT auch auf Rech-ner zugreifen konnen, die nicht in /etc/hosts gelistet sind, muss auf ihnen auchzusatzlich ein Nameserver konfiguriert werden.

Serverseitig ist eine Firewall zu aktivieren, denn NAT wird unter Linux durch dieFirewall-Funktionen des Kernels implementiert. Der Kernel des Servers muss dazumindestens die Module

• ip tables,

Page 128: [X.systems.press] Cluster Computing ||

120 5 PCs vernetzen

Listing 5.24. Dieses Init-Skript aktiviert unter Debian GNU/Linux Network Address Transla-tion.

#! /bin/sh#PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/binNAME="masquerade"

5 DESC="masquerading"set -ecase "$1" in

start)echo -n "Starting $DESC: $NAME"

10 # Load the NAT module (this pulls in all the others).modprobe iptable_nat# Allow outgoing packets, but let only packets that are related# to some outgoing packets.iptables -P FORWARD DROP

15 iptables -A FORWARD -i eth0 -o eth1 -j ACCEPTiptables -A FORWARD -i eth1 -o eth0 -m state \

--state ESTABLISHED,RELATED -j ACCEPT# In the NAT table (-t nat), Append a rule (-A) after routing# (POSTROUTING) for all packets going out eth1 (-o eth1) which

20 # says to MASQUERADE the connection (-j MASQUERADE).iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE# Turn on IP forwardingecho 1 > /proc/sys/net/ipv4/ip_forwardecho "."

25 ;;stop)

echo -n "Stopping $DESC: $NAME"iptables -t nat -D POSTROUTING -o eth1 -j MASQUERADE# Turn off IP forwarding

30 echo 0 > /proc/sys/net/ipv4/ip_forwardecho ".";;

*)N=/etc/init.d/$NAME

35 echo "Usage: $N {start|stop}" >&2exit 1;;

esacexit 0

• iptable nat,• iptable filter,• ipt MASQUERADE und• ip conntrack

enthalten. Wenn eth1 das Netzwerkinterface mit einer global gultigen IP-Adresse istund sonst keine weiteren Firewall-Einstellungen vorgenommen wurden, so konnenSie NAT auf dem Server mit

root@server:˜# modprobe iptable_natroot@server:˜# iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADEroot@server:˜# echo 1 > /proc/sys/net/ipv4/ip_forward

Page 129: [X.systems.press] Cluster Computing ||

5.6 Wichtige Netzdienste 121

aktivieren. Diese drei Kommandos bewirken, dass die notwendigen Kernelmodulegeladen werden, und sie aktivieren das NAT in den Filterregeln der Firewall und dassog. IP-Forwarding. Mit

root@server:˜# iptables -t nat -D POSTROUTING -o eth1 -j MASQUERADEroot@server:˜# echo 0 > /proc/sys/net/ipv4/ip_forward

wird NAT wieder abgeschaltet. Durch ein Init-Skript wie das in Listing 5.24 kannNAT auch beim Booten automatisch gestartet werden. Die drei zusatzlichen Zeilen indiesem Skript, erhohen etwas die Sicherheit. Sie weisen die Firewall an, alle Paketeaus dem lokalen Subnetz nach außen durchzulassen. Aber nur Pakete, die als Antwortauf andere Pakete eingehen, werden in das lokale Subnetz hineingelassen.

Leider vertragt sich NAT nicht mit allen Internet-Protokollen. Das liegt z. B. dar-an, dass manche Protokolle IP-Adressen zusatzlich als Klartext in IP-Paketen ab-legen. FTP ist ein solches Protokoll. Fur einige dieser problematischen Protokol-le gibt es weitere Module, die fur ein reibungsloses Zusammenspiel von diesenProtokollen und NAT sorgen. Fur FTP sind dies die Module ip nat ftp undip conntrack ftp. Weitere Informationen zu NAT unter Linux finden Sie in[145] und [87].

5.6.6 Dynamic Host Configuration Protocol

Im Abschnitt 5.4 haben wir die Netzwerk-Basiskonfiguration beschrieben. Dabeiwurden IP-Adressen, Gateways und andere Parameter in verschiedenen Konfigu-rationsdateien statisch hinterlegt. Mit dem Dynamic Host Configuration Protocol(DHCP) konnen diese Netzwerkparameter dynamisch durch einen DHCP-Server zu-gewiesen werden. Die Vorteile einer dynamische Netzwerkkonfiguration sind:

• Die Netzwerkadministration wird durch DHCP zentralisiert und vereinfacht.• Die Client-Netzwerkkonfiguration reduziert sich darauf, ein DHCP-Client-Pro-

gramm einzurichten.• Befinden sich im Cluster Knoten ohne Festplatte, die mit einer Netzwerkkarte

mit PXE-Boot-ROM uber das Netz booten sollen, so muss dafur im Cluster einDHCP-Server vorhanden sein, siehe auch Abschnitt 5.8.

Die Netzwerkkonfiguration mit DHCP funktioniert (leicht vereinfacht) folgenderma-ßen: Ein DHCP-Client schickt beim Booten an die Adresse 255.255.255.255 eineDHCP-Anfrage (DHCPDISCOVER). Da der Client noch keine gultige IP-Adressehat, benutzt er als Absenderadresse 0.0.0.0. Diese Anfrage wird an alle Computer imlokalen Subnetz weitergeleitet. Ein oder mehrere DHCP-Server beantworten dieseAnfrage mit einer IP-Adresse, die sie einem Pool freier Adressen entnehmen. Die-se Antwort heißt auch DHCPOFFER. Obwohl der Client keine gultige IP-Adres-se hat, erreicht ihn diese Antwort. Das liegt einerseits an einer recht großzugigenAuslegung von RFC 1122 und andererseits daran, dass der DHCP-Server die MAC-Adresse des DHCP-Client kennt. Eine MAC-Adresse ist eine 48 Bit lange Nummer,die jede Ethernetkarte eindeutig identifiziert. Wenn der Client eine angebotene IP-Adresse fur akzeptabel halt, sendet er an den DHCP-Server ein DHCPREQUEST,

Page 130: [X.systems.press] Cluster Computing ||

122 5 PCs vernetzen

Listing 5.25. Minimale Konfigurationsdatei /etc/dhcpd.conf fur einen DHCP-Server.

option domain-name "our-domain.org"option domain-name-servers 123.234.20.254

subnet 192.168.0.0 netmask 255.255.255.0 {5 range 192.168.0.1 192.168.0.250;

option routers 192.168.0.254;option broadcast-address 192.168.0.255;option subnet-mask 255.255.255.0;

}

um ihm mitzuteilen, dass er diese verwenden mochte. Was der DHCP-Server miteinem DCHPACK bestatigt oder mit einem DHCPDECLINE ablehnt. In letzteremFall kann der DHCP-Client erneut ein DHCPDISCOVER senden. Wird ein Knotenheruntergefahren, so schickt er an den DHCP-Server, von dem er seine IP-Adresseerhalten hat, ein DHCPRELEASE. Damit ist die IP-Adresse wieder frei und kanneinem anderen DHCP-Client zugewiesen werden.

Fur ein so kleines Netz wie unseren Beispiel-Cluster ist die Einrichtung einesDHCP-Servers recht einfach. Installieren Sie das DHCP-Server-Paket Ihrer Distri-bution und editieren Sie die Konfigurationsdatei /etc/dhcpd.conf gemaß derVorlage in Listing 5.25. Die Konfigurationsdatei besteht aus globalen Optionen undlokalen Optionen, die nur fur das Subnetz 192.168.0.xxx gelten. Die beiden globa-len Optionen in den ersten beiden Zeilen der Konfigurationsdatei bestimmen den Do-mainnamen und den DNS-Server. In den nachfolgenden Zeilen von Listing 5.25 wirdfestgelegt, dass die IP-Adressen von 192.168.0.1 bis 192.168.0.250 dynamisch verge-ben werden durfen, die IP-Adresse des Default-Gateways ist jeweils 192.168.0.254,Broadcast-Adresse ist 192.168.0.255 und die Subnetzmaske lautet 255.255.255.0.

Die dynamische Zuweisung von IP-Adressen hat auch ihre Nachteile. Sie fuhrtdazu, dass ein Knoten nach jedem Reboot eine andere IP-Adresse haben kann. Das istin einem Cluster nicht unbedingt erwunscht. Stellen Sie sich vor, Sie haben durch dasHardware-Monitoring festgestellt, dass beim Knoten mit der IP-Adresse 192.168.0.3der CPU-Lufter ausgefallen ist. Bei welchem Knoten mussen Sie nun das Gehauseaufschrauben, um den Lufter zu tauschen? Zum Gluck konnen mit DHCP vergebe-ne IP-Adressen auch fest (statisch) an MAC-Adressen gebunden werden. Dies istzwar nicht unbedingt im Geiste von DHCP, aber in einem Cluster meist praktischer.Listing 5.26 zeigt ein Beispiel fur eine DHCP-Server-Konfigurationsdatei fur einean MAC-Adressen gebundene Vergabe von IP-Adressen. Fur jeden Knoten enthaltsie eine host-Deklaration, in der jeder MAC-Adresse eine IP-Adresse zugewiesenwird. Naturlich mussen Sie die MAC-Adressen des Beispiels gegen die Ihrer Netz-werkkarten austauschen.

Aber wie erfahrt man die MAC-Adresse einer Ethernetkarte? Auf den meistenNetzwerkkarten ist die MAC-Adresse irgendwo aufgedruckt. Wurde eine Netzwerk-karte schon einmal konfiguriert, so gibt ifconfig die MAC-Adresse aus.

Page 131: [X.systems.press] Cluster Computing ||

5.6 Wichtige Netzdienste 123

Listing 5.26. Konfigurationsdatei /etc/dhcpd.conf eines DHCP-Servers mit statischerVergabe von IP-Adressen.

option domain-name "our-domain.org"option domain-name-servers 123.234.20.254

subnet 192.168.0.0 netmask 255.255.255.0 {5 option routers 192.168.0.254;

option broadcast-address 192.168.0.255;option subnet-mask 255.255.255.0;

host node1 {10 hardware ethernet 00:11:22:33:44:55:01;

fixed-address 192.168.0.1;}host node2 {

hardware ethernet 00:11:22:33:44:55:02;15 fixed-address 192.168.0.2;

}host node3 {

hardware ethernet 00:11:22:33:44:55:03;fixed-address 192.168.0.3;

20 }host node4 {

hardware ethernet 00:11:22:33:44:55:04;fixed-address 192.168.0.4;

}25 }

root@node1:˜# ifconfigeth0 Link encap:Ethernet HWaddr 00:04:75:E3:9D:45

inet addr:192.168.0.1 Bcast:192.168.0.255 Mask:255.255.255.0UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1RX packets:10284 errors:0 dropped:0 overruns:0 frame:0TX packets:8172 errors:0 dropped:0 overruns:0 carrier:0collisions:2657 txqueuelen:100RX bytes:5788149 (5.5 MiB) TX bytes:1095186 (1.0 MiB)Interrupt:11 Base address:0x1000

Hier hat die Netzwerkkarte also die MAC-Adresse 00:04:75:E3:9D:45. Auch mitdmesg konnen Sie (meist) die MAC-Adresse ermitteln. Die folgenden Kommandosfiltern aus den Meldungen des dmesg-Programms alle Zeilen heraus, die eine MAC-Adresse enthalten konnten.

root@node1:˜# dmesg | grep -E -i ’([0-9a-f]{2}:){5}[0-9a-f]{2}’00:04:75:e3:9d:45, IRQ 18

Solange auf dem fraglichen Knoten noch kein Betriebssystem installiert wurde, nut-zen diese beiden Methoden recht wenig. Hier kann man ausnutzen, dass Knotenmit PXE-Boot-ROM schon beim Booten eine DHCP-Anfrage stellen und durch denDHCP-Server die MAC-Adresse jeder Netzwerkkarte, die ein DHCPDISCOVERoder DHCPREQUEST sendet, in der Datei /var/log/syslog protokolliert wird.

Page 132: [X.systems.press] Cluster Computing ||

124 5 PCs vernetzen

Listing 5.27. Init-Skript fur einen DHCP-Server unter Debian GNU/Linux.

#!/bin/sh#test -x /usr/sbin/dhcpd || exit 0# Defaults

5 INTERFACES="eth0"# Reads config file (will override defaults above)[ -r /etc/default/dhcp ] && . /etc/default/dhcpDHCPDPID=/var/run/dhcpd.pidcase "$1" in

10 start)echo -n "Starting DHCP server: dhcp"start-stop-daemon --start --quiet --pidfile $DHCPDPID \

--exec /usr/sbin/dhcpd -- -q $INTERFACESecho "."

15 ;;stop)

echo -n "Stopping DHCP server: dhcp"start-stop-daemon --stop --quiet --pidfile $DHCPDPIDecho "."

20 ;;restart)

echo -n "Stopping DHCP server: dhcp"start-stop-daemon --stop --quiet --pidfile $DHCPDPIDecho "."

25 sleep 2echo -n "Starting DHCP server: dhcp"start-stop-daemon --start --quiet --pidfile $DHCPDPID \

--exec /usr/sbin/dhcpd -- -q $INTERFACESecho "."

30 ;;

*)echo "Usage: /etc/init.d/dhcp {start|stop|restart}"exit 1

esac35 exit 0

Gestartet wird der DHCP-Server durch ein Init-Skript wie das in Listing 5.27.Ganz wichtig ist, dass dem DHCP-Server beim Start der Name des Interfaces ange-geben wird, an dem er auf DHCP-Anfragen von DHCP-Clients lauschen soll. Ohnediese Angabe wurde er von allen Interfaces Anfragen entgegennehmen. Fur unse-ren Beispiel-Cluster hieße dies, dass er auch Anfragen beantworten wurde, die uberdie mit dem externen Netz verbundene Netzwerkkarte eingehen, was normalerweisenicht erwunscht ist.

Die clientseitige Konfiguration von DHCP ist bei jeder Distribution etwas andersaber nicht schwierig. Am besten Sie benutzen dazu die KonfigurationswerkzeugeIhrer Distribution, z. B. bei SuSE yast, oder editieren die entsprechenden Konfi-gurationsdateien. Unter Debian GNU/Linux ist dies die Datei /etc/network/interfaces. Soll das Interface eth0 uber DHCP konfiguriert werden, so muss die-se Datei die in Listing 5.28 gezeigten Zeilen enthalten. Beim Systemstart wird durchein Init-Skript ein DHCP-Client-Programm aufgerufen. Je nach Distribution ist diesdhclient (RedHat, Debian), dhcpcd (SuSE) oder pump. Abhangig von der Kon-

Page 133: [X.systems.press] Cluster Computing ||

5.7 Channel bonding 125

Listing 5.28. DHCP-Client-Konfiguration durch die Datei /etc/network/interfacesunter Debian GNU/Linux.

# das Loopback-Interfaceauto loiface lo inet loopback# erste Ethernetkarte

5 auto eth0iface eth0 inet dhcp

figuration setzt das DHCP-Client-Programm neben der IP-Adresse auch Host- undDomainnamen.

Weitere Informationen rund um DHCP finden Sie in den Manpages dhcpd(8),dhcpd.conf(5), dhclient(8) und dhclient.conf(5) sowie in dem Artikel [1].

5.7 Channel bonding

Fur viele Cluster-Anwendungen ist eine hohe Netzbandbreite essentiell. Der Preiseiner Netzwerktechnik wachst jedoch uberproportional mit der von ihr bereitgestel-len Bandbreite. Darum haben High-End-Netzwerktechniken leider auch High-End-Preise, so dass die Wahl der in einem Cluster eingesetzten Netzwerktechnik auch im-mer ein Abwagen zwischen Preis und Leistung ist. Mit channel bonding unterstutztLinux eine Technik, die Bandbreitenengpasse auf recht preiswerte Art und Weise zuuberwinden hilft. Beim channel bonding werden mehrere physische Netzwerkkartenzu einem logischen Netzwerkinterface zusammengefasst. Die Bandbreite dieses lo-gischen Netzwerkinterfaces ist im Idealfall gleich der Summe der Bandbreiten derzusammengefassten Netzwerkkarten. Werfen wir noch einmal einen Blick auf Tabel-le 4.1, so erkennen wir, dass zwei durch channel bonding zusammengefasste Giga-bit Ethernet Netze eine Bandbreite besitzen, die fast schon so groß ist wie die vonMyrinet-2000, aber um einen Faktor funf preiswerter ist. Latenzzeiten werden durchchannel bonding leider nicht positiv beeinflusst, siehe unten. Hier punkten weiterhinHigh-End-Netzwerktechniken wie Myrinet.

Alles was man benotigt, um die Bandbreite eines Clusters durch channel bondingzu steigern, sind

• ein Kernel mit channel-bonding-Treiber und das Programm ifenslave,• mindestens zwei Ethernetkarten pro Knoten und• je ein Switch pro physischem Netz oder ein Switch, der channel bonding (von

Cisco und anderen Hardwareherstellern auch trunking genannt) beherrscht.

Das Programm ifenslave wird fur die Konfiguration des Bonding-Interfacebenotigt. Seine Quellen liegen im Dokumentationsverzeichnis des Kernels unternetworking/ifenslave.c. Kompilieren Sie das Programm mit

root@node1:˜# gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include \> -o /sbin/ifenslave \> /usr/src/linux/Documentation/networking/ifenslave.c

Page 134: [X.systems.press] Cluster Computing ||

126 5 PCs vernetzen

Falls Ihre Linux-Distribution das Programm ifenslave enthalt, Sie aber nicht denin der Distribution enthaltenen Kernel verwenden, mussen Sie damit rechnen, dassIhr Kernel und das ifenslave der Distribution nicht miteinander harmonieren.Wenn Sie ifenslave und Kernel aus dem gleichen Quellbaum erstellen, sind Sieauf der sicheren Seite.

Der channel-bonding-Treiber unterstutzt verschiedene Modi zur Lastverteilungund zum Aufbau ausfallsicherer Netze. Fur uns ist hier nur der Standardmodus(Round-Robin-Modus) von Interesse. Er verteilt ausgehende Pakete gleichmaßig aufdie physischen Netzwerk-Interfaces. Dabei findet eine Gewichtung mit der Band-breite der Netzwerk-Interfaces statt, so dass langsame Interfaces schnellere nichtausbremsen.

Falls der channel-bonding-Treiber als Modul in den Kernel integriert wurde,mussen Sie noch dafur sorgen, dass er wie auch der Treiber der Netzwerkartebei Bedarf automatisch geladen wird, siehe Abschnitt 5.4.1. Die Konfiguration desBonding-Interfaces bond0 erfolgt ganz ahnlich, wie bei einer Ethernetkarte. StellenSie zunachst sicher, dass keines der Netzwerk-Interfaces, die durch channel bondingzusammengefasst werden sollen, aktiv ist. Ein inaktives Netzwerk-Interface erken-nen Sie daran, dass es in der Ausgabe von ifconfig nicht aufgelistet wird. AufKnoten node1 ist das Bonding-Interface z. B. durch

root@node1:˜# ifconfig bond0 192.168.0.1 netmask 255.255.255.0 \> broadcast 192.168.0.255 up

zu aktivieren. Nun konnen dem logischen Bonding-Interface physische Netzwerkin-terfaces zugeordnet werden. Das ist die Aufgabe von ifenslave. Mit

root@node1:˜# ifenslave bond0 eth0root@node1:˜# ifenslave bond0 eth1

werden die beiden Interfaces eth0 und eth1 dem Bonding-Interface bond0 zugewie-sen. Wird ifenslave mit der Option -d aufgerufen, kann eine solche Zuweisungauch wieder aufgehoben werden.

Das automatische Konfiguration des Bonding-Interfaces beim Systemstart ist lei-der wieder distributionsspezifisch. Listing 5.29 zeigt einen Ausschnitt aus der Datei/etc/network/interfaces mit dem unter Debian GNU/Linux ein Bonding-Interface automatisch konfiguriert werden kann. Die Einrichtung unter RedHat wirdin der Dokumentation das channel-bonding-Treibers beschrieben. Sie liegt in derKerneldokumentation unter networking/bonding.txt. Hier finden Sie auchweitere Informationen rund um channel bonding.

Um uns von der Leistungsfahigkeit des channel bonding zu uberzeugen, habenwir mit zwei Computern, die jeweils mit zwei Fast-Ethernet-Karten ausgestattet wa-ren, einige Bandbreitenmessungen durchgefuhrt. Fur die Tests haben wir einmal vierFast-Ethernet-Karten vom Typ Intel E100 Pro und ein anderes Mal vier vom Typ3Com 905 verwendet. Bei diesen Messungen wurden wie beim PingPong-Test (sie-he Abschnitt 12.2.2) Datenpakete verschiedener Große von einem Computer zumanderen und wieder zuruck gesendet und dabei die Bandbreite in Abhangigkeit vonder Paketgroße ermittelt. Bei den Bandbreitenmessungen liefen die Datenpakete ein-

Page 135: [X.systems.press] Cluster Computing ||

5.7 Channel bonding 127

Listing 5.29. Mit diesen Eintragen in der Datei /etc/network/interfaces lassen sichauf einem Debian-System die Interfaces eth0 und eth1 zu einem Bonding-Interface zusammen-fassen.

iface bond0 inet staticup ifenslave bond0 eth0up ifenslave bond0 eth1down ifenslave -d bond0 eth1

5 down ifenslave -d bond0 eth0address 192.168.0.1netmask 255.255.255.0broadcast 192.168.0.255gateway 192.168.0.254

mal durch nur eine Karte je Computer (kein channel bonding) und einmal uber zweiKarten.

Welche Leistung konnen wir erwarten? Die Zeit, die benotigt wird, ein Datenpa-ket der Lange P von einem Computer zu einem anderen zu senden, setzt sich aus derLatenzzeit TL und der Zeit fur die eigentliche Datenubertragung zusammen. Mit derBandbreite B gilt somit

Teff = TL +PB

, (5.1)

woraus sich eine effektive Bandbreite

Beff =P

Teff=

PTL +P/B

(5.2)

ergibt. Fur P � B ·TL wird die effektive Bandbreite durch die Latenzzeit beschrankt.Erst bei großen Paketen (P � B ·TL) kommt die effektive Bandbreite der maximalenBandbreite B nahe. Im Falle von Fast-Ethernet ohne channel bonding konnen TL ≈70µs und Beff = 100MBit/s angesetzt werden.

In Abb. 5.4 sehen Sie die Ergebnisse unserer Messungen. Die gute Nachricht ist,dass mit channel bonding uber zwei Fast-Ethernet-Karten die Bandbreite wirklichfast verdoppelt werden kann. Leider gilt dies nur, wenn die Datenpakete großer alsca. 64 KByte sind. Kommunikation mit kleinen Datenpaketen kann nicht von channelbonding profitieren. Erstaunlicherweise gibt es auch zwischen den beiden getestetenKartentypen große Performanceunterschiede. Zwar erreichen beide Typen bei Daten-paketen, die großer als 1 MByte sind, fast die theoretische Maximalbandbreite von100 MBit/s bzw. 200 MBit/s, jedoch bei Paketen zwischen 16 Byte und ca. 64 KByteist die Karte von Intel um bis zu einen Faktor zehn langsamer als die von 3Com.Zusatzlich zu den Messergebnissen haben wir die aus unseren theoretischen Uber-legungen erhaltene effektive Bandbreite (5.2) in Abb. 5.4 eingezeichnet. Zumindestim Falle der 3Com-Karte stimmt diese theoretische Bandbreite mit der tatsachlichgemessenen ganz gut uberein.

Wir haben zwar nur Messungen mit Fast-Ethernet-Karten gemacht, bei anderenNetzwerktechniken sind aber qualitativ ahnliche Ergebnisse zu erwarten. Sei Pmin dieminimale Paketgroße und fordern wir, dass sich mit dem Einsatz von n Netzwerkkar-ten die effektive Bandbreite mindestens um einen Faktor α (1 < α < n) gegenuber

Page 136: [X.systems.press] Cluster Computing ||

128 5 PCs vernetzen

0,1

1

10

100

20 22 24 26 28 210 212 214 216 218 220 222

Ban

dbre

ite in

MB

it/s

Paketgröße in Byte

3Com 9052×3Com 905

Intel E100 Pro2×Intel E100 Pro

theoretisch (B = 100MBit/s)theoretisch (B = 200MBit/s)

Abb. 5.4. Effektive Bandbreite vom channel bonding mit zwei Fast-Ethernet-Karten im Ver-gleich zu reinem Fast-Ethernet. Fur theoretische Abschatzung der effektiven Bandbreite nach(5.2) wurde eine Latenzzeit von 70 µs angenommen.

nur einer Karte erhoht, so muss

Beff,n

Beff,1=

PminTL+Pmin/(nB)

PminTL+Pmin/B

> α (5.3)

gelten. Daraus folgt eine minimale Paketgroße von

Pmin > B ·TLn(α −1)

n−α. (5.4)

Nur wenn Ihre Anwendungen typischerweise Nachrichten versenden, die langer alsPmin sind, lohnt sich der Aufwand fur channel bonding.

Bei dieser Uberlegung setzen wir naturlich voraus, dass sich keine neuen Fla-schenhalse auftun. Bedenken Sie, dass alle Netzwerkkarten ihre Daten uber den Sys-tembus (meist PCI-Bus) in den Speicher schreiben bzw. von dort lesen. So ist esz. B. praktisch nicht moglich, channel bonding sinnvoll mit zwei Gigabit-Ethernet-Karten je Knoten an einem Standard-PCI-Bus zu betreiben. Schnelle Bussystemewie PCI Express und AMDs HyperTransport sollten hier aber in Zukunft Abhilfeschaffen. Allerdings kommt erschwerend hinzu, dass aufgrund eines etwas ungunsti-gen Designs des Linux channel-bonding-Treibers sich bei großen Datendurchsatzenmehrere Netzwerkkarten teilweise gegenseitig behindern konnen. Falls Sie vorallemMPI-Anwendungen einsetzen, konnen Sie alternativ auch eine MPI-Implementationverwenden, die ihre Kommunikation gleichzeitig uber mehrere Interfaces abwickelnkann. Open MPI wird dies z. B. konnen (Notiz 6.1).

Page 137: [X.systems.press] Cluster Computing ||

5.8 Diskless nodes 129

5.8 Diskless nodes

Einen Cluster aus Knoten ohne Festplatten (diskless nodes) zu betreiben, hat einigeVorteile, siehe Abschnitt 4.7. Leider bieten die gangigen Linux-Distributionen keineoder nur wenig Unterstutzung fur diese Betriebsart und die erstmalige Konfigurationeines Clusters mit diskless nodes erfordert relativ viel Handarbeit. Der Aufwand istjedoch unabhangig von der Zahl der Knoten und lohnt sich besonders fur großereCluster mit ca. 16 oder mehr Knoten. Fur Administratoren, die zum ersten Mal einenCluster mit diskless nodes aufbauen, kommt erschwerend hinzu, dass viele Wege zusolch einem Cluster fuhren. Das Studium diverser HowTos und FAQs zu diesem The-ma sorgt darum anfangs fur mehr Verwirrung als Einsicht. Wir beschranken uns andieser Stelle darauf, einen dieser Wege ausfuhrlicher darzustellen und auf moglicheAlternativen nur zu verweisen.

Wie in den vorherigen Abschnitten gehen wir von einem Cluster mit einem Ser-ver und vier gleichartigen Knoten aus. Man kann das Beispiel aber leicht auf ande-re Cluster-Konfigurationen verallgemeinern, zumindest solange die Knotenhardwarehalbwegs einheitlich ist.

5.8.1 Uberblick

Da diskless nodes keine lokale Festplatte besitzen, auf der sich das Betriebssystembefindet, mussen sie sich ihr Betriebsystem uber das Netzwerk von einem Serverholen. Um das Booten uber das Netzwerk besser zu verstehen, rufen wir uns nocheinmal ins Gedachtnis, was beim Booten von einer Festplatte geschieht.

Wird ein Computer eingeschaltet, so startet zunachst ein Programm (das BIOS),das sich auf einem nichtfluchtigen Speicherchip auf dem Motherboard befindet. Esfuhrt einige elementare Hardwaretests durch und sucht nach Hardwarekomponenten,die als Bootmedium in Frage kommen. Typischerweise sind dies Festplatte, Disketteoder CD-ROM. Hat das BIOS z. B. die Festplatte als Bootmedium erkannt, so liestes von einer bestimmten Stelle auf der Festplatte (dem Master Boot Record) einkleines Programm. Dessen Aufgabe es ist, das Boot-Loader-Programm (z. B. GRUBoder Lilo) von der Festplatte zu laden. Erst dieser Boot-Loader ist in der Lage, denKernel von der Festplatte zu lesen und zu starten. Der Kernel bindet schließlich vonder Festplatte das Root-Dateisystem ein startet den init-Prozess, die Mutter allerProzesse. Damit ist der Bootvorgang abgeschlossen.

Das Booten uber das Netzwerk funktioniert fast genau so, nur sind die Akteureandere. Grundvoraussetzung ist, dass sich die Netzwerkkarte gegenuber dem BIOSals Bootmedium identifiziert und das BIOS sie als solche erkennt. Neuere Netzwerk-karten und Motherboards sind dazu fast immer in der Lage. Jedoch muss diese Funk-tion oft erst im Motherboard-BIOS und manchmal auch im Netzwerkarten-BIOSaktiviert werden. Statt eines Master Boot Record besitzt die Netzwerkkarte ein Boot-ROM. Darin ist das Programm gespeichert, das von einem Server den Boot-Loaderholt. Dieser ladt uber das Netz schließlich den Kernel, startet ihn und der Kernelbindet das Root-Dateisystem ein und startet den init-Prozess.

Page 138: [X.systems.press] Cluster Computing ||

130 5 PCs vernetzen

Tabelle 5.1. Verschiedene Komponenten zum Booten uber das Netz.

Komponente hier beschieben mogliche Alternativen

Boot-ROM PXE Etherboot [36], Netboot [112]Boot-Loader pxelinux [162] BpBatch [14]Root-Dateisystem NFS-Root RAM-Disk

5.8.2 Booten uber das Netzwerk mit PXE

Es konnen verschiedene Arten von Boot-ROM, Boot-Loader und Root-Dateisystemverwendet werden, siehe Tabelle 5.1. Hier soll eine Kombination aus PXE-Boot-ROM, pxelinux und einem uber NFS eingebundenen Root-Dateisystem beschiebenwerden. PXE ist ein von Intel geschaffener Standard fur Boot-ROMs und steht furPre-Boot Execution Environment. Mittlerweile sind viele Netzwerkkarten verschie-dener Hersteller mit einem PXE-Boot-ROM ausgestattet. Altere Netzwerkkarten oh-ne PXE-Boot-ROM besitzen oft nur einen Sockel fur ein Boot-ROM, das man sicherst selbst brennen muss.

Das Booten mit PXE funktioniert im Detail folgendermaßen: Das Motherboard-BIOS erkennt die Netzwerkkarte als Bootmedium und startet das im Boot-ROMgespeicherte Programm. Dies sendet eine DHCP-Anfrage in das Netz und erhaltdarauf von einem DHCP-Server eine IP-Adresse zugewiesen. Danach holt das Pro-gramm im Boot-ROM mittels Trivial File Transfer Protocol (TFTP) den Boot-Loa-der pxelinux.0 von einem Server. Die IP-Adresse und andere Parameter werdenan einer definierten Speicherstelle abgelegt. Der Boot-Loader liest diese spater wie-der aus, um uber TFTP den Kernel vom Server zu laden und zu starten.

Leider weiß der Kernel nichts uber PXE und hat insbesondere keine Informati-on uber die bei der vorherigen DHCP-Anfrage erhaltene IP-Adresse. Die endgulti-ge IP-Adresse kann entweder uber ein DHCP-Client-Programm zugewiesen werdenoder der Kernel kummert sich selbst darum. Dafur muss im Kernel die Option IP:kernel level autoconfiguration aktiviert worden sein. Dann holt sich der Kernel viaDHCP, BOOTP oder RARP von einem Server die IP-Adresse oder erhalt sie durcheinen Kernel-Parameter vom Boot-Loader zugewiesen. Die Variante mit dem DHCP-Client-Programm setzt voraus, dass vor seinem Aufruf bereits das Root-Dateisystemeingebunden wurde. Dies kann praktisch nur eine RAM-Disk sein. Eine Festplatteist nicht vorhanden und ein Netzwerkdateisystem setzt eine konfigurierte Netzwerk-karte voraus. Eine Zuweisung der IP-Adresse auf Kernel-Ebene uber eine DHCP-Anfrage oder Kernel-Parameter ist mit dem geringsten administrativen Aufwand ein-zurichten. Die Protokolle BOOTP oder RARP werden heute kaum noch verwendet.

Bevor der init-Prozess startet, muss das Root-Dateisystem eingebunden wer-den. Es liegt entweder in einer RAM-Disk oder, was wir hier annehmen wollen, wirdvon einem NFS-Server eingebunden.

Page 139: [X.systems.press] Cluster Computing ||

5.8 Diskless nodes 131

5.8.3 Kernelkonfiguration

Ein Kernel fur einen Knoten ohne Festplatten muss, wie wir gesehen haben, uberganz besondere Fahigkeiten verfugen. Beim Bau eines solchen Kernels sind folgendePunkte zu beachten:

• Der Kernel sollte monolithisch sein, also keinerlei Module enthalten. Diese Be-dingung ist zwar nicht zwingend, macht das Leben aber etwas leichter. Insbeson-dere muss der Treiber fur die Netzwerkkarte fest im Kernel eingebaut sein.

• Im Menu Networking options ist der Punkt IP: kernel level autoconfigurationund gegebenenfalls IP: DHCP support auszuwahlen.

• Unter Network File Systems sind NFS file system support und Root file system onNFS zu aktivieren. Letzterer Menupunkt ist nur sichtbar, wenn zuvor IP: kernellevel autoconfiguration ausgewahlt wurde.

• Falls der Kernel sein Root-Dateisystem von einer RAM-Disk laden soll, wahlenSie unter Block devices die Optionen RAM disk support und Initial RAM disk(initrd) support aus und lesen Sie die Datei initrd.txt in der Kernel-Doku-mentation.

• Temporare Dateien im /tmp-Verzeichnis sollten in einem tmpfs-Dateisystemliegen. Dabei handelt es sich um ein virtuelles Dateisystem, das Dateien im Ar-beitsspeicher ablegt. Damit belasten Zugriffe auf das Verzeichnis /tmp nichtdas Netzwerk und außerdem wird ein Problem umgangen, das regelmaßig beiLAM/MPI (siehe 6.1) auftritt, wenn /tmp uber NFS eingebunden wird. Eintmpfs-Dateisystem wachst dynamisch, belegt so immer nur soviel RAM wie gera-de notig, kann aber in seiner Große nach oben beschrankt werden. Die Option furtmpfs finden Sie im Menu File systems unter Virtual memory file system support.

• Alle Komponenten, die nicht unbedingt benotigt werden, sollten aus dem Ker-nel entfernt werden. Dazu gehoren z. B. Treiber fur Festplatten und CD-ROM-Laufwerke.

Der so konfigurierte Kernel kann wie gewohnt ubersetzt werden, nur die Installationentfallt.

5.8.4 Server-Konfiguration

Damit die diskless nodes booten konnen, sind sie auf die Unterstutzung eines Serversangewiesen. Serverseitig sind dazu folgende Dienste einzurichten:

• TFTP-Server,• DHCP-Server,• NFS-Server und• Verzeichnisstrukturen fur die Root-Verzeichnisse der Knoten.

Als TFTP-Server kommen verschiedene Programme in Frage. Allerdings muss derTFTP-Server die in RFC 2349 beschriebene TSIZE-Funktion unterstutzen. Dadurchkann pxelinux die Große einer Datei bestimmen, noch bevor sie ubertragen wurde.Bewahrt hat sich tftp-hpa. Dieser TFTP-Server stammt von H. P. Anvin, der auch

Page 140: [X.systems.press] Cluster Computing ||

132 5 PCs vernetzen

Listing 5.30. Fur einen TFTP-Server notwendige Erganzung in /etc/hosts.allow.

in.tftpd: 192.168.0.0/255.255.255.0

Listing 5.31. Fur einen TFTP-Server notwendige Erganzung in /etc/inetd.conf.

tftp dgram udp wait root /usr/sbin/tcpd /usr/sbin/in.tftpd -s /tftpboot

Listing 5.32. Beispiel fur eine pxelinux-Konfigurationsdatei.

DEFAULT vmlinuz-2.4.22APPEND root=/dev/nfs nfsroot=192.168.0.254:/nodes/node1,rw ip=dhcp

Autor von pxelinux ist. Das Programm tftp-hpa ist in den meisten Linux-Distributio-nen vorhanden und kann mit deren Installationsprogrammen problemlos eingerich-tet werden. Beachten Sie, dass der TFTP-Server uber den Internet-Damon inetdbzw. xinetd gestartet wird und einen sehr unsicheren Dienst darstellt. Durch ihnkann auf Dateien des Servers ohne Authentifikation zugegriffen werden. Darum soll-te der TFTP-Server unbedingt durch den TCP-Wrapper abgesichert und der Zugriffdarauf ausschließlich Knoten aus dem lokalen Netz erlaubt werden. Im Falle desinetd ist dazu in /etc/hosts.allow die in Listing 5.30 gezeigte Zeile ein-zutragen und die Datei /etc/inetd.conf ist durch Listing 5.31 zu erganzen.Die Option -s /tftpboot schrankt Dateizugriffe des TFTP-Servers auf das Ver-zeichnis /tftpboot ein. In diesem Verzeichnis liegen alle Dateien, die uber TFTPverteilt werden mussen. Dies sind der Boot-Loader pxelinux.0 und der Kernel,z. B. vmlinuz-2.4.22.

Außerdem liegt in /tftpboot das Verzeichnis pxelinux.cfg, das Konfigu-rationsdateien des Boot-Loaders fur jeden der Knoten enthalt. Der Name der Konfi-gurationsdatei ist jeweils die IP-Adresse des Knotens in hexadezimaler Schreibweise,also z. B. C0A80001 fur 192.168.0.1. Im einfachsten Falle besteht eine solche Kon-figurationsdatei aus nur zwei Zeilen. Die erste gibt den Namen der Datei mit demLinux-Kernel an, die zweite eine Liste der Optionen, die an den Kernel ubergebenwerden sollen. Listing 5.32 zeigt ein Beispiel. Die Optionen root=/dev/nfs undnfsroot=192.168.0.254:/nodes/node1,rw weisen den Kernel an, dasRoot-Dateisystem vom NFS-Server mit der IP-Adresse 192.168.0.254 vom Verzeich-nis /nodes/node1 mit Lese- und Schreibrechten einzubinden. Seine IP-Adressesoll der Kernel via DHCP anfordern. Viele weitere nutzliche Kernel-Optionen wer-den in den Dateien nfsroot.txt und kernel-parameters.txt der Kernel-Dokumentation beschrieben. Das Format der pxelinux-Konfigurationsdatei konnenSie in der Dokumentation des syslinux-Boot-Loaders, von dem pxelinux abstammt,unter [162] nachlesen.

Die Einrichtung eines DHCP-Servers wurde schon im Abschnitt 5.6.6 beschrie-ben. Allerdings sind im Falle von diskless nodes einige Erganzungen in der Konfi-gurationsdatei /etc/dhcpd.conf vorzunehmen, siehe Listing 5.33. Die beiden

Page 141: [X.systems.press] Cluster Computing ||

5.8 Diskless nodes 133

Listing 5.33. Konfigurationsdatei /etc/dhcpd.conf des DHCP-Servers bei statischer Ver-gabe von IP-Adressen fur einen Cluster mit diskless nodes.

allow booting;allow bootp;use-host-decl-names on;

5 subnet 192.168.0.0 netmask 255.255.255.0 {

option domain-name "our-domain.org";option broadcast-address 192.168.0.255;option domain-name-servers 192.168.0.254;

10 option routers 192.168.0.254;next-server 192.168.0.254;filename "pxelinux.0";

host node1 {15 hardware ethernet 00:00:E2:8F:5D:99;

fixed-address 192.168.0.1;}host node2 {

hardware ethernet 00:00:E2:8F:1F:41;20 fixed-address 192.168.0.2;

}host node3 {

hardware ethernet 00:00:E2:8F:31:54;fixed-address 192.168.0.3;

25 }host node4 {

hardware ethernet 00:00:E2:8F:43:72;fixed-address 192.168.0.4;

}30

}

Optionen allow booting und allow bootp sind fur das Zusammenspiel vonPXE und DHCP notwendig. Durch die Option use-host-decl-names onwer-den DHCP-Clients angewiesen, neben der IP-Adresse auch den Hostnamen auf einenvom DHCP-Server vorgegebenen Namen zu setzen. Außer den Netzwerkparameternmuss ein PXE-Client auch den Namen des Boot-Loaders und die IP-Adresse desTFTP-Server wissen. In unserem Beispiel teilt der DHCP-Server durch die beidenOptionen next-server 192.168.0.254 und filename "pxelinux.0",einem PXE-Client mit, dass er sich den Boot-Loader pxelinux.0 vom Server mitder IP-Adresse 192.168.0.254 holen kann.

Wenn Sie Abschnitt 5.6.1 gelesen haben, sind Sie auch schon mit der Konfigu-ration eines NFS-Servers bestens vertraut. Lediglich der Inhalt der Datei /etc/exports muss etwas angepasst werden, siehe Listing 5.34. In unserem Beispielexportiert der NFS-Server folgende Verzeichnisse:

/usr/local. Dieses Verzeichnis werden alle Knoten als /usr/local einbin-den, wobei (meist) nur lesender Zugriff gestattet werden muss. Hier werdenspater Programme installiert, die auf jedem Knoten zur Verfugung stehen mussenund von denen relativ oft neue Versionen eingespielt werden. Da /usr/local

Page 142: [X.systems.press] Cluster Computing ||

134 5 PCs vernetzen

Listing 5.34. NFS-Server-Konfigurationsdatei /etc/exports fur einen Cluster mit dis-kless nodes.

/usr/local 192.168.0.0/255.255.255.0(no_root_squash,ro,sync)/home 192.168.0.0/255.255.255.0(rw,sync)/nodes/golden_image/usr 192.168.0.0/255.255.255.0(no_root_squash,ro,sync)/nodes/node1 192.168.0.1(no_root_squash,rw,sync)

5 /nodes/node2 192.168.0.2(no_root_squash,rw,sync)/nodes/node3 192.168.0.3(no_root_squash,rw,sync)/nodes/node4 192.168.0.4(no_root_squash,rw,sync)

vom Server an alle Knoten exportiert wird, ist ein Programm, das auf dem Serverunter diesem Verzeichnis installiert wurde, auch sofort auf allen anderen Knotenverfugbar.

/home. Hier liegen die Heimatverzeichnisse der Nutzer, sie mussen auf ihre Datenauch schreibend zugreifen konnen.

/nodes/golden image/usr. Dieses Verzeichnis werden alle Knoten als /usreinbinden. Hier liegen Programme und Daten, auf die die Knoten nur lesend zu-greifen mussen und die noch nicht wahrend der ganz fruhen Phase des Boot-Prozess benotigt werden.

/nodes/node1 bis /nodes/node4. Dies sind die Root-Verzeichnisse der Kno-ten. Jeder Knoten benotigt sein eigenes Root-Verzeichnis, auf das er exklusivschreibend zugreifen kann. Das Root-Dateisystem muss insbesondere alle Datei-en enthalten, die zu einem sehr fruhen Zeitpunkt wahrend des Boot-Prozessesbenotigt werden. Dies sind z. B. die Verzeichnisse /bin, /sbin und /dev.

Beachten Sie, dass außer den Heimatverzeichnissen alle Verzeichnisse mit der Opti-on no root squash exportiert werden mussen, sonst greift root auf den Knotenauf diese Verzeichnisse mit den Rechten von nobody zu.

Der schwierigste Schritt bei der Einrichtung des Servers besteht darin, die Root-Verzeichnisse der Knoten und das Verzeichnis /nodes/golden image/usr an-zulegen. Leider gibt es hier kaum wirklich ausgereifte Losungen, die einem Adminis-trator dabei helfen. Losungsvorschlage fur dieses Problem, die man in den einschlagi-gen HowTos findet, munden nicht selten in schwer wartbaren Installationen. Wir be-schreiben hier eine Methode, die recht einfach aber effektiv zu warten ist. Moglichwird dies, weil wir einem der Knoten doch eine lokale Festplatte spendieren.

Die Vorgehensweise ist dabei die folgende: Auf diese Festplatte werden zunachstLinux installiert und alle Programme und Dienste eingerichtet, die auch spater auf al-len diskless nodes laufen sollen. Ein Skript get golden image.sh holt ahnlichwie getimage von SystemImager alle Dateien des Knotens (golden node) und legtsie auf dem Server unter /nodes/golden image/ ab. Danach baut das Skriptbuild all.sh die Root-Verzeichnisse und legt verschiedene Konfigurationsdatei-en an. In den Listings 5.36 und 5.37 sind beide Programme abgedruckt.

Alle Skripten sind fur ein Debian GNU/Linux geschrieben. Fur andere Distri-butionen sind leichte Anpassungen notwendig. Schauen wir uns diese Programmegenauer an. Das Skript get golden image.sh liest zunachst die Konfigurati-onsdatei /etc/cluster/cluster.conf ein. Sie enthalt IP-Adressen, Dateina-

Page 143: [X.systems.press] Cluster Computing ||

5.8 Diskless nodes 135

Listing 5.35. Konfigurationsdatei fur die Skripten zur Erstellung der Root-NFS-Verzeichnisse.

NODES_DIR=/nodesGOLDEN_NODE=goldenGOLDEN_NODE_IP=192.168.0.253NETWORK_ADDRESS=192.168.0

5 SERVER_IP=$NETWORK_ADDRESS.254KERNEL_IMAGE=vmlinuz-2.4.22NODE_BASE_NAME=nodeDOMAIN=our-domain.orgSERVER=server

10 MAC_FILE=/etc/cluster/MAC.conf

Listing 5.36. Das Skript get golden image.sh holt alle fur die festplattenlosen Knotennotwendigen Dateien vom golden node.

# ! / b i n / bash

### K o n f i g u r a t i o n s d a t e n l e s e n ########################################. /etc/cluster/cluster.conf

5### V e r z e i c h n i s s e a n l e g e n ############################################mkdir -p $NODES_DIRmkdir -p $NODES_DIR/golden_image

10 ### D a t e i e n vom Golden−Node k o p i e r e n #################################rsync --rsh=ssh -auz --delete \

--include=/bin --include=/etc --include=/lib \--include=/root --include=/sbin --include=/usr \--include=/var \

15 --exclude=” / * / ” --exclude=” / vml inuz * ” --exclude=/lib/modules \$GOLDEN_NODE_IP:/ $NODES_DIR/golden_image

### D a t e i e n zum S e t z e n des Hostnamen e n t f e r n e n #######################rm -rf $NODES_DIR/golden_image/etc/init.d/hostname.sh

20 rm -rf $NODES_DIR/golden_image/etc/rcS.d/S40hostname.shrm -rf $NODES_DIR/golden_image/etc/hostname

### K o n f i g u r a t i o n s d a t e i d e r N e t z w e r k i n t e r f a c e s s c h r e i b e n #############cat <<EOF > $NODES_DIR/golden_image/etc/network/interfaces

25 auto loiface lo inet loopbackEOF

Listing 5.37. Das Skript build all.sh ruft alle weiteren Skripten zur Einrichtung festplat-tenloser Knoten auf.

# ! / b i n / bash

build_nfs_root.shbuild_etc_hosts.sh

5 build_etc_exports.shbuild_etc_dhcpd.conf.sh

Page 144: [X.systems.press] Cluster Computing ||

136 5 PCs vernetzen

men und andere Parameter, siehe Listing 5.35. Dann legt das Skript get goldenimage.sh auf dem Server die notwendigen Verzeichnisse an und kopiert mitrsync und ssh alle wichtigen Verzeichnisse vom golden node nach /nodes/golden image. Anschließend werden die Dateien geloscht, mit denen unter De-bian beim Systemstart normalerweise der Hostname gesetzt wird. Wir benotigen sienicht, da in der hier vorgestellten Konfiguration der Kernel sich den Hostnamen vomDHCP-Server holt. Außerdem wird vom Skript get golden image.sh die Kon-figurationsdatei der Netzwerkinterfaces uberschrieben. Sie enthalt nur die Konfigura-tionsdaten fur das Loopback-Device.

Das Skript build all.sh ruft lediglich einige weitere Skripten auf, sieheListing 5.37. Diese erzeugen nacheinander die Root-Verzeichnisse aller Knoten,legen die Konfigurationsdateien in /tftpboot/pxelinux.cfg sowie /etc/fstab, /etc/hosts, /etc/exports und /etc/dhcpd.conf an. Zuerstfuhrt build all.sh das Skript build nfs root.sh aus. Dieses liest die Konfi-gurationsdatei /etc/cluster/MAC.conf, die in jeder Zeile eine MAC-Adresseeiner Netzwerkkarte enthalt, ein und legt in einer Schleife uber alle MAC-Adressendie Root-Verzeichnisse an. Dabei werden auch die Datei /etc/fstab und eineKonfigurationsdatei im Verzeichnis /tftpboot/pxelinux.cfg angelegt. DieZeile

tmpfs /tmp tmpfs defaults,size=64m 0 0

in /etc/fstab sorgt dafur, dass die Knoten das Verzeichnis /tmp als tmpfs-Dateisystem einbinden und der Inhalt dieses Verzeichnisses auf maximal 64 MB be-schrankt bleibt.

Wahrend das Skript build nfs root.sh einige Dateien des Root-Verzeich-nisses aus dem Verzeichnis des golden node herauskopiert, werden andere nur leerangelegt und dienen spater als Mount-Point (z. B. /home oder /usr). Zum Kopie-ren der Dateien wird rsync statt cp verwendet. Dadurch werden keine Dateien ausdem golden image in ein Root-Verzeichnis kopiert, die dort schon so liegen. Wenndie Root-Verzeichnisse nicht ganz neu angelegt werden, ist die Verwendung vonrsync deutlich schneller. Außerdem loscht rsync alle nicht benotigten Dateien,die eventuell schon im Root-Verzeichnis liegen. Das /dev-Verzeichnis wird nichtvom golden node ubernommen. Es enthalt meist mehrere tausend Device-Dateien,von denen die meisten gar nicht benotigt werden. Das Skript build nfs root.shlegt darum ein leeres /dev-Verzeichnis an und erzeugt mit dem MAKEDEV-Skriptnur die unbedingt notwendigen Device-Dateien.

Das Skript build etc hosts.sh (siehe Listing 5.39) generiert die Datei/etc/hosts sowohl fur den Server als auch unter /nodes/node1 bis /nodes/node4 fur die compute nodes. Dazu durchlauft das Skript wieder eine Schleife uberalle Knoten (MAC-Adressen). Ganz ahnlich arbeitet auch build etc exports.sh (siehe Listing 5.40), das die Datei /etc/exports auf dem Server anlegt unddanach den NFS-Server neu startet. Das Skript build etc dhcpd.conf.sh er-zeugt schließlich die Konfigurationsdatei fur den DHCP-Server und startet auch ihnmit seiner neuen Konfigurationsdatei.

Page 145: [X.systems.press] Cluster Computing ||

5.8 Diskless nodes 137

Listing 5.38. Das Skript build nfs root.sh baut die Root-Dateisysteme der festplatten-losen Knoten.

# ! / b i n / bash#### NFS−Root−V e r z e i c h n i s s e a n l e g e n ###################################

5 . /etc/cluster/cluster.conf # K o n f i g u r a t i o n s d a t e n l e s e nNODE_NR=0for MAC in ‘cat $MAC_FILE‘; do

(( NODE_NR+=1 ))NODE_NAME=$NODE_BASE_NAME$NODE_NR

10 NODE_IP=$NETWORK_ADDRESS.$NODE_NRNFS_ROOT_DIR=$NODES_DIR/$NODE_NAMEecho ” Bu ld ing NFS−Root f o r node : $NODE NAME”# V e r z e i c h n i s s e k o p i e r e nmkdir -p $NFS_ROOT_DIR

15 rsync -auz --delete \$NODES_DIR/golden_image/bin $NODES_DIR/golden_image/etc \$NODES_DIR/golden_image/lib $NODES_DIR/golden_image/root \$NODES_DIR/golden_image/sbin $NODES_DIR/golden_image/var \$NFS_ROOT_DIR

20 # w e i t e r e V e r z e i c h n i s s e a n l e g e nmkdir -p $NFS_ROOT_DIR/procmkdir -p $NFS_ROOT_DIR/homemkdir -p $NFS_ROOT_DIR/tmpmkdir -p $NFS_ROOT_DIR/usr

25 mkdir -p $NFS_ROOT_DIR/dev( cd $NFS_ROOT_DIR/dev; MAKEDEV std console )# / e t c / f s t a b a n l e g e ncat << EOF > $NFS_ROOT_DIR/etc/fstab

$SERVER_IP:$NFS_ROOT_DIR / nfs defaults 0 030 tmpfs /tmp tmpfs defaults,size=64m 0 0

proc /proc proc defaults 0 0$SERVER_IP:$NODES_DIR/golden_image/usr /usr nfs defaults 0 0$SERVER_IP:/usr/local /usr/local nfs defaults 0 0$SERVER_IP:/home /home nfs defaults 0 0

35 EOF# K o n f i g u r a t i o n s d a t e i mi t B o o t p a r a m e t e r# i n / t f t p b o o t / p x e l i n u x . c f g a n l e g e nIP2NUM=’(((\1*256+\2)*256+\3)*256)+\4’NODE_IP_HEX=‘echo $NODE_IP | \

40 sed -e ” s /\ ( [ 0 −9 ] *\ ) .\ ( [ 0 −9 ] *\ ) .\ ( [ 0 −9 ] *\ ) .\ ( [ 0 −9 ] *\ ) / $IP2NUM / ” |\bc‘

NODE_IP_HEX=‘printf ”%008X” $NODE_IP_HEX‘mkdir -p /tftpboot/pxelinux.cfgcat <<EOF > /tftpboot/pxelinux.cfg/$NODE_IP_HEX

45 DEFAULT $KERNEL_IMAGEAPPEND root=/dev/nfs \nfsroot=$SERVER_IP:$NFS_ROOT_DIR,rsize=8192,rsize=8129,rw ip=dhcpEOFdone

Page 146: [X.systems.press] Cluster Computing ||

138 5 PCs vernetzen

Listing 5.39. Das Skript build etc hosts.sh legt die Datei /etc/hosts an.

# ! / b i n / bash#### / e t c / h o s t s a n l e g e n ##############################################

5 . /etc/cluster/cluster.conf # K o n f i g u r a t i o n s d a t e n l e s e necho Writing /etc/hosts(

cat <<EOF127.0.0.1 localhost

10 $SERVER_IP $SERVER.$DOMAIN $SERVER$GOLDEN_NODE_IP $GOLDEN_NODE.$DOMAIN $GOLDEN_NODEEOF

NODE_NR=0for MAC in ‘cat $MAC_FILE‘; do

15 (( NODE_NR+=1 ))NODE_NAME=$NODE_BASE_NAME$NODE_NRNODE_IP=$NETWORK_ADDRESS.$NODE_NRecho $NODE_IP $NODE_NAME.$DOMAIN $NODE_NAME

done20 ) > /etc/hosts

NODE_NR=0for MAC in ‘cat $MAC_FILE‘; do

(( NODE_NR+=1 ))NODE_NAME=$NODE_BASE_NAME$NODE_NR

25 NFS_ROOT_DIR=$NODES_DIR/$NODE_NAMEcp /etc/hosts $NFS_ROOT_DIR/etc/hosts

done

Listing 5.40. Das Skript build etc exports.sh generiert die Datei /etc/exports.

# ! / b i n / bash#### / e t c / e x p o r t s a n l e g e n #############################################

5 . /etc/cluster/cluster.conf # K o n f i g u r a t i o n s d a t e n l e s e necho Writing /etc/exports(

cat <<EOF/usr/local $NETWORK_ADDRESS.0/255.255.255.0(no_root_squash,ro)

10 /home $NETWORK_ADDRESS.0/255.255.255.0(rw)$NODES_DIR/golden_image/usr \$NETWORK_ADDRESS.0/255.255.255.0(no_root_squash,ro)EOF

NODE_NR=015 for MAC in ‘cat $MAC_FILE‘; do

(( NODE_NR+=1 ))NODE_NAME=$NODE_BASE_NAME$NODE_NRNFS_ROOT_DIR=$NODES_DIR/$NODE_NAMENODE_IP=$NETWORK_ADDRESS.$NODE_NR

20 echo ”$NFS ROOT DIR $NODE IP ( n o r o o t s q u a s h , rw ) ”done

) > /etc/exports# NFS−S e r v e r neu s t a r t e n/etc/init.d/nfs-kernel-server restart > /dev/null

Page 147: [X.systems.press] Cluster Computing ||

5.8 Diskless nodes 139

Listing 5.41. Durch das Skript build etc dhcpd.conf.sh wird die Konfigurationsdateides DHCP-Servers angelegt.

# ! / b i n / bash#### / e t c / dhcpd . con f a n l e g e n #########################################

5 . /etc/cluster/cluster.conf # K o n f i g u r a t i o n s d a t e n l e s e necho Writing /etc/dhcpd.conf(

cat <<EOFallow booting;

10 allow bootp;use-host-decl-names on;

subnet $NETWORK_ADDRESS.0 netmask 255.255.255.0 {

15 option domain-name ”$DOMAIN”;option broadcast-address $NETWORK_ADDRESS.255;option domain-name-servers $SERVER_IP;option routers $SERVER_IP;next-server $SERVER_IP;

20 filename ” p x e l i n u x . 0 ”;

EOFNODE_NR=0for MAC in ‘cat $MAC_FILE‘; do

25 (( NODE_NR+=1 ))NODE_NAME=$NODE_BASE_NAME$NODE_NRNFS_ROOT_DIR=$NODES_DIR/$NODE_NAMENODE_IP=$NETWORK_ADDRESS.$NODE_NRcat <<EOF

30 host $NODE_NAME {hardware ethernet $MAC;fixed-address $NODE_IP;

}EOF

35 donecat <<EOF

}EOF

40 ) > /etc/dhcpd.conf# DHCP−S e r v e r neu s t a r t e n/etc/init.d/dhcp restart > /dev/null

5.8.5 Alternativen und weitere Quellen

Die hier vorgestellten Skripten sind sicher an vielen Stellen verbesserungswurdigund bedurfen bei der Verwendung einer anderen Distribution als Debian GNU/Li-nux einiger Anpassungen. Sie zeigen aber das grundsatzliche Funktionsprinzip undkonnen als Ausgangspunkt fur eigene Entwicklungen dienen. Leider sind Cluster mitfestplattenlosen Knoten innerhalb der Linux-Gemeinde noch ein eher stiefmutterlichbehandeltes Thema. Bleibt zu hoffen, dass sich dies in Zukunft andert. Ein erster An-satz in diese Richtung konnte Thin-OSCAR [128] sein, siehe Abschnitt 6.3.1. Auch

Page 148: [X.systems.press] Cluster Computing ||

140 5 PCs vernetzen

mit der Infrastruktur des Linux Terminal Server Project [97] lasst sich ein Clustermit diskless nodes aufbauen.

Zahlreiche weitere Tipps zu diskless nodes finden Sie in den Artikeln

• ”Root over nfs clients & server Howto“ [53],• ”Root over NFS – Another Approach“ [54],• ”Network Boot and Exotic Root HOWTO“ [76] und• ”Remote Linux Explained“ [37].

Falls Sie altere Netzwerkkarten ohne PXE-Boot-ROM verwenden mochten, so sinddie beiden Projekte Etherboot [36] und Netboot [112] fur Sie sicher interessant. Mitihnen konnen individuelle Boot-ROMs fur verschiedene Netzwerkkarten erstellt wer-den. Dazu wird allerdings ein EPROM-Brenner benotigt.

5.9 Notizen

5.1 Literatur. Die in diesem Kapitel dargestellten Techniken sind auch Thema vielerBucher zur Systemadministration unter Linux. Sollten Sie weiterfuhrende Informa-tionen benotigen, finden Sie diese in [87, 46, 83] oder anderen Buchern.

5.2 Sicherheit. Aus Platzgrunden mussten wir das Thema Sicherheit auf ein absolu-tes Minimum beschranken. Beachten Sie aber, dass alle Knoten Ihres Clusters, dieeine direkte Verbindung zum Internet haben, auch direkt allen damit verbundenenGefahren ausgesetzt sind. Das regelmaßige Einspielen von Sicherheitsupdates, dasLesen der Sicherheits-Mailing-Listen der eingesetzten Distribution und das Anlegenvon Backups gehoren zum Pflichtprogramm eines jeden Cluster-Administrators.

5.3 Hardware fur TCP/IP. TCP/IP kann heute auf einer erstaunlich breiten Palettevon Hardwarearchitekturen betrieben werden. RFC 1149 beschreibt, wie das InternetProtocol mit Brieftauben verwirklicht werden kann. Obwohl dieses RFC an einem1. April erschien, wurde es mittlerweile auch von der Linux-Gruppe in Bergen im-plementiert. Die durchschnittliche Antwortzeit eines Pings betrug 45 Minuten.

5.4 Linux-Distributionen. Die Frage nach der besten Linux-Distribution wird gernmit fast schon religiosem Eifer diskutiert. Die Autoren dieses Buches praferierenDebian GNU/Linux, weil sich diese Distribution als besonders stabil, zuverlassigund gut zu administrieren erwiesen hat.

5.5 Journaling-Dateisysteme. Neben dem Journal, mit dem das Dateisystem immerin einem konsistenten Zustand gehalten wird, verfugen moderne Journaling-Datei-systeme uber weitere Merkmale, die sie von einfacheren Dateisystemen unterschei-den. Zum Beispiel speichern sie Daten in baumartigen Strukturen statt in Listen ab(positiv fur große Verzeichnisse). Außerdem konnen Dateien erweiterte Attribute(ACLs) zugewiesen werden. Die Entwicklung der Journaling-Dateisysteme fur Li-nux ist noch immer sehr dynamisch.

Page 149: [X.systems.press] Cluster Computing ||

5.9 Notizen 141

5.6 Interface-Namen. Die symbolischen Interface-Namen eth0, eth1 usw. werdennormalerweise von Linux automatisch vergeben. Ist mehr als eine Ethernetkarte ineinem Knoten vorhanden, so lasst sich allerdings nicht a priori, sagen welche derKarten den Namen eth0, eth1 usw. bekommt. Angenommen Sie haben einen Clustermit heterogener Hardware, in dem jeder Knoten eine Fast-Ethernet- und eine Gigabit-Ethernet-Karte hat. Da ist es sehr wahrscheinlich, dass Linux auf einigen Knoten dieFast-Ethernet-Karte als eth0 und die Gigabit-Ethernet-Karte als eth1 bezeichnet, undauf anderen Knoten die Interface-Namen gerade andersherum vergibt. Soll die Be-zeichnung der Interfaces im ganzen Cluster einheitlich sein, so konnen Sie dies mitdem Programm nameif erreichen. Tragen Sie dazu in die Datei /etc/mactabInterface-Namen und MAC-Adresse der betreffenden Karten ein und rufen Sie dasProgramm nameif auf, bevor die Interfaces mit ifconfig konfiguriert werden.

Mit dem Programm ifrename lassen sich auch Interfaces umbenennen. NebenMAC-Adressen konnen hier auch andere Kriterien (wie z. B. der verwendete Treiber)zur Namenszuweisung herangezogen werden.

Listing 5.42. Die Datei /etc/mactab verknupft MAC-Adressen und Interface-Namen.eth0 10:10:10:10:10:10 # Gigabit Etherneteth1 20:20:20:20:20:20 # Fast Ethernet

5.7 Swapping uber NFS. Diskless nodes konnen normalerweise keinen Speicherauf eine Swap-Partition auslagern. Deshalb sollte ihr Arbeitsspeicher großzugig be-messen sein. Falls der Arbeitsspeicher aber doch einmal knapp werden sollte, kannunter Linux auf uber NFS geswappt werden. Den dafur notigen Kernel-Patch gibtes unter [115]. Allerdings durfte die Performance dieser Losung in den allermeistenFallen eher unbefriedigend sein.

5.8 Cluster Command and Control. Neben der in Abschnitt 5.6.3 vorgestelltenDistributed Shell gibt es noch eine Reihe weiterer Werkzeuge mit vergleichbarerFunktionalitat. Zu den popularsten Programmen dieser Art durfte wohl Cluster Com-mand and Control [15], kurz C3 genannt, gehoren. C3 besteht aus mehreren Pro-grammen, mit denen auf allen Knoten eines Clusters ein Kommando ausgefuhrt oderein Prozess beendet werden kann. Außerdem lassen sich Dateien von allen Knoteneinsammeln oder auf alle Knoten verteilen. Da C3 alle Aktionen gleichzeitig (nichtnacheinander) auf mehreren Knoten durchfuhrt, ist es auch fur großere Cluster geeig-net.

5.9 Channel bonding. Mit channel bonding kann nicht nur die Bandbreite verschie-dener Netzwerkkarten zusammengefasst werden. Es existieren auch Modi mit denenSie hochverfugbare Netzwerkkonfigurationen aufbauen konnen. Der Artikel [174]beleuchtet diese Moglichkeit genauer.

5.10 BOOTP und RARP. Neben DHCP konnen auch BOOTP und RARP einemComputer eine IP-Adresse und eine Reihe weiterer Parameter zuweisen. DHCP isteine Weiterentwicklung dieser beiden Protokolle. Sollten Sie aus irgendeinem Grun-de das veraltete BOOTP verwenden mussen, so finden Sie in [69] alle notwendigenInformationen.

Page 150: [X.systems.press] Cluster Computing ||

6

Cluster-Dienste

batch: adj.

[. . . ]2. Performance of dreary tasks all at one sitting. “I finally satdown in batch mode and wrote out checks for all those bills; Iguess they’ll turn the electricity back on next week . . . ”

The Jargon File

Im vorherigen Kapitel wurden elementare Dienste und Programme beschrieben, diein fast jedem Netz von Linux-PCs benotigt werden. Ein Cluster-Computer ist jedochweit mehr als ein Netz von Linux-PCs. Erst spezielle Cluster-Dienste machen ausvernetzten PCs einen Cluster. Zu diesen Cluster-Diensten gehoren insbesondere

• Message-Passing-Bibliotheken,• ein Batch-System und• ein Cluster-Management-System.

In diesem Kapitel erfahren Sie, wie aus Ihrem Netz von Linux-PCs ein echter Cluster-Computer wird.

6.1 LAM/MPI

Auf Cluster-Computern kommunizieren parallele Programme durch Nachrichtenaus-tausch. Jedes parallele Programm benotigt also Funktionen zum Senden und Emp-fangen von Daten. Damit ein Anwendungsprogrammierer diese Funktionen nichtjedesmal neu schreiben muss, verwendet er dafur spezielle Nachrichtenaustausch-Bibliotheken. Meist handelt es sich dabei um eine Implementation des Message Pas-sing Interface Standards. Wie Sie mit diesem Standard eigene Programme schreiben,erfahren Sie im Teil III dieses Buches.

Der MPI-Standard [59] legt nur Syntax und Semantik von Schnittstellen zuden Programmiersprachen C, C++ und FORTRAN fest. Es existieren diverse Im-plementierungen des MPI-Standards fur eine große Zahl von Hardware-Plattformen.Fast jeder Super-Computer-Hersteller hat heute eine auf seine Hardware optimierteMPI-Implementation im Angebot. Daneben gibt es einige Implementationen von un-abhangigen Anbietern. Zu den am haufigsten eingesetzten MPI-Implementationen

Page 151: [X.systems.press] Cluster Computing ||

144 6 Cluster-Dienste

gehoren u. a. MPICH, LAM/MPI, MPICH-GM, Scali MPI Connect, MPI/Pro unddie Intel MPI Library.

MPICH und MPICH2. MPICH [107] ist eine am Argonne National Laboratoryentwickelte freie MPI-Implementation und MPICH2 eine vollstandige Neuent-wicklung vom gleichen Team. Viele andere MPI-Implementationen bauen aufMPICH auf. Die neueste Version von MPICH2 unterstutzt neben TCP/IP-Netzenauch InfiniBand [108].

LAM/MPI. Die Abkurzung LAM steht fur Local Area Multicomputer. Die freieLAM/MPI-Implementation [89] unterstutzt Nachrichtenaustausch uber TCP/IP-Netze, Myrinet und InfiniBand. Daneben gibt es unter [35] eine Erweiterung furLAM/MPI, die den TCP/IP-Stack umgeht und die Ethernethardware uber dasVIA-Protokoll ansteuert und so kleinere Latenzen erreicht.

MPICH-GM. MPICH-GM ist die auf MPICH basierende MPI-Implementation vonMyricom fur Myrinet. Myricom vertreibt außerdem eine eigene auf Myrinet opti-mierte Implementation der Message-Passing-Bibliothek PVM, siehe auch [110]und [137].

MPICH G2. Hierbei handelt es sich um einen weiteren Abkommling von MPICH.Mit MPICH G2 konnen Sie MPI-Programme nicht nur verteilt auf den Knoteneines Clusters sondern verteilt auf den Knoten mehrerer Cluster laufen lassen.Bei einem solchen Cluster-Verbund spricht man auch von einem Grid, sieheAbschnitt 2.4. Da die gekoppelten Cluster auf ganz verschiedenen Netzwerk-techniken beruhen konnen und meist uber offentliche, d. h. unsichere Netze ver-bunden sind, stellt Grid-Computing hohe Anforderungen an Sicherheit und In-teroperabilitat. MPICH G2 setzt darum auf dem Globus Toolkit [51] auf, dasdie Unterschiede zwischen den verschiedenen Clustern wegabstrahiert und sichz. B. um die Authentifikation kummert. Da die Bandbreite des Netzwerkes zwi-schen den Clustern meist deutlich geringer ist als innerhalb eines Clusters, kannMPICH G2 Informationen uber die Topologie des Cluster-Verbundes nutzen, umkollektive Kommunikationsoperationen zu optimieren. Auch ist es moglich, in-nerhalb eines Clusters eine auf die jeweilige Hardware optimierte MPI-Versioneinzusetzen. In solch einem Fall wickelt MPICH G2 lediglich die Inter-Cluster-Kommunikation ab. MPICH G2 unterstutzt nur MPI-1.1, siehe Abschnitt 7.6.1.

Scali MPI Connect. Dies ist eine von Scali [147] kommerziell vertriebene MPI-Implementationen, die TCP/IP-, Ethernet-, SCI-, Myrinet- und InfiniBand-Netz-werke unterstutzt.

MPI/Pro und ChaMPIon/Pro. MPI/Pro [109] und ChaMPIon/Pro [16] sind zweiweitere kommerzielle MPI-Implementation. ChaMPIon/Pro hat im Vergleichzu MPI/Pro einen großeren Funktionsumfang, lauft aber nur unter Linux undMac OS X, wahrend MPI/Pro auch Windows unterstutzt. Beide Implementatio-nen kosten pro CPU zwar einen dreistelligen Dollarbetrag, dafur kann speziellChaMPIon/Pro mit einer ganzen Reihe von Funktionen aufwarten. Es unterstutztKommunikation via TCP/IP, shared memory, Myrinet, InfiniBand und Quadrics.Diese MPI-Implementation ist multithreaded, wodurch Kommunikation und Be-rechnung von einem MPI-Programm gleichzeitig abgewickelt konnen. Außer-

Page 152: [X.systems.press] Cluster Computing ||

6.1 LAM/MPI 145

dem implementiert diese Bibliothek laut Hersteller den vollstandigen MPI-2-Standard, siehe Abschnitt 7.6.1.

Intel MPI Library. Bei der Intel MPI Library [72] handelt es sich um eine rechtneue, auf MPICH2 basierende kommerzielle MPI-Implementation. Zu den High-lights dieser Bibliothek durfte die Unterstutzung fur InfiniBand gehoren.

Wir haben versucht, samtliche Programm- und Anwendungsbeispiele, die Sie in die-sem Buch finden, weitestgehend unabhangig von der verwendeten MPI-Implemen-tation zu halten. Wo dies nicht moglich war, setzen wir LAM/MPI voraus. MehrereGrunde sprechen fur LAM/MPI.

• LAM/MPI ist Open-Source-Software.• LAM/MPI ist sehr stabil und performant.• LAM/MPI implementiert den Standard MPI-1 vollstandig und den Standard

MPI-2 fast vollstandig. Lediglich einige eher exotische Funktionen aus MPI-2fehlen.

• LAM/MPI stellt eine komfortable Laufzeitumgebung zur Verfugung, in der MPI-Anwendungen kompiliert und ausgefuhrt werden konnen.

• Das LAM/MPI-Entwicklerteam ist sehr aktiv. LAM/MPI wird kontinuierlich wei-terentwickelt und regelmaßig erscheinen neue Releases. Anfragen an die Mai-linglisten des Projektes werden schnell und kompetent beantwortet. Die aktiveNutzer- und Entwicklergemeinde ist eines der starksten Argumente fur dieseMPI-Implementation.

6.1.1 Installation

LAM/MPI ist mittlerweile Bestandteil der meisten Linux-Distributionen. Allerdingsentwickelt es sich so rasant, dass die von den Distributionen ausgelieferte Versio-nen oft schon recht alt sind. Außerdem kompilieren die Distributoren LAM/MPI mitOptionen, die gewahrleisten, dass es auf moglichst vielen Clustern lauft. Diese Op-tionen sind aber unter Performanceaspekten selten optimal. Auch kann es sein, dassHochgeschwindigkeitsnetzwerke wie Myrinet nicht unterstutzt werden. Daher ist esangebracht, sich von [89] die neueste Version von LAM/MPI zu besorgen und selbstzu kompilieren.

Dem Quellpaket liegt eine ausfuhrliche Dokumentation bei, die auch die Uberset-zung von LAM/MPI beschreibt. Fur ganz Ungeduldige hier eine Kurzbeschreibung.Zunachst ist das Quellpaket z. B. unter /usr/local/src zu entpacken. Danachwerden mit dem configure-Skript die Makefiles erstellt. Uber die Umgebungs-variablen CC, CXX und FC konnen Sie explizit bestimmte Compiler auswahlen. Inunserem Beispiel ubersetzen wir LAM/MPI mit Compilern von Intel und Trillium-Unterstutzung. Zum Starten von MPI-Programmen auf anderen Rechnern soll SSHverwendet werden. Die Trillium-Unterstutzung wird fur einige Programme von Dritt-anbietern benotigt, z. B. xmpi (siehe Abschnitt 10.4).

Page 153: [X.systems.press] Cluster Computing ||

146 6 Cluster-Dienste

root@server:/usr/local/src/lam-7.0.6# CC=icc; CXX=icc; FC=ifortroot@server:/usr/local/src/lam-7.0.6# export CC CXX FCroot@server:/usr/local/src/lam-7.0.6# ./configure --with-trillium \> --with-rsh=ssh

Das Programm configure erzeugt eine Reihe von Makefiles, die dafur sorgen,dass LAM/MPI durch das Kommando make mit den ausgewahlten Compilern uber-setzt und mit make install im Verzeichnisbaum unter /usr/local installiertwerden kann.

Seit der Version 7.0 besteht die Laufzeitumgebung aus verschiedenen Modulen,die zur Laufzeit ausgewahlt und konfiguriert werden konnen. Die Module diesesSystem Services Interface (kurz SSI) genannten Systems regeln z. B., wie Prozessegestartet werden oder uber welche Protokolle sie kommunizieren. Das Konfigura-tionsskript schaut sich auf dem Rechner nach einigen Bibliotheken zur Ansteuerungspezieller Hocheschwindigkeitsnetzwerke (wie Myrinet oder InfiniBand) oder zumCheckpointing um und baut entsprechende Funktionalitat in Form eines SSI-ModulsLAM/MPI ein. Nach der Installation informaiert Sie das Programm laminfo uberalle tatsachlich vorhandenen Module. In Terminal Session 13.1 sehen Sie verschie-dene Arten von Module.

boot. Die Module der Kategorie boot regeln, wie das LAM-Universum getartet wird,siehe unten.

coll. Der MPI-Standard definiert verschiedene kolletive Kommunikationsoperation-en und deren Wirkung, siehe Abschnitt 7.3. Er schreibt jedoch nicht vor, wiediese zu implementieren sind. Stattdessen kann eine MPI-Bibliothek eine fur dietatsachlich verwendete Hardware optimierte Implementation kollektiver Kom-munikationsoperationen verwenden. Die Kategorie coll enthalt Module, die kol-lektive Kommunikationsoperationen auf verschiedener Hardware ausfuhren.

rpi. Das Request Progression Interface (RPI) wickelt alle grundlegenden Kommuni-kationsoperationen ab. Je nach Hardware existieren verschiedene Module.tcp. Kommunikation uber ein TCP/IP-Netzgm. Myrinetib. InfiniBandsysv und usysv. fur Cluster mit SMP-Knoten, knotenintern Kommunikation

uber shared memory, sonst uber TCP/IPlamd. Kommunikation uber LAM/MPI-Damoncrtcp. wie tcp, jedoch checkpointfahig, siehe Abschitt 13.3

cr. Hierbei handelt es sich um Module fur das Checkpointing, siehe Abschitt 13.3.

Die verschieden Module konnen vom Nutzer manuell ausgewahlt werden. Norma-lerweise erkennt LAM/MPI jedoch in Abhangigkeit von der verwendeten Hardwareselbstandig, welche Module zu verwenden sind. Falls Sie einen Cluster mit Myrinetoder InfiniBand haben, beachten Sie, dass auf dem Computer auf dem LAM/MPIubersetzt wird, selbst keine Myrinet- bzw. InfiniBand-Hardware haben muss. ZumUberstzen von LAM/MPI reicht es aus, wenn entsprechende Bibliotheken installiertsind.

Page 154: [X.systems.press] Cluster Computing ||

6.1 LAM/MPI 147

Listing 6.1. Ein Beispiel fur ein Bootschema /usr/local/etc/lam-bhost.def.

server.our-domain.org schedule=nonode1.our-domain.orgnode2.our-domain.orgnode3.our-domain.org cpu=2

5 node4.our-domain.org cpu=2

Zum Starten von MPI-Programmen und zum Teil auch fur deren Kommunikati-on untereinander wird bei LAM/MPI ein Damon verwendet, der auf allen Knotengestartet werden muss. Jeder Nutzer, der MPI-Programme ausfuhren mochte, mussseine eigenen Damonen starten. In der Konfigurationsdatei /usr/local/etc/lam-bhost.def wird eine Liste der Knoten, auf denen der LAM-Damon stan-dardmaßig gestartet werden soll, vermerkt. Im LAM/MPI-Jargon heißt eine solcheDatei Bootschema. Beispielhaft ist in Listing 6.1 eine solches Bootschema darge-stellt. Hier haben wir angenommen, dass Knoten node3 und node4 SMP-Maschinenmit je zwei CPUs sind und alle anderen Computer nur eine CPU haben. Die Optioncpu sagt aber nicht zwingend etwas uber die auf einem Knoten physisch vorhande-nen CPUs aus, jedoch beeinflusst sie, wieviele Prozesse von LAM/MPI auf einemKnoten gestartet werden. Mit der Option schedule=no in der ersten Zeile bewir-ken wir, dass auf dem Server zwar der LAM-Damon gestartet wird, jedoch nie MPI-Anwendungen laufen. Auf dem Server wird der LAM/MPI-Damon lediglich zumStarten von MPI-Programmen benotigt. Mit dieser Konfiguration mussen sich dieNutzer zum Starten von MPI-Programmen nie auf einem der compute nodes einlog-gen.

Wenn Sie das Verzeichnis /usr/local, in das LAM/MPI normalerweise in-stalliert wird, clusterweit an alle Knoten exportieren, ist die LAM/MPI-Installa-tion auch schon vollstandig. Unter Umstanden muss noch auf jedem Knoten in/etc/ld.so.conf das Verzeichnis /usr/local/lib eingetragen und dasProgramm ldconfig aufgerufen werden, sonst findet der Linker die LAM/MPI-Bibliotheken nicht.

Wenn Sie sichergehen wollen, dass Ihre LAM/MPI-Installation tatsachlich kor-rekt arbeitet, konnen Sie diese mit einem Paket von Testprogrammen auf Herz undNieren testen. Diese Programme finden Sie auch auf den LAM/MPI-Webseiten [89].

6.1.2 MPI-Programme kompilieren und starten

Der Kern der LAM/MPI-Software ist naturlich die Implementierung des MPI-Stan-dards. Um die MPI-Bibliothek von LAM/MPI fur Ihre Anwendungen nutzen zukonnen, mussen Sie dem Compiler und dem Linker mitteilen, wo die notwendigenHeaderdateien und Bibliotheken zu finden sind. Sparen konnen Sie sich diese An-gaben, wenn Sie die von LAM/MPI mitgelieferten Wrapper-Compiler mpicc (furC), mpiCC (fur C++) bzw. mpif77 (fur FORTRAN 77) verwenden. Das MPI-Pro-gramm mpiint.c in Listing 3.2 aus Abschnitt 3.3 zur numerischen Integrationkonnen Sie z. B. mit

Page 155: [X.systems.press] Cluster Computing ||

148 6 Cluster-Dienste

bauke@server:˜/$ mpicc -o mpiint mpiint.c pintegral.c -lm

ubersetzen. Die MPI-Compiler heißen Wrapper-Compiler, weil sie selbst gar keineechten Compiler sind, sondern nur andere Compiler mit zusatzlichen Optionen auf-rufen. Die Option -showme veranlasst die Wrapper-Compiler anzuzeigen, wie siediesen anderen Compiler aufrufen.

bauke@server:˜/$ mpicc --showme -o mpiint mpiint.c pintegral.c -lmicc -I/usr/local/include -pthread -o mpiint mpiint.c pintegral.c -lm-L/usr/local/lib -llammpio -llamf77mpi -lmpi -llam -lutil

Sie sehen, hinter mpicc verbirgt sich der Intel-C-Compiler und es werden beimUbersetzen von MPI-Programmen etliche Bibliotheken hinzugelinkt.

Bevor ein Nutzer des Clusters MPI-Programme starten kann, muss er erst nochmit dem lamboot-Kommando die LAM/MPI-Damonen starten und den LAM/MPI-Multicomputer ”booten“, siehe Terminal Session 6.1. Dazu greift das Programmlamboot (normalerweise) auf die Programme rsh oder ssh zuruck. Es kann al-so nur dann den LAM/MPI-Multicomputer erfolgreich starten, wenn Sie gemaß Ab-schnitt 5.6.3 die Berkeley-r-Kommandos bzw. die Secure Shell so eingerichtet haben,dass man sich ohne ein Passwort einzugeben, von Knoten zu Knoten bewegen kann.

Das Programm lamnodes erteilt Auskunft uber alle Knoten, auf denen einLAM-Damon lauft. Die erste Spalte der Ausgabe von lamnodes zeigt den Knoten-namen an, unter dem LAM/MPI einen Host identifiziert, siehe Terminal Session 6.1.In der zweiten Spalte stehen durch Doppelpunkte getrennt der Hostname, Zahl derCPUs sowie weitere Charakteristika, die zum Teil aus dem Bootschema stammen.In obigem Beispiel bedeuten origin und this node, dass die LAM/MPI-Damo-nen vom Knoten server aus gestartet wurden, bzw. dass lamnodes auf dem Knotenserver aufgerufen wurde. Benotigen Sie die LAM/MPI-Damonen spater nicht mehr,so konnen Sie diese mit lamhalt stoppen.

Sollte das lamboot-Kommando fehlschlagen, so uberprufen Sie zuerst die fol-genden Punkte:

Terminal Session 6.1. Bevor MPI-Programme ausgefuhrt werden konnen, muss mit dem Pro-gramm lamboot der LAM/MPI-Multicomputer gestartet werden.bauke@server:˜/$ lamboot -v

LAM 7.0.6/MPI 2 C++/ROMIO - Indiana University

n-1<11601> ssi:boot:base:linear: booting n0 (server)n-1<11601> ssi:boot:base:linear: booting n1 (node1)n-1<11601> ssi:boot:base:linear: booting n2 (node2)n-1<11601> ssi:boot:base:linear: booting n3 (node3)n-1<11601> ssi:boot:base:linear: booting n4 (node4)n-1<11601> ssi:boot:base:linear: finishedbauke@server:˜/$ lamnodesn0 server:1:no_schedule,origin,this_noden1 node1:1:n2 node2:1:n3 node3:2:n4 node4:2:

Page 156: [X.systems.press] Cluster Computing ||

6.1 LAM/MPI 149

Tabelle 6.1. LAM/MPI-Programme im Uberblick.

Programme Funktion

lamboot LAM-Universum startenlamshrink LAM-Universum schrumpfenlamgrow LAM-Universum vergroßernlamhalt LAM-Universum stoppenlamwipe LAM-Universum stoppen∗laminfo Informationen uber LAM-Konfiguration ausgeben†

lamnodes Informationen uber LAM-Knoten ausgebenlamclean LAM-System aufraumenlamexec Nicht-MPI-Programm auf LAM-Knoten startenmpicc C-Wrapper-CompilermpiCC C++-Wrapper-Compilermpic++ Synonym fur mpiCCmpif77 FORTRAN-Wrapper-Compilermpirun MPI-Programm auf LAM-Knoten startenmpiexec MPI-Programm auf LAM-Knoten starten‡

mpitask MPI-Programm uberwachen∗

Langsam und benotigt Bootschema, funktioniert aber noch,falls lamhalt mal versagt.

†Siehe auch Terminal Session 13.1.

‡Falls notwendig wird das LAM-Universum vorher gestartet.mpiexec ist ein Vorschlag fur einen Startmechanismus furMPI-Programme aus dem MPI-II-Standard.

• Sind alle Knoten uber das Netz erreichbar?• Konnen auf den Knoten mit rsh bzw. ssh Kommandos ausgefuhrt werden, oh-

ne dass der Nutzer dabei ein Passwort eingeben muss? Wenn nicht, lesen Sienoch einmal in Abschnitt 5.6.3 nach.

• Landen beim Ausfuhren von Kommandos mit rsh bzw. ssh außer den Resul-taten des gestarteten Programms weitere Ausgaben auf dem Terminal? Wenn ja,unterbinden Sie diese.

• Enthalt die $PATH-Umgebungsvariable auf allen Knoten das Verzeichnis mitden LAM/MPI-Programmen?

Zu LAM/MPI gehort das Programm recon, das bei der Suche nach der Problem-ursache hilft und obige Punkte uberpruft. Lauft recon ohne Fehlermeldungen, solasst sich in den allermeisten Fallen auch lamboot erfolgreich ausfuhren. Solltedas Programm lamboot daran scheitern, dass es zum Starten der LAM/MPI-Damo-ne rsh verwendet, Sie aber stattdessen die sicherere Alternative ssh eingerichtethaben, so legen Sie entweder an geeigneter Stelle einen symbolischen Link rsh an,der auf ssh zeigt, oder teilen Sie lamboot explizit mit, dass Sie die Secure Shellverwenden wollen.

bauke@server:˜/$ lamboot -v -ssi boot rsh -ssi rsh_agent ssh

Page 157: [X.systems.press] Cluster Computing ||

150 6 Cluster-Dienste

Wenn auf jedem Knoten ein LAM/MPI-Damon lauft, so kann mit mpirun einMPI-Programm gestartet werden. Dazu benotigt mpirun drei Angaben:

• die Knoten, auf denen das MPI-Programm gestartet werden soll,• das zu startende MPI-Programm und• die Argumente, die dem MPI-Programm ubergeben werden sollen.

Eine Menge von Knoten- bzw. CPU-Schlussel bestimmt, wo LAM/MPI ein MPI-Programm startet. Der Knotenschlussel N steht fur alle Knoten, n gefolgt von einerKnotennummer bzw. einem Bereich von Knotennummern, steht fur einen bestimm-ten Knoten bzw. einen Bereich von Knoten (siehe Ausgabe von lamnodes in Ter-minal Session 6.1). Die Schlussel C und c haben ahnliche Bedeutung wie N und n,nur beziehen sie sich auf CPUs. Einige Beispiele: Mit

bauke@server:˜/$ mpirun N mpiint 1000

wird auf jedem Knoten ein Prozess des Programms mpiint mit dem Argument1000 gestartet, also mit dem oben gezeigten Hostschema insgesamt vier Prozesse.Hingegen werden durch

bauke@server:˜/$ mpirun C mpiint 1000

insgesamt sechs Prozesse gestartet, da zwei der vier Knoten SMP-Systeme mit jezwei CPUs sind. Das Kommando

bauke@server:˜/$ mpirun n1,1-4 mpiint 1000

veranlasst LAM/MPI, auf node1 zwei Prozesse und auf den anderen Knoten je einProzess zu starten. Diese Beispiele setzen voraus, dass das Programm mpiint aufjedem Knoten im Heimatverzeichnis des Nutzers liegt. Am einfachsten lasst sichdiese Bedingung erfullen, wenn das Heimatverzeichnis als ein Netzwerkdateisystemeingebunden wird, siehe Abschnitt 5.6.1. Alternativ kann LAM/MPI durch die Opti-on -s auch angewiesen werden, das Programm von einem Knoten auf die anderenzu ubertragen.

Weitere Beispiele finden Sie in der Manpage mpirun(1). Außerdem wird dortbeschrieben, wie MPI-Programme durch ein sog. Applikations-Schema gestartet wer-den. Ein solches Applikations-Schema erlaubt eine noch großere Kontrolle uber denStartprozess, z. B. konnen verschiedene Binaries auf verschiedenen Knoten gestartetwerden. Dies kann notwendig sein, falls sich die Architekturen der Knoten unter-scheiden oder das Programm nicht dem SIMD-Paradigma (siehe Seite 170) folgt.

Zu LAM/MPI gehoren noch weitere Programme zum Ubersetzen und Ausfuhrenvon MPI-Programmen. Einen Uberblick uber die wichtigsten LAM/MPI-Programmegibt Tabelle 6.1. Eine ausfuhrliche Beschreibung dieser Werkzuge finden Sie in denentsprechenden Manpages bzw. der LAM/MPI-Dokumentation.

Page 158: [X.systems.press] Cluster Computing ||

6.2 Jobverwaltung und Batch-Systeme 151

6.2 Jobverwaltung und Batch-Systeme

Wenn Sie die in den vorherigen Abschnitten beschriebenen Konfigurationsschritteauf Ihren Cluster angewendet haben, haben Sie schon eine ganze Menge Arbeitinvestiert. Die Nutzer haben ein clusterweites einheitliches Heimatverzeichnis undkonnen sich ohne Passwortabfrage auf andere Knoten einloggen und dort mit rshoder ssh sequentielle Programme starten. Dank LAM/MPI fuhrt der Cluster sogarparallele MPI-Programme aus. Der Cluster ist nun schon ganz gut geeignet, um ersteErfahrungen im Cluster-Computing zu sammeln.

Wenn der Cluster aber in seinem jetzigen Zustand einer großeren Nutzergemein-de ubergeben wird, so wird bald Chaos ausbrechen. Viele Nutzer werden den neuenNumber-Cruncher gleichzeitig mit ihren Programmen futtern und sich dabei zumin-dest zeitweise gegenseitig behindern. Nachts hat der Cluster moglicherweise hinge-gen nichts zu tun. Sie brauchen noch ein Werkzeug, das hilft, Ordnung ins Chaos zubringen. Sie brauchen ein Batch-System.

6.2.1 Funktionsweise

Aufgabe eines Batch-Systems ist es, Auftrage von Nutzern fur rechenintensive Pro-gramme (Jobs) anzunehmen und, sobald geeignete Ressourcen auf dem Cluster freisind, diese auf einem oder mehreren Knoten des Clusters zu starten. Mit einem Batch-System konnen Sie Ihren Cluster kontinuierlich stark auslasten ohne dabei Uberlas-ten zu erzeugen. Ein Batch-System kann auch dabei helfen, eine gewisse Gerechtig-keit zwischen den Nutzern herzustellen.

Eine kleine Analogie aus der Bankenwelt soll helfen, die Funktionweise einesBatch-Systems zu verstehen. In der Schalterhalle einer (altmodischen) Bank wartenzahlreiche Kunden. Jeder dieser Kunden mochte eine andere Dienstleistung in An-spruch nehmen. Ein Kunde mochte eine Uberweisung tatigen, ein anderer sich Geldauszahlen lassen, ein weiterer Kunde hat einen Termin fur ein Beratungsgesprachmit seinem Kundenberater. An den Schaltern werden unterschiedliche Dienste an-geboten. An einigen Schaltern konnen alle moglichen Bankgeschafte abgewickeltwerden, am Expressschalter werden nur Auszahlungen getatigt und ein Schalter istbesonders wichtigen Kunden mit einer gewissen Mindestanlage vorbehalten.

Wurde ein Batch-System die Schalterhalle verwalten, so liefe dies in etwa wiefolgt ab:

• Wenn ein Kunde die Schalterhalle betritt, so muss er sich ausweisen und angeben,welche Art von Bankgeschaft er tatigen mochte. Das Batch-System vermerkt die-se Angaben zusammen mit dem Zeitpunkt, an dem der Kunde die Bank betrat.

• Jedem Kunden wird eine Prioritat zugewiesen. Je langer der Kunde schon wartet,desto hoher seine Prioritat. Aber auch personliche Merkmale konnen seine Prio-ritat beeinflussen. Zum Beispiel konnte eine Bank Geschaftskunden eine hoherePrioritat als Privatkunden einraumen.

• Sobald ein Schalter frei ist, wird ihm vom Batch-System der Kunde mit dergroßten Prioritat zugewiesen, dessen Bedurfnissen der Schalter gerecht wird.

Page 159: [X.systems.press] Cluster Computing ||

152 6 Cluster-Dienste

In dieser Analogie entsprechen die Kunden den Jobs und die Schalter den Knoteneines Clusters. Die Jobs konnen verschiedene Anspruche an Arbeitspeicher, Anzahlder CPUs oder andere Merkmale der Hard- oder Softwarekonfiguration der Knotenhaben. Ubergibt ein Nutzer einen Job an das Batch-System, so wird dieser vom Batch-System wie folgt behandelt:

• Der Nutzer teilt dem Batch-System mit, dass er einen Job starten mochte. Dabeikann er nicht nur den Namen des Programms angeben, sondern auch noch Min-destanforderungen an Speicher oder andere Ressourcen. Das Batch-System ver-merkt diese zusammen mit dem Zeitpunkt, an dem der Job dem Batch-Systemubergeben wurde, und personlichen Angaben des Nutzers, wie Name oder Zu-gehorigkeit zu einer bestimmen Nutzergruppe.

• Auf Grundlage der Wartezeit und anderer Angaben zu einem Job wird jedem Jobeine Prioritat zugewiesen.

• Sobald ein oder mehrere Knoten frei sind, wird ihnen vom Batch-System der Jobmit der großten Prioritat ubergeben, dessen Anforderungen die freien Knotenerfullen konnen.

• Nachdem der Job beendet wurde, speichert das Batch-System eventuell noch Da-ten uber den ausgefuhrten Job und schickt, falls gewunscht, an den Nutzer eineE-Mail, die ihn uber die erfolgreiche Bearbeitung seines Jobs informiert.

Der (logische) Bereich, in dem die Jobs bis zu ihrer Ausfuhrung warten und in demsie ausgefuhrt werden, heißt Queue. Je nach Batch-System konnen Queues mit ein-zelnen Hosts oder ganzen Hostgruppen assoziiert sein.

6.2.2 Scheduling-Strategien

Wann welche Jobs auf welchen Knoten des Clusters gestartet werden, entscheidetder Scheduler des Batch-Systems. Um eine optimale Auslastung des Clusters zu er-reichen, bedienen sich Scheduler verschiedener Strategien. Je nachdem welche Artder Auslastung angestrebt wird, sind diese Strategien mehr oder weniger gut geeig-net.

First-Come-First-Served. Dies ist die einfachste Scheduling-Strategie. Eingehen-de Jobs werden der Reihe nach abgearbeitet. Diese etwas starre Strategie fuhrtleicht zu einer schlechten Ausnutzung des Clusters. Angenommen in der Queuebefinden sich ein MPI-Programm fur 16 CPUs und einige Jobs fur nur eine CPUund das MPI-Programm wartet schon am langsten. Wenn nun nur 15 CPUs freisind, so wartet das Batch-System bis auch noch eine 16. CPU frei wird, um erstdas MPI-Programm auszufuhren. Der MPI-Job blockiert somit die nachfolgenJobs, die ja eigentlich schon auf den 15 freien Knoten laufen konnten.

Backfill. Die Backfill-Strategie versucht eine bessere Gesamtauslastung gegenuberder First-Come-First-Served-Strategie zu erreichen, indem freie CPUs auch mitJobs niedrigerer Prioritat belegt werden.

Fairshare. Die beiden erst genannten Strategien erweisen sich als ungunstig, fallsdie Nutzer den Cluster sehr unterschiedlich stark beanspruchen. Nutzer, die nur

Page 160: [X.systems.press] Cluster Computing ||

6.2 Jobverwaltung und Batch-Systeme 153

gelegentlich Jobs in die Queue stellen, mussen immer warten bis die Jobs ih-res Kollegen, der standig was zu rechnen hat, die Queue passiert haben. Fairs-hare versucht, fur mehr Gerechtigkeit zwischen den Nutzern zu sorgen. Dazuwird bei der Prioritatenberechnung der Ressourcenverbrauch der Vergangenheitberucksichtigt. Wer schon viel gerechnet hat, muss seine Kollegen vorlassen.

Exclusive. Um die Durchlaufzeiten zu minimieren, wird pro CPU nur ein Job ge-startet.

Preemtion. Preemtion bezeichnet die Fahigkeit, Jobs kurzzeitig beenden zu konnenund sie spater wieder zu starten, um zwischenzeitlich anderen Jobs Platz zu ma-chen. Grundvoraussetzung fur Preemtion ist das Checkpointing, siehe Kapitel 13und Abschnitt 6.2.3.

In der Praxis verwenden Batch-Systeme eine Kombination aus verschiedenen Sche-duling-Strategien und bieten vielfaltige Einstellmoglichkeiten. Zum Beispiel gestat-ten es einige Batch-Systeme, neue Ressourcen zu definieren. Ein typischer Anwen-dungsfall hierfur sind fließende Lizenzen kommerzieller Software. Die Anzahl ge-kaufter Lizenzen, die moglicherweise kleiner als die Zahl der Knoten ist, stellt hiereine begrenze Ressource dar.

6.2.3 Checkpointing

Das oben erwahnte Checkpointing (auch Checkpoint-Restart genannt) ermoglichtdas komplette Abspeichern eines Job-Status inklusive Programmzahler, Daten, offe-nen Dateien und anderen Job-Eigenschaften. Fuhrt ein Job regelmaßig ein Check-pointing durch, so kann er z. B. nach einem Stromausfall wieder aufgesetzt werden,ohne ihn von ganz vorne starten zu mussen. Stattdessen lauft er da weiter, wo er sichbeim letzten Checkpointing befand. Ein Job kann aber auch angehalten werden, umihn dann auf einem anderen Computer gleicher Architektur weiter laufen zu lassen.Dieser Fall wird Job-Migration genannt.

Das Checkpointing kann unterschiedlich implementiert sein. Man unterscheidetKernel-Level-, User-Level- und Application-Level-Checkpointing.

Kernel-Level-Checkpointing. Hier wird das Checkpointing als eine Betriebssys-temfunktion zur Verfugung gestellt. Eine spezielle Modifikation der Anwen-dungsprogramme ist nicht notwendig.

User-Level-Checkpointing. Auch beim User-Level-Checkpointing mussen Anwen-dungsprogramme nicht modifiziert werden. Um das Checkpointing zu aktivieren,wird eine Anwendung lediglich gegen eine spezielle Checkpointing-Bibliothekgelinkt. Prinzipiell ist Kernel-Level-Checkpointing machtiger als User-Level-Checkpointing, denn nur der Kernel hat die volle Kontrolle uber alle Prozesse.Mit User-Level-Checkpointing konnen nicht samtliche Prozesseigenschaften ge-sichert und rekonstruiert werden.

Application-Level-Checkpointing. Das Application-Level-Checkpointing verzich-tet auf spezielle Betriebssystemfunktionen und externe Bibliotheken. Stattdessenwird die gesamte Checkpointing-Funktionalitat in die Anwendung selbst einge-baut. Die Programmierung solcher Anwendungen ist relativ aufwendig.

Page 161: [X.systems.press] Cluster Computing ||

154 6 Cluster-Dienste

Neben dieser Einteilung ist die Fahigkeit, auch parallele Programme behandeln zukonnen, ein wichtiges Unterscheidungskriterium fur Checkpointing-Systeme. FurLinux existieren mehrere verschiedene Checkpointing-Losungen mit verschiedenenFahigkeiten und Einschrankungen. Einige dieser Losungen werden wir im Kapitel 13naher beschreiben.

6.2.4 Batch-Systeme im Uberblick

Auf Cluster-Computern findet man heute verschiedene Batch-Systeme, die sich inihrer Funktionalitat und Handhabung unterscheiden. Diese Batch-Systeme werdenteilweise kommerziell vertrieben und teilweise nicht kommerziell uber das Internetverteilt. Im folgenden sollen einige nicht kommerzielle Batch-Systeme vorgestelltwerden. Dabei beschranken wir uns auf einige ihrer wesentlichen Merkmale underheben keinen Anspruch auf Vollstandigkeit.

OpenPBS

OpenPBS ist wohl das alteste noch verbreitete Batch-System. Es wurde ursprunglichals Portable Batch System (PBS) vom Ames Research Center der NASA entwickelt.PBS war Grundlage des POSIX Standards 1003.2d, an dem sich nun auch einigeandere Batch-Systeme orientieren. Heute wird PBS von der Firma Veridian Systems[124] vertrieben. Daneben bietet diese Firma auch die kommerzielle Version PBS Proan.

OpenPBS lauft auf fast allen UNIX-Derivaten und unterstutzt auch heterogeneCluster. Der Scheduler von OpenPBS kann, entsprechende Programmierkenntnis-se vorausgesetzt, bei Bedarf durch eine C-ahnliche Sprache modifiziert oder aus-getauscht werden. Es konnen keine neuen Ressourcen definiert werden. OpenPBSunterstutzt Checkpointing nur auf Kernel-Level. OpenPBS wird auf Kommandozei-lenebene und zum Teil durch Werkzeuge mit graphischer Oberflache konfiguriertund bedient. Großter Nachteil von OpenPBS ist, dass seine Entwicklung zugunstenvon PBS Pro praktisch eingestellt wurde. Allerdings gibt es mit TORQUE [167] einmodernes Batch-System, das auf OpenPBS basiert, aber noch aktiv gepflegt wird.

Sun Grid Engine

Die Grid Engine von Sun geht auf das Batch-System Codine zuruck. Sun hat im Jah-re 2000 die Firma Gridware ubernommen und vertreibt und entwickelt heute derenProgramm unter dem Namen Grid Engine weiter. Im Vertrieb verfolgt Sun eine zwei-gleisige Strategie. Zum einen kann die Grid Engine frei von [56] im Quellcode oderin vorkompilierter Form heruntergeladen werden. Zum anderen bietet Sun mit derGrid Engine Enterprise Edition auch eine kommerzielle Version an. Diese kommer-zielle Variante hat einige zusatzliche Funktionen und der Kunde erhalt zusatzlichenSupport und weitere Dokumentation. Allerdings ist die Dokumentation der freienVersion schon recht beachtlich und umfasst uber 400 Seiten. Außerdem findet manauf den Webseiten [56] Informationen zu speziellen Themen.

Page 162: [X.systems.press] Cluster Computing ||

6.2 Jobverwaltung und Batch-Systeme 155

Abb. 6.1. Das Konfigurationswerkzeug der Grind Engine qmon in Aktion.

Etwas ungewohnlich bei der Grid Engine ist die hostorientierte Zuordnung derQueues. Da die meisten anderen Batch-Systeme einen netzorientierten Ansatz verfol-gen, muss ein Administrator, der vorher mit einem anderen Batch-System gearbeitethat, etwas umdenken. Dafur verwohnt Grid Engine den Administrator und die Nut-zer mit komfortablen Werkzeugen. Alle Konfigurationen lassen sich mit dem graphi-schen Werkzeug qmon vornehmen. Dies erleichtert besonders Einsteigern und Gele-genheitsadministratoren die Arbeit. Außerdem gehort zur Grid Engine eine Samm-lung von Kommandozeilenprogrammen, die im Funktionsumfang der graphischenOberflache gleichwertig sind. Konfigurationsanderungen wirken sich immer sofortohne Neustart auf das Batch-System aus.

Die Queues sind umfangreich konfigurierbar und der Scheduler lasst sich guteigenen Bedurfnissen anpassen. Dabei erreicht die Grid Engine durch die sog. Kom-plexe (complexes) große Flexibilitat. Komplexe sind den Queues oder dem Clusterzugeordnete Mengen von Attributen. Auch konnen eigene Ressourcen definiert wer-den.

Die Grid Engine unterstutzt Kernel-Level- und User-Level-Checkpointing, be-sitzt aber selbst keine Bibliothek, die User-Level-Checkpointing implementiert. DasBatch-System ist hier auf externe Bibliotheken angewiesen, z. B. die Checkpointing-Bibliothek von Condor.

Condor

Condor ist das Ergebnis eines Forschungsprojektes des Department of ComputerSciences der University of Wisconsin-Madison [21]. Diese vertreibt ihr Batch-Sys-

Page 163: [X.systems.press] Cluster Computing ||

156 6 Cluster-Dienste

tem unter der Condor Public License in binarer Form fur verschiedene Linux-Varian-ten sowie fur Windows. Auf Anfrage ist auch der Quellcode verfugbar. Die CondorPublic License ist recht liberal gehalten und gestattet z. B. die Weitergabe und dieModifizierung der Quellen.

Condor besitzt einige Merkmale, die es deutlich von anderen Batch-Systemen ab-hebt. Dazu zahlen die zu Condor gehorende Checkpointing-Bibliothek (User-Level-Checkpointing) und das Umleiten von Systemaufrufen. Durch die Checkpointing-Bibliothek konnen Jobs angehalten, wieder aufgesetzt oder migriert werden. Durchdiese Funktionalitat ist Condor besonders gut fur networks of workstations geeignet.

Condor leitet alle Systemaufrufe eines Jobs auf den Computer um, von dem ausder Job dem Batch-System ubergeben wurde. Dazu ist die Anwendung zunachst ge-gen eine bestimmte Bibliothek zu linken. Durch diese fangt Condor jeden Systemauf-ruf des Jobs ab, sendet diese zum Computer, von dem aus der Job Condor ubergebenwurde. Dort werden die Systemaufrufe ausgefuhrt. Danach sendet Condor die Er-gebnisse der Systemaufrufe zuruck zum Job. Dies bedeutet, dass obwohl der Jobirgendwo im Netzwerk lauft, es aus der Sicht des Nutzers so aussieht, als liefe er aufseinem Computer. Zum Beispiel werden alle Ein- und Ausgabeoperationen auf denComputer des Nutzers umgeleitet und der Nutzer muss uber kein Nutzerkonto aufdem entfernten Rechner verfugen, auf dem sein Job tatsachlich lauft.

Condor lasst sich sowohl auf Einzelplatzrechnern, dedizierten Clustern als auchnetworks of workstations einsetzen. Auf einem Einzelplatzrechner dient Condor vor-allem dazu, lang laufende Programme zu unterbrechen und sie spater wieder aufzuset-zen. Auf kleinen Clustern dient es als gewohnliches Batch-System und in networksof workstations hilft es, ungenutzte Rechenzeit in Mittagspausen und in der Nachtproduktiv zu nutzen.

Maui-Scheduler

Der Maui-Scheduler ist ein sehr leistungsfahiges Batch-System fur Cluster und Su-percomputer. Die Entwickler von Maui bezeichnen ihr Programm etwas unbeschei-den selbst als ”the most advanced scheduler in the world“. Dieser Scheduler wur-de maßgeblich von großen amerikanischen Supercomputing-Zentren wie Cluster Re-sources Incorporated und dem U. S. Department of Energy, dem Pacific NorthwestNational Laboratory, dem Center for High Performance Computing der Universi-ty of Utah oder dem San Diego Supercomputing Center entwickelt. Da Maui einCommunity-Projekt ist, kann aber jeder die Quellen herunterladen, anpassen undVerbesserungen zum Maui-Projekt beisteuern. Vorkompilierte Pakte, der Quellcodeund Dokumentation von Maui werden uber [100] vertrieben.

Der Maui-Scheduler lasst sich am besten als Meta-Scheduler charakterisieren. Ersetzt auf verschiedenen anderen Schedulern wie z. B. OpenPBS auf, erweitert derenFahigkeiten und macht diese unterschiedlichen Scheduler unter einer einheitlichenOberflache zuganglich. Maui erweitert die Fahigkeiten der Basis-Scheduling-Syste-me um folgende Merkmale:

• Maui verfugt uber vielfaltige und konfigurierbare Strategien zur Berechnung vonJob-Prioritaten,

Page 164: [X.systems.press] Cluster Computing ||

6.2 Jobverwaltung und Batch-Systeme 157

• fortgeschrittene Ressourcenverwaltung und Ressourcenreservierung im Vorausund bietet

• Quallity of Service. Das heißt, bestimmte Ressourcen konnen bestimmten Jobszugesichert werden.

• Mit Maui lassen sich Fairness-Regeln definieren und• es beherrscht Backfill-Scheduling.• Maui hilft bei der Systemdiagnose.

Maui bietet so viele Einstellmoglichkeiten, dass es manchmal a priori nicht sichervorhersagbar ist, wie sich bestimmte Einstellungen auf das Scheduling-Verhalten aus-wirken. Darum erweist sich bei großen Clustern, die komplexe Scheduling-Strategi-en benotigen, der Testmodus als sehr praktisch. In diesem Modus konnen verschiede-ne Lastszenarien mit unterschiedlichsten Scheduling-Strategien simuliert und derenAuswirkungen untersucht werden, ohne dabei den eigentlichen Cluster-Betrieb zubehindern.

6.2.5 Anwendungsbeispiel: Sun Grid Engine

Seit Sun das Batch-System Codine unter dem Namen Sun Grid Engine frei vertreibt,hat dieses Programm stark an Popularitat gewonnen. Schauen wir uns das Programmdarum einmal aus Sicht eines Nutzers etwas genauer an.

Zur Verwaltung der Queues und zum Einfugen von Jobs in das Batch-Systemkennt die Sun Grid Engine verschiedene Programme. Dazu gehoren:

qacct. Das Prgramm qacct extrahiert Informationen aus Protokolldateien.qalter. Hiermit konnen Eigenschaften von Jobs, die schon dem Batch-System

ubergeben wurden aber noch nicht laufen, geandert werden.qconf. Dies ist das zentrale Werkzeug zur Konfiguration des Batch-Systems und

der Queues.qdel. qdel sendet Signale an Jobs, um sie z. B. aus dem Batch-System zu loschen.qhold. qhold verhindert das Starten von Jobs, die schon dem Batch-System uber-

geben wurden aber noch nicht laufen.qhost. Mit qhost erhalten Sie die Statusinformationen eines Knotens.qlogin. qlogin offnet eine Telnet-Sitzung zu einem wenig belasteten Knoten.qmake. qmake ist eine parallele Variante des bekannten make-Programms.qmod. Mit qmod konnen Queues aktiviert oder deaktiviert werden.qmon. qmon ist ein komfortables Programm mit graphischer Oberflache zur Admi-

nistration der Sun Grid Engine.qresub. Mit qresub erzeugen Nutzer neue Jobs, indem laufende oder wartende

Jobs kopiert werden.qrls. qrls macht die Wirkung von qhold ruckgangig.qrsh. qrsh startet u. a. interaktive Batch-Jobs.qselect. Das Programm qselect gibt eine Liste von Queues aus, die bestimm-

ten Kriterien entsprechen.qsh. Mit qsh offnen Sie eine interaktive Shell in einem Terminal auf einem Knoten

mit geringer Last.

Page 165: [X.systems.press] Cluster Computing ||

158 6 Cluster-Dienste

qstat. qstat liefert Informationen uber Queues, wartende und laufende Jobs.qsub. Durch qsub ubergeben Nutzer dem Batch-System neue Jobs.qtcsh. qtcsh ist ein Ersatz fur die C-Shell mit Erweiterungen, die Programme

auf Knoten mit geringer Last ausfuhrt.

Eine genaue Beschreibung dieser Programme finden Sie in den entsprechenden Man-pages bzw. dem ”User’s Guide“. In der taglichen Arbeit mit der Sun Grid Enginesind qsub, qdel und qmon sicher die wichtigsten Programme. Fur einige der obengenannten Programme werden Administratorrechte benotigt.

Die Grid Engine startet Jobs grundsatzlich nur uber Shell-Skripten. Diese Skrip-ten bestehen aus einem Kopf in Form von Kommentarzeilen und einem Korper ausnormalen Shell-Kommandos. Die Kommentarzeilen konnen Metainformationen furdie Grid Engine enthalten. Solche Zeilen erkennt man daran, dass sie mit #$ begin-nen. Die Metainformationen dienen z. B. dazu, das Batch-System anzuweisen, einenJob nur auf Knoten zu starten, die bestimmte Anforderungen an Hard- und Software-ausstattung erfullen.

In folgendem Beispiel soll ein Job eine Graphik mit dem Programm POV-Ray[135] berechnen. POV-Ray ist ein ray tracing Programm, mit dem pseudorealisti-sche dreidimensionale Szenen berechnet werden konnen. POV-Ray liest dazu eineBeschreibungsdatei mit den Daten uber geometrische Objekte, deren optischen Ober-flacheneigenschaften und Lichtquellen ein und gibt als Ergebnis eine Grafikdatei aus.POV-Ray eignet sich auch hervorragend dazu, mathematische Sachverhalte durchqualitativ hochwertige Graphiken zu visualisieren. In Abb. 6.2 ist z. B. eine mit POV-Ray gezeichnete Flache zu sehen, die durch die implizite Formel

0 = 81(x3 + y3 + z3)−189(x2(y+ z)+ y2(x+ z)+ z2(x+ y))+54xyz

+126(xy+ xz+ yz)−9(x2 + y2 + z2)−9(x+ y+ z)(6.1)

Abb. 6.2. Eine mit POV-Ray gezeichnete implizite Flache.

Page 166: [X.systems.press] Cluster Computing ||

6.2 Jobverwaltung und Batch-Systeme 159

Listing 6.2. Job-Skript fur die Grid Engine zur Berechnung einer POV-Ray-Szene.

# ! / b i n / sh## F e h l e r a u s g a b e u m l e i t e n#$ −e $HOME/ tmp / $JOB NAME . $JOB ID . s t d e r r

5 ## S t a n d a r d a u s g a b e u m l e i t e n#$ −o $HOME/ tmp / $JOB NAME . $JOB ID . s t d o u t## a l t e $PATH V a r i a b l e r e k o n s t r u i e r e n

10 if [ $COD_O_PATH ]; thenexport PATH=$COD_O_PATH

fi# i n A r b e i t s v e r z e i c h n i s wechse lncd pov

15 # POV−Ray s t a r t e n# E i n g a b e d a t e i : C l e b s c h D i a g o n a l C u b i c . pov# Ausgabeformat : png# B i l d f o r m a t : 800 x600povray +i Clebsch_Diagonal_Cubic.pov +FN +W800 +H600

definiert ist und einige interessante Eigenschaften besitzt [20]. Die Eingabedatei furdie Abb. 6.2 haben wir mit dem Mathematikprogramm Maple erzeugt.

Listing 6.2 zeigt das Shell-Skript, mit dem wir den Job gestartet haben, derdie Abb. 6.2 berechnet hat. Im Kopf enthalt es zwei Anweisungen an die GridEngine. Diese leiten die Standardausgabe und die Fehlerausgabe in die Dateien$HOME/tmp/$JOB NAME.$JOB ID.stdout und $HOME/tmp/$JOB NAME.$JOB ID.stderr um. Dies ist notwendig, weil der Job, wenn ihn das Batch-Sys-tem gestartet hat, mit keinem Terminal verbunden ist, auf dem diese Ausgaben lan-den konnten. Die beiden Variablen $JOB NAME und $JOB ID sind spezielle Umge-bungsvariablen der Grid Engine. Sie enthalten den Namen des Job-Shell-Skript bzw.eine Nummer, die jeden Job eindeutig identifiziert. Wenn wir das Skript pov.shnennen und die Grid Engine dem Job die Nummer 121 gibt, werden die Standardaus-gabe und die Fehlerausgabe in die beiden Dateien tmp/pov.sh.121.stdoutund tmp/pov.sh.121.stderr im Heimatverzeichnis des Nutzers umgeleitet.Dazu muss das Verzeichnis tmp allerdings existieren.

Im eigentlichen Anweisungsteil des Skripts wird die $PATH-Variable rekon-struiert, in das Arbeitsverzeichnis pov gewechselt und schließlich das Programmpovray aufgerufen. Die Rekonstruktion der $PATH-Variable ist notwendig, weildie Grid Engine $PATH und einige andere Umgebungsvariablen mit eigenen Wer-ten uberschreibt, was nicht immer gewollt ist. Glucklicherweise legt die Grid Engineeine Sicherheitskopie an.

Mit dem Kommando qsub wird, ein Job an das Batch-System ubergeben.

bauke@server:˜/pov$ qsub pov.shyour job 121 ("pov.sh") has been submitted

Je nachdem wie voll die Queue ist, findent man ein paar Minuten oder einige Stundenspater im Verzeichnis pov das von POV-Ray berechnete Bild.

Page 167: [X.systems.press] Cluster Computing ||

160 6 Cluster-Dienste

Listing 6.3. Job-Skript fur die Grid Engine bei dem Argumente uber qsub spezifiziert werdenkonnen.

# ! / b i n / sh## F e h l e r a u s g a b e u m l e i t e n#$ −e $HOME/ tmp / $JOB NAME . $JOB ID . s t d e r r

5 ## S t a n d a r d a u s g a b e u m l e i t e n#$ −o $HOME/ tmp / $JOB NAME . $JOB ID . s t d o u t## a l t e $PATH V a r i a b l e r e k o n s t r u i e r e n

10 if [ $COD_O_PATH ]; thenexport PATH=$COD_O_PATH

fi# i n A r b e i t s v e r z e i c h n i s wechse lncd project

15 # Anwendung mi t den P a r a m e t e r n des Job−S k r i p t s s t a r t e nmy_application ”$@”

Im obigen Beispiel waren alle Parameter fur das vom Skript aufgerufene Pro-gramm (Eingabedatei, Bildgroße), fest im Job-Skript codiert. Dies ist oft unpraktisch,da sich zahlreiche Jobs nur durch ihre Eingabeparameter unterscheiden. Stellen Siesich vor, Sie wollten mit POV-Ray sehr viele Bilder mit verschiedenen Eingabeda-teien berechnen, um sie spater zu einem ganzen Film zusammen zu setzen. In solcheinem Fall ist es gunstiger, die variablen Parameter beim Aufruf von qsub zu spezi-fizieren.

bauke@server:˜/project$ qsub my_application.sh 42 3.14your job 122 ("my_application.sh 42 3.14") has been submitted

Listing 6.3 zeigt, wie ein Skript dafur aussehen konnte. Entscheidend ist die letzteZeile, hier werden alle Parameter, mit dem das Skript aufgerufen wurde und in derVariablen $@ gespeichert sind, an das Programm my application weitergereicht.In unserem Beispiel wurde also effektiv das Programm my application mit denbeiden Parmetern 42 und 3.14 ausgefuhrt werden.

Auch MPI-Programme lassen sich durch die Grid Engine starten. Dazu mussder Administrator in der Grid Engine eine parallele Umgebung anlegen, siehe GridEngine Handbuch. Ein Nutzer muss nur wissen, dass dem Job-Skript in der Vari-ablen $NSLOTS die Zahl der zur Verfugung gestellten CPUs steht und in der Da-tei $TMPDIR/machines sich eine Liste der Knoten auf denen das parallele Pro-gramm ausgefuhrt werden darf. Diese beiden Informationen nutzt das in Listing 6.4gezeigte Job-Skript, das einen Job mit 16 CPUs in der parallelen Umgebung ”LAM“startet.

6.3 Cluster-Management-Systeme

Im Vergleich zu einem Einzelcomputer stellt ein Cluster-Computer ein recht kom-plexes Gebilde dar. Auch wenn ein solcher Verbund von Einzelcomputern sich dem

Page 168: [X.systems.press] Cluster Computing ||

6.3 Cluster-Management-Systeme 161

Listing 6.4. Job-Skript fur die Grid Engine zum Starten eines MPI-Programms.

# ! / b i n / bash## P a r a l l e l e Umgebung ”LAM” mi t 16 CPUs#$ −pe LAM 16

5 ## F e h l e r a u s g a b e u m l e i t e n#$ −e $HOME/ tmp / $JOB NAME . $JOB ID . s t d e r r## S t a n d a r d a u s g a b e u m l e i t e n

10 #$ −o $HOME/ tmp / $JOB NAME . $JOB ID . s t d o u t## a l t e $PATH V a r i a b l e r e k o n s t u i e r e nif [ $COD_O_PATH ]; then

export PATH=$COD_O_PATH15 fi

## $NSLOTS : Zahl d e r P r o z e s s o r e n# $TMPDIR / machines : L i s t e mi t Knoten#

20 # i n A r b e i t s v e r z e i c h n i s wechse lncd project# Anwendung mi t den P a r a m e t e r n des Job−S k r i p t s s t a r t e nmpiexec -machinefile $TMPDIR/machines -n $NSLOTS my_mpi_application ”$@”

Nutzer im Idealfall als einheitliches Ganzes reprasentiert, so erschwert seine ver-teilte Struktur in der Praxis doch zumindest dem Administrator die Arbeit. DieseSituation verscharft sich noch, wenn, was (leider) durchaus gangige Praxis ist, Clus-ter von Teilzeitadministratoren verwaltet werden, die hauptberuflich einer anderenz. B. wissenschaftlichen Aufgabe nachgehen. Spezielle Cluster-Management-Syste-me konnen hier helfen.

Es existieren verschiedene Ansatze fur Cluster-Management-Systeme. Zum einenhandelt es sich dabei um Entwicklungen von Cluster-Distributoren, die Kunden beimKauf eines Clusters erhalten, zum anderen um Open-Source-Projekte. Beziehen SieCluster-Hardware und Cluster-Management-System vom gleichen Cluster-Distribu-tor, so konnen Sie relativ sicher sein, dass Hard- und Software gut aufeinander ab-gestimmt sind. Bei Schwierigkeiten mit dem Cluster-Management-System oder fallsAnpassungen notwendig sind, ist man aber auf die Unterstutzung des Cluster-Dis-tributors angewiesen. Was sich dieser meist gut bezahlen lasst. Wer auf Cluster-Management-Systeme von Open-Source-Projekten setzt, begibt sich nicht in dieseAbhangigkeit. OSCAR und Rocks sind zwei Cluster-Management-Systeme aus demOpen-Source-Bereich, mit denen auch Administratoren ohne Vorkenntnisse im Clus-ter-Computing schnell einen voll funktionsfahigen Cluster aufbauen konnen. Wirwerden OSCAR und Rocks nur kurz anreißen. Eine ausfuhrlichere Beschreibung fin-den Sie in der Dokumentation der beiden Systeme sowie in den Buchern [58] und[153].

So nutzlich Cluster-Management-Systeme auch sind, sie haben auch einige Nach-teile. Cluster-Management-Systeme sollen dem Cluster-Administrator die Arbeit er-leichtern und Routineaufgaben automatisieren. Dabei kann es aber schon einmal pas-

Page 169: [X.systems.press] Cluster Computing ||

162 6 Cluster-Dienste

sieren, dass man als Cluster-Administrator das Verstandnis fur die zum Teil rechtkomplexen Ablaufe verliert. So lange alles glatt lauft, kein Problem. Aber wehe,es treten Schwierigkeiten auf. Dann mussen Sie eventuell doch Konfigurationsda-teien von Hand editieren oder Programme selbst kompilieren. Darum sollten Sie dieKapitel 5 und 6 auch dann aufmerksam lesen, wenn Sie ein Cluster-Management-System verwenden. Die Cluster-Management-Systeme enthalten bereits (fast) alleProgramme, die man auf einem Cluster benotigt, aber eventuell nicht in der von Ih-nen gewunschten Version oder Konfiguration. Auch dann sind Sie wieder auf dieInformationen aus den Kapiteln 5 und 6 angewiesen.

6.3.1 OSCAR

OSCAR [126] steht fur Open Source Cluster Application Resources und ist ein Open-Source-Projekt der Open Cluster Group, in der im Wesentlichen amerikanische Uni-versitaten und Hardwarehersteller vertreten sind. Ziel dieses Projektes ist es, eineneinheitlichen Rahmen fur die Installation und Administration von Linux-Cluster-Computern zu schaffen und damit fur eine großere Akzeptanz von Linux-Cluster-Computern zu sorgen. Dazu vereinigt OSCAR eine Sammlung popularer Software-werkzeuge fur Cluster-Computer in eine Art Metadistribution. Dazu gehoren Admi-nistrationswerkzeuge wie

• System Installation Suite [163], zur Installation vernetzter Workstations bzw. derCluster-Knoten dient,

• C3 [15] (Cluster Command & Control), einer Sammlung von Programmen mitdenen ahnlich der Distributed Shell Kommandos gleichzeitig auf mehreren Com-putern ausgefuhrt werden konnen, und

• OPIUM, mit dem die Nutzerkonten verwaltet werden.

Die System Installation Suite baut ubrigens auf dem uns schon vertrauten System-Imager auf, siehe Abschnitt 5.5. Außerdem beinhaltet OSCAR

• Message-Passing-Bibliotheken wie MPICH, LAM/MPI und PVM,• Batch-Systeme wie OpenPBS/MAUI und Sun Grid Engine,• Uberwachungswerkzeuge wie Ganglia (Notiz 6.5) [45] und Clumon,• sowie von OSCAR-Projekt erstellte Programme wie eine Cluster-Datenbank, ei-

ne Paketverwaltung und ein Installationsprogramm, siehe Abb. 6.3.

Samtliche Programme der OSCAR Metadistribution konnen mit dem selben graphi-schen Installationsprogramm installiert und konfiguriert werden, was gerade weni-ger erfahreren Administratoren die Arbeit stark erleichtern sollte. Allerdings musssich das Installationsprogramm mit der eingesetzten Linux-Distribution vertragen.Momentan unterstutzt OSCAR offiziell nur RedHat, Fedora und Mandriva (fruherMandrake), bei anderen Distributionen muss man zumindest mit Inkompatibilitatenrechnen. Das OSCAR-Team arbeitet jedoch daran, die Zahl der unterstutzten Distri-butionen zu erhohen. Geplant sind Erweiterungen auf Debian GNU/Linux und SuSE.

Vom OSCAR-Projekt gibt es zwei interessante Ableger, Thin-OSCAR [128] undHA-OSCAR [127]. Thin-OSCAR ist auf Cluster mit diskless nodes spezialisiert und

Page 170: [X.systems.press] Cluster Computing ||

6.4 Notizen 163

Abb. 6.3. Das OSCAR Installationsprogramm.

HA-OSCAR erweitert OSCAR, so dass mit ihm Hochverfugbarkeits-Cluster aufge-baut werden konnen.

6.3.2 Rocks Cluster Distribution

Bei Rocks [143] handelt es sich weniger um eine Werkzeugsammlung als viel-mehr um eine fur Cluster-Computer optimierte Linux-Distribution. Rocks basiertauf RedHat und lauft auf x86-kompatiblen Computern, IA-64 und Opteron. DieRocks-Distribution beinhaltet schon alles, was man zum Aufbau eines Clustersbenotigt, z. B. eine MPI-Implementation (MPICH aber nicht LAM/MPI), Batch-Sys-teme (Sun Grid Engine und OpenPBS/Maui) und Uberwachungsprogramme (Gang-lia (Notiz 6.5)). Zur Installation und Konfiguration aller Knoten dient das Kickstart-Programm von RedHat.

Rocks berucksichtigt, dass ein Cluster aus verschiedenen Knotentypen besteht.Diese Knotentypen heißen im Rocks-Jargon appliance types. Samtliche Informatio-nen uber den Cluster, die verschiedenen Knotentypen oder einzelne Knoten, die furdie Administratoren notwendig sind, speichert Rocks in einer zentralen Datenbank.Diese Informationen konnen auch abgespeichert und in einem anderen Cluster wie-der verwendet werden. Dabei sind die Beschreibungsdateien weitgehend hardware-unspezifisch, so dass sie sogar zwischen Clustern mit unterschiedlicher Knoten-Hard-ware ausgetauscht werden konnen, bzw. Rocks auch mit heterogenen Clustern umge-hen kann. Allerdings unterstutzt Rocks keine Cluster mit festplattenlosen Knoten.

6.4 Notizen

6.1 Open MPI. Wahrend wir an diesem Buch schrieben, kundigte das LAM/MPI-Entwicklerteam auf ihrer Mailingliste an, dass sich LAM/MPI in einer der nachstenVersionen so stark verandern wird, dass die MPI-Bibliothek in Zukunft unter dem

Page 171: [X.systems.press] Cluster Computing ||

164 6 Cluster-Dienste

Namen Open MPI [121] veroffentlicht werden wird. Dafur haben sich die LAM-Ent-wickler mit den Entwicklern dreier weiterer MPI-Implementationen zusammengetan,um aus den besten Komponenten von vier verschiedenen MPI-Implementationen ei-ne neue leistungsstarke MPI-Implementation zu schaffen. Zu ihren Merkmalen wer-den u. a.

• volle MPI-1- und MPI-2-Funktionalitat,• Unterstutzung von Kommunikation uber TCP/IP, shared memory, Myrinet, Infi-

niBand und Quadrics und• asynchroner Nachrichtenaustausch

gehoren. Zur Zeit (Juni 2005) gibt es nur eine Alpha-Version der Software zu diesemProjekt.

6.2 POV-Ray. Die Berechnung zahlreicher POV-Ray-Szenen lasst sich nicht nur da-durch beschleunigen, dass ein Cluster-Computer auf mehreren Knoten gleichzeitigmehrere Bilder berechnet. Mit POV-Ray konnen auch mehrere Computer gleichzei-tig an einem Bild rechnen, was die Rechenzeit entsprechend verkurzt. POV-Ray ver-wendet dazu die Nachrichtenaustausch-Bibliothek PVM. Daneben gibt es unter [106]auch eine POV-Ray-Version, die MPI statt PVM verwendet, siehe Abschnitt 11.1.9.

6.3 Cluster-Management-Systeme. Neben den hier vorgestellten Cluster-Mana-gement-Systemen gibt es noch einige weitere weniger verbreitete Systeme. Dazuzahlen z. B. SCore [148], LCFG [91] und Debian Cluster Components [25]. De-bian Cluster Components ist eine recht komplette Werkzeugsammlung fur Debian-basierte Cluster-Computer. Es besteht aus einem Satz von Debian-Paketen, die dieErzeugung und den Einsatz von auf Debian basierten Clustern vereinfachen.

6.4 ParallelKnoppix. Noch schneller als mit einem Cluster-Management-Systemkommen Sie mit ParallelKnoppix zu einem lauffahigen Cluster. Die Linux-Live-CDKnoppix [84] lauft komplett von CD, ohne dabei Anderungen auf der Festplatte vor-zunehmen. Darum ist es ideal, um erste Gehversuche mit dem freien Betriebssys-tem zu machen. ParallelKnoppix [132] ist eine Knoppix-Variante mit der Sie Ihreersten Erfahrungen im Cluster-Computing sammeln konnen. Dazu wurde die Knop-pix-Distribution um LAM/MPI und MPICH erganzt. Dank der Knoppix-Terminal-Server-Funktion konnen alle Knoten des Clusters von einer einzigen ParallelKnop-pix-CD gebootet werden, vorausgesetzt die Knoten verfugen uber eine Netzwerkkar-te mit PXE-Boot-ROM. ParallelKnoppix spielt seine Starken vorallem bei Ad-hoc-Clustern aus, fur einen dauerhaften Einsatz ist es allerdings wenig geeignet. Einenahnlichen Ansatz wie ParallelKnoppix verfolgt die Bootable Cluster CD [13].

6.5 Ganglia. Es existieren noch zahreiche Prgramme, die im weitesten Sinne unterdie Rubrik Cluster-Dienste fallen. Naturlich konnen wir hier nicht alle vorstellen.Eines dieser von uns bisher unerwahnten Programme ist Ganglia [45]. Ganglia ist einverteiltes Cluster-Monitoring-System. Es uberwacht, protokolliert und visualisiertden Zustand aller Knoten eines Clusters.

Page 172: [X.systems.press] Cluster Computing ||

Teil III

MPI

Page 173: [X.systems.press] Cluster Computing ||

7

Grundlagen

I am not sure how I will program a Petaflops machine, but Iam sure that I will need MPI somewhere.

Horst D. Simon [151]

Nachdem wir die Idee der nachrichtenbasierten Programmierung an Hand eines ein-fachen MPI-Programmes kennen gelernt haben (Abschnitt 3.3) und gezeigt haben,wie man eine MPI-Bibliothek installiert und MPI-Programme startet (Abschnitt 6.1),ist es an der Zeit, dass wir uns genauer mit der MPI-Programmierung auseinanderset-zen. Dazu werden wir in diesem Kapitel die wichtigsten Elemente von MPI vorstel-len. Befassen werden wir uns auch mit einigen typischen Problemen der parallelenProgrammierung (deadlocks, race conditions und fairness) und wie man damit imRahmen von MPI umgeht.

7.1 Das Minimalgerust

Jedes MPI-Programm enthalt ein Minimalgerust von Elementen aus der MPI-Biblio-thek. Dieses Gerust findet man naturlich auch in unserem Beispiel zur numerischenIntegration (Listing 3.2). Dazu gehort zunachst das Einlesen der Headerdatei mpi.h.

#include ” mpi . h ”

Sie enthalt die Schnittstelle zur MPI-Bibliothek. Darin sind alle MPI-Funktionendeklariert und MPI-spezifische Konstanten definiert. MPI verwendet ein festes Na-mensschema. Alle Bezeichner beginnen mit MPI . Bei Konstanten besteht der Restaus Großbuchstaben (z. B. MPI DOUBLE), bei Funktionen folgen ein oder mehreredurch Tiefstriche getrennte Worte, wobei nur der erste Buchstabe des ersten Wortesgroß geschrieben wird (z. B. MPI Init).

Wenn Sie MPI Programme entwickeln, so sind diese quellcode-portabel. DerQuellcode eines MPI-Programms lasst sich ohne Anderungen mit jeder MPI-Im-plementation ubersetzen und ausfuhren. Uber alle Dinge, die uber diese Quellcode-Portabilitat hinausgehen, macht der Standard keinerlei Aussage. Insbesondere be-schreibt er nicht, wie MPI-Programme gestartet werden, welche Programme der Nut-zer dazu benutzt oder welche Voraussetzungen er vorher schaffen muss. All dies sindimplementationsspezifische Details.

Page 174: [X.systems.press] Cluster Computing ||

168 7 Grundlagen

Wurde ein MPI-Programm aber erst einmal gestartet, so sind in den allermeistenFallen noch einige implementationsspezifische Vorbereitungen zu treffen, bevor dieMPI-Programme untereinander kommunizieren konnen. Dies wird von der Initiali-sierungsfunktion MPI Init erledigt. Der Prototyp dieser Funktion lautet:

int MPI_Init(int *argc, char ***argv)

Mit MPI Init wird das MPI-System initialisiert. Keine andere MPI-Funktion darfvor ihr aufgerufen werden (Notiz 7.2). MPI Init wiederum darf von jedem Prozessnur ein einziges Mal aufgerufen werden.

Die Signatur der Hauptfunktion main eines C-Programms verlangt entwederkeine Argumente

int main(void)

oder lautet

int main(int argc, char *argv[])

In diesem Fall enthalten die Argumente von main die Kommandozeilenargumen-te, die Sie beim Start des Programms angeben konnen. Unser Beispielprogrammmpiint.c in Listing 3.2 verwendet die Kommandozeile zur Angabe der Anzahlvon Stutzstellen. Falls Sie diese nutzliche Technik noch nicht kennen, finden Sie imAnhang 15 eine Diskussion dieser Technik.

Auch bei MPI-Programmen, die selbst keine Kommandozeilenargumente ab-fragen, mussen die Parameter in main angegeben werden, denn diese werden andie Initialisierungsfunktion MPI Init weitergereicht. Die Funktion erwartet nichteine Kopie der Argumente von main sondern zwei Zeiger auf deren Adressen.MPI Init benotigt die Informationen aus der Kommandozeile, damit Informatio-nen von der Kommandozeile an die MPI-Umgebung weitergereicht werden konnen(Notiz 7.1). Die Ubergabe via Zeiger ermoglicht es der MPI-Implementation, dieKommandozeilenargumente zu modifizieren. So kann MPI Init die Kommandozei-lenargumente in Umgebungen bereitstellen, in denen sie der Funktion main selbstnicht zur Verfugung stehen. Ihre Anwendungen sollten die Kommandozeilenargu-mente deshalb immer erst nach MPI Init auswerten.

MPI Init liefert wie fast alle MPI-Funktionen als Ruckgabewert einen Fehler-code. Bei fehlerfreier Ausfuhrung ist dessen Wert gleich MPI SUCCESS. Tritt ineiner MPI-Funktion allerdings tatsachlich ein Fehler auf, so wird der laufende Pro-zess abgebrochen, noch bevor die Funktion zuruckkehren kann. Wir werden deshalbden Ruckgabewert ignorieren. Allerdings bietet MPI die Moglichkeit, den Abbruchbei Auftritt eines Fehlers zu unterbinden und durch eine eigene Fehler-Behandlungs-Funktion zu ersetzen (siehe Abschnitt 8.2). Dabei gewinnen die Ruckgabewertenaturlich an Bedeutung.

Am Schluss eines MPI-Programms werden alle von MPI benutzten Systemres-sourcen mit der Funktion

int MPI_Finalize(void)

Page 175: [X.systems.press] Cluster Computing ||

7.1 Das Minimalgerust 169

wieder freigegeben. Danach durfen keine MPI-Funktion mehr aufgerufen werden,auch ein erneutes Initialisieren mit MPI Init ist nicht gestattet.

Mit den oben vorgestellten Funktionen ergibt sich ein Minimalgerust, das in je-dem MPI-Programm enthalten ist.

...#include ” mpi . h ”...int main(int argc, char *argv[]) {

.../ * k e i n e Auswertung d e r Kommandozeile b i s h i e r h e r * // * k e i n e MPI−F u n k t i o n e n b i s h i e r h e r * /MPI_Init(&argc, &argv);/ * ab h i e r : MPI−F u n k t i o n e n und Auswertung d e r Kommandozeile * /...MPI_Finalize();/ * k e i n e MPI−F u n k t i o n e n ab h i e r * /...

} / * main * /

Mit diesem Minimalgerust allein lasst sich noch nicht viel anfangen. In einem par-allelen Programm braucht jeder Prozess die Antwort auf zwei Fragen: ”WievieleProzesse gibt es?“ und ”Welcher davon bin ich?“

MPI organisiert die Prozesse einer Anwendung in so genannten Kommunikatoren.Kommunikatoren dienen mehreren Zwecken, einer davon ist die Zusammenfassungvon Prozessen in Prozessgruppen. Wir werden gelegentlich die Begriffe ”Kommuni-kator“ und ”Gruppe“ synonym verwenden, aber Sie sollten im Hinterkopf behalten,dass die Prozessgruppe nur einen Teil eines Kommunikators ausmacht (siehe Ab-schnitt 8.1). Ein Kommunikator ist ein opakes Objekt (siehe Abschnitt 8.1.2) vomDatentyp MPI Comm.

Nach der Initialisierung durch MPI Init existiert bereits der vordefinierteKommunikator MPI COMM WORLD. Er enthalt die Gruppe aller von mpirun odermpiexec gestarteten Prozesse. Die Funktion

int MPI_Comm_size(MPI_Comm comm, int *p)

liefert die Anzahl p der zum Kommunikator comm gehorenden Prozesse. Die p Pro-zesse eines Kommunikators sind von 0 bis p− 1 durchnummeriert. Die Nummereines Prozesses ist sein Rang und wird von

int MPI_Comm_rank(MPI_Comm comm, int *myrank)

in der Variablen myrank ermittelt.Listing 7.1 zeigt ein minimalistisches MPI-Programm, bei dem jeder Prozess nur

seine Identitat ausgibt und sich danach gleich beendet. Neu ist hier die FunktionMPI Get processor name.

int MPI_Get_processor_name(char *name, int *len)

Sie gibt in name den Namen der Maschine zuruck, auf der der aufrufende Pro-zess lauft. In den meisten Fallen stimmt dieser Name mit dem uberein, was die

Page 176: [X.systems.press] Cluster Computing ||

170 7 Grundlagen

Listing 7.1. Minimalistisches MPI-Programm mpiident.c: Jeder Prozess gibt seine eigeneIdentitat aus.

#include <stdio.h>#include <stdlib.h>#include ” mpi . h ”

5 int main(int argc, char *argv[]) {int myrank, nprocs, len;char name[MPI_MAX_PROCESSOR_NAME+1];

MPI_Init(&argc, &argv);10 MPI_Comm_size(MPI_COMM_WORLD, &nprocs);

MPI_Comm_rank(MPI_COMM_WORLD, &myrank);MPI_Get_processor_name(name, &len);name[len]= ’\0 ’;printf(” P r o z e s s %d ( von %d ) l a u f t a u f %s .\ n ”, myrank, nprocs, name);

15 MPI_Finalize();return EXIT_SUCCESS;

}

C-Funktion gethostname liefert. In len wird die Lange des Namens zuruckge-geben. Sie ist niemals großer als die Konstante MPI MAX PROCESSOR NAME. Dader MPI-Standard nicht explizit verlangt, dass die Zeichenkette, auf die name zeigt,nullterminiert ist, wird in Zeile 13 vorsichtshalber eine terminierende Null an dieZeichenkette angehangen.

Das Duo MPI Comm size und MPI Comm rank findet sich auch in unseremBeispiel mpiint.c zur numerischen Integration in Abschnitt 3.3. In diesem Pro-gramm verhalten sich die Prozesse je nach Rang unterschiedlich. Der Prozess mitdem Rang null soll von allen anderen Prozessen die Teilergebnisse empfangen undaufaddieren, alle anderen Prozesse schicken dazu ihr Teilergebnis an Prozess null.Diese Differenzierung der Prozesse nach ihrem Rang ist typisch fur MPI-Program-me. Alle Prozesse werden aus dem gleichen Programmcode generiert, aber der Kon-trollfluss in den Prozessen ist unterschiedlich. Der Prozess mit Rang null ist dabeikeineswegs ausgezeichnet, außer durch die Tatsache, dass es ihn unabhangig von derZahl der gestarteten Prozesse immer gibt. Dieses Schema wird in Anspielung aufFlynns Taxonomie (Notiz 2.1) auch SPMD (single program, multiple data) genannt.Im Unterschied zum SIMD-Schema (single instruction, multiple data) fuhrt jederProzess das gleiche Programm, aber nicht zwingend den gleichen Code aus.

7.2 Senden und Empfangen von Nachrichten

Herzstuck von MPI sind naturlich die Funktionen zum Austausch von Daten. Inmpiint.c (Listing 3.2) kommen zwei davon vor, MPI Send zum Senden undMPI Recv zum Empfangen einer Nachricht. Schauen wir uns zuerst die Funktionzum Senden genauer an.

int MPI_Send(void *buf, int count, MPI_Datatype type, int dest, int tag,MPI_Comm comm)

Page 177: [X.systems.press] Cluster Computing ||

7.2 Senden und Empfangen von Nachrichten 171

Im ersten Parameter buf wird der Sendefunktion mitgeteilt, wo die zu versenden-den Daten stehen, und im Parameter count, wieviele Datenelemente zu versendensind. Der Parameter type beschreibt den Typ der zu versendenden Datenelemente.Fur dessen Angabe stellt MPI einen Satz symbolischer Konstanten bereit, siehe Ta-belle 14.1 auf Seite 411. In mpiint.c wird ein Datenelement vom Typ doubleverschickt, dem entspricht der MPI-Datentyp MPI DOUBLE (Notiz 7.4).

Eine Nachricht braucht naturlich auch einen Empfanger. Wie man in MPI einenProzess spezifiziert, wissen wir aber schon: durch Angabe seines Ranges innerhalbeiner Gruppe. Bei MPI Sendwird der Empfanger der Nachricht entsprechend durchdest und comm festgelegt. In mpiint.c gehen alle Nachrichten an Rang null imKommunikator MPI COMM WORLD.

Der Parameter tag bietet eine Moglichkeit, Nachrichten voneinander zu unter-scheiden. In einer Anwendung tauschen die Prozesse gewohnlich viele Nachrichtenmiteinander aus, bei denen die Daten vom gleichen Typ aber von unterschiedlicherBedeutung sind. Mit dem Parameter tag kann man gewissermaßen ein Etikett uber-mitteln, das dem Empfanger z. B. anzeigt, ob eine gesendete double Zahl das End-ergebnis einer Berechnung ist oder dessen Fehlerschranke. In mpiint.c haben wirtag willkurlich auf 99 gesetzt. MPI erlaubt fur Etiketten Werte zwischen 0 und min-destens 32767. Eine Implementierung kann hier auch einen großeren Wertebereichzulassen.

Die Funktion zum Empfang einer Nachricht heißt MPI Recv.

int MPI_Recv(void *buf, int maxbuf, MPI_Datatype type, int source, int tag,MPI_Comm comm, MPI_Status &status)

Die ersten sechs Parameter korrespondieren zu den Parametern von MPI Send. DerEmpfangspuffer buf muss ein vom Empfanger-Prozess bereitgestellter Speichersein, der mindestens maxbuf Datenelemente des Typs type aufnehmen kann. Mitsource wird der Rang des erwarteten Absenders in der Gruppe comm angegeben.Der letzte Parameter status ist neu. Er enthalt nach dem Aufruf von MPI Recveinige Statusinformationen.

MPI Send und MPI Recv fuhren gemeinsam das aus, was man eine Punkt-zu-Punkt-Kommunikation nennt, eine Kommunikation zwischen genau zwei Teilneh-mern, einem Sender und einem Empfanger. Fur eine erfolgreiche Kommunikationmussen Sender und Empfanger zueinander passende Ubertragungsfunktionen aufru-fen. Zwei Ubertragungsfunktionen passen zueinander, wenn

• Absender- und Empfanger-Rang,• Etikett,• Datentyp und• Kommunikator

ubereinstimmen bzw. zueinander passen. Die Anzahlparameter von MPI Send undMPI Recv mussen dagegen nicht zwingend ubereinstimmen. Der Empfangspuffermuss lediglich groß genug sein, um die mit MPI Send verschickte Nachricht auf-nehmen zu konnen. Wenn Sie sich auf die Verwendung der MPI-Grunddatentypenaus Tabelle 14.1 beschranken, bedeutet dies, dass maxbuf ≥ count gelten muss.

Page 178: [X.systems.press] Cluster Computing ||

172 7 Grundlagen

Ist diese Bedingung bei ansonsten passenden Nachrichten verletzt, bricht MPI Recvmit einem entsprechenden Fehlercode ab.

Solange der Empfanger auf eine passende Nachricht von einem bestimmten Ab-sender wartet, werden alle anderen Nachrichten ignoriert, die eventuell schon vonanderen Prozessen abgeschickt wurden. Im Falle von mpiint.c kommt es aufdie Reihenfolge der empfangenen Nachrichten aber gar nicht an. In solchen Situa-tionen kann es zu Leistungseinbußen fuhren, wenn man trotzdem eine Reihenfolgevorschreibt. Statt auf die Nachricht eines bestimmten Absenders zu warten, sollteder Empfanger besser jede Nachricht akzeptieren, die bereits vorliegt, und diese wei-terverarbeiten. Diese Flexibilitat wird durch die Verwendung eines Jokers fur denAbsender moglich. Der Rang MPI ANY SOURCE passt auf jeden Absender. WennSie die Empfangsschleife in mpiint.c in

for (src=1; src<nprocs; ++src) {MPI_Recv(&x, 1, MPI_DOUBLE, MPI_ANY_SOURCE, 99, MPI_COMM_WORLD, &status);result+=x;

}

andern, so erwartet Prozess null die Teilergebnisse nicht mehr in einer festgelegtenReihenfolge. Probieren Sie es aus!

Auch fur das Etikett gibt es einen Joker, MPI ANY TAG passt auf jedes Etikett.Wir hatten im Empfanger das Etikett 99 auch durch MPI ANY TAG ersetzen konnen,was in unserem Fall aber keinen Effekt gehabt hatte.

Fur den Empfanger bedeutet die Verwendung von Jokern einen Informations-verlust, denn nach dem Empfang einer Nachricht mit MPI Recv(...,MPI ANYSOURCE,...)weiß der Empfanger ja nicht, von wem die Nachricht stammt. Unteranderem um diesen Informationsverlust auszugleichen, gibt es den letzten Parameterin MPI Recv. Die Variable vom Typ MPI STATUS ist eine Struktur mit den Kom-ponenten

typedef struct {int MPI_SOURCE;int MPI_TAG;int MPI_ERROR;...

} MPI_Status;

Nach Beendigung von MPI Recv kann der Empfanger hieraus sowohl den Absen-der status.MPI SOURCE als auch das Etikett status.MPI TAG der Nachrichtabfragen. Die Komponente MPI ERROR enthalt noch einmal den Fehlercode, denMPI Recv auch als Ruckgabewert liefert. Die Punkte stehen fur eine mogliche wei-tere implementationsspezifische Komponenten, auf die aber nicht direkt zugegriffenwerden kann (siehe Abschnitt 8.1.2). Diese Komponenten erlauben es, die Anzahlder tatsachlich ubertragenen Datenelemente festzustellen. Dafur gibt es die FunktionMPI Get count, die in count die Anzahl der tatsachlich ubertragenen Elementezuruckliefert.

int MPI_Get_count(MPI_Status *status, MPI_Datatype type, int *count)

Page 179: [X.systems.press] Cluster Computing ||

7.3 Kollektive Kommunikation 173

Eine typische Anwendung von MPI Get count ist das Sondieren einer eingehen-den Nachricht mit MPI Probe.

int MPI_Probe(int src, int tag, MPI_Comm comm, MPI_Status *stat)

Diese Funktion kehrt zum Aufrufer zuruck, sobald eine Nachricht vom Absendersrc mit Etikett tag zum Empfang vorliegt. Die Nachricht selbst wird dabei nichtempfangen, aber die Statusvariable wird gesetzt. Der Empfanger kann per MPI Getcount(&status,...) die Große der wartenden Nachricht ermitteln, genugendSpeicherplatz reservieren und die Nachricht schließlich mit MPI Recv empfangen.

In komplexen Anwendungen sind eine Menge Nachrichten unterwegs. Datentyp,Absenderangabe und Etikett konnen nicht in allen Fallen garantieren, dass zwei Nach-richten nicht miteinander vertauscht werden. Insbesondere die Benutzung von Jokernerhoht die Verwechslungsgefahr. Selbst bei einem vollstandigen Verzicht auf Jokerbleibt ein Restrisiko, da die konsistente Vergabe von Etiketten in der Verantwortungdes fehlbaren Programmierers liegt. Hier kommt die Rolle der Kommunikatoren alsKontext fur die Kommunikation ins Spiel. Der Kommunikator gehort wie der Daten-typ und das Etikett zur Signatur einer Nachricht. Dadurch werden zwei Nachrichtenmit verschiedenen Kommunikatoren niemals verwechselt. Ein Kommunikator defi-niert damit ein Universum, das eine Nachricht nicht einfach verlassen kann. Und an-ders als bei Etiketten gibt es fur Kommunikatoren keine Joker. Daruberhinaus liegtdas Kommunikator-Management (Abschnitt 8.1) vollstandig in der Verantwortungdes MPI-Systems, was Verwechslungen durch nachlassige Anwendungsprogrammeausschließt. Eine Bibliothek, die MPI benutzt, sollte ihre interne Kommunikation ineinem eigenen Kommunikator ablaufen lassen. Damit werden Konflikte mit Nach-richten außerhalb der Bibliotheksroutinen sicher vermieden. Ohne das Konzept desKommunikators ware eine zuverlassige Kapselung der bibliotheksinternen Kommu-nikation nicht moglich.

7.3 Kollektive Kommunikation

7.3.1 Daten verteilen mit MPI Bcast

Mit MPI Send und MPI Recv kann man nur Nachrichten von genau einem Pro-zess an genau einen anderen Prozess schicken (Punkt-zu-Punkt-Kommunikation).In parallelen Anwendungen kommt es aber haufig vor, dass ein Prozess Daten anmehrere andere Prozesse schicken mochte. Das lasst sich naturlich uber eine Abfol-ge von Punkt-zu-Punkt-Nachrichten realisieren, aber viel eleganter geht das mit derRundsende-Funktion MPI Bcast.

int MPI_Bcast(void *buf, int count, MPI_Datatype type, int root,MPI_Comm comm)

MPI Bcast verschickt die in buf abgelegten Daten an alle Prozesse der Gruppecomm. Sie ist dabei Sende- und Empfangsfunktion zugleich und muss von allen Pro-zessen der Gruppe aufgerufen werden. Der Parameter root enthalt den Rang des

Page 180: [X.systems.press] Cluster Computing ||

174 7 Grundlagen

SendenZeit

P0

P0

P0

P0

P1

P2P1

P3P2P1 P4 P5 P6

P3

P7

Abb. 7.1. Effizientes Rundsenden mit MPI Bcast.

Senders, d. h. des Prozesses, der die Daten verteilt. Am besten merken Sie sich: Vordem Aufruf von MPI Bcast kennt nur ein Prozess (root) den Inhalt von buf,nach dem Aufruf kennen alle Prozesse diesen Inhalt.

Nehmen wir als Beispiel an, dass der Prozess mit Rang null den Wert einer Ganz-zahlvariablen n allen anderen Prozessen mitteilen mochte. Das geht entweder miteiner Schleife uber Punkt-zu-Punkt-Nachrichten

if (myrank==0)for (dest=1; dest<nprocs; ++dest)

MPI_Send(&n, 1, MPI_INT, dest, tag, comm);else

MPI_Recv(&n, 1, MPI_INT, 0, tag, comm, &status);

oder aber viel eleganter und kurzer mit der Funktion MPI Bcast.

MPI_Bcast(&n, 1, MPI_INT, 0, comm);

MPI Bcast muss so von allen Prozessen in comm aufgerufen werden, denn sieist eine kollektive Kommunikationsfunktion. Kollektive Kommunikationsfunktionenmussen grundsatzlich von allen Prozessen des verwendeten Kommunikators gemein-sam ausgefuhrt werden.

Die ursprunglich verwendete Schleife uber MPI Send induziert eine Reihenfol-ge des Datentransfers, die uberflussig ist. Ohne vorgeschriebene Reihenfolge kannder gesamte Nachrichtenaustausch viel effizienter organisiert werden, namlich paral-lel. Abbildung 7.1 zeigt, wie das fur acht Prozesse geht. Im ersten Zeitschritt schicktProzess 0 seine Daten an Prozess 1. In den folgenden Zeitschritten beteiligen sichdann all die Prozesse am Versenden, die die Daten schon selbst empfangen haben. Da-durch sind schon nach dem dritten Zeitschritt alle Prozesse im Besitz der Nachricht.Eine Schleife uber MPI Send hatte sieben Zeitschritte benotigt. Im Allgemeinenbenotigt ein Broadcast an p Prozesse mit dieser Strategie genau �log2 p� Zeitschritte.Das ist deutlich schneller als die p−1 Zeitschritte der Schleifenlosung. Bei hundertProzessen auf einem typischen Cluster betragt der Geschwindigkeitsfaktor schon 15.Der MPI-Standard schreibt keineswegs vor, dass MPI Bcast ein solches parallelesSchema verwenden muss, aber in den meisten MPI-Bibliotheken ist MPI Bcast soimplementiert, wie in Abb. 7.1 angedeutet (Notiz 7.5).

Bei der Verwendung der MPI Bcast-Funktion sind einige Besonderheiten zubeachten.

Page 181: [X.systems.press] Cluster Computing ||

7.3 Kollektive Kommunikation 175

• Nachrichten, die mit MPI Bcast verschickt werden, konnen nicht mit MPIRecv empfangen werden. Wenn Sie das versuchen, wird Ihre Anwendunghangenbleiben oder absturzen. Der Grund dafur ist, dass in einer effizienten Im-plementierung wie in Abb. 7.1 Empfanger auch zu Sendern werden. Ein Prozess,der die Nachricht mit MPI Recv empfangt, fallt als Sender aber aus.

• Anders als bei der Punkt-zu-Punkt-Kommunikation muss der Anzahlparameterbei MPI Bcast uberall den exakt gleichen Wert haben. Der Grund ist auchhier die Zwitternatur der Prozesse als Sender und Empfanger. Mit nutzerspezi-fischen Datentypen ergibt sich allerdings eine Lockerung dieser Regel, siehe Ab-schnitt 8.3.4.

• MPI Bcast verwendet keine Etiketten. Das kann bei unglucklicher Program-mierung dazu fuhren, dass Nachrichten vertauscht werden. Beispiel: Prozess 0mochte zwei Zahlen x = 47 und y = 11 an alle anderen Prozesse verschickenund ruft dazu zweimal hintereinander MPI Bcast auf. Prozess 1 ruft ebenfallszweimal MPI Bcast auf, allerdings mit vertauschten Argumenten:

Zeit Prozess 0 Prozess 1MPI Bcast(&x,...); MPI Bcast(&y,...);↓MPI Bcast(&y,...); MPI Bcast(&x,...);

Wenn x und y (wie hier) vom gleichen Datentyp sind, bemerkt MPI diesen Unter-schied nicht, und Prozess 1 erhalt das falsche Paar x = 11, y = 47.

• MPI Bcast verwendet keine Statusvariable. Das ist auch nicht notig, da allebeteiligten Prozesse vollstandig uber die Nachricht informiert sind.

7.3.2 Synchronisation

Obwohl MPI Bcast von allen Prozessen einer Gruppe aufgerufen wird, heißt dasnicht, dass MPI Bcast die Prozesse in irgendeiner Weise synchronisiert. WennMPI Bcast in einem Prozess die Kontrolle an den Aufrufer zuruckgibt, bedeutetdas nur, dass der Absender root inzwischen MPI Bcast aufgerufen haben muss.

Listing 7.2. Beispiel mit nicht deterministischen send-receive-Paarungen.

switch(rank) {case 0:

MPI_Bcast(buf1, count, type, 0, comm);MPI_Send(buf2, count, type, 1, tag, comm);break;

case 1:MPI_Recv(buf2, count, type, MPI_ANY_SOURCE, tag, comm);MPI_Bcast(buf1, count, type, 0, comm);MPI_Recv(buf3, count, type, MPI_ANY_SOURCE, tag, comm);break;

case 2:MPI_Send(buf2, count, type, 1, tag, comm);MPI_Bcast(buf1, count, type, 0, comm);break;

}

Page 182: [X.systems.press] Cluster Computing ||

176 7 Grundlagen

P0 P1 P2

MPI_Bcast

MPI_Send

MPI_Bcast

MPI_Send

MPI_Recv

MPI_Bcast

MPI_Recv MPI_Send

MPI_Bcast

MPI_Send

MPI_Bcast

MPI_Recv

MPI_Bcast

MPI_Recv

Abb. 7.2. Nicht deterministische send-receive-Paarungen. Das obere Szenario wird nur er-zwungen, wenn MPI Bcast die Prozesse synchronisieren wurde.

Uber den Zustand der anderen Prozesse relativ zu MPI Bcast kann man dagegenkeine verlasslichen Annahmen machen. In vielen Implementierungen gehen kollek-tive Operationen wie MPI Bcast zwar mit einer Synchronisation einher, aber derMPI-Standard verlangt dies nicht, und man sollte sich deshalb auch nicht darauf ver-lassen. Betrachten wir das Beispiel aus Listing 7.2 mit drei Prozessen. Der Program-mausschnitt ist syntaktisch korrekt, aber das Ergebnis ist nicht determiniert. Alle dreiProzesse nehmen an einem Broadcast teil, die Prozesse 0 und 2 senden daruberhin-aus je eine Nachricht an Prozess 1. Da MPI Bcast die Prozesse nicht synchronisiert,sind zwei Szenarien moglich (Abb. 7.2). Wir haben hier ein Beispiel fur eine racecondition. Das Ergebnis hangt davon ab, welche Nachricht zuerst beim Empfangerankommt. Race conditions sind sehr schwer zu entdecken, besonders dann, wennTestlaufe scheinbar determiniert sind und nur in sehr seltenen Fallen ein anderes

MPI_Barrier MPI_Barrier MPI_Barrier MPI_Barrier MPI_Barrier

MPI_Barrier

MPI_Barrier

MPI_Barrier MPI_Barrier

MPI_BarrierMPI_Barrier

MPI_Barrier

MPI_Barrier

MPI_Barrier

MPI_Barrier

P0

P1

P2

Zeit

Abb. 7.3. Synchronisation von Prozessen mit MPI Barrier. Der Pfeil symbolisiert jeweilsdie Position im Programmfluss.

Page 183: [X.systems.press] Cluster Computing ||

7.3 Kollektive Kommunikation 177

Ergebnis liefern. Eine Vermeidungsstrategie besteht darin, kollektive Operationenniemals in Codeabschnitten zu verwenden, die sich auf verschiedenen Rangen unter-scheiden.

Es gibt Situationen, in denen man Prozesse explizit synchronisieren mochte (sie-he z. B. Abschnitt 7.4.2). Dafur bietet MPI die Funktion MPI Barrier.

int MPI_Barrier(MPI_Comm comm)

Auch MPI Barrier ist eine kollektive Funktion, d. h., sie muss von allen Prozessenin comm aufgerufen werden. Wenn Sie das nicht beachten, bemerken Sie das aller-dings sofort, denn MPI Barrier kehrt erst dann zum Aufrufer zuruck, nachdemdie Funktion von allen Prozessen in comm aufgerufen wurde (Abb. 7.3). Der NameBarrier unterstreicht diese Wirkung: Die Prozesse sammeln sich vor dem ”Hinder-niss“, das gemeinsam uberwunden wird, sobald alle angekommen sind.

7.3.3 Kollektive Varianten

Das Rundsenden an alle Prozesse mit MPI Bcast ist nur eine von insgesamt vier-zehn kollektiven Operationen des MPI-Standards. Andere kollektive Funktionen er-lauben die Verteilung von Daten in verschiedenen Varianten (Abb. 7.4). In einer die-ser Varianten verfugt ein Prozess (root) uber mehrere Datenelemente, die auf alleanderen Prozesse verteilt werden sollen. Dazu rufen alle Prozesse MPI Scatterauf.

int MPI_Scatter(void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, int recvcount, MPI_Datatype recvtype,int root, MPI_Comm comm)

Die ersten drei Parameter beschreiben die zu versendenden Daten, die naturlich nurdem root-Prozess bekannt sind und darum auf den anderen Prozessen ignoriertwerden. Die nachsten drei Parameter beschreiben die Daten, die bei den Empfangernankommen. Die Anzahlparameter sendcount und recvcount bestimmen dabeidie Anzahl der Datenelemente pro Prozess, d. h., bei p Prozessen versendet rootinsgesamt p ·sendcount Datenelemente. Zum Beispiel fuhrt

int sendbuf[6]={3, 14, 15, 92, 65, 35};int recvbuf[2];...MPI_Scatter(sendbuf, 2, MPI_INT, recvbuf, 2, MPI_INT, 0, comm);

auf drei Prozessen zu folgender Verteilung:

Prozess recvbuf

0 { 3, 14}1 {15, 92}2 {65, 35}

Alle Prozesse außer root ignorieren sendbuf, Sie brauchen dafur keinen Spei-cherplatz zu reservieren. Der root-Prozess verwendet dagegen sowohl den Sende-als auch den Empfangspuffer, er sendet gewissermaßen an sich selbst.

Page 184: [X.systems.press] Cluster Computing ||

178 7 Grundlagen

D

B

A

C

DCBA

1

2

3

0P

P

P

P

1

2

3

0P

P

P

P

DCBA

DCBA

DCBA

DCBAD

B

A

C1

2

3

0P

P

P

P

1

2

3

0P

P

P

P

1

2

3

0P

P

P

P

1

2

3

0P

P

P

P

1

2

3

0P

P

P

P

1

2

3

0P

P

P

P

A3

A2

A1

A0

B2

B3

B1

B0 C0

D3

D2

D1

D0

C3

C2

C1

D0

C0

B0

A0

C1

D1

B1

A1 A2

D3

C3

B3

A3

D2

C2

B2

A

A

A

A

A

MPI_Bcast

MPI_Scatter

MPI_Gather

MPI_Allgather

MPI_Alltoall

Abb. 7.4. Kollektiver Datentransfer mit MPI.

Das Gegenstuck zu MPI Scatter heißt

int MPI_Gather(void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, int recvcount, MPI_Datatype recvtype,int root, MPI_Comm comm)

und organisiert den Datenfluss genau umgekehrt zu MPI Scatter. Die Daten al-ler Prozesse werden von root gesammelt und nach Absenderrang geordnet inrecvbuf abgelegt. Auch hier wird recvbuf von allen Prozessen außer rootignoriert, und root schickt sich selbst Daten in seinen Empfangspuffer. Wahrendbei MPI Gather ein Prozess als Empfanger der Daten ausgezeichnet ist, fuhrt

int MPI_Allgather(void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, int recvcount, MPI_Datatype recvtype,MPI_Comm comm)

dazu, dass alle Prozesse die gleichen Daten erhalten. Hierbei muss naturlich jederProzess ausreichend Speicher in recvbuf zur Verfugung stellen. MPI Allgatherentspricht effektiv einem MPI Gather, gefolgt von einem MPI Bcast.

Eine Art Kombination von MPI Gather und MPI Scatter wird durch

int MPI_Alltoall(void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, int recvcount, MPI_Datatype recvtype,MPI_Comm comm)

Page 185: [X.systems.press] Cluster Computing ||

7.3 Kollektive Kommunikation 179

realisiert. Hier schickt jeder Prozess unterschiedliche Daten an jeden Prozess. DenDatenfluss stellt man sich am besten an Hand einer Matrix vor (Abb. 7.4). Vor MPIAlltoall verfugt Prozess k uber die k-te Zeile der Matrix, nach MPI Alltoallauch uber die k-te Spalte.

Fur alle kollektiven Operationen dieses Kapitels gilt:

• Anzahl und Typ der Datenelemente von Sender und Empfanger mussen gleichsein. Mit der Verwendung nutzerspezifischer MPI-Datentypen ergeben sich hierallerdings etwas flexiblere Regeln, siehe Abschnitt 8.3.

• Aliasing ist nicht erlaubt, die Speicherbereiche sendbuf und recvbuf durfensich nicht uberlappen.

• Der Verzicht auf Etiketten kann wie bei MPI Bcast zu Verwechslungen fuhren.

7.3.4 Mehr Variabilitat mit v

MPI Scatter, MPI Gather und ihre All-Varianten verwenden bei der Datenver-teilung ein starres Schema. Alle Prozesse erhalten bzw. versenden dieselbe Anzahlvon Datenelementen und die Positionierung der Daten im Sende- bzw. Empfangsspei-cher erfolgt in zusammenhangenden, nicht uberlappenden Speicherbereichen. DiesesSchema ist nicht immer angemessen. Sehr viel flexibler ist die Variante

int MPI_Scatterv(void *sendbuf, int *sendcounts, int *displs,MPI_Datatype sendtype,void *recvbuf, int recvcount, MPI_Datatype recvtype,int root, MPI_Comm comm)

der Scatter-Operation. Das zusatzliche ”v“ steht fur variabel. Variabel ist hier sowohldie Anzahl der Datenelemente, die an die einzelnen Range verteilt wird, als auchderen Position im Sendepuffer sendbuf (siehe Abb. 7.5).

Große und Ort der versendeten Datenblocke werden in den beiden Feldernsendcounts und displs festgelegt.

• sendcounts[i] enthalt die Anzahl der an Prozess i zu versendenden Daten-elemente.

• displs[i] legt den Beginn des Datenblocks fur Prozess i relativ zu sendbuffest.

rootroot

P P

P P

P P

P P

33

22

11

00

Abb. 7.5. Im Vergleich zu MPI Scatter (links) erlaubt MPI Scatterv (rechts) das Ver-senden von Datenblocken, die unterschiedlich groß sein durfen und von frei wahlbaren Posi-tionen innerhalb des Sendepuffers stammen konnen.

Page 186: [X.systems.press] Cluster Computing ||

180 7 Grundlagen

Ansonsten verhalt sich MPI Scatterv genauso wie MPI Scatter. Insbesonderemuss auch bei MPI Scatterv die Anzahl der empfangenen Datenelemente mit derAnzahl der gesendeten Datenelemente ubereinstimmen. In der Regel wird der Aufrufauf Prozess myrank so aussehen:

MPI_Scatterv(sendbuf, counts, displs, type,recvbuf, counts[myrank], type, root, comm);

Ein einfaches Beispiel: Der Codeabschnitt

char sendbuf[]=” v e r t e i l e d i e s e Daten ”;int counts[3]={8, 5, 5};int displs[3]={0, 9, 15};...MPI_Scatterv(sendbuf, counts, displs, MPI_CHAR,

recvbuf, counts[myrank], MPI_CHAR, root, comm);

auf drei Prozessen fuhrt dazu, dass die Prozesse 0, 1 und 2 jeweils die Zeichenkette

”verteile“, ”diese“ und ”Daten“ in recvbuf erhalten.Die Funktion MPI Scatterv ist insbesondere dann nutzlich, wenn die Anzahl

der Datenelemente nicht fur alle Prozesse gleich ist. Betrachten wir als Beispiel dieLosung der eindimensionalen Wellengleichung

∂ 2u(x, t)∂ t2 = c2 ∂ 2u(x, t)

∂x2 (7.1)

mit den Anfangsbedingung u(x,0) = u0(x) und ∂u(x,t)∂ t

∣∣∣t=0

= v0(x) sowie den Randbe-

dingungen u(0, t) = u(L, t) = 0 (eingespannte Saite). Zur numerischen Losung wer-den Raum und Zeit diskretisiert,

x = i∆x, t = j ∆ t . (7.2)

Mit ν(i, j) = u(i∆x, j ∆ t) lassen sich die Differentiale durch finite Differenzen ap-proximieren.

∂ 2u(x, t)∂ t2 ν(i, j +1)+ν(i, j−1)−2ν(i, j)

∆ t2

∂ 2u(x, t)∂x2 ν(i+1, j)+ν(i−1, j)−2ν(i, j)

∆x2

(7.3)

Die Diskretisierungen (7.2) und (7.3) in die Wellengleichung eingesetzt, ergibt mitc′ = ∆x/∆ t die Differenzengleichung

ν(i, j +1) =c2

c′2[ν(i+1, j)+ν(i−1, j)]+2

(1− c2

c′2

)ν(i, j)−ν(i, j−1) . (7.4)

Diese Gleichung wird nun uber j iteriert, wodurch wir aus den Auslenkungen ν(i,0)und ν(i,1) zu den Zeitpunkten t = 0 und t = ∆ t die Auslenkung ν(i,2) erhalten, undso weiter. Die notwendigen Anfangswerte fur i = 0,1, . . . ,n mit n = L/∆x sowie j =

Page 187: [X.systems.press] Cluster Computing ||

7.3 Kollektive Kommunikation 181

P1 P2P0

u

0 x L

Abb. 7.6. Gebietszerlegung fur die parallele Losung der eindimensionalen Wellengleichungmit drei Prozessen.

0,1 werden durch die Anfangsbedingungen u(x,0) = u0(x) und ∂u(x,t)∂ t

∣∣∣t=0

= v0(x)

vorgegeben.

ν(i,0) = u0(i∆x)

ν(i,1) =12

c2

c′2[ν(i+1,0)+ν(i−1,0)]+

(1− c2

c′2

)ν(i,0)+∆ t · v0(i∆x)

(7.5)

Wobei wir fur die Ableitung der Anfangsbedingung ν(i,1) die Naherung

v0(i∆x) ν(i,1)−ν(i,−1)

2∆ t(7.6)

verwendet und Gleichung (7.4) einmal iteriert haben.Die Iteration der Gleichung (7.4) kann fur verschiedene Orte i unabhangig durch-

gefuhrt werden. Als Parallelisierungsstrategie bietet sich deshalb die Gebietszerle-gung (domain decomposition) an. Dabei ist jeder Prozess fur einen zusammenhangen-den Abschnitt der x-Achse zustandig (siehe Abb. 7.6). Zur parallelen Losung der Wel-lengleichung mussen zunachst die Vektoren der Anfangsbedingungen (7.5) stuckwei-se an die einzelnen Prozesse verteilt werden. Wenn N die Anzahl aller Datenpunkteist und p die Zahl der Prozesse, so liefert

N=n+1; / * n+1 Da tenpunk te b e i i =0 ,1 , . . . , n * /for (i=0; i<p; ++i) {

displs[i]=(i*N)/p;counts[i]=((i+1)*N)/p-(i*N)/p;

}

die Parameter fur die Verteilung mit MPI Scatterv. In Abb. 7.6 ist p = 3 und N =26, d. h., der erste Prozess erhalt acht Datenelemente, der zweite und dritte Prozessje neun.

Aus der Iterationsgleichung (7.4) ist ersichtlich, dass die Iteration am Ort i aufdie Nachbarpunkte i− 1 und i + 1 zugreift. Fur die parallele Berechnung der Itera-tionsgleichung (7.4) bedeutet dies, dass jeder Prozess fur jede Iteration Daten vonden Prozessen benotigt, die die benachbarten Gebiete verwalten. In Abb. 7.6 habenwir das durch uberlappende Zustandigkeitsbereiche angedeutet. Wir werden in Ab-schnitt 9.2 noch sehen, wie man diesen Datenaustausch zwischen benachbarten Pro-zessen am besten organisiert.

Page 188: [X.systems.press] Cluster Computing ||

182 7 Grundlagen

Bei der Verteilung der Anfangsdaten liegt es nahe, mit MPI Scatterv durchentsprechende Wahl von counts und displs uberlappende Datenblocke aussendbuf zu versenden. Das wird tatsachlich in einigen Lehrbuchern empfohlenund wird in der Praxis vermutlich auch funktionieren. Der MPI-Standard ist in dieserAngelegenheit allerdings unmissverstandlich [102]: The specification of counts andtypes should not cause any location on the root to be read more than once. Die Ver-wendung uberlappender Datenblocke ist deshalb nicht standard-konform und sollteunterbleiben. Der Grund fur diese Einschrankung liegt in der angestrebten Symme-trie zur ”Umkehroperation“ MPI Gatherv, die einen zu MPI Scatterv umge-kehrtem Datenfluss implementiert.

int MPI_Gatherv(void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, int* recvcounts, int *displs,MPI_Datatype recvtype, int root, MPI_Comm comm)

Hier waren uberlappende Datenblocke in recvbuf naturlich fatal. Dank der Sym-metrie zwischen beiden Operationen konnen die verteilten Anfangsdaten am Endeder Rechnung mit denselben Feldern counts und displs wieder eingesammeltwerden. Auch die beiden All-Operationen haben variable Varianten. Die Syntax furMPI Allgatherv und MPI Alltoallv finden Sie im Anhang 14.7.

7.3.5 Daten zusammenfassen mit MPI Reduce

Am Ende der parallelen numerischen Integration (Listing 3.2 auf Seite 46) sendenalle Prozesse ihr Teilergebnis an Prozess mit dem Rang null, der die Teilergebnissezum Gesamtergebnis aufsummiert. Dieses Zusammenfassen von Teilergebnissen istein haufiges Motiv in parallelen Anwendungen, weshalb der MPI-Standard dafureine spezielle kollektive Funktion bereitstellt. Die Funktion

int MPI_Reduce(void *data, void *result, int count, MPI_Datatype type,MPI_Op op, int root, MPI_Comm comm)

wird von allen Prozessen der Gruppe comm aufgerufen und hat folgenden Effekt:Der Operator op (z. B. Addition) wird auf die Datenelemente data aller Prozesseangewandt, und das Ergebnis wird in result des Prozesses root abgelegt. Inunserem Beispiel der numerischen Integration konnen wir die Code-Sequenz

if (myrank!=0)MPI_Send(&x, 1, MPI_DOUBLE, 0, 99, MPI_COMM_WORLD);

elsefor (src=1; src<nprocs; ++src) {

MPI_Recv(&x, 1, MPI_DOUBLE, MPI_ANY_SOURCE, 99, MPI_COMM_WORLD,&status);

result+=x;}

auch durch

MPI_Reduce(&x, &result, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);

ersetzen.

Page 189: [X.systems.press] Cluster Computing ||

7.3 Kollektive Kommunikation 183

Der MPI-Standard bietet eine Reihe vordefinierter Reduktionsoperatoren, sieheTabelle 14.2 auf Seite 412. So kann man mit MPI Reduce z. B. durch Angabevon MPI MIN bzw. MPI MAX als Reduktionsoperator das Minimum oder das Ma-ximum verteilter Daten berechnen (siehe Listing 7.3). Der Reduktionsoperator inMPI Reduce wirkt elementweise auf die Daten, d. h., ein Aufruf von

double v[5], result[5];...MPI_Reduce(v, result, 5, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD);

bewirkt, dass Prozess null insgesamt funf Maxima erhalt, result[0] enthalt dasMaximum von v[0] aller Prozesse, result[1] das Maximum von v[1] usw.Das Programm aus Listing 7.3 liefert z. B. folgende Ausgabe:

mertens@node1:˜/src$ mpirun -np 3 demo-reduceProcess 0 (data): 112 84 96 151 110Process 1 (data): 122 105 131 146 154Process 2 (data): 102 66 126 73 109MPI_Reduce:Process 0 (Max.): 122 105 131 151 154Process 0 (Min.): 102 66 96 73 109Process 0 (GGT ): 2 3 1 1 1

Der MPI-Standard erlaubt auch die Definition eigener Reduktionsoperatoren.Das haben wir in Listing 7.3 beispielsweise mit MPI GGT gemacht, denn MPI bie-tet von Haus aus keinen Reduktionsoperator, der zwei Zahlen durch ihren großtengemeinsamen Teiler (ggT) ersetzt. Um MPI Reduce mit einem eigenen Operatorausfuhren zu konnen, muss der Operator in einer Routine, deren Prototyp dem TypMPI User function entspricht, definiert werden.

typedef void MPI_User_function(void *invec, void *inoutvec, int *len,MPI_Datatype *datatype)

Dabei bezeichnen die ersten beiden Argumente Vektoren der Lange *len, deren Ele-mente vom Type *datatype elementweise verknupft werden sollen. Das Ergebnisder Verknupfung wird in inoutvec geschrieben. Diese Funktion bildet das ersteArgument der Funktion MPI Op create.

int MPI_Op_create(MPI_User_function *funct, int commute, MPI_Op *op)

Sie verknupft eine vom Benutzer definierte Funktion funct mit einem MPI-Ope-rator op, welcher dann in MPI Reduce verwendet werden kann. Mit commutewird angegeben, ob die Reduktion kommutativ ist (commute �= 0) oder nicht(commute = 0). Bei nicht kommutativen Operatoren wird in der Reihenfolge auf-steigender Range reduziert. Die Assoziativitat der Operatoren wird vorausgesetzt,um ein eindeutiges Ergebnis bei mehr als zwei Datenelementen zu garantieren (No-tiz 7.7).

Die vorgeschriebene Signatur der benutzerdefinierten Funktion verlangt als Ar-gumente generische Zeiger und ein Datentyp-Argument und ist damit so angelegt,dass ein Operator-Objekt fur unterschiedliche Datentypen verwendet werden kann.So kann MPI SUMDaten der Typen int, long, float und double addieren. Der

Page 190: [X.systems.press] Cluster Computing ||

184 7 Grundlagen

Listing 7.3. Das Programm demo-reduce.c berechnet Maximum, Minimum und großtengemeinsamen Teiler von Zufallszahlen.

#include <stdio.h>#include <stdlib.h>#include <time.h>#include ” mpi . h ”

5void print_data(int p, const char *prompt, const int *d, int count) {

int k;printf(” P r o c e s s %d (%s ) : ”, p, prompt);for (k=0; k<count; ++k)

10 printf(”%4d ”, d[k]);printf(”\n ”);

}

void MPI_Ggt(void *in, void *inout, int *len, MPI_Datatype *type) {15 int i, m, n, t;

if (*type!=MPI_INT)MPI_Abort(MPI_COMM_WORLD, MPI_ERR_OP);

int *a=(int *)in, *b=(int *)inout;for (i=0; i<*len; ++i) {

20 m=abs(a[i]);n=abs(b[i]);while (n>0) {

t=m%n; m=n; n=t;}

25 b[i]=m;}

}

int main(int argc, char *argv[]) {30 const int dim=5;

int myrank, nprocs, p, data[dim], result[dim];MPI_Status status;MPI_Op MPI_GGT;

35 MPI_Init (&argc, &argv);MPI_Comm_size(MPI_COMM_WORLD, &nprocs);MPI_Comm_rank(MPI_COMM_WORLD, &myrank);MPI_Op_create(&MPI_Ggt, 1, &MPI_GGT);srand((myrank+17) * time(NULL));

40 for (p=0; p<dim; ++p)data[p]=64+rand()%93;

print_data(myrank, ” d a t a ”, data, dim);MPI_Barrier(MPI_COMM_WORLD);if (myrank==0) printf(” MPI Reduce :\ n ”);

45 MPI_Reduce(data, result, dim, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);if (myrank==0) print_data(0, ”Max . ”, result, dim);MPI_Reduce(data, result, dim, MPI_INT, MPI_MIN, 0, MPI_COMM_WORLD);if (myrank==0) print_data(0, ”Min . ”, result, dim);MPI_Reduce(data, result, dim, MPI_INT, MPI_GGT, 0, MPI_COMM_WORLD);

50 if (myrank==0) print_data(0, ”GGT ”, result, dim);MPI_Op_free(&MPI_GGT);MPI_Finalize();return EXIT_SUCCESS;

}

Page 191: [X.systems.press] Cluster Computing ||

7.3 Kollektive Kommunikation 185

SendenZeit

⊕ ⊕ ⊕

P0

P0

P0

P0

P4

P4P2

P3P2P1 P4 P5 P6

P6

P7

Abb. 7.7. Parallele Organisation einer Reduktionsoperation ⊕ mittels parallelem Prafixsum-menalgorithmus.

Compiler ubersetzt allerdings ohne Murren einen Aufruf von MPI Reduce, bei demMPI SUM auf Daten des Typs MPI CHAR angewendet wird. Ein solches Programmwurde naturlich Unsinn liefern oder besser mit einer geeigneten Fehlermeldung aus-steigen. In unserem Beispiel bricht die Funktion MPI Ggt die ganze Anwendung viaMPI Abort ab, wenn sie etwas anderes als Daten vom Typ MPI INT verarbeitensoll. Die Erweiterung auf Typen wie MPI LONG und MPI UINT ist offensichtlich.

Wird die Funktion MPI Abort von irgendeinem Prozess aufgerufen, so brichtsie alle Prozesse innerhalb des Kommunikators comm ab. Ihr Prototyp lautet:

int MPI_Abort(MPI_Comm comm, int errorcode)

Der Fehlercode errorcode kann als Ruckgabewert der Funktion main zuruck-gegeben werden, muss aber nicht. Das hangt von der MPI-Implementation ab. Indiesem Fall verhalt sich MPI Abort ahnlich wie die C-Funktion exit. AußerMPI Abort darf keine MPI-Funktion innerhalb der benutzerdefinierten Reduktions-funktion aufgerufen werden.

Nach Gebrauch sollten die von einem benutzerdefinierten Operator belegten Res-sourcen durch einen Aufruf von MPI Op free wieder freigegeben werden.

int MPI_Op_free(MPI_Op *op)

Danach hat op den Wert MPI OP NULL, siehe auch Abschnitt 8.1.2.Wenn Sie den Abschnitt 7.3.1 uber MPI Bcast aufmerksam gelesen haben, ah-

nen Sie sicher, wie man auch das Zusammenfassen von Daten parallelisieren kann.Nehmen wir an, dass acht Prozessoren uber je ein Teilergebnis verfugen und die Sum-me aller Teilergebnisse beim Prozess mit dem Rang null landen soll. Dazu sendendie Prozesse 2k+1 (mit k = 0, . . . ,3) parallel jeweils ihr Teilergebnis an den Prozess2k, (siehe Abb. 7.7). Die Prozesse 0, 2, 4 und 6 addieren das empfangene Teilergeb-nis zum dem ihrigen hinzu. Mit diesen vier Prozessen wiederholt sich das Spiel. DerProzess mit der Nummer 2 sendet seine Summe an 0, 6 an 4, und die Prozesse 0 und4 addieren wieder. Zum Schluss muss nur noch Prozess 4 seine Summe an 0 schickenund nach einer letzten Addition kann der Prozess 0 das Ergebnis ausgeben. DiesesVerfahren erfordert bei p Prozessen nur �log2 p� Zeitschritte und wird auch Prafix-summenalgorithmus genanannt. Genau wie bei MPI Bcast schreibt der Standard

Page 192: [X.systems.press] Cluster Computing ||

186 7 Grundlagen

0 10 20 30 40 50 60 70

0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75

Spee

dup

S(p)

idealn = 106

n = 105

n = 104

0

0,1

0,2

0,3

0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75

sequ

entie

ller A

ntei

l f

Zahl Prozessoren p

Abb. 7.8. Parallele numerische Integration mit n Stutzstellen. Speedup (oben) und Karp-Flatt-Metrik (1.14) (unten), nicht gefullte Symbole: MPI Send/MPI Recv, gefullte Symbole:MPI Reduce. Die Messungen wurden auf einem Cluster mit PIII 800 Mhz CPUs und Fast-Ethernet-Vernetzung durchgefuhrt.

nicht vor, dass MPI Reduce einen Prafixsummenalgorithmus verwendet, aber diemeisten MPI-Implementierungen lassen sich diesen Effizienzgewinn nicht entgehen.

Abbildung 7.8 zeigt Speedup und Karp-Flatt-Metrik der parallelen numerischenIntegration mit mpiint.c. Wie zu erwarten steigt die Effizienz mit der Anzahl derStutzstellen (Granularitat), aber auch der Effizienzgewinn durch MPI Reduce istdeutlich zu sehen. Das Anwachsen des empirisch sequentiellen Anteils f mit derZahl der Prozessoren bedeutet, dass die Kommunikation die parallelen Reibungsver-luste dominiert, zumindest bei feiner Granularitat. Es zahlt sich also aus, die Kom-munikation durch kollektive Operationen wie MPI Reduce moglichst effizient zugestalten.

Hier noch ein paar ”Sicherheitshinweise“ fur den Umgang mit MPI Reduce:

• Bei MPI Reduce gibt es keine Etiketten zur Unterscheidung von Nachrichten,darum besteht eine ahnliche Verwechslungsgefahr wie bei MPI Bcast. Auf dersicheren Seite ist man, wenn die Codeabschnitte mit MPI Reduce bei allen Pro-zessen identisch sind und nicht nach dem Rang unterschieden wird.

• Alle Prozesse (nicht nur der Empfanger-Prozess root) mussen ausreichend Spei-cher fur das Ergebnis result bereitstellen. Das liegt auf der Hand, wenn man

Page 193: [X.systems.press] Cluster Computing ||

7.3 Kollektive Kommunikation 187

den baumartigen Datenfluss aus Abb. 7.7 zu Grunde legt, in dem jeder Prozesssowohl Sender als auch Empfanger von (Zwischen-)Ergebnissen sein kann.

• Wenn man die Daten nach der Reduktion sowieso nicht mehr braucht, liegt esnahe, fur Daten und Ergebnis denselben Speicherbereich zu nutzen, also mit

double data[5];...MPI_Reduce(data, data, 5, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);

den Speicherbedarf auf jedem Knoten zu halbieren. Ein solches aliasing vonDaten ist in MPI generell verboten und wird mit unsinnigen Ergebnissen oderabsturzenden Programmen bestraft. Der Inhalt des Ergebnis-Speichers ist aller-dings nur fur den root Prozess definiert.

Nach dem Aufruf von MPI Reduce verfugt nur ein Prozess (root) uber das Ergeb-nis der Reduktion. Sollen alle Prozesse uber das Ergebniss verfugen, verwendet manstattdessen die Funktion MPI Allreduce.

int MPI_Allreduce(void *data, void *result, int count,MPI_Datatype type, MPI_Op op, MPI_Comm comm)

MPI Allreduce entspricht syntaktisch einem MPI Reduce ohne root-Prozessund semantisch einem MPI Reduce gefolgt von einem MPI Bcast. Eine effizienteImplementierung von MPI Allreduce wird den Datenfluss dabei so organisieren,dass genau wie bei MPI Bcast und MPI Reduce nach �log2 p� Zeitschritten alleserledigt ist. Abbildung 7.9 zeigt den Nachrichtenfluss fur ein MPI Allreduce mitacht Prozessen. Dabei ist es egal, ob die Zeit von oben nach unten ablauft oder um-gekehrt. Nehmen wir an, die Zeit laufe von oben nach unten ab, und konzentrierenwir uns auf Prozess 4. Im ersten Zeitschritt tauscht Prozess 4 sein Datenelement mitProzess 5 aus und beide Prozesse reduzieren die Daten mit dem entsprechenden Ope-rator. Im zweiten Zeitschritt tauscht Prozess 4 dann sein (einmal reduziertes) Zwi-schenergebnis mit dem (einmal reduzierten) Zwischenergebnis von Prozess 6 aus.Erneute Reduktion bringt Prozess 4 damit in den Besitz der reduzierten Ursprungs-daten der Prozesse 4 bis 7. Dieses Ergebnis wird dann im letzten Zeitschritt mitProzess 0 ausgetauscht, der inzwsichen uber die reduzierten Daten der Prozesse 0

P0 P1 P2 P3 P4 P5 P6 P7

P0 P1 P2 P3 P4 P5 P6 P7

P0 P1 P2 P3 P4 P5 P6 P7

P0 P1 P2 P3 P4 P5 P6 P7

Abb. 7.9. Datenfluss in Form eines butterfly bei MPI Allreduce.

Page 194: [X.systems.press] Cluster Computing ||

188 7 Grundlagen

D

B

A

C

1

2

3

0P

P

P

P

1

2

3

0P

P

P

P

1

2

3

0P

P

P

P

1

2

3

0P

P

P

PD

B

A

C

A ⊕ B ⊕ ⊕ DC

A ⊕ B ⊕ ⊕ DC

A ⊕ B ⊕ ⊕ DC

A ⊕ B ⊕ ⊕ DC

A ⊕ B ⊕ ⊕ DC

1

2

3

0P

P

P

P

1

2

3

0P

P

P

P

D

B

A

C

1

2

3

0P

P

P

P

1

2

3

0P

P

P

P A ⊕ B ⊕ ⊕ DC

D0

C0

B0

A0

C1

D1

B1

A1 A2

D3

C3

B3

A3

D2

C2

B2 A1⊕B1⊕ ⊕D1C1

A0⊕B0⊕ ⊕D0C0

A2⊕B2⊕ ⊕D2C2

A3⊕B3⊕ ⊕D3C3

A

A ⊕ B

A ⊕ B ⊕ C

MPI_Reduce

MPI_Allreduce

MPI_Reduce_scatter

MPI_Scan

Abb. 7.10. Varianten der kollektiven Datenreduktion.

bis 3 verfugt. Am Ende verfugen alle Prozesse uber die reduzierten Daten. Das ent-standene Kommunikationsmuster heißt auch butterfly.

Neben MPI Reduce und MPI Allreduce gibt es noch zwei weitere Varian-ten kollektiver Datenreduktion (siehe Abb. 7.10). Bei

int MPI_Reduce_scatter(void *sendbuf, void *recvbuf, int *recvcounts,MPI_Datatype type, MPI_Op op, MPI_Comm comm)

ist der Name Programm. Zunachst werden die Daten elementweise reduziert (wiemit MPI Reduce), danach wird der Resultatvektor per MPI Scatterv an dieeinzelnen Prozesse ausgeteilt. Dabei legt recvcounts[i] fest, wie groß der Da-tenblock ist, der an Prozess i verschickt wird. Die Gesamtzahl der Datenelemen-te in sendbuf muss demnach gleich ∑irecvcounts[i] sein. Die FunktionMPI Scan ist gewissermaßen die Prafixversion von MPI Reduce.

int MPI_Scan(void *sendbuf, void *recvbuf, int count,MPI_Datatype type, MPI_Op op, MPI_Comm comm)

Wenn ai die Daten in sendbuf sind, erhalt Prozess r damit den Wert

br = a0 ⊕ a1 ⊕ · · ·⊕ ar (7.7)

in recvbuf. Fur den Operator ⊕ konnen dabei alle Operatoren verwendet werden,die auch fur MPI Reduce zulassig sind.

Page 195: [X.systems.press] Cluster Computing ||

7.4 Anatomie der Nachrichtenubertragung 189

7.4 Anatomie der Nachrichtenubertragung

Sequentielle Programme sind zeitlich eindimensional. In ihnen tickt nur eine Uhr,die mit jedem Tick die nachste Anweisung abarbeitet. Der Ablauf ist geordnet undreproduzierbar. Parallele Programme sind dagegen zeitlich mehrdimensional. In je-dem Prozess tickt eine eigene Uhr. Die genaue zeitliche Abfolge der Anweisungenin verschiedenen Prozessen relativ zueinander ist in der Regel weder vorhersagbarnoch reproduzierbar. Um dennoch in einem paralleles Programm den Uberblick zubehalten, ist ein genaues Verstandnis der zeitlichen Ablaufe beim elementaren Daten-transfer mit MPI erforderlich. Außerdem werden wir sehen, dass sich der Nachrich-tentransfer viel effizienter gestalten lasst als mit MPI Send und MPI Recv.

Abbildung 7.11 zeigt einen moglichen zeitlichen Ablauf einer Nachrichtenuber-tragung. Der Sender ruft zu einem Zeitpunkt Sa die Funktion MPI Send auf undteilt der MPI-Bibliothek dabei die Adresse eines Sendepuffers mit, in dem die zuversendenden Daten liegen. MPI beginnt zum Zeitpunkt S0 > Sa damit, diesen Sen-depuffer auszulesen. Das Auslesen sei zum Zeitpunkt S1 > S0 beendet, die FunktionMPI Send gibt zum Zeitpunkt Se > Sa die Kontrolle an den Aufrufer zuruck. Auchauf der Empfangerseite sind vier Zeitpunkte zu beachten. Der Aufruf von MPI Recvdauere von Ra bis Re, der Empfangspuffer werde in der Zeit von R0 bis R1 beschrie-ben.

Der MPI-Standard kennt zwei grundsatzlich verschiedene Operationsmodi: blo-ckierende und nicht blockierende Operationen. Blockierend bedeutet, dass die Kon-trolle erst dann an den Aufrufer zuruckgegeben wird, wenn der Nachrichtenpufferweiterverarbeitet werden darf. Beim Empfang einer Nachricht bedeutet dies, dasszum Zeitpunkt der Ruckkehr der Empfangspuffer vollstandig beschrieben wurde,Re > R1. Blockierendes Senden erlaubt es dem Aufrufer entsprechend, den Sen-depuffer nach der Ruckkehr sofort wieder zu uberschreiben, da die Sendefunktiondie Daten inzwischen vollstandig ausgelesen hat, also Se > S1 gilt. MPI Recv undMPI Send sind (wie alle bisher beschriebenen Transfer-Funktionen) blockierendeOperationen.

Der Aufruf einer nicht blockierenden Operation meldet dagegen quasi nur denWunsch an, Daten zu ubertragen oder zu empfangen, und legt fest, von wo die Da-

S1S Zeit

ZeitR R1

Sender

Sa 0S

MPI

RR 0

MPI_SendAufruf

Aufruf MPI_RecvEmpfänger

e

ea

schreibt Empfangspuffer

liest Sendepuffer

Abb. 7.11. Moglicher zeitlicher Ablauf eines Nachrichtentransfers.

Page 196: [X.systems.press] Cluster Computing ||

190 7 Grundlagen

ten gelesen bzw. wohin sie geschrieben werden sollen. Danach gibt die Funktiondie Kontrolle an den Aufrufer zuruck, ohne dass Daten vom MPI-System gelesen,ubertragen oder geschrieben wurden. Der Aufrufer ist selbst dafur verantwortlich,gelegentlich nachzufragen, ob sein Wunsch inzwischen bearbeitet wurde. Erst danndarf der Sendepuffer uberschrieben bzw. der Empfangspuffer ausgelesen werden.

7.4.1 Blockierender Nachrichtentransfer

Blockierende Nachrichtenubertragungen garantieren eine feste Reihenfolge der zeit-lichen Ablaufe. Stets gelten

Sa < S0 < S1 < Se und Ra < R0 < R1 < Re .

Diese Ungleichungen garantieren die Reihenfolge jeweils nur auf der Sender- bzw.nur auf der Empfangerseite. Zeitliche Relationen zwischen Sende- und Empfangs-prozess, die uber triviale Kausalitaten wie S0 < R0 hinausgehen, fehlen noch. Diesehangen vom konkreten Modus der blockierende Ubertragung ab. Der MPI-Standarddefiniert vier verschiedene Modi fur das blockierende Senden (Tabelle 7.1).

Gepuffertes Senden

Beim gepufferten Senden wird die Nachricht aus dem Sendepuffer ausgelesen, abernicht sofort zum Empfanger ubertragen, sondern lokal in einem Puffer zwischengela-gert. Von dort kann die MPI-Bibliothek sie dann spater an den Empfanger ausliefern(Notiz 7.8). Dadurch sind Sende- und Empfangsprozess zeitlich entkoppelt. Das hatden Vorteil, dass der Sender nur solange warten muss, wie das Umkopieren in denPuffer dauert. Da das Umkopieren eine lokale Operation ist, geht sie in der Regel vielschneller als das Ubertragen zum entfernten Prozess. Außerdem muss der Senderauch nicht darauf warten, dass der Empfanger empfangsbereit ist. Dadurch gewinntder Sender Zeit, die er fur sinnvolle Arbeiten nutzen kann. Nachteil des gepuffertenSendens ist naturlich der erhohte Speicherverbrauch. Besonders wenn der Sender vie-le lange Nachrichten erzeugt, kann das Puffern erhebliche Systemressourcen belegen.Die MPI-Funktion zum gepufferten Senden heißt MPI Bsend.

int MPI_Bsend(void *buf, int count, MPI_Datatype type, int dest, int tag,MPI_Comm comm)

Sie hat exakt die gleichen Parameter wie MPI Send.Der Puffer, den die MPI-Bibliothek zum Zwischenlagern verwendet, muss vom

Sender bereitgestellt werden. Dazu dient die Funktion MPI Buffer attach.

int MPI_Buffer_attach(void *buffer, int size)

Sie verlangt die Angabe der Adresse buf und der Große size (in Bytes) des Puffer-speichers. Dieser Speicher muss naturlich vorher mit malloc oder ahnlichen Funk-tionen reserviert werden. Jeder Prozess kann ubrigens nur einen Pufferspeicher ver-wenden. Mit

Page 197: [X.systems.press] Cluster Computing ||

7.4 Anatomie der Nachrichtenubertragung 191

Tabelle 7.1. Blockierende Sendeoperationen.

Operation Funktionsweise

MPI Bsend Gepufferter Modus: Sendedaten werden in einen Pufferspeicher umko-piert und von dort gesendet, die Funktion kehrt sofort nach dem Ko-piervorgang zuruck.

MPI Ssend Synchroner Modus: Funktion kehrt erst zuruck, nachdem mit dem Emp-fang der Daten begonnen wurde, Se > R0.

MPI Rsend Empfangsbereiter Modus: Ubertragung findet nur statt, wenn beimAufruf der korrespondierende Empfangswunsch bereits vorliegt, d. h.fur Sa > Ra. Falls kein Empfangswunsch vorliegt, gilt der Sendever-such als fehlerhaft.

MPI Send Standardmodus: Kann wie MPI Ssend oder MPI Bsend arbeiten.Das kann sich auch dynamisch andern, z. B. in Abhangigkeit der Nach-richtenlange.

int MPI_Buffer_detach(void *buffer, int *size)

wird der MPI-Implementation mitgeteilt, dass der Pufferspeicher nicht mehr benotigtwird. Die Adresse des bisherigen Puffers und seine Große werden in den Parame-tern buf und size zuruckgeliefert. Beachten Sie, dass die ersten Parameter inMPI Buffer attach und MPI Buffer detach verschiedene Bedeutungen ha-ben, obwohl sie formal in beiden Fallen vom Typ void * sind. Bei MPI Bufferattach ist buf die Adresse des Speichers, bei MPI Buffer detach die Adres-se der Adresse des Speichers. Dass das ein bisschen verwirrend ist, liegt daran, dassein Zeiger vom Typ void * eben auf alles zeigen kann, auch auf andere Zeiger.Das ist eine der gewohnungsbedurftigen Eigenheiten der Sprache C. Klarer wird dieSache durch ein kleines Beispiel:

const int bufsize1=100000;int bufsize2;char *buf1, *buf2;...

5 buf=malloc(bufsize);if (buf!=NULL) {

/ * P u f f e r s p e i c h e r vorhanden , a b e r noch n i c h t f u r MPI v e r f u g b a r * /...MPI_Buffer_attach(buf1, bufsize1);

10 / * ab h i e r kann MPI den P u f f e r verwenden * /...MPI_Buffer_detach(&buf2, &bufsize2);/ * ab h i e r i s t d e r P u f f e r f u r MPI t a b u * /...

15 MPI_Buffer_attach(buf2, size2);/ * j e t z t kann MPI den P u f f e r w iede r n u t z e n * /...MPI_Buffer_detach(&buf2, &bufsize2);free(buf);

20 }

Page 198: [X.systems.press] Cluster Computing ||

192 7 Grundlagen

Zuerst wird dem MPI-System ein Pufferspeicher zugewiesen (Zeile 9) und danachwieder weggenommen (Zeile 12). Die Startadresse und die Große des Puffers werdendabei in den Variablen buf2 und bufsize2 abgelegt. Der mit malloc reservierteSpeicher ist allerdings noch immer vorhanden und kann erneut als Puffer fur MPIeingesetzt werden (Zeile 15).

MPI Bsend wird mit einem Fehler beendet, wenn nicht genug Pufferspeicherzur Verfugung steht. In diesem Fall kann – je nach Fehlerbehandlung – das ganzeProgramm absturzen. Sie sollten also mit MPI Buffer attach nicht zu knauserigsein.

Auf den ersten Blick scheint MPI Bsend dem zu entsprechen, was wir oben mitnicht blockierend bezeichnet haben. Die Sendeoperation kehrt zuruck, bevor nochein einziges Byte zum Empfanger ubertragen wurde. Es gibt aber einen wichtigenUnterschied zwischen beiden Modi. Beim gepufferten, blockierten Senden ist dieOperation aus Sicht des Senders bei Ruckkehr der Sendefunktion erledigt. Er mussnicht beachten, dass die Nachricht unter Umstanden noch gar nicht ausgeliefert ist,sondern kann seinen Sendepuffer sofort anderweitig verwenden. Beim nicht blockie-renden Senden dagegen ist sein Sendepuffer der einzige Speicher, der die Nachrichtenthalt, und der Sender muss explizit nachfragen, ob der Empfanger schon eine Ko-pie davon erhalten hat, bevor er diesen Speicher uberschreiben darf.

Synchrones Senden

Beim synchronen Senden benutzt das MPI-System keinen Puffer. Dieser Sendemo-dus wird von der Funktion

int MPI_Ssend(void *buf, int count, MPI_Datatype type, int dest, int tag,MPI_Comm comm)

bereitgestellt. Die Parameter haben hier die gleiche Bedeutung wie bei MPI Send.Auch MPI Ssend ist eine blockierende Operation, d. h., bei Ruckkehr kann der Sen-depuffer sofort uberschrieben werden. Wenn das MPI-System die Daten nicht zwi-schenspeichert, und der Sendepuffer sofort uberschrieben werden darf, bedeutet dasnicht, dass die Daten schon beim Empfanger sein mussen?

Nein, nicht zwangslaufig. Denn die Nachricht kann durchaus noch ”im System“unterwegs sein. Der Grund dafur ist, dass die MPI-Bibliothek Netzwerkprotokollewie TCP/IP zum Verschicken von Daten benutzt und diese Protokolle konnen soimplementiert sein, dass sie ihrerseits Daten puffern. Was beim synchronen Sendengarantiert wird, ist, dass bei Ruckkehr von MPI Ssend bereits mit der Ubertragung(genauer: mit dem Schreiben des Empfangspuffers) begonnen wurde. Also gilt Se >R0. Wegen der unklaren Verhaltnisse in der unterliegenden Netzwerksoftware kannuber die Abfolge von Se und Re bzw. R1 nichts gesagt werden. Trotzdem bedeutetsynchrones Senden eine gewisse Synchronisierung von Sender und Empfanger. DaMPI Ssend nicht zuruckkehrt, ohne dass ein anderer Prozess mit dem Empfangder Nachricht begonnen hat, spricht man von einer nicht lokalen Ruckkehrsemantik.Gepufferte Sendefunktionen haben dagegen eine lokale Ruckkehrsemantik.

Page 199: [X.systems.press] Cluster Computing ||

7.4 Anatomie der Nachrichtenubertragung 193

Standardisiertes Senden

Die Funktion MPI Send, die wir bisher verwendet haben, versendet Daten im so ge-nannten Standardmodus. Hier entscheidet die Implementierung selbst, ob die Sende-daten gepuffert werden oder nicht. MPI Send kann sich wie MPI Bsend verhaltenoder wie MPI Ssend. Das Verhalten kann sogar dynamisch angepasst werden, z. B.je nach Lange der Nachricht oder nach verfugbarem Pufferspeicher. In der Regel wer-den kurze Nachrichten gepuffert, lange Nachrichten nicht. Auf jeden Fall haben Sieals Programmierer keinen Einfluss darauf, mussen sich allerdings auch nicht selbst(wie bei MPI Bsend) um die Bereitstellung von Pufferspeicher kummern. Außer-dem gibt es keinen Fehler, falls MPI Send eigentlich im gepufferten Modus ablau-fen mochte, aber nicht genugend Pufferspeicher hat. In diesem Fall wird einfachwieder auf den synchronen Modus umgeschaltet.

Mit seiner Flexibilitat kann der Standardmodus die Systemressourcen besser aus-nutzen als ein stures Festhalten an gepuffertem oder synchronem Senden. MancheAutoren empfehlen deshalb, immer den Standardmodus zu verwenden. Wir empfeh-len dagegen fur die Punkt-zu-Punkt-Kommunikation nicht blockierende Operatio-nen (Abschnitt 7.5) zu verwenden. Die etwas umstandlichere Programmierung wirddurch den Gewinn an Effizienz mehr als wettgemacht.

Empfangsbereites Senden

Bei allen Sendemodi, die wir bisher kennengelernt haben, konnte der Sender dieUbertragung anstoßen, ohne dass ein passender Empfangswunsch vorlag. Beim emp-fangsbereiten Senden (ready send) ist die Situation anders. Die entsprechende Sen-defunktion

int MPI_Rsend(void *buf, int count, MPI_Datatype type, int dest, int tag,MPI_Comm comm)

produziert einen Fehler, wenn zum Zeitpunkt des Aufrufs kein passender Emp-fangswunsch vorliegt, d. h. im Fall Sa < Ra. Die Nachricht wird in diesem Fallnicht ubertragen und stattdessen ein Fehler ausgelost. Wenn Sie MPI Rsend ver-wenden, sollten Sie also sicherstellen, dass immer ein Empfangswunsch vorliegt.Es gibt Anwendungen, wo das durchaus moglich ist, aber warum sollte man sichdie Muhe machen? Nun, wenn das MPI-System sich darauf verlassen kann, dasses fur einen Sende- schon einen passenden Empfangswunsch gibt, dann kann dieNachrichtenubertragung machmal viel schneller abgewickelt werden, da z. B. dieganze Buchhaltung zum Speichern eines Sendewunsches wegfallt. Deshalb kann essich unter Umstanden durchaus lohnen, MPI Rsend zu verwenden. Ansonsten hatMPI Rsend die gleiche Ruckkehrsemantik wie MPI Ssend. Bei Ruckkehr wird ga-rantiert, dass auf der Empfangerseite bereits mit dem Schreiben des Empfangspuffersbegonnen wurde.

Page 200: [X.systems.press] Cluster Computing ||

194 7 Grundlagen

Empfangsmodi

Falls Ihnen nach all den Sendemodi der Kopf schwirrt, konnen Sie sich an dieserStelle entspannen. Beim Empfang gibt es nur einen einzigen blockierenden Modus,und den kennen Sie schon: MPI Recv. Mit MPI Recv kann ein Prozess jederzeiteinen Empfangswunsch signalisieren, und nach fehlerfreier Beendigung steht dieNachricht komplett im Empfangspuffer.

7.4.2 Laufzeitmessungen

Die Laufzeit einer Nachricht vom Sender zum Empfanger ist eine wichtige Großebeim Benchmarking von Cluster-Installationen (siehe Abschnitt 12.2.2) und dientaußerdem zur Abschatzung der Granularitat einer parallelen Anwendung (siehe Ab-schnitt 1.6). Wie aber misst man diese Laufzeit?

Die einfachste Losung arbeitet wie die Laufzeitmessung von Paketen bei der Post.Der Sender schreibt die Uhrzeit in das Datenpaket und der Empfanger vergleichtdiese Zeit mit der Uhrzeit beim Eintreffen des Paketes. Dieses Verfahren setzt al-lerdings voraus, dass die Uhren in den beteiligten Rechnern sehr gut synchronisiertsind, was sich meistens nicht mit der erforderlichen Genauigkeit realisieren lasst.Verlasslicher sind deshalb Verfahren mit rein lokalen Zeitmessungen. Der naive An-satz, einfach die Ausfuhrungszeit von MPI Ssend zu messen, scheitert aber daran,dass selbst MPI Ssend nicht garantiert, dass zum Zeitpunkt der Ruckkehr die Nach-richt vollstandig beim Empfangerprozess gelandet ist. Was wir eigentlich wollen, istdie Differenz Re −Sa, und daruber macht keiner der MPI-Transfermodi eine scharfeAussage. Die Losung dieses Problems ist ganz einfach und unter dem Namen Ping-Pong-Protokoll bekannt, siehe Abb. 7.12.

Der Prozess mit dem Rang 0 schickt dabei eine Nachricht an den Prozess 1 (Ping)und druckt vor dem Aufruf von MPI Send auf die Stoppuhr. Nachdem Prozess 1die Nachricht vollstandig erhalten hat (MPI Recv), schickt er sie sofort an den Pro-zess 0 (Pong) zuruck. Dieser schaut nach dem vollstandigen Empfang des Echos(Ruckkehr von MPI Recv) auf die Stoppuhr und liest die Zeit ∆T ab. Unter derplausiblen Annahme, dass die Nachricht in beide Richtungen gleich lange unterwegs

P

PZei

t

P

MPI_Send

MPI_Recv

MPI_RecvMPI_Send

0

1

0

Abb. 7.12. Messung der Laufzeit einer Nachricht durch Hin- und Herschicken zwischen zweiProzessen.

Page 201: [X.systems.press] Cluster Computing ||

7.4 Anatomie der Nachrichtenubertragung 195

Listing 7.4. Das Programm ping-pong.c misst mit dem Ping-Pong-Protokoll die Laufzeiteiner MPI-Nachricht.

#include <stdlib.h>#include <stdio.h>#include ” mpi . h ”

5 int main(int argc, char *argv[]) {int myrank, numprocs, k;const int msg_size=1024, samples=100, ping=1, pong=2;double t, x[msg_size];MPI_Status status;

10MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD, &myrank);MPI_Comm_size(MPI_COMM_WORLD, &numprocs);if (numprocs!=2) {

15 fprintf(stderr, ” Sorry , genau zwei P r o z e s s e e r f o r d e r l i c h .\ n ”);MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);

}if (myrank==0) {

MPI_Barrier(MPI_COMM_WORLD);20 for (k=0; k<samples; ++k) {

t=MPI_Wtime();MPI_Send(x, msg_size, MPI_DOUBLE, 1, ping, MPI_COMM_WORLD);MPI_Recv(x, msg_size, MPI_DOUBLE, 1, pong, MPI_COMM_WORLD, &status);t=MPI_Wtime()-t;

25 printf(”%d : %l f \n ”, k, 0.5*t);}

} else {MPI_Barrier(MPI_COMM_WORLD);for (k=0; k<samples; ++k) {

30 MPI_Recv(x, msg_size, MPI_DOUBLE, 0, ping, MPI_COMM_WORLD, &status);MPI_Send(x, msg_size, MPI_DOUBLE, 0, pong, MPI_COMM_WORLD);

}}MPI_Finalize();

35 return EXIT_SUCCESS;}

ist, gilt T = Re − Sa = ∆T/2. Listing 7.4 zeigt eine Implementierung dieses Ping-Pong-Protokolls.

Die Nachricht, die im Beispiel hin- und hergeschickt wird, besteht aus einer An-zahl (msg size) von Elementen des Typs double. Wie oft die Laufzeit fur diesesPaket gemessen wird, steht in der Konstanten samples. Sie sollten immer mehrereMessungen machen, da die Laufzeit durch anderweitigen Verkehr auf dem Netzwerkund durch schwankende Systemlast variieren kann. Die eigentliche Messung findetin der Schleife uber k statt. Zur Messung der Zeit wird die MPI-Funktion

Page 202: [X.systems.press] Cluster Computing ||

196 7 Grundlagen

0,001

0,01

0,1

1

10

100

1000

10000

20 22 24 26 28 210 212 214 216 218 220 222 224

Pake

tlauf

zeit

T in

µs

Paketlänge M in Byte

TL + M/Bshared memoryfast ethernet

Abb. 7.13. Laufzeit T einer MPI-Nachricht als Funktion der Nachrichtenlange M, gemessenmit dem Programm ping-pong auf dem Beowulf-Cluster Tina.

double MPI_Wtime(void)

benutzt. Sie liefert die Zeit in Sekunden, die seit einem festen Zeitpunkt in der Ver-gangenheit verstrichen ist. Die Differenz, der bei zwei aufeinander folgenden Aufru-fen gelieferten Werte, ist also die zwischen diesen Aufrufen verstrichene Zeit.

Die Laufzeitmessung mit dem Ping-Pong-Protokoll ist ein einfaches Beispielfur die Nutzlichkeit der Synchronisation mit MPI Barrier (siehe Abschnitt 7.3.2),denn das MPI-System muss zunachst beide Prozesse starten. Dabei kann es passieren,dass ein Prozess deutlich spater gestartet wird als der andere. In diesem Fall wurdeder fruher gestartete Prozess das erste Mal auf die Stoppuhr drucken, wahrend derspatere Prozess noch nicht einmal lauft. Das erste Ping-Pong wurde dann deutlichlanger dauern, weil es die Differenz der Startzeiten enthielte. Nach dem ersten Ping-Pong sind die Prozesse immer synchronisiert, aber mit MPI Barrier gilt dies auchfur die erste Messung.

Abbildung 7.13 zeigt die Ergebnisse einer Laufzeitmessung fur verschiedenePaketgroßen auf unserem Beowulf Cluster Tina. Tinas Knoten bestehen aus Dual-Prozessor-Boards. Das erlaubt uns die Messung der Laufzeit sowohl zwischen denbeiden CPUs eines Knotens als auch zwischen zwei CPUs auf verschiedenen Kno-ten. Im ersten Fall erfolgt die Kommunikation uber das ubliche TCP/IP-Protokollund das Netzwerk (switched Fast Ethernet), im zweiten Fall uber den gemeinsamenSpeicher. Gemittelt wurde uber jeweils 104 Messungen.

Nach (2.1) erwarten wir einen linearen Zusammenhang zwischen der Paketgroßeund der Laufzeit. Wie Sie sehen, beschreibt (2.1) die Situation recht gut, zumindestfur sehr kurze und sehr lange Nachrichten. Aus den Daten in Abb. 7.13 erhalt manfolgende Werte:

Page 203: [X.systems.press] Cluster Computing ||

7.4 Anatomie der Nachrichtenubertragung 197

Latenzzeit TL Bandbreite Bin µs in MBit/s

Fast Ethernet 85 94Shared Memory 1,4 790

Das sind typische Werte fur einen Cluster wie Tina. Die gemessene Bandbreite von94 MBit/s kommt sehr nahe an das theoretische Maximum von 100 MBit/s fur FastEthernet heran. Bemerkenswert sind aber vor allem die Unterschiede zwischen denKommunikationmedien. Der Nachrichtenaustausch uber den gemeinsamen Speicherhat eine mehr als achtfache hohere Bandbreite und eine um den Faktor sechzig kleine-re Latenzzeit verglichen mit der Kommunikation uber das Netz. Die Daseinsberech-tigung exorbitant teurer shared-memory- Systeme speist sich aus solchen Zahlen.

Um zu verstehen, wie die Kommunikation zum Flaschenhals paralleler Anwen-dungen wird, setzen Sie einfach die Latenzzeit in Relation zur Rechengeschwindig-keit der CPU. Zum Zeitpunkt der Messung verfugte Tina uber 800 MHz Pentium IIIProzessoren. Diese schaffen theoretisch 800 Rechenoperationen pro µs (praktisch istes vielleicht nur die Halfte davon). Das heißt, wahrend eine CPU auf die Ubertragungdes ersten Bytes uber das Netz wartet, konnte sie alternativ 68 000 Rechenoperatio-nen durchfuhren. Bei Kommunikation via shared memory sind es immerhin nochuber tausend Rechenoperationen. Und das sind die Werte fur den Nachrichtenaus-tausch unter optimalen Bedingungen, denn so schon synchronisiert wie beim Ping-Pong sind Sender und Empfanger in echten Anwendungen selten. Zahlen wie dieseerlauben es Ihnen aber, die fur eine effiziente Parallelisierung notige Granularitatabzuschatzen.

Bedenken sollten Sie auch, dass es oft die Latenzzeit ist, die die Kommunikationteuer macht, nicht so sehr die Bandbreite. Grob gesagt, macht es zeitlich keinenUnterschied, ob Sie ein einziges Byte in einer Nachricht verschicken oder gleichTL · B Bytes. Bei Tina sollte eine Nachricht daher mindestens 1 KByte (Ethernet)bzw. 150 Byte (shared memory) enthalten, um effizient zu sein. Der Merksatz lautethier: Lieber wenige lange Nachrichten als viele kurze.

Fur eine effiziente parallele Nutzung sollten Sie Bandbreite und Latenzzeit IhresSystem wenigstens ungefahr kennen. Machen Sie entweder selbst Messungen (sie-he Abschnitt 12.2) oder fragen Sie Ihren Systemadministrator. Bei einer Messungsollten Sie sowohl uber die beteiligten Knoten als auch uber das Netz moglichst ex-klusiv verfugen. Netzverkehr und CPU-Last von anderen Prozessen verfalschen dieErgebnisse sonst, obwohl es naturlich durchaus der Realitat entspricht, dass Sie dieRessourcen mit anderen teilen mussen.

7.4.3 Deadlocks

Bei der Ping-Pong-Messung ist zu jedem Zeitpunkt genau eine Nachricht unterwegs.In echten Applikationen ist das Kommunikationsmuster in der Regel viel komplexer.Hier gibt es viele Prozesse, und alle reden durcheinander. Das fuhrt dazu, dass sichNachrichten gegenseitig behindern, sei es ”auf dem Netz“, wo sie sich die Bandbreite

Page 204: [X.systems.press] Cluster Computing ||

198 7 Grundlagen

P

PP

P

P

PP

P

43

2

10

7

6

5

Abb. 7.14. Beim Ringtausch senden alle Prozess zum rechten Nachbarn, empfangen vomlinken.

teilen, oder lokal auf einem Knoten, wo das MPI-System mehrere ein- und ausgehen-de Nachrichten zugleich verwalten muss. Benchmark-Programme zur Leistungsbe-urteilung von Clustern unter MPI bestehen deshalb aus einer ganzen Reihe von Pro-grammen, die die unterschiedlichsten Kommunikationsmuster erzeugen. Ping-Pongzwischen zwei Prozessen ist davon nur das einfachste, siehe auch Abschnitt 12.2.2.

Eine Moglichkeit, mehr Nachrichtenverkehr zu erzeugen, ist die, einfach bei-den Ping-Pong-Spielern einen Ball zu geben. Dann fliegen zu jedem Zeitpunkt zweiNachrichten uber, Pardon, durch das Netz, eine von P0 zu P1, die andere von P1 zuP0. Auf p Mitspieler mit p Ballen verallgemeinert entsteht ein Ring als Kommuni-kationsmuster (siehe Abb. 7.14). Prozess Pn empfangt eine Nachricht von Pn−1 undsendet eine Nachricht an Pn+1. Um den Ring zu schließen, verwenden wir die peri-odischen Randbedingungen P−1 = Pp−1 und Pp = P0. Wenn am Anfang jeder Prozesseine Nachricht losschickt, sind standig p Nachrichten im System unterwegs, die furStau im Netzwerk sorgen konnen. Dieses Kommunikationsschema ist typisch furdie große Klasse von Problemen, die sich geometrisch parallelisieren lassen, sieheAbschnitt 9.2.

Die p-te Nachricht, die ein Prozess auf diese Weise empfangt, ist die Nachricht,die er ursprunglich losgeschickt hat. Die Zeit fur diese Rundreise, geteilt durch p,ist ein Maß fur die Nachrichtenubertragung von einem Prozess zum nachsten. JederProzess kann hier eine rein lokale Zeitmessung machen, und wir konnen am Schlussuber diese Ergebnisse mitteln.

Wie sieht ein Programm zur Messung der Rundreisezeit einer Nachricht aus?Zunachst muss jeder Prozess seinen linken (von dort kommen die Nachrichten) undseinen rechten Nachbarn (dahin gehen die Nachrichten) ermitteln.

src =(myrank-1+p)%p; / * l i n k e r Nachbar * /dest=(myrank+1)%p; / * r e c h t e r Nachbar * /

Eine Rundreise ist nach p Sende- und Empfangsprozessen abgeschlossen. Jeder Pro-zess konnte einfach die Ausfuhrungszeit der Schleife

for (i=0; i<p; ++i) {MPI_Send(x, packetsize, MPI_INT, dest, ping, MPI_COMM_WORLD);MPI_Recv(x, packetsize, MPI_INT, src, ping, MPI_COMM_WORLD, &status);

}

Page 205: [X.systems.press] Cluster Computing ||

7.4 Anatomie der Nachrichtenubertragung 199

MPI_Recv(src=1)

MPI_Send(dest=1) MPI_Send(dest=0)

MPI_Recv(src=0)

Prozess 1Prozess 0

...

...

...

...

Abb. 7.15. Ein deadlock: zwei Prozesse blockieren sich gegenseitig.

messen. Doch halt! Was passiert, wenn jeder Prozess diese Schleife ausfuhrt? Den-ken Sie daruber nach, bevor Sie weiterlesen!

Das Verhalten der Prozesse ist unbestimmt, denn es hangt entscheidend von denunbestimmten Eigenschaften von MPI Send ab. Sie erinnern sich: MPI Send kannsich sowohl wie synchrones als auch wie gepuffertes Senden verhalten. Nehmen wiran, MPI Send arbeite ungepuffert, d. h. synchron. Außerdem sei der Einfachheithalber p = 2 (siehe Abb. 7.15). Der Prozess P0 ruft das erst einmal MPI Send auf.Dieser Aufruf kehrt nur zuruck, wenn der andere Prozess P1 mit dem Empfang begon-nen hat. Prozess P0 wartet also darauf, dass P1 sein MPI Recv aufruft. Prozess P1hat aber ebenfalls ein synchrones MPI Send abgesetzt und wartet seinerseits darauf,dass Prozess P0 MPI Recv aufruft, was aber nicht passiert, da P0 ja selbst in seinemMPI Send steckt und wartet . . . Sie sehen, beide Prozesse warten und behindernsich gegenseitig. Das bleibt auch so bei mehr als zwei Prozessen. Jeder wartet aufseinen rechten Nachbarn, bevor der linke Nachbar bedient wird. Nichts geht mehr,ein klassischer Fall von deadlock1.

Deadlocks sind eine uble Fehlerquelle in parallelen Programmen. Sie sind oftschwer zu entdecken und nicht immer reproduzierbar. Auch in unserem, extrem ein-fachen Fall ist der deadlock leicht zu ubersehen, denn mit hoher Wahrscheinlichkeitware er bei Testlaufen nicht aufgetreten. Testlaufe macht man in der Regel mit kurzenNachrichten, und MPI Send ist haufig so implementiert, dass kurze Nachrichten in-tern gepuffert werden, lange dagegen nicht. Mit gepuffertem Senden gibt es hier aberkeinen deadlock, denn MPI Bsend kehrt ja zuruck, auch ohne dass der Empfangervorher MPI Recv aufrufen musste. Die Verwendung von

for (i=0; i<p; ++i) {MPI_Bsend(x, packetsize, MPI_INT, dest, ping, MPI_COMM_WORLD);MPI_Recv(x, packetsize, MPI_INT, src, ping, MPI_COMM_WORLD, &status);

}

ware also eine Variante ohne deadlock, vorausgesetzt, jeder Prozess stellt genugendPufferspeicher zur Verfugung. Preisfrage: Wieviele Nachrichten muss ein Puffer auf-nehmen konnen, damit die obige Variante unter allen Umstanden funktioniert? Auchwenn der Puffer nicht ausreicht, gibt es wenigstens einen Abbruch mit erklarenderFehlermeldung und Sie konnen das Problem beheben. Einen deadlock erkennen Siedagegen nur daran, dass Ihr Programm nie fertig wird.

1Das deutsche Wort ”Verklemmung“ klingt irgendwie verklemmt, deshalb bleiben wirbeim englischen Begriff deadlock.

Page 206: [X.systems.press] Cluster Computing ||

200 7 Grundlagen

Falls MPI Send die Nachrichten intern puffert, funktioniert der Ringtausch auchdamit. Programme, die sich implizit darauf verlassen, dass das MPI-System Nach-richten puffert, heißen aus offensichtlichen Grunden unsicher. Als Sicherheitscheckkonnen Sie in Ihren Programmen vorubergehend jeden Aufruf von MPI Send durchein MPI Ssend ersetzen. Lauft Ihr Programm auch nach dieser Anderung nicht ineinen deadlock, ist es sicher. Nach dem Test sollten Sie die Anderungen aber wie-der ruckgangig machen, denn MPI Send ist aufgrund seiner Flexibilitat dem sturensynchronen Senden uberlegen.

In unserem Ringtausch-Beispiel kann der deadlock ubrigens auch dadurch be-hoben werden, dass mindestens einer der Prozesse MPI Send und MPI Recv inumgekehrter Reihenfolge aufruft. Uberlegen Sie sich auf dem Papier, wieso ein ein-zelner abweichender Prozess die globale Blockade losen kann, oder probieren Sie eseinfach aus.

Szenarien wie der Ringtausch, bei denen alle Prozesse sowohl senden als auchempfangen, kommen in parallelen Anwendungen recht haufig vor, siehe z. B. Sei-te 296. Der MPI-Standard bietet deshalb eine spezielle Funktion an, mit der sich dasgleichzeitige Senden und Empfangen elegant und vor allem ohne deadlock realisie-ren lasst:

int MPI_Sendrecv(void *sendbuf, int sendcount, MPI_Datatype sendtype,int dest, int sendtag,void *recvbuf, int recvcount, MPI_Datatype recvtype,int src, int srctag, MPI_Comm comm, MPI_Status *status)

MPI Sendrecv enthalt die kombinierten Parameter von MPI Send und MPIRecv, und es fuhrt diese beiden Befehle auch aus. Allerdings in zwei unabhangi-gen Verarbeitungsstrangen, also quasi gleichzeitig und frei von deadlocks. MPISendrecv ist eine blockierende Operation. Adressat dest und Absender srcdurfen identisch sein. Aliasing ist auch hier verboten, die beiden Speicherbereichesendbuf und recvbuf durfen nicht identisch sein oder sich uberlappen. Ein Ring-tausch mit MPI Sendrecv sahe dann so aus:

for (i=0; i<p; ++i) {MPI_Sendrecv(x, packetsize, MPI_INT, dest, ping,

y, packetsize, MPI_INT, src, ping, MPI_COMM_WORLD, &status);memcpy(x, y, packetsize*sizeof(*x));

}

Das Umkopieren der Daten vom Empfangs- in den Sendepuffer ist Folge des Alia-sing-Verbotes. Darauf verzichten kann man mit der Variante

int MPI_Sendrecv_replace(void *buf, int count, MPI_Datatype type,int dest, int sendtag, int src, int recvtag,MPI_Comm comm, MPI_Status *status)

die auf einem einzigen Pufferspeicher arbeitet. MPI Sendrecv replace versen-det die Daten in buf an dest und ersetzt den Inhalt von buf dann durch die vonsrc empfangenen Daten. Jetzt mussen allerdings Anzahl und Typ der Daten fur bei-de Richtungen identisch sein. Der Ringtausch vereinfacht sich hiermit zu

Page 207: [X.systems.press] Cluster Computing ||

7.4 Anatomie der Nachrichtenubertragung 201

for (i=0; i<p; ++i)MPI_Sendrecv_replace(x, packetsize, MPI_INT, dest, ping,

src, ping, MPI_COMM_WORLD, &status);

7.4.4 Fairness

Abbildung 7.16 zeigt ein Kommunikationsmuster mit mehr als zwei Prozessen underhohtem Nachrichtenaufkommen. Hier spielt Prozess P0 gleichzeitig mit allen ande-ren Prozessen Ping-Pong. Dieses Kommunikationsmuster tritt vor allem in Anwen-dungen auf, die nach dem Master-Worker-Schema parallelisiert werden. Bei diesemSchema verwaltet ein zentraler Prozess (der Master P0) die gesamte Arbeit. Die Wor-ker (Pi>0) holen sich Teilaufgaben beim Master ab, erledigen diese, liefern das Er-gebnis zuruck und bekommen eine neue Teilaufgabe zugeteilt (Abschnitt 9.1.4).

Listing 7.5 zeigt den Kern eines Programms zur Messung der Paketlaufzei-ten bei diesem Ping-Pong-Spiel ”alle gegen einen“. Schauen wir uns zunachstden Prozess P0 an. Er wartet auf ein Ping von irgendeinem der anderen Prozesse(MPI ANY SOURCE in der Empfangsfunktion). Der Absender des Ping, der im FeldMPI SOURCE der Variablen status steht, erhalt postwendend sein Pong zuruck. Inder Variablen packets zahlt P0 die Nachrichten, die so hin- und hergehen. DieseZahl wird den Partnern immer im ersten Element der Pong-Nachricht mitgeschickt.Das wird gemacht, um das Ende dieses Spiels zu signalisieren. Alle Prozesse horennamlich mit dem Ping-Pong auf, sobald mehr als numpackets Nachrichten ausge-tauscht wurden. Der zentrale Prozess P0 merkt sich in der Variablen d die Anzahlseiner aktiven Mitspieler. Immer, wenn er einem aktiven Prozess eine Nachricht mitpackets ≥ numpackets geschickt hat, reduziert er die Variable d um eins. So-bald keiner der Mitspieler mehr aktiv ist (d= 0), sammelt Prozess P0 die Messdatenein und gibt sie aus. Auf diese Weise laufen bei numprocs gestarteten Prozessengenau numpackets+numprocs−2 Nachrichten hin und her.

Die Prozesse mit Rang großer null schicken ihr Ping an Prozess P0 und wartenauf das Pong. Die Zeit dazwischen wird wieder gemessen. Außerdem wird jeder

”Ballwechsel“ in der Variablen packets gezahlt. Sobald das erste Element einerempfangenen Pong-Nachricht anzeigt, dass insgesamt mehr als numpackets Pake-te hin- und hergegangen sind, hort der Prozess auf, Pings zu senden. Danach wird

P

PP

P

PP

P

P

P

7

81

0

65

4

3

2

Abb. 7.16. Mehr Verkehr im Netz: Alle Prozesse spielen Ping-Pong mit Prozess P0.

Page 208: [X.systems.press] Cluster Computing ||

202 7 Grundlagen

Listing 7.5. Auszug aus dem Programm all2one.c. Prozess P0 spielt Ping-Pong mit allenanderen Prozessen.

MPI_Barrier(MPI_COMM_WORLD);40 if (myrank==0) {

packets=0;d=numprocs-1;while (d>0) {

MPI_Recv(x, packetsize, MPI_INT, MPI_ANY_SOURCE, ping,45 MPI_COMM_WORLD, &status);

++packets;x[0]=packets;MPI_Send(x, packetsize, MPI_INT, status.MPI_SOURCE, pong,

MPI_COMM_WORLD);50 if (packets>=numpackets)

--d;}numpackets=packets;printf(” P r o z e s s 0 a u f %s h a t %u P a k e t e a %u Bytes a u s g e t a u s c h t .\ n ”,

55 procname, numpackets, size);printf(” Daran waren b e t e i l i g t :\ n ”);for (d=1; d<numprocs; ++d) {

MPI_Recv(procname, MPI_MAX_PROCESSOR_NAME+1, MPI_CHAR, d, 0,MPI_COMM_WORLD, &status);

60 MPI_Recv(&packets, 1, MPI_UNSIGNED_LONG, d, 0, MPI_COMM_WORLD,&status);

MPI_Recv(&t_ave, 1, MPI_DOUBLE, d, 0, MPI_COMM_WORLD, &status);printf(” P r o z e s s %d a u f %s : %u Pake te , %l f ms pro P a k e t\n ”,

d, procname, packets, t_ave);65 }

} else {packets=0;t_ave=0;while (1) {

70 t=MPI_Wtime();MPI_Send(x, packetsize, MPI_INT, 0, ping, MPI_COMM_WORLD);MPI_Recv(x, packetsize, MPI_INT, 0, pong, MPI_COMM_WORLD,

&status);t=0.5*(MPI_Wtime()-t);

75 t*=1000.0; / * M i l l i s e k u n d e n * /t_ave+=t;++packets;if (x[0]>=numpackets)

break;80 }

t_ave=t_ave/((double)packets);MPI_Send(procname, namelength+1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);MPI_Send(&packets, 1, MPI_UNSIGNED_LONG, 0, 0, MPI_COMM_WORLD);MPI_Send(&t_ave, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);

85 }

der Mittelwert der Zeiten, die Zahl der getauschten Pakete sowie der Rechnernamedieses Prozesses zum Prozess P0 geschickt, der alles ausgibt.

Das vollstandige Programm all2one.c finden Sie auf der Webseite zum Buch[7]. Aufgerufen wird es mit zwei Parametern: -M numpackets legt die Anzahl der

Page 209: [X.systems.press] Cluster Computing ||

7.4 Anatomie der Nachrichtenubertragung 203

Terminal Session 7.1. Messergebnisse beim Ping-Pong-Spiel mit mehreren Partnern.mertens@tina:˜$ mpirun -np 3 all2one -s 10000 -M 1000Prozess 0 auf node1 hat 1000 Pakete a 40000 Bytes ausgetauscht.Daran waren beteiligt:

Prozess 1 auf node2: 500 Pakete, 4.088146 ms pro PaketProzess 2 auf node3: 500 Pakete, 4.092301 ms pro Paket

mertens@tina:˜$ mpirun -np 5 all2one -s 10000 -M 1000Prozess 0 auf node1 hat 1000 Pakete a 40000 Bytes ausgetauscht.Daran waren beteiligt:

Prozess 1 auf node2: 250 Pakete, 7.031453 ms pro PaketProzess 2 auf node3: 250 Pakete, 7.010472 ms pro PaketProzess 3 auf node4: 250 Pakete, 7.045146 ms pro PaketProzess 4 auf node5: 250 Pakete, 7.024498 ms pro Paket

mertens@tina:˜$ mpirun -np 10 all2one -s 10000 -M 1000Prozess 0 auf node1 hat 1000 Pakete a 40000 Bytes ausgetauscht.Daran waren beteiligt:

Prozess 1 auf node2: 149 Pakete, 29.795244 ms pro PaketProzess 2 auf node3: 123 Pakete, 35.826315 ms pro PaketProzess 3 auf node4: 60 Pakete, 71.769378 ms pro PaketProzess 4 auf node5: 167 Pakete, 26.630797 ms pro PaketProzess 5 auf node6: 109 Pakete, 40.812544 ms pro PaketProzess 6 auf node7: 105 Pakete, 42.403693 ms pro PaketProzess 7 auf node8: 111 Pakete, 40.083718 ms pro PaketProzess 8 auf node9: 101 Pakete, 43.107925 ms pro PaketProzess 9 auf node10: 75 Pakete, 56.931565 ms pro Paket

mertens@tina:˜$

Pakete fest und -s packetsize die Anzahl von Ganzzahlwerten, die in jedemPaket verschickt werden.

In Terminal Session 7.1 finden Sie das Ergebnis einer Messung auf unserem Clus-ter Tina, bei der jeweils tausend Pakete zu je 10000 Ganzzahlen zwischen Prozessnull und zwei, vier oder neun Partnern hin- und hergeschickt wurden. Sehr deutlichist hier die Zunahme der Laufzeit pro Paket mit der Zahl der Prozesse zu sehen.Schuld daran ist naturlich die zentralistische Struktur, bei der sich alle Pakete dieNetzbandbreite zum zentralen Knoten als auch die ”Aufmerksamkeit“, sprich dieAntwortzeit des zentralen Prozesses P0, teilen mussen.

Auf unserem Beowulf-Cluster sind alle Knoten identisch und wahrend der Mes-sung gab es keine Storungen durch andere Prozesse. Die Prozesse wurden auch soverteilt, dass die komplette Kommunikation uber das Ethernet laufen musste. In soeinem Fall sollte man eigentlich erwarten, dass jeder Prozess einen gleich großen An-teil am Nachrichtensalat hat. Die Messung zeigt aber, dass das nur gilt, wenn nichtzu viele Prozesse mitmischen. Bei zehn gestarteten Prozessen variiert die Anzahl derPakete von 62 bis 149. Bei homogener Verteilung hatte jeder Prozess dagegen 111Nachrichten verschicken mussen (und einer 112). Die Abweichungen deuten daraufhin, dass das MPI-System bzw. das Betriebssystem die Prozesse offensichtlich nichtgleichbehandelt. Wir sind hier auf ein Phanomen gestoßen, das in der parallelen Pro-grammierung als das Problem der Fairness bekannt ist.

Wenn viele Prozesse ihre Nachrichten zum Prozess P0 schicken, liegen dort beijedem Aufruf von MPI Recv in der Regel auch mehrere Nachrichten vor, die imPrinzip empfangen werden konnten. Mit MPI ANY SOURCE sagt P0, dass ihm derAbsender egal ist. Das MPI-System entscheidet dann, welche der vorliegenden Nach-

Page 210: [X.systems.press] Cluster Computing ||

204 7 Grundlagen

dest=0 dest=0 dest=0tag=3tag=2tag=1MPI_Send

MPI_Recvsrc=ANYsrc=ANY

tag=1 tag=1src=2tag=ANY

src=2tag=ANY

src=ANYtag=ANY

MPI_send tag=1dest=0 dest=0

tag=4

Zeit

P2

0P

P1

Abb. 7.17. Zum Uberholverbot von Nachrichten.

richten zum Zuge kommt. Dabei kann es durchaus vorkommen, dass einige Nachrich-ten nie abgeholt werden, weil andere immer vorgezogen werden. Fairness bedeutetdagegen, dass ein solches ”Verhungern“ ausgeschlossen wird. Der MPI-Standard ga-rantiert diese Fairness nicht. Wenn Sie das Programm all2one auf sehr vielenProzessen starten und mit kurzen Nachrichten arbeiten, werden Sie leicht Falle pro-duzieren, in denen Prozesse nur eine einzige Nachricht mit P0 austauschen, namlichdie, die ihnen mitteilt, dass das Experiment schon vorbei ist. Wir werden im nachstenAbschnitt sehen, wie man mittels nicht blockierender Transfers die Situation etwasfairer gestalten kann.

Unfairness kann nur auftreten, weil Nachrichten sich uberholen konnen. WennProzess P0 eine Nachricht mit MPI ANY SOURCE empfangt, und P1 und P2 einepassende Nachricht an P0 abgeschickt haben, kann durchaus die Nachricht zuerstempfangen werden, die spater abgeschickt wurde. Der MPI-Standard erlaubt, dasssich Nachrichten uberholen, jedenfalls dann, wenn die Absender der Nachrichtenverschieden sind. Zwei Nachrichten vom selben Absender zum selben Empfangerkonnen sich dagegen nie uberholen.

Abbildung 7.17 zeigt ein Beispiel aus [59] zur Erlauterung. Zwei Prozesse P1 undP2 senden Nachrichten an den Prozess P0. Kommunikator und Datentyp aller Sende-und Empfangsfunktionen stimmen uberein, so dass nur noch Etikett (tag) und Ab-sender (src) daruber entscheiden, ob eine Nachricht beim Empfanger ”passt“. DieEmpfangsoperationen werden vom Prozess P0 in einer festen Reihenfolge aufgerufen,genau wie die Sendeoperationen bei P1 und P2. Die jeweils erste Nachricht von P1und P2 passen auf die ersten beiden Empfangsoperationen von P0. Hier sind deshalbbeide Reihenfolgen des Nachrichteneingangs moglich, unabhangig davon, welchezuerst abgeschickt wurde. Das ist auch die Situation in all2one.c in Listing 7.5.Unabhangig davon, welche Reihenfolge realisiert wurde, wartet Prozess P0 anschlie-ßend auf zwei Nachrichten von P2. Danach ist der Prozess P0 wieder bereit, voneinem der anderen Prozesse Daten zu empfangen. Aber nur Prozess P1 verschicktnoch eine Nachricht, die dann auch empfangen wird.

Das Uberholverbot fur Nachrichten zwischen denselben Prozessen bedeutet, dasssich die Pfeile in Abb. 7.17 niemals kreuzen durfen. Nachrichten von verschiedenenAbsendern durfen sich dagegen sehr wohl uberholen.

Page 211: [X.systems.press] Cluster Computing ||

7.5 Nicht blockierender Nachrichtentransfer 205

Die Reihenfolge des Nachrichtenempfangs ist naturlich nur dann unbestimmt,wenn der Empfanger die Joker MPI ANY SOURCE oder MPI ANY TAG verwendet.Sie konnen sich zu Recht fragen, ob man nicht zu Gunsten eines klar determiniertenProgrammablaufs auf diese Joker verzichten sollte. Die Antwort ist ein klares Nein.Die Joker bieten eine Flexibilitat, die die Effizienz des Programmablaufs betracht-lich steigern kann. Das sehen wir z. B. im Programm all2one. Stellen Sie sichvor, einer der Knoten sei viel langsamer als die anderen oder habe eine schlechte-re Netzanbindung. Bei unserem Programmablauf bekommt dieser Knoten dann ganzautomatisch weniger Pakete. Ohne Joker, mit einem fest vorgegebenen Anteil von Pa-keten, wurde die ganze Anwendung noch auf den letzten, langsamen Knoten warten,wenn alle anderen Knoten bereits fertig sind. Mit den Jokern ergibt sich hier dage-gen ein einfaches Beispiel fur die automatische, dynamische Lastverteilung. Damitwerden wir uns im Abschnitt 9.1.3 noch ausfuhrlich beschaftigen.

7.5 Nicht blockierender Nachrichtentransfer

Die blockierenden Funktionen wie MPI Send und MPI Recv sind fur den Aufruferrecht bequem, denn aus seiner (lokalen) Sicht ist mit ihrer Ruckkehr der Nachrich-tentransfer erledigt. Bei den nicht blockierenden Funktionen ist das nicht mehr so.Hier besteht der komplette Nachrichtentransfer aus zwei lokalen Funktionsaufrufen.Der Erste stoßt den Transfer nur an, der Zweite schließt ihn ab. Ein Aufruf von

int MPI_Isend(void *buf, int count, MPI_Datatype datatype, int dest,int tag, MPI_Comm comm, MPI_Request *request)

stoßt den Sendevorgang an. Die Argumente von MPI Isend entsprechen denen vonMPI Send, nur das letzte Argument request ist neu. Mit request wird demAufrufer ein Ticket zuruckgegeben, mit dem er den Fortgang des Transfers kontrollie-ren kann. Tickets sind undurchsichtige Objekte vom Typ MPI Request (siehe Ab-schnitt 8.1.2). Die Funktion MPI Isend kehrt ”sofort“ (das ”I“ steht fur immediate)zum Aufrufer zuruck, ohne die Daten im Sendepuffer lokal oder gar zum entferntenProzess zu kopieren. Fur den Aufrufer bedeutet das, dass er den Sendepuffer nichtuberschreiben darf. Das geht erst dann, wenn der Sendepuffer vom MPI-System kom-plett ausgelesen wurde. Ob das bereits passiert ist, erfahrt der Prozess durch Aufrufvon MPI Wait.

int MPI_Wait(MPI_Request *request, MPI_Status *status)

Im ersten Argument wird das von MPI Isend ausgestellte Ticket ubergeben. DieFunktion MPI Wait ist blockierend. Nach der Ruckkehr darf darum der zum Trans-ferauftrag request gehorige Sendepuffer uberschrieben werden. Bei Ruckkehrvon MPI Wait wird das Ticket annulliert und request wird auf MPI REQUESTNULL gesetzt.

7.5.1 Rechnen statt Warten

Im Prinzip wird beim nicht blockierenden Senden das einfache MPI Send durch

Page 212: [X.systems.press] Cluster Computing ||

206 7 Grundlagen

MPI Send(...)=

⎧⎪⎨⎪⎩MPI Isend(..., &request)

...MPI Wait(&request, ...)

ersetzt. Warum sollte man so etwas machen? Ubersichtlicher werden MPI-Program-me dadurch sicher nicht. Den Hauptgrund bilden die vertikalen Punkte in obigerGleichung. Sie stehen fur (nahezu) beliebige Kommandos, die der Prozess ausfuhrenkann, wahrend sich das MPI-System um die Abwicklung des Nachrichtentransferskummert. Betrachten wir als Beispiel einen Prozess, der sukzessive Daten berechnetund jedes Datum an einen zweiten Prozess schickt.

finished=calculate(buf1);while (!finished) {

MPI_Isend(buf1, ..., &request);finished=calculate(buf2);MPI_Wait(&request...);swap(buf2, buf1); / * nur Z e i g e r t a u s c h e n * /

}

Der Witz ist dabei, dass mit MPI Isend die Ubertragung nur angestoßen wird undder Prozess ”sofort“ mit der Berechnung der neuen Daten weitermachen kann. Paral-lel dazu kann MPI den eigentlichen Transfer vorantreiben, so dass das abschließen-de MPI Wait im Idealfall auch ”sofort“ zuruckkehrt und der Nachrichtentransferunterm Strich keine Zeit kostet. Das grundlegende Motiv ist auch hier, niemals eineunnotige Reihenfolge festzulegen. Blockierende Funktionen legen implizit eine Rei-henfolge fest, denn sie zwingen den Aufrufer zu warten, bis MPI den Transferpufferfreigegeben hat, auch wenn dieser gar nicht sofort wieder benotigt wird. Durch dieVerwendung von nicht blockierenden Funktionen ermoglicht man eine Uberlagerungvon computation und communication, die im Idealfall den Zeitverlust bei der Kom-munikation uber langsame Netzwerke effektiv zum Verschwinden bringt (Notiz 7.8).

Die Funktion MPI Irecv ist die nicht blockierende Version von MPI Recv.

int MPI_Irecv(void *buf, int maxbuf, MPI_Datatype datatype, int src,int tag, MPI_Comm comm, MPI_Request *request)

Auch hier wird nur der Empfangswunsch angemeldet und auf die komplette Ab-wicklung wird mit MPI Wait gewartet. Vor Ruckkehr von MPI Wait darf derEmpfangspuffer nicht gelesen werden. Die Parameter von MPI Irecv entspre-chen denen von MPI Recv, nur das Argument status wurde durch ein Argu-ment request vom Typ MPI Request * ersetzt. Der Status einer empfangenenNachricht ist naturlich erst dann sinnvoll definiert, wenn die Nachricht bereits an-gekommen ist. Deshalb erhalt der Empfanger das Statusobjekt durch die FunktionMPI Wait.

Noch mehr Flexibilitat bietet die nicht blockierende Alternative zu MPI Wait.

int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status).

Die Funktion MPI Test uberpruft, ob der zu request gehorige Transfer abge-schlossen wurde. Falls ja, wird flag auf einen Wert ungleich null gesetzt, und

Page 213: [X.systems.press] Cluster Computing ||

7.5 Nicht blockierender Nachrichtentransfer 207

die Funktion verhalt sich genauso wie MPI Wait. Das Ticket request wird aufMPI REQUEST NULL gesetzt und status enthalt die Einzelheiten des Transfers.Die Funktion MPI Test kehrt aber auch dann zuruck, wenn der Transfer nochnicht abgeschlossen werden konnte. In diesem Fall wird flag auf null gesetzt undrequest behalt seinen Wert. Diese Funktion ist insbesondere dann nutzlich, wennein Prozess sinnvolle Alternativen zum Warten auf einen Nachrichtentransfer hat.

MPI_Test(&request, &flag, &status);if (flag) {

/ * Daten angekommen , v e r a r b e i t e s i e * /...

} else {/ * Daten noch n i c h t angekommen * // * mache e twas a n d e r e s und f r a g e s p a e t e r nochmal * /...

}

Bevor wir uns mit weiteren Eigenheiten und Spielarten nicht blockierender Kommu-nikation befassen, hier noch ein paar Bemerkungen:

Ruckkehrsemantik. Die Ruckkehrsemantik von MPI Test ist lokal, die von MPIWait ist nicht lokal (siehe Seite 192).

Kompatibilitat. Blockierende und nicht blockierende Transfers sind kompatibel zu-einander. Eine mit MPI Send abgeschickte Nachricht kann mit einem MPIIrecv empfangen, ahnliches gilt fur MPI Isend und MPI Recv.

Uberholverbot. Die ”Uberholregeln“ fur blockierende Transfers (Seite 204) geltenauch fur nicht blockierende Kommunikation.

Fairness. Fairness wird ebensowenig garantiert wie bei den blockierenden Operatio-nen.

Sendemodi. Ebenfalls wie bei der blockierenden Kommunikation gibt es vier nichtblockierende Sendemodi:• MPI Ibsend (gepuffertes Senden),• MPI Issend (synchrones Senden),• MPI Isend (Standardsenden) und• MPI Irsend (empfangsbereites Senden).Bei den ersten drei Modi zeigt sich der Unterschied nur in der Ruckkehrsemantikvon MPI Wait. Ein erfolgreiches MPI Wait zu einem MPI Issend bedeutetz. B., dass der Empfanger mit der Ubertragung in den Empfangspuffer begonnenhat usw. Die Funktion MPI Irsend fuhrt zu einem Fehler, wenn zum Zeitpunktihres Aufrufs kein passender Empfangswunsch vorliegt.

7.5.2 Zeitlicher Ablauf

Fehlende Blockaden bedeuten zusatzliche Freiheitsgrade im zeitlichen Miteinandervon Prozessen. Das kann manchmal zu unerwarteten Situationen fuhren. Betrachtenwir folgendes Beispiel:

flag1=0; flag2=0;if (myrank==0) {

Page 214: [X.systems.press] Cluster Computing ||

208 7 Grundlagen

MPI_Isend(buf1, count, MPI_DOUBLE, 1, 0, comm, &req1);MPI_Isend(buf2, count, MPI_DOUBLE, 1, 0, comm, &req2);while (!(flag1 && flag2)) {

if (!flag1) MPI_Test(&req1, &flag1, &status1);if (!flag2) MPI_Test(&req2, &flag2, &status2);

}} else if (myrank==1) {

MPI_Irecv(buf1, count, MPI_DOUBLE, 0, 0, comm, &req1);MPI_Irecv(buf2, count, MPI_DOUBLE, 0, 0, comm, &req2);while (!(flag1 && flag2)) {

if (!flag1) MPI_Test(&req1, &flag1, &status1);if (!flag2) MPI_Test(&req2, &flag2, &status2);

}}

Das Uberholverbot garantiert hier, dass die Daten aus buf1 des Senders in buf1des Empfangers landen und entsprechendes fur buf2 gilt. Was allerdings nicht ga-rantiert wird, ist die zeitliche Reihenfolge der vollstandigen Abwicklung. Es kanndurchaus sein, dass MPI Test die zweite Transaktion (flag2) vor der ersten Trans-aktion (flag1) ”fertigmeldet“. Außerdem ist die Reihenfolge dieser Fertigmeldung-en in Empfanger und Sender auch noch unabhangig voneinander. MPI-Implementie-rungen folgen zwar Regeln wie ”Anmeldungsreihenfolge bewahren“, ”kurze Nach-richten bevorzugen“ etc. Aber der Standard schreibt nichts vor und deshalb darf mansich hier auf nichts verlassen.

Was der Standard dagegen festschreibt, ist eine Art Fortschrittsgarantie. Sobaldzu einem Sendewunsch ein passender Empfangswunsch angemeldet wurde (oderumgekehrt), muss die MPI-Bibliothek diese Transaktion komplettieren. Diese Regelfuhrt dazu, dass folgendes Beispiel nicht zu einem deadlock fuhrt:

if (myrank==0) {MPI_Isend(buf1, count, MPI_DOUBLE, 1, tag, comm, &req);MPI_Recv(buf2, count, MPI_DOUBLE, 1, tag, comm, &status);MPI_Wait(&req, &status);

} else if (myrank==1) {MPI_Isend(buf1, count, MPI_DOUBLE, 0, tag, comm, &req);MPI_Recv(buf2, count, MPI_DOUBLE, 0, tag, comm, &status);MPI_Wait(&req, &status);

}

Das ist das klassische Szenario zweier Prozesse, die Daten austauschen. Mit blockie-render Kommunikation ware dies ein unsicheres Programm (siehe Abb. 7.15), dessenKorrektheit vom Zwischenpuffern der Nachricht abhangt. Dank nicht blockierendemSenden und Fortschrittsgarantie ist das obige Beispiel dagegen sicher. Der Prozess,der als zweiter MPI Recv aufruft, findet bereits einen passenden Sendewunsch vorund wird die Transaktion auf jeden Fall komplettieren. Nicht blockierende Kommuni-kation erlaubt so die Vermeidung von deadlocks ohne die Ressourcenverschwendungdurch das Puffern von Nachrichten. In diesem Licht betrachtet, gibt es eigentlich kei-nen Grund, den gepufferten, nicht blockierenden Sendemodus (MPI Ibsend) zuverwenden.

Page 215: [X.systems.press] Cluster Computing ||

7.5 Nicht blockierender Nachrichtentransfer 209

7.5.3 Flexibles Warten

Ein Prozess, der mehrere Transferwunsche gleichzeitig aktiviert hat, sollte bei derKomplettierung dieser Transfers flexibel sein. Sie wissen schon, das ubliche Argu-ment mit der unnotigen Reihenfolge. Dafur bietet der MPI-Standard drei Variantenvon MPI Wait und entsprechende Varianten von MPI Test.int MPI_Waitany(int count, MPI_Request *array_of_requests, int *index,

MPI_Status *status)

Diese Funktion erhalt in array of requests eine Liste von count offenenTransfers und kehrt zuruck, sobald irgendeiner davon komplettiert werden konn-te. Der Index des komplettierten Transfers wird in index zuruckgegeben undarray of requests[index] ist bei Ruckkehr auf MPI REQUEST NULL ge-setzt. Details des abgeschlossenen Transfers werden in status abgelegt. Die Funk-tion MPI Testany ist die entsprechende nicht blockierende Variante.int MPI_Testany(int count, MPI_Request *array_of_requests,

int *index, int *flag, MPI_Status *status)

Nur falls beim Aufruf mindestens einer der angegebenen Transfers abgewickelt wer-den konnte, wird flag auf einen Wert ungleich null gesetzt. In diesem Fall verhaltsich die Funktion genau wie MPI Waitany.

Will man nicht auf irgendeine der aufgefuhrten Transfers warten, sondern aufalle, so benutzt man MPI Waitall bzw. die nicht blockierende Variante MPITestall.int MPI_Waitall(int count, MPI_Request *array_of_requests,

MPI_Status *array_of_statuses)int MPI_Testall(int count, MPI_Request *array_of_requests, int *flag,

MPI_Status *array_of_statuses)

MPI Waitall kehrt erst dann zuruck, wenn alle in array of requests geliste-ten offenen Transfers abgeschlossen wurden. Die Funktion MPI Testall hingegenkehrt sofort zuruck, setzt aber flag nur dann auf einen Wert ungleich null, wenn al-le in array of requests gelisteten Transfers abgeschlossen wurden. Die Detailsder abgeschlossenen Transfers werden im Vektor array of statuses abgelegt,der naturlich groß genug sein muss, um alle count Elemente aufnehmen zu konnen.

Die meiste Flexibilitat bietet die Funktion MPI Waitsome.int MPI_Waitsome(int incount, MPI_Request *array_of_requests,

int *outcount, int *array_of_indices,MPI_Status *array_of_statuses)

Diese blockierende Funktion kehrt schon dann zuruck, sobald mindestens eine derangegebenen Transfers beendet wurde. Sind bereits mehrere Transaktionen abge-schlossen, kann MPI Waitsome dies dem Aufrufer auch anzeigen. Die Variableoutcount enthalt die Anzahl der komplettierten Transfers, die ersten outcountElemente von array of statuses deren Parameter. Die Indizes der komplet-tierten Transfers in array of requests werden in den ersten outcount Ele-menten von array of indices geliefert. Die nicht blockierende Variante vonMPI Waitsome heißt MPI Testsome.

Page 216: [X.systems.press] Cluster Computing ||

210 7 Grundlagen

int MPI_Testsome(int incount, MPI_Request *array_of_requests,int *outcount, int *array_of_indices,MPI_Status *array_of_statuses)

Im Gegensatz zu MPI Waitsome ist hier auch die Ruckkehr mit outcount = 0moglich.

Der MPI-Standard schreibt nicht vor, dass die Funktionen MPI Waitsome undMPI Testsome alle moglichen Transfers komplettieren mussen. In seinen advicesto implementors empfiehlt der Standard jedoch, bei jedem Aufruf soviel Transferswie moglich zu komplettieren. Diese Empfehlung zielt darauf ab, in Situationen wiein Abb. 7.16 eine gewisse Fairness zu gewahrleisten.

Listing 7.6 zeigt eine Variante des ”alle gegen einen“ Ping-Pong-Spiels mit nichtblockierendem Nachrichtenmanagement des zentralen Prozesses. Durch die Verwen-dung von MPI Waitsome wird es der Implementierung zumindest moglich ge-macht, alle zu diesem Zeitpunkt beim zentralen Prozess angemeldeten Transaktionenauch abzuarbeiten.

7.5.4 Persistente Kommunikation

Jeder Aufruf von MPI Isend erzeugt ein Ticket vom Typ MPI Request, das nachAbwicklung der Transaktion durch MPI Wait geloscht wird. Ein Prozess, der ineiner Schleife viele ahnliche Nachrichten (gleiche Anzahl, gleicher Typ) zum selbenPartner schickt, lost und annulliert bei jedem Durchlauf ein Ticket mit identischenParametern. Hier ware es effizienter, wenn ein Prozess eine Art ”Dauerticket“ losenkonnte, das fur beliebig viele Transaktionen gultig ist. Solche Dauertickets gibt esim MPI-Standard tatsachlich. Die Ausstellung eine Dauertickets fur einen Sendergeschieht mittels MPI Send init.

int MPI_Send_init(void *buf, int count, MPI_Datatype datatype,int dest, int tag, MPI_Comm comm, MPI_Request *request)

MPI Send init hat dieselben Parameter wie MPI Isend, verhalt sich aber an-ders.

• MPI Send init liefert ein Ticket, welches fur beliebig viele Transaktionengultig ist.

• MPI Send init stoßt keinerlei Transaktion an. Insbesondere braucht der Sen-depuffer buf beim Aufruf von MPI Send init noch keine Daten zu enthalten.

Nach Aufruf von MPI Send init ist die Transaktion mit Ticket request nochinaktiv. Aktiviert bzw. angestoßen wird sie erst durch einen Aufruf der FunktionMPI Start.

int MPI_Start(MPI_Request *request)

Auf die Abwicklung einer aktivierten Transaktion kann mit den ublichen BefehlenMPI Wait oder MPI Test gewartet werden. Anders als die ”Einmal-Tickets“ wirdein Dauerticket von MPI Wait nicht annulliert sondern nur inaktiviert. Mit einem

Page 217: [X.systems.press] Cluster Computing ||

7.5 Nicht blockierender Nachrichtentransfer 211

Listing 7.6. Auszug aus dem Programm all2oneI.c, der Variante des ”alle gegen einen“Ping-Pong-Spiels mit nicht blockierender Kommunikation durch den zentralen Prozess.

50 MPI_Barrier(MPI_COMM_WORLD);if (myrank==0) {

packets=0;d=numprocs-1;for (i=0; i<d; ++i)

55 MPI_Irecv(xlist[i], packetsize, MPI_INT, i+1,ping, MPI_COMM_WORLD, &requests[i]);

while (d>0) {MPI_Waitsome(numprocs-1, requests, &received, indices, statuses);for (i=0; i<received; ++i) {

60 j=indices[i];xlist[j][0]=++packets;MPI_Send(xlist[j], packetsize, MPI_INT, statuses[i].MPI_SOURCE,

pong, MPI_COMM_WORLD);if (packets>numpackets-numprocs+1)

65 --d;else

MPI_Irecv(xlist[j], packetsize, MPI_INT, statuses[i].MPI_SOURCE,ping, MPI_COMM_WORLD, &requests[j]);

}70 }

numpackets=packets;printf(” P r o z e s s 0 a u f %s h a t %u P a k e t e a %u Bytes a u s g e t a u s c h t .\ n ”,

procname, numpackets, sizeof(*x)*packetsize);printf(” Daran waren b e t e i l i g t :\ n ”);

75 for (d=1; d<numprocs; ++d) {MPI_Recv(procname, MPI_MAX_PROCESSOR_NAME+1, MPI_CHAR, d, 0,

MPI_COMM_WORLD, &status);MPI_Recv(&packets, 1, MPI_UNSIGNED_LONG, d, 0, MPI_COMM_WORLD,

&status);80 MPI_Recv(&t_ave, 1, MPI_DOUBLE, d, 0, MPI_COMM_WORLD, &status);

printf(” P r o z e s s %d a u f %s : %u Pake te , %l f ms pro P a k e t\n ”,d, procname, packets, t_ave);

}} else {

85 packets=0;t_ave=0;do {

t=MPI_Wtime();MPI_Send(x, packetsize, MPI_INT, 0, ping, MPI_COMM_WORLD);

90 MPI_Recv(x, packetsize, MPI_INT, 0, pong, MPI_COMM_WORLD,&status);

t=0.5*(MPI_Wtime()-t)*1000.0; / * M i l l i s e k u n d e n * /t_ave+=t;++packets;

95 } while (!(x[0]>numpackets-numprocs+1));t_ave=t_ave/((double)packets);MPI_Send(procname, namelength+1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);MPI_Send(&packets, 1, MPI_UNSIGNED_LONG, 0, 0, MPI_COMM_WORLD);MPI_Send(&t_ave, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);

100 }

Page 218: [X.systems.press] Cluster Computing ||

212 7 Grundlagen

0

500

1000

1500

2000

2500

3000

3500

4000

20 22 24 26 28 210 212 214 216 218 220 222

Ban

dbre

ite in

MB

it/s

Paketgröße in Byte

nicht blockierendpersistent

Abb. 7.18. Bandbreite beim Ringtausch nach Abb. 7.14 mit zwei Prozessen. Gemessen wurdeauf einem Dual-XEON shared memory System.

Aufruf von MPI Start kann die Transaktion danach wieder aktiviert werden. DieNachricht wurde dann (mit evtl. geandertem Inhalt) erneut ubertragen werden. Furdie endgultige Annullierung eines Dauertickets muss explizit die Funktion

int MPI_Request_free(MPI_Request *request)

aufgerufen werden, die request auf den Wert MPI REQUEST NULL setzt. DerNachrichtentransfer per Dauerticket wird persistente Kommunikation genannt.

Kurz gesagt: Beim persistenten Senden wird das Paar MPI Isend/Wait durchvier die Funktionen

MPI_Send_init(..., &request);...MPI_Start(&request);...MPI_Wait(&request, ...);...MPI_Request_free(&request);

ersetzt. Dabei kann das Paar MPI Start/Wait allerdings beliebig oft ausgefuhrtwerden, wahrend der Aufwand fur die Ticketverwaltung nur einmal anfallt. Ob undwie stark die Performance durch die reduzierte Ticketverwaltung gewinnt, hangtstark von der Applikation und dem unterliegenden Kommunikationssystem ab. Aufder Webseite zum Buch [7] finden Sie das Programm ringtausch.c, das Paket-laufzeiten nach dem Schema der Abb. 7.14 misst. Das Programm kann die Messungsowohl mit einfachem nicht blockierendem Transfer als auch mit der persistentenVariante durchfuhren.

Abbildung 7.18 zeigt das Resultat einer Messung mit ringtausch.c auf ei-nem Dual-Prozessor System (XEON 3 GHz) und Kommunikation uber shared memo-

Page 219: [X.systems.press] Cluster Computing ||

7.6 Der MPI-Standard 213

ry. Der Performance-Gewinn hangt von der Paketgroße ab und betragt hier maximal15 %.

Ein Dauerticket fur den Empfang von Nachrichten erhalt man mit der FunktionMPI Recv init.

int MPI_Recv_init(void *buf, int count, MPI_Datatype datatype,int src, int tag, MPI_Comm comm, MPI_Request *request)

Aktiviert wird das Empfangsticket genau wie beim Senden mit MPI Start. Eineganze Liste von Dauertickets reqs[0]. . .reqs[nreq-1] kann man mit

int MPI_Startall(int nreq, MPI_Request *reqs)

aktivieren. Dabei kann das Feld reqs auch eine Mischung von Sende- und Emp-fangstickets enthalten. Dauertickets gibt es naturlich fur alle vier Sendemodi. Ne-ben MPI Send init gibt also auch MPI Bsend init, MPI Ssend init undMPI Rsend init. Persistente und nicht persistente Transfers sind kompatibel zu-einander. Ein mit persistentem Ticket verschickte Nachricht kann mit einem ”Einmal-Ticket“ empfangen werden und umgekehrt.

7.6 Der MPI-Standard

Sie haben jetzt genug von MPI gesehen, um einen Blick in den Standard zu riskieren.Der komplette MPI-Standard definiert 280 Funktionen, von denen wir Ihnen bishernoch nicht einmal ein Funftel vorgestellt haben. Einige weitere werden in den nachs-ten Abschnitten noch folgen, aber eine vollstandige Diskussion des MPI-Funktions-umfanges wurde den Rahmen dieses Buches sprengen. Das sollte Sie nicht daranhindern, Ihre Applikationen mit den bisher vorgestellten Funktionen zu realisieren.Schließlich gilt fur MPI wie fur die meisten anderen Programmier-Bibliotheken die80-20-Regel: Mehr als 80 % aller Anwendungen kommen mit weniger als 20 % desFunktionsumfanges aus.

Allerdings sollten Sie uber die restlichen 80 % wenigstens grob Bescheid wissen.Der folgende Uberblick uber den Standard soll Ihnen als Orientierungshilfe dienen.

7.6.1 MPI-1 und MPI-2

Der MPI-Standard wurde vom MPI-Forum, einem Komitee aus Vertretern von Indus-trie, Forschungseinrichtungen und Universitaten entwickelt. Das MPI-Forum tagteerstmals 1993 mit dem Ziel, einen einheitlichen, portablen Standard zur Programmie-rung nachrichtenparalleler Anwendungen zu entwerfen. Im Juni des Jahres 1995 ver-abschiedete das MPI-Forum die Version 1.1 des Message Passing Interfaces [102].

Die Arbeit des Komitees war damit aber keineswegs beendet. Erste Erfahrungenmit MPI 1.1 und Diskussionen mit den Anwendern fuhrten dazu, dass das Komi-tee im Juli 1997 ein zweites Dokument veroffentlichte [103]. Im ersten Teil diesesDokumentes wurden einige Unklarheiten der Version 1.1 beseitigt und verschiedene

Page 220: [X.systems.press] Cluster Computing ||

214 7 Grundlagen

Kleinigkeiten hinzugefugt. Zusammen mit dem Dokument von 1995 bildet dieserTeil die Version 1.2 des MPI-Standards, der bis heute als MPI-1 maßgeblich ist.

Im zweiten Teil des neuen Textes wird MPI um grundlegend neue Konzepte undFunktionen erweitert. Der Standard, der diese erweiterte Funktionalitat umfasst, er-hielt die Versionsummer 2. Der MPI-Standard ist demnach zweiteilig: MPI-1 (womitimmer die Version 1.2 gemeint ist) definiert die Grundfunktionen, MPI-2 fugt Erwei-terungen hinzu. Dabei gilt Aufwartskompatibilitat: jedes korrekte MPI-1 Programmist auch ein korrektes MPI-2 Programm. Allerdings wurden in MPI-2 einige Funk-tionen aus MPI-1 als deprecated, also unerwunscht gekennzeichnet und gegen neuefunktional gleichwertige Funktionen ersetzt. Die betroffenen Funktionen sind jedochnoch immer gultiger Teil des MPI-Standards, von ihrer Verwendung wird lediglichabgeraten.

Beide Teile legen Semantik und Syntax der Programmierschnittstelle in den Spra-chen C und FORTRAN fest, MPI-2 definiert daruberhinaus noch eine Schnittstellefur C++. Die Dokumente, die den MPI-Standard definieren [102, 103], sind fur tech-nische Standards uberraschend gut lesbar. Neben Beispielen zur Illustration werdenauch die Hintergrunde fur die eine oder andere Designentscheidung prasentiert.

Die Version 1 des MPI-Standards beschreibt und definiert

• Punkt-zu-Punkt-Kommunikation,• kollektive Kommunikation,• Kommunikatormanagement,• Prozesstopologien,• Fehlerbehandlung und• Profiling-Interface.

Die wesentlichen neuen Konzepte, die mit MPI-2 eingefuhrt wurden, sind

• dynamische Prozesserzeugung,• Einseitige Kommunikation,• erweiterte kollektive Operationen,• Funktionen zur Kommunikation zwischen MPI-Programmen, die in verschieden

Sprachen programmiert wurden,• parallele Ein- und Ausgabe und• C++-Interface.

Punkt-zu-Punkt- und kollektive Kommunikation haben wir in den zuruckliegendenAbschnitten relativ ausfuhrlich behandelt. Kommunikatormanagement, Prozesstopo-logien und die Fehlerbehandlung sind Gegenstand des folgenden Kapitels, ebensowie die parallele Ein- und Ausgabe aus MPI-2. Einige andere Punkte werden wirhier nur im Uberblick behandeln. Eine ausfuhrliche Darstellung finden Sie naturlichim Standard.

Die meisten Implementierungen sind MPI-1-konform und enthalten bereits großeTeile von MPI-2. Dass eine MPI-Implementation den vollen MPI-2-Funktionsum-fang unterstutzt, ist jedoch die Ausnahme. Dies leistet z. B. die kommerzielle Bi-bliothek ChaMPIon/Pro und auch das Open-MPI-Projekt [121] hat es sich zumZiel gesetzt, den gesamten MPI-2-Standard zu implementieren. Dass die meisten

Page 221: [X.systems.press] Cluster Computing ||

7.6 Der MPI-Standard 215

Listing 7.7. FORTRAN-77-Version mpiident.f des minimalistischen MPI-Programm ausListing 7.1.

PROGRAM MPIIDENTIMPLICIT NONEINCLUDE ” mpif . h ”INTEGER MYRANK, NPROCS, LENGTH, ERROR

5 CHARACTER(LEN=MPI_MAX_PROCESSOR_NAME) NAME

CALL MPI_INIT(ERROR)CALL MPI_COMM_SIZE(MPI_COMM_WORLD, NPROCS, ERROR)CALL MPI_COMM_RANK(MPI_COMM_WORLD, MYRANK, ERROR)

10 CALL MPI_GET_PROCESSOR_NAME(NAME, LENGTH, ERROR)WRITE (*, *) ’Prozess ’, MYRANK, ’ (von ’, NPROCS,+ ’) lauft auf ’, NAME(1:LENGTH)CALL MPI_FINALIZE(ERROR)END

MPI-Bibliotheken nur eine Teilmenge des MPI-Standards implenentieren, sollte Sieaber nicht zu sehr storen. Die wenigen fehlenden Funktionen sind meist eher exoti-scher Natur und werden in der Regel nur von sehr ambitionierten MPI-Anwendernbenotigt.

7.6.2 FORTRAN-Schnittstelle

Bisher haben wir fur unsere MPI-Programme ausschließlich die Sprache C verwen-det. Wollen oder mussen Sie fur Ihre Projekte MPI-Programme in FORTRAN schrei-ben, so konnen Sie das bisher Gelernte leicht auf den Dinosaurier unter den Program-miersprachen ubertragen. In Listing 7.7 sehen Sie dafur ein kleines Beispiel. Wie inListing 7.1 ermittelt auch hier jeder Prozess seinen Rang, die Große des Kommunika-tors MPI COMM WOLRD und den Namen des Knotens, auf dem er gerade lauft, undgibt diese Daten aus. Wie Sie in Listing 7.1 und 7.7 sehen, sind C- und FORTRAN-Schnittstelle zu den MPI-Funktionen sich sehr ahnlich. Zu jeder C-MPI-Funktionenexistiert eine gleichnamige FORTRAN-MPI-Subroutine, die die gleichen Argumenteerwartet und die gleiche Funktionalitat implementiert. Da FORTRAN-Subroutinenkeine Ruckgabewerte haben, wird der Fehlercode im letzten Argument zuruckgeben.Statt der Headerdatei mpi.h werden MPI-spezifische Konstanten fur FORTRAN inmpif.h definiert.

Eine kleine Besonderheit gibt es bei Kommunikatoren, Statusargumenten undlogischen Argumenten zu beachten. Vergleichen wir dazu einmal die Funktion

int MPI_Iprobe(int source, int tag, MPI_Comm comm, int *flag,MPI_Status *status)

mit ihrem FORTRAN-Pendant.

MPI_IPROBE(SOURCE, TAG, COMM, FLAG, STATUS, IERROR)LOGICAL FLAGINTEGER SOURCE, TAG, COMM, STATUS(MPI_STATUS_SIZE), IERROR

Page 222: [X.systems.press] Cluster Computing ||

216 7 Grundlagen

Listing 7.8. C++-Version mpiident.cc des minimalistischen MPI-Programm aus Lis-ting 7.1.

#include <iostream>#include <cstdlib>#include ” mpi . h ”

5 int main(int argc, char *argv[]) {char name[MPI::MAX_PROCESSOR_NAME+1];

MPI::Init(argc, argv);int nprocs=MPI::COMM_WORLD.Get_size();

10 int myrank=MPI::COMM_WORLD.Get_rank();int len;MPI::Get_processor_name(name, len) ;name[len]= ’\0 ’;std::cout << ” P r o z e s s ” << myrank << ” ( von ” << nprocs

15 << ” ) l a u f t a u f ” << name << ” .\ n ”;MPI::Finalize();return EXIT_SUCCESS;

}

Kommunikatoren und andere Objekte, die in C durch einen eigenen Datentyp darge-stellt werden, sind in FORTRAN einfach Ganzzahlen vom Typ INTEGER. Ein Kom-munikationsstatus wird gleich durch ein ganzes Feld der Lange MPI STATUS SIZEreprasentiert. Die Funktion MPI Iprobe testet, ob eine empfangsbereite Nachrichtvorliegt, und gibt das Ergebnis in flag zuruck. In Ermangelung eines logischenDatentyps wird diese Information in C in einer Ganzzahlvariablen abgelegt. Entspre-chende FORTRAN-Subroutinen verwenden in solchen Situationen den binaren Da-tentyp LOGICAL.

7.6.3 C++-Schnittstelle

MPI-2 definiert eine vollstandige C++-Schnittstelle zur MPI Bibliothek. Das Designvon MPI basierte von Anfang an auf eigenen, opaken Datentypen wie MPI Comm,MPI Request, MPI Status etc. (siehe auch Abschnitt 8.1.2). Dieser Ansatzkommt einer C++ Klassenbibliothek naturlich sehr entgegen. Das C++-Interface istdementsprechend eleganter und schlanker als die prozeduralen Schnittstellen von Coder FORTRAN. Wenn Sie in C++ programmieren, haben Sie die Wahl zwischender C und der C++-Schnittstelle zu MPI, aber mit Ersterer gewinnt Ihr Programmetwas an Ubersichtlichkeit und Eleganz.

Auch hier wollen wir Ihnen wenigstens ein kleines Beispiel geben, siehe Lis-ting 7.8. Wie schon in Listing 7.1 und 7.7 ermittelt auch hier jeder Prozess seinenRang, die Große des Kommunikators MPI COMM WOLRD und den Namen des Kno-tens, auf dem er gerade lauft, und gibt diese Daten aus. Aufgrund des objektorien-tierten Designs ist der Unterschied zwischen C- und C++-Schnittstelle etwas großerals zwischen C- und FORTRAN-Schnittstelle. Zunachst ist aber auch hier die Hea-derdatei mpi.h einzubinden. In ihr sind alle notwendigen Datenstrukturen und derNamensraum MPI definiert. Er ubernimmt in C++ im Wesentlichen die Funktion

Page 223: [X.systems.press] Cluster Computing ||

7.6 Der MPI-Standard 217

des MPI -Prafixes der C-Funktionen. Sie mussen also jeder MPI-Funktion, jedemMPI-Typ, jeder MPI-Konstanten usw. ein MPI:: voranstellen. Die nachste wichtigeAnderung ist, dass Kommunikatoren, MPI-Datentypen usw. in C++ durch Klassenreprasentiert werden. Der großte Teil der MPI-Funktionalitat ist als Methoden dieserKlassen implementiert. So entspricht z. B. der Funktion MPI Send in C++ die Me-thode Send der Klasse MPI::Comm. Der Kommunikator MPI COMM WORLD istin C++ eine Instanz dieser Klasse und heißt MPI::COMM WORLD. Das Versendeneiner Nachricht konnte also so aussehen:

MPI::COMM_WOLD.Send(buf, count, MPI::DOUBLE, dest, tag);

Desweiteren werden in C++ Fehler nicht durch den Ruckgabewert einer Funktionsignalisiert, stattdessen wird im Falle eines Fehlers eine Ausnahme ausgelost. Funk-tionen liefern entweder keinen Ruckgabewert oder aber das Ergebnis einer Operation,siehe Zeile 9 in Listing 7.1.

Alle weiteren Unterschiede zwischen C- und C++-Schnittstelle sind eher kosme-tischer Natur und kommen faulen Programmierern entgegen. So werden in C++ eini-ge Parameter, die in C als Zeiger ubergeben werden mussen, als Referenz ubergeben(vergleiche Zeile 9 in Listing 7.1 und Zeile 8 in Listing 7.8) und manche Parameter,die in C zwingend ubergeben werden mussen, durfen in C++ weggelassen werden.Dies betrifft z. B. die Empfangsfunktionen, deren Statusargument in C++ nur fakul-tativ ist.

Auf der LAM/MPI Webseite [89] finden Sie eine Liste, die die FORTRAN-77-,C- und C++-Syntax aquivalenter MPI-Funktionen gegenuberstellt. Wenn Sie einge-fleischter C++-Programmierer sind, werden Sie sicher die C++-Schnittstelle bevor-zugen. Leider stammt diese Schnittstellendefinition aus einer Zeit, in der realexistie-rende C++-Compiler den C++-Standard oft nur luckenhaft implementierten, weshalbdie MPI-C++-Schnittstellendefinition nicht alle Moglichkeiten dieser Programmier-sprache nutzt. Abgesehen von einer Kapselung in Klassen und etwas syntaktischemZucker ist, wie Sie gesehen haben, die MPI-C++-Schnittstellendefinition aquivalentzur C-Variante. Dies erleichtert zwar den Wechsel zwischen den Programmierspra-chen, bedeutet aber auch, dass die MPI-C++-Schnittstelle nicht so komfortabel undeinfach zu benutzen ist, wie es moglich ware. Diesen Nachteil versucht Object Ori-ented MPI (OOMPI) [119] zu umgehen. Dabei handelt es sich um eine vollkom-men neue objektorientierte Implementierung einer C++-Schnittstelle zu den MPI-Funktionen des MPI-Standards in der Version 1.1.

7.6.4 Profiling-Interface

Laut MPI-Standard muss jede MPI-Funktion auch unter einem zweiten Namen auf-rufbar sein. Genauer gesagt, muss jede Funktion MPI xyz auch unter dem NamenPMPI xyz aufrufbar sein. Das ”P“ steht fur profiling. Der Sinn dieser Doppelna-men besteht darin, MPI-Funktionsaufrufe so abfangen zu konnen und in eine eigeneFunktion, in der beispielsweise Daten fur ein Ablaufprofil gesammelt werden, umzu-lenken. Eine entsprechende eigene Version der Funktion MPI Send konnte etwa soaussehen:

Page 224: [X.systems.press] Cluster Computing ||

218 7 Grundlagen

static int totalBytes;static double totalTime;

int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest,5 int tag, MPI_comm comm) {

double tstart=MPI_Wtime();int extent;int result=PMPI_Send(buffer, count, datatype, dest, tag, comm);MPI_Type_size(datatype, &extent); / * Groes se d a t a t y p e i n b y t e * /

10 totalBytes+=count*extent;totalTime +=MPI_Wtime()-tstart;return result;

}

Wird der Objekt-Code dieser Funktion vor der MPI-Bibliothek gegen die Anwen-dung gelinkt, so landen alle Aufrufe von MPI Send in der eigenen Routine. Dadiese ihrerseits PMPI Send aufruft, ”merkt“ die Anwendung von der Umleitungnichts. Die Ausgabe der Profilingdaten konnte dann in einer eigenen Version vonMPI Finalize erfolgen.

Eine Bibliothek, die samtliche MPI-Funktionen auf diese Weise abfangt, kannden Kommunikationsablauf in einer Anwendung vollstandig protokollieren, ohneauf den Quellcode der Anwendung oder der MPI-Bibliothek zugreifen zu mussen.Das Multi Processing Environment (MPE), eine Sammlung von Programmen und Bi-bliotheken zur Analyse von MPI-Anwendungen, macht von dieser Technik Gebrauch(Notiz 10.3).

7.6.5 Dynamische Prozesserzeugung

Ein Charakteristikum von MPI-1.2 ist die konstante Anzahl von Prozessen, die ei-ne MPI-Anwendung ausmachen. Sie muss beim Start einer Anwendung festgelegtwerden und kann danach nicht mehr verandert werden. In der Version 2 des MPI-Standards wurde diese Restriktion aufgehoben, Prozesse konnen nun bei Bedarf auchdynamisch erzeugt werden. Dafur, diese neue Funktionalitat in den Standard aufzu-nehmen, gab es sowohl technische als auch praktische Grunde.

Einige parallele Anwendungen erfordern es, dass die Zahl der parallelen Prozes-se im Laufe eines Programms dynamisch angepasst wird. Muss ein Programm einerechenintensive aber gut parallelisierbare Teilaufgabe losen, konnte es zusatzlicheProzesse erzeugen und danach wieder vernichten, um dann als paralleles Programmmit wenigen Prozessen oder gar als sequentielles Programm weiterzulaufen. Bei die-sem Programmiermodell kommen und gehen die Prozesse ganz nach Bedarf.

Zusammen mit der dynamischen Prozesserzeugung bietet MPI-2 auch die Mog-lichkeit, getrennt gestartete, unabhangige MPI-Programme miteinander kommuni-zieren zu lassen. Damit konnen nun auch Programme nach dem Client-Server-Modell geschrieben werden. Hier kommen und gehen Prozesse, wie es ihnen gefallt.Wahrend ein Prozess (bzw. eine Prozessgruppe) permanent vorhanden ist (Server),werden andere Prozesse (Clients) wahrend der Laufzeit des Servers aber ohne seinZutun erzeugt. Mit einem solchen Client-Server-Modell ließe sich z. B. das Master-Worker-Schema (Abschnitt 9.1.3) mit variabler Workerzahl realisieren.

Page 225: [X.systems.press] Cluster Computing ||

7.6 Der MPI-Standard 219

PP 01

W MM

Abb. 7.19. Einseitige Kommunikation: Prozess P0 deklariert einen Ausschnitt W (window)seines Speichers als offentlich und erlaubt anderen Prozessen wie P1, darauf lesend und schrei-bend zuzugreifen.

Der historische Vorlaufer von MPI, die Parallel Virtual Machine (PVM), arbei-tete ausschließlich nach dem Prinzip der dynamischen Prozesserzeugung. Zu denpraktischen Grunden, MPI um Funktionen zur dynamischen Prozesserzeugung zuerweitern, durfte darum zahlen, dass sich dadurch PVM-Programme (zumindest po-tentiell) leichter nach MPI portieren lassen.

In der Umgebung eines Batch-Systems ist die dynamische Erzeugung und Ver-nichtung von MPI-Prozessen etwas problematisch. Sie ist hier nur sinnvoll, wenndas Batch-System nicht nur einmalig eine fixe Zahl von Prozessoren zur Verfugungstellt, sondern ein MPI-Programm auch bei Bedarf zusatzliche Prozessoren beimBatch-System anfordern bzw. Prozessoren dem Batch-System zuruckgeben kann.

7.6.6 Einseitige Kommunikation

Beim Nachrichtenversand unter MPI mussen sowohl der Sender- als auch der Emp-fangerprozess aktiv werden. Beide mussen stets Einigkeit daruber bewahren, wievie-le und welche Nachrichten sie noch austauschen werden. Diese Abstimmung kann inkomplizierteren Fallen zu einem erhohten Kommunikationsbedarf fuhren (polling).Mit MPI-2 wurde deshalb eine neue Form der Kommunikation eingefuhrt, bei dernur noch ein Prozess aktiv werden muss (Abb. 7.19).

Bei dieser einseitigen Kommunikation definiert ein Prozess einen Bereich seinesSpeichers (window genannt), auf den andere Prozesse lesend und schreibend zugrei-fen konnen. Mit der einseitigen Kommunikation wird quasi ein gemeinsamer Spei-cher simuliert, inklusive der damit verbundenen Probleme wie der Synchronisationkonkurrierender Speicherzugriffe. Eine Technik zur Synchronisation arbeitet ahnlichwie die Mutex-Variablen bei den Threads (Abschnitt 3.2). Hier kann ein Prozess nurdann in das ”Fenster“ schreiben, wenn er im Besitz des einzigen Schlussels ist. Die-sen Schlussel muss er vorher vom MPI-System erfragen und nach der Operationwieder abgeben. MPI bietet eine ganze Palette von weiteren, zum Teil sehr flexiblenSynchronisationsmechanismen, aber jede Synchronisation impliziert auch Kommu-nikation. Einseitige Kommunikation ist deshalb keineswegs per definitionem effizi-enter als das ubliche ”Rendezvous“ zwischen Sender- und Empfanger. Die Arbeitmit einseitiger Kommunikation ist auch riskanter, da die Synchronisation in der Ver-antwortung des Programmierers liegt. Wahrend ein Programmierfehler beim traditio-nellen Nachrichtenaustausch meistens zu kaum ubersehbaren Fehlern wie deadlocks

Page 226: [X.systems.press] Cluster Computing ||

220 7 Grundlagen

oder Absturzen fuhrt, hat eine mangelnde Synchronisation oftmals ”nur“ falsche Er-gebnisse zur Folge.

7.7 Notizen

7.1 Argumente von MPI Init. MPI-1 erlaubt es Implementierungen, darauf zubestehen, dass MPI Init dieselben Argumente erhalt wie main. MPI-2 verbietetdiese Einschrankung jedoch. Um MPI auch dann initialisieren zu konnen, wennkein Zugriff auf die Argumente von main besteht (z. B. in Bibliotheken), musseine zu MPI-2 konforme Implementierung auch akzeptieren, dass MPI Init mitNullzeigern aufgerufen wird. Sie sollten die Parameter von main grundsatzlich anMPI Init weiterreichen. Dann lauft Ihr Programm auch in Umgebungen, die sichnur an MPI-1 orientieren.

7.2 MPI ohne Initialisierung. Auf Seite 168 hieß es, dass keine andere MPI-Funk-tion aufgerufen werden darf, bevor nicht MPI Init aufgerufen wurde. Aber keineRegel ohne Ausnahme. Ein Aufruf von

int MPI_Initialized(int *flag)

ist jederzeit gestattet. MPI Initialized setzt flag auf einen Wert ungleich null,falls das MPI-System bereits initialisiert wurde. Ist das nicht der Fall, wird flag aufnull gesetzt. Damit kann z. B. eine Bibliothek feststellen, ob das Anwendungspro-gramm bereits die MPI-Initialisierung vorgenommen hat oder nicht. In der Version 2des MPI-Standard wird außerdem die Funktion

int MPI_Finalized(int *flag)

definiert. Mit ihr lasst sich feststellen, ob bereits MPI Finalize aufgerufen wurde.Auch sie darf zu jeder Zeit, also insbesondere auch vor MPI Init und nach MPIFinalize, ausgefuhrt werden.

7.3 Ein-Ausgabe-Problem. Eines der Probleme, die vom MPI-Standard nicht ge-regelt werden, ist der Zugriff auf Standardausgabe, -eingabe und -fehlerausgabe.Durfen MPI-Prozesse uberhaupt darauf zugreifen? Und wenn ja, wo landen z. B.die Ausgaben? Die meisten Implementierungen bieten hier eigene Losungen an. BeiLAM/MPI z. B. wird die Standardeingabe bei allen Prozessen mit einem Rang inMPI COMM WORLD großer null nach /dev/null umgeleitet, d. h., nur Rang nullkann von der Standardeingabe lesen. Die Ausgabekanale werden fur alle Prozesseauf die Ausgabekanale des Kommandos umgeleitet, welches die MPI-Applikationgestartet hat, also ublichwerweise mpirun oder mpiexec. LAM/MPI sorgt beider Ausgabe der verschiedenen Prozesse dafur, dass diese sich niemals innerhalb ei-ner Zeile uberlagern (line buffered output). In Abschnitt 10.1 wird uns diese Proble-matik noch einmal beschaftigen. Der Standard definiert allerdings eine Moglichkeit(durch Attribute eines Kommunikators), uber die einem MPI-Programm mitgeteiltwerden kann, welche Prozesse (wenn uberhaupt) uber die ublichen I/O-Fahigkeitenverfugen.

Page 227: [X.systems.press] Cluster Computing ||

7.7 Notizen 221

7.4 MPI-Typen 1. Warum fuhrt MPI eigene Typbezeichnungen wie MPI DOUBLEein? Ist das in stark typisierten Programmiersprachen wie C und C++ nicht uber-flussig? Die MPI-Typen wurden vor allem aus Grunden der Interpretationssicherheiteingefuhrt. Die interne Darstellung gleicher C-Datentypen kann auf verschiedenenSystemen unterschiedlich sein. Auf 32-Bit-CPUs besteht ein int-Wert aus vier By-tes, die nacheinander im Speicher angeordnet sind. Zum Beispiel steht

1129783047 = 67 ·2563 +87 ·2562 +31 ·256+7

entweder als Folge (67,87,31,7) im Speicher (little-endian, niedrigwertiges Bytezuerst) oder als Folge (7,31,87,67) (big-endian, hochstwertiges Byte zuerst). Intel-Prozessoren verwenden z. B. das little-endian-Format, wahrend z. B. Prozessoren derFirma Motorola das big-endian-Format benutzen. Die Typangabe MPI Int erlaubtes MPI, die interne Darstellung in eine im ganzen MPI-Universum gultige Darstel-lung umzuwandeln. Damit ist gewahrleistet, dass aus einer Zahl auf ihrem Wegvon einer little-endian Architektur zu einer big-endian-Architektur nicht die Zahl1129494467 wird. Diese Problematik unterschiedlicher Formate betrifft grundsatz-lich alle Multi-Byte-Datentypen, unter anderem auch Fließkommazahlen. Bei Pro-grammiersprachen wie C++ oder FORTRAN 90, die Polymorphismus unterstutzen,hatte man dieses Problem naturlich durch eigene Ubertragungsfunktionen fur jedenelementaren Datentyp losen konnen, aber der MPI-Standard wurde so definiert, dasser auch in nicht polymorphen Sprachen wie C und FORTRAN 77 implementiert wer-den kann.

7.5 Broadcast. Netzwerk-Protokolle wie Ethernet und TCP/IP erlauben ein Broad-cast auf Protokollebene. Eine MPI-Implementierung, welche diese Moglichkeit aus-nutzt, konnte die Ausfuhrungszeit kollektiver Operationen wie MPI Bcast oderMPI Barrier damit quasi unabhangig von der Anzahl der Prozesse machen. Dasist fur große Cluster durchaus interessant, wird aber von den gangigen MPI-Imple-mentierungen nicht unterstutzt.

7.6 Extremum lokalisieren. Neben den Reduktionsoperatoren MPI MIN und MPIMAX zur Berechnung des Minimums bzw. des Maximums verteilter Daten mit MPIReduce gibt es die Varianten MPI MINLOC und MPI MAXLOC, die zusatzlich zumWert des Extremums auch dessen Index ermitteln.

7.7 Assoziative Reduktionsoperatoren. Manche Operatoren, die in der Theoriekommutativ oder assoziativ sind, verlieren diese Eigenschaften bei in der Realitatdarstellbarer Datentypen. Das gilt insbesondere fur Operationen mit Fließkomma-zahlen. Das Beispiel

float x=1e30, eps=1e-30;printf(” x + eps − x = %e\n ”, x+eps-x);printf(” x − x + eps = %e\n ”, x-x+eps);

liefert fur vier Byte große float-Typen bei der ersten Ausgabe 0, bei der zweitendagegen 1e-30. Wenn das Ergebnis wie hier von der Reihenfolge der Einzelberech-nungen abhangt, ist das Resultat von MPI Reduce nicht determiniert. Der Standard

Page 228: [X.systems.press] Cluster Computing ||

222 7 Grundlagen

empfiehlt, MPI Reduce und Co. so zu implementieren, dass Aufrufe mit denselbenAusgangsdaten auch jedesmal dasselbe Ergebnis liefern. Verlassen sollte man sichdarauf im Zweifelsfall aber nicht.

7.8 Asynchroner Nachrichtentransport. Sowohl beim gepufferten Senden als auchbei den nicht blockierenden Operationen vertraut man darauf, dass das MPI-SystemNachrichten weitertransportiert, wahrend der aufrufende Prozess schon wieder dieKontrolle erhalten hat. Damit dieser asynchrone Nachrichtentransport funktionierenkann, muss im Prinzip jede Transaktion von MPI in einem eigenen Thread abgewi-ckelt werden. Einige kommerzielle MPI-Implementierungen sind tatsachlich multithreaded, aber die meisten frei verfugbaren Implementierungen wie LAM/MPI sindes nicht. In solchen single threaded MPI-Bibliotheken wird der Nachrichtentrans-port immer nur dann vorangetrieben, wenn der Kontrollfluss vom Nutzerprozessin die MPI-Bibliothek geht. Allerdings konnen auch single threaded BibliothekenNachrichten asynchron transportieren, namlich dann, wenn die Nachricht so kleinist, dass Sie ”in einem Stuck“ an den unterliegenden Transportmechanismus uberge-ben werden kann und dieser selbst in einem eigenen Thread ablauft. Bei LAM/MPIist das z. B. der Fall, falls der Transport uber TCP und mit Nachrichtenlangen kleinerals 65536 Byte erfolgt. Auf der Webseite zum Buch [7] finden Sie das Programmcheckasync.c, mit dem Sie uberprufen konnen, ob Ihre MPI-Implementationden asynchronen Nachrichtentransport unterstutzt. Sie sollten aber auch dann nichtblockierenden Operationen den Vorzug geben, wenn Ihre MPI-Bibliothek noch kei-nen echten asynchronen Nachrichtentransport erlaubt. Erstens nutzen Sie damit dieSystemressourcen in jedem Fall besser aus (Notiz 7.9) und zweitens ist Ihre Appli-kation damit fur eine zukunftige multi-threaded MPI-Implementierung wie das freiverfugbare Open MPI [121] bestens gerustet.

7.9 Duplex-Betrieb. Moderne Interconnects bieten Vollduplex-Betrieb, und auf je-der Punkt-zu-Punkt-Verbindung steht die volle Bandbreite in beiden Richtungenzur Verfugung. Die Verwendung nicht blockierender Transfers ermoglicht es, ei-nem Prozess, Sende- und Empfangswunsche lokal zu sammeln und mit dem erstenblockierenden Aufruf einer MPI-Funktion gemeinsam abzuwickeln. Damit wird diedoppelte Bandbreite des Vollduplex-Modus fur den MPI Nachrichtenverkehr ausge-nutzt. Mit blockierenden Punkt-zu-Punkt-Operationen (außer MPI Sendreceive)ist das nicht moglich.

Page 229: [X.systems.press] Cluster Computing ||

8

Fortgeschrittene Techniken

Parallel machines are hard to program and we should makethem even harder—to keep the riff-raff off them.

Gary Montry

8.1 Kommunikator- und Gruppenmanagement

8.1.1 Motivation

In Kapitel 7 haben Sie gelernt, dass alle MPI-Kommunikationsfunktionen den Daten-austausch innerhalb eines Kommunikators abwickeln. Nach der Initialisierung mitMPI Init ist jeder lokale Prozess Mitglied in zwei verschieden Kommunikatoren,in MPI COMM WORLD und in MPI COMM SELF. Im Kommunikator MPI COMMWORLD werden alle Prozesse zusammengefasst, mit denen der lokale Prozess uber-haupt kommunizieren kann, MPI COMM SELF besteht nur aus dem lokalen Prozessselbst.

Gabe es nur diese zwei vordefinierten Kommunikatoren, ware das Konzept derKommunikatoren nichts weiter als ein aufgeblasener Formalismus. Wirklich nutzlichwerden Kommunikatoren dadurch, dass man zur Programmlaufzeit weitere Kommu-nikatoren konstruieren kann. Warum ist so etwas nutzlich?

Kollektive Operationen wirken immer auf alle Prozesse eines Kommunikators.Da wir bisher nur den Kommunikator MPI COMM WORLD verwendet haben, warenan kollektiven Operationen immer alle uberhaupt vorhandene Prozesse beteiligt. Kol-lektive Operationen lassen sich aber auch gezielt auf ausgewahlte Untermengen vonProzessen einschranken. Dazu benotiYgt man nur einen entsprechenden Kommuni-kator, der an Stelle von MPI COMM WORLD als Argument in die kollektiven Funkti-onen eingeht. Außerdem sind Kommunikatoren fur Programmierer paralleler Biblio-theken wichtig. Durch sie lassen sich die Kommunikation innerhalb von Bibliotheks-funktionen und die Kommunikation eines Anwendungsprogramms voneinander ent-koppeln.

Bevor wir uns jedoch ausfuhrlich mit der Konstruktion neuer Kommunikatorenbeschaftigen konnen, sind noch ein paar konzeptionelle Vorbemerkungen notwendig.

8.1.2 Undurchsichtige Objekte

Eine MPI-Bibliothek verwaltet eine Reihe von internen Datenstrukturen, die wirzum Teil noch kennenlernen werden. Dazu gehoren u. a. Kommunikatoren, Grup-

Page 230: [X.systems.press] Cluster Computing ||

224 8 Fortgeschrittene Techniken

pen, Tickets oder auch Fehler-Behandlungs-Funktionen. Diese Datenstrukturen sindundurchsichtig, man sagt auch opak. Ihr interner Aufbau bleibt dem Nutzer der MPI-Bibliothek vollkommen verborgen. Er kann darum diese Datentypen auch nicht di-rekt manipulieren. Stattdessen wird auf sie durch abstrakte Referenzen, sog. Hand-les, zugegriffen. MPI-Funktionen, die interne Datenstrukturen verandern, wird einHandle als Argument ubergeben, das der Funktion z. B. mitteilt, innerhalb welchesKommunikators ein bestimmter Nachrichtenaustausch ablauft.

Fur jeden Handletyp definiert der MPI-Standard eine Null-Handle-Konstante,z. B. MPI COMM NULL fur Kommunikatoren. Null-Handles reprasentieren ungulti-ge Handles und haben eine ahnliche Semantik wie Nullzeiger in Bezug auf Zeiger.Eine Liste aller Null-Handles finden Sie in Tabelle 14.4. Handles vom gleichen Typkonnen miteinander auf (Un-)Gleichheit getestet werden. Durch den Vergleich mitdem entsprechenden Null-Handle lasst sich so, die Gultigkeit des Handles testen.Außerdem durfen Handles einander zugewiesen werden. So referenzieren die beidenKommunikatoren world1 und world2 nach

MPI_Comm world1, world2;...world2=world1;

den gleichen Kommunikator. Im Gegensatz dazu wird mit

MPI_Comm world1, world2;...MPI_Comm_dup(world1, &world2);

ein vollkommen neuer Kommunikator world2 erzeugt, der aus den gleichen Prozes-sen besteht, wie world1. (Wir stellen die Funktion MPI Comm dup unten genauervor.) Beide Vorgehensweisen sind nicht aquivalent. Im ersten Fall wird eine Referenzauf ein Objekt kopiert, im zweiten das Objekt selbst.

Werden interne Datenstrukturen nicht mehr benotigt, so lassen sie sich von ei-ner MPI-Funktion loschen. Dieser Funktion wird ein Zeiger auf ein Handle auf daszu loschenden Objekt ubergeben. Eine Funktion zum Loschen interner unsichtigerDatenstrukturen haben Sie schon in Abschnitt 7.3.5 kennengelernt, MPI Op freeloscht die internen Daten fur eine Reduktionsoperation. Da das Objekt, auf das dasHandle verweist, nachdem es geloscht wurde, nicht mehr existiert, wird dem Handlevon der Funktion außerdem eine Null-Handle-Konstante zugewiesen. Im Falle vonMPI Op free ist dies die Konstante MPI OP NULL.

Wenn ein Handle den Wert einer Null-Handle-Konstanten hat, so zeigt der Hand-le mit Sicherheit auf kein gultiges Objekt. Umgekehrt gilt aber nicht, dass ein Hand-le auf ein gultiges Objekt verweist, wenn es nicht den Wert einer Null-Handle-Konstanten hat. Solche ungultigen Handles (dangling handle oder dangling refe-rence) erhalt man immer dann, wenn ein Handle in ein zweites kopiert wurde undspater das Objekt, auf das das erste Handle verweist, geloscht wurde. Das zweiteHandle ist nach dem Loschen des Objekts weiterhin kein Null-Handle, zeigt aberauch nicht mehr auf ein noch existierendes Objekt. Eines Referenzierung des zwei-ten Handles in einer MPI-Funktionen fuhrt sofort zu einem Fehler.

Page 231: [X.systems.press] Cluster Computing ||

8.1 Kommunikator- und Gruppenmanagement 225

8.1.3 Kommunikatoren kopieren und teilen

Kommen wir aber nun zu den Kommunikatoren zuruck. Am einfachsten lasst sichein neuer Kommunikator durch die Funktion MPI Comm dup erzeugen.

int MPI_Comm_dup(MPI_Comm comm, MPI_Comm *newcomm)

Sie erzeugt eine Kopie newcomm des Kommunikators commmit identischer Prozess-gruppe. Das erlaubt z. B. die eindeutige Charakterisierung von Nachrichten (sieheSeite 173). Eine Bibliothek, die in ihrer Initialisierungsroutine

MPI_Comm myworld;...MPI_Comm_dup(MPI_COMM_WORLD, &myworld);

verwendet und fur samtliche Nachrichtentransfers den Kommunikator myworld be-nutzt, wird niemals mit Nachrichten aus anderen Teilen einer Anwendung interferie-ren. MPI Comm dup ist eine kollektive Operation und muss von allen Prozessen incomm aufgerufen werden.

Eine Beschrankung kollektiver Operationen auf eine Untermenge von Prozessenlasst sich mit einer Kopie von MPI COMM WORLD naturlich nicht erreichen. Dazubraucht man die Funktion MPI Comm split.

int MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm *newcomm)

Sie unterteilt den Kommunikator comm in mehrere Kommunikatoren mit disjunktenProzessgruppen. Als kollektive Operation muss MPI Comm split von allen Pro-zessen in comm aufgerufen werden. MPI Comm split verortet jeden Prozess in ei-nem neuen Kommunikator newcomm. Dabei landen alle Prozesse mit dem gleichenWert von color auch im selben neuen Kommunikator. Die Rangordnung der Pro-zesse innerhalb des neuen Kommunikators wird durch den Wert von key bzw. beigleichem key-Wert durch die Ordnung im alten Kommunikator geregelt. Betrachtenwir als Beispiel einem Kommunikator mit zehn Prozessen:

Rang 0 1 2 3 4 5 6 7 8 9Prozess a b c d e f g h i jcolor 0 ⊥ 3 0 0 3 0 0 5 ⊥key 3 1 2 5 1 1 1 2 1 0

Das Symbol ⊥ steht fur den vordefinierten Wert MPI UNDEFINED. Ein Aufruf vonMPI Comm split mit diesen Parametern ordnet die Prozesse in drei neuen Kom-munikatoren an.

color Kommunikator

0 (e,g,h,a,d)3 ( f ,c)5 (i)

Page 232: [X.systems.press] Cluster Computing ||

226 8 Fortgeschrittene Techniken

MPI_COMM_WORLD

COM1 COM2

c d g i

hfeba

Abb. 8.1. Gruppenbildung: Die Prozesse (e, f ,g) haben in MPI COMM WORLD die Range(4,5,6), in COM2 dagegen die Range (0,1,2).

Die Prozesse b und j mit color = MPI UNDEFINED werden keinem neuen Kom-munikator zugeordnet und sie erhalten in newcomm das Null-Handle MPI COMMNULL. Ein MPI-Prozess kann zugleich in mehreren Kommunikatoren vertreten sein,darum bleibt mit der Erzeugung eines neuen Kommunikators der ursprungliche Kom-munikator bestehen. Da in jeder Gruppe die Prozessrange mit null beginnend durch-nummeriert werden, hat ein Prozess in verschiedenen Kommunikatoren auch ver-schiedene Range (siehe Abb. 8.1). Seinen Rang innerhalb eines Kommunikatorserfahrt ein Prozess wie ublich mit MPI Comm rank.

Wenn ein Kommunikator nicht mehr benotigt wird, sollten alle Prozesse auscomm die kollektive Funktion

int MPI_Comm_free(MPI_Comm *comm)

aufrufen. Dadurch werden die von comm belegten Ressourcen vom MPI-System frei-geben. Der Kommunikator hat nach dem Funktionsaufruf den Wert des das Null-Handles MPI COMM NULL.

8.1.4 Prozessgruppen

Mehr Moglichkeiten zur Konstruktion von Kommunikatoren bieten MPI-Funktionen,mit denen Prozessgruppen direkt manipuliert werden. Normalerweise ist eine Pro-zessgruppe in einen Kommunikator eingebettet. Fur eine direkte Manipulation mussman sich zunachst eine Zugriffsmoglichkeit auf die Prozessgruppe eines Kommuni-kators verschaffen. Das geschieht mit der Funktion

int MPI_Comm_group(MPI_Comm comm, MPI_Group *grp)

die in grp ein Handle auf die Prozessgruppe von comm liefert. Prozessgruppen wer-den in MPI durch den opaken Datentyp MPI Group reprasentiert. Die Funktion

int MPI_Comm_create(MPI_Comm comm, MPI_Group grp, MPI_Comm *newcomm)

erzeugt einen neuen Kommunikator newcomm mit der Prozessgruppe grp. Dabeimuss comm ein bereits vorhandener Kommunikator sein, der alle Prozesse in grpenthalt. MPI Comm create ist eine kollektive Funktion, sie muss von allen Prozes-sen des alten Kommunikators comm aufgerufen werden, auch solchen, die nicht in

Page 233: [X.systems.press] Cluster Computing ||

8.1 Kommunikator- und Gruppenmanagement 227

grp enthalten sind. Letztere erhalten MPI PROC NULL als Wert fur newcomm. DerAufruf scheitert, wenn grp keine Untermenge der Gruppe von comm ist oder nichtauf allen aufrufenden Prozessen identisch ist. Die Befehlsfolge

MPI_Comm_group(comm, &grp);MPI_Comm_create(comm, grp, &newcomm);

erzeugt eine Kopie von comm und ist aquivalent zu

MPI_Comm_dup(comm, &newcomm);

Sinnvoll wird das explizite ”Herausgreifen“ der Prozessgruppe erst durch dieMoglichkeiten, die die MPI-Bibliothek zur Erzeugung neuer Prozessgruppen bietet.Neue Gruppen werden in MPI immer aus bereits vorhandenen Gruppen erzeugt, z. B.mit der Funktion MPI Group incl.

int MPI_Group_incl(MPI_Group grp, int n, int *rank, MPI_Group *newgrp)

Hier wird aus der Vorlage grp die neue Gruppe newgrp erzeugt. Die neue Grup-pe enthalt n Prozesse, wobei Rang i der neuen Gruppe dem Rang rank[i]der Vorlage entspricht. Komplementar zu MPI Group incl arbeitet die FunktionMPI Group excl.

int MPI_Group_excl(MPI_Group grp, int n, int *rank, MPI_Group *newgrp)

Die Auswahl der Prozesse entspricht der bei MPI Group incl, nur werden hierdie nicht ausgewahlten Prozesse in der Ordnung ihrer Range aus grp in die neueGruppe newgrp ubertragen. Ein Beispiel: Mit

grp= (a,b,c,d,e, f ,g) , n= 3 und rank= [6,0,2]

liefert MPI Group incl die Gruppe ( f ,a,c) und MPI Group excl die Gruppe(b,d,e,g). Man kann mit MPI Group incl auch alle Prozesse der alten in die neueGruppe ubernehmen und dabei die Range in der neuen Gruppe beliebig permutieren.

Bei MPI Group incl muss jeder Prozess, der in die neue Gruppe ubernom-men werden soll, explizit spezifiziert werden. Folgt die Auswahl der Prozesse einemeinfachen Muster, so kann man stattdessen auch die Funktion

int MPI_Group_range_incl(MPI_Group grp, int n, int ranges[][3],MPI_Group *newgrp)

verwenden. Hier enthalt ranges genau n Tripel, und jedes Tripel spezifiziert eineFolge von Rangen, die in die neue Gruppe ubernommen werden sollen. Die erstenbeiden Werte eines Tripels geben den ersten und den letzten Rang an, der dritte Wertden Abstand aufeinanderfolgender Range. Das macht man sich am besten an einemBeispiel klar. Seien

grp= (a,b,c,d,e, f ,g,h, i, j) , n= 3 und ranges= [[6,7,1], [1,6,2], [0,9,4]] .

Das erste Tripel spezifiziert die Gruppe (g,h), das zweite (b,d, f ) und das dritteschließlich (a,e, i). Insgesamt liefert MPI Group range incl damit die Gruppe(g,h,b,d, f ,a,e, i).

Page 234: [X.systems.press] Cluster Computing ||

228 8 Fortgeschrittene Techniken

Auch zu MPI Group range incl gibt es eine Variante, die das Komplementder Auswahl in die neue Gruppe uberfuhrt. Sie heißt MPI Group range excl.

int MPI_Group_range_excl(MPI_Group grp, int n, int ranges[][3],MPI_Group *newgrp)

Bei der Berechnung der Range durch MPI Group range incl bzw. MPIGroup range excl muss jeder Rang einem Prozess in grp entsprechen und al-le berechneten Range mussen verschieden voneinander sein. Ein Verletzung dieserBedingung fuhrt zu einem Fehler.

Aus zwei Gruppen grp1 und grp2 lassen sich mit Hilfe der ublichen Mengen-verknupfungen leicht neue Gruppen bilden.

int MPI_Group_union(MPI_Group grp1, MPI_Group grp2, MPI_Group *newgrp)int MPI_Group_intersection(MPI_Group grp1, MPI_Group grp2,

MPI_Group *newgrp)int MPI_Group_difference(MPI_Group grp1, MPI_Group grp2, MPI_Group *newgrp)

Die Ordnung der Range in der resultierenden Vereinigungs-, Schnitt- oder Differen-zengruppe ist dabei wie folgt festgelegt:

MPI Group union. Alle Elemente aus grp1 (unter Wahrung ihrer Ordnung), ge-folgt von allen Elementen aus grp2, die nicht in grp1 enthalten sind (ebenfallsunter Wahrung ihrer Ordnung).

MPI Group intersection. Alle Elemente aus grp1, die auch in grp2 enthal-ten sind, unter Wahrung ihrer Ordnung in grp1.

MPI Group difference. Alle Elemente aus grp1, die nicht in grp2 enthaltensind, unter Wahrung ihrer Ordnung in grp1.

Bei der Festlegung der Ordnung gibt das erste Argument grp1 den Ton an. Andersals bei ungeordneten Mengen sind die Operationen auf Gruppen deshalb nicht kom-mutativ. Betrachten wir ein Beispiel mit grp1= (a,b,c,d) und grp2= (d,a,e):

• MPI Group union(grp1, grp2, &newgrp)=⇒ newgrp= (a,b,c,d,e)MPI Group union(grp2, grp1, &newgrp)=⇒ newgrp= (d,a,e,b,c)

• MPI Group intersection(grp1, grp2, &newgrp)=⇒ newgrp= (a,d)MPI Group intersection(grp2, grp1, &newgrp)=⇒ newgrp= (d,a)

• MPI Group difference(grp1, grp2, &newgrp)=⇒ newgrp= (b,c)MPI Group difference(grp2, grp1, &newgrp)=⇒ newgrp= (e)

Bei der Erzeugung neuer Gruppen kann es durchaus vorkommen, dass eine neueGruppe keine Prozesse enthalt. In diesem Fall hat newgrp den Wert MPI GROUPEMPTY.

Page 235: [X.systems.press] Cluster Computing ||

8.1 Kommunikator- und Gruppenmanagement 229

Die Erzeugung einer neuen Gruppe mit den hier beschriebenen Funktionen isteine rein lokale Angelegenheit, d. h., sie verursacht keine Kommunikation zwischenden Prozessen. Verschiedene Prozesse konnen unterschiedliche Gruppen erzeugen,und ein Prozess kann auch Gruppen erzeugen, in denen er selbst nicht enthalten ist.In diesem Fall liefert MPI Group rank (siehe unten) den Wert MPI UNDEFINED.Sobald man eine Gruppe zur Erzeugung eines neuen Kommunikators verwendet,muss die Gruppendefinition auf allen beteiligten Prozessen allerdings konsistent sein.Zur Erinnerung: MPI Comm create ist eine kollektive, d. h. nichtlokale Operation,die von allen Prozessen des Ausgangskommunikators aufgerufen werden muss.

Wenn man eine Gruppe nicht mehr benotigt, weil man z. B. den entsprechendenKommunikator erzeugt hat, sollte man das durch die Funktion

int MPI_Group_free(MPI_Group *grp)

dem MPI System mitteilen. Dadurch werden eventuell belegte Ressourcen freigege-ben und grp auf MPI GROUP NULL gesetzt.

Damit man bei komplexen Gruppenbildungen nicht den Uberblick verliert, bietetder MPI-Standard eine Reihe von Funktionen an, mit denen die Eigenschaften vonGruppen ermittelt werden konnen. So lassen sich die Anzahl der Prozesse in einerGruppe sowie der eigene Rang darin, analog zu den entsprechenden Funktionen furKommunikatoren, mit

int MPI_Group_size(MPI_Group grp, int *size)

und

int MPI_Group_rank(MPI_Group grp, int *rank)

bestimmen. Mit der Funktion MPI Group compare lassen sich zwei Gruppen ver-gleichen.

int MPI_Group_compare(MPI_Group grp1, MPI_Group grp2, int *result).

Sie liefert in result den Wert MPI IDENT, MPI SIMILAR oder MPI UNEQUAL.

MPI IDENT. Die Gruppen grp1 und grp2 enthalten dieselben Prozesse in dersel-ben Ordnung.

MPI SIMILAR. Die Gruppen grp1 und grp2 enthalten zwar dieselben Prozesseaber in unterschiedlicher Ordnung.

MPI UNEQUAL. Dieser Wert wird in allen anderen Fallen zuruckgegeben.

Eine Art ”Ubersetzungstabelle“ fur die Range zweier Gruppen erhalt man mit derFunktion MPI Group translate ranks.

int MPI_Group_translate_ranks(MPI_Group grp1, int n, int *ranks1,MPI_Group grp2, int *ranks2)

Diese Funktion liefert in ranks2 die Range von n Prozessen in grp2, die perranks1 aus grp1 ausgewahlt wurden. Prozesse, die nicht in grp2 enthalten sind,liefern dabei als Rang MPI UNDEFINED.

Page 236: [X.systems.press] Cluster Computing ||

230 8 Fortgeschrittene Techniken

Ein Beispiel: grp1= (a,b,c,d,e, f ) und grp2= (e,a, f ). Ein Aufruf von MPIGroup translate ranks mit n= 3 und ranks1= (0,2,4) liefert ranks2=(1,⊥,0), wobei hier ⊥ fur MPI UNDEFINED steht.

8.2 Fehlerbehandlung

Eine MPI-Bibliothek stellt dem Nutzer einen zuverlassigen Datenaustausch zur Ver-fugung. Gesendete Nachrichten werden korrekt empfangen und der Nutzer muss sich(normalerweise) nicht um Ubertragungsfehler oder time-outs sorgen. Alle Ubertra-gungsfehler, die innerhalb des Kommunikationssystems, auf dem die MPI-Imple-mentation aufsetzt, auftreten, mussen soweit moglich von der MPI-Bibliothek selbstbehandelt werden. Nur sehr schwerwiegende, nicht behebbare Fehler werden an denNutzer weitergereicht.

Neben dem Kommunikationssystem kann ein MPI-Programm auch selbst Quel-le fur Fehler sein. Ein Fehler kann auftreten wenn, MPI-Funktionen mit ungulti-gen Argumenten aufgerufen werden, wenn in einer Sendefunktion ein langst mitMPI Comm free geloschter Kommunikator oder ein nicht existierender Empfangs-rang verwendet wird oder ein Empfangspuffer zu klein ist. Der MPI-Standard kenntzwar keine Mechanismen, mit denen die Wirkung aufgetretener Fehler vollstandigbehoben werden kann, jedoch konnen Fehler detektiert und ihre Auswirkungen we-nigstens beschrankt werden.

Wann immer in einer MPI-Funktion ein Fehler auftritt, wird zunachst eine Fehler-Behandlungs-Funktion aufgerufen. Bei schweren Fehlern bricht diese Funktion daslaufende Programm ab. Bei weniger schweren Fehlern kann sie auch weniger radi-kal reagieren und z. B. nur eine Fehlermeldung erzeugen. In diesem Fall gibt dieFunktion, in der der Fehler auftrat, außerdem einen Wert ungleich MPI SUCCESSzuruck. Jedem Kommunikator kann eine eigene Fehler-Behandlungs-Funktion zu-geordnet werden. Da Fehler in den Kommunikationsfunktionen als sehr schwerwie-gend angesehen werden, legt der MPI-Standard fur alle Kommunikatoren die Fehler-Behandlungs-Funktion MPI ERRORS ARE FATAL fest. Sie bricht das laufende Pro-gramm sofort ab. Eine zweite vom MPI-Standard vordefinierte Fehler-Behandlungs-Funktion heißt MPI ERRORS RETURN. Ist die mit einem Kommunikator verknupf-te Fehler-Behandlungs-Funktion gleich MPI ERRORS RETURN, so werden alle imKontext dieses Kommunikators auftretenden Fehler zunachst ignoriert und Kommu-nikationsfunktionen, die auf diesem Kommunikator operieren, kehren mit einemWert ungleich MPI SUCCESS zuruck, sobald in ihnen ein Fehler auftritt.

MPI SUCCESS ist der einzige Fehlercode, den der MPI-Standard verbindlichdefiniert, alle anderen Fehlercodes sind vollkommen implementationsspezifisch. Da-durch konnen MPI-Implementationen ihre Nutzer mit praktisch beliebig spezifischenFehlermeldungen versorgen. Um aber Fehlercodes implementationsubergreifend we-nigstens grob klassifizieren zu konnen, gehort jeder Fehlercode einer Oberklasse vonFehlern an, die sich mit der Funktion MPI Error class ermitteln lasst.

int MPI_Error_class(int errorcode, int *errorclass)

Page 237: [X.systems.press] Cluster Computing ||

8.2 Fehlerbehandlung 231

In Tabelle 14.5 finden Sie eine Ubersicht uber alle Fehlerklassen. Ein Fehlercodekann mit der Funktion MPI Error string in eine lesbare Nachricht umgewandeltwerden.

int MPI_Error_string(int errorcode, char *string, int *resultlen)

Diese Funktion legt in string eine maximal MPI MAX ERROR STRING Zeichenlange Fehlernachricht ab.

Wie aber schon oben beschrieben, kann Ihr Programm diese Fehlercodes norma-lerweise gar nicht auswerten, da bei einem Fehler die Fehler-Behandlungs-FunktionMPI ERRORS ARE FATAL ausgefuhrt wird, die so wirkt, als wurde MPI Abortmit dem betroffenen Kommunikator aufgerufen, und die betroffenen Prozesse been-det. Wollen Sie auf eventuelle Fehler reagieren konnen, mussen Sie MPI ERRORSRETURN oder eine eigene Fehler-Behandlungs-Funktion mit einem Kommunikatorverknupfen. Dies geschieht durch die Funktion MPI Errhandler set.

int MPI_Errhandler_set(MPI_Comm comm, MPI_Errhandler errhandler)

Analog dazu kann man auch die aktuelle Fehler-Behandlungs-Funktion eines Kom-munikators mit MPI Errhandler get abfragen.

int MPI_Errhandler_get(MPI_Comm comm, MPI_Errhandler *errhandler)

Die beiden Fehler-Behandlungs-Funktion MPI ERRORS ARE FATAL und MPIERRORS RETURN sind Extremlosungen, Fehler entweder als so fatal ansehen, dasssie das Programm abbrechen, oder Fehler einfach ignorieren. Wollen Sie etwas diffe-renzierter auf Fehler reagieren, so schreiben Sie sich eine eigene Fehler-Behandlungs-Funktion. Fehler-Behandlungs-Funktionen mussen immer der Signatur

typedef void (MPI_Handler_function)(MPI_Comm *, int *, ...);

entsprechen. Im ersten Argument wird der Funktion immer der Kommunikator undals zweites Argument der Fehlercode ubergeben, eventuelle weitere Argumentesind implementationsspezifisch. Bevor Ihre Fehler-Behandlungs-Funktion mit einemKommunikator verknupft werden kann, muss sie beim MPI-System durch die Funk-tion MPI Errhandler create angemeldet werden.

int MPI_Errhandler_create(MPI_Handler_function *function,MPI_Errhandler *errhandler)

Wird eine Fehler-Behandlungs-Funktion nicht mehr benotigt, kann sie mit MPIErrhandler free auch wieder aus dem MPI-System entfernt werden.

int MPI_Errhandler_free(MPI_Errhandler *errhandler)

Nach dem Aufruf dieser Funktion enthalt das ubergebene Handle den Wert MPIERRHANDLER NULL.

Das Listing 8.1 zeigt, wie man Fehler-Behandlungs-Funktionen praktisch ver-wendet. Wir haben absichtlich einen kleinen Fehler in das Programm eingebaut. Hiersendet der erste Prozess eine Nachricht an den zweiten. Startet man es mit nur einemProzess, existiert kein Empfangsprozess. In den Zeilen 5 bis 19 finden Sie unsere

Page 238: [X.systems.press] Cluster Computing ||

232 8 Fortgeschrittene Techniken

Listing 8.1. Das Programm error.c demonstriert den Einsatz eigener Fehler-Behandlungs-Funktionen.

#include <stdlib.h>#include <stdio.h>#include ” mpi . h ”

5 void comm_errhandler(MPI_Comm *comm, int *err) {int err_cl, err_len;char err_str[MPI_MAX_ERROR_STRING+1];fprintf(stderr, ” K o m m u n i k a t i o n s f e h l e r\n ”);/ * F e h l e r k l a s s e * /

10 MPI_Error_class(*err, &err_cl);MPI_Error_string(err_cl, err_str, &err_len);err_str[err_len]= ’\0 ’;fprintf(stderr, ” e r r o r c l a s s : %s\n ”, err_str);/ * F e h l e r c o d e * /

15 MPI_Error_string(*err, err_str, &err_len);err_str[err_len]= ’\0 ’;fprintf(stderr, ” e r r o r code : %s\n ”, err_str);MPI_Abort(*comm, EXIT_FAILURE); / * Programm a b b r e c h e n * /

}20

int main(int argc, char *argv[]) {int C_rank, C_size, x[10];MPI_Status status;MPI_Errhandler errh_old, errh_new;

25MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD, &C_rank);MPI_Comm_size(MPI_COMM_WORLD, &C_size);

/ * a l t e F e h l e r b e h a n d l u n g s r o u t i n e s i c h e r n und30 e i g e n e F e h l e r b e h a n d l u n g s r o u t i n e r e g i s t r i e r e n * /

MPI_Errhandler_get(MPI_COMM_WORLD, &errh_old);MPI_Errhandler_create((MPI_Handler_function *)(&comm_errhandler),

&errh_new);MPI_Errhandler_set(MPI_COMM_WORLD, errh_new);

35 / * Kommunikation * /if (C_rank==0) {

MPI_Send(x, 10, MPI_INT, 1, 0, MPI_COMM_WORLD);fprintf(stderr, ” Daten e r f o l g r e i c h g e s e n d e t\n ”);

}40 if (C_rank==1) {

MPI_Recv(x, 10, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);fprintf(stderr, ” Daten e r f o l g r e i c h empfangen\n ”);

}/ * a l t e F e h l e r b e h a n d l u n g s r o u t i n e wiede r r e g i s t r i e r e n * /

45 MPI_Errhandler_set(MPI_COMM_WORLD, errh_old);MPI_Errhandler_free(&errh_new);MPI_Finalize();return EXIT_SUCCESS;

}

Page 239: [X.systems.press] Cluster Computing ||

8.2 Fehlerbehandlung 233

Fehler-Behandlungs-Funktion. Sie gibt lediglich eine Fehlermeldung aus und been-det das Programm. Sobald in einer MPI-Funktion ein Fehler aufgetreten ist, ist esvollkommen undefiniert, welche Wirkung weitere Aufrufe von MPI-Funktionen ha-ben. In der Praxis konnen Fehler-Behandlungs-Funktionen lediglich fur einen geord-neten Programmabbruch sorgen, offene Dateien schließen usw. Ihre Aufgabe ist esnicht, sicherzustellen, dass ein MPI-Programm nach einem Fehler problemlos weiter-laufen kann. Allerdings verbietet es der Standard auch nicht, nach einem Fehler wei-tere MPI-Funktionen zu verwenden. Eine besonders robuste MPI-Implementationkonnte auch garantieren, dass selbst nach einem Fehler weitere Aufrufe von MPI-Funktionen problemlos moglich sind. Dann leistet sie jedoch deutlich mehr als derStandard verlangt. In der Praxis sollte jedoch zumindest der Aufruf von MPI Abortnoch moglich sein.

In den Zeilen 29 bis 34 werden die alte Fehler-Behandlungs-Funktionen gesi-chert und die neue Fehler-Behandlungs-Funktion comm errhandler mit demKommunikator MPI COMM WORLD verknupft. Falls bei den folgenden Sende- undEmpfangsfunktionen ein Fehler auftritt, so wird er nun von comm errhandlerabgefangen. Mit zwei Prozessen arbeitet das Programm korrekt.

bauke@server:˜/src$ mpirun -np 2 errorDaten erfolgreich gesendetDaten erfolgreich empfangen

Starten wir es mit nur einem Prozess, erhalten wir eine von der Fehler-Behandlungs-Funktion erzeugte Fehlermeldung. Die textliche Beschreibung eines Fehlers hangtvon der MPI-Implementation ab. Mit LAM/MPI (Version 7.1.1) erhalten wir:

bauke@server:˜/src$ mpirun -np 1 errorKommunikationsfehlererror class: MPI_Error_string: invalid rankerror code : MPI_Error_string: invalid rank

Und MPICH2 (Version 1.0.1) meldet:

bauke@server:˜/src$ mpirun -np 1 ./errorKommunikationsfehlererror class: Invalid rankerror code : Invalid rank, error stack:MPI_Send(177): MPI_Send(buf=0xbffff5b0, count=10, MPI_INT, dest=1, tag=0,MPI_COMM_WORLD) failedMPI_Send(97): Invalid rank has value 1 but must be nonnegative and lessthan 1aborting job:application called MPI_Abort(MPI_COMM_WORLD, 1) - process 0rank 0 in job 4 server_32977 caused collective abort of all ranksexit status of rank 0: killed by signal 9

Wobei hier ein Teil der Ausgaben von MPI Abort verursacht wurden.Bei Bedarf kann eine alte Fehler-Behandlungs-Funktion auch wieder aktiviert

werden, wie am Ende des Programms gezeigt. Auf diese Weise kann man fur be-stimmte Programmabschnitte geziehlt spezielle Fehler-Behandlungs-Funktionen nut-zen.

Page 240: [X.systems.press] Cluster Computing ||

234 8 Fortgeschrittene Techniken

Im Abschnitt 8.4 uber parallele Dateizugriffe mit MPI-2 werden wir uns nocheinmal mit Fehlern in MPI-Funktionen beschaftigen. Dort werden Sie sehen, dassneben Kommunikatoren auch Dateien Fehler-Behandlungs-Funktionen zugeordnetwerden konnen.

8.3 Nutzerspezifische Datentypen

8.3.1 Motivation

Der MPI-Standard definiert eine Reihe von MPI-Grunddatentypen (Tabelle 14.1), diejeweils zu einem C-Datentyp korrespondieren. Mussten sich MPI-Programmierer aufdiese MPI-Grunddatentypen beschranken, so ließen sich verschiedene Kommunikati-onsmuster nicht effizient abwickeln. Darum enthalt der MPI-Standard verschiedeneFunktionen, mit denen aus den Grunddatentypen weitere MPI-Datentypen angelei-tet werden konnen. Diese neuen Datentypen konnen ihrerseits dazu genutzt werden,weitere noch komplexere Datentypen zu konstruieren.

Angenommen Sie wollten eine Struktur vom Typ

typedef struct {int x;double y;char str[13];

} coord;

versenden. Da keine der MPI-Grunddatentypen dieser Struktur entspricht, waren ins-gesamt drei Aufrufe von MPI Send bzw. MPI Recv notwendig, um diese Strukturauszutauschen, einer fur jedes Element der Struktur. Konnte man die Struktur in einereinzigen Nachricht austauschen, ware dies deutlich eleganter und auch effizienter.

Ein weiteres wichtiges Szenario, in dem sich nutzerspezifische MPI-Datentypenals notwendig erweisen, ist der Austausch von mehrdimensionalen Feldern bzw. Tei-len davon. Betrachten wir ein C-Feld mit 3× 4 Elementen. Seine zwolf Elementewerden vom Compiler zeilenweise kontinuierlich im Hauptspeicher abgelegt, sie-he Abb. 8.2. Da die Elemente kontinuierlich im Speicher liegen, bereitet der Aus-tausch des ganzen Feldes kein Problem. Dazu mussen die Adresse des ersten Ele-mentes ubergeben und das count-Argument der Sende- bzw. Empfangsfunktion

logische Anordnung

physische Anordnung im Arbeitsspeicher

[2][0]

[1][0]

[0][2][0][3]

[0][0][0][1][0][2][0][3] [1][0] [2][0]

[1][1][1][2][1][3]

[2][3][2][2][2][1]

[1][1][1][2][1][3] [2][1][2][2][2][3]

[0][0][0][1]

Abb. 8.2. Physische Anordnung der Elemente des C-Feldes A[3][4] im Arbeitsspeicher.

Page 241: [X.systems.press] Cluster Computing ||

8.3 Nutzerspezifische Datentypen 235

lediglich auf zwolf gesetzt werden. Das Versenden einer einzelnen Zeile basiert aufder gleichen Idee. Hier ist die Adresse des ersten Elementes der entsprechenden Zei-le und deren Lange zu ubergeben. Problematisch sind die Spalten eines Feldes. Dadie Elemente einer Spalte nicht kontinuierlich im Speicher liegen (Zwischen ihnensind Lucken.), kann sie nicht durch einen einzigen Funktionsaufruf versendet bzw.empfangen werden. Stattdessen mussen die Elemente einer Spalte erst in einen tem-poraren kontinuierlichen Puffer umkopiert werden, aus dem sie dann mit einem ein-zigen Aufruf von z. B. MPI Send versendet werden konnen. Durch die Definitionnutzerspezifischer MPI-Datentypen lasst sich eine einzelne Spalte eines Feldes ohnegroßen Aufwand und Umkopieren austauschen. Auch der Austausch kompliziertererTeilmatrizen wie beliebiger rechteckiger Ausschnitte oder einer oberen Dreiecksma-trix bereiten bei der Verwendung nutzerspezifischer Datentypen keine Kopfschmer-zen mehr.

8.3.2 Der Aufbau von MPI-Datentypen

Ein MPI-Datentyp ist ein undurchsichtiges Objekt, das vom Programmierer nur uberMPI-Bibliotheksfunktionen manipuliert werden kann. Auch wenn der genaue inter-ne Aufbau eines MPI-Datentyps vor dem Programmierer vorborgen bleibt, so lasstsich doch etwas uber die grundlegende Struktur eines MPI-Datentyps sagen. Ein all-gemeiner MPI-Datentyp besteht aus

• einer Liste von Grundtypen und• einer Liste von Distanzadressen (displacements).

Distanzadressen mussen weder positiv, verschieden noch geordnet sein. Die Liste derDistanzadressen eines MPI-Datentyps ist darum nicht zwingend mit der physischenSpeicherreprasentation des entsprechenden C-Typs identisch. Distanzadressen in ei-ner Liste von Distanzadressen durfen sogar (fur Sendeoperationen) identisch sein.Die Liste von Grundtypen heißt auch Typsignatur eines allgemeinen MPI-Datentyps.Die Liste von Grundtypen und die Liste von Distanzadressen bilden zusammen dieTypbeschreibung (type map). Symbolisch lasst sich eine Typbeschreibung Tmap mitden Grundtypen ti und den Distanzadressen di als geordnetes Tupel

Tmap = {(t0,d0),(t1,d1), . . . ,(tn−1,dn−1)} (8.1)

und eine Typsignatur alsTsig = {t0, t1, . . . , tn−1} (8.2)

schreiben. Der MPI-Datentyp MPI INT hat z. B. die Typbeschreibung

Tmap = {(int,0)} . (8.3)

Die anderen Typen in Tabelle 14.1 haben einen analogen Aufbau.Zusammen mit einer Speicheradresse b bildet diese Typbeschreibung einen Kom-

munikationspuffer. Er beinhaltet n Eintrage. Der i-te Eintrag steht an der Speicher-adresse b + di und hat den Typ ti. Ist das count-Argument einer Sende- bzw. Emp-fangsfunktion großer als eins, so wird der Kommunikationspuffer durch entspre-chend ofte Wiederholung der Typbeschreibung gebildet.

Page 242: [X.systems.press] Cluster Computing ||

236 8 Fortgeschrittene Techniken

Um die Konstruktion nutzerspezifischer MPI-Datentypen im Detail zu verstehen,mussen wir noch die Begriffe Ausdehnung (extend) extent(T ), obere ub(T ) und un-tere Beschrankung lb(T ) (upper bound und lower bound) eines Typs T einfuhren.

lb(T ) = mini

di (8.4)

ub(T ) = maxi

(di + sizeof(ti))+ ε (8.5)

extent(T ) = ub(T )− lb(T ) (8.6)

Die Ausdehnung gibt also an, wie groß der Speicherbereich ist, uber den sich einDatentyp erstreckt. Das ε steht fur eventuelle Lucken, die ein Compiler einfugt, umein bestimmtes Datenlayout zu erzeugen. Durch die Verwendung der Pseudodatenty-pen lb und ub kann ein Programmierer die obere bzw. untere Beschrankung einesDatentyps aktiv beeinflussen. Eine verallgemeinerte Definition dieser Großen lautet:

lb(T ) =

⎧⎨⎩

mini

di falls kein Element den Typ lb hat

mini mit ti = lb

di sonst(8.7)

ub(T ) =

⎧⎨⎩

maxi(di + sizeof(ti))+ ε falls kein Element den Typ ub hatmax

i mit ti = ubdi sonst (8.8)

Durch die Verwendung dieser Pseudodatentypen kann die Ausdehnung eines Typsuber seine naturliche Große hinaus erreicht oder eine Lucke an sein Anfang eingefugtwerden. Die Ausdehnung kann auch kunstlich verkleinert werden. Den Pseudodaten-typen lb und ub entsprechen die MPI-Datentypen MPI LB und MPI UB. Diese re-prasentieren keinerlei Daten, sie dienen ausschließlich dazu, die obere bzw. untereBeschrankung eines Datentyps zu manipulieren. Sie werden auch (zumindest bzgl.der unten diskutierten Typzuordnungsregeln) auch nicht als Bestandteil der Typsi-gnatur bzw. der Typbeschreibung betrachtet.

8.3.3 MPI-Funktionen fur nutzerspezifische Datentypen

Der MPI-Standard definiert verschiedene Funktionen zur Manipulation von nutzer-spezifischen MPI-Datentypen, von denen wir in diesem Abschnitt die wichtigstenvorstellen wollen. Die Verwendung nutzerspezifischer MPI-Datentypen lauft immernach dem gleichen Muster ab. Zuerst wird der MPI-Datentyp mit einer Konstrukti-onsfunktion beschrieben, dann mit

int MPI_Type_commit(MPI_Datatype *datatype)

beim MPI-System angemeldet, in verschiedenen MPI-Funktionen verwendet und mit

int MPI_Type_free(MPI_Datatype *datatype)

wieder abgemeldet. Manchmal werden MPI-Datentypen nur als Hilfsdatentypen kon-struiert, um daraus weitere MPI-Datentypen abzuleiten. Werden diese Hilfsdatenty-pen als solche nie in Kommunikationsoperationen verwendet, so konnen diese nach

Page 243: [X.systems.press] Cluster Computing ||

8.3 Nutzerspezifische Datentypen 237

oldtype

newtype

blocklength = 3

stride = 5

count = 2

Abb. 8.3. Bedeutung der Argumente von MPI Type vector.

der Konstruktion der weiteren MPI-Datentypen gefahrlos beim MPI-System abge-meldet werden.

Die einfachste Konstruktionsfunktion heißt MPI Type contiguous. Mit ihrlasst sich ein Datentyp konstruieren, der aus count kontinuierlich im Speicher an-geordneten Elementen des Typs oldtype besteht.

int MPI_Type_contiguous(int count, MPI_Datatype oldtype,MPI_Datatype *newtype)

Die Funktion MPI Type vector ist eine Verallgemeinerung von MPI Typecontiguous. Der hiermit konstruierte Datentyp steht fur eine Ansammlung vonElementen des Typs oldtype, die in regelmaßigen Blocken mit moglichen Luckenim Speicher liegt.

int MPI_Type_vector(int count, int blocklength, int stride,MPI_Datatype oldtype, MPI_Datatype *newtype)

Das Argument count beziffert die Anzahl dieser Blocke, blocklength dieLange der Datenelemente je Block und stride den Abstand von Block zu Block,siehe Abb. 8.3. Mit der Funktion MPI Type vector lasst sich z. B. ein Datentypkonstruieren, der eine Spalte eines zweidimensionalen Feldes reprasentiert. Durchdie Funktion MPI Type indexed lasst sich ein Datentyp konstruieren, dessenGrundelemente vollkommen unregelmaßig im Speicher liegen.

int MPI_Type_indexed(int count, int *array_of_blocklengths,

newtype

3 2 4

16

9

oldtype

count = 3

array_of_blocklength = { 3, 2, 4 }

array_of_displacements = { 1, 6, 9 }

Abb. 8.4. Bedeutung der Argumente von MPI Type indexed.

Page 244: [X.systems.press] Cluster Computing ||

238 8 Fortgeschrittene Techniken

int *array_of_displacements,MPI_Datatype oldtype, MPI_Datatype *newtype)

Hierbei wird angenommen, dass die Grundelemente in count kontinuierlichenBlocken im Speicher liegen. Die Felder array of blocklengths bzw. arrayof displacements codieren die Zahl der Grundelemente je Block bzw. die An-fangsposition der Blocke in Bezug auf die Basisadresse, siehe Abb. 8.4. Das Feldarray of displacements darf auch negative Eintrage und Doppelungen ent-halten, in array of blocklengths sind keine negativen Eintrage erlaubt.

Den bisher genannten Konstruktionsfunktionen ist gemein, dass sie einen neuenDatentyp aus einem einzigen Grundtyp konstruieren. Mit MPI Type struct las-sen sich auch verschiedene Grundtypen in einen einzigen MPI-Typ packen. Damitkann man z. B. einen Datentyp bauen, der einer C-Struktur entspricht.

int MPI_Type_struct(int count, int *array_of_blocklengths,MPI_Aint *array_of_displacements,MPI_Datatype *array_of_types, MPI_Datatype *newtype)

Die Funktion MPI Type struct arbeitet ahnlich wie MPI Type indexed. Al-lerdings mussen die Grundtypen nur innerhalb eines Blockes gleich sein, darum istin array of types ein ganzes Feld von Grundtypen zu ubergeben. Außerdemwird die Position eines Blocks in Bezug auf die Basisadresse nicht in der Anzahl derElemente eines bestimmten Datentyps, sondern in Byte gemessen.

Fur die Reprasentation von Speicheradressen gibt es im MPI-Standard den Daten-typ MPI Aint. Die im Feld array of displacements ubergebenen Adressensollten moglichst nicht direkt mit dem Adressoperator & bestimmt werden. Die Funk-tion MPI Address wandelt einen Zeiger in eine gultige Adresse.

int MPI_Address(void *location, MPI_Aint *address)

Durch die Einfuhrung dieser Funktion und des Datentyps MPI Aint werden u. a.einige potentielle Probleme bzgl. der Wandlung von Zeigern in Ganzzahlen wegab-strahiert.

Die in (8.6), (8.7) und (8.6) definierten Großen lassen sich mit den FunktionenMPI Type extent, MPI Type lb und MPI Type ub ermitteln. Sie haben diefolgenden Signaturen:

int MPI_Type_extent(MPI_Datatype datatype, MPI_Aint *extent)int MPI_Type_lb(MPI_Datatype datatype, MPI_Aint *displacement)int MPI_Type_ub(MPI_Datatype datatype, MPI_Aint *displacement)

8.3.4 Senden und Empfangen von nutzerspezifischen Datentypen

Bevor wir im nachsten Abschnitt zeigen, wie obige MPI-Funktionen praktisch ge-nutzt werden, mussen wir noch klaren, welche Regeln beim Senden und Empfangenvon nutzerspezifischen MPI-Datentypen gelten. Maßgeblich fur die Frage, ob eineEmpfangsfunktion bzgl. des Datentyps zu einer Sendefunktion passt, ist die Typ-signatur. Daraus folgt insbesondere, dass Sendefunktion und Empfangsfunktion zu

Page 245: [X.systems.press] Cluster Computing ||

8.3 Nutzerspezifische Datentypen 239

einanderpassen, wenn sie jeweils den selben Datentyp type1 zusammen mit einemcount-Argument von eins benutzen. Eine Nachricht, die mit

MPI_Send(buffer, 1, type1, ...);

versendet wird, kann also mit

MPI_Recv(buffer, 1, type1, ...);

empfangen werden. Ist das count-Argument großer als eins, so gilt, dass dies aqui-valent dazu ist, einen mit MPI Type contiguous erzeugten Typ und ein count-Argument gleich eins zu verwenden. So kann die Nachricht

MPI_Send(buffer, 16, type1, ...);

von

MPI_Type_contiguous(16, type1, &type2);MPI_Type_commit(&type2);MPI_Recv(buffer, 1, type2, ...);

empfangen werden. Da fur die Typzuordnung lediglich die Typsignatur ausschlagge-bend ist, kann sich die interne Speicherreprasentation von Daten durch einen Nach-richtenaustausch andern. Durch die Sendeoperation

MPI_Type_contiguous(8, type1, &type2);MPI_Type_commit(&type2);MPI_Send(buffer, 2, type2, ...);

werden effektiv 16 Elemente des Typs type1 versendet, die z. B. mit

MPI_Type_vector(2, 5, 8, type1, &type3);MPI_Type_commit(&type3);MPI_Recv(buffer, 1, type3, ...);

empfangen werden konnen, denn auch ein type2 besteht aus 16 Elementen des Typstype1. Beachten Sie, dass in diesem Beispiel beim Sender alle Daten kontinuierlichim Speicher liegen, wahrend sie beim Empfanger in Blocken ankommen.

In den bis hier betrachteten Beispielen waren Sende- und Empfangspuffer gleichgroß. Der Empfangspuffer darf jedoch auch großer sein. So kann eine Nachricht, diemit

MPI_Send(buffer, 12, type1, ...);

versendet wurde, mit

MPI_Type_contiguous(8, type1, &type2);MPI_Type_commit(&type2);MPI_Recv(buffer, 2, type2, ..., &status);

empfangen werden. Der Empfangspuffer halt hier 16 Speicherplatze fur Daten vomTyp type1 bereit, von denen aber nur zwolf uberschrieben werden. Es wurden ge-wissermaßen eineinhalb Elemente des Typs type2 empfangen, in solch einem Fallgibt

Page 246: [X.systems.press] Cluster Computing ||

240 8 Fortgeschrittene Techniken

MPI_Get_count(&status, type2, &count);

den Wert MPI UNDEFINED zuruck. Allerdings lasst sich dann immer noch ermitteln,wieviele Datenelemente in Bezug auf die MPI-Grunddatentypen empfange wurden.Diese Zahl lasst sich mit

int MPI_Get_elements(MPI_Status *status, MPI_Datatype datatype, int *count)

bestimmen. In unserem Beispiel schriebe ein Aufruf von

MPI_Get_elements(&status, type2, &count);

in count den Wert zwolf, vorausgesetzt, dass der Typ type1 selbst ein MPI-Grund-datentyp aus Tabelle 14.1 ist.

Wenn die Anzahl der Elemente und die Typen bei der Funktion MPI Scatterimmer gleich sein mussten, hatte der MPI-Standard sicher auf die getrennte Anga-be fur Sender und Empfanger verzichtet. Mit dem, was Sie nun uber nutzerspe-zifische Datentypen wissen, verstehen Sie auch, was es mit diesen scheinbar red-undanten Argumenten auf sich hat. Zwischen dem Senden und Empfangen mitMPI Scatter konnen namlich kompatible Typumwandlungen durchgefuhrt wer-den. So kann der Sender beispielsweise Daten des benutzerdefinierten Typs MPICOMPLEX versenden, der aus zwei im Speicher aufeinander folgenden Zahlen vomTyp MPI DOUBLE besteht. Der Empfanger konnte die empfangenen Daten dannnach Real- und Imaginarteil getrennt als MPI DOUBLE interpretieren. In diesem Fallware recvcount= 2 ·sendcount. Diese Uberlegungen gelten naturlich auch furandere kollektive Operationen wie MPI Gather etc.

8.3.5 Beispiele

Nachdem wir die verschiedenen MPI-Funktionen zur Manipulation von Datentypennun ausfuhrlich besprochen haben, wollen wir sie uns auch einmal in Aktion ansehen.In Listing 8.2 finden Sie ein Programm, das die wichtigsten oben besprochenen Funk-tionen und Effekte demonstriert. Es ist fur genau zwei Prozesse geschrieben, jeweilseinen sendenden und einen empfangenden. Sendender und empfangender Prozessverwalten eine Matrix aus Strukturen und senden bzw. empfangen Teile daraus. InTerminal Session 8.1 sehen Sie die Ausgabe des Programms.

Bis zur Zeile 32 werden lediglich die zu verwendende Struktur und einige Hilfs-funktionen definiert. Die eigentliche Arbeit steckt im Hauptprogramm. Nach der ubli-chen Initialisierung von MPI, werden alle notwendigen MPI-Datentypen konstruiert,um mit ihnen spater Nachrichten auszutauschen. Diese Nachrichten sollen aus ein-zelnen Elementen, Zeilen, Spalten bzw. einer Dreiecksmatrix bestehen. Die Grund-elemente der Matrix sind vom Typ

typedef struct {int x;double y;char str[13];

} coord;

Page 247: [X.systems.press] Cluster Computing ||

8.3 Nutzerspezifische Datentypen 241

Terminal Session 8.1. Ausgabe des Programms types demo.bauke@server:˜/src$ mpirun -np 2 types_demo0,0,... 1,0,... 2,0,... 3,0,... 4,0,... 5,0,... 6,0,... 7,0,...0,1,... 1,1,... 2,1,... 3,1,... 4,1,... 5,1,... 6,1,... 7,1,...0,2,... 1,2,... 2,2,... 3,2,... 4,2,... 5,2,... 6,2,... 7,2,...0,3,... 1,3,... 0,0,### 3,3,... 4,3,... 5,3,... 6,3,... 7,3,...0,4,... 1,4,... 2,4,... 3,4,... 4,4,... 5,4,... 6,4,... 7,4,...0,5,... 1,5,... 2,5,... 3,5,... 4,5,... 5,5,... 6,5,... 7,5,...0,6,... 1,6,... 2,6,... 3,6,... 4,6,... 5,6,... 6,6,... 7,6,...0,7,... 1,7,... 2,7,... 3,7,... 4,7,... 5,7,... 6,7,... 7,7,...

0,0,... 1,0,... 2,0,... 3,0,... 4,0,... 5,0,... 6,0,... 7,0,...0,1,... 1,1,... 2,1,... 3,1,... 4,1,... 5,1,... 6,1,... 7,1,...0,2,... 1,2,... 2,2,... 3,2,... 4,2,... 5,2,... 6,2,... 7,2,...0,3,... 1,3,... 2,3,... 3,3,... 4,3,... 5,3,... 6,3,... 7,3,...0,1,### 1,1,### 2,1,### 3,1,### 4,1,### 5,1,### 6,1,### 7,1,###0,2,### 1,2,### 2,2,### 3,2,### 4,2,### 5,2,### 6,2,### 7,2,###0,6,... 1,6,... 2,6,... 3,6,... 4,6,... 5,6,... 6,6,... 7,6,...0,7,... 1,7,... 2,7,... 3,7,... 4,7,... 5,7,... 6,7,... 7,7,...

0,0,... 1,0,... 2,0,... 3,0,... 1,0,### 2,0,### 6,0,... 7,0,...0,1,... 1,1,... 2,1,... 3,1,... 1,1,### 2,1,### 6,1,... 7,1,...0,2,... 1,2,... 2,2,... 3,2,... 1,2,### 2,2,### 6,2,... 7,2,...0,3,... 1,3,... 2,3,... 3,3,... 1,3,### 2,3,### 6,3,... 7,3,...0,4,... 1,4,... 2,4,... 3,4,... 1,4,### 2,4,### 6,4,... 7,4,...0,5,... 1,5,... 2,5,... 3,5,... 1,5,### 2,5,### 6,5,... 7,5,...0,6,... 1,6,... 2,6,... 3,6,... 1,6,### 2,6,### 6,6,... 7,6,...0,7,... 1,7,... 2,7,... 3,7,... 1,7,### 2,7,### 6,7,... 7,7,...

0,0,+++ 1,0,+++ 2,0,+++ 3,0,+++ 4,0,+++ 5,0,+++ 6,0,+++ 7,0,+++0,1,... 8,0,+++ 9,0,+++ 10,0,+++ 11,0,+++ 12,0,+++ 13,0,+++ 14,0,+++0,2,... 1,2,... 15,0,+++ 16,0,+++ 17,0,+++ 18,0,+++ 19,0,+++ 20,0,+++0,3,... 1,3,... 2,3,... 21,0,+++ 22,0,+++ 23,0,+++ 24,0,+++ 25,0,+++0,4,... 1,4,... 2,4,... 3,4,... 26,0,+++ 27,0,+++ 28,0,+++ 29,0,+++0,5,... 1,5,... 2,5,... 3,5,... 4,5,... 30,0,+++ 31,0,+++ 32,0,+++0,6,... 1,6,... 2,6,... 3,6,... 4,6,... 5,6,... 33,0,+++ 34,0,+++0,7,... 1,7,... 2,7,... 3,7,... 4,7,... 5,7,... 6,7,... 35,0,+++

Zu diesem Typ existiert kein MPI-Datentyp, wir mussen darum unseren eigenen bau-en. Dies geschieht in den Zeilen 47 bis 57 auf Grundlage der Funktion MPI Typestruct. Das Feld der Anfangspositionen der einzelnen Datenelemente der Strukturwerden mit MPI Address berechnet, die Blocklangen und die Datentypen sind festin den Feldern len bzw. types codiert. Tatsachlich baut das Programm gleich zweiMPI-Datentypen, die auf unsere C-Struktur passen, einmal mit expliziter Angabe deroberen Beschrankung durch den Pseudotyp MPI UP und einmal ohne. Die expliziteAngabe der oberen Beschrankung ist hier sinnvoll, da in C eine Struktur mehr Spei-cherplatz einnehmen darf, als die Summe des Speicherbedarfs der Komponenten derStruktur. So belegen auf einer 32-Bit-Architektur ein int vier, ein double acht undein char ein Byte Speicher, macht fur unsere Struktur vom Typ coord zusammen(4+8+13 = 25) Byte. Tatsachlich wird aber ein sizeof(coord) wahrscheinlichden Wert 28 liefern, denn die meisten Compiler (auf 32-Bit-Architekturen) richtendie Anfangsadressen von Variablen an einem Vier-Byte-Raster aus. Der Datentyp

Page 248: [X.systems.press] Cluster Computing ||

242 8 Fortgeschrittene Techniken

Listing 8.2. Das Programm types demo.c zeigt die Verwendung eigener Datentypen.

#include <stdlib.h>#include <stdio.h>#include <string.h>#include ” mpi . h ”

5typedef struct { int x; double y; char str[13]; } coord;

void * secure_malloc(size_t size) {void * p=malloc(size);

10 if (p==NULL) MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);return p;

}

void fill(coord *M, int N, int rank) {15 int i, j;

for (j=0; j<N; ++j)for (i=0; i<N; ++i) {

M[i+N*j].x=i; M[i+N*j].y=j;strcpy(M[i+N*j].str, rank==0 ? ” ### ” : ” . . . ”);

20 }}

void print(coord *M, int N) {int i, j;

25 for (j=0; j<N; ++j) {for (i=0; i<N; ++i)

printf(”%2i ,%g,% s ”, M[i+N*j].x, M[i+N*j].y, M[i+N*j].str);printf(”\n ”);

}30 printf(”\n ”);

}

int main(int argc, char *argv[]) {const int N=8;

35 int C_rank, C_size, i, len[4]={1, 1, 13, 1}, *tri_disp, *tri_len;coord *M, *v;MPI_Status status;MPI_Datatype types[4]={MPI_INT, MPI_DOUBLE, MPI_CHAR, MPI_UB};MPI_Aint displacements[4];

40 MPI_Datatype coord_t0, coord_t, row_t, col_t0, col_t, tri_t;/ * MPI i n i t i a l i s i e r e n * /MPI_Init(&argc, &argv);MPI_Comm_size(MPI_COMM_WORLD, &C_size);MPI_Comm_rank(MPI_COMM_WORLD, &C_rank);

45 if (C_size!=2) MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);M=secure_malloc(N*N*sizeof(*M));/ * MPI−D a t e n t y p e n f u r K o o r d i n a t e bauen * /MPI_Address(&M[0].x, displacements);MPI_Address(&M[0].y, displacements+1);

50 MPI_Address(M[0].str, displacements+2);MPI_Address(&M[1].x, displacements+3);for (i=3; i>=0; --i)

displacements[i]-=displacements[0];MPI_Type_struct(3, len, displacements, types, &coord_t0);

55 MPI_Type_commit(&coord_t0);MPI_Type_struct(4, len, displacements, types, &coord_t);MPI_Type_commit(&coord_t);/ * MPI−D a t e n t y p f u r Z e i l e n v e k t o r bauen * /

Page 249: [X.systems.press] Cluster Computing ||

8.3 Nutzerspezifische Datentypen 243

MPI_Type_contiguous(N, coord_t, &row_t);60 MPI_Type_commit(&row_t);

/ * MPI−D a t e n t y p e n f u r S p a l t e n v e k t o r bauen * /MPI_Type_vector(N, 1, N, coord_t0, &col_t0);MPI_Type_commit(&col_t0);types[0]=col_t0; MPI_Address(&M[0], displacements); len[0]=1;

65 types[1]=MPI_UB; MPI_Address(&M[1], displacements+1); len[1]=1;for (i=1; i>=0; --i)

displacements[i]-=displacements[0];MPI_Type_struct(2, len, displacements, types, &col_t);MPI_Type_commit(&col_t);

70 / * MPI−D a t e n t y p f u r D r e i e c k s m a t r i x bauen * /tri_disp=secure_malloc(N*sizeof(*tri_disp));tri_len=secure_malloc(N*sizeof(*tri_len));for (i=0; i<N; ++i) {

tri_len[i]=N-i; tri_disp[i]=i*N+i;75 }

MPI_Type_indexed(N, tri_len, tri_disp, coord_t, &tri_t);MPI_Type_commit(&tri_t);/ * n i c h t mehr b e n o t i g t e D a t e n t y p e n f e i g e b e n * /MPI_Type_free(&coord_t0); MPI_Type_free(&col_t0);

80 / * neue D a t e n s t r u k t u r e n b e n u t z e n * /fill(M, N, C_rank);if (C_rank==0) / * sende M( 0 , 0 ) * /

MPI_Send(M, 1, coord_t, 1, 0, MPI_COMM_WORLD);else { / * empfange M( 2 , 3 ) * /

85 MPI_Recv(M+2+3*N, 1, coord_t, 0, 0, MPI_COMM_WORLD, &status);print(M, N);

}fill(M, N, C_rank);if (C_rank==0) / * sende 1 . u . 2 . Z e i l e * /

90 MPI_Send(M+N, 2, row_t, 1, 0, MPI_COMM_WORLD);else { / * empfange 4 . u . 5 . Z e i l e * /

MPI_Recv(M+4*N, 2, row_t, 0, 0, MPI_COMM_WORLD, &status);print(M, N);

}95 fill(M, N, C_rank);

if (C_rank==0) / * sende 1 . u . 2 . S p a l t e * /MPI_Send(M+1, 2, col_t, 1, 0, MPI_COMM_WORLD);

else { / * empfange 4 . u . 5 S p a l t e * /MPI_Recv(M+4, 2, col_t, 0, 0, MPI_COMM_WORLD, &status);

100 print(M, N);}fill(M, N, C_rank);if (C_rank==0) { / * sende Vek to r d e r Große e i n e r D r e i e c k s m a t r i x * /

v=secure_malloc(N*(N+1)/2*sizeof(*v));105 for (i=0; i<N*(N+1)/2; ++i) {

v[i].x=i; v[i].y=0; strcpy(v[i].str, ”+++”);}MPI_Send(v, N*(N+1)/2, coord_t, 1, 0, MPI_COMM_WORLD);

} else { / * empfange D r e i e c k s m a t r i x * /110 MPI_Recv(M, 1, tri_t, 0, 0, MPI_COMM_WORLD, &status);

print(M, N);}MPI_Type_free(&tri_t); MPI_Type_free(&col_t);MPI_Type_free(&row_t); MPI_Type_free(&coord_t);

115 MPI_Finalize();return EXIT_SUCCESS;

}

Page 250: [X.systems.press] Cluster Computing ||

244 8 Fortgeschrittene Techniken

coord t0 ohne explizite obere Beschrankung soll spater nur als Hilfstyp zur Kon-struktion einer Spalte dienen.

Bei dem in unserem Programm gewahlten Speicherlayout belegt eine Zeileeinen kontinuierlichen Speicherbereich. Entsprechend wird in den Zeilen 58 bis 60der Datentyp row t durch die Funktion MPI Type contiguous und dem Typcoord t gebaut. Die Konstruktion eines Datentypes, der einer Spalte entspricht,ist schon etwas aufwendiger, siehe Zeile 61 bis 69. Die Elemente einer Spalte lie-gen in einem Abstand, der gleich der Zahl der Spalten ist, in Blocken der Langeeins. Hier ist also die Funktion MPI Type vector zu verwenden. Wir wollen abernicht nur einzelne Spalten versenden konnen, sondern durch Angabe eines entspre-chenden count-Arguments in der Sende- bzw. Empfangsfunktion gleich beliebigviele benachbarte Spalten. Mit dem Typ col t0 ist dies noch nicht moglich. Wurdeman zwei Elemente des Typs col t0 empfangen, wurden diese hintereinander imSpeicher abgelegt. Benachbarte Spalten uberlappen sich aber im Speicher, die ers-ten Elemente zweier benachbarter Spalten liegen direkt nebeneinander, genauso diezweiten usw. In den Zeilen 64 bis 69 wird darum aus dem Typ col t0 ein Daten-typ col t gebaut, der sich von diesem lediglich dadurch unterscheidet, dass dieuntere Beschrankung direkt hinter dem ersten Datenelement der Spalte liegt. Jetztwird auch klar, warum wir fur die Definiton von col t0 statt coord t den Typcoord t0 (Der kein Elemet vom Typ MPI UP enthalt.) verwendet haben. DieMPI UP-Elemente in coord t wurden bei der Definition von col t storen unddie Wirkung des in col t eingefugten MPI UP-Elements uberdecken.

In den Zeilen 70 bis 77 sehen wir noch eine Anwendung fur MPI Typeindexed, wo wir einen Typ kreieren, der einer oberen Dreiecksmatrix entspricht.Die dazu notwendigen Blocklangen und -adressen werden mit etwas Arithmetik inden Zeilen 73 bis 75 berechnet. Nun haben wir alle notwendigen Datentypen erzeugt,die Hilfstypen coord t0 und col t0 konnen wieder freigegeben werden.

Die restlichen Zeilen des Programms zeigen, wie man die Datentypen praktischbenuzten kann, und sollte großtenteils selbsterklarend sein. Die Betrachtung der Aus-gabe in Terminal Session 8.1 hilft, das Programm types demo.c zu verstehen. Be-achtenswert ist weiterhin die Berechnung des Sende- bzw. Empfangspuffers (erstesArgumet von MPI Send bzw. MPI Recv) und der Versandt der Dreiecksmatrix amEnde des Programms. Hier wird zwar ein Vektor mit N(N + 1)/2 Elementen ver-sandt, beim Empfangsprozess kommt jedoch eine Dreiecksmatrix mit gleich vielenEintragen an. Weitere Beispiele zur Versendung nutzerspezifischer Datentypen findetder Leser in [59] im Abschnitt 3.12.7.

8.4 Parallele Ein- und Ausgabe

8.4.1 Motivation

Die rechenintensiven Probleme, die Cluster-Computer typischerweise bearbeiten, be-lasten nicht nur Netzwerk und CPUs sondern auch das Dateisystem. Denn die in ei-nem Programm bearbeiteten (moglicherweise sehr großen) Datenmengen mussen ja

Page 251: [X.systems.press] Cluster Computing ||

8.4 Parallele Ein- und Ausgabe 245

erst eingelesen und spater wieder gespeichert werden. Leider sind die Dateizugriffs-funktionen der Sprache C bzw. die des POSIX-Standards fur parallele Programmewenig geeignet. In den einfachen Beispielprogrammen dieses Buches fuhrt meist einProzess exklusiv alle Dateioperationen durch. Zuvor muss er dazu alle notwendigenDaten von den anderen Prozessen einsammeln, bzw. gelesene Daten an die anderenProzesse verteilen. Naturlich wird der die Dateioperationen abwickelnde Prozess inProgrammen mit haufigen Dateizugriffen so schnell zum Flaschenhals. Fur paralleleAnwendungen benotigen wir darum eine Dateisystemschnittstelle, die speziell aufdiese abgestimmt ist.

Seit der Version 2 des MPI-Standards steht uns eine solche Dateisystemschnitt-stelle mit paralleler Semantik zur Verfugung. Die Mechanismen, die einen koordi-nierten und effizienten Dateizugriff mehrerer Prozesse ermoglichen, sind stark archi-tekturabhangig. Die Dateizugriffsfunktionen von MPI-2 besitzen jedoch einen hohenAbstraktionsgrad und erlauben dadurch einen weitgehend architekturunabhangigenUmgang mit Dateien. Sie abstrahieren die Unterschiede zwischen den verschiede-nen parallelen Dateisystemen (NFS, PVFS, GPFS oder andere), auf denen eine Im-plementierung der MPI-Dateifunktionen letztenendes basiert, einfach weg und Siemussen sich um dateisystemspezifische Unterschiede genauso wenig kummern wiedarum, ob Ihr MPI-Programm spater auf einem Cluster-Computer oder auf einergroßen SMP-Maschine lauft.

8.4.2 Definitionen und Konzepte

Eine MPI-Datei ist eine geordnete Sammlung typisierter Daten. Auf diese Datenkann wahlfrei oder sequentiell zugegriffen werden. Dazu werden Dateien stets vonallen Prozessen eines Kommunikators gemeinsam geoffnet. Jeder Prozess hat eineganz bestimmte Sicht (engl. view) auf den Dateiinhalt. Diese beginnt relativ zum Da-teianfang bei einer bestimmten Distanzadresse (displacement), die in Byte gegebenist.

Als Basiseinheit fur Datenzugriff und fur Positionierungen innerhalb einer Da-tei dient ein elementarer Datentyp (etype). Dies kann ein MPI-Grunddatentyp (sie-he Tabelle 14.1) oder ein nutzerspezifischer Datentyp sein, vorausgesetzt er besitzt

elementarer Typ

Datenaufteilung durch Dateityp

Distanzadresse

Dateityp

Löcher

sichtbare Daten

Daten

Abb. 8.5. Lokale Dateisicht eines einzelnen Prozesses auf eine Datei.

Page 252: [X.systems.press] Cluster Computing ||

246 8 Fortgeschrittene Techniken

Datenaufteilung durch Dateityp

Distanzadresse

elementarer Typ

Dateityp Prozess 0

Dateityp Prozess 1

Dateityp Prozess 2

Abb. 8.6. Globale Dateisicht aller Prozesse auf eine Datei.

eine aufsteigende Anordnung seiner Elemente und enthalt keine negativen Distanz-adressen. Die Aufteilung der Daten einer Datei erfolgt auf Grundlage eines Datei-typs (filetype). Ein Dateityp ist entweder ein einzelner elementarer Datentyp oderein davon abgeleiteter MPI-Datentyp, der aus mehreren Elementen des gleichen ele-mentaren Datentyps und moglicherweise einigen Lochern besteht. Die Große einesDatenblocks betragt ein ganzzahliges Vielfaches eines elementaren Datentyps. DieDateisicht (view) beschreibt, auf welche Daten ein Prozess zugreifen kann. Sie er-gibt sich aus dem elementaren Datentyp, dem Dateityp und der Distanzadresse, sieheAbb. 8.5. Jeder Prozess eines Kommunikators kann eine andere Sicht auf eine Dateihaben, siehe Abb. 8.6.

Innerhalb einer Dateisicht lasst sich die momentane Lese- bzw. Schreibpositiondurch ein Offset angeben. Offsets werden in elementaren Datentypen ohne Beruck-sichtigung von Lochern gemessen. Ein Offset von null zeigt auf das erste Datenele-ment in einer Dateisicht. So zeigt z. B. ein Offset von drei bei Prozess 1 in Abb. 8.6auf das neunte Datenelement hinter der Distanzadresse. Ein Dateizeiger (file poin-ter) ist ein von MPI implizit verwaltetes Offset. Individuelle Dateizeiger sind lokaleObjekte, die dem Prozess gehoren, der eine Datei geoffnet hat. Gemeinsame Dateizei-ger gehoren hingegen einer ganzen Gruppe von Prozessen. Der MPI-Standard kenntsomit insgesamt drei Arten, die aktuelle Lese- und Schreibposition zu verandern:

• explizite Offsets,• individuelle Dateizeiger oder• gemeinsame Dateizeiger.

Alle drei Methoden sind voneinander unabhangig und konnen auch gemischt werden.Ahnlich wie die C- oder den POSIX-Dateifunktionen verwenden auch die MPI-

Dateifunktionen einen Dateihandle, um eine Datei zu identifizieren. Dieses Handlewird beim Offnen einer Datei erzeugt und beim Schließen freigegeben.

8.4.3 Grundfunktionen

Bevor eine Datei geschrieben oder gelesen werden kann, muss man sie durch diekollektive Funktion MPI File open offnen.

Page 253: [X.systems.press] Cluster Computing ||

8.4 Parallele Ein- und Ausgabe 247

int MPI_File_open(MPI_Comm comm, char *filename, int amode, MPI_Info info,MPI_File *fh)

Alle Prozesse des Kommunikators comm rufen diese Funktion gemeinsam mit glei-chen Argumenten auf und erhalten einen Dateihandle fh auf die geoffnete Datei.Das Argument filename enthalt den Dateinamen und amode den Zugriffsmodus,durch info konnen der MPI-Implementation Informationen (hints) uber das Musterdes Dateizugriffs (Es werden oft kleine Datenhappen eingelesen, es erfolgen wenigelange Schreibzugriffe und ahnliches.) gegeben werden. Diese Informationen kanneine MPI-Implementation nutzen, um einen auf das Zugriffsmuster optimal abge-stimmten Schreib- oder Lesealgorithmus zu wahlen und so einen moglichst großenNettodurchsatz zu erzielen. Welche Art von Zusatzinformationen hier tatsachlich spe-zifiziert werden konnen, hangt von der MPI-Implementation ab. Genaueres findenSie dazu in [103] Abschnitt 4.10 und 9.2.8. Konnen oder wollen Sie keine Hinwei-se uber Zugriffsmuster geben, muss info den Wert MPI INFO NULL haben. Auchwir werden im Folgenden immer MPI INFO NULL verwenden.

Dateinamen konnen in MPI-Programmen unter Umstanden etwas anders ausse-hen als Sie das von Ihrem Betriebssystem gewohnt sind. So kann z. B. eine MPI-Implementation verlangen, dass jedem Dateinamen ein Suffix oder Prafix hinzu-zufugen ist, der bestimmte Zusatzinformationen uber Dateiserver, Protokolle oderPassworter enthalt. Allerdings handelt es sich hierbei um ein implementationsspe-zifisches Detail, uber das Sie die Dokumentation Ihrer MPI-Implementation naherinformiert.

Der Wert des Arguments amode ergibt sich aus einer Verknupfung durch den|-Operator (binares Oder) folgender Werte:

MPI MODE RDONLY. Reiner Lesezugriff.MPI MODE RDWR. Schreib- und Lesezugriff.MPI MODE WRONLY. Reiner Schreibzugriff.MPI MODE CREATE. Erzeuge Datei, falls sie noch nicht existiert.MPI MODE EXCL. Melde einen Fehler, falls eine Datei erzeugt werden soll, die

schon existiert.MPI MODE DELETE ON CLOSE. Losche Datei beim Schließen. Diese Option wird

bei temporaren Dateien verwendet, die nur Zwischenergebnisse speichern, dieausschließlich wahrend einer Rechnung benotigt werden.

MPI MODE UNIQUE OPEN. Auf Datei kann nie von mehr als einem Programm(MPI-Programm oder anderes) zugegriffen werden.

MPI MODE SEQUENTIAL. Nur sequentieller Zugriff.MPI MODE APPEND. Setze nach dem Offnen den Dateizeiger auf das Ende der Da-

tei.

Durch den |-Operator lassen sich verschiedene Zugriffsmodi kombinieren, so wirdmit MPI MODE WRONLY | MPI MODE APPEND eine Datei mit schreibendem Zu-griff geoffnet, wobei alle neuen Daten an das Dateiende angehangt werden.

Page 254: [X.systems.press] Cluster Computing ||

248 8 Fortgeschrittene Techniken

elementarer Typ

Dateityp Prozess 0

Dateityp Prozess 1

Dateityp Prozess 2

,

,

, "native", MPI_NULL_INFO);MPI_File_set_view(fh, 0, ,

MPI_File_set_view(fh, 0,

MPI_File_set_view(fh, 0,

, "native", MPI_NULL_INFO);

, "native", MPI_NULL_INFO);

Abb. 8.7. Verschiedene Prozesse erhalten durch die Funktion MPI File set view eineindividuelle Sicht auf die Daten in einer Datei.

Bevor auf eine Datei lesend oder schreibend zugegriffen werden kann, muss nochdurch die kollektive Funktion MPI File set view eine passende Dateisicht fest-gelegt werden.

int MPI_File_set_view(MPI_File fh, MPI_Offset disp, MPI_Datatype etype,MPI_Datatype filetype, char *datarep, MPI_Info info)

Das erste Argument ist das die Datei reprasentierende Handle und disp die Distanz-adresse. Drittes und viertes Argument bestimmen den elementaren Datentyp und denDateityp, das funfte Argument datarep wahlt eine Datenreprasentation aus. Imletzten Argument finden wir schließlich das schon von MPI File open bekannteInfoobjekt. Distanzadressen werden durch den Typ MPI Offset reprasentiert. Die-ser Typ verhalt sich wie ein Ganzzahltyp kann aber moglicherweise einen großerenWerteumfang als int haben. Erklarungsbedurfig ist noch das datarep-Argument.

Eine standardkonforme MPI-Implementation kennt mindestens drei Moglichkei-ten, Daten in einer Datei zu reprasentieren. Diese unterschieden sich in erster Liniehinsichtlich ihrer Portabilitat.

native. Diese Form der Datenreprasentation entspricht einem exakten Abbild desArbeitsspeichers und verspricht eine maximale Ein- Ausgabeleistung. Leidersind Dateien mit dieser Datenreprasentation nicht uber Architekturgrenzen hin-weg portabel, weshalb sie nur in einer homogenen Umgebung eingesetzt werdensollte. Innerhalb einer Architektur konnen die so kodierten Daten auch mit denC-Funktionen fread und fwrite gelesen bzw. geschrieben werden.

internal. Mit der Datenreprasentation internal werden Daten in einem ar-chitekturunabhangigen Format gespeichert und konnen innerhalb einer MPI-Implementation problemlos zwischen verschiedenen Architekturen ausgetauschtwerden.

external32. In Abschnitt 9.5.2 definiert der MPI-2 Standard [103] eine Daten-reprasentation, die auf dem ANSI/IEEE Standard 754-1985 basiert und sowohluber Architekturgrenzen als auch uber verschiedene MPI-Implementationen hin-weg einen portablen Datenaustausch garantiert. Diese Portabilitat wird durchzusatzliche Konvertierungen zwischen dem architekturspezifischen Format, in

Page 255: [X.systems.press] Cluster Computing ||

8.4 Parallele Ein- und Ausgabe 249

dem die Daten im Arbeitsspeicher liegen, und dem portablen Format, in dem dieDaten auf dem Massenspeichermedium liegen, erkauft.

Daruberhinaus konnen MPI-Implementationen noch weitere Formen der Datenre-prasentation anbieten und mit der Funktion MPI Register datarep lassen sichauch eigene Datenreprasentationen definieren, siehe [103] Abschnitt 9.5.3.

Sind alle Ein- und Ausgaben beendet, muss eine Datei auch wieder geschlossenwerden. Dazu dient die kollektive Funktion MPI File close, die noch vor MPIFinalize aufzurufen ist.

int MPI_File_close(MPI_File *fh)

Greift tatsachlich nur ein einziger Prozess auf eine bestimmte Datei zu, so sollte diesewegen des kollektiven Charakters der Funktionen MPI File open, MPI Fileclose und anderer mit dem Kommunikator MPI COMM SELF geoffnet werden.

8.4.4 Schreib- und Leseoperationen

Der MPI-Standard stellt eine Vielzahl verschiedener Schreib- und Lesefunktionenzur Verfugung. Diese orientieren sich in Syntax und Semantik stark an den Sende-und Empfangsfunktionen, die wir in Kapitel 7 ausfuhrlich vorgestellt haben. DieSchreib- und Lesefunktionen ebenso ausfuhrlich beschreiben zu wollen, hieße ihnenein eigenes Kapitel vergleichbar dem Kapitel 7 zu widmen. Denn wie bei den Sende-und Empfangsfunktionen gibt es auch bei den Ein- und Ausgabefunktionen blockie-rende und nicht blockierende, kollektive und nicht kollektive Varianten, und außer-dem wird noch nach der Art der Positionierung innerhalb der Datei unterschieden.In Tabelle 8.1 finden Sie eine Zusammenstellung aller Dateizugriffsfunktionen ausMPI-2. Im Kapitel 9 des Standards werden alle Funktionen im Detail beschrieben.

Der Unterschied zwischen blockierenden und nicht blockierenden Schreib- undLesefunktionen ist der gleiche wie zwischen blockierenden und nicht blockieren-den Sende- und Empfangsfunktionen. Blockierende Schreib- bzw. Lesefunktionenkehren erst zuruck, wenn der Lesepuffer, die angeforderten Daten enthalt, bzw. derSchreibvorgang so weit fortgeschritten ist, dass der Schreibpuffer mit neuen Datengefullt werden darf. Bei den nicht blockierenden Varianten wird lediglich ein Datei-zugriff angestoßen, dessen Beendigung mit MPI Wait, MPI Test oder verwandtenFunktionen abgefragt werden muss.

Kollektive und nicht kollektive Funktionen in der selben Zeile in Tabelle 8.1 sindfunktional fast identisch. Der einzige Unterschied besteht darin, dass die kollektivenVarianten immer von allen Prozessen des Kommunikators, mit dem die Datei geoff-net wurde, gemeinsam aufgerufen werden mussen. Wann immer die Logik Ihres Pro-gramms die Verwendung kollektiver Schreib- bzw. Lesefunktionen zulasst, solltenSie diese auch nutzen. Diese sind potentiell schneller als nicht kollektive Schreib-bzw. Lesefunktionen, die gleichzeitig von vielen Prozessen aufgerufen werden.

In Listing 8.3 finden Sie ein sehr einfaches Beispielprogramm, das die Verwen-dung paralleler Ein- und Ausgabefunktionen mit individuellen Dateizeigern illus-triert. In diesem Programm liest zunachst jeder Prozess aus einer Datei den gleichen

Page 256: [X.systems.press] Cluster Computing ||

250 8 Fortgeschrittene Techniken

Tabelle 8.1. Dateizugriffsfunktionen aus MPI-2 im Uberblick.

Position- Synchroni- Koordination

ierung sation nicht kollektiv kollektiv

explizite blockierend MPI File read at MPI File read at allOffsets MPI File write at MPI File write at all

nicht MPI File iread at MPI File read at all beginblockierend MPI File read at all end

MPI File iwrite at MPI File write at all beginMPI File write at all end

individuelle blockierend MPI File read MPI File read allDateizeiger MPI File write MPI File write all

nicht MPI File iread MPI File read all beginblockierend MPI File read all end

MPI File iwrite MPI File write all beginMPI File write all end

gemeinsame blockierend MPI File read shared MPI File read orderedDateizeiger MPI File write shared MPI File write ordered

nicht MPI File iread shared MPI File read ordered beginblockierend MPI File read ordered end

MPI File iwrite shared MPI File write ordered beginMPI File write ordered end

Datensatz ein. Dazu wird mit MPI File open die Eingabedatei geoffnet und mitder Funktion MPI File set view eine geeignete Dateisicht gewahlt. Da sowohlder elementare Datentyp als auch der Dateityp MPI INT sind, sieht jeder Prozesseinen Strom von Ganzzahlen ohne irgendwelche Locher. Die kollektive FunktionMPI File read all liest das Datenfeld ein und danach wird die Eingabedateimit MPI File close wieder geschlossen. Die Funktion MPI File read allhat den Prototyp

int MPI_File_read_all(MPI_File fh, void *buf, int count,MPI_Datatype datatype, MPI_Status *status)

und erwartet als Argumente ein Dateihandle, einen Zeigen auf einen Puffer, in demdie eingelesenen Daten abgelegt werden, die Zahl der einzulesenden Datenelemente,den Datentyp der einzulesenden Datenelemente und ein Zeiger auf ein Statusobjekt.

Die Ausgabe des Ergebnisfeldes mit MPI File write all erfolgt im Lis-ting 8.3 analog zur Eingabe. Die Funktion benotigt dazu die gleichen Argumentewie MPI File read all.

int MPI_File_write_all(MPI_File fh, void *buf, int count,MPI_Datatype datatype, MPI_Status *status)

Allerdings hat nun jeder Prozess einen anderen Datensatz, den er in die Datei schreibt.Damit die Prozesse ihre Ergebnisse nicht gegenseitig uberschreiben, legen sie diese

Page 257: [X.systems.press] Cluster Computing ||

8.4 Parallele Ein- und Ausgabe 251

Listing 8.3. Das Beispielprogramm read write.c demonstriert die parallele Ein- und Aus-gabe mit individuellen Dateizeigern.

#include <stdio.h>#include <stdlib.h>#include ” mpi . h ”#define SIZE 100

5int main(int argc, char *argv[]) {

MPI_File fh;MPI_Status status;int a[SIZE], C_rank, i;

10MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD, &C_rank);/ * a l l e P r o z e s s e l e s e n g l e i c h e n Vekto r mi t SIZE Ganzzah len * /MPI_File_open(MPI_COMM_WORLD, ” d a t a i n . d a t ”,

15 MPI_MODE_RDONLY, MPI_INFO_NULL, &fh);MPI_File_set_view(fh, 0, MPI_INT, MPI_INT, ” n a t i v e ”, MPI_INFO_NULL);MPI_File_read_all(fh, a, SIZE, MPI_INT, &status);MPI_File_close(&fh);/ * au fwend ige Rechnung * /

20 for (i=0; i<SIZE; ++i)a[i]*=C_rank+1;

/ * P r o z e s s e s c h r e i b e n v e r s c h i e d e n e Vek to ren mi t SIZE Ganzzah leni n Bl ocken h i n t e r e i n a n d e r * /

MPI_File_open(MPI_COMM_WORLD, ” d a t a o u t . d a t ”,25 MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_INFO_NULL, &fh);

MPI_File_set_view(fh, 0, MPI_INT, MPI_INT, ” n a t i v e ”, MPI_INFO_NULL);MPI_File_seek(fh, C_rank*SIZE, MPI_SEEK_SET);MPI_File_write_all(fh, a, SIZE, MPI_INT, &status);MPI_File_close(&fh);

30 MPI_Finalize();return EXIT_SUCCESS;

}

hintereinander in Blocken in der Ausgabedatei ab. Dazu verschiebt jeder Prozess mitMPI File seek seinen Dateizeiger an die Stelle innerhalb der Ausgabedatei, abder er seine Daten ablegen soll.

int MPI_File_seek(MPI_File fh, MPI_Offset offset, int whence)

Die Funktion MPI File seek benotigt als Argumente ein Dateihandle, eine Di-stanzangabe und eine Information daruber, bezuglich welcher Referenz der aktuelleDateizeiger verandert werden soll. Die Distanzangabe darf sowohl positiv als auchnegativ sein. Das Argument whence kann folgende Werte haben:

MPI SEEK SET. Der Dateizeiger zeigt offset Datenelemente hinter den Dateian-fang.

MPI SEEK CUR. Der Dateizeiger wird um offset Datenelemente hinter seine ak-tuelle Position verschoben.

MPI SEEK END. Der Dateizeiger wird um offset Datenelemente hinter das Da-teiende verschoben.

Page 258: [X.systems.press] Cluster Computing ||

252 8 Fortgeschrittene Techniken

Listing 8.4. Das Beispielprogramm matrix mult.c liest und schreibt parallel Matrizen inbzw. aus einer Datei.

#include <stdlib.h>#include <stdio.h>#include ” mpi . h ”#define SIZE 100

5 #define NP 4

int main(int argc, char *argv[]) {int len[3]={1, SIZE/NP, 1}, C_rank, C_size, i, j, k;double A[SIZE][SIZE], B[SIZE][SIZE/NP], C[SIZE][SIZE/NP];

10 MPI_Datatype filetype, types[3]={MPI_LB, MPI_DOUBLE, MPI_UB};MPI_Aint displacements[3];MPI_File fh;MPI_Status status;/ * MPI i n i t i a l i s i e r e n * /

15 MPI_Init(&argc, &argv);MPI_Comm_size(MPI_COMM_WORLD, &C_size);MPI_Comm_rank(MPI_COMM_WORLD, &C_rank);if (C_size!=NP)

MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);20 / * v o l l s t a n d i g e Mat r i x e i n l e s e n * /

MPI_File_open(MPI_COMM_WORLD, ” m a t r i x i n 1 . d a t ”,MPI_MODE_RDONLY, MPI_INFO_NULL, &fh);

MPI_File_set_view(fh, 0, MPI_DOUBLE, MPI_DOUBLE, ” n a t i v e ”,MPI_INFO_NULL);

25 MPI_File_read_all(fh, A, SIZE*SIZE, MPI_DOUBLE, &status);MPI_File_close(&fh);/ * MPI D a t e n t y p bauen * /MPI_Address(&A[0][0], displacements);MPI_Address(&A[0][C_rank*SIZE/NP], displacements+1);

30 MPI_Address(&A[0][SIZE], displacements+2);for (i=2; i>=0; --i)

displacements[i]-=displacements[0];MPI_Type_struct(3, len, displacements, types, &filetype);MPI_Type_commit(&filetype);

35 / * M a t r i x a u s c h n i t t e mi t j e SIZE / NP S p a l t e n e i n l e s e n * /MPI_File_open(MPI_COMM_WORLD, ” m a t r i x i n 2 . d a t ”,

MPI_MODE_RDONLY, MPI_INFO_NULL, &fh);MPI_File_set_view(fh, 0, MPI_DOUBLE, filetype, ” n a t i v e ”, MPI_INFO_NULL);MPI_File_read_all(fh, B, SIZE*SIZE/NP, MPI_DOUBLE, &status);

40 MPI_File_close(&fh);/ * M a t r i x m u l t i p l i k a t i o n * /for (i=0; i<SIZE; ++i)

for (j=0; j<SIZE/NP; ++j) {C[i][j]=0;

45 for (k=0; k<SIZE; ++k)C[i][j]+=A[i][k]*B[k][j];

}/ * M a t r i x a u s c h n i t t e mi t j e SIZE / NP S p a l t e n s c h r e i b e n * /MPI_File_open(MPI_COMM_WORLD, ” m a t r i x o u t . d a t ”,

50 MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_INFO_NULL, &fh);MPI_File_set_view(fh, 0, MPI_DOUBLE, filetype, ” n a t i v e ”, MPI_INFO_NULL);MPI_File_write_all(fh, C, SIZE*SIZE/NP, MPI_DOUBLE, &status);MPI_File_close(&fh);MPI_Finalize();

55 return EXIT_SUCCESS;}

Page 259: [X.systems.press] Cluster Computing ||

8.4 Parallele Ein- und Ausgabe 253

× =

A B C× =

Abb. 8.8. Matrix-Matrix-Multiplikation mit vier Prozessen und block-spaltenweiser Auf-teilung.

In unserem zweiten Beispielprogramm lesen und schreiben die Prozesse ihre Datenin der Form von ineinander verschachtelten Blocken, ahnlich wie in Abb. 8.6. DasProgramm in Listing 8.4 fuhrt eine parallele Matrix-Matrix-Multiplikation A ·B = Cmit vier Prozessen durch. Da die Berechnung jedes Matrixelementes

ci, j = ∑k

ai,k ·bk, j (8.9)

von der Berechnung der anderen Matrixelemente vollkommen unabhangig ist, lasstsich dieses Problem gut parallelisieren. In unserem konkreten Beispiel berechnetjeder Prozess 25 der insgesamt 100 Spalten der quadratischen Ergebnismatrix. Dazubenotigt er jeweils die vollstandige Matrix A und einen Streifen aus 25 Spalten derMatrix B, siehe Abb. 8.8.

Zweidimensionale Felder werden in C zeilenweise linear im Hauptspeicher ab-gelegt. Das Programm geht davon aus, dass auch die Eingabedateien die Matrizen Aund B zeilenweise speichern. Da die Matrix A vollstandig eingelesen wird, konnenwir in Zeile 23 eine Dateisicht wahlen, deren Dateityp lediglich ein MPI DOUBLEist, und dann 100×100 Werte lesen. Um die Matrix B einzulesen, benotigen wir je-doch einen speziellen Dateityp. Wegen der zeilenorientierten Speicherung der Matrixmuss dieser Dateityp, der hier jeweils eine Zeile reprasentiert, vorne keine, 25, 50,oder 75 und hinten 75, 50, 25 bzw. keine Locher haben und dazwischen 25 Datenele-mente vom Typ MPI DOUBLE enthalten. Genau solch ein Datentyp konstruiert dasProgramm in den Zeilen 27 bis 34. Die Locher werden durch das explizite Setzender unteren und oberen Beschrankung durch die Datentypen MPI LB und MPI UBeingefugt.

Nachdem die Prozesse jeweils ihren Teil der Matrix C berechnet haben, schreibensie ihn schließlich in eine Ausgabedatei. Dabei konnen wir die gleiche Dateisichtverwenden, wie schon beim Lesen der Matrix B.

8.4.5 Fehlerbehandlung

Beim Umgang mit Dateien muss man immer mit unvorhergesehenen Fehlern rech-nen. Sei es, weil versucht wurde, auf eine nicht vorhandene Datei zuzugreifen, dieFestplatte voll ist oder ein Programm nicht die notwendigen Rechte besitzt, um ei-ne Datei zu offnen. Sauber programmierte Software lasst sich durch solche Fehlernicht aus der Bahn werfen, fangt sie ab und informiert z. B. den Nutzer durch eineFehlermeldung.

Page 260: [X.systems.press] Cluster Computing ||

254 8 Fortgeschrittene Techniken

Listing 8.5. Das Beispielprogramm mpi-io-error.c demonstriert die Fehlerbehandlungbei paralleler Ein- und Ausgabe.

#include <stdio.h>#include <stdlib.h>#include ” mpi . h ”

5 void file_errhandler(MPI_File *fh, int *err) {int err_cl, err_len;char err_str[MPI_MAX_ERROR_STRING+1];fprintf(stderr, ” D a t e i z u g r i f f s f e h l e r \n ”);/ * F e h l e r k l a s s e * /

10 MPI_Error_class(*err, &err_cl);MPI_Error_string(err_cl, err_str, &err_len);err_str[err_len]= ’\0 ’;fprintf(stderr, ” e r r o r c l a s s : %s\n ”, err_str);/ * F e h l e r c o d e * /

15 MPI_Error_string(*err, err_str, &err_len);err_str[err_len]= ’\0 ’;fprintf(stderr, ” e r r o r code : %s\n ”, err_str);MPI_File_close(fh); / * D a t e i s c h l i e ß e n * /MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE); / * Programm a b b r e c h e n * /

20 }

int main(int argc, char *argv[]) {MPI_File fh;MPI_Errhandler errh_old, errh_new;

25 int err, err_cl, err_len;char err_str[MPI_MAX_ERROR_STRING+1];

MPI_Init(&argc, &argv);err=MPI_File_open(MPI_COMM_WORLD, ” h i d d e n f i l e . d a t ”, / * D a t e i * /

30 MPI_MODE_RDONLY, MPI_INFO_NULL, &fh); / * o f f n e n * /if (err!=MPI_SUCCESS) { / * I s t beim Offnen e i n F e h l e r a u f g e t r e t e n ? * /

fprintf(stderr, ” M P I F i l e o p e n s c h l u g f e h l .\ n ”);/ * F e h l e r k l a s s e * /MPI_Error_class(err, &err_cl);

35 MPI_Error_string(err_cl, err_str, &err_len);err_str[err_len]= ’\0 ’;fprintf(stderr, ” e r r o r c l a s s : %s\n ”, err_str);/ * F e h l e r c o d e * /MPI_Error_string(err, err_str, &err_len);

40 err_str[err_len]= ’\0 ’;fprintf(stderr, ” e r r o r code : %s\n ”, err_str);MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE); / * Programm a b b r e c h e n * /

}/ * a l t e F e h l e r b e h a n d l u n g s r o u t i n e s i c h e r n und

45 e i g e n e F e h l e r b e h a n d l u n g s r o u t i n e r e g i s t r i e r e n * /MPI_File_get_errhandler(fh, &errh_old);MPI_File_create_errhandler((MPI_File_errhandler_fn *)file_errhandler,

&errh_new);MPI_File_set_errhandler(fh, errh_new);

50 / * D a t e i o p e r a t i o n e n * /

/ * a l t e F e h l e r b e h a n d l u n g s r o u t i n e wiede r r e g i s t r i e r e n * /MPI_File_set_errhandler(fh, errh_old);MPI_Errhandler_free(&errh_new);

55 MPI_File_close(&fh); / * D a t e i s c h l i e ß e n * /MPI_Finalize();return EXIT_SUCCESS;

}

Page 261: [X.systems.press] Cluster Computing ||

8.4 Parallele Ein- und Ausgabe 255

Genau wie jedem Kommunikator ist auch jedem Dateihandle eine Fehler-Be-handlungs-Funktion zugeordnet. Da aber Fehler, die wahrend Dateioperationen auf-treten, meist weniger schwerwiegend sind, wird einem Dateihandle standardmaßigdie Fehler-Behandlungs-Funktion MPI ERRORS RETURN zugewiesen. Sie ignoriertalle auftretenden Fehler und fehlerhafte Dateizugriffsfunktionen kehren mit einemWert ungleich MPI SUCCESS zuruck.

Das Listing 8.5 zeigt, wie man diese Fehlercodes im Zusammenhang mit Da-teizugriffen praktisch verwendet. In Zeile 29 versucht dieses Programm, eine Dateizu offnen. Schlagt dies fehl, weil sie z. B. nicht gefunden wurde, so werden einigeFehlermeldungen ausgegeben und das Programm abgebrochen. Dazu ermittelt dasProgramm zunachst die zum Fehlercode gehorende Fehlerklasse und gibt dann ei-ne textliche Beschreibung der Fehlerklasse und des Fehlercodes aus. Diese textlicheBeschreibung ist ein Detail der MPI-Implementation. Wird unter MPICH2 (Version1.0.1) versucht, eine nicht existente Datei zu offnen, so erhalten wir die folgendeMeldung:

bauke@server:˜/mpi $ mpiexec -n 1 ./mpi-io-errorMPI_File_open schlug fehl.error class: File does not existerror code : File does not exist, error stack:ADIOI_UFS_OPEN(52): File hidden_file.dat does not existaborting job:application called MPI_Abort(MPI_COMM_WORLD, 1) - process 0rank 0 in job 30 server_32897 caused collective abort of all ranksexit status of rank 0: return code 1

LAM/MPI (Version 7.1.1) zeigt sich hier leider weniger auskunftsfreudig.

bauke@server:˜/mpi $ mpiexec -n 1 ./mpi-io-errorMPI_File_open schlug fehl.error class: MPI_Error_string: unknown errorerror code : MPI_Error_string: unknown error

Nicht nur die Fehler von MPI File open konnen wie in den Zeilen 31 bis 43demonstriert abgefangen werden, diese Vorgehensweise funktioniert mit allen MPI-Dateifunktionen. Auf die Dauer ist es jedoch etwas aufwendig, jede MPI-Dateifunk-tion auf ihre korrekte Abarbeitung zu testen. Darum schreiben wir uns unsere ei-gene Fehler-Behandlungs-Funktion file errhandler. Im Grunde kennen Siedie folgende Vorgehensweise schon aus Abschnitt 8.2. Jedoch kommen fur Datei-Fehler-Behandlungs-Funktionen andere Funktionen zum Einsatz als im Kontext vonKommunikatoren. In den Zeilen 44 bis 49 wird die Fehler-Behandlungs-FunktionMPI ERRORS RETURN mit

int MPI_File_get_errhandler(MPI_File file, MPI_Errhandler *errhandler)

gesichert und mit den beiden Funktionen

int MPI_File_create_errhandler(MPI_File_errhandler_fn *function,MPI_Errhandler *errhandler)

und

Page 262: [X.systems.press] Cluster Computing ||

256 8 Fortgeschrittene Techniken

int MPI_File_set_errhandler(MPI_File file, MPI_Errhandler errhandler)

gegen die neue Fehler-Behandlungs-Funktion file errhandler ausgetauscht.Wann immer nun im Zusammenhang mit dem Dateihandle fh ein Fehler auftritt,gibt die Funktion eine Meldung uber den aufgetreten Fehler aus, schließt die Da-tei und bricht das laufende Programm ab. Fehler-Behandlungs-Funktionen mussenimmer die Signatur

typedef void MPI_File_errhandler_fn(MPI_File *, int *, ...);

haben. Im ersten Argument wird der Funktion immer das Dateihandle und als zwei-tes Argument der Fehlercode ubergeben, eventuelle weitere Argumente sind imple-mentationsspezifisch. Da wir uns die alte Fehler-Behandlungs-Funktion gemerkt ha-ben, konnen wir bei Bedarf diese wieder reaktivieren. Nicht mehr benotigte Fehler-Behandlungs-Funktionen lassen sich mit

int MPI_Errhandler_free(MPI_Errhandler *errhandler)

wieder beim MPI-System abmelden.

8.5 Notizen

8.1 Pack/Unpack. Wenn es darum geht, heterogene Daten in eine einzige Nachrichtzu verpacken, konnen statt nutzerspezifischer Datentypen auch die Funktionen MPIPack und MPI Unpack verwendet werden. Hierbei werden die zu versendendenDaten zuerst in einen Sendepuffer gepackt und vom Empfanger wieder entpackt. Inder Regel sind nutzerspezifische Datentypen den Funktionen MPI Pack und MPIUnpack vorzuziehen.

8.2 Neue Funktionen zur Manipulation von Datentypen aus MPI-2. In MPI-2wurden einige neue Funktionen zur Manipulation von Datentypen eingefuhrt. Nichtalle stellen jedoch eine neue Funktionalitat zur Verfugung, manche beseitigenlediglich einige potentielle Probleme bzgl. der FORTRAN-Versionen der altenDatentyp-Manipulations-Funktionen und sind zum Teil etwas einfacher zu handha-ben. Die drei Funktionen MPI Type get true extent, MPI Type createsubarray und MPI Type create darray haben in MPI-1.2 hingegen keinPendant. Außerdem kann die Wirkung der Pseudodatentypen MPI UB und MPI LBdurch die neue Funktion MPI Type create resized erreicht werden.

Die alten Funktionen werden in MPI-2 als deprecated bezeichnet, sind aber nochimmer Teil des Standards, sollten bloß nicht mehr verwendet werden. Allerding durf-ten Programme, die die alten Funktionen benutzen, in der Praxis portabler sein.

8.3 Fehlerbehandlung nach MPI-2. In MPI-2 wurde das Konzept der Fehler-Behandlungs-Funktionen von Kommunikatoren auf andere Objekte wie z. B. Da-teihandles ausgedehnt und dazu neue Funktionen wie z. B. MPI File createerrhandler eingefuhrt. Aus Grunden der Konsistenz gibt es in MPI-2 auch gleich

Page 263: [X.systems.press] Cluster Computing ||

8.5 Notizen 257

neue Funktionen zum Umgang mit Fehler-Behandlungs-Funktionen fur Kommunika-toren. Die neuen Funktionen sind bis auf den Namen identisch zu ihrem Pendant ausMPI-1.1.

MPI-1.1 MPI-2

MPI Errhandler create MPI Comm create errhandlerMPI Errhandler get MPI Comm get errhandlerMPI Errhandler set MPI Comm set errhandler

8.4 Dateizugriffsfunktionen. Die in Abschnitt 8.4 vorgestellten Dateizugriffsfunk-tionen werden leider von keiner von uns bekannten freien MPI-Implementation ohneEinschrankungen implementiert. So kennt MPICH2 (Version 1.0.1) z. B. nicht dasDatenformat external32 und in LAM/MPI (Version 7.1.1) fehlen u. a. die Funkti-onen zur Definition eigener Fehler-Behandlungs-Funktionen fur Dateihandles. SindIhre Anwendungen auf die MPI-Dateifunktionen angewiesen, sollten Sie sich alsogenau erkundigen, welche MPI-Implementation, die fur Ihre Zwecke notwendigeFunktionalitat bereitstellen kann.

Page 264: [X.systems.press] Cluster Computing ||

9

Parallelisierungstechniken

If the work is a 100 separate jobs that don’t depend on eachother, and they all take the same amount of time and can beeasily parceled out to the workers, then you’ll get it doneabout 100 times faster. This is so easy that it is calledembarrassingly parallel. Just because it is embarrassingdoesn’t mean you shouldn’t do it, it just means you shouldn’tthink you are especially clever.

Quentin F. Stout [161]

9.1 Perfekte Parallelisierung

9.1.1 Peinliche und weniger peinliche Probleme

Der Aufwand, den man treiben muss, um ein Problem effizient auf einem Parallel-rechner losen zu konnen, hangt von der Struktur des Problems ab. Manchmal genugtes, einen sequentiellen Algorithmus geringfugig zu modifizieren. Andere Problemeerfordern einen ganz neuen Ansatz und manche lassen sich gar nicht effizient paral-lelisieren. Es existiert aber auch eine Klasse von Problemen, die praktisch von selbstin eine große Zahl voneinander unabhangige Teilprobleme zerfallen. Diese werdenauch als inharent parallel oder auch embarrassingly parallel bezeichnet. Wobei em-barrassingly hier soviel wie beschamend oder peinlich heißt.

Probleme, die sich leicht in voneinander unabhangige Teilprobleme zerlegen las-sen, treten in ganz verschiedenen Kontexten auf.

Parameterstudien. In einer Parameterstudie wird dasselbe Problem immer wiedermit unterschiedlichen Eingabedaten gelost. Die einzelnen Programmlaufe sindvoneinander unabhangig. Fur die parallele Bearbeitung reicht ein Batch-System,eine echte Parallelisierung ist nur notig, wenn die Auswahl weiterer Eingabeda-ten von den bisherigen Ergebnissen abhangt.

Datenauswertung. Bei manchen physikalischen Experimenten werden riesige Da-tenmengen erhoben. Die Analyse eines Datensatzes ist aber meist unabhangigvon der eines anderen.

Monte-Carlo-Simulationen. Ergebnisse von Monte-Carlo-Simulationen sind im-mer mit einem statistischen Fehler behaftet. Die Große dieses Fehlers lasst sichleicht abschatzen, wenn man eine Monte-Carlo-Simulation mehrfach wiederholtund die Streuung der Einzelergebnisse analysiert. Die verschiedenen Monte-Car-lo-Simulationen sind naturlich voneinander vollkommen unabhangig.

Page 265: [X.systems.press] Cluster Computing ||

260 9 Parallelisierungstechniken

Filmproduktion. Auch die digitale Bearbeitung von Filmen ist eine inharent paral-lele Aufgabe. Fur jede Sekunde Film mussen ca. 25 Standbilder erstellt werden,ein abendfullender Spielfilm zerfallt so in ca. 135 000 voneinander unabhangigeTeilprobleme.

Kombinatorische Optimierung. Manche besonders hartnackige Probleme der kom-binatorischen Optimierung lassen sich nur durch systematisches Testen allermoglichen Eingabewerte losen. Hier stellt das Testen jedes moglichen Satzesvon Eingabewerten ein unabhangiges Problem dar. Ein brute-force-Angriff aufein Kryptosystem, bei dem alle moglichen Schlussel probiert werden, fallt auchin diese Kategorie. In Abschnitt 9.1.5 werden wir uns mit einem solchen Pro-blem genauer beschaftigen.

Die Liste ließe sich noch fortsetzen.

9.1.2 Statische Lastverteilung

Die Parallelisierung inharent paralleler Probleme ist denkbar einfach. Da das Aus-gangsproblem von sich aus in viele, sagen wir N, unabhangige Teilprobleme zerfallt,kann man dieses bei der Verwendung von p Prozessoren effizient losen, indem manjeden Prozess ca. N/p Teilprobleme bearbeiten lasst. Inharent parallele Problemezeichnen sich dadurch aus, dass sie sich (fast) ohne jede Kommunikation zwischenden Prozessen losen lassen. Darum wird bei ihnen meist ein fast idealer Speedup er-reicht. Lediglich durch Kommunikation vor und nach der eigentlichen Berechnungkann der real erreichte Speedup etwas unterhalb des ideal erreichbaren liegen. Die-se beiden Kommunikationsschritte sind meist notwendig, um Eingabedaten fur eineBerechnung an die Prozesse zu verteilen bzw. nach einer Berechnung die Ergebnisseeinzusammeln.

Wir wollen die grundsatzliche Vorgehensweise bei der Parallelisierung inharentparalleler Probleme an einem kleinen Beispiel illustrieren. In [65] beschreibt BrianHayes, wie man mit dem Computer optische Beugungsbilder berechnet. Experimen-tell lassen sich solche Beugungsbilder realisieren, indem man eine Maske mit sehrkleinen Lochern mit koharentem Licht (Laser) bestrahlt. Hinter der Maske tritt dasLicht in kugelformigen Wellen aus und trifft im Abstand d schließlich auf einenSchirm. In jedem Punkt des Schirms uberlagern sich die Kugelwellen aller Locher.Dabei kann es zu konstruktiver oder destruktiver Uberlagerungen der Wellen kom-men, so dass ein Beugungsbild wie das in Abb. 9.1 entsteht. Die Abbildung zeigt einBeugungsbild, das durch die Uberlagerung der Wellen von funf an den Ecken einesregelmaßigen Funfeckes angeordneten Quellen entstand.

Der Algorithmus zur Berechnung solcher Bilder arbeitet wie folgt [38]: DerSchirm wird in ein Raster von Nx ×Ny diskreten Punkten eingeteilt. Fur jeden Punkt(x,y) des Schirms berechnen wir eine komplexe Amplitude I(x,y), zu der jede der qQuellen einen Beitrag leistet.

I(x,y) =q

∑i=1

ai

l((x,y),(xi,yi))

(cos

2π · l((x,y),(xi,yi))

λ+ i sin

2π · l((x,y),(xi,yi))

λ

)

(9.1)

Page 266: [X.systems.press] Cluster Computing ||

9.1 Perfekte Parallelisierung 261

�� Nx

Prozess 0Nyl,0

Prozess 1Nyl,1

Prozess 2Nyl,2

Prozess 3Nyl,3

Prozess 4Nyl,4

Prozess 5Nyl,5

Ny

Ny0l,5

Ny0l,4

Ny0l,3

Ny0l,2

Ny0l,1

Ny0l,0

Abb. 9.1. Berechnetes Beugungsbild von an den Ecken eines regelmaßigen Funfecks ange-ordneten Quellen (dunkle Stellen entsprechen hoher Intensitat). Die Berechnung des Bildeswurde auf sechs Prozesse verteilt, indem das Bild in sechs etwa gleich große Streifen zerlegtwurde.

Die Funktion l((x,y),(xi,yi) steht hier fur den Abstand der i-ten Quelle, die sich bei(xi,yi) befindet, zum Punkt (x,y). Diese Distanz hangt naturlich auch vom Abstandd zwischen Maske und Schirm ab. Die Variable λ bezeichnet die Wellenlange desLichtes und ai die relative Intensitat der i-ten Quelle. Die tatsachlich auf dem Schirmbeobachtete Intensitat ist proportional zum Absolutquadrat |I(x,y)|2.

In Listing 9.1 sehen Sie das Programm, mit dem wir das Beugungsbild inAbb. 9.1 berechnet haben. Die zentrale Datenstruktur in diesem Programm ist vomTyp diff data t. Diese Struktur kodiert alle notwendigen Geometriedaten.

Nsources. Zahl der Quellen (Locher in der Maske).Nx, Ny. Zahl der Bildpunkte in horizontaler und vertikaler Richtung, in die der

Schirm zerlegt wird.dist. Abstand der Maske zum Schirm.x1, y1, x2, y2. Große des rechteckigen Schirms (linke untere Ecke und rech-

te obere Ecke).lambda. Wellenlange der verwendeten Lichts.sources. Feld, das horizontale und vertikale Position und relative Intensitat der

Quellen enthalt.

Nachdem ab Zeile 69 die MPI-Umgebung initialisiert wurde, ruft jeder Prozess dieFunktion read input auf und liest aus einer Eingabedatei alle notwendigen Geo-

Page 267: [X.systems.press] Cluster Computing ||

262 9 Parallelisierungstechniken

Listing 9.1. Das Programm digital diffraction.c berechnet Beugungsbilder wie dasin Abb. 9.1.

#include <stdlib.h>#include <stdio.h>#include <math.h>#include ” mpi . h ”

5typedef struct {

int Nsources, Nx, Ny;double dist, x1, y1, x2, y2, lambda;struct { double x, y, a; } *sources;

10 } diff_data_t;

void * secure_malloc(size_t size) {void * p=malloc(size);if (p==NULL)

15 MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);return p;

}

diff_data_t read_input(const char *fname) {20 int i;

diff_data_t D={0};FILE *fd;fd=fopen(fname, ” r ”);if (fd!=NULL) {

25 fscanf(fd, ” d i s t%l f \n ”, &D.dist);fscanf(fd, ” s c r e e n%l f%l f%l f%l f \n ”, &D.x1, &D.y1, &D.x2, &D.y2);fscanf(fd, ” p i c t u r e%i%i \n ”, &D.Nx, &D.Ny);fscanf(fd, ” lambda%l f \n ”, &D.lambda);fscanf(fd, ” s o u r c e s%i \n ”, &D.Nsources);

30 D.sources=secure_malloc(D.Nsources*sizeof(*D.sources));for (i=0; i<D.Nsources; ++i)

fscanf(fd, ” s o u r c e%l f%l f%l f \n ”, &D.sources[i].x,&D.sources[i].y, &D.sources[i].a);

fclose(fd);35 }

return D;}

double intensity(diff_data_t D, double *I) {40 double dx=D.x2-D.x1, dy=D.y2-D.y1, dist2=D.dist*D.dist,

x, y, d, phi, I_re, I_im, I_max=0.0;int i, j, k;for (j=0; j<D.Ny; ++j) { / * I t e r a t i o n ube r Z e i l e n * /

y=D.y1+(j+0.5)*dy/D.Ny;45 for (i=0; i<D.Nx; ++i) { / * I t e r a t i o n ube r S p a l t e n * /

x=D.x1+(i+0.5)*dx/D.Nx;I_re=I_im=0.0;for (k=0; k<D.Nsources; ++k) { / * I t e r a t i o n u b e r Q u e l l e n * /

d=sqrt((x-D.sources[k].x)*(x-D.sources[k].x)+50 (y-D.sources[k].y)*(y-D.sources[k].y)+dist2);

phi=6.28318530717958648*d/D.lambda;I_re+=D.sources[k].a*cos(phi)/d;I_im+=D.sources[k].a*sin(phi)/d;

}55 I[i+D.Nx*j]=I_re*I_re+I_im*I_im; / * A b s o l u t q u a d r a t = I n t e n s i t a t * /

if (I[i+D.Nx*j]>I_max)I_max=I[i+D.Nx*j];

Page 268: [X.systems.press] Cluster Computing ||

9.1 Perfekte Parallelisierung 263

}}

60 return I_max;}

int main(int argc, char *argv[]) {int C_rank, C_size, *Ny_l, *Ny0_l, i;

65 double *I_l, *I=NULL, I_max_l, I_max;diff_data_t D={0}, D_l={0};FILE *out;MPI_Datatype row_t;/ * MPI i n i t i a l i s i e r e n * /

70 MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD, &C_rank);MPI_Comm_size(MPI_COMM_WORLD, &C_size);if (argc>=2)

D=read_input(argv[1]); / * Daten e i n l e s e n * /75 if (D.Nsources==0) / * k e i n e E i n g a b e d a t e i * /

MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);/ * b e r e c h n e B r e i t e des S t r e i f e n s f u r j e d e n P r o z e s s * /Ny_l=secure_malloc(C_size*sizeof(*Ny_l));Ny0_l=secure_malloc(C_size*sizeof(*Ny0_l));

80 for (i=0; i<C_size; ++i) {Ny_l[i]=(i+1)*D.Ny/C_size-i*D.Ny/C_size;Ny0_l[i]=i*D.Ny/C_size;

}/ * r e c h n e g l o b a l e G e o m e t r i e d a t e n a u f l o k a l e Daten um * /

85 D_l=D;D_l.Ny=Ny_l[C_rank];D_l.y1=Ny0_l[C_rank]*(D.y2-D.y1)/D.Ny+D.y1;D_l.y2=(Ny0_l[C_rank]+Ny_l[C_rank])*(D.y2-D.y1)/D.Ny+D.y1;I_l=secure_malloc(D.Nx*D_l.Ny*sizeof(*I_l));

90 I_max_l=intensity(D_l, I_l); / * b e r e c h n e I n t e n s i t a t * // * e r m i t t l e maximale I n t e n s i t a t u b e r a l l e P r o z e s s e * /MPI_Allreduce(&I_max_l, &I_max, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);for (i=0; i<D.Nx*D_l.Ny; ++i) / * I n t e n s i t a t e n a u f [ 0 , 255] n o r m i e r e n * /

I_l[i]=255.0-floor(I_l[i]/I_max*255.0+0.5);95 / * Daten einsammeln und ausgeben * /

if (C_rank==0)I=secure_malloc(D.Nx*D.Nx*sizeof(*I));

MPI_Type_contiguous(D.Nx, MPI_DOUBLE, &row_t); / * D a t e n t y p f u r Z e i l e * /MPI_Type_commit(&row_t);

100 MPI_Gatherv(I_l, Ny_l[C_rank], row_t, I, Ny_l, Ny0_l, row_t,0, MPI_COMM_WORLD);

if (C_rank==0 && argc>=3) {out=fopen(argv[2], ”w”);fprintf(out, ”P5\n%i %i \n255\n ”, D.Nx, D.Ny); / * PGM−Header * /

105 for (i=0; i<D.Nx*D.Ny; ++i) / * G r a u s t u f e n * /fputc((int)I[i], out);

}/ * R e s s o u r c e n f r e i g e b e n * /free(I); free(I_l);

110 free(Ny_l); free(Ny0_l);free(D.sources);MPI_Type_free(&row_t);MPI_Finalize();return EXIT_SUCCESS;

115 }

Page 269: [X.systems.press] Cluster Computing ||

264 9 Parallelisierungstechniken

Listing 9.2. Eingabedatei zur Berechnung des Beugungsbildes in Abb. 9.1.

dist 0.2screen -0.4 -0.4 0.4 0.4picture 1000 1000lambda 0.3e-6

5 sources 5source 3e-06 0 1source 9.27051e-07 2.85317e-06 1source -2.42705e-06 1.76336e-06 1source -2.42705e-06 -1.76336e-06 1

10 source 9.27051e-07 -2.85317e-06 1

metriedaten ein. Die Eingabedatei hat ein recht starres Format, sie enthalt Schlussel-worte und numerische Werte. In Listing 9.2 finden Sie die Konfigurationsdatei furAbb. 9.1.

Die Berechnung des Beugungsbildes wird auf p Prozesse aufgeteilt, indem jedemProzess ein etwa gleich großer Streifen des Schirms zugewiesen wird, siehe Abb. 9.1.Die Zahl der Bildpunkte in vertikaler Richtung lasst sich im Allgemeinen nicht durchdie Zahl der Prozesse teilen. Der Prozess mit der Nummer i (i = 0,1, . . . , p− 1) istfur einen Streifen der Breite

Nyl,i =

⌊(i+1) ·Ny

p

⌋−

⌊i ·Ny

p

⌋(9.2)

zustandig. Die erste Zeile eines Streifens befindet sich an der vertikalen Position

Ny0l,i =

⌊i ·Ny

p

⌋. (9.3)

(Die Klammer �·� steht hier fur das Abrunden auf ganze Zahlen.) Durch diese Art derAufteilung wird sichergestellt, dass sich die Zahlen der jedem Prozess zugewiesenenBildschirmzeilen um maximal eins unterscheiden.

Diese Aufteilungsart lasst sich auch auf ganz allgemeine Probleme anwenden.Sollen N Teilprobleme gleichmaßig auf p Prozesse aufgeteilt werden, so werdenProzesse und Probleme von null bis p−1 bzw. N −1 durchnummeriert und der i-teProzess bearbeitet die Teilprobleme �i ·N/p� bis einschließlich �(i+1) ·N/p�− 1.In Abschnitt 9.2 werden wir diesem Muster noch einmal begegnen. Die Großen(9.2) und (9.3) werden von jedem Prozess in den Zeilen 77 bis 83 berechnet. Dajeder Prozess nur fur einen Ausschnitt des Schirms zustandig ist, mussen die obeneingelesenen globalen Geometriedaten noch auf den lokalen Ausschnitt umgerechnetwerden. Dies geschieht in den Zeilen 84 bis 89. Mit diesen lokalen Daten kann nun je-der Prozess fur seinen Bildschirmausschnitt die Intensitatsverteilung und die (lokale)maximale Intensitat berechnen. Dazu ruft er in Zeile 90 die Funktion intensityauf, welche die Formel (9.1) implementiert.

Nach der Berechnung des Beugungsbildes soll die Intensitatsverteilung in Formeiner Pixelgrafik im portable-graymap-Format ausgegeben werden. Dazu mussenzunachst die Intensitatswerte auf ganze Zahlen zwischen 0 und 255 umgerechnet wer-den. Die hellste Stelle im Gesamtbild bekommt den Farbwert 0. Fur die Umrechnung

Page 270: [X.systems.press] Cluster Computing ||

9.1 Perfekte Parallelisierung 265

der Intensitatswerte benotigen also alle Prozesse den global großten Intensitatswert,der in Zeile 92 mit MPI Allreduce ermittelt wird. Hier mussen die Prozesse zumersten Mal miteinander kommunizieren. Die Normierung der Intensitatsverteilungauf 0,1, . . . ,255 erfolgt in der Schleife in den Zeilen 93 und 94.

Ab Zeile 95 sammelt der Prozess mit dem Rang null alle Intensitatswerte ein.Da nicht alle Prozesse gleich viele Zeilen bearbeitet haben, mussen wir dazu MPIGatherv verwenden. Jetzt sollte Ihnen auch klar werden, warum in den Zeilen 77bis 83 samtliche Werte Nyl,0 bis Nyl,p−1 und Ny0l,0 bis Ny0l,p−1 berechnet wurden. ZurIntensitatsberechnung benotigt Prozess i eigentlich nur Nyl,i und Ny0l,i, beim Aufrufvon MPI Gatherv braucht zumindest der Prozess mit dem Rang null jedoch allediese Werte.

Hat der Prozess mit dem Rang null alle Intensitatswerte eingesammelt, so schreibter sie als Bytewerte in eine portable-graymap-Datei. Neben den Bytewerten, die ver-schiedene Graustufen codieren, hat eine portable-graymap-Datei noch einen Kopf,der aus der Kennung P5, der Breite und Hohe und dem maximalen Grauwert be-steht, siehe Zeile 104. Zum Schluss wird MPI Finalize aufgerufen und belegteRessourcen werden wieder freigegeben.

9.1.3 Dynamische Lastverteilung, Master-Worker-Schema

Bei der im vorherigen Abschnitt beschriebenen statischen Lastverteilung haben wirimplizit zwei Annahmen gemacht.

• Die Zahl der Rechenoperationen, die benotigt wird, um ein Teilproblem zu losen,ist fur alle Teilprobleme gleich.

• Alle Prozesse laufen auf gleich schnellen CPUs.

Allzuoft ist eine oder sind beide Annahmen nicht erfullt. Einerseits konnen die Kno-ten eines Cluster-Computers durchaus verschieden schnelle CPUs haben, anderer-seits kann man nicht immer a priori vorhersagen, wieviele Rechenoperationen zurLosung eines konkreten Teilproblems notwendig sind.

Ist eine der obigen Annahmen nicht erfullt, so wird bei einer statischen Lastvertei-lung die Gesamtlaufzeit eines parallelen Programms von der langsamsten CPU bzw.dem aufwendigsten Teilproblem bestimmt. Wahrend einige Prozesse noch rechnen,haben andere schon langst ihr Teilproblem abgearbeitet und warten. In diesem Fall isteine statische Lastverteilung sicher alles andere als perfekt. Mit einer dynamischenLastverteilung nach dem Master-Worker-Schema lasst sich eine homogenere Aus-lastung der Prozesse erzielen. Prozesse auf schnellen CPUs bekommen automatischmehr Arbeit zugewiesen, langsame Prozesse dafur weniger.

Die zentrale Idee besteht beim Master-Worker-Schema (manchmal auch Master-Servant- oder auch Bank-Queue-Schema genannt) darin, einen der Prozesse ge-genuber den restlichen funktional auszuzeichnen. Dieser Prozess heißt Master, dieubrigen werden Worker genannt. Die Aufgabe des Masters ist es, die Worker mitArbeit und Eingabedaten zu versorgen und deren Ergebnisse einzusammeln. Dazuverwaltet er zwei Stapel mit Teilproblemen. Ein Stapel enthalt die noch unerledigtenTeilprobleme, der andere die, die schon abgearbeitet wurden, siehe Abb. 9.2.

Page 271: [X.systems.press] Cluster Computing ||

266 9 Parallelisierungstechniken

unerledigt erledigt

Worker 1 Worker 2 Worker 3 Worker 4

Master

Abb. 9.2. Master-Worker-Schema zur dynamischen Lastverteilung.

Nach dem Programmstart fragen alle Worker beim Master nach einem Teilpro-blem. Der Master nimmt vom Stapel mit den noch unerledigten Teilproblemen einesherunter und weist es einem Worker zu. Nachdem ein Worker sein aktuelles Teilpro-blem abgearbeitet hat, schickt er das Ergebnis an den Master zuruck und fragt auchgleich die nachste Aufgabe ab. Der Master nimmt das Ergebnis entgegen und packtdas entsprechende Teilproblem auf den Stapel mit den schon erledigten Teilproble-men. Ist der Stapel mit den noch unerledigten Teilproblemen noch nicht leer, nimmtder Master das nachste Teilproblem von diesem Stapel und schickt zur Bearbeitungan den Worker. Andernfalls darf er sich beenden. Dieses Spiel geht so lange, bis so al-le Teilprobleme vom Stapel mit den noch unerledigten Teilproblemen auf den Stapelmit den schon erledigten Teilproblemen transferiert wurden.

Da ein Worker sich immer nur dann Arbeit vom Master holt, wenn er geradenichts zu tun hat, bekommen Prozesse auf schnellen CPUs automatisch mehr Arbeitund Prozesse auf langsamen CPUs weniger Arbeit zugewiesen. Die Zeit, die dieWorker-Prozesse mit aktiver Arbeit verbringen, ist aber bei allen ungefahr gleich, sodass die Rechenlast annahernd optimal verteilt wird. Trotzdem schwankt die Zeit Ti,die die Worker-Prozesse mit aktiver Arbeit verbringen. Ein Maß dafur, wie homogendie Gesamtrechenlast auf die Worker verteilt wurde, ist das Verhaltnis

maxi Ti −mini Ti

maxi Ti. (9.4)

Je kleinder dieses Verhaltnis ist, desto homogener die Lastverteilung.Theoretisch sollte die Lastverteilung besonders homogen sein, wenn die Zahl

der Teilprobleme sehr groß gegen die Zahl der Worker ist. Denn die Differenzmaxi Ti −mini Ti ist maximal so groß wie die Zeit, die der langsamste Prozess furdas aufwendigste Teilproblem benotigt. Indem man das Ausgangsproblem in immerkleinere Teilprobleme zerlegt, kann man diese Differenz beliebig klein machen. Al-lerdings nimmt mit der Zahl der Teilprobleme auch die Kommunikation zwischenMaster und Worker zu, wodurch sich die Gesamtlaufzeit erhoht. Bei extrem frein-granularer Aufteilung des Ausgangsproblems kommt es sogar dazu, dass der Masterdie zahlreichen Anfragen der Worker gar nicht mehr in angemessener Zeit bearbei-ten kann. Statt zu rechnen, warten die Worker auf den Master. Sie sehen, auch hier

Page 272: [X.systems.press] Cluster Computing ||

9.1 Perfekte Parallelisierung 267

gelten die Uberlegungen aus Abschnitt 1.6 und es kommt auf den richtigen Grad derGranularitat an.

9.1.4 Eine Master-Worker-Bibliothek

Das Master-Worker-Schema ist einerseits so wichtig und andererseits so generisch,dass wir Ihnen nicht nur ein exemplarisches Programm zeigen wollen. Stattdessenstellen wir hier eine kleine C-Bibliothek vor, mit der Sie sehr einfach eigene Pro-gramme nach dem Master-Worker-Schema schreiben konnen. Diese Bibliothek wi-ckelt fur Sie samtliche Kommunikationsschritte eines Master-Worker-Programms ab,wahrend Sie sich auf die Programmierung des eigentlichen Losungsalgorithmus furIhr Problem konzentrieren konnen.

Die Master-Worker-Bibliothek besteht aus einer Headerdatei, siehe Listing 9.3,in der alle Prototypen der Bibliotheks-Funktionen und einige Typen definiert wer-den, und der Implementierung, siehe Listing 9.4. Die beiden Typen master t undworker t sind Zeiger auf die Strukturen master str und worker str, in de-nen alle Verwaltungsinformation fur Master- und Worker-Prozesse gespeichert wer-den. Zu diesen Informationen gehoren

• die Anzahl der Worker,• die Anzahl der gerade arbeitenden Worker,• ein Zeiger auf ein Feld, das Information uber den momentanen Zustand (frei,

arbeitend oder beendet) eines jeden Workers enthalt,• den Kommunikator, uber den Master und Worker mit einander kommunizieren,

sowie• die MPI-Datentypen, die die Daten fur einen Job bzw. dessen Ergebnis reprasen-

tieren.

In einem Programm, das unsere Master-Worker-Bibliothek benutzt, werden samtli-che Kommunikationsprozesse von den Workern initiiert. Die Worker senden an denMaster eine Nachricht, in der sie ihm mitteilen, dass sie entweder

• einen Job vom Master erhalten mochten,• ein (Teil-)Ergebnis zum Master senden mochten oder• dass ihr Job abgearbeitet wurde.

So lange dem Master noch unbearbeitete Jobs vorliegen oder einige Worker beschaf-tigt sind, lauscht der Master in einer Schleife mit der Funktion master listennach Anfragen der Worker. Diese beantwortet der Master indem er

• den Worker mit neuen Job-Daten versorgt und als arbeitend markiert,• falls keine Jobs mehr vorliegen, dem Worker mitteilt, dass er sich beenden kann,

und ihn als beendet markiert,• Job-Ergebnisse vom Worker empfangt oder• einen Worker als wieder frei markiert.

Page 273: [X.systems.press] Cluster Computing ||

268 9 Parallelisierungstechniken

Listing 9.3. Die Headerdatei master worker.h der Master-Worker-Bibliothek.

#if !(defined MASTER_WORKER_H)

#define MASTER_WORKER_H#include ” mpi . h ”

5/ * V e r w a l t u n g s s t r u k t u r f u r Master−P r o z e s s * /typedef struct {

int num_workers, num_working_workers, *working;MPI_Comm comm;

10 MPI_Datatype job_dt, result_dt;} master_str;typedef master_str * master_t;

/ * V e r w a l t u n g s s t r u k t u r f u r Worker−P r o z e s s * /15 typedef struct {

MPI_Comm comm;MPI_Datatype job_dt, result_dt;

} worker_str;typedef worker_str * worker_t;

20/ * Worker−Kommandos * /enum { MW_ask_for_job, MW_return_result, MW_job_done };/ * Kennze ichnungen f u r v e r s c h i e d e n e N a c h r i c h t e n * /enum { MW_listen_tag, MW_send_job_data_tag, MW_recv_result_data_tag };

25 / * Z u s t a n d e e i n e s Workers * /enum { MW_worker_free, MW_worker_working, MW_worker_suspended };

/ * Master−F u n k t i o n e n * /master_t master_new(int num_workers, MPI_Comm comm,

30 MPI_Datatype job_dt, MPI_Datatype result_dt);void master_free(master_t m);int master_some_working(master_t m);int master_listen(master_t m, int *command);void master_send_work(master_t m, int w, void *data);

35 void master_get_result(master_t m, int w, void *data);void master_free_worker(master_t m, int w);void master_suspend_worker(master_t m, int w);void master_suspend_all_workers(master_t m);

40 / * Worker−F u n k t i o n e n * /worker_t worker_new(MPI_Comm comm,

MPI_Datatype job_dt, MPI_Datatype result_dt);void worker_free(worker_t w);int worker_get_work(worker_t w, void *data);

45 void worker_send_result(worker_t w, void *data);void worker_done(worker_t w);

#endif

Listing 9.4. Implementation master worker.c der Master-Worker-Bibliothek.

#include <stdlib.h>#include <unistd.h>#include ” m a s t e r w o r k e r . h ”

5 master_t master_new(int num_workers, MPI_Comm comm,MPI_Datatype job_dt, MPI_Datatype result_dt) {

Page 274: [X.systems.press] Cluster Computing ||

9.1 Perfekte Parallelisierung 269

int i;master_t m=malloc(sizeof(*m));if (m!=NULL) { / * genug S p e i c h e r vorhanden * /

10 m->num_working_workers=0;m->num_workers=num_workers;m->comm=comm;m->job_dt=job_dt;m->result_dt=result_dt;

15 m->working=malloc(sizeof(*m->working)*num_workers);if (m->working!=NULL) / * genug S p e i c h e r vorhanden * /

for (i=0; i<num_workers; ++i)m->working[i]=MW_worker_free;

else { / * n i c h t genug S p e i c h e r vorhanden * /20 free(m);

m=NULL;}

}return m;

25 }

void master_free(master_t m) {if (m!=NULL) {

free(m->working);30 free(m);

}}

int master_some_working(master_t m) {35 return (m->num_working_workers)>0;

}

int master_listen(master_t m, int *command) {MPI_Status status;

40 int flag;MPI_Iprobe(MPI_ANY_SOURCE, MW_listen_tag, m->comm, &flag, &status);if (flag) {

MPI_Recv(command, 1, MPI_INT, status.MPI_SOURCE, MW_listen_tag,m->comm, &status);

45 return status.MPI_SOURCE;}return 0;

}

50 void master_send_work(master_t m, int w_rank, void *data) {MPI_Send(data, 1, m->job_dt, w_rank, MW_send_job_data_tag, m->comm);if (m->working[w_rank-1]==MW_worker_free) {

m->working[w_rank-1]=MW_worker_working;++(m->num_working_workers);

55 }}

void master_get_result(master_t m, int w_rank, void *data) {MPI_Status status;

60 MPI_Recv(data, 1, m->result_dt, w_rank, MW_recv_result_data_tag,m->comm, &status);

}

void master_free_worker(master_t m, int w_rank) {65 if (m->working[w_rank-1]==MW_worker_working)

--(m->num_working_workers);

Page 275: [X.systems.press] Cluster Computing ||

270 9 Parallelisierungstechniken

m->working[w_rank-1]=MW_worker_free;}

70 void master_suspend_worker(master_t m, int w_rank) {MPI_Send(NULL, 0, m->job_dt, w_rank, MW_send_job_data_tag,

m->comm);if (m->working[w_rank-1]!=MW_worker_suspended)

--(m->num_workers);75 m->working[w_rank-1]=MW_worker_suspended;

}

void master_suspend_all_workers(master_t m) {int w_rank, command;

80 while (m->num_workers>0) {if (w_rank=master_listen(m, &command))

if (command==MW_ask_for_job)master_suspend_worker(m, w_rank);

else85 MPI_Abort(m->comm, EXIT_FAILURE);

usleep(1);}

}

90 worker_t worker_new(MPI_Comm comm,MPI_Datatype job_dt, MPI_Datatype result_dt) {

worker_t w=malloc(sizeof(*w));if (w!=NULL) { / * genug S p e i c h e r vorhanden * /

w->comm=comm;95 w->job_dt=job_dt;

w->result_dt=result_dt;}return w;

}100

void worker_free(worker_t w) {free(w);

}

105 int worker_get_work(worker_t w, void *data) {int command=MW_ask_for_job, count;MPI_Status status;MPI_Send(&command, 1, MPI_INT, 0, MW_listen_tag, w->comm);MPI_Recv(data, 1, w->job_dt, 0, MW_send_job_data_tag,

110 w->comm, &status);MPI_Get_count(&status, MPI_INT, &count);return count>0;

}

115 void worker_send_result(worker_t w, void *data) {int command=MW_return_result;MPI_Send(&command, 1, MPI_INT, 0, MW_listen_tag, w->comm);MPI_Send(data, 1, w->result_dt, 0, MW_recv_result_data_tag,

w->comm);120 }

void worker_done(worker_t w) {int command=MW_job_done;MPI_Send(&command, 1, MPI_INT, 0, MW_listen_tag, w->comm);

125 }

Page 276: [X.systems.press] Cluster Computing ||

9.1 Perfekte Parallelisierung 271

Schauen wir uns die Funktionen der Bibliothek in Listing 9.4 im Einzelnen an. Dievon einem Master-Prozess genutzten Funktionen sind:

master new. Diese Funktion alloziert Speicher zur Verwaltung eines Master-Pro-zesses und gibt einen Zeiger auf diesen Speicher oder bei Speichermangel einenNullzeiger zuruck. Als Argumente sind die Zahl der zu verwaltenden Worker(bzw. der großte Rang aller Worker), der Kommunikator der Master-Worker-Kommunikation und die beiden MPI-Datentypen, die den Daten fur einen Jobbzw. dessen Ergebnis entsprechen, anzugeben.

master free. Wurden alle Jobs abgearbeitet gibt der Master mit master freeden allozierten Speicher wieder frei.

master some working. Diese Funktion gibt einen Wert ungleich null zuruck,solange es mindestens einen Worker gibt, der noch arbeitet.

master listen. Mit dieser Funktion lauscht ein Master nach Anfragen von Wor-kern und gibt deren Rang oder, falls keine Anfragen vorliegen, null zuruck. Ander Adresse command wird die Art der Anfrage des Workers gespeichert.

master send work. Hiermit werden die Job-Daten data an den Worker mitdem Rang w rank gesendet und dieser als beschaftigt markiert.

master get result. Durch diese Funktion empfangt ein Master vom Workermit dem Rang w rank ein (Teil-)Ergebnis und speichert es bei data ab.

master free worker. Hiermit markiert ein Master den Worker mit dem Rangw rank als frei.

master suspend worker. Falls keine neuen Jobs mehr vorliegen aber ein Wor-ker mit dem Rang w rank nach einem neuen Job fragt, so kann ein Masterdiesem Worker mit dieser Funktion mitteilen, dass er sich beenden soll. Dazusendet sie dem Worker eine leere Nachricht (Lange null) mit Job-Daten.

master suspend all workers. Hiermit werden alle Worker, die noch nichtvorher mit master suspend worker zur Beendigung aufgefordert wurden,angehalten.

Ein Worker-Prozess kommt mit weniger Funktionen als der Master-Prozess aus. Diessind im Einzelnen:

worker new. Hiermit alloziert ein Worker Speicher zur Verwaltung seines Prozes-ses. Die Funktion gibt einen Zeiger auf diesen Speicher oder bei Speicherman-gel einen Nullzeiger zuruck. Als Argumente sind der Kommunikator der Mas-ter-Worker-Kommunikation und die beiden MPI-Datentypen, die den Daten fureinen Job bzw. dessen Ergebnis entsprechen, anzugeben. In einem Master-Wor-ker-Programm mussen master new und worker new von Master und Wor-ker mit den gleichen Argumenten aufgerufen werden, damit es korrekt arbeitenkann.

worker free. Durch worker free wird der mit worker new allozierte Spei-cher wieder freigegeben.

worker get work. Diese Funktion versucht, Daten fur neuen Job zu empfangen,und legt diese bei data ab. Konnten keine Daten empfangen werden, weil derMaster keine neuen Jobs mehr hat, so wird null zuruckgegeben, sonst ein Wertungleich null.

Page 277: [X.systems.press] Cluster Computing ||

272 9 Parallelisierungstechniken

worker send result. Diese Funktion sendet ein (Teil-)Ergebnis data an denMaster-Prozess zuruck.

worker done. Hiermit signalisiert ein Worker dem Master-Prozess, dass sein Jobvollstandig abgearbeitet wurde.

Damit bei der spateren Entwicklung verschiedener Master-Worker-Programme dieFunktionen aus Listing 9.4 nicht jedes Mal erneut ubersetzt werden mussen, wol-len wir diese in einer Bibliothek libmw.a ablegen. Unsere Master-Worker-Pro-gramme mussen so nur die Headerdatei master worker.h einbinden und beimUbersetzen mit der Option -lmw gegen die Bibliothek libmw.a gelinkt werden.Der Bau einer Bibliothek erfolgt in zwei Schritten. Zunachst ist aus der Quelldateimaster worker.c eine Objektdatei master worker.o zu erzeugen, danachwird mit dem Archivierungswerkzeug ar diese Objektdatei in das Archiv libmw.agepackt.

bauke@server:˜/src$ mpicc -c master_worker.cbauke@server:˜/src$ ar rs libmw.a master_worker.o

Wir wollen diesen Anschnitt nicht beenden, ohne die Master-Worker-Bibliothekauch in Aktion zu zeigen. In Listing 9.5 sehen wir eine Beispielanwendung, wie mansie sich kaum einfacher denken kann. Der Master-Prozess soll nacheinander an dieWorker-Prozesse eine Integerzahl zwischen eins und zehn senden. Dieser multipli-ziert die Integerzahl mit 3,14 und sendet das Ergebnis in Form einer Fließkommazahlan den Master zuruck.

Ab Zeile 22 wird zunachst die MPI-Umgebung initialisiert. Wurden weniger alszwei MPI-Prozesse gestartet, so wird das Programm durch MPI Abort abgebro-chen, denn wir brauchen mindestens einen Worker. Die Implementierung der Master-Worker-Bibliothek geht davon aus, dass die Rolle eines Masters immer von einemProzess mit dem Rang null ubernommen wird, wahrend Prozesse großeren Rangsimmer als Worker fungieren. In Zeile 28 wird entweder in den Master- oder Worker-Programmteil verzweigt.

Der Master muss sich zunachst mit der Funktion master new Speicher fur sei-ne Verwaltungsaufgaben allozieren. Die Argumente der Funktion master new sindwie folgt zu verstehen:

• Die Zahl der Worker ist gleich der Zahl der Prozesse des Kommunikators MPICOMM WORLD minus eins.

• Die Master-Worker-Kommunikation wird uber den Kommunikator MPI COMMWORLD abgewickelt.

• Der MPI-Datentyp fur die Eingabedaten eines Jobs ist vom Typ MPI INT, derdes Resultats vom Typ MPI DOUBLE.

Hat die Funktion master new einen Nullzeiger zuruckgegeben, weil nicht genugSpeicher vorhanden war, so wird das Programm in Zeile 32 mit MPI Abort abge-brochen.

Bevor irgendwelche Worker mit Arbeit versorgt werden, setzt der Master dieglobale Variable count auf null. Bei jeder Zuweisung eines Jobs an einen Worker

Page 278: [X.systems.press] Cluster Computing ||

9.1 Perfekte Parallelisierung 273

Listing 9.5. Das Master-Worker-Beispielprogramm master worker test.c.

#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include ” mpi . h ”

5 #include ” m a s t e r w o r k e r . h ”

int count;

int job_pending(void) { return count<10; }10

void get_job_data(int *data) { ++count; *data=count; }

void do_job(int *data, double *result) { *result=3.14*(*data); }

15 int main(int argc, char *argv[]) {int rank, size, w_rank, command, job_data;double result_data;master_t master;worker_t worker;

20/ * i n i t i a l s i e r e MPI * /MPI_Init(&argc, &argv);MPI_Comm_size(MPI_COMM_WORLD, &size);MPI_Comm_rank(MPI_COMM_WORLD, &rank);

25 if (size<2) / * b r a u c h e m i n d e s t e n s 2 P r o z e s s e * /MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);

if (rank==0) { / * Mas te r * // * a l l o z i e r e S p e i c h e r f u r Master−P r o z e s s e s mi t s i z e −1 Workern * /

30 master=master_new(size-1, MPI_COMM_WORLD, MPI_INT, MPI_DOUBLE);if (master==NULL)

MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);count=0;/ * b e a r b e i t e H a u p t s c h l e i f e s o l a n g e noch Jobs v o r l i e g e n ode r

35 Worker b e s c h a f t i g t s i n d und b e a n t w o r t e Anfragen d e r Worker * /while (job_pending() || master_some_working(master)) {

if (w_rank=master_listen(master, &command))switch (command) {

case MW_ask_for_job:40 if (job_pending()) {

get_job_data(&job_data);printf(”%d nach %d g e s e n d e t\n ”, job_data, w_rank);master_send_work(master, w_rank, &job_data);

} else {45 printf(” beende worker %d\n ”, w_rank);

master_suspend_worker(master, w_rank);}break;

case MW_return_result:50 master_get_result(master, w_rank, &result_data);

printf(”%g von %d empfangen\n ”, result_data, w_rank);break;

case MW_job_done:master_free_worker(master, w_rank);

55 break;}

usleep(1); / * s c h l a f e n l e g e n * /}

Page 279: [X.systems.press] Cluster Computing ||

274 9 Parallelisierungstechniken

master_suspend_all_workers(master);60 master_free(master);

} else { / * Worker * /worker=worker_new(MPI_COMM_WORLD, MPI_INT, MPI_DOUBLE);if (worker==NULL)

MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);65 while (worker_get_work(worker, &job_data)) {

do_job(&job_data, &result_data);worker_send_result(worker, &result_data);worker_done(worker);

}70 worker_free(worker);

}

MPI_Finalize(); / * MPI beenden * /return EXIT_SUCCESS;

75 }

wird diese in der Funktion get job data hochgezahlt, bis sie schließlich einenvon der Funktion job pending uberpruften Maximalwert erreicht hat. Die Haupt-arbeit leistet der Master in der Schleife zwischen den Zeilen 36 und 58, die so langedurchlaufen wird, wie noch Jobs vorliegen, die an noch keinen Worker vergebenwurden, oder noch Worker mit der Bearbeitung von Jobs beschaftigt sind. Falls dieFunktion master listen einen Rang großer null zuruckgibt, so beantwortet derMaster die in command gespeicherte Anfrage. Um die CPU nicht unnotig mit er-folglosen Aufrufen von master listen zu belasten, legt sich der Master in jedemSchleifendurchlauf fur einige Mikrosekunden schlafen. Sind alle Jobs abgearbeitet,so wird die Schleife verlassen und mit master suspend all workers halt derMaster alle Worker, die noch nicht vorher mit master suspend worker zur Be-endigung aufgefordert wurden, an. Zum Schluss gibt der Master mit master freeden allozierten Speicher wieder frei.

Der Code fur die Worker findet sich ab Zeile 62. Wie beim Master muss auchhier zunachst Speicher fur Verwaltungsdaten alloziert werden. Solange die Funkti-on worker get job einen Wert ungleich null zuruckgibt, findet der Worker inder Variablen job data das Datum fur einen neuen Job, der von der Funktiondo job bearbeitet wird. Das in result data gespeicherte Ergebnis wird mitworker send result an den Master zuruckgesendet und anschließend meldetder Worker mit worker done den Job als beendet. Hat der Master keine neuenJobs mehr anzubieten, so verlasst der Worker seine Arbeitsschleife zwischen denZeilen 65 bis 69, gibt mit worker free seinen Speicher wieder frei und beendetsich.

Beim Ubersetzen des Programms master worker test mussen wir es mit-lmw gegen unsere Master-Worker-Bibliothek linken. Danach kann das Programmz. B. mit vier Prozessen gestartet werden, wie in Terminal Session 9.1 gezeigt. Beach-ten Sie, dass die Reihenfolge Ausgabe des Programms durchaus auch etwas andersaussehen kann, je nachdem welche Worker am schnellsten zum Master durch drin-gen konnen. Falls Sie eine MPI-Implementation benutzen, die das Scheiben von MPI-Programmen auf die Standardausgabe nicht unterstutzt, so sollten Sie das Programm,so umschreiben, dass es seine Statusmeldungen in eine Datei schreibt.

Page 280: [X.systems.press] Cluster Computing ||

9.1 Perfekte Parallelisierung 275

Terminal Session 9.1. Master-Worker-Programm 9.5 in Aktion.bauke@server:˜/src$ mpicc -o master_worker_test \> master_worker_test.c -L . -lmwbauke@server:˜/src$ mpirun -np 4 master_worker_test1 nach 1 gesendet2 nach 2 gesendet3 nach 3 gesendet3.14 von 1 empfangen6.28 von 2 empfangen9.42 von 3 empfangen4 nach 1 gesendet5 nach 2 gesendet6 nach 3 gesendet12.56 von 1 empfangen15.7 von 2 empfangen18.84 von 3 empfangen7 nach 1 gesendet8 nach 2 gesendet9 nach 3 gesendet21.98 von 1 empfangen25.12 von 2 empfangen28.26 von 3 empfangen10 nach 1 gesendetbeende worker 2beende worker 331.4 von 1 empfangen

Auf der Basis von Listing 9.5 konnen Sie nun beginnen, eigene Master-Worker-Programme zu entwickeln. In den meisten Fallen mussen Sie nur die Funktionenjob pending, get job data und do job anpassen. Ale kleine Fingerubungschlagen wir Ihnen vor, ein Integrationsprogramm ahnlich dem in Listing 3.2 zuschreiben. Allerdings sollte es nun seine Arbeit dynamisch nach dem Master-Wor-ker-Schema aufteilen. Auch hier soll das Integrationsintervall in eine große Zahlvon Teilintervallen gegliedert werden, die jeweils ein Worker behandelt. Der Mas-ter verschickt dazu an den Worker eine Intervallnummer, empfangt vom Worker dasIntegral uber das entsprechende Teilintervall und summiert alle Teilergebnisse auf.Viel Spaß dabei!

9.1.5 Kombinatorische Probleme

In der Kombinatorik finden sich zahlreiche interessante Probleme, die sich oft leidernur mit großem Rechenaufwand losen lassen. Ein allgemeine und darum machti-ge Losungsmethode kombinatorischer Probleme ist die Ruckverfolgung (engl. back-tracking). Auch bei dieser Methode lasst sich das Ausgangsproblem leicht in vonein-ander unabhanige Teilprobleme zerlegen. In diesem Abschnitt werden wir darum amBeispiel des Graphfarbungsproblems zeigen, wie ein Backtracking-Algorithmus un-ter Verwendung eines Master-Worker-Schemas effizient parallelisiert werden kann.

Das Graphfarbungsproblem

Ein Graph G(V,E) besteht aus den zwei Mengen V (Vertex- oder Knotenmenge)und E (Kantenmenge). Dabei sind die Elemente der Kantenmenge zweielementige

Page 281: [X.systems.press] Cluster Computing ||

276 9 Parallelisierungstechniken

6

0

4

7 8

3

5

12

0

4

7 8

3

12

Abb. 9.3. Ein Graph mit neun Knoten V = {0,1,2,3,4,5,6,7,8} und der durch die Knoten{0,1,2,3,4,7,8} induzierte Teilgraph dieses Graphen.

Teilmengen der Vertexmenge V . Veranschaulichen lassen sich Graphen durch Zeich-nungen wie die in Abb. 9.3. Die Kreise sind hier nichts weiter als die Knoten und dieLinien die Kanten des Graphen, die jeweils zwei verschiedene Knoten miteinanderverbinden.

Sei V ′ eine Teilmenge von V und bezeichne E|V ′ die Teilmenge aller Kanten ausE, deren beide Knoten in V ′ liegen. Der Graph G′(V ′,E|V ′) wird von V ′ induzierterTeilgraph von G(V,E) genannt, siehe auch Abb. 9.3.

Das Graphfarbungsproblem besteht darin, die Knoten eines Graphen mit maxi-mal k Farben so zu farben, dass kein Paar von durch eine Kante verbundene Knotengleich gefarbt sind. Eine solche Farbung der Knoten nennen wir gultige Farbung. Ab-bildung 9.4 zeigt einen Graphen mit einer Farbung unter der Verwendung von k = 3Farben. Wir wollen ein Programm schreiben, das fur einen gegebenen Graphen alleFarbungen mit k = 3 oder weniger Farben findet.

Eine Graphen-Bibliothek

Bevor wir naher auf das Graphfarbungsproblem eingehen konnen, mussen wir unseinige Gedanken daruber machen, wie wir einen Graphen im Computer reprasentie-

Abb. 9.4. Eine Farbung eines Graphen unter der Verwendung von drei Farben.

Page 282: [X.systems.press] Cluster Computing ||

9.1 Perfekte Parallelisierung 277

Listing 9.6. Die Headerdatei graph.h der Graphen-Bibliothek.

#if !(defined GRAPH_H)

#define GRAPH_H

5 typedef struct {unsigned nodes;char *A;

} graph_str;typedef graph_str * graph_t;

10graph_t graph_new(unsigned nodes);graph_t graph_read(const char *fname);graph_t graph_rand(unsigned nodes, double p, double (*R)(void));void graph_free(graph_t G);

15 void graph_insert_edge(graph_t G, unsigned i, unsigned j);void graph_del_edge(graph_t G, unsigned i, unsigned j);int graph_has_edge(graph_t G, unsigned i, unsigned j);void graph_coloring(graph_t G, unsigned ncols, unsigned *cols,

unsigned depth, unsigned max_depth,20 void (*call)(unsigned *, unsigned));

#endif

ren. Eine Moglichkeit zur Speicherung eines Graphen sind Adjazenzmatrizen. DieAdjazenzmatrix eines Graphen mit n Knoten ist eine symmetrische n× n-Matrix A,die bei Ai+1, j+1 den Wert 1 hat, falls die Knoten i und j durch eine Kante verbundensind, sonst ist er gleich 0. Die n Knoten nummerieren wir von 0 bis n−1.

Um das Graphfarbungsproblem zu losen, werden wir die Graphen-Bibliothekverwenden, die aus der Headerdatei graph.h (Listing 9.6) und der Implementa-tion graph.c (Listing 9.7) besteht. Diese Bibliothek unterstutzt langst nicht alleFunktionen, die man sich von einer allgemeinen Graphen-Bibliothek wunscht, aberdoch alles, um das Graphfarbungsproblem zu losen. In der Headerdatei finden wirdie Definition der Struktur graph str und des Typs graph t, welche die Anzahlder Knoten und die Adjazenzmatrix eines Graphen speichern. Außerdem enthalt dieHeaderdatei graph.h die Prototypen aller Bibliotheksroutinen. Diese erfullen imEinzelnen folgende Aufgaben:

graph new. Die Funktion graph new alloziert Speicher fur einen Graphen mitnodes Knoten und gibt einen Zeiger auf eine Struktur graph str oder, fallsnicht genug Speicher vorhanden ist, einen Nullzeiger zuruck. Der Graph hatzunachst keine Kanten.

graph read. Hiermit kann ein Graph aus der Datei mit dem Namen fname ein-gelesen werden. Die Textdatei muss dazu eine Liste von Ganzzahlen enthalten.Die ersten beiden Zahlen geben Knoten- und Kantenzahl des Graphen an. Dar-auf folgen Paare von Zahlen, die jeweils die Endknoten einer Kante codieren.Die Knoten werden dafur bei null beginnend nummeriert. Tritt beim Einlesendes Graphen ein Fehler auf, so gibt die Funktion einen Nullzeiger zuruck, sonsteinen Zeiger auf eine gultige graph str-Struktur.

Page 283: [X.systems.press] Cluster Computing ||

278 9 Parallelisierungstechniken

Listing 9.7. Die Implementation graph.c der Graphen-Bibliothek.

#include <stdlib.h>#include <stdio.h>#include <string.h>#include ” graph . h ”

5graph_t graph_new(unsigned nodes) {

unsigned i, j;graph_t G;G=malloc(sizeof(*G));

10 if (G!=NULL) {G->nodes=nodes;G->A=malloc(sizeof(*G->A)*nodes*nodes);if (G->A!=NULL) {

for (i=0; i<G->nodes; ++i)15 for (j=0; j<G->nodes; ++j)

G->A[i*nodes+j]=0;} else {

free(G);G=NULL;

20 }}return G;

}

25 graph_t graph_read(const char *fname) {unsigned nodes, edges, i, j, k;graph_t G;G=NULL;FILE *fd;

30 fd=fopen(fname, ” r ”);if (fd!=NULL) {

if (fscanf(fd, ”%u%u ”, &nodes, &edges)==2) {G=graph_new(nodes);if (G!=NULL)

35 for (k=0; k<edges; ++k) {fscanf(fd, ”%u%u ”, &i, &j);if (i<G->nodes && j<G->nodes)

G->A[i*G->nodes+j]=G->A[j*G->nodes+i]=1;}

40 }fclose(fd);

}return G;

}45

graph_t graph_rand(unsigned nodes, double p, double (*R)(void)) {unsigned i, j;graph_t G;G=malloc(sizeof(*G));

50 if (G!=NULL) {G->nodes=nodes;G->A=malloc(sizeof(*G->A)*nodes*nodes);if (G->A!=NULL) {

memset(G->A, 0, G->nodes*G->nodes*sizeof(*(G->A)));55 for (i=0; i<G->nodes; ++i)

for (j=i+1; j<G->nodes; ++j)if (R()<p)

G->A[i*G->nodes+j]=G->A[j*G->nodes+i]=1;

Page 284: [X.systems.press] Cluster Computing ||

9.1 Perfekte Parallelisierung 279

} else {60 free(G);

G=NULL;}

}return G;

65 }

void graph_free(graph_t G) {free(G->A);free(G);

70 }

void graph_insert_edge(graph_t G, unsigned i, unsigned j) {G->A[i*G->nodes+j]=G->A[j*G->nodes+i]=1;

}75

void graph_del_edge(graph_t G, unsigned i, unsigned j) {G->A[i*G->nodes+j]=G->A[j*G->nodes+i]=0;

}

80 int graph_has_edge(graph_t G, unsigned i, unsigned j) {return G->A[i*G->nodes+j]>0;

}

static graph_t graph_coloring_G;85 static unsigned *graph_coloring_cols, graph_coloring_max_depth,

graph_coloring_ncols;static void (*graph_coloring_call)(unsigned *, unsigned);

static void graph_coloring_rec(unsigned depth) {90 unsigned i, j, coloring_ok;

for (i=0; i<graph_coloring_ncols; ++i) {graph_coloring_cols[depth]=i;coloring_ok=1;for (j=0; j<depth && coloring_ok; ++j)

95 if (graph_has_edge(graph_coloring_G, depth, j) &&graph_coloring_cols[depth]==graph_coloring_cols[j])

coloring_ok=0;if (coloring_ok)

if (depth+1<graph_coloring_max_depth)100 graph_coloring_rec(depth+1);

elsegraph_coloring_call(graph_coloring_cols, graph_coloring_G->nodes);

}}

105void graph_coloring(graph_t G, unsigned ncols, unsigned *cols,

unsigned depth, unsigned max_depth,void (*call)(unsigned *, unsigned)) {

graph_coloring_G=G;110 graph_coloring_ncols=ncols;

graph_coloring_cols=cols;graph_coloring_max_depth=max_depth;graph_coloring_call=call;graph_coloring_rec(depth);

115 }

Page 285: [X.systems.press] Cluster Computing ||

280 9 Parallelisierungstechniken

graph rand. Mit graph rand wird ein Zufallsgraph mit nodes Knoten er-zeugt. Jede Kante ist mit der Wahrscheinlichkeit p vorhanden. Diese Funktionbenutzt dafur den in R ubergebenen Zufallszahlengenerator, der in [0,1) gleich-verteilte Zufallszahlen erzeugt.

graph free. Diese Funktion gibt den von einem Graphen belegten Speicher wie-der frei.

graph insert edge. Die Funktion graph insert edge fugt eine Kante zwi-schen den Knoten i und j in einen Graphen ein.

graph del edge. Hiermit lasst sich aus einem Graphen die Kante zwischen denbeiden Knoten i und j wieder entfernen.

graph has edge. Diese Funktion pruft, ob zwischen den Knoten i und j eineKante vorhanden ist.

graph coloring. Mit dieser Funktion konnen alle k-Farbungen eines Graphengeneriert werden. Sie wird weiter unten genauer beschrieben.

Aus der Hearderdatei graph.h und der Implementation graph.c erzeugen wirganz ahnlich wie bei der in Abschnitt 9.1.4 vorgestellen Master-Worker-Bibliothekein Archiv libgraph.a.

bauke@server:˜/src$ icc -c graph.cbauke@server:˜/src$ ar rs libgraph.a graph.o

Backtracking

Mit Backtracking-Algorithmen konnen zahlreiche kombinatorische Probleme gelostwerden. Sie stellen eine Form der erschopfenden Suche in einem oft sehr großenaber endlichen Suchraum dar. Dabei werden auf systematische Weise alle moglichenKandidaten einer Losung inspiziert. Partiell erzeugte Kandidaten, die sich als inkon-sistent erweisen, werden dabei genutzt, um den Suchraum effektiv einzuschranken.

In leicht abgeanderter Form lasst sich ein Backtracking-Algorithmus nach [86]wie folgt beschreiben: Es sind alle Folgen (x0,x1, . . . ,xn−1) zu finden, die eine Eigen-schaft Pn(x0,x1, . . . ,xn−1) erfullen. Im Falle des Graphfarbungsproblems codiert eineFolge (x0,x1, . . . ,xn−1) mit xi ∈{0,1, . . . ,k−1} eine Farbung eines gegeben Graphenmit n Knoten unter der Verwendung von maximal k Farben und Pn(x0,x1, . . . ,xn−1)ist die Eigenschaft, dass diese Farbung gultig ist.

Um die Backtracking-Methode anwenden zu konnen, werden partielle Eigen-schaften Pl(x0,x1, . . . ,xl−1) eingefuhrt, fur die gilt, dass

Pl+1(x0,x1, . . . ,xl) auch Pl(x0,x1, . . . ,xl−1) fur alle 0 ≤ l < n

impliziert. Oder anders ausgedruckt, falls die Folge (x0,x1, . . . ,xl−1) die EigenschaftPl(x0,x1, . . . ,xl−1) nicht erfullt, so kann die erweiterte Folge (x0,x1, . . . ,xl−1,xl)auf keinen Fall Pl+1(x0,x1, . . . ,xl−1,xl) erfullen und durch Induktion folgt, dass(x0,x1, . . . ,xn−1) nicht die Zieleigenschaft Pn(x0,x1, . . . ,xn−1) erfullen kann. Auf dasGraphfarbungsproblem ubertragen bezeichnet Pl(x0,x1, . . . ,xl−1) die Eigenschaft,

Page 286: [X.systems.press] Cluster Computing ||

9.1 Perfekte Parallelisierung 281

Algorithmus 9.1. Allgemeine Form eines Backtracking-Algorithmus.

backtrack(l, (x0,x1, . . . ,xn−1))S := {xl |Pl+1(x0,x1, . . . ,xl−1,xl) wird erfullt}for q ∈ S do

xl := qif l < n−1 then

backtrack(l +1, (x0,x1, . . . ,xn−1))else

gebe (x0,x1, . . . ,xn−1) ausend if

end for

dass der durch die l Knoten {0,1, . . . , l−1} induzierte Teilgraph eine gultige Farbung(x0,x1, . . . ,xl−1,xl) besitzt.

Ein Backtracking-Algorithmus berechnet nun auf systematische Weise alle Lo-sungen (x0,x1, . . . ,xn−1), die Pn(x0,x1, . . . ,xn−1) erfullen, indem er alle partiellenLosungen (x0,x1, . . . ,xl−1), die Pl(x0,x1, . . . ,xl−1) genugen, erzeugt. Eine rekursiveFormulierung der generellen Form eines Backtracking-Algorithmus ist in Algorith-mus 9.1 wiedergegeben. Die Funktion backtrack wird mit l = 0 gestartet und ruft sichselbst solange mit l := l +1 auf, wie Pl+1(x0,x1, . . . ,xl−1,xl) erfullt ist. Backtracking-Algorithmen mussen nicht unbedingt rekursiv arbeiten. In [86] finden Sie auch einenicht rekursive Formulierung, die allerdings etwas weniger klar als die rekursive ist.

Die Funktion graph coloring rec in Listing 9.7 ist die direkte Anwendungvon Algorithmus 9.1 auf das Graphfarbungsproblem. Diese Funktion wird durch dieTreiberroutine graph coloring gestartet. Aufgabe dieser Treiberroutine ist eslediglich, einige globale Variablen zu setzen. Die Parameter der Funktion graphcoloring sind:

G. Der zu farbende Graph mit n Knoten.ncols. Die maximale Anzahl der zu verwendender Farben.cols. Ein Feld der Lange n, das die Farben der Knoten speichert.depth. Die Starttiefe der Rekursion, normalerweise null.max depth. Die maximale Tiefe der Rekursion, normalerweise gleich Zahl der

Knoten.call. Eine Funktion, die bei Erreichen der maximalen Rekursionstiefe mit dem

Feld der Farben und der Anzahl der Knoten als Parameter aufgerufen wird.

Sequentielle Losung des Graphfarbungsproblems

In Listing 9.8 finden Sie ein kleines Programm, das mit der graph coloring-Funktion Farbungen verschiedener Graphen berechnet. Haben Sie es mit

bauke@server:˜/src$ icc -o graph_coloring graph_coloring.c -L . -lgraph

ubersetzt, so konnen Sie damit einen Graphen, der entweder aus einer Datei eingele-sen wird, oder einen Zufallsgraphen farben. Das Programm ist dazu entweder mit

Page 287: [X.systems.press] Cluster Computing ||

282 9 Parallelisierungstechniken

Listing 9.8. Programm graph coloring.c zur sequentiellen Losung des Graphfarbungs-problems.

#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <time.h>

5 #include ” graph . h ”

unsigned long n_colorings=0;

double Rand(void) { return (double)rand()/(double)RAND_MAX; }10

void count_colorings(unsigned *cols, unsigned nodes) {unsigned i;for (i=0; i<nodes; ++i)

printf(”%d ”, cols[i]);15 printf(”\n ”);

++n_colorings;}

int main(int argc, char *argv[]) {20 graph_t G=NULL;

unsigned *cols, nodes=0, ncols=0;double p=0.0;int c;srand(time(NULL));

25 while ((c=getopt(argc, argv, ”G: p : n : k : ”))!=-1) {switch (c) {

case ’G’:G=graph_read(optarg);break;

30 case ’ p ’:sscanf(optarg, ”%l f ”, &p);break;

case ’ n ’:sscanf(optarg, ”%u ”, &nodes);

35 break;case ’ k ’:

sscanf(optarg, ”%u ”, &ncols);break;

}40 if (nodes>0 && p>0.0 && p<1.0 && G==NULL)

G=graph_rand(nodes, p, Rand);}if (G==NULL || ncols<3) {

fprintf(stderr, ” F a l s c h e P a r a m e t e r\n ”);45 return EXIT_FAILURE;

}if ((cols=malloc(sizeof(*cols)*G->nodes))==NULL) {

fprintf(stderr, ” S p e i c h e r v o l l \n ”);return EXIT_FAILURE;

50 }graph_coloring(G, ncols, cols, 0, G->nodes, count_colorings);printf(” Anzahl d e r ge fundenen C o l o r i e r u n g e n : %l d\n ”, n_colorings);free(cols);graph_free(G);

55 return EXIT_SUCCESS;}

Page 288: [X.systems.press] Cluster Computing ||

9.1 Perfekte Parallelisierung 283

0 1

23

Abb. 9.5. Ein Graph mit vier Knoten.

den Parametern -G graph -k farben oder mit -n knoten -p wkt -kfarben aufzurufen. Dabei steht graph fur eine Graphendatei, farben fur dieAnzahl der zu verwendenen Farben, knoten fur die Anzahl der Knoten in einemZufallsgraphen und wkt fur die Wahrscheinlichkeit, mit der jede Kante im Zufalls-graphen vorhanden ist.

Zur Funktionsweise des Programms. In den Zeilen 25 bis 42 werden mit Hilfe dergetopt-Funktion die Kommandozeilenparameter ausgewertet (siehe Anhang 15).Dabei liest das Programm entweder einen Graphen aus einer Datei ein oder erzeugtmit der Funktion Rand in Zeile 9 als Zufallszahlengenerator einen Zufallsgraphen.Damit das Programm nicht bei jedem Aufruf den gleichen Zufallsgraphen erzeugt,initialisieren wir in Zeile 24 den Startwert des Generators in Abhanigkeit von derSystemzeit. Sind die Kommandozeilenparameter inkonsistent, wird ab Zeile 43 eineFehlermeldung ausgegeben und das Programm beendet. In Zeile 51 wird endlich diegraph coloring-Funktion aufgerufen. Bei jeder gefundenen gultigen Farbungverzweigt diese in die Funktion count colorings, die alle Farbungen ausgibtund die Anzahl der gultigen Farbung in der globalen Variablen n colorings zahlt.

Um ein besseres Verstandnis fur die Backtracking-Methode zu bekommen, schau-en wir uns den Ablauf des Graphfarbungsalgorithmus am Beispiel des Graphenaus Abb. 9.5 und drei Farben einmal im Detail an. Der Backtracking-Algorithmusdurchlauft in sog. Tiefensuche den in Abb. 9.6 gezeigten Suchbaum. Der Suchbaumlasst sich in verschiedene Entscheidungsebenen unterteilen, in denen jeweils die Far-be eines festen Knotes gesetzt wird. Die Anzahl dieser Entscheidungsebenen isthochstens gleich der Zahl der Knoten des zu farbenden Graphen. Besitzt der Graphkeine gultige Farbung, sind es weniger. Zwischen den Entscheidungsebenen befindensich Knoten, an denen sich der Suchbaum jeweils verzweigt. Jeder dieser Knoten ent-

0

1

2

21

2

1 0 0

1

1 2

2 0 2

10 1 2 0 1 1 0 2

1011202020221

0

0

0

1

2

3

x1

0

x2

x3

x

=

=

=

=

=

=

=

=

=

4l

l

l

l

l

Abb. 9.6. Der Suchbaum fur die Farbung des Graphen aus Abb. 9.5 mit maximal drei Farben.

Page 289: [X.systems.press] Cluster Computing ||

284 9 Parallelisierungstechniken

Terminal Session 9.2. Alle Farbungen Graphen aus Abb. 9.5 mit maximal drei Farben.bauke@server:˜/src$ cat square.gr4 40 11 22 33 0bauke@server:˜/src$ ./graph_coloring -G square.gr -k 30 1 0 10 1 0 20 1 2 10 2 0 10 2 0 20 2 1 21 0 1 01 0 1 21 0 2 01 2 0 21 2 1 01 2 1 22 0 1 02 0 2 02 0 2 12 1 0 12 1 2 02 1 2 1Anzahl der gefundenen Colorierung: 18

spricht einem Aufruf der graph coloring-Funktion. Die Zahl dieser Knoten istein Maß fur den Rechenaufwand. Die Zahl der Verzweigungen an einem Knoten desSuchbaumes ist gleich der Anzahl der Werte xl (0 ≤ l < 4), fur die der von den erstenl +1 Knoten induzierte Teilgraph noch mit den aktuellen Werten (x0,x1, . . . ,xl−1,xl)gultig gefarbt wird, die also der Eigenschaft Pl+1(x0,x1, . . . ,xl−1,xl) genugen. DieKnoten der Ebene mit l = 4 codieren jeweils eine gultige Farbung des gesamtenGraphen. Die Farben dieser Farbung erhalt man, in dem man von diesem Knotenaufwarts zum Knoten bei l = 0 lauft. In Terminal Session 9.2 finden Sie die Ausga-be des Programms graph coloring, wenn es mit dem Graphen aus Abb. 9.5 alsEingabe gestartet wird.

Parallele Losung des Graphfarbungsproblems

Die sequentielle Losung des Graphfarbungsproblems war nur eine Vorubung aufdem Weg zu unserem eigentlichen Ziel, der parallelen Losung des Graphfarbungs-problems. Wie konnen wir den im vorherigen Abschnitt gezeigten sequentiellen Al-gorithmus parallelisieren?

Schauen wir uns noch einmal den Suchbaum in Abb. 9.6 an. Der Backtracking-Algorithmus setzt zunachst die Farbe des ersten Knotens auf x0 = 0 und verzweigtvom Knoten bei l = 0 in den linken Teil-Suchbaum. Wurde dieser vollstandig ab-gearbeitet, wird x0 = 1 gesetz und der mittlere Teil-Suchbaum wird untersucht,bis schließlich x0 = 2 gesetzt werden kann und der rechte Teil-Suchbaum an derReihe ist. Dass der Backtracking-Algorithmus zuerst den linken, dann den mittle-ren und dann erst den rechten Teil-Suchbaum untersucht, ist naturlich vollkommen

Page 290: [X.systems.press] Cluster Computing ||

9.1 Perfekte Parallelisierung 285

1

0

2

3

=

=

=

=

=

=

=

=

=

4

0

1

2

3

x

x

x

x 0

1

2

21

2

1 0 0

1

1 2

2 0 2

10 1 2 0 1 1 0 2

1011202020221

0

0

Job 0 Job 1 Job 2 Job 3 Job 4 Job 5

Worker

Master

l

l

l

l

l

Abb. 9.7. Der Suchbaum fur die Farbung des Graphen aus Abb. 9.5 mit maximal drei Farbenbei paralleler Bearbeitung nach dem Master-Worker-Schema.

willkurlich. Jede andere Reihenfolge ware genauso gut moglich. Ja, es spricht auchnichts dagegen, die drei Teil-Suchbaume gleichzeitig zu untersuchen.

Diese Art der Parallelisierung beschafigt bei der Verwendung von drei Farben ma-ximal drei Prozessoren und ergibt eine Beschleunigung um einen Faktor drei. Wollenwir mehr als bloß drei Prozessoren beschaftigen und eine noch großere Beschleuni-gung erreichen, so konnen wir unser Parallisierungsverfahren rekursiv auch auf Teil-Suchbaume anwenden. Auf diese Art erhalten wir immer mehr unabhangige Teilpro-bleme, die parallel gelost werden konnen. Abbildung 9.7 verdeutlicht noch einmaldie Parallelisierungsidee am Beispiel des Graphen aus Abb. 9.5. Hier wird der Such-baum bei l = 2 in sechs unabhanige Teilprobleme aufgebrochen.

Am gunstigsten werden diese unabhangigen Teilprobleme in einem Master-Wor-ker-Schema bearbeitet. Die Zahl der Teilprobleme sollte dabei so gewahlt werden,dass sie großer als die Zahl der Worker ist. Andererseits muss jedes Teilproblem abernoch so groß sein, dass Master und Worker nicht zu haufig kommunizieren. Auchhier kommt es also auf den richtigen Grad der Granularitat an, siehe Abschnitt 1.6.

In Listing 9.9 ist ein MPI-Programm abgedruckt, das das Graphfarbungsproblemmit der im Abschnitt 9.1.4 vorgestellten Master-Worker-Bibliothek lost. In den Zei-len 66 bis 70 wird zunachst die MPI-Umgebung initialisiert. Der Prozess mit demRang null, der Master-Prozess, liest danach in den Zeilen 73 bis 95 die Kommando-zeilenparameter ein. Die Kommandozeilenparameter haben die gleiche Bedeutungwie schon im sequentiellen Programm 9.8. Lediglich die Option -d tiefe ist hin-zugekommen. Sie gibt an, bei welcher Tiefe l im Suchbaum dieser in unabhanigeTeilprobleme zerlegt wird. Da die Kommandozeilenparameter nur vom Master-Pro-zess ausgewertet werden, werden in den Zeilen 97 bis 103 der eingelesene Graphund andere Parameter mittels MPI Bcast-Funktion allen Prozessen mitgeteilt.

Sowohl die Ein- als auch die Ausgabedaten der verschiedenen Teilprobleme, diepartielle bzw. gultige Farbungen sind, werden durch Felder vorzeichenloser Ganzzah-len dargestellt. In den Zeilen 106 und 107 wird darum ein MPI-Datentyp angelegt,der einem solchen Feld entspricht, dessen Lange gleich der Anzahl der Knoten des

Page 291: [X.systems.press] Cluster Computing ||

286 9 Parallelisierungstechniken

Listing 9.9. Programm graph coloring mpi.c zur parallelen Losung des Graphfar-bungsproblems.

#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <time.h>

5 #include ” graph . h ”#include ” m a s t e r w o r k e r . h ”#include ” mpi . h ”

unsigned long n_colorings=0;10 master_t master;

worker_t worker;MPI_Datatype col_array;

double Rand(void) { return (double)rand()/(double)RAND_MAX; }15

void count_colorings(unsigned *cols, unsigned nodes) {unsigned i;for (i=0; i<nodes; ++i)

printf(”%d ”, cols[i]);20 printf(”\n ”);

++n_colorings;}

void error(int rank, const char *message) {25 fprintf(stderr, ” Rang %i : %s\n ”, rank, message);

MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);}

void send_result(unsigned *cols, unsigned nodes) {30 worker_send_result(worker, cols);

}

void master_loop(unsigned *cols, unsigned nodes) {int w_rank, command;

35 unsigned *cols2;while (1) {

if (w_rank=master_listen(master, &command))switch (command) {

case MW_ask_for_job:40 if (cols!=NULL)

master_send_work(master, w_rank, cols);else

master_suspend_worker(master, w_rank);return;

45 case MW_return_result:if ((cols2=malloc(sizeof(*cols2)*nodes))==NULL)

error(0, ” S p e i c h e r v o l l ”);master_get_result(master, w_rank, cols2);printf(” Rang %i : ”, w_rank);

50 count_colorings(cols2, nodes);free(cols2);break;

case MW_job_done:master_free_worker(master, w_rank);

55 }usleep(1);

}}

Page 292: [X.systems.press] Cluster Computing ||

9.1 Perfekte Parallelisierung 287

60 int main(int argc, char *argv[]) {graph_t G=NULL;unsigned *cols, depth=0, i, nodes=0, ncols=0;double p=0.0;char c;

65 int rank, size, w_rank, command;MPI_Init(&argc, &argv);MPI_Comm_size(MPI_COMM_WORLD, &size);MPI_Comm_rank(MPI_COMM_WORLD, &rank);if (size<2) / * b r a u c h e m i n d e s t e n s 2 P r o z e s s e * /

70 MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);if (rank==0) { / * Mas te r * /

srand(time(NULL));while ((c=getopt(argc, argv, ”G: p : n : k : d : ”))!=-1) {

switch (c) {75 case ’G’:

G=graph_read(optarg);nodes=G->nodes;break;

case ’ p ’:80 sscanf(optarg, ”%l f ”, &p);

break;case ’ n ’:

sscanf(optarg, ”%u ”, &nodes);break;

85 case ’ k ’:sscanf(optarg, ”%u ”, &ncols);break;

case ’ d ’:sscanf(optarg, ”%u ”, &depth);

90 }if (nodes>0 && p>0.0 && p<1.0 && G==NULL)

G=graph_rand(nodes, p, Rand);}if (G==NULL || ncols<3 || depth==0 || depth>=G->nodes)

95 error(rank, ” F a l s c h e P a r a m e t e r ode r S p e i c h e r v o l l ”);}MPI_Bcast(&nodes, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD);if (rank!=0) / * Worker * /

if ((G=graph_new(nodes))==NULL)100 error(rank, ” S p e i c h e r v o l l ”);

MPI_Bcast(G->A, G->nodes*G->nodes, MPI_CHAR, 0, MPI_COMM_WORLD);MPI_Bcast(&ncols, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD);MPI_Bcast(&depth, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD);if ((cols=malloc(sizeof(*cols)*G->nodes))==NULL)

105 error(rank, ” S p e i c h e r v o l l ”);MPI_Type_contiguous(G->nodes, MPI_UNSIGNED, &col_array);MPI_Type_commit(&col_array);if (rank==0) { / * Mas te r * /

master=master_new(size-1, MPI_COMM_WORLD, col_array, col_array);110 if (master==NULL)

error(rank, ” S p e i c h e r v o l l ”);graph_coloring(G, ncols, cols, 0, depth, master_loop);while (master_some_working(master)) {

master_loop(NULL, G->nodes);115 }

printf(” Anzahl d e r ge fundenen C o l o r i e r u n g e n : %l d\n ”, n_colorings);master_suspend_all_workers(master);

Page 293: [X.systems.press] Cluster Computing ||

288 9 Parallelisierungstechniken

master_free(master);} else { / * Worker * /

120 worker=worker_new(MPI_COMM_WORLD, col_array, col_array);if (worker==NULL)

error(rank, ” S p e i c h e r v o l l ”);while (worker_get_work(worker, cols)) {

graph_coloring(G, ncols, cols, depth, G->nodes, send_result);125 worker_done(worker);

}worker_free(worker);

}free(cols);

130 graph_free(G);MPI_Finalize();return EXIT_SUCCESS;

}

zu farbenden Graphen ist. Dieser MPI-Datentyp wird spater als Parameter in denFunktionen master new und wroker new verwendet.

In Zeile 108 verzweigt das Programm in einen Master- bzw. Worker-Teil. DerMaster arbeitet mit der Funktion graph coloring den Suchbaum bis zu der aufder Kommandozeile angegebenen Tiefe ab. Dort angekommen wird vom Master je-desmal die Funktion master loop aufgerufen, die so lange Anfragen der Workerbearbeitet, bis einer der Worker einen neuen Job abgefragt hat. Wenn im Master-Pro-zess die graph coloring-Funktion abgearbeitet wurde, bedeutet dies, dass samt-liche Jobs an die Worker ubergeben wurden. Deren Ergebnisse wurden zum großtenTeil schon wahrend der rekursiven Abarbeitung der graph coloring-Funktiondurch die Funktion master loop eingesammtelt, jedoch nicht alle. Eventuell nochausstehende Ergebnisse werden darum in der Scheife in den Zeilen 113 bis 115 eben-falls duch die Funktion master loop eingesammelt, bis schließlich alle Workerihren Job abgearbeitet haben. Nun konnen mit master suspend all workersalle Worker beendet werden. Beachten Sie, dass die Routine graph coloring dieFunktion master loop mit einem gultigen Zeiger auf ein Feld mit Farben aufruft,wahrend in der Scheife in den Zeilen 113 bis 115 der Funktion master loop einNullzeiger ubergeben wird. Auf diese Weise kann master loop unterscheiden, obeine Anforderung eines neuen Jobs mit einem solchen Job oder einer Anweisung zurBeendigung beantwortet wird, siehe Zeilen 39 bis 44.

Der Programmteil des Worker-Prozesses ab Zeile 120 ist wie schon in Listing 9.5recht einfach gehalten. So lange der Master Jobs zu verteilen hat, werden diese vonder Funktion graph coloring abgearbeitet. Danach wird das Programm beendet.Beachten Sie, dass in Zeile 124 die Funktion graph coloringmit einer Starttiefedepth aufgerufen wird. Das ist gerade die Tiefe, bei der der Master-Prozess dieRekursion abgebrochen hat.

Kompiliert und gestartet wird das Programm wie in Terminal Session 9.3 gezeigt.Hier haben wir wieder den Graphen aus Abb. 9.5 benutzt und den Paramter -d sogewahlt, dass die Aufteilung des Graphfarbungsproblems in der in Abb. 9.7 gezeig-ten Weise geschieht.

Zum Schluss noch eine kleine Anregung: Wie eingangs beschrieben kann mandurch Backtracking nicht nur das Graphfarbungsproblem losen, sondern auch viele

Page 294: [X.systems.press] Cluster Computing ||

9.2 Geometrische Parallelisierung 289

Terminal Session 9.3. Das Programm graph coloring mpi berechnet alle zwolf Artenden Graphen aus Abb. 9.5 mit drei Farben zu farben.bauke@server:˜/src$ mpicc -o graph_coloring_mpi graph_coloring_mpi.c \> -L . -lgraph -lmwbauke@server:˜/src$ mpirun -np 4 graph_coloring_mpi -G square.gr -k 3 -d 2Rang 1: 0 1 0 1Rang 2: 0 2 0 1Rang 3: 1 0 1 0Rang 1: 0 1 0 2Rang 2: 0 2 0 2Rang 3: 1 0 1 2Rang 1: 0 1 2 1Rang 2: 0 2 1 2Rang 3: 1 0 2 0Rang 1: 1 2 0 2Rang 2: 2 0 1 0Rang 3: 2 1 0 1Rang 1: 1 2 1 0Rang 2: 2 0 2 0Rang 3: 2 1 2 0Rang 1: 1 2 1 2Rang 2: 2 0 2 1Rang 3: 2 1 2 1Anzahl der gefundenen Colorierungen: 18

andere kombinatorische Probleme. In der Computer-Zeitschrift c’t erschien vor ei-niger Zeit ein Artikel [22], in dem beschrieben wurde, wie durch Backtracking eindreidimensionales Puzzle gelost werden kann, und schrieb ein Wettbewerb aus, indem es ein bestimmtes Puzzle moglichst schnell zu losen galt. Konnen Sie durchparalleles Backtracking das Puzzle noch schneller losen?

9.2 Geometrische Parallelisierung

9.2.1 Probleme auf Gittern

Einige wichtige technisch-wissenschaftliche Probleme lassen sich auf diskreten Git-tern formulieren. Dazu gehoren z. B.

• partielle Differentialgleichungen,• zellulare Automaten,• Probleme der linearen Algebra,• die Modellierung von Festkorpern und• die Modellierung von magnetischen Substanzen durch Spinsysteme.

All diesen Problemen ist gemein, dass die Grundelemente der Simulation nur mitihren benachbarten Elementen interagieren. So wechselt eine Zelle eines zellularenAutomaten in jedem Zeitschritt ihren Zustand in Abhangigkeit von ihren nachstenNachbarn. Weiter entfernte Zellen uben keinen Einfluss auf die Zelle aus. Bei denanderen genannten Beispielen verhalt es sich ahnlich. Berechnet man, wie sich dieauf einem Gitter gegebenen Werte einer Funktion unter dem Einfluss einer partiel-len Differentialgleichung zeitlich entwickeln, so ergeben sich die neuen Funktions-werte aus dem alten und den benachbarten Funktionswerten. Bei der Simulation von

Page 295: [X.systems.press] Cluster Computing ||

290 9 Parallelisierungstechniken

Festkorpern werden regelmaßig angeordnete Atome betrachtet, die mit ihren Nachba-ratomen interagieren. Wechselwirkungen zwischen weit entfernten Atomen konnenin der Regel vernachlassigt werden.

9.2.2 Gebietszerlegung

Modelle mit lokalen Wechselwirkungen lassen sich effizient durch Gebietszerlegung,auch domain decomposition genannt, parallelisieren. Ahnlich wie im Beispiel zuroptischen Beugung aus Abschnitt 9.1.2 wird hier das Grundgebiet in kleinere Teil-gebiete gegliedert und jeder Prozess bearbeitet je ein Teilgebiet. Anders als beimBeispiel zur optischen Beugung sind diese Teilgebiete nun nicht mehr vollkommenunabhangig voneinander. Die Randpunkte eines Teilgebietes interagieren mit denRandpunkten der benachbarten Teilgebiete.

Darum muss ein Prozess bei der Anwendung der Gebietszerlegung auf Model-le mit lokalen Wechselwirkungen neben seinen lokalen Daten noch eine Kopie derRanddaten seiner Nachbarprozesse verwalten. Solche Randdaten werden manchmalauch Geisterpunkte oder ghost points genannt. Da sich diese Randdaten im Laufeeiner Simulation andern, mussen die Prozesse regelmaßig mit ihren Nachbarn kom-munizieren und ihre Geisterpunkte auf den neuesten Stand bringen.

Abbildung 9.8 illustriert die Parallelisierungsidee am Beispiel eines zweidimen-sionalen rechteckigen Gebietes. Dieses wird hier in ein 4× 3-Gitter aufgeteilt undjeder Prozess besitzt eine Kopie der Randdaten seines oberen, unteren, linken undrechten Nachbarn. Je nach Art der Wechselwirkungen kann es notwendig sein, dassjeder Prozess auch noch Randdaten von diagonal benachbarten Prozessen vorhalt.Eine Sonderstellung nehmen die Prozesse am Rand des Grundgebietes ein, dennsie haben nicht in allen Richtungen Nachbarn. Dann mussen sie auch keine ent-sprechenden Randdaten vorhalten. Bei manchen Aufgabenstellungen (z. B. partiel-le Differentialgleichungen) sind die Randwerte des Grundgebietes fest vorgegeben.

0,0P 0,1P 0,2P 0,3P

1,3P1,2P

2,2P 2,3P2,1P2,0P

P1,0 1,1P

0,2P

1,3P

2,2P1,1P

1,2P

Geisterpunkte von

Geisterpunkte von

Geisterpunkte von

Geisterpunkte von

lokale Daten

Abb. 9.8. Bei einer Parallelisierung durch Gebietszerlegung muss jeder Prozess neben seinelokalen Daten noch eine Kopie der Randdaten seiner Nachbarn speichern.

Page 296: [X.systems.press] Cluster Computing ||

9.2 Geometrische Parallelisierung 291

Hier konnen diese Randwerte effektiv die Rolle der Geisterpunkte ubernehmen, sie-he Abschnitt 9.2.3. In anderen Modellen kann die Sonderstellung der Randprozessevermieden werden, indem zyklische Randbedingungen eingefuhrt werden, siehe Ab-schnitt 9.2.5. Prozesse am linken Rand tauschen dann ihre Randdaten mit denen amrechten Rand aus, und die am oberen Rand mit denen am unteren.

Naturlich lasst sich die beschriebene Gebietsaufteilung auf hohere Dimensionenverallgemeinern, wobei der dreidimensionale Fall wohl am wichtigsten sein durf-te. Auch andere Verallgemeinerungen sind moglich. So muss die Art der Gebiets-aufteilung nicht statisch sein. Besonders fur eine gleichmaßige Lastverteilung erfor-dern manche Probleme eine adaptive Gebietsaufteilung. Außerdem mussen wederGrundgebiet noch Teilgebiete rechteckig sein, auch andere Gebietsaufteilungen sindmoglich. Diese sind aber deutlich schwieriger zu implementieren, weshalb wir unsim Weiteren auf rechteckige Gebietsaufteilungen beschranken.

9.2.3 Schwingende Saite

Aber wie implementiert man nun die Gebietszerlegung konkret mit MPI und wiewickelt man den Austausch der Randdaten am besten ab? Erinnern wir uns nocheinmal an die schwingende Saite aus Abschnitt 7.3.4. Dieses einfache eindimensio-nale Problem eignet sich gut, die grundsatzlichen Ideen der Implementierung einerParallelisierung via Gebietszerlegung zu demonstrieren.

Fur nicht zu starke Auslenkungen u(x, t) lasst sich eine schwingende Saite derLange L durch die eindimensionale Wellengleichung

∂ 2u(x, t)∂ t2 = c2 ∂ 2u(x, t)

∂x2 (9.5)

beschreiben. Da eine Saite an den Enden eingespannt ist, soll fur alle Zeiten u(0, t) =u(L, t) = 0 gelten. Bei einer numerischen Simulation der Saitenschwingung konnenwir die Funktion u(x, t) zu jedem Zeitpunkt nur an N + 1 diskreten aquidistantenPunkten ν(i, j) approximieren. Wie in Abschnitt 7.3.4 gezeigt, ergeben sich fur i =1,2, . . . ,N −1 diese Werte aus der Iterationsgleichung

ν(i, j +1) = ε [ν(i+1, j)+ν(i−1, j)]+2(

1− c2

c′2

)ν(i, j)−ν(i, j−1) . (9.6)

Die Randpunkte sind fest.

ν(0, j +1) = ν(N, j +1) = 0 (9.7)

Wobei die Große ε mit

ε =c2

(L/(N ·∆ t))2 (9.8)

durch die raumliche und zeitliche Auflosung sowie die Wellengeschwindigkeit c ge-geben ist.

Page 297: [X.systems.press] Cluster Computing ||

292 9 Parallelisierungstechniken

Listing 9.10. Implementation der Rekursionsgleichung (9.6).

void string(double *u, double *u_old, double *u_new, int N, double eps) {int i;u_new[0]=u[0];for (i=1; i<N; ++i)

5 u_new[i]=eps*(u[i-1]+u[i+1])+2.0*(1.0-eps)*u[i]-u_old[i];u_new[N]=u[N];

}

In der spateren parallelen Implementation der Losung der partiellen Differential-gleichung (9.5) werden wir je einen Schritt der Iterationsgleichung (9.6) durch eineFunktion string berechnen (Listing 9.10). Sie berucksichtigt dabei feste Randbe-dingungen. Dazu mussen ihr als Argumente die Liste der aktuellen Funktionswerteν(i, j) (u), die Liste der vorletzten Funktionswerte ν(i, j−1) (u old), eine Liste furdie neuen Funktionswerte ν(i, j + 1) (u new), Zahl der Funktionswerte minus einsN (N) und der Parameter ε (eps) ubergeben werden.

In einer Dimension ist eine Gebietszerlegung konzeptionell am einfachsten. Umaus ν(i, j − 1) und ν(i, j) nach der Iterationsgleichung (9.6) die neuen Funktions-werte ν(i, j + 1) parallel zu berechnen, werden die N − 1 variablen Datenpunkteν(i, j) bzw. ν(i, j−1) (i = 1,2, . . . ,N −1) in etwa gleichgroße zusammenhangendeBlocke von Datenpunkten zerlegt und der Reihe nach an alle p Prozesse verteilt, sodass der außerste linke Block zu Prozess 0 und der außerste rechte zu Prozess p−1gehort, siehe Abb. 9.9. Entsprechend dieser Aufteilung ist jeder Prozess auch fur dieBerechnung eines zusammenhangenden Blocks von neuen Datenpunkten ν(i, j +1)zustandig. Da jeder Prozess zur Berechnung seines neuen außersten linken (rech-ten) Datenpunktes den außersten rechten (linken) Datenpunkt seines linken (rech-ten) Nachbarprozesses kennen muss, verwaltet er noch zusatzlich zwei Geisterpunk-

variabler Datenpunkt

fester Rand− bzw. Geisterdatenpunkt

0l,0 = 0N N N Nl,0 0l,2 l,2= 8 = 15 = 9

= 9= 7N N0l,1 l,1

0 N = 24

Prozess 0 Prozess 2

Prozess 1

Abb. 9.9. Gebietszerlegung mit drei Prozessoren und 25 diskreten Funktionswerten bei einerschwingenden Saite, unten globale Sicht auf Daten, oben lokale Daten mit Geisterpunkten.Die Geisterpunkte mussen nach jedem Iterationsschritt durch Kommunikation mit dem Nach-barprozess auf den neuesten Stand gebracht werden.

Page 298: [X.systems.press] Cluster Computing ||

9.2 Geometrische Parallelisierung 293

te. Die Prozesse 0 und p−1 haben keinen linken bzw. rechten Nachbar. Hier wirkendie Randbedingung ν(0, j) = 0 bzw. ν(N, j) = 0 wie Geisterpunkte.

Im Endeffekt kennt nach der Aufteilung der Daten ν(i, j − 1) und ν(i, j) (i =0,1, . . . ,N und j fest) der Prozess mit der Nummer P (P = 0,1, . . . , p−1) die Daten

ν(N0l,P, j−1) bis einschließlich ν(N0l,P +Nl,P, j−1)

undν(N0l,P, j) bis einschließlich ν(N0l,P +Nl,P, j)

und berechnet die neuen Werte

ν(N0l,P +1, j +1) bis einschließlich ν(N0l,P +Nl,P −1, j +1) .

Wobei die Variable N0l,P die Nummer des ersten von Prozess P verwalteten Daten-punktes ist und Nl,P die Zahl der von ihm gespeicherten Datenpunkte minus einsenthalt. Der Index l soll hier nur andeuten, dass die Variablen die lokale Aufteilungder Daten beschreiben. Bei der Implementierung der Simulation der schwingendenSaite werden wir diesen Variablen wieder begegnen. Sie sind u. a. wichtig, wenn amEnde die verteilten Datenblocke wieder zusammengesetzt werden sollen.

Nachdem alle Prozesse die neuen Funktionswerte ν(N0l,P + 1, j + 1) bis ein-schließlich ν(N0l,P +Nl,P−1, j +1) berechnet haben, fehlen ihnen noch die Randda-ten ν(N0l,P, j +1) und ν(N0l,P +Nl,P, j +1). Diese erfahren sie durch Kommunikati-on mit ihren Nachbarn

ν(N0l,P, j +1) = ν(N0l,P−1 +Nl,P−1 −1, j +1)

ν(N0l,P +Nl,P, j +1) = ν(N0l,P+1 +1, j +1)(9.9)

bzw. fur die Prozesse 0 bzw. p−1 gilt wegen der festen Randbedingungen

ν(N0l,0, j +1) = ν(N0l,0, j) bzw.ν(N0l,p−1 +Nl,p−1, j +1) = ν(N0l,p−1 +Nl,p−1, j) .

(9.10)

In Listing 9.11 sehen Sie, wie man die Parallelisierung der Simulation einerschwingenden Saite via Gebietszerlegung in ein MPI-Programm umsetzen kann.Nach der ublichen Initialisierung des MPI-Systems ab Zeile 29 berechnet das Pro-gramm zunachst ab Zeile 33 die Startpositionen N0l,i der lokalen Daten sowie derenAnzahl Nl,i. Das kennen Sie im Prinzip schon aus dem Beispiel mit den Beugungsbil-dern Listing 9.1 bzw. den Formeln (9.2) und (9.3). Nur mussen wir hier berucksich-tigen, dass sich die Datenblocke uberlappen. Fur die Iteration der Gleichung (9.6)werden dann noch die Anfangswerte ν(i,0) und ν(i,1) benotigt, welche ab Zeile 40berechnet werden. Wir haben hier als Anfangsbedingung eine Auslenkung in Formeiner Glockenkurve gewahlt, siehe Zeile 19.

Die eigentliche Losung der Schwingungsgleichung geschieht in der Schleife zwi-schen den Zeilen 49 bis 72. In jedem Zeitschritt berechnet zunachst jeder Prozessseine neuen Datenpunkte, siehe Zeile 51. Danach werden die Geisterpunkte durchKommunikation mit dem linken und rechten Nachbarn auf den neuesten Stand ge-bracht. Dabei werden zuerst Daten an den rechten Nachbarn und dann an den jeweils

Page 299: [X.systems.press] Cluster Computing ||

294 9 Parallelisierungstechniken

Listing 9.11. Das Programm string0 mpi.c lost die Differentialgleichung einer schwin-genden Saite.

#include <stdlib.h>#include <stdio.h>#include <math.h>#include ” mpi . h ”

5const int N=1000;const double L=1, c=1, dt=0.001, t_end=2.4;enum { left_copy, right_copy };

10 void string(double *u, double *u_old, double *u_new, int N, double eps);

void * secure_malloc(size_t size) {void * p=malloc(size);if (p==NULL)

15 MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);return p;

}

double u_0(double x) { return exp(-200.0*(x-0.5*L)*(x-0.5*L)); }20

double u_0_dt(double x) { return 0.0; }

int main(int argc, char *argv[]) {int C_rank, C_size, *N_l, *N0_l, i;

25 double dx=L/N, eps=dt*dt*c*c/(dx*dx),

*u=NULL, *u_l, *u_old_l, *u_new_l, *u_temp, x, t;MPI_Status status;

/ * MPI i n i t i a l i s i e r e n * /30 MPI_Init(&argc, &argv);

MPI_Comm_size(MPI_COMM_WORLD, &C_size);MPI_Comm_rank(MPI_COMM_WORLD, &C_rank);/ * Zahl d e r l o k a l e n S t u t z s t e l l e n b e r e c h n e n * /N_l=secure_malloc(C_size*sizeof(*N_l));

35 N0_l=secure_malloc(C_size*sizeof(*N0_l));for (i=0; i<C_size; ++i) {

N_l[i]=(i+1)*(N-1)/C_size-i*(N-1)/C_size+1;N0_l[i]=i*(N-1)/C_size;

}40 / * S p e i c h e r a l l o z i e r e n und Anfangswer t e b e r e c h n e n * /

u_old_l=secure_malloc((N_l[C_rank]+1)*sizeof(*u_old_l));u_l=secure_malloc((N_l[C_rank]+1)*sizeof(*u_l));u_new_l=secure_malloc((N_l[C_rank]+1)*sizeof(*u_new_l));for (i=0; i<=N_l[C_rank]; ++i) {

45 x=(i+N0_l[C_rank])*dx;u_old_l[i]=u_0(x);u_l[i]=0.5*eps*(u_0(x-dx)+u_0(x+dx))+(1.0-eps)*u_0(x)+dt*u_0_dt(x);

}/ * DGL l o s e n * /

50 for (t=2*dt; t<=t_end; t+=dt) {string(u_l, u_old_l, u_new_l, N_l[C_rank], eps);if (C_size>1) {

/ * nach r e c h t s senden * /if (C_rank!=0)

55 MPI_Recv(&u_new_l[0], 1, MPI_DOUBLE, C_rank-1,right_copy, MPI_COMM_WORLD, &status);

if (C_rank!=C_size-1)

Page 300: [X.systems.press] Cluster Computing ||

9.2 Geometrische Parallelisierung 295

MPI_Send(&u_new_l[N_l[C_rank]-1], 1, MPI_DOUBLE, C_rank+1,right_copy, MPI_COMM_WORLD);

60 / * nach l i n k s senden * /if (C_rank!=C_size-1)

MPI_Recv(&u_new_l[N_l[C_rank]], 1, MPI_DOUBLE, C_rank+1,left_copy, MPI_COMM_WORLD, &status);

if (C_rank!=0)65 MPI_Send(&u_new_l[1], 1, MPI_DOUBLE, C_rank-1,

left_copy, MPI_COMM_WORLD);}/ * F e l d e r t a u s c h e n * /u_temp=u_old_l; u_old_l=u_l; u_l=u_new_l; u_new_l=u_temp;

70 }/ * Daten einsammeln und E n d p o s i t i o n ausgeben * /if (C_rank==0)

u=secure_malloc((N+1)*sizeof(*u));++N_l[C_size-1];

75 MPI_Gatherv(u_l, N_l[C_rank], MPI_DOUBLE, u, N_l, N0_l, MPI_DOUBLE,0, MPI_COMM_WORLD);

if (C_rank==0)for (i=0; i<=N; ++i)

printf(”%g\n ”, u[i]);80 / * R e s s o u r c e n f r e i g e b e n * /

free(u); free(u_old_l); free(u_l); free(u_new_l);MPI_Finalize();return EXIT_SUCCESS;

}

linken Nachbarn versendet. Nach einer Rotation der Felder (Zeile 69) beginnt dernachste Schleifendurchlauf. Wenn eine gewisse Zahl von Schleifendurchlaufen er-reicht ist, sammelt der Prozess mit dem Rang null alle Daten ein und gibt die Datender letzten Saitenauslenkung aus.

Wenn Sie das Programm in Listing 9.11 testen, werden Sie sehen, dass es primafunktioniert. Nur hat es einen Schwachpunkt, und der betrifft die Art, wie die Kom-munikation zwischen den Prozessen abgewickelt wird. Betrachten wir nocheinmalZeile 55. Jeder Prozess außer dem außerst linken versucht hier, mit MPI Recv Da-ten von seinem linken Nachbarn zu empfangen. Da bis hierher kein Prozess Datenversendet hat, kehrt ersteinmal kein Prozess aus dem Aufruf von MPI Recv zuruck.Lediglich der außerst linke Prozess mit dem Rang null verzichtet auf das Empfan-gen von Daten, ruft direkt MPI Send auf und schickt damit Daten an seinen rechtenNachbarn mit dem Rang eins. Nun kehrt dieser endlich aus MPI Recv zuruck undsendet seinerseits Daten an seinen rechten Nachbarn mit dem Rang zwei. DiesesMuster geht so weiter, bis schließlich der vorletzte Prozess Daten an den außerstrechten Prozess gesendet hat. Der Datenfluss zum jeweils rechten Nachbarn lauftzwischen den Prozessen also nicht gleichzeitig ab, stattdessen kommunizieren dieProzesse zeitlich nacheinander. Dabei lauft durch die Prozesse gewissermaßen vonlinks nach rechts eine ”Kommunikationswelle“, die die Prozesse nacheinander ”akti-viert“. Der Datenaustausch von rechts nach links ab Zeile 60 lauft im Prinzip nachdem gleichen Schema, nur lauft hier die ”Kommunikationswelle“ in die entgegenge-setzte Richtung.

Page 301: [X.systems.press] Cluster Computing ||

296 9 Parallelisierungstechniken

Das wellenformige Kommunikationsmuster fuhrt dazu, dass die Zeit, die notwen-dig ist, um die Randdaten auszutauschen, proportional zur Zahl der Prozesse ist. Diesist sicher keine gute Basis fur einen skalierbaren parallelen Algorithmus. Bei Proble-men mit periodischen Randbedingungen ist die Situation sogar noch vertrackter. Hiergibt es keinen außerst linken oder rechten Prozess, der nur sendet oder empfangt, undsomit wurde es zu einem deadlock kommen, siehe Abschnitt 7.4.3.

Was wir brauchen, um deadlocks und das beschriebene wellenformige Kommu-nikationsmuster zu vermeiden, ist eine Funktion mit der man gleichzeitig sendenund empfangen kann. Glucklicherweise haben die Entwickler des MPI-Standardsauch daran gedacht. Die entsprechende Funktion heißt (Wie sollte es anders sein?)MPI Sendrecv. Diese Funktion haben Sie schon im Abschnitt 7.4.3 kennengelernt.Ihre Argumente entsprechen denen der Funktionen MPI Send und MPI Recv. Da-ten, die mit MPI Sendrecv versendet werden, durfen mit den Empfangsfunktionenaus Kapitel 7 empfangen werden. Gleichfalls konnen Daten, die mit Sendefunktionenaus Kapitel 7 verschickt wurden, mit MPI Sendrecv empfangen werden. Ersetzenwir die Zeilen 52 bis 67 gegen folgende Programmzeilen, so konnen alle Prozessegleichzeitig senden und empfangen. Dadurch wachst die Zeit zum Randdatenaus-tausch nicht mehr linear mit der Zahl der Prozesse an.

if (C_size>1) {/ * nach r e c h t s senden * /if (0==C_rank)

MPI_Send(&u_new_l[N_l[C_rank]-1], 1, MPI_DOUBLE, C_rank+1,right_copy, MPI_COMM_WORLD);

if (0<C_rank && C_rank<C_size-1)MPI_Sendrecv(&u_new_l[N_l[C_rank]-1], 1, MPI_DOUBLE, C_rank+1,

right_copy,&u_new_l[0], 1, MPI_DOUBLE, C_rank-1,right_copy,MPI_COMM_WORLD, &status);

if (C_rank==C_size-1)MPI_Recv(&u_new_l[0], 1, MPI_DOUBLE, C_rank-1, right_copy,

MPI_COMM_WORLD, &status);/ * nach l i n k s senden * /if (0==C_rank)

MPI_Recv(&u_new_l[N_l[C_rank]], 1, MPI_DOUBLE, C_rank+1,left_copy, MPI_COMM_WORLD, &status);

if (0<C_rank && C_rank<C_size-1)MPI_Sendrecv(&u_new_l[1], 1, MPI_DOUBLE, C_rank-1,

left_copy,&u_new_l[N_l[C_rank]], 1, MPI_DOUBLE, C_rank+1,left_copy,MPI_COMM_WORLD, &status);

if (C_rank==C_size-1)MPI_Send(&u_new_l[1], 1, MPI_DOUBLE, C_rank-1, left_copy,

MPI_COMM_WORLD);}

Beachten Sie, dass die außersten Prozesse jeweils nur Daten mit MPI Send sendenoder mit MPI Recv empfangen.

Dieses Beispiel zeigt zwar sehr schon, dass die Funktion MPI Sendrecv auchmit den Standardsende- und -empfangsfunktionen zusammenarbeitet, die Sonderbe-handlung der Randprozesse macht den Programmcode aber recht unubersichtlich.

Page 302: [X.systems.press] Cluster Computing ||

9.2 Geometrische Parallelisierung 297

Aber auch dafur kennt der MPI-Standard eine elegante Losung, MPI PROC NULL.Diese Konstante darf in allen Sende- bzw. Empfangsfunktionen als Empfanger- bzw.Senderrang verwendet werden. Sie steht gewissermaßen fur einen nicht vorhandenenProzess. Mit MPI PROC NULL werden Sende- bzw. Empfangsfunktionen zu Null-operationen ohne jede Wirkung. Verwenden wir MPI Sendrecv zusammen mitMPI PROC NULL vereinfacht sich der Programmcode fur den Randdatenaustauschauf zwei Funktionsaufrufe.

/ * nach r e c h t s senden * /MPI_Sendrecv(&u_new_l[N_l[C_rank]-1], 1, MPI_DOUBLE,

C_rank+1<C_size ? C_rank+1 : MPI_PROC_NULL, right_copy,&u_new_l[0], 1, MPI_DOUBLE,C_rank-1>=0 ? C_rank-1 : MPI_PROC_NULL, right_copy,MPI_COMM_WORLD, &status);

/ * nach l i n k s senden * /MPI_Sendrecv(&u_new_l[1], 1, MPI_DOUBLE,

C_rank-1>=0 ? C_rank-1 : MPI_PROC_NULL, left_copy,&u_new_l[N_l[C_rank]], 1, MPI_DOUBLE,C_rank+1<C_size ? C_rank+1 : MPI_PROC_NULL, left_copy,MPI_COMM_WORLD, &status);

Wie Sie sehen, kann nun auch die außere if-Klammer entfallen. Ihre Aufgabe war esin den vorher gezeigten Versionen des Randdatenaustauschs, im Falle nur eines Pro-zesses einen deadlock zu verhindern. Da aber nun in diesem Fall MPI Sendrecvmit MPI PROC NULL fur Sender- und Empfangerrang aufgerufen wird, hat die Funk-tion keinerlei Wirkung und es kann nicht zu einem deadlock kommen.

Ein Aufruf von MPI Sendrecv ist im Wesentlichen aquivalent zur Verwendungnicht blockierenden Sendens. Wenn wir ab Zeile 27 in Listing 9.11 noch zusatzlichdie Variablen

MPI_Status status, statuses[2];MPI_Request requests[2];

deklarieren, so konnte der Randdatenaustausch auch mit

/ * nach r e c h t s und l i n k s senden * /MPI_Isend(&u_new_l[N_l[C_rank]-1], 1, MPI_DOUBLE,

C_rank+1<C_size ? C_rank+1 : MPI_PROC_NULL, right_copy,MPI_COMM_WORLD, &requests[0]);

MPI_Isend(&u_new_l[1], 1, MPI_DOUBLE,C_rank-1>=0 ? C_rank-1 : MPI_PROC_NULL, left_copy,MPI_COMM_WORLD, &requests[1]);

MPI_Recv(&u_new_l[0], 1, MPI_DOUBLE,C_rank-1>=0 ? C_rank-1 : MPI_PROC_NULL, right_copy,MPI_COMM_WORLD, &status);

MPI_Recv(&u_new_l[N_l[C_rank]], 1, MPI_DOUBLE,C_rank+1<C_size ? C_rank+1 : MPI_PROC_NULL, left_copy,MPI_COMM_WORLD, &status);

MPI_Waitall(2, requests, statuses);

implementiert werden.

Page 303: [X.systems.press] Cluster Computing ||

298 9 Parallelisierungstechniken

9.2.4 Kommunikatoren und Topologien

Bei der Simulation der schwingenden Saite tauschen die Prozesse standig Daten mitihren linken und rechten Nachbarn aus. Aber woher weiß ein Prozess, welchen Rangsein linker oder rechter Nachbar hat? Weil im eindimensionalen Beispiel der schwin-genden Saite die Datenblocke nach aufsteigendem Rang verteilt wurden, war dieseFrage leicht zu beantworten. Der linke Nachbar eines Prozesses mit dem Rang P hatden Rang P− 1 und der rechte den Rang P + 1. Bei Gebietszerlegungen in hoher-en Dimensionen wird die Sache schon recht unubersichtlich. Im Falle einer zwei-dimensionalen Gebietszerlegung wie in Abb. 9.8 wird eine lineare Nummerierungder Prozesse den verwendeten Kommunikationsmustern nicht mehr gerecht. DurchKommunikatoren mit einer virtuellen Topologie erhalten wir ein Adressierungssche-ma, das besser zu den typischen Kommunikationsmustern bei Gebietszerlegungen inhoheren Dimensionen passt.

In Abschnitt 8.1 haben wir gesehen, dass ein Kommunikator im Wesentlicheneine Gruppe von Prozessen enthalt. Neben der Information, welche Prozesse zu ei-nem Kommunikator gehoren, konnen aber noch andere Daten mit ihm assoziiert sein.Dazu gehort u. a. seine Topologie. Topologien stellen neben den Rang eine weitereMoglichkeit dar, einen Prozess innerhalb eines Kommunikators zu adressieren. DerMPI-Standard kennt zwei Arten von Topologien, kartesische Topologien und allge-meine Graphen. Wir beschranken uns hier auf die Darstellung kartesischer Topolo-gien, denn diese haben in der Praxis die großte Bedeutung. Die im MPI-Standardeingefuhrten Topologien sind rein logischer Natur. Das heißt, sie entsprechen nichtunbedingt einem physisch prasenten Netzwerk.

Die Funktion MPI Cart create erzeugt aus einem vorhandenen Kommunika-tor einen neuen Kommunikator mit einer kartesischen Topologie.int MPI_Cart_create(MPI_Comm comm_old, int ndims, int *dims, int *periods,

int reorder, MPI_Comm *comm_cart)

Dabei werden die Prozesse in einem kartesischen Gitter mit ndims Dimensionenangeordnet. Das Feld dims enthalt die Zahl der Prozesse in den einzelnen Dimen-sionen. Fur jede der Dimensionen lasst sich einzeln festlegen, ob sie periodischfortgesetzt wird. Ist ein Element des Feldes periods ungleich null, so wird dieentsprechende Dimension periodisch fortgesetzt. Das Argument reorder legt fest,ob die Prozesse im neuen Kommunikator comm cart den gleichen Rang habenmussen wie im alten comm old. Ist es ungleich null, so darf die MPI-Bibliothek dieProzesse umordnen. MPI-Implementationen, die Informationen uber die physischeNetzwerktopologie haben, konnen durch eine Umordnung der Prozesse die logischeProzesstopologie auf die physische Topologie des Netzwerkes besser abbilden.

Die Zahl der Prozesse in dem Prozessgitter ist gleich dem Produkt der Prozessein jeder Dimension, also gleich dem Produkt der Zahlen im Feld dims.

p =ndims−1

∏i=0

dimsi

Da der neue Kommunikator comm cart und der alte comm old dieselben (und so-mit auch gleichviele) Prozesse enthalten, muss der alte Kommunikator comm old

Page 304: [X.systems.press] Cluster Computing ||

9.2 Geometrische Parallelisierung 299

mindestens p Prozesse enthalten, sonst ist der Aufruf von MPI Cart createfehlerhaft. Mehr als p Prozesse sind allerdings erlaubt, bei den uberzahligen Pro-zesse gibt die Funktion MPI Cart create dann den ungultigen KommunikatorMPI COMM NULL zuruck.

Portable MPI-Programme zeichnen sich u. a. dadurch aus, dass ihre Funktiona-litat nicht von der Zahl der Prozesse abhangt, mit der sie gestartet wurden. Bei derVerwendung von Kommunikatoren mit kartesischer Topologie ist die Dimension derTopologie in der Regel implizit durch die zu losende Aufgabenstellung fest vorge-geben. Bei der Wahl der Zahl der Prozesse in den jeweiligen Dimensionen dimsibesteht aber eine gewisse Freiheit. Um eine gute Lastverteilung zu erzielen, ist es inden meisten Anwendungen erstrebenswert, dass

• das Produkt ∏ndims−1i=0 dimsi gleich der Zahl der Prozesse im alten Kommunikator

comm old ist und• sich entlang jeder Dimension etwa gleichviele Prozesse befinden.

Eine Geometrie, die die genannten Anforderungen moglichst gut erfullt, lasst sichmit der Funktion MPI Dims create ermitteln.

int MPI_Dims_create(int nnodes, int ndims, int *dims)

Dazu benotigt die Funktion die Gesamtzahl der Prozesse nnodes und die Dimen-sion des Gitters ndims. Im Feld dims, dessen Elemente vor dem Aufruf vonMPI Dims create mit dem Wert null initialisiert werden mussen, wird die Zahlder Prozesse entlang jeder Dimension zuruckgegeben. Sind einige Werte in dimsvor dem Aufruf von MPI Dims create großer null, so versucht die Funktion eineGeometrie mit der vorgegebenen Anzahl von Prozessen entlang dieser Dimensionenzu finden.

Die Charakteristika eines Kommunikators mit kartesischer Topologie lassensich nach seiner Konstruktion mit den beiden Funktionen MPI Cartdim get undMPI Cart get abfragen. Erstere ermittelt seine Dimension, die andere die Zahl derProzesse entlang jeder Dimension (Feld dims), Periodizitat jeder Dimension (Feldperiods) und die Koordinate des aufrufenden Prozesses (Feld coords). Ihre Pro-totypen lauten:

int MPI_Cartdim_get(MPI_Comm comm, int *ndims)int MPI_Cart_get(MPI_Comm comm, int maxdims, int *dims, int *periods,

int *coords)

Stellen Sie sich vor, Sie haben in einem Programm einen Kommunikator zwei-dimensionaler kartesischer Topologie erstellt und wollen nun eine Reduktionsope-ration entlang jeder Spalte durchfuhren. Da Reduktionsoperationen immer auf alleProzesse eines Kommunikators wirken, benotigen Sie fur jede Spalte einen separa-ten Kommunikator, der nur die Prozess der entsprechenden Spalte enthalt. DieseKommunikatoren konnte man mit der Funktion MPI Comm split erzeugen, kom-fortabler geht es aber mit MPI Cart sub.

int MPI_Cart_sub(MPI_Comm comm, int *remain_dims, MPI_Comm *newcomm)

Page 305: [X.systems.press] Cluster Computing ||

300 9 Parallelisierungstechniken

Im Allgemeinen liefert diese Funktion einen Kommunikator newcomm zuruck, dereinem niederdimensionalen Untergitter des Kommunikators comm entspricht. Diein newcomm enthaltenen Unterdimensionen werden uber das Feld remain dimsausgewahlt. Einige Beispiele:

• Sei eine zweidimensionale Topologie mit 4×5 Prozessen gegeben und das Feldremain dims= [1,0]. So werden nach dem Aufruf von MPI Cart sub insge-samt funf Kommunikatoren erzeugt, die jeweils vier Prozesse entlang der erstenDimension enthalten.

• Sei eine vierdimensionale Topologie mit 4× 5× 6× 7 Prozessen gegeben undremain dims = [1,1,0,0]. So werden nach dem Aufruf von MPI Cart subinsgesamt 6 ·7 Kommunikatoren erzeugt, die aus jeweils 4 ·5 Prozessen entlangder ersten beiden Dimension des alten Kommunikators bestehen.

• Enthalt das Feld remain dims nur Einsen, so besteht der neue Kommunikatoraus den gleichen Prozessen wie der alte Kommunikator comm, besteht das Feldnur aus Nullen, so ist der neue Kommunikator kongruent zu MPI COMM SELF.

Die eigentliche Aufgabe von Kommunikatoren mit kartesischer Topologie bestehtdarin, Prozesse leichter zu adressieren. In einer kartesischen Topologie sind alle Pro-zesse in einem kartesischen Gitter angeordnet und lassen sich entweder uber ihrenRang oder uber ihre Koordinate innerhalb des Gitters adressieren. Mit den beidenFunktionen MPI Cart coords und MPI Cart rank konnen diese beiden Adres-sen ineinander umgerechnet werden.

int MPI_Cart_coords(MPI_Comm comm, int rank, int maxdims, int *coords)int MPI_Cart_rank(MPI_Comm comm, int *coords, int *rank)

Beachten Sie, dass die Nummerierung der Koordinaten bei null beginnt. In einem3×4-Gitter laufen die Koordinaten also von null bis zwei bzw. von null bis drei.

Mit der Funktion MPI Cart shift kann ein Prozess herausfinden, welchenRang ein Prozess hat, der sich in einer bestimmten Entfernung entlang einer Koordi-natenrichtung befindet.

int MPI_Cart_shift(MPI_Comm comm, int direction, int disp,int *rank_source, int *rank_dest)

Diese Funktion wird typischerweise benutzt, wenn Daten entlang einer Koordina-tenrichtung verschoben werden. Die Resultate rank source und rank destkonnen direkt an das Rangargument von Sende- und Empfangsfunktionen weiter-gereicht werden. Dabei ist rank dest zu verwenden, wenn der Prozess selbstals Sender fungiert, und rank source, falls er Daten empfangt. Das Argumentdirection wahlt die Richtung aus, disp gibt die Entfernung an. Erfolgt die Ver-schiebung entlang einer aperiodischen Koordinatenrichtung kann eine Koordinateauch außerhalb des Gitters liegen. In diesem Fall ist der zuruckgegebene Rang gleichMPI NULL PROC. Leider kann man sich mit MPI Cart shift immer nur entlangeiner einzigen Koordinatenrichtung bewegen. Es lasst sich mit dieser Funktion dar-um z. B. nicht bestimmen, welchen Rang der nachste Prozess in ”nordostlicher“ Rich-tung hat.

Page 306: [X.systems.press] Cluster Computing ||

9.2 Geometrische Parallelisierung 301

P P

PP PP

P P P P

P P P

P P P P

P

P P P P

PP PP

P

P P P P

P P P P

P P P P

P P P

P P

aufrufender Prozess rank_source rank_dest

P

P PP

direction = 1 disp = 2 direction = 0 disp = −1

0 1

75 64

12 13 14 15

16 17 18

20 21 22 23

9

0 1 2 3

75 64

11

12 13 14 15

16 17 18 19

20 21 22 23

8 9 10

2 3

19

8 1110

Abb. 9.10. Demonstration der Arbeitsweise von MPI Cart shift am Beispiel einer zweidi-mensionalen kartesischen Topologie, deren erste Koordinatenrichtung periodisch ist. BeachtenSie den Effekt der periodischen Koordinatenrichtung.

Die Vorteile von Kommunikatoren mit virtueller kartesischer Topologie zei-gen sich in Ganze erst in zwei oder drei Dimensionen bei kachelformiger (sie-he Abb. 9.8) bzw. quaderformiger Gebietsaufteilung. Aber naturlich kann man sieauch bei eindimensionalen Problemen wie der Simulation der schwingenden Sai-te verwenden. Listing 9.12 zeigt, wie es geht. In Zeile 32 erzeugt die FunktionMPI Cart create einen Kommunikator mit eindimensionaler kartesischer Topo-logie und MPI Comm rank bestimmt den Rang innerhalb des neuen Kommunika-tors. Beachten Sie, dass ein Prozess in MPI COMM WORLD und im kartesischen Kom-munikator verschiedene Range haben kann. Der Randdatenaustausch erfolgt wie aufSeite 297 gezeigt durch MPI Sendrecv. Allerdings werden nun Quell- und Ziel-rang mit der Funktion MPI Cart shift bestimmt.

Listing 9.12. Das Programm string4 mpi.c lost die Differentialgleichung einer schwin-genden Saite und verwendet dabei eine eindimensionale kartesische virtuelle Prozesstopologie.Fehlende Zeilen wie in Listing 9.12.int main(int argc, char *argv[]) {

int C_rank, C_size, *N_l, *N0_l, i;25 double dx=L/N, eps=dt*dt*c*c/(dx*dx),

*u=NULL, *u_l, *u_old_l, *u_new_l, *u_temp, x, t;MPI_Status status;

/ * MPI i n i t i a l i s i e r e n * /30 MPI_Init(&argc, &argv);

MPI_Comm_size(MPI_COMM_WORLD, &C_size);MPI_Comm_rank(MPI_COMM_WORLD, &C_rank);/ * Zahl d e r l o k a l e n S t u t z s t e l l e n b e r e c h n e n * /N_l=secure_malloc(C_size*sizeof(*N_l));

35 N0_l=secure_malloc(C_size*sizeof(*N0_l));

Page 307: [X.systems.press] Cluster Computing ||

302 9 Parallelisierungstechniken

for (i=0; i<C_size; ++i) {N_l[i]=(i+1)*(N-1)/C_size-i*(N-1)/C_size+1;N0_l[i]=i*(N-1)/C_size;

}40 / * S p e i c h e r a l l o z i e r e n und Anfangswer t e b e r e c h n e n * /

u_old_l=secure_malloc((N_l[C_rank]+1)*sizeof(*u_old_l));u_l=secure_malloc((N_l[C_rank]+1)*sizeof(*u_l));u_new_l=secure_malloc((N_l[C_rank]+1)*sizeof(*u_new_l));for (i=0; i<=N_l[C_rank]; ++i) {

45 x=(i+N0_l[C_rank])*dx;u_old_l[i]=u_0(x);u_l[i]=0.5*eps*(u_0(x-dx)+u_0(x+dx))+(1.0-eps)*u_0(x)+dt*u_0_dt(x);

}/ * DGL l o s e n * /

50 for (t=2*dt; t<=t_end; t+=dt) {string(u_l, u_old_l, u_new_l, N_l[C_rank], eps);if (C_size>1) {

/ * nach r e c h t s senden * /if (C_rank!=0)

55 MPI_Recv(&u_new_l[0], 1, MPI_DOUBLE, C_rank-1,right_copy, MPI_COMM_WORLD, &status);

if (C_rank!=C_size-1)MPI_Send(&u_new_l[N_l[C_rank]-1], 1, MPI_DOUBLE, C_rank+1,

right_copy, MPI_COMM_WORLD);60 / * nach l i n k s senden * /

if (C_rank!=C_size-1)MPI_Recv(&u_new_l[N_l[C_rank]], 1, MPI_DOUBLE, C_rank+1,

left_copy, MPI_COMM_WORLD, &status);if (C_rank!=0)

65 MPI_Send(&u_new_l[1], 1, MPI_DOUBLE, C_rank-1,left_copy, MPI_COMM_WORLD);

}/ * F e l d e r t a u s c h e n * /u_temp=u_old_l; u_old_l=u_l; u_l=u_new_l; u_new_l=u_temp;

70 }/ * Daten einsammeln und E n d p o s i t i o n ausgeben * /if (C_rank==0)

u=secure_malloc((N+1)*sizeof(*u));++N_l[C_size-1];

75 MPI_Gatherv(u_l, N_l[C_rank], MPI_DOUBLE, u, N_l, N0_l, MPI_DOUBLE,0, MPI_COMM_WORLD);

if (C_rank==0)for (i=0; i<=N; ++i)

printf(”%g\n ”, u[i]);80 / * R e s s o u r c e n f r e i g e b e n * /

free(u); free(u_old_l); free(u_l); free(u_new_l);MPI_Finalize();return EXIT_SUCCESS;

}

9.2.5 Zellulare Automaten

Ein zellularer Automat besteht aus einer Vielzahl von Zellen, die in einem regelmaßi-gen Gitter angeordnet sind. Jede dieser Zellen befindet sich zu jedem Zeitpunkt ineinen von (meist endlich vielen) Zustanden. Was zellulare Automaten interessantmacht, ist ihre Dynamik. In jedem Zeitschritt verandern alle Zellen gemaß einer be-stimmten Evolutionsregel gleichzeitig ihren Zustand. Obwohl die Evolutionsregeln

Page 308: [X.systems.press] Cluster Computing ||

9.2 Geometrische Parallelisierung 303

von Neumann Moore

Abb. 9.11. Die von-Neumann- und die Moore-Nachbarschaft sind die wichtigsten Nachbar-schaftsarten fur zellulare Automaten auf einem Quadratgitter.

der meisten zellularen Automaten relativ einfach sind, konnen sie sehr komplexe Dy-namiken entwickeln. Egal wie die Regel eines Automaten im Detail aussieht, derneue Zustand einer Zelle hangt nur vom alten Zustand dieser Zelle und denen ih-rer nachsten Nachbarn ab. Im Falle eines quadratischen Gitters werden ublicherwei-se die nachsten vier (von-Neumann-Nachbarschaft) oder die nachsten acht (Moore-Nachbarschaft) Nachbarn berucksichtigt, siehe Abb. 9.11. Aufgrund der Lokalitatder Evolutionsregel sind Zellulare Automaten ideale Kandidaten fur eine Paralleli-sierung durch Gebietsaufteilung.

Einem zellularen Automaten sind wir in diesem Buch schon begegnet. Die Finite-Differenzen-Approximation der Schwingungsgleichung (9.6) ist nichts weiter alseine Regel fur einen eindimensionalen Zellularen Automaten, dessen Zellen konti-nuierlichviele Werte annehmen konnen. Auch Finite-Differenzen-Approximationenanderer partieller Differentialgleichungen fuhren auf Iterationsschemata, die sich alszellulare Automaten interpretieren lassen.

Wie wollen hier einen zellularen Automaten untersuchen, der die Dynamik derBelousov-Zhabotinsky-Reaktion nachahmt. Durch ein komplexes Zusammenspielvon chemischen Reaktionen und Diffusion bilden sich bei der Belousov-Zhabotinsky-Reaktion wellenartige Muster in Form von Kreisen oder Spiralen aus, siehe Abb. 9.12.Diese chemische Reaktion dient in der Biophysik als Modellsystem fur erregbareMedien. Ein erregbares Medium kann sich lokal in einem von drei verschiedenenZustanden befinden. Es ist entweder erregbar, aktiviert oder inaktiv.

In [27] stellt Alexander Keewatin Dewdney einen zellularen Automaten vor,der eine ahnliche raum-zeitliche Dynamik erzeugt wie die Belousov-Zhabotinsky-Reaktion. Der Zustand einer Zelle wird durch die ganzen Zahlen 0 bis n gekennzeich-net. Eine erregbare Zelle befindet sich im Zustand 0, eine inaktive im Zustand n. Alle

Abb. 9.12. Links Belousov-Zhabotinsky-Reaktion in einer Petrischale, rechts ein vom im Textbeschriebenen zellularen Automaten erzeugter Zustand. Verschiedene Helligkeiten entspre-chen verschiedenen chemischen Konzentrationen.

Page 309: [X.systems.press] Cluster Computing ||

304 9 Parallelisierungstechniken

anderen Zustande reprasentieren eine erregte Zelle. Bei diesem Automaten befindensich alle Zellen auf einem quadratischen Gitter und haben eine Moore-Nachbarschaft.Die Dynamik der Evolutionsregel lasst sich durch die Wahl der Konstanten k1, k2 undg beeinflussen. Die Evolutionsregel lautet wie folgt:

• Fur jede Zelle werden die Großen a, b und s bestimmt, wobei a die Zahl deraktivierten Zellen und b die Zahl der inaktiven Zellen innerhalb der Moore-Nach-barschaft ist. Die Zahl s ergibt sich aus der Summe der Zustande der betrachtetenZelle und seiner Nachbarn.

• Falls eine Zelle erregbar ist (Zustand 0), dann ist ihr neuer Zustand gleich�a/k1�+ �b/k2�.

• Inaktive Zellen (Zustand n) werden wieder erregbar (Zustand 0).• Der neue Zustand einer erregten Zelle ist �s/(a+b+1)�+g. Er ergibt sich also

aus dem Mittelwert seines Zustands und der Zustande seiner Nachbarn und einemadditiven Term. Dabei modelliert die Mittelwertbildung einen Diffusionsprozessund der additive Term einen Stoffumsatz durch chemische Reaktion.

• Falls der Zustand einer Zelle durch eine der obigen Operationen großer als ngeworden ist, wird er auf n abgerundet.

Fur bestimmte Parameter k1, k2 und g erzeugt diese Regel unabhangig vom Anfangs-zustand des zellularen Automaten im Laufe seiner Evolution spiralformige Musterwie in Abb. 9.12.

Wir wollen den zellularen Automaten auf einem Nx × Ny-Gitter mit periodi-schen Randbedingen simulieren. Dazu wird das Gitter der zellularen Automaten inPx ×Py rechteckige Teilgitter zerlegt und jedes Teilgitter wird am Rand durch Geis-terzellen erganzt, die die Randdaten der angrenzenden Teilgitter enthalten. Da derhier betrachtete zellulare Automat eine Moore-Nachbarschaft besitzt, mussen in je-dem Zeitschritt Randdaten in insgesamt acht Richtungen ausgetauscht werden, sieheAbb. 9.13.

In Listing 9.13 finden Sie eine parallele Implementation des zellularen Automa-ten. Wie jedes MPI-Programm beginnt auch dieses mit der Initialisierung der MPI-Umgebung. Mit der Funktion MPI Dims create sucht das Programm danach einemoglichst gleichmaßige Aufteilung der C size Prozesse in ein zweidimensionalesProzessgitter der Große P[0]×P[1], erzeugt mit MPI Cart create einen Kom-munikator mit zweidimensionaler kartesischer Topologie und jeder Prozess bestimmtseinen Rang in dem neuen Kommunikator und seine Position im Prozessgitter undspeichert sie in P l.

Um das Beispielprogramm 9.13 moglichst kurz und einfach zu halten, bedienenwir uns in den Zeilen 35 und 36 eines kleinen Tricks. Hier werden Lange und Brei-te des zellularen Automaten auf ein ganzzahliges Vielfaches von P[0] und P[1]abgerundet. Dadurch verwaltet jeder Prozess ein exakt gleich großes Teilgebiet mitje Nx l×Ny l Zellen. Will man auf diese Abrundung verzichten, so muss dafurdie am Beispiel des Beugungsbilds und der schwingenden Saite demonstrierte Auf-teilungstechnik auf zwei Dimensionen verallgemeinert werden. Allerdings gestaltetsich dann das Einsammeln der Daten am Schluss des Programms etwas aufwendiger.

Page 310: [X.systems.press] Cluster Computing ||

9.2 Geometrische Parallelisierung 305

Nx_l

Ny_l

X_l

Nx_l + 2

+ 2

Ny_l

5

6

0

1

74

23

6

5

1

0

47

32

Px +1 y,Px −1 y,

,xP y +1Px −1,y +1

Px −1,y −1 Px +1,y −1xP , y −1

Px ,y

Px +1,y +1

Abb. 9.13. Randdatenaustausch bei einem zellularen Automaten mit Moore-Nachbarschaft.Die Zahlen geben die Reihenfolge wieder, in der das Programm 9.13 die Randdaten aus-tauscht.

In den Zeilen 37 bis 45 werden einige MPI-Datentypen gebaut. Sie verwendetdas Programm spater fur das Senden und Empfangen von Randzeilen (row t) bzw.Randspalten (col t), dem Senden eines ganzen Teilgebiets ohne Randdaten andererProzesse (innermatrix t) und dem Empfang dieser (submatrix t).

Nachdem nun jeder Prozess weiß, wie groß sein Teilgebiet des zellularen Auto-maten ist, reserviert er Speicher fur eine Matrix mit insgesamt (Nx l+2)×(Ny l+2) Zellen. Zwei Zeilen und Spalten enthalten die Randdaten der Nachbarn, die an-deren die lokalen Daten. Außerdem verschieben wir die beiden Zeiger X l undX l new, so dass sie auf die erste Zelle zeigen, die keine Randdaten von Nachbar-prozessen enthalt, und fullen die Zellen mit Zufallsdaten. Damit nicht jeder Prozessdie gleichen Pseudozufallszahlen verwendet, wird der Pseudozufallszahlengeneratorin Abhangigkeit vom Rang initialisiert.

Bevor in jedem Iterationsschritt die Evolutionsregel auf Seite 304 angewendetwerden kann, muss jeder Prozess die Randdaten seiner Nachbarprozesse erhalten. Da-zu sind insgesamt acht Aufrufe von MPI Sendrecv notwendig, die jeweils einenQuell- und Zielrang und Zeiger auf Sende- und Empfangspuffer benotigen. DieseDaten hangen naturlich von der Zahl der Prozesse ab, mit dem das MPI-Programmgestartet wurde, und mussen darum zur Laufzeit bestimmt werden. Dies geschiehtin den Zeilen 55 bis 80. Fur ein besseres Verstandnis dieser Zeilen, sollten Sie nocheinmal einen Blick auf Abb. 9.13 werfen. Es zeigt, in welcher Reihenfolge die Rand-

Page 311: [X.systems.press] Cluster Computing ||

306 9 Parallelisierungstechniken

Listing 9.13. Das Programm bz mpi.c implementiert den auf Seite 304 beschriebenen zel-lularen Automaten.

#include <stdlib.h>#include <stdio.h>#include ” mpi . h ”

5 const int n=255, k1=3, k2=3, g=41, t_end=1000;int Nx=400, Ny=300;enum { gather_tag, sendrecv_tag };

void * secure_malloc(size_t size) {10 void * p=malloc(size);

if (p==NULL)MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);

return p;}

15void bz_iterate(int *X, int *X_new, int Nx, int Ny,

int n, int k1, int k2, int g);

int main(int argc, char *argv[]) {20 int C_rank, C_size, P[2]={0, 0}, P_periods[2]={1, 1}, P_l[2],

*X=NULL, *X_l, *X_l_new, *X_l_t, i, j, k, t, Nx_l, Ny_l,soffset[8], roffset[8], srank[8], rrank[8], coords[2];

MPI_Comm comm;MPI_Datatype submatrix_t, innermatrix_t, row_t, col_t, types[8];

25 MPI_Request request;MPI_Status status;/ * MPI i n i t i a l i s i e r e n und k a r t e s i s c h e n Kommunikator bauen * /MPI_Init(&argc, &argv);MPI_Comm_size(MPI_COMM_WORLD, &C_size);

30 MPI_Dims_create(C_size, 2, P);MPI_Cart_create(MPI_COMM_WORLD, 2, P, P_periods, 1, &comm);MPI_Comm_rank(comm, &C_rank);MPI_Cart_coords(comm, C_rank, 2, P_l);/ * Große des z e l l u l a r e n Automaten abrunden * /

35 Nx -=Nx%P[0]; Nx_l=Nx/P[0];Ny -=Ny%P[1]; Ny_l=Ny/P[1];/ * MPI−D a t e n t y p e n bauen * /MPI_Type_vector(1, Nx_l, Nx_l, MPI_INT, &row_t);MPI_Type_commit(&row_t);

40 MPI_Type_vector(Ny_l, 1, Nx_l+2, MPI_INT, &col_t);MPI_Type_commit(&col_t);MPI_Type_vector(Ny_l, Nx_l, Nx_l+2, MPI_INT, &innermatrix_t);MPI_Type_commit(&innermatrix_t);MPI_Type_vector(Ny_l, Nx_l, Nx, MPI_INT, &submatrix_t);

45 MPI_Type_commit(&submatrix_t);/ * S p e i c h e r f u r Automaten a l l o z i e r e n und mi t Z u f a l l s w e r t e n f u l l e n * /X_l =secure_malloc((Nx_l+2)*(Ny_l+2)*sizeof(*X_l ));X_l +=(Nx_l+2)+1;X_l_new =secure_malloc((Nx_l+2)*(Ny_l+2)*sizeof(*X_l_new));

50 X_l_new+=(Nx_l+2)+1;srand(C_rank);for (j=0; j<Ny_l; ++j)

for (i=0; i<Nx_l; ++i)X_l[i+(Nx_l+2)*j]=rand()%n;

55 / * Daten f u r MPI Sendrecv a u f b e r e i t e n * /k=0;for (j=0; j<=1; ++j) / * Range und Typen f u r hor . & v e r t . Aus t ausch * /

Page 312: [X.systems.press] Cluster Computing ||

9.2 Geometrische Parallelisierung 307

for (i=-1; i<=1; i+=2, ++k) {types[k]=j==0 ? col_t : row_t;

60 MPI_Cart_shift(comm, j, i, rrank+k, srank+k);}

for (j=-1; j<=1; j+=2) / * Range und Typen f u r d i a g o n a l e n Aus tausch * /for (i=-1; i<=1; i+=2, ++k) {

types[k]=MPI_INT;65 coords[0]=P_l[0]+i; coords[1]=P_l[1]+j;

MPI_Cart_rank(comm, coords, srank+k);coords[0]=P_l[0]-i; coords[1]=P_l[1]-j;MPI_Cart_rank(comm, coords, rrank+k);

}70 soffset[0]=0; roffset[0]=Nx_l;

soffset[1]=Nx_l-1; roffset[1]=-1;soffset[2]=0; roffset[2]=(Nx_l+2)*Ny_l;soffset[3]=(Nx_l+2)*(Ny_l-1); roffset[3]=-(Nx_l+2);soffset[4]=0; roffset[4]=(Nx_l+2)*Ny_l+Nx_l;

75 soffset[5]=Nx_l-1; roffset[5]=(Nx_l+2)*Ny_l-1;soffset[6]=(Nx_l+2)*(Ny_l-1); roffset[6]=-2;soffset[7]=(Nx_l+2)*(Ny_l-1)+Nx_l-1; roffset[7]=-1-(Nx_l+2);/ * Regel des Automaten i t e r i e r e n * /for (t=0; t<t_end; ++t) {

80 for (i=0; i<8; ++i)MPI_Sendrecv(X_l+soffset[i], 1, types[i], srank[i], sendrecv_tag,

X_l+roffset[i], 1, types[i], rrank[i], sendrecv_tag,comm, &status);

bz_iterate(X_l, X_l_new, Nx_l, Ny_l, n, k1, k2, g);85 X_l_t=X_l; X_l=X_l_new; X_l_new=X_l_t; / * M a t r i z e n t a u s c h e n * /

}/ * Daten einsammeln und ausgeben * /MPI_Isend(X_l, 1, innermatrix_t, 0, gather_tag, comm, &request);if (C_rank==0) {

90 X=secure_malloc(Nx*Ny*sizeof(*X));for (P_l[1]=0; P_l[1]<P[1]; ++P_l[1])

for (P_l[0]=0; P_l[0]<P[0]; ++P_l[0]) {MPI_Cart_rank(comm, P_l, &C_rank);MPI_Recv(X+P_l[0]*Nx_l+P_l[1]*Nx*Ny_l,

95 1, submatrix_t, C_rank, gather_tag, comm, &status);}

printf(”P5\n%i %i \n%i \n ”, Nx, Ny, n); / * PGM−Header * /for (i=0; i<Nx*Ny; ++i)

fputc(X[i], stdout);100 }

MPI_Wait(&request, &status);/ * R e s s o u r c e n f r e i g e b e n * /MPI_Type_free(&submatrix_t); MPI_Type_free(&innermatrix_t);MPI_Comm_free(&comm);

105 MPI_Finalize();return EXIT_SUCCESS;

}

daten ausgetauscht werden. Diese Reihenfolge ist willkurlich. Jedoch ist es wichtig,in jedem Aufruf von MPI Sendrecv die richtigen Sender- und Empfangerrange,Datentypen und Sende- und Empfangspuffer anzugeben, leicht schleicht sich hier einFehler ein. In der Schleife ab Zeile 57 werden die Argumente fur MPI Sendrecvfur den Datenaustausch in horizontaler und vertikaler Richtung aufbereitet, ab Zei-le 62 folgen die fur den diagonalen Datenaustausch. Um die Range der empfangen-

Page 313: [X.systems.press] Cluster Computing ||

308 9 Parallelisierungstechniken

Listing 9.14. Die Funktion bz iterate wendet einmalig die auf Seite 304 beschriebeneEvolutionsregel an.

void bz_iterate(int *X, int *X_new, int Nx, int Ny,int n, int k1, int k2, int g) {

int i, j, k, a, b, s, x, x_n;const int dx[]={0, 1, 1, 1, 0,-1,-1,-1}, dy[]={1, 1, 0,-1,-1,-1, 0, 1};

5 for (j=0; j<Ny; ++j)for (i=0; i<Nx; ++i) {

x=X[i+(Nx+2)*j];a=b=0;s=x;

10 for (k=0; k<8; ++k) {x_n=X[(i+dx[k])+(Nx+2)*(j+dy[k])];s+=x_n;if (0<x_n && x_n<n) ++a;else if (x_n==n) ++b;

15 }if (x==0) X_new[i+(Nx+2)*j]=a/k1+b/k2;else if (0<x && x<n) X_new[i+(Nx+2)*j]=s/(a+b+1)+g;else X_new[i+(Nx+2)*j]=0;if (X_new[i+(Nx+2)*j]>n)

20 X_new[i+(Nx+2)*j]=n;}

}

den bzw. sendenden Prozesse zu ermitteln, verwenden wir im Falle des horizontalenbzw. vertikalen Datenaustausches die Funktion MPI Cart shift. Leider kann die-se Funktion aber nicht mit diagonalen Verschiebungen umgehen. Darum werden dieRange fur den diagonalen Datenaustausch durch die Funktion MPI Cart rank be-stimmt.

Die Felder soffset und roffset enthalten die Speicheradressen relativ zuX l, ab wo sich Sende- bzw. Empfangspuffer befinden und werden ab Zeile 70gefullt. Die dafur notwendige Arithmetik ist auf den ersten Blick etwas unubersicht-lich, wird aber schnell klar, wenn man sich daran erinnert, dass X l auf die ersteZelle, die keine Geisterzelle ist, zeigt und das lokale Gitter mit Geisterzellen aus(Nx l+2)× (Ny l+2) Elementen besteht, siehe Abb. 9.13.

Nach all dieser Vorarbeit kann die Evolutionsregel des zellularen Automaten nunendlich in der Schleife ab Zeile 78 iteriert werden. Dazu werden zunachst die Rand-daten ausgetauscht, um dann in der Funktion bz iterate einmalig die Evolutions-regel anzuwenden. Ist die maximale Iterationstiefe erreicht, sammelt der Prozess mitdem Rang null alle Daten ein und gibt sie als portable-graymap-Datei aus. Damitsich der Prozess mit dem Rang null nicht beim Senden an sich selbst blockiert undes zu einem deadlock kommt, haben wir hier eine nicht blockierenden Sendefunktionverwendet. Alternativ konnte man die Daten auch mit der Funktion MPI Gathervund geschickt gebauten MPI-Datentypen einsammeln. Eine Schleife uber alle Pro-zesse tut es hier auch und ist außerdem einfacher zu programmieren. Ganz zumSchluss werden noch belegte Ressourcen freigegeben und mit MPI Finalize dieMPI-Umgebung beendet.

Page 314: [X.systems.press] Cluster Computing ||

9.3 Notizen 309

Noch ein Tipp zum Schluss: Wann immer Sie eine Parallelisierung durch Gebiets-zerlegung implementieren und Sie ein stetige Losung erwarten, visualisieren Sie IhreLosung. Eventuelle Fehler beim Austausch der Randdaten fallen dann sofort durchunstetige Losungen ins Auge.

9.3 Notizen

9.1 Schlafender Master. Haben Sie bei einer Parallelisierung nach dem Master-Worker-Schema eine hinreichend grobe Granularitat gewahlt, so hat der Master nichtviel zu tun. Nur gelegentlich verteilt er neue Aufgaben an die Worker bzw. nimmtihre Ergebnisse entgegen. Zwischenzeitlich legt er sich mit der Funktion usleepschlafen. Dadurch erzeugt der Master-Prozess keine nennenswerte CPU-Last undder Master-Prozess und ein Worker-Prozess konnen sich Problemlos eine gemeinsa-me CPU teilen.

9.2 Objektorientierter Ansatz. Falls Sie schon einmal in einer objekt-orientiertenProgrammiersprache wie C++, Java oder Ruby gearbeitet haben, so wird Ihnen si-cher aufgefallen sein, dass wir fur die Master-Worker-Bibliothek einen objektori-entierten Ansatz gewahlt haben. Die Funktionen master new und worker newentsprechen dem Konstruktor einer Klasse und master free und worker freeubernehmen die Funktion eines Destruktors. Die Datentypen master str undworker str sind opake Datentypen. Das heißt, der Nutzer der Master-Worker-Bi-bliothek muss deren internen Aufbau nicht kennen, um die Bibliothek nutzen zukonnen. Genau diesen Ansatz hat man auch im MPI-Standard gewahlt, siehe Ab-schnitt 8.1.2.

9.3 Optimierungen. Das in Listing 9.9 vorgestellte Programm ist naturlich nochan vielen Punkten verbesserungsfahig. Haben die zu farbenden Graphen nur wenigeKanten, so konnte man viel Speicher sparen, indem der Graph statt in einer Adja-zenzmatrix in Adjazenzlisten gespeichert wird. Außerdem ließe sich der Rechnen-aufwand durch die Nutzung von Symmetrien reduzieren, denn aus jeder Farbunglasst sich durch Permutation der Farben eine neue Farbung konstruieren.

9.4 Boost Graph Library. Um das Graphfarbungsproblem zu losen, haben wirhier eine sehr rudimentare Graphenbibliothek benutzt. Wenn Sie anspruchsvolleregraphenalgorithmische Probleme losen mochten, sollten Sie besser auf ausgereifteGraphenbibliotheken wie die Boost Graph Library [150, 12] oder LEDA [101, 92]zuruckgreifen.

9.5 Virtuelle Topologien in Form eines Hyperkubus. Mit der in Abschnitt 9.2.4vorgestellten Funktion MPI Cart create kann auch eine Topologie in Form einesn-dimensionalen Hyperkubus konstruiert werden. Denn ein n-dimensionaler Hyper-kubus ist nichts weiter als ein n-dimensionales kartesisches Gitter mit periodischenRandbedingungen in allen Dimensionen (n-dimensionaler Torus), das in jeder Koor-dinatenrichtung genau zwei Prozesse zahlt.

Page 315: [X.systems.press] Cluster Computing ||

Teil IV

Praxis

Page 316: [X.systems.press] Cluster Computing ||

10

Debuggingmethoden und Entwicklungswerkzeugefur MPI-Programme

Mit der richtigen Einstellung kann das Debuggen ebenso wiedas Losen eines Puzzles Spaß machen.

Brian W. Kerninghan, Rob Pike [80]

To err is human—and to blame it on a computer is even moreso.

Robert Orben

Kaum ein Programm ist von Anfang an frei von Fehlern. Je komplexer ein Programmist, je mehr Komponenten in einem Programm zusammenarbeiten, desto wahrschein-licher befinden sich Fehler in ihm. Trotzdem hat naturlich jeder Programmierer dasZiel, seine Software bug-frei zu machen. Falls Sie etwas Erfahrung bei der Erstellungsequentieller Programme haben, wissen Sie sicher, wie schwer es ist, dieses Ziel zuerreichen. Die Fehlersuche in parallelen Programmen ist noch etwas anspruchsvol-ler. Das liegt zu einen daran, dass bei parallelen Programmen viele Dinge gleichzei-tig ablaufen. Zum andern konnen parallele Programme Fehler haben, die man vonsequentiellen Programmen nicht kennt, z. B. deadlocks (Abschnitt 7.4.3) oder raceconditions.

Ein verbreiteter Debugging-Ansatz besteht darin, ein fehlerhaftes Programm ankritischen Stellen Zwischenergebnisse ausgeben zu lassen und diese Ausgaben mitden zu erwartenden Werten zu vergleichen. Etwas erfahrenere Programmierer nutzenaußerdem Debugger und andere Werkzeuge. In diesem Kapitel lernen Sie, wie Siemit diesen Werkzeugen MPI-Programme untersuchen und welche MPI-spezifischenBesonderheiten dabei zu beachten sind. Die in diesem Kapitel vorgestellten Techni-ken sind zum großten Teil spezifisch fur LAM/MPI. Verwenden Sie eine andere MPI-Implementation mussen Sie auf andere (aber wahrscheinlich ahnliche) Programmeund Techniken zuruckgreifen.

10.1 Kontrollausgaben

Wer erfolgreich und zeitsparend Fehler in Programmen finden will, kommt um dieVerwendung geeigneter Werkzeuge nicht herum. Dies gilt fur parallele Programme

Page 317: [X.systems.press] Cluster Computing ||

314 10 Debuggingmethoden und Entwicklungswerkzeuge fur MPI-Programme

noch mehr als fur sequentielle. Als Anlaufstelle der Kollegen bei Programmierpro-blemen jeder Art machen wir dennoch sehr oft die Erfahrung, dass die Verwendungvon Debuggern gemieden wird. Anstatt auf diese machtigen Werkzeuge zuzugreifen,spicken viele Programmierer ihren Quellcode mit Zeilen wie

fprintf(stderr, ” Vor f o o b a r ( ) : foo=%f\n ”, foo);foo_bar(&foo);fprintf(stderr, ” Nach f o o b a r ( ) : foo=%f\n ”, foo);

Bei einfachen seriellen Programmen mag diese Methode noch eine brauchbare Artder Fehlersuche sein, beim Cluster-Computing stoßt sie schnell an ihre Grenzen.

Dies liegt unter anderem an der Art, wie Ein- und Ausgaben von der MPI-Imple-mentation gehandhabt werden. Gewohnlichen sequentiellen Programmen stehen dreiStandarddateien zur Verfugung, die von den Ein- und Ausgaberoutinen genutzt wer-den. Dies sind die Standardeingabe (stdin) fur Eingaben, Standardausgabe (stdout)fur normale Ausgaben und die Standardfehlerausgabe (stderr) fur die Ausgabe vonFehlermeldungen. Bei einem einfachen Programm sind diese Standarddateien typi-scherweise mit dem Terminal verbunden, in dem es gestartet wurde. Ausgaben aufStandardausgabe und Standardfehlerausgabe erscheinen dann auf dem Bildschirm,Eingaben der Standardeingabe kommen von der Tastatur.

MPI-Programme sind normalerweise nicht mit einem Terminal verbunden. Wieverhalt es sich dann mit den Standardein- und Standardausgabedateien im Falle ei-nes MPI-Programms? Leider lasst sich diese Frage nicht allgemein beantworten, derMPI-Standard schweigt sich zu diesem Thema namlich aus und uberlasst es den Im-plementatoren einer MPI-Bibliothek, wie sie mit den Standardein- und Standardaus-gabendateien umgehen. Im ungunstigsten Falle sind Standardausgabe und Standard-fehlerausgabe mit /dev/null und die Standardeingabe mit /dev/zero verbun-den und somit fur den Nutzer unbrauchbar und ein auf Kontrollausgaben basierenderDebugging-Ansatz scheidet von vornherein aus.

LAM/MPI verhalt sich hier zum Gluck etwas nutzerfreundlicher. Bei dieserMPI-Implementation werden Prozesse eines MPI-Programms durch das Programmmpirun gestartet. Es verbindet die Standardausgaben und die Standardfehlerausga-ben der MPI-Prozesse mit seiner eigenen Standardausgabe bzw. Standardfehlerausga-be. Außerdem wird die Standardeingabe von mpirun an den MPI-Prozess mit demRang null im Kommunikator MPI COMM WORLD weitergereicht. Auf diese Weisewerden Ausgaben auf Standardausgabe und Standardfehlerausgabe an mpirun wei-tergegeben und schließlich auf dem Terminal dargestellt, in dem mpirun lauft, undzumindest einer der MPI-Prozesse kann Eingaben von der Standardeingabe lesen.Die Weiterleitung ist jedoch relativ langsam und vergroßert die Programmlaufzeiterheblich. Das Hauptproblem ist aber, dass die Ausgaben der einzelnen Prozesse ge-puffert werden. Die Reihenfolge der Ausgaben, wie man sie im Terminal sieht, mussnicht die Reihenfolge sein, in der die Ausgaben erstellt wurden. Es wird lediglich ga-rantiert, dass die Ausgaben der verschiedenen Prozesse sich niemals innerhalb einerZeile uberlagern (line buffered output). Um zu verstehen, welche Konsequenzen dieshat, werfen wir einen Blick auf das Beispiel in Listing 10.1.

Page 318: [X.systems.press] Cluster Computing ||

10.1 Kontrollausgaben 315

Listing 10.1. Programm debug std.c, das zum Debugging Kontrollausgaben erzeugt.

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include ” mpi . h ”

5int main(int argc, char *argv[]) {

int rank, i;MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD, &rank);

10 for (i=0; i<100; ++i) {fprintf(stdout, ” Text von Knoten %i . i = %i \n ”, rank, i);fprintf(stderr, ” F e h l e r von Knoten %i . i = %i \n ”, rank, i);usleep(100); / * s i m u l i e r e A r b e i t * /

}15 MPI_Finalize();

return EXIT_SUCCESS;}

Terminal Session 10.1. Teil der Kontrollausgaben von debug std.bauke@server:˜/src$ mpirun -np 4 debug_stdText von Knoten 0. i = 0Fehler von Knoten 0. i = 0Fehler von Knoten 1. i = 0Text von Knoten 1. i = 0Text von Knoten 3. i = 0Fehler von Knoten 3. i = 0Text von Knoten 2. i = 0Fehler von Knoten 2. i = 0...Fehler von Knoten 1. i = 99Text von Knoten 1. i = 99Text von Knoten 3. i = 99Fehler von Knoten 3. i = 99Text von Knoten 0. i = 99Fehler von Knoten 0. i = 99Text von Knoten 2. i = 99Fehler von Knoten 2. i = 99

Nach der Initialisierung von MPI in den Zeilen 8 und 9 schreibt das Programmin einer Schleife einen kurzen Text auf die Standardausgabe bzw. die Standardfeh-lerausgabe. In Terminal Session 10.1 sehen Sie die Ausgaben des Programms ausListing 10.1. Beachten Sie, dass durch die Pufferung der Standardausgabe die Rei-henfolge der Ausgaben zum Teil durcheinander gerat. Zwar sorgt LAM/MPI dafur,dass niemals die Meldung

Text von Knoten 1. i = 75

vor

Text von Knoten 1. i = 30

erscheint. Jedoch sehen wir die Fehlermeldung

Page 319: [X.systems.press] Cluster Computing ||

316 10 Debuggingmethoden und Entwicklungswerkzeuge fur MPI-Programme

Fehler von Knoten 1. i = 99

vor der Textausgabe

Text von Knoten 1. i = 99

Dies geschieht, obwohl nach der Logik von Listing 10.1 zuerst die Textmeldunghatte ausgegeben werden mussen. Auch kann es passieren, dass

Text von Knoten 1. i = 75

lange vor

Text von Knoten 2. i = 5

erscheint. Uberhaupt ist die Reihenfolge der Ausgaben unvorhersagbar und kann sichvon Programmlauf zu Programmlauf andern. Probieren Sie es aus!

Glucklicherweise ist LAM/MPI sehr flexibel und gestattet es uns, selbst die Kon-trolle uber Standardausgabe und Standardfehlerausgabe zu erlangen und so etwasOrdnung in die Ausgaben eines MPI-Programms zu bringen. Dazu mussen wir aberverstehen, was beim Start eines MPI-Programms im Detail passiert. Das Starten einesMPI-Programms erfolgt uber mpirun und die LAM/MPI-Damonen. Ein LAM/MPI-Damon muss dafur

• einen neuen UNIX-Prozess starten,• durch mpirun exportierte Umgebungsvariablen setzen,• einige LAM/MPI-interne Umgebungsvariablen (z. B. $LAMRANK) setzen,• Standardausgabe und Standardfehlerausgabe umleiten und• das an mpirun ubergebene Programm starten.

Der so gestartete Prozess (oder einer seiner Kindprozesse) muss irgendwann dieFunktion MPI Init aufrufen. Dabei kommuniziert er mit mpirun und erhaltalle notwendigen Informationen uber alle anderen Prozesse des KommunikatorsMPI COMM WORLD. So weiß schließlich jeder Prozess von jedem, die FunktionMPI Init kehrt zuruck und der Prozess lauft normal weiter.

Die Tatsache, dass nicht zwingend das Programm, das dem mpirun-Komman-do ubergeben wurde, selbst die Funktion MPI Init aufrufen muss, sondern dies

Listing 10.2. Skript stdout2files.sh zum Umleiten von Standardausgabe und Standard-fehlerausgabe.

# ! / b i n / bash

# Programmnamen e x t r a h i e r e nPNAME=‘basename $1‘

5 # Kommando mi t a l l e n w e i t e r e n Argumenten a u s f u h r e n und# S t a n d a r d f e h l e r a u s g a b e und S t a n d a r d a u s g a b e f u r j e d e n Rang u m l e i t e n”$@” > $PNAME.stdout.$LAMRANK 2> $PNAME.stderr.$LAMRANK# Return−Code w e i t e r r e i c h e nexit $?

Page 320: [X.systems.press] Cluster Computing ||

10.2 Debugger 317

auch einer dessen Kind-Prozesse tun kann, ist der Schlussel zu allen im Folgendendargestellten Debugging-Techniken. Statt eines MPI-Programms konnen wir auchein Shell-Skript an mpirun ubergeben, das seinerseits ein MPI-Programm aufruft,dabei aber noch allerhand andere magische Dinge machen kann.

Zum Beispiel konnen wir Standardausgabe und Standardfehlerausgabe einesjeden MPI-Prozesses in eine einzelne Datei umleiten, wie es das kleine Skriptstdout2files.sh in Listing 10.2 tut. Rufen wir nun

bauke@server:˜/src$ mpirun -np 4 stdout2files.sh ./debug_std

auf, so werden die Standardausgaben der gestarteten MPI-Prozesse in die vier Da-teien debug std.stdout.0 bis debug std.stdout.3 und die Standardfeh-lerausgabe in die Dateien debug std.stderr.0 bis debug std.stderr.3umgeleitet. Um fur jeden Prozess einen eindeutigen Namen fur diese Dateien zuerzeugen, setzt das Skript diesen aus dem Programmnamen, dem in der Umge-bungsvariablen $LAMRANK gespeicherten Rang sowie dem Zusatz .stdout. bzw..stderr. zusammen.

10.2 Debugger

Hat Ihr Programm eine gewisse Komplexitatsgrenze uberschritten, ist das Debug-ging uber Kontrollausgaben ungeeignet und unproduktiv, weil Sie z. B. nach jederneu eingefugten fprintf-Anweisung Ihr Programm erneut kompilieren mussen,oder weil es immer schwieriger wird, aus der Menge der Kontrollausgaben die re-levanten Informationen herauszufiltern. Mit einem Debugger werden Sie auch nochbei komplexen Programmen der Fehler Herr.

Um ein Programm mit Hilfe eines Debuggers zu untersuchen, muss man es miteiner bestimmten Option ubersetzten. Beim GNU Compiler gcc und dem Compilericc von Intel ist dies die Option -g. Dabei werden zusatzliche Informationen inder sog. Symboltabelle abgelegt. Mit diesen Informationen kann der Debugger danndem Maschinencode die entsprechenden Zeilen des Quellcodes zuordnen und kenntden Variablennamen fur die einzelnen Speicherplatze.

Unter Linux ist der GNU Debugger gdb sicher das gebrauchlichste Debugging-Werkzeug. Starten Sie beispielsweise den Debugger, um das Programm myprog ausListing 10.3 zu untersuchen.

Listing 10.3. Programm myprog.c zur Illustration der Funktionsweise eines Debuggers.

int main(void) {int a;a=1;a=2;

5 a=3;return 0;

}

Page 321: [X.systems.press] Cluster Computing ||

318 10 Debuggingmethoden und Entwicklungswerkzeuge fur MPI-Programme

bauke@node1:˜/src$ gdb -quiet ./myprog(gdb)

Dabei legt sich der Debuggers als zusatzliche Schicht zwischen Betriebssystem undProgramm. Dieses kann man nun in Einzelschritten ausfuhren, an vorgegebenen Hal-tepunkten (breakpoints) unterbrechen und den Inhalt von Variablen, Registern undSpeicherbereichen auswerten. Im folgenden Beispiel wird ein Haltepunkt in Zeile 4gesetzt, das Programm bis zu diesem Punkt ausgefuhrt, der Inhalt der Variablen aausgegeben und die Programmausfuhrung bis zum Programmende fortgesetzt. Dain Zeile 3 des Programms 10.3 die Variale a auf den Wert 1 gesetzt wird, gibt dieAnweisung print a nach Erreichen des Haltepunkt in Zeile 4 eine 1 aus.

(gdb) break 4Breakpoint 1 at 0x80483cd: file myprog.c, line 4.(gdb) runStarting program: /home/bauke/src/myprog

Breakpoint 1, main () at myprog.c:44 a=2;(gdb) print a$1 = 1(gdb) continueContinuing.

Program exited normally.(gdb) quit

Den GNU Debugger im Detail zu beschreiben, wurde den Rahmen dieses Buchessprengen. Stattdessen beschranken wir uns im Folgenden darauf, auf die Besonder-heiten beim Debuggen von MPI-Programmen einzugehen, und verweisen Sie auf[156] und [52].

Das Debuggen vom MPI-Programmen bedarf aus zwei Grunden einiger techni-scher Vorbereitungen, die bei sequentiellen Programmen nicht notwendig sind. Ers-tens benotigt jeder Prozess eines MPI-Programms seinen eigenen Debugger. Zwei-tens brauchen textbasierte Debugger (wie der GNU Debugger) wieder fur jeden derMPI-Prozesse eine eigene Standardein- und Standardausgabe, was wie oben gezeigtnormalerweise nicht gegeben ist. Separate Standardein- und Standardausgaben erhal-ten wir, indem wir jeden MPI-Prozess in einem eigenen Terminalfenster starten.

Dazu machen wir uns die Netzwerkfahigkeiten des X-Protokolls zu nutze. DasX Window System, auf dem die meisten graphischen Nutzeroberflachen auf unixar-tigen Betriebssystemen aufsetzen, basiert auf einem netzwerktransparenten Client-Server-Modell. Auf Ihrem Arbeitsplatzrechner lauft ein als X-Server bezeichne-tes Programm, das seine Dienste verschiedenen X-Clients zur Verfugung stellt. Erenthalt den Grafikkartentreiber, Treiber fur Tastatur und Maus, und kommuniziertuber das Netzwerk mit X-Clients. Diese X-Clients sind Anwendungsprogramme, diedie Dienste des X-Servers nutzen, um z. B. graphische Elemente dazustellen und vonihm diverse Ereignisse wie Tastenanschlage, Mausbewegungen und -klicks zu emp-fangen. Als netzwerktransparent wird das X Window System bezeichnet, weil es aus

Page 322: [X.systems.press] Cluster Computing ||

10.2 Debugger 319

der Sicht eines Nutzers keinen Unterschied macht, ob ein X-Client auf dem selbenRechner wie der X-Server oder irgendwo auf einem entfernten Rechner lauft.

Wo sich der X-Server, durch den ein X-Client seine graphischen Elemente dar-stellen lasst, befindet, erfahrt es durch die Umgebungsvariable $DISPLAY. DerenInhalt setzt sich aus

• einem Hostnamen oder einem leeren String,• einem Doppelpunkt,• einer Displaynummer sowie• optional einem Punkt und einer Bildschirmnummer (meist null, da nur ein Bild-

schirm vorhanden)

zusammen. Ist der Hostname leer, so kommuniziert der X-Client uber sog. Unix Do-main Sockets mit dem X-Server, der auf dem selben Computer lauft wie der X-Client.Ist der Hostname hingegen nicht leer, so kommunizieren X-Client und X-Server uberdas TCP-Protokoll. Die dabei verwendete Portnummer ist gleich 6000 plus der Dis-playnummer. Die Displaynummer ist meist null, kann aber auch einen anderen Werthaben, falls mehrere X-Server auf einem Computer laufen.

Angenommen Ihr Arbeitsplatzrechner heißt newton und Sie haben sich mit rshvon newton auf den Rechner leibniz eingeloggt, so konnen Sie, nachdem Sie die$DISPLAY-Variable gesetzt haben, auf leibniz ein Terminalfenster starten, das aufnewton angezeigt wird. Zuvor mussen wir aber noch dem X-Server erlauben, An-fragen von auf leibniz laufenden X-Clients anzunehmen. Dies geschieht mit demProgramm xhost.

bauke@newton:˜$ xhost +leibnizleibniz being added to access control listbauke@newton:˜$ rsh leibnizbauke@leibniz:˜$ export DISPLAY=newton:0bauke@leibniz:˜$ xterm &[1] 27016bauke@leibniz:˜$

Spater konnen Sie den Zugriff auf den X-Server wieder einschranken.

bauke@newton:˜$ xhost -leibnizleibniz being removed from access control list

Die Secure Shell kummert sich (sofern ssh-Server und ssh-Client entsprechend kon-figuriert sind) selbst um das Setzen der $DISPLAY-Variablen und die Authentifizie-rung gegenuber dem X-Server. Sie konnen diese Funktion aber durch die Option -xabschalten und obiges Beispiel so auch mit ssh statt mit rsh nachvollziehen. Ver-tiefende Informationen zum Programm xhost finden Sie in [175]. Lasst sich dasTerminalfenster nicht gemaß obiger Anleitung offnen, wurden moglicherweise dieNetzwerkfahigkeiten Ihres X-Servers deaktiviert (Notiz 10.1).

Mit diesem Grundlagenwissen uber das X Window System und den Mechanis-mus, mit dem LAM/MPI MPI-Programme startet (siehe Abschnitt 10.1), konnen wirjeden Prozess in einem eigenen Terminalfenster bzw. Debugger starten. Wir nehmen

Page 323: [X.systems.press] Cluster Computing ||

320 10 Debuggingmethoden und Entwicklungswerkzeuge fur MPI-Programme

Listing 10.4. Skript lam xhost.sh zur Steuerung des Zugriffs auf lokalen X-Server.

# ! / b i n / bash

# Kommandozei lenargumente t e s t e nif [ $# −ne 1 −o ” $1 ” != ”−−add ” −a ” $1 ” != ”−−remove ” ] ; t h e n

5 echo $0: falsche Parameter oder Parameterzahl >&2else

# LAM/ MPI Hos t s e r m i t t e l nHOSTS=‘lamnodes -n -c 2> /dev/null‘# Hos t s Z u g r i f f a u f l o k a l e n X−S e r v e r e r l a u b e n ode r v e r b i e t e n

10 for i in $HOSTS; doif [ $1 = ”−−add ” ]; then xhost +$i; else xhost -$i; fi

donefi

an, dass der Cluster ein Network of Workstations (siehe Abschnitt 4.10) mit den Com-putern newton, bohr, goedel und leibniz ist und Sie am Computer newton arbeiten.Zunachst sind naturlich die LAM-Damone auf den (in der Datei nodes gelisteten)Knoten zu starten.

bauke@newton:˜/src$ lamboot -v nodes

LAM 7.0.6/MPI 2 C++/ROMIO - Indiana University

n-1<1936> ssi:boot:base:linear: booting n0 (newton)n-1<1936> ssi:boot:base:linear: booting n1 (bohr)n-1<1936> ssi:boot:base:linear: booting n2 (goedel)n-1<1936> ssi:boot:base:linear: booting n3 (leibniz)n-1<1936> ssi:boot:base:linear: finished

Danach erlauben wir X-Clients aller Knoten, auf die Dienste des auf newtonlaufenden X-Servers zuzugreifen. Dies konnen Sie wie oben gezeigt mit xhost furjeden Knoten von Hand machen, oder Sie verwenden das in Listing 10.4 gezeigteSkript lam xhost.sh. Je nachdem ob es mit der Option --add oder --removeaufgerufen wird, wird den Knoten, auf denen gerade ein LAM/MPI Damon lauft, derZugriff auf den lokalen X-Server gestattet oder wieder verboten. Das Skript wertetdazu in Zeile 8 die Informationen des Programms lamnodes aus und setzt in derSchleife in den Zeilen 10 bis 12 die Zugriffsrechte.

bauke@newton:˜/src$ lam_xhost.sh --addnewton.our-domain.org being added to access control listbohr.our-domain.org being added to access control listgoedel.our-domain.org being added to access control listleibniz.our-domain.org being added to access control list

Setzen wir nun noch die $DISPLAY-Variable, so haben wir alle Grundvorausset-zungen geschaffen, um jeden Prozess eines MPI-Programms in einem eigenen Ter-minalfenster laufen zu lassen. Ahnlich wie in Abschnitt 10.1 nutzen wir dazu wiederein Shellskript, das seinerseits das eigentliche MPI-Programm startet. Das in Lis-ting 10.5 gezeigte Skript run in xterm.sh startet in Zeile 15 ein Terminalfenster,in dem ein Prozess des MPI-Programms lauft.

Page 324: [X.systems.press] Cluster Computing ||

10.2 Debugger 321

Listing 10.5. Skript run in xterm.sh zum Starten von MPI-Prozessen in separaten Termi-nalfenstern.

# ! / b i n / bash

TITLE=” Rang $LAMRANK a u f $HOSTNAME”;if [ $1 = --only ]; then

5 # nur a u s g e s u c h t e Range i n xterm s t a r t e nif echo $2 | grep -Eq ’(ˆ|,)’$LAMRANK’($|,)’; then

shift 2xterm -T ”$TITLE” -e ”$@”

else10 shift 2

”$@”fi

else# a l l e Range i n xterm s t a r t e n

15 xterm -T ”$TITLE” -e ”$@”fiexit 0

bauke@newton:˜/src$ export DISPLAY=newton:0bauke@newton:˜/src$ mpirun -np 4 -x DISPLAY run_in_xterm.sh ./my_mpi_prog

Beachten Sie, dass wir mit der Option -x DISPLAY das Programm mpirun ange-wiesen haben, die Umgebungsvariable $DISPLAY an alle durch mpirun gestarte-ten Prozesse zu vererben, siehe Manpage mpirun(1). Damit Sie vor lauter Terminal-fenstern nicht die Ubersicht verlieren, vermerkt das Skript im Titel des Terminalfens-ters den Rang des Prozesses sowie den Namen des Knotens, auf dem der jeweiligeProzess lauft.

Als besonderen Clou testet das Skript 10.5 in Zeile 4, ob das erste Kommando-zeilenargument --only heißt. Ist dies der Fall, wertet es in Zeile 6 auch noch daszweite Kommandozeilenargument aus, um nur die dort angegebenen Prozesse desMPI-Programms in einem Terminal zu starten. Dazu ist im zeiten Argument einedurch Kommata separierte Liste von Rangen anzugeben. Im folgenden Beispiel wirddas Programm my mpi prog mit insgesammt vier Prozessen gestartet, aber nur dieProzesse mit den Rangen eins und drei laufen in einem Terminalfenster.

bauke@newton:˜/src$ mpirun -np 4 -x DISPLAY run_in_xterm.sh --only 1,3 \> ./my_mpi_prog

Listing 10.6 zeigt das Skript run in gdb.sh. Es ist in Aufbau und Funktionmit dem Skript run in xterm.sh fast identisch, nur startet es einen MPI-Pro-zess in einem Debugger, der selbst in einem eigenen Terminalfenster lauft. Naturlichkonnten Sie statt eines textbasierten Debuggers wie den GNU Debugger gdb aucheinen Debugger mit graphischer Oberflache starten, z. B. den Data Display Debuggerddd. Dazu mussen Sie nur die Zeilen 8 und 15 in Listing 10.6 in

ddd ”$@”

andern.

Page 325: [X.systems.press] Cluster Computing ||

322 10 Debuggingmethoden und Entwicklungswerkzeuge fur MPI-Programme

Listing 10.6. Skript run in gdb.sh zum Starten von MPI-Prozessen in separaten Terminal-fenstern laufenden GNU Debuggern.

# ! / b i n / bash

TITLE=” Rang $LAMRANK a u f $HOSTNAME”;if [ $1 = --only ]; then

5 # nur a u s g e s u c h t e Range i n xterm s t a r t e nif echo $2 | grep -Eq ’(ˆ|,)’$LAMRANK’($|,)’; then

shift 2xterm -T ”$TITLE” -e gdb ”$@”

else10 shift 2

”$@”fi

else# a l l e Range i n xterm s t a r t e n

15 xterm -T ”$TITLE” -e gdb ”$@”fiexit 0

10.3 Profiler

Nachdem Sie mit Hilfe des Debuggers Ihr Programm von allen Fehlern bereinigthaben, mochten Sie sicher noch das Laufzeitverhalten des Programms optimieren.Eine alte Faustregel besagt, dass ein Programm ca. 90 % seiner Laufzeit in 10 % desProgrammcodes verbringt. Ein Profiler gibt an, wie lange ein Programm in einzelnenFunktionen verbracht hat und wie oft diese aufgerufen wurden. Mit Hilfes eines Profi-lers konnen Sie also herausfinden, welche Funktionen Ihres Programms zu besagten10 % Programmcode gehoren und dann diese Funktionen gezielt optimieren.

Der GNU Profiler gprof ist unter Linux sicher der meist verwendete Profiler.Damit dieser das Laufzeitverhalten eines Programms analysieren kann, muss es miteiner speziellen Compiler-Option ubersetzt werden. Beim GNU Compiler gcc unddem Compiler icc von Intel ist dies die Option -pg. Als Beispiel wollen wir dasProgramm int.c aus Listing 10.7 analysieren, hierbei handelt es sich um eine se-quentielle Variante der Integrationsprogramme in Listing 3.1 bzw. 3.2.

bauke@server:˜/src$ icc -o int -pg int.c pintegral.c -lmbauke@server:˜/src$ ./int 1000000010000000 Stuetzst., 1 Proz. Zeit 1.16 Sek, Ergebnis 0.7853981634

Startet man ein mit der Option -pg ubersetztes Programm, so erzeugt es bei jedemLauf eine Datei gmon.out. Diese enthalt samtliche Profiling-Informationen ausdem letzten Programmlauf. Der GNU Profiler muss diese Daten fur uns nur nochaufbereiten. Dazu ist gprof mit dem Programm, das die Profiling-Informationenerzeugt hat, und die Profiling-Datei gmon.out aufzurufen.

Page 326: [X.systems.press] Cluster Computing ||

10.3 Profiler 323

bauke@server:˜/src$ gprof --flat-profile --brief int gmon.outFlat profile:

Each sample counts as 0.01 seconds.% cumulative self self totaltime seconds seconds calls ms/call ms/call name92.96 0.66 0.66 10000000 0.00 0.00 f7.04 0.71 0.05 1 50.00 710.00 pintegral

Hier haben wir gprof nur nach dem sog. flat profile befragt. Durch die zusatzlichenOptionen --flat-profile und --brief gibt der GNU Profiler nur eine kurzeZusammenfassung der Profiling-Daten aus. Es zeigt sich, dass das Programm int.cdie meiste Zeit damit verbringt, die zu integrierende Funktion f auszuwerten. DerGNU Profiler kann uns aber noch viel detailreichere Analysen des Laufzeitverhaltensgeben, genaueres finden Sie dazu in der Manpage gprof(1).

Naturlich konnen mit dem GNU Profiler auch MPI-Programme untersucht wer-den. Allerdings haben wir hier das Problem, dass alle Prozesse gleichzeitig versu-chen wurden, die Datei gmon.out zu erzeugen. Jedoch konnen wir die Umge-bungsvariable $GMON OUT PREFIX nutzen, um fur jeden Prozess einen eindeuti-gen Namen fur die Profiling-Datei zu erzeugen. Ist diese Variable gesetzt, so wirdstatt einer Datei namens gmon.out eine mit einem Namen, der sich aus dem In-halt von $GMON OUT PREFIX, einem Punkt und der Prozess-ID zusammensetzt, er-zeugt. Listing 10.8 zeigt das Skript run for gprof.sh, das der Umgebungsvaria-ble $GMON OUT PREFIX einen Wert zuweist, der sich aus dem Prafix gmon., dem

Listing 10.7. Programm int.c zur sequentiellen numerischen Integration.

#include <stdio.h>#include <stdlib.h>#include <math.h>#include <time.h>

5double pintegral(double (*f)(double), double a, double b,

long n, int k, int tasks); / * s i e h e p i n t e g r a l . c * /

double f(double x) {10 return sqrt(1.0-x*x);

}

int main (int argc, char *argv[]) {double result, x, T;

15 long n=1000000;

if (argc==2)n=atol(argv[1]);

T=(double)clock()/(double)CLOCKS_PER_SEC;20 result=pintegral(f, 0.0, 1.0, n, 0, 1);

T=(double)clock()/(double)CLOCKS_PER_SEC-T;printf(”%l d S t u e t z s t . , %d Proz . Z e i t %6.4g Sek , E r g e b n i s %15.12g\n ”,

n, 1, T, result);return EXIT_SUCCESS;

25 }

Page 327: [X.systems.press] Cluster Computing ||

324 10 Debuggingmethoden und Entwicklungswerkzeuge fur MPI-Programme

Listing 10.8. Das Skript run for gprof.sh startet MPI-Programme und erzeugt Profiling-Dateien.

# ! / b i n / bash

# Programmnamen e x t r a h i e r e nPNAME=‘basename $1‘

5 # Dateinamen f u r P r o f i l i n g −D a t e i s e t z e nexport GMON_OUT_PREFIX=”gmon .$PNAME.$LAMRANK”# Kommando mi t a l l e n w e i t e r e n Argumenten a u s f u h r e n”$@”# Return−Code w e i t e r r e i c h e n

10 exit $?

Programmnamen sowie dem Rang des MPI-Prozesses zusammensetzt. Hier ein Bei-spiel zur Verwendung des run for gprof.sh-Skripts fur die MPI-Version desIntegrationsprogrammes (Listing 3.2):

bauke@server:˜/src$ mpicc -pg -o mpiint mpiint.c pintegral.c -lmbauke@server:˜/src$ mpirun -np 2 run_for_gprof.sh ./mpiint 1000000010000000 Stuetzst., 2 Proz. Zeit 0.5798 Sek, Ergebnis 0.7853981634

Im (netzweiten) Heimatverzeichnis finden wir nun zwei verschiedene Profiling-Dateien, die wir wieder durch gprof aufbereiten lassen konnen.

bauke@server:˜/src$ ls -l gmon.mpiint.*-rw-r--r-- 1 bauke bauke 124533 27. Okt 18:56 gmon.mpiint.0.11413-rw-r--r-- 1 bauke bauke 124533 27. Okt 18:56 gmon.mpiint.1.756bauke@server:˜/src$ gprof --flat-profile --brief mpiint gmon.mpiint.1.756Flat profile:

Each sample counts as 0.01 seconds.% cumulative self self totaltime seconds seconds calls ms/call ms/call name93.94 0.31 0.31 5000000 0.00 0.00 f6.06 0.33 0.02 1 20.00 330.00 pintegral

Der GNU Profiler ist naturlich nicht das einzige Profilingwerkzeug. Wem diezahlreichen Kommandozeilenparameter von gprof zu unubersichtlich sind, wirdsich vielleicht mit dem KDE-Programm KProf anfreunden konnen. Daneben gibtes noch einige interessante kommerzielle Programme zur Laufzeitanalyse, wie denDebugger idb, der mit den Compilern von Intel geliefert wird, und den VTune Per-formance Analyser von Intel oder Purify Plus von IBM.

10.4 XMPI

In parallelen Programmen treten manchmal Fehler auf, die mit herkomlichen Debug-gern nur schwer zu analysieren sind. Dazu gehoren Fehler in der zeitlichen Koor-dination des Nachrichtenaustauschs wie z. B. deadlocks, die immer dann auftreten,wenn alle Prozesse zwar auf Nachrichten warten aber kein Prozess eine passende

Page 328: [X.systems.press] Cluster Computing ||

10.4 XMPI 325

Abb. 10.1. Build&Run-Dialog der X Window Nutzer-Schnittstelle XMPI.

Nachricht versendet. Um den zeitlichen Verlauf der Kommunikation zu untersuchen,werden spezielle Werkzeuge benotigt.

Fur die LAM/MPI-Implementation ubernimmt das Programm XMPI diese Auf-gabe. XMPI ist ein Programm mit graphischer Oberflache, mit dem MPI-Program-me gestartet und MPI-Prozesse und Nachrichten uberwacht werden konnen. XMPIgehort nicht zum Standardumfang der LAM/MPI-Distribution und muss daher zusatz-lich von [89] heruntergeladen und gemaß der Anleitung in der Datei INSTALL ein-gerichtet werden. Haben Sie die Installation erfolgreich gemeistert, prasentiert sichdas Programm nach seinem Start wie in Abb. 10.1 links gezeigt.

XMPI visualisiert den Kommunikationsstatus von MPI-Programmen. Dies kannsowohl wahrend der Programmausfuhrung als auch nachtraglich durch Auswertungeiner Trace-Datei geschehen. In solch einer Trace-Datei protokolliert das LAM/MPI-System alle Nachrichtentranfers zwischen allen Prozessen eines MPI-Programms,die wahrend seiner Ausfuhrung aufgetreten sind. Wir wollen die Funktionsweise vonXMPI am Beispiel des Programms in Listing 10.9 veranschaulichen. In einer Schlei-fe empfangt hier der Prozess null nacheinander Nachrichten von den Prozessen einsund zwei.

Zunachst mussen wie gewohnt das MPI-Programm ubersetzt und die LAM/MPI-Damone gestartet werden.

bauke@server:˜/src$ lamboot nodes

LAM 7.0.6/MPI 2 C++/ROMIO - Indiana University

bauke@server:˜/src$ mpicc -o xmpi-demo xmpi-demo.c

Danach konnen Sie XMPI unter Angabe des aktuellen Bootschemas aufrufen.

Page 329: [X.systems.press] Cluster Computing ||

326 10 Debuggingmethoden und Entwicklungswerkzeuge fur MPI-Programme

Listing 10.9. Beispielprogramm xmpi-demo.c zur Kommunikationsanalyse mit XMPI.

#include <stdlib.h>#include <unistd.h>#include ” mpi . h ”

5 int main(int argc, char *argv[]) {const int cnt=100000;int rank, size, p[cnt], i;MPI_Status status;

10 MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD, &rank);MPI_Comm_size(MPI_COMM_WORLD, &size);for (i=0; i<5; ++i) {

if (rank==0) {15 MPI_Recv(p, cnt, MPI_INT, 1, 101, MPI_COMM_WORLD, &status);

usleep(500000);MPI_Recv(p, cnt, MPI_INT, 2, 102, MPI_COMM_WORLD, &status);

} else if (rank==1) {MPI_Send(p, cnt, MPI_INT, 0, 101, MPI_COMM_WORLD);

20 usleep(500000);} else if (rank==2) {

MPI_Send(p, cnt, MPI_INT, 0, 102, MPI_COMM_WORLD);usleep(500000);

}25 usleep(500000);

MPI_Barrier(MPI_COMM_WORLD);usleep(500000);

}MPI_Finalize();

30 return EXIT_SUCCESS;}

bauke@server:˜/src$ xmpi nodes

Wahlen Sie nun den Punkt Browse&Run im Menu Application, um festzulegen, wel-ches MPI-Programm auf welchen Knoten zu starten ist, siehe Abb. 10.1. Außerdemkonnen hier verschiedene Optionen, die Eigenschaften der LAM/MPI-Umgebungbeeinflussen, gewahlt werden. Da wir im Folgenden die Kommunikation des Pro-gramms in Listing 10.9 uberwachen wollen, aktivieren wir die Optionen LAM Tra-cing Enabled und LAM Tracing Initially On. Mit Save kann man eine in diesemMenupunkt erstellte Konfiguration (im LAM/MPI-Jargon application schema ge-nannt, siehe Manpage appschema(5)) abspeichern, mit Load spater wieder ladensowie mit Run ausfuhren.

Sobald ein MPI-Programm in XMPI gestartet wurde, erscheinen im XMPI-Hauptfenster mehrere sechseckige Kacheln, von denen jede einen Rang des Kom-munikators MPI COMM WORLD reprasentiert. In jeder Kachel ist der Rang des ent-sprechenden Prozesses vermerkt, eine Verkehrsampel gibt Auskunft uber den mo-mentanen Status eines Prozesses. Ist sie grun, so rechnet der Prozess, ist sie rot, soist der Prozess blockiert, weil er auf eine Nachricht wartet. Ist die Ampel gelb, so hatder Prozess gerade eine MPI-Funktion aufgerufen, ist aber nicht durch noch ausste-

Page 330: [X.systems.press] Cluster Computing ||

10.4 XMPI 327

Abb. 10.2. Kommunikationsanalyse des Programms in Listing 10.9 mit XMPI.

hende Nachrichten blockiert. Die Zeit, die ein Prozess im gelben Zustand verbringt,ist ein Maß fur den Zusatzaufwand, der durch das MPI-Protokoll entsteht.

Bevor Sie die Kommunikation des gerade ausgefuhrten oder noch laufenden Pro-gramms analysieren konnen, mussen Sie durch den Punkt Dump im Menu Trace dasKommunikatiosprotokoll in eine Datei abspeichern und mit View wieder laden. PerKonvention enden Kommunikationsprotokolldateien auf .lamtr. Der MenupunktExpress ist eine Kombination aus Dump und View. Durch ihn wird das Kommunikati-onsprotokoll in eine temporare Datei geschrieben und eingelesen. Alternativ konnenSie auch den trace-Button nutzen. Naturlich lassen sich mit View auch die Kommu-nikationsprotokolle alterer Programmlaufe immer wieder laden und erneut untersu-chen.

Haben Sie nun des Menupunkt View oder Express ausgewahlt, so offnet sich dasTimeline-Fenster, siehe Abb. 10.2 rechts unten. Das Timeline-Fenster gibt einen Uber-blick uber den zeitlichen Kommunikationsverlauf eines Programms, indem es denZustand eines jeden Prozesses als Funktion der Zeit zeigt. Durch die Buttons im obe-ren Bereich des Timeline-Fensters konnen Sie die Skalierung der Zeitachse andern(zoomen) oder sich einen ”Film“ des Kommunikationsprotokolls ansehen. Mit derlinken Maustaste lasst sich der weiße wagerechte Balken im Timeline-Fenster ver-schieben und so ein Zeitpunkt auswahlen, zu dem Sie nahere Informationen erhaltenmochten.

In Abb. 10.2 haben wir einen Zeitpunkt bei ca. 2,9 s gewahlt. Da die Linien al-ler Prozesse rot hinterlegt sind, waren zu diesem Zeitpukt offensichtlich alle mitdem Empfangen oder Senden von Daten beschaftigt. Durch einen Klick auf die bei-den Sechsecke 0 und 1 im Hauptfenster offnen sich zwei zusatzliche Fenster, sieheAbb. 10.2 rechts oben. Zu jedem Zeitpunkt, an dem ein Prozess blockiert ist, zeigtdiese Fenster die blockierende Funktion (z. B. MPI Send oder MPI Recv), denRang, an den Daten geschickt bzw. von dem Daten erwartet werden, den Kommuni-

Page 331: [X.systems.press] Cluster Computing ||

328 10 Debuggingmethoden und Entwicklungswerkzeuge fur MPI-Programme

kator, das Etikett der Nachricht (tag) und die Anzahl der Elemente der Nachricht an.Falls fur einen Prozess zum ausgewahlten Zeitpunkt noch Nachrichten vorliegen, dienoch nicht vollstandig empfangen wurden, so werden auch deren Anzahl, Quellrang,Kommunikator, das Etikett der Nachricht und die Anzahl der Elemente der Nachrichtangezeigt.

Mit einem Klick auf den matrix-Button im XMPI-Hauptfenster offnet sich einweiteres nutzliches Fenster, siehe Abb. 10.2 links unten. Es zeigt in einer Matrix,wieviele Nachrichten momentan von einem Quellrang zu einem Zielrang unterwegssind. Zum in Abb. 10.2 gewahlten Zeitpunkt senden jeweils die Prozesse mit denRangen eins und zwei eine Nachricht zum Prozess null. Dass fur den Prozess nullnoch insgesamt zwei Nachrichten unterwegs sind, konnen Sie auch der ”2“ nebender Ampel in der dem Prozess null zugeordneten Kachel im XMPI-Hauptfensterentnehmen.

Im XMPI-Hauptfenster findet sich noch ein mit kiviat beschrifteter Button. Er off-net das Kiviat-Fenster, das eine Art Effizienzanalyse in Form eines Tortendiagrammsdarstellt. Es zeigt das Verhaltnis von mit Arbeit verbrachter Zeit, zu der Zeit, diedie Prozesse mit Senden oder Empfangen von Daten bis zum aktuellen Zeitpunktbeschaftigt waren. Die Dokumentation weiterer weniger wichtiger Funktionen fin-den Sie in der Manpage xmpi(1). Die Erstellung einer Trace-Datei kann nicht nurdurch XMPI sondern auch durch mpirun oder das MPI-Programm selbst gesteuertwerden. Naheres erfahren Sie dazu in der LAM/MPI-Dokumentation und der Man-page mpirun(1).

10.5 Namen fur MPI-Objekte

Graphische MPI-Debugger wie XMPI zeigen dem Nutzer u. a. an, welche Daten vonwelchem MPI-Typ in welchem Kommunikator ausgetauscht werden. Solange es sichdabei um Standard-MPI-Typen und den Kommunikator MPI COMM WORLD handelt,kann der Debugger diese Typen auch textlich anzeigen, siehe Abb. 10.2. Bei zurLaufzeit erzeugten Kommunikatoren und Datentypen ist dies nicht ohne Weiteresmoglich. Stattdessen zeigt der Debugger hier nur einen (meist kryptischen) Namenaus den Eingeweiden der MPI-Bibliothek an.

In MPI-2 werden allerdings Funktionen eingefuhrt, mit denen Kommunikatorenund Datentypen textuelle Namen zugeordnt werden konnen. Diese haben die folgen-den Prototypen:

int MPI_Comm_set_name(MPI_Comm comm, char *comm_name)int MPI_Comm_get_name(MPI_Comm comm, char *comm_name, int *resultlen)int MPI_Type_set_name(MPI_Datatype type, char *type_name)int MPI_Type_get_name(MPI_Datatype type, char *type_name, int *resultlen)

Mit den Funktionen MPI Comm set name und MPI Type set name lassen sichKommunikatoren bzw. Datentypen benennen, und mit MPI Comm get name undMPI Type get name wieder abfragen. Im dritten Argument resultlen wird je-weils die Lange des Namens hinterlegt. Die vom Programmierer vergebenen Namen

Page 332: [X.systems.press] Cluster Computing ||

10.5 Namen fur MPI-Objekte 329

Listing 10.10. Das Beispielprogramm type name.c gibt Kommunikatoren und MPI-Daten-typen aussagekraftige Namen.

#include <stdlib.h>#include <stdio.h>#include <time.h>#include <string.h>

5 #include ” mpi . h ”

int main(int argc, char *argv[]) {time_t t;char str[256];

10 int rank;MPI_Comm Universum;MPI_Datatype String256;MPI_Init(&argc, &argv);MPI_Comm_dup(MPI_COMM_WORLD, &Universum);

15 MPI_Comm_rank(Universum, &rank);MPI_Type_contiguous(256, MPI_CHAR, &String256);MPI_Type_commit(&String256);MPI_Type_set_name(String256, ” Z e i c h e n k e t t e mi t 255 Ze ichen ”);MPI_Comm_set_name(Universum, ”MPI Universum ”);

20 if (rank==0) {t=time(NULL);strncpy(str, ctime(&t), 256);

}MPI_Bcast(str, 1, String256, 0, Universum);

25 printf(” rank %i : %s ”, rank, str);MPI_Comm_free(&Universum);MPI_Type_free(&String256);MPI_Finalize();

}

durfen inklusive terminierender Null maximal MPI MAX OBJECT NAME Zeichenlang sein.

Listing 10.10 zeigt die Verwendung dieser Funktionen. In diesem Programmwird dem Kommunikator Universum der Name MPI Universum zugewiesenund der selbstdefinierte Datentyp String256 erhalt den Namen Zeichenkettemit 255 Zeichen. Wenn Sie das Programm nun in XMPI starten und analysie-ren, so sehen Sie, dass die Broadcast-Funktion im Kommunikator MPI Universum

Abb. 10.3. Wird dem Kommunikator Universum kein Name zugewiesen, so protokolliertXMPI nur, dass die Broadcast-Funktion im Kommunikator zwei aufgerufen wird (links). MitMPI Comm set name erhalt der Kommunikator einen aussagekraftigen Namen (Mitte). Denmit MPI Type set name gesetzten Namen ignoriert XMPI higengen (rechts).

Page 333: [X.systems.press] Cluster Computing ||

330 10 Debuggingmethoden und Entwicklungswerkzeuge fur MPI-Programme

aufgerufen wird, siehe Abb. 10.3. Den durch MPI Type set name gesetzten Na-men fur den selbstdefinierten Datentyp berucksichtigt XMPI leider nicht und zeigtstattdessen MPI CONTIG (256) MPI CHAR an.

Wann immer Sie in Ihren MPI-Programmen selbstdefinierte Kommunikatorenoder Datentypen verwenden, sollten Sie ihnen auch einen aussagekraftigen Namengeben. Die Performance der Kommunikationsrourinen wird dadurch in keiner Weisebeeinflusst aber das Debugging gestaltet sich komfortabler.

10.6 Notizen

10.1 Sicherheit. Falls die Darstellung von entfernten X-Client-Programmen auf demlokalen X-Server nicht wie in Abschnitt 10.1 beschieben funktioniert, schauen Siemit ps xa | grep X11/X nach, mit welchen Kommandozeilenargumenten derlokale X-Server gestartet wurde. Viele Linux-Distributionen starten aus Sicherheits-grunden den X-Server standardmaßig mit der Option -nolisten tcp und deak-tivieren somit seine Netzwerkfahigkeiten. Sollte das bei Ihnen der Fall sein, mussenSie dafur sogen, dass der X-Server ohne diese Option gestartet wird. Meist geschiehtdies durch einen sog. Displaymanager wie den GDM oder den KDM. Sie mussendie Konfigurationsdateien des Displaymanagers so modifizieren, dass der X-Servernicht mehr mit der Option -nolisten tcp gestartet wird. Je nach Linux-Distri-bution liegen die Konfigurationsdateien an unterschiedlichen Orten. Unter DebianGNU/Linux liegen sie in /etc/X11/gdm/ bzw. /etc/X11/kdm/, bei SuSE un-ter /etc/opt/kde3/share/config/kdm/.

10.2 Debugger auf dediziertem Cluster starten. Arbeiten Sie auf einem dedizier-ten Cluster (wie unserem Beispiel-Cluster aus Abschnitt 5.2) statt auf einem Networkof Workstations, so funktioniert der in Abschnitt 10.2 dargestellte Ansatz nicht oh-ne Weiteres. In solch einem Szenario loggen Sie sich von Ihrem Arbeitsplatzrechner(Nennen wir ihn office.) auf dem Frontend-Knoten server ein. Die Terminals, in de-nen die Debugger laufen, werden auf den internen Knoten gestartet. Diese Knotensind aber von außerhalb des Clusters gar nicht sichtbar, weshalb Sie nicht einfachmit xhost +node1 die Darstellung eines Terminalfensters gestatten konnen.

Um dieses Problem zu meistern, konnen wir die Moglichkeit des Portforwardingder Secure Shell nutzen. Tragen Sie dazu in die SSH-Server-Konfigurationsdatei/etc/ssh/sshd config des Frontend-Knotens die Zeilen

X11Forwarding yesGatewayPorts yesX11DisplayOffset 10X11UseLocalhost yes

5 AllowTcpForwarding yes

ein und starten Sie den SSH-Server neu. Wenn Sie sich mit folgendem Komman-do auf dem Frontend-Server Ihres Clusters anmelden, so startet die SSH auf demFrontend-Server einen Pseudo-X-Server mit der Displaynummer 1, der uber denPort 6001 kommuniziert. Außerdem werden alle Pakete, die an den SSH-Pseudo-X-Server gehen, an den lokalen X-Server Ihres Burorechners office weitergeleitet.

Page 334: [X.systems.press] Cluster Computing ||

10.6 Notizen 331

bauke@office:˜$ ssh -X -R 6001:localhost:6000 [email protected]’s password:

Damit der lokale X-Server Ihres Burorechners die Daten des SSH-Pseudo-X-Serversauch annimmt, darf er nicht mit der Option -nolisten tcp gestartet wordensein. Außerdem muss der Secure Shell der Zugriff auf den lokalen X-Server gestattetwerden.

bauke@office:˜$ xhost +localhostlocalhost being added to access control list

Nun konnen Sie sich endlich auf einen internen Knoten einloggen und ein Terminal-fenster starten, das auf Ihrem Burorechner dargestellt wird.

bauke@server:˜$ rsh node1bauke@node1:˜$ export DISPLAY=server:1bauke@node1:˜$ xterm &

Der Nachteil dieser Methode ist, dass sie nicht automatisch fur mehrere Benutzerfunktioniert. Ein weiterer Nutzer, der gleichzeitig Fenster von Programmen, die aufinternen Knoten laufen, auf seinem Burorechner darstellen mochte, muss statt 6001die Portnummer 6002 und statt 1 die Displaynummer 2 verwenden, ein dritter 6003und 3 und so fort.

10.3 Multi-Processing Environment (MPE). Das Multi-Processing Environmentist eine Sammlung von Programmen und Bibliotheken zur Analyse von MPI-Pro-grammen und stellt eine ganz ahnliche Funktionalitat wie die von XMPI bereit, ist imGegensatz zu XMPI aber nicht von einer speziellen MPI-Implementation abhangig.MPE ist zwar Bestandteil von MPICH [107], lasst sich aber auch mit anderen MPI-Implementationen verwenden.

Wenn Sie Ihre Programme mit MPE analysieren wollen, mussen diese gegenspezielle Bibliotheken gelinkt werden, die verschiedene Aufgaben erfullen.

Tracing-Bibliothek. Ein gegen die MPE-Tracing-Bibliothek gelinktes Programmverfolgt die Aufrufe aller MPI-Funktionen. Vor und nach jedem Aufruf einerMPI-Funktion wird ein kurzer Kommentar auf die Standardausgabe geschrieben.Terminal Session 10.2 zeigt den Programmlauf des Integrationsprogramms ausListing 3.2, wenn Letzteres gegen die MPE-Tracing-Bibliothek libtmpe.agelinkt wurde. Beachten Sie, dass keine Anderungen am Quelltext notwen-dig waren, um diese Ausgaben zu erhalten, denn MPE setzt auf dem in Ab-schnitt 7.6.4 vorgestellten Profiling-Interface auf.

Grafikbibliothek. Mit den Funktionen der MPE-Grafikbibliothek lassen sich einfa-che Echtzeitanimationen erstellen.

Logging-Bibliotheken. Die Tracing-Bibliothek protokolliert samtliche MPI-Funkti-onen. Das ist oft zu viel des Guten und kann ein MPI-Programm erheblich aus-bremsen. Mit den Funktionen der Logging-Bibliotheken lassen sich gezielt in-teressante Programmabschnitte protokollieren. Die Protokolldaten werden abernicht auf die Standardausgabe sondern in eine Datei geschrieben. Diese lasst

Page 335: [X.systems.press] Cluster Computing ||

332 10 Debuggingmethoden und Entwicklungswerkzeuge fur MPI-Programme

Terminal Session 10.2. Bei Verwendung der MPE-Tracing-Bibliothek werden alle Aufrufevon MPI-Funktionen protokolliert.bauke@server:˜/mpi/src$ mpicc -o mpiint mpiint.c pintegral.c -ltmpebauke@server:˜/mpi/src$ mpirun -np 2 mpiintStarting MPI_Init...Starting MPI_Init...[0] Ending MPI_Init[0] Starting MPI_Comm_size...[0] Ending MPI_Comm_size[0] Starting MPI_Comm_rank...[0] Ending MPI_Comm_rank[0] Starting MPI_Recv with count = 1, source = 1, tag = 99...[1] Ending MPI_Init[1] Starting MPI_Comm_size...[1] Ending MPI_Comm_size[1] Starting MPI_Comm_rank...[1] Ending MPI_Comm_rank[1] Starting MPI_Send with count = 1, dest = 0, tag = 99...[0] Ending MPI_Recv from 1 with tag 991000000 Stuetzst., 2 Proz. Zeit 0.03385 Sek, Ergebnis 0.785398163484[0] Starting MPI_Finalize...[0] Ending MPI_Finalize[1] Ending MPI_Send[1] Starting MPI_Finalize...[1] Ending MPI_Finalize

sich nach dem Programmlauf mit dem grafischen Java-Programm jumpshot,das in seiner Funktionalitat mit XMPI vergleichbar ist, analysieren.

10.4 Kommerzielle MPI-Debugger. Fur sehr anspruchsvolle Entwickler, denen dieMoglichkeiten von XMPI oder MPE nicht ausreichen, konnte Intels Trace Analyzer[169] eine mogliche Alternative sein. Trace Analyzer ist eine Weiterentwicklung desProgramms Vampir der deutschen Firma Pallas. Anders als XMPI ist Trace Analyzernicht von einer bestimmten MPI-Implementation abhangig, sondern kann mit jederstandardkonformen MPI-Implementation verwendet werden.

Ein weiteres kommerzielles Produkt ist TotalView [168] der Firma Etnus. To-talView lauft auf verschiedenen Unixplattformen und unterstutzt Threads, MPI,OpenMP, C, C++ und Fortran. Damit mit TotalView MPI-Programme analysierenkann, muss die MPI-Implementation auf die Verwendung dieses Debuggers abge-stimmt sein. Bei LAM/MPI, MPICH und einigen kommerziellen MPI-Implementa-tionen ist dies der Fall.

10.5 MPI-Plugin fur KDevelop. Unter [105] finden Sie ein Plugin fur die inte-grierte Enwicklungsumgebung KDevelop. Es befindet sich zwar noch in der Ent-wicklung, soll aber einmal verschiedene Werkzeuge wie GNU Compiler, GNUDebugger und die Entwicklungswerkzeuge verschiedener MPI-Implementierungen(LAM/MPI, MPICH, MVAPICH) unter einer Oberflache vereinen.

Page 336: [X.systems.press] Cluster Computing ||

11

Bibliotheken

So go out and spread the gospel!Libraries of Parallel Software for the Masses!

Peter Pacheco [130]

Die Abstraktionsebene von MPI ist relativ niedrig. Jeder Datentaustausch muss expli-zit und penibel codiert werden. Bose Zungen bezeichnen MPI deshalb als ”Assemb-lersprache des verteilten Rechnens“. Wunschenswert ware eine hohere Abstraktions-ebene, die es erlaubt, sich mehr auf die algorithmischen Aspekte des vorliegendenProblems zu konzentrieren als auf die technische Abwicklung der Kommunikation.

An dieser Stelle kommen parallele Programmbibliotheken ins Spiel, die auf einerhoheren Stufe ansetzen als eine reine Kommunikationsbibliothek wie MPI. Genausowie Sie bei sequentiellen Programmen z. B. die qsort-Funktion aus der C-Standard-Bibliothek verwenden, um Zahlen zu sortieren, ohne sich dabei Gedanken uber dieDetails dieser Funktion machen zu mussen, konnten Sie z. B. eine Sortierfunktioneiner Bibliothek parallelisierter Funktionen aufrufen, um große Datenmengen auf ei-nem Cluster-Computer zu sortieren oder deren Fouriertransformation zu berechnen.

Eines der Hauptziele des MPI-Forums, das den MPI-Standard definiert hat, wares, eine Kommunikationsbibliothek zu schaffen, die es erlaubt, wiederverwendbarenCode in Bibliotheken zu packen. So erlaubt z. B. das Konzept des Kommunikators,die gesamte Kommunikation einer Bibliotheksfunktion und die restliche Kommuni-kation eines MPI-Programms voneinander zu entkoppeln. Die Bibliotheksfunktio-nen mussen dazu nur einen eigenen Kommunikator verwenden. Trotzdem sind leis-tungsfahige Bibliotheken noch immer eher rar gesat und unterstutzen nur mehr oderweniger spezielle Anwendungsgebiete. Dies hat zwei Grunde:

• Zwar haben Cluster-Computer in den letzten Jahren eine recht starke Verbrei-tung gefunden, im gesamten Computermarkt nehmen sie aber noch immer ehereine Exotenstellung ein. Genauso exotisch ist meist auch die Software, die dar-auf lauft. Sie wurde oft geschrieben, um ein ganz spezielles Problem zu losen.Es fehlt noch immer an einer kritischen Masse allgemeiner Probleme, die dieEntwicklung von Bibliotheken paralleler Funktionen in großerem Umfang inter-essant machen wurde.

• Außerdem ist es deutlich schwieriger gute Bibliotheken mit parallelen Funkti-onen als mit sequentiellen Funktionen zu schreiben. Darum werden solche Bi-bliotheken oft von Experten und leider oft auch fur Experten geschrieben. Die

Page 337: [X.systems.press] Cluster Computing ||

334 11 Bibliotheken

Mehrzahl heute existierender paralleler Bibliotheken stammt aus verschiedenenForschungsprojekten.

Im folgen Abschnitt werden wir einen Uberblick uber einige frei verfugbare Biblio-theken und Programme geben und Sie ermutigen (trotz oben genannter Einschrankun-gen), wann immer es moglich ist, diese auch zu benutzen. Auf einige Bibliothekengehen wir spater exemplarisch genauer ein.

Neben diesen freien Programmen und Bibliotheken gibt es fur Cluster-Computerauch einige Programme und Bibliotheken kommerzieller Anbieter. Darunter findetman z. B. Finite-Elemente-Programme zur Simulation von Stromungen oder tech-nischen Konstruktionen, Animationsprogramme oder Programme zur Bildverarbei-tung. Diese Programme werden oft fur einen engen Markt entwickelt und sind ent-sprechend teuer.

11.1 Uberblick

Im Bereich freier paralleler Bibliotheken gibt es eine ganze Menge Bewegung. Im-mer neue Projekte entstehen, die Weiterentwicklung mancher alterer Bibliothekenwird eingestellt. Folgende Liste gibt einen kleinen Uberblick uber frei verfugbareProgramme und Bibliotheken. Sie erhebt keinen Anspruch auf Vollstandigkeit, dieReihenfolge impliziert keine Wertung. Jedoch haben wir versucht, moglichst solcheProgramme und Bibliotheken aufzufuhren, die eine gewisse Verbreitung gefundenhaben und noch aktiv gepflegt werden. Da einige sequentielle Bibliotheken auch inparallelen Programmen ganz nutzlich sind bzw. einige parallele Bibliotheken auf an-deren sequentiellen Bibliotheken aufbauen, finden Sie in der folgenden Liste aucheinige sequentielle Bibliotheken.

11.1.1 Allgemeines

GNU Scientific Library

WWW: http://www.gnu.org/software/gsl/Sprache(n): CModus: sequentiellBeschreibung: Die GNU Scientific Library (GSL) ist eine in C programmierte, unter

GPL lizenzierte Numerikbibliothek. Sie enthalt verschiedenste Routinen aus denGebieten• komplexe Zahlen,• spezielle Funktionen,• lineare Algebra (BLAS, siehe unten),• Fast-Fourier-Transformation,• Integration,• Zufallszahlen,• Differentialgleichungen u. v. m.Obwohl die GSL in C geschrieben ist, lasst sie sich auch aus anderen Program-miersprachen wie C++, Python, Ruby, S oder Perl nutzen.

Page 338: [X.systems.press] Cluster Computing ||

11.1 Uberblick 335

Hierarchical Data Format 5

WWW: http://hdf.ncsa.uiuc.edu/HDF5/Sprache(n): FORTRAN 90, C, C++, JavaModus: sequentiell, parallelBeschreibung: Das Hierarchical Data Format 5 (HDF5) ist zum Einen fur ein fle-

xibles Datenformat zur Speicherung komplexer multidimensionaler Daten. ZumAnderen ist es eine Bibliothek, mit der Daten in diesem Format abgespeichertund gelesen werden konnen. Dateien im Hierarchical Data Format 5 konnen be-liebig groß sein und bestehen aus einem Kopf, der die Organisation der Datenin der Datei beschreibt, und den eigentlichen Daten. Durch die virtuelle Datei-schicht der HDF5-Bibliothek unterstutzt diese ganz verschiedene Arten der Ein-und Ausgabe, Dateisystemen und Speichermedien. Fur Parallelrechner imple-mentiert die HDF5-Bibliothek kollektive MPI-Funktionen, mit denen Daten imHierarchical Data Format 5 geschrieben und gelesen werden konnen.

Global Arrays Toolkit

WWW: http://www.emsl.pnl.gov/docs/global/Sprache(n): C, FORTRAN 77, Python, C++Modus: parallelBeschreibung: Das Global Arrays Toolkit verwandelt einen distributed-memory-

Cluster in ein großes virtuelles shared-memory-System. Mit ihm kann jeder Pro-zess asynchron auf jeden Teil eines uber den Cluster verteilen multidimensiona-len Feldes zugreifen, selbst wenn dieser auf einem entfernten Knoten liegt. Dermit dem Global Arrays Toolkit verfolgte Ansatz der Interpozesskommunikati-on ist komplementar zur auf Nachrichtenaustausch basierenden Kommunikation,kann aber mit z. B. MPI kombiniert werden.

11.1.2 Lineare Algebra

Basic Linear Algebra Subprograms

WWW: http://www.netlib.org/blas/Sprache(n): FORTRAN 77, C, C++Modus: sequentiellBeschreibung: Die Basic Linear Algebra Subprograms (BLAS) sind eine Sammlung

von Unterprogrammen, die die grundlegenden Operationen der linearen Algebraunterstutzen. BLAS kennt drei Stufen, diese umfassen:BLAS Level-1. Vektor-Vektor-OperationenBLAS Level-2. Matrix-Vektor-OperationenBLAS Level-3. Matrix-Matrix-OperationenDie BLAS-Routinen bilden die Grundlage einiger weiterer Bibliotheken, wiez. B. LINPACK und LAPACK. Eine FORTRAN-77-Referenz-Implementati-on dieser Routinen finden Sie unter http://www.netlib.org/blas/. Außerdem

Page 339: [X.systems.press] Cluster Computing ||

336 11 Bibliotheken

definiert der BLAS Technical Forum Standard unter http://www.netlib.org/blas/blast-forum/ eine C-Schnittstelle zu BLAS und vertreibt unter http://www.netlib.org/blas/blast-forum/cblas.tgz eine Referenz-Implementation dieserC-Schnittstelle. Im Boost Projekt (http://www.boost.org) finden Sie unter http://www.boost.org/libs/numeric/ublas/doc/index.htm eine templatebasierte C++-Implementation der BLAS-Routinen.

Daneben bieten einige Computerhersteller eigene fur ihre Hardware opti-mierte Implementationen an.AMD. Siehe http://www.developwithamd.com/acml/.Compaq. Siehe http://www.compaq.com/hpc/software/dxml.html.HP. Siehe http://www.hp.com/go/mlib/.IBM. Siehe http://www.rs6000.ibm.com/software/Apps/essl.html sowie http://

www.rs6000.ibm.com/software/sp products/esslpara.html.Intel. Siehe http://developer.intel.com/software/products/mkl/index.htm.SGI. Siehe http://www.sgi.com/software/scsl.html.SUN. Siehe http://docs.sun.com/htmlcoll/coll.118.3/iso-8859-1/PERFLIBUG/

plug bookTOC.html.

High-Performance BLAS

WWW: http://www.cs.utexas.edu/users/flame/goto/Sprache(n): FORTRAN 77, CModus: sequentiell, parallel auf shared-memory-Systemen (POSIX Threads)Beschreibung: Die High-Performance BLAS Bibliothek von Kazushige Goto unter-

scheidet sich von anderen BLAS-Implementation dadurch, dass sie nicht nur aufeine effiziente Nutzung des Caches hin optimiert ist, sondern auch die Zugriffeauf den sog. translation lookaside buffer optimiert. Der translation lookaside buf-fer ist eine prozessorinterne Tabelle, die den virtuellen Adressraum eines Com-puters auf physische Speicheradressen abbildet. Sie enthalt allerdings nur einenIndex der Seiten des Hauptspeichers, auf die zuletzt zugegriffen wurde. WennDaten aus den Hauptspeicher in den Cache ubertragen werden, so muss jedes-mal eine virtuelle Adresse in eine physische umgerechnet werden. Wenn sichdie gesuchte physische Adresse nicht im translation lookaside buffer befindet,muss sie durch eine andere aufwendigere Logik errechnet werden. Messung-en der Autoren dieser Bibliothek zeigen, dass ihr Ansatz zumindest fur einigeBLAS-Routinen einen leichten Geschwindigkeitsvorsprung gegenuber ATLAS(siehe unten) oder BLAS-Implementationen verschiedener Prozessorherstellerbringt.

Page 340: [X.systems.press] Cluster Computing ||

11.1 Uberblick 337

LINPACK

WWW: http://www.netlib.org/linpack/Sprache(n): FORTRAN 77Modus: sequentiellBeschreibung: Hinter LINPACK verbirgt sich eine Sammlung von FORTRAN-77-

Subroutinen zum Losen von linearen Gleichungssystemen und linearen Klein-ste-Quadrate-Problemen und der Berechnung von QR-Faktorisierungen. Es exis-tieren spezielle Losungsroutinen fur Bandmatrizen, symmetrisch indefinite, po-sitiv semidefinite Matrizen und Dreiecksmatrizen. Die Entwicklung von LIN-PACK geht bis in die 1970er zuruck. Inzwischen wurde LINPACK zum Teil vonLAPACK verdrangt, das neben sequentiellen Computern auch shared-memory-Systeme unterstutzt.

LAPACK, LAPACK95

WWW: http://www.netlib.org/lapack/, http://www.netlib.org/lapack95/Sprache(n): FORTRAN 77Modus: sequentiell, parallel auf shared-memory-Systemen und VektorcomputernBeschreibung: Die beiden Bibliotheken LAPACK und LAPACK95 enthalten in

FORTRAN 77 bzw. FORTRAN 95 geschriebene Routinen u. a. zum Losen vonlinearen Gleichungssystemen und von Eigenwertproblemen. Außerdem konnenmit LAPACK und LAPACK95 verschiedene Matrix-Faktorisierungen (LU , Cho-lesky, QR u. a.) berechnet werden. Die von LAPACK manipulierten Matrizensind entweder dicht oder haben eine Bandstruktur mit reel- oder komplexwerti-gen Eintragen.

Die Muster der Speicherzugriffe der in LAPACK implementierten Algorith-men wurden durch eine blockweise Aufteilung der Matrizen speziell in Hinsichtauf shared-memory-Systeme und Vektorcomputer optimiert. Dabei greift die Bi-bliothek so weit wie moglich auf Funktionen der BLAS-Bibliothek zuruck undprofitiert somit von deren hochperformanten maschinen-spezifischen Implemen-tationen.

Automatically Tuned Linear Algebra Software

WWW: http://math-atlas.sourceforge.net, http://www.netlib.org/atlas/Sprache(n): C, FORTRAN 77Modus: sequentiell, parallel (Threads)Beschreibung: Die ATLAS-Bibliothek ist eine portable Implementation der BLAS-

Routinen und einiger LAPACK-Routinen. Beim Ubersetzen dieser Bibliothekwerden verschiedene Tests durchgefuhrt, um auf empirische Weise eine schnellst-mogliche Realisierung der BLAS-Routinen zu finden. Falls Sie keine speziell furIhre Hardware optimierte BLAS-Implementation einsetzen konnen oder wollen,ist ATLAS eine mogliche Alternative.

Page 341: [X.systems.press] Cluster Computing ||

338 11 Bibliotheken

Parallel Linear Algebra Package

WWW: http://www.cs.utexas.edu/users/plapack/Sprache(n): C, FORTRAN 77Modus: parallel (MPI)Beschreibung: Das Parallel Linear Algebra Package (PLAPACK) lost verschiedene

Probleme der linearen Algebra auf Parallel-Computern mit verteiltem Speicher.Die Entwickler dieser Bibliothek verwandten dafur einen objektorientierten An-satz, der die verwickelten Indexmanipulationen, die zwangsweise bei der Imple-mentation von Algorithmen der linearen Algebra auftreten, vor dem Anwenderverbirgt. MPI-Programme, die diese Bibliothek verwenden, bleiben so relativubersichtlich. Die von PLAPACK manipulierten Matrizen sind dicht, PLAPACKenthalt keine fur dunn besetzte Matrizen optimierten Routinen.

Leider geben die PLAPACK-Entwickler ihre Bibliothek nur noch auf Anfra-ge weiter, eine aktuelle Version lasst sich nicht mehr direkt von der oben ge-nannten Webseite herunterladen. Eine ausfuhrliche PLAPACK-Dokumentationfinden Sie im Buch [47].

ScaLAPACK

WWW: http://www.netlib.org/scalapack/Sprache(n): FORTRAN 77Modus: parallel (MPI, PVM)Beschreibung: Die ScaLAPACK-Bibliothek implementiert einen Teil der LAPACK-

Funktionen fur Parallel-Computer mit verteiltem Speicher. Dafur verwendetScaLAPACK auf Nachrichtenaustausch basierende Kommunikation uber MPIoder PVM. Ahnlich wie LAPACK teilt auch ScaLAPACK Matrizen blockweiseauf einzelne Prozessoren auf, um den Kommunikationsaufwand zu minimieren.Einige Computer-Hersteller bieten auch fur diese Bibliothek speziell auf ihreHardware optimierte Varianten an. In [130] finden Sie eine nahere Beschreibungdieser Bibliothek sowie ein Beispielprogramm.

hypre

WWW: http://www.llnl.gov/CASC/hypre/Sprache(n): C, FORTRAN 77Modus: parallel (MPI, OpenMP)Beschreibung: hypre ist ein Produkt des Scalable Linear Solvers Projekts, das es

sich zur Aufgabe gemacht hat, skalierbare parallele Algorithmen zur Losungvon linearen Gleichungssystemen mit dunnbesetzter Koeffizientenmatrix zu ent-wickeln. Leichte Benutzbarkeit, Robustheit und Flexibilitat standen bei der Ent-wicklung dieser Bibliothek im Vordergrund. Besonderen Wert wurde auf einenleistungsstarken Prakonditionierer gelegt.

Page 342: [X.systems.press] Cluster Computing ||

11.1 Uberblick 339

11.1.3 Differentialgleichungen

Cactus

WWW: http://www.cactuscode.org/Sprache(n): FORTRAN 77, FORTRAN 90, C, C++Modus: parallelBeschreibung: Cactus ist modulares System zum Losen von partiellen Differenti-

algleichungen wie sie in verschiedenen Gebieten der Natur- und Ingenieurwis-senschaften auftreten. Dieses System besteht zum einen aus einem Kern (fleshim Cactus-Jargon) und verschiedenen Anwendungsmodulen (thorns im Cactus-Jargon), die mit dem Kern und anderen Modulen zusammenarbeiten. Cactusist fur Sie interessant, wenn Sie Programme fur verschiedene Parallelcomputerunterschiedlichster Architektur und Betriebssystem in der Sprache Ihrer Wahl(FORTRAN 77, FORTRAN 90, C, C++) schreiben wollen. Auch konnen SieIhre Cactus-Programme problemlos auf einem Laptop entwickeln, um sie spaterz. B. auf einer Cray oder einem Cluster-Computer laufen zu lassen.

Das Cactus-System ist sehr machtig und entsprechend komplex, weshalb wirhierauf nicht naher eingehen wollen. Jedoch ist Cactus im Vergleich zu anderenBibliotheken außerordentlich gut dokumentiert. Tutorials und FAQs erleichternden Einstieg in Cactus.

PETSc

WWW: http://www.mcs.anl.gov/petsc/petsc-2/Sprache(n): C, C++, FORTRAN 77Modus: parallel (MPI)Beschreibung: Mit der Bibliothek PETSc konnen Systeme partieller Differentialglei-

chungen und nichtlineare Gleichungssysteme gelost werden. Fur die Koordinie-rung der parallelen Prozesse verwendet PETSc MPI. PETSc bietet Funktionenfur• verteilte Vektoren und Matrizen,• parallelisierte Prakonditionierer,• parallelisierte Krylov-Unterraumverfahren zur Losung partieller Differenti-

algleichungen,• parallelisierte auf dem Newton-Verfahren basierende Losungsfunktionen fur

nichtlineare Gleichungssysteme sowie• parallelisierte Loser fur gewohnliche Differentialgleichungen.All diese Funktionen sind gut dokumentiert und verschiedene Beispielprogram-me verdeutlichen ihre Verwendung. In [130] finden Sie eine nahere Beschrei-bung dieser Bibliothek sowie ein Beispielprogramm.

Page 343: [X.systems.press] Cluster Computing ||

340 11 Bibliotheken

Chombo

WWW: http://seesar.lbl.gov/ANAG/chombo/index.htmlSprache(n): C++, FORTRAN 77Modus: parallel (MPI)Beschreibung: Die Chombo-Bibliothek beinhaltet Funktionen zur Implementierung

von Finite-Differenzen-Methoden zur Losung von partiellen Differentialglei-chungen auf blockstrukturierten, adaptiv verfeinerten regularen Gittern.

Conservation LAWs PACKage

WWW: http://www.amath.washington.edu/∼claw/Sprache(n): FORTRAN 77Modus: sequentiell, parallel (MPI)Beschreibung: Das Conservation LAWs PACKage (CLAWPACK) ist eine Samm-

lung von FORTRAN-Unterprogrammen zur Losung von Systemen zeitabhangi-ger hyperbolischer partieller Differentialgleichungen in ein, zwei oder drei Di-mensionen. Diese Losungen werden hier durch einen Wellenfrontalgorithmus be-rechnet. AMRCLAW ist eine mit MPI parallelisierte Variante von CLAWPACK.Diese teilt den Rechenaufwand durch Gebietsaufteilung auf mehrere Prozesseauf.

eXtensible multi-dimensional Simulator

WWW: http://www.xmds.orgSprache(n): C++Modus: sequentiell, parallel (MPI)Beschreibung: Zu den moderneren Methoden zur Losung partieller Differentialglei-

chungen gehoren auch sog. Pseudospektralmethoden. Bei ihnen werden Diffe-rentialgleichungen zum Teil im Fourierraum gelost, weshalb in jedem Zeitschritteine Fouriertransformation und eine anschließende Rucktransformation berech-net werden mussen. Der eXtensible multi-dimensional Simulator (XmdS) imple-mentiert u. a. solche Pseudospektralmethoden fur einen Codegenerator. Ausge-hend von einer XML-Datei, die ein physikalisches Problem in Form von gewohn-lichen oder partiellen Differentialgleichungen beschreibt, erzeugt es ein C++-Programm, das das beschriebene Problem numerisch lost. Auf Wunsch nutztdas C++-Programm, die parallelen Transformationsmethoden von FFTW (Ab-schnitt 11.1.6).

Page 344: [X.systems.press] Cluster Computing ||

11.1 Uberblick 341

11.1.4 Hydrodynamik

Advanced Regional Prediction System

WWW: http://www.caps.ou.edu/ARPS/Sprache(n): FORTRAN 90Modus: sequentiell, parallel (MPI, PVM)Beschreibung: Das Advanced Regional Prediction System (ARPS) ist ein umfassen-

des System zur Modellierung der Atmosphare. Es beinhaltet Echtzeitdatenanaly-se, Werkzeuge zur Vorhersage und Nachbearbeitung.

Community Atmosphere Model

WWW: http://www.ccsm.ucar.edu/models/atm-cam/Sprache(n): CModus: sequentiell, parallel (MPI, OpenMP)Beschreibung: Das Community Atmosphere Model (CAM) ist ein globales Atmo-

spharenmodell des amerikanischen National Center for Atmospheric Research.

Gerris

WWW: http://gfs.sourceforge.netSprache(n): CModus: parallel (MPI)Beschreibung: Gerris ist eine Bibliothek zum Losen von partiellen Differentialglei-

chungen, wie sie bei der Simulation von Stromungen in zwei oder drei Dimen-sionen auftreten. Unter anderem werden die zeitabhangigen Euler-, Stokes- undNavier-Stokes-Gleichungen unterstutzt. Durch Gerris’ objektorientiertes Designlassen sich auch komplexe Rand- und Anfangsbedingungen sowie Quellen spe-zifizieren. Die Resultate einer mit Gerris durchgefuhrten Simulation lassen sichmit dem Programm GfsView visualisieren, siehe Abb. 11.1.

StarCrash

WWW: http://www.astro.northwestern.edu/StarCrash/Sprache(n): FORTRAN 77Modus: sequentiell, parallel (MPI)Beschreibung: Mit dem Programm StarCrash lassen sich gravitativ wechselwirken-

de Systeme wie z. B. Sternenkollisionen simulieren. Dazu verwendet StarCrasheine Smoothed Particle Hydrodynamics genannte Methode und die BibliothekFFTW, siehe Abschnitt 11.1.6.

Page 345: [X.systems.press] Cluster Computing ||

342 11 Bibliotheken

Abb. 11.1. Darstellung einer mit Gerris berechneten Simulation eines umstromten Halbzylin-ders im Visualisierungsprogramm GfsView. Deutlich sind sich vom Halbzylinder ablosendeWirbel zuerkennen.

11.1.5 N-Korperprobleme und Molekulardynamik

Distributed Parallel Multipole Tree Algorithm

WWW: http://www.ee.duke.edu/∼wrankin/Dpmta/Sprache(n): C, FORTRAN 77Modus: parallel (MPI, PVM)Beschreibung: Auf Grundlage des Distributed Parallel Multipole Tree Algorithm,

kurz DPMTA, lassen sog. N-Korperprobleme, wie sie z. B. in der Molekulardy-namik auftreten, losen.

EGO

WWW: http://www.lrz-muenchen.de/∼heller/ego/Sprache(n): CModus: parallel (MPI, PVM)Beschreibung: Mit dem Programm EGO lassen sich Molekulardynamiksimulatio-

nen auf verschiedenen Parallelcomputern (Hitachi SR8000, CRAY-T3E, IBM-SP2, Fujitsu VPP700, Parsytec-CC) und Cluster-Computern unter MPI oderPVM durchfuhren. EGO verwendet dazu einen Algorithmus, der auf verschiedenZeitskalen arbeitet sowie eine Multipolmethode. Dieser Algorithmus skaliert li-near mit der Zahl der simulierten Atome, so dass sich auf ParallelcomputernSysteme mit bis zu 40 000 Atomen behandeln lassen.

Page 346: [X.systems.press] Cluster Computing ||

11.1 Uberblick 343

GADGET

WWW: http://www.mpa-garching.mpg.de/gadget/Sprache(n): CModus: parallel (MPI)Beschreibung: Der Name GADGET steht fur galaxies with dark matter and gas

interact. Dies ist ein Programm zur Simulation kosmologischer N-Korperproble-me auf Cluster-Computern. Mit ihm kann eine Vielzahl interessanter astrophy-sikalischer Fragestellungen untersucht werden. Dazu gehoren z. B. kollidieren-de Galaxien, die Entstehung von Sternen und Planeten oder die großraumigeStruktur des Universums. Auch in diesem Programm werden die auf die Korpereinwirkenden Krafte mit einem Multipolalgorithmus berechnet. Mit GADGETkonnen sowohl isolierte Systeme als auch Systeme unter dem Einfluss der kos-mologischen Expansion jeweils mit oder ohne zyklische Randbedingen behan-delt werden.

Molecular Dynamics Simulator

WWW: http://www.cs.sandia.gov/∼sjplimp/lammps.htmlSprache(n): C++Modus: sequentiell, parallel (MPI)Beschreibung: Der Molecular Dynamics Simulator, kurz LAMMPS, ist ein klas-

sisches Molekulardynamikprogramm, das Molekule im festen, flussigen odergasformigen Zustand simuliert. Mit ihm konnen einzelne Molekule, Polymere,biologische, metallische und granulare Systeme unter Einwirkung verschiedenerKrafte und mit verschiedenen Randbedingen untersucht werden. Diese Systemekonnen aus nur wenigen Teilchen bis mehreren Millionen Teilchen bestehen.

11.1.6 Fouriertransformation

Fastest Fourier Transform in the West

WWW: http://www.fftw.orgSprache(n): C, C++, FORTRAN 77Modus: sequentiell, parallel (MPI und Threads)Beschreibung: Die FFTW-Bibliothek besteht aus verschiedenen in C programmier-

ten Funktionen zur Berechnung diskreter Fouriertransformationen reeller undkomplexwertiger Großen sowohl in einer als auch in hoheren Dimensionen. Ver-sion 2.1.5 dieser Bibliothek enthalt Implementationen der schnellen Fouriertrans-formation fur sequentielle Rechner, parallele Rechner mit gemeinsamen Spei-cher und parallele Rechner mit verteiltem Speicher. In letzterem Fall setzt FFTWauf MPI auf. Aktuell ist momentan (Juni 2005) Version 3.0.1, die zu Versi-on 2.1.5 inkompatibel ist und (bisher) keine Rechner mit verteiltem Speicherunterstutzt.

Page 347: [X.systems.press] Cluster Computing ||

344 11 Bibliotheken

11.1.7 Optimierung

Asynchronous Parallel Pattern Search

WWW: http://software.sandia.gov/appspack/Sprache(n): C++Modus: sequentiell, parallel (MPI)Beschreibung: Asynchronous Parallel Pattern Search, kurz APPSPACK, ist eine se-

quentielle bzw. parallele Software zur Losung nicht linearer Optimierungspro-bleme. Die zu losenden Optimierungsprobleme haben mit f : R

n → R∪{+∞}die Form

min f (x1,x2, . . . ,xn) fur li ≤ xi ≤ ui mit i = 1,2, . . . ,n . (11.1)

Um eine Losung fur dieses Problem zu finden, verwendet APPSPACK eine asyn-chrone parallele Mustersuche. Durch dieses Verfahren mussen keinerlei Ablei-tungen der zu minimierenden Funktion berechnet werden und die Zahl der not-wendigen Funktionsauswertungen bleibt relativ gering. Nutzer dieser Softwaremussen nur eine Eingabedatei und ein Programm, das die zu minimierende Funk-tion an einem gegebenen Ort auswertet, bereitstellen. Dieses Programm kann injeder beliebigen Sprache programmiert sein.

OPT++

WWW: http://csmr.ca.sandia.gov/projects/opt++/Sprache(n): C++Modus: sequentiell, parallel (MPI)Beschreibung: OPT++ ist eine Bibliothek von Algorithmen zur Losung verschiede-

ner nicht linearer Optimierungsprobleme. Einige dieser Algorithmen arbeitenauch parallel.

ParMETIS

WWW: http://www-users.cs.umn.edu/∼karypis/metis/parmetis/index.htmlSprache(n): CModus: parallel (MPI)Beschreibung: ParMETIS ist eine auf MPI basierende Bibliothek, die verschiedene

Algorithmen zur Partitionierung unstrukturierter Graphen enthalt. Die Partitio-nierung eines Graphen ist ein sehr schwieriges Optimierungsproblem, das beiverschiedenen numerischen Berechnungen, in Operations Research oder bei geo-graphischen Informationsystemen Anwendung findet.

Page 348: [X.systems.press] Cluster Computing ||

11.1 Uberblick 345

11.1.8 Pseudozufallszahlen

Tina’s Random Number Generator Library

WWW: http://tina.nat.uni-magdeburg.de/TRNGSprache(n): C++Modus: sequentiell, parallelBeschreibung: Tina’s Random Number Generator Library, kurz TRNG, implemen-

tiert eine ganze Batterie von Pseudozufallszahlengeneratoren, die speziell fur dieAnwendung auf Parallelcomputern hin entwickelt wurden. Mit TRNG konnenausgehend von einem exzellenten sequentiellen Pseudozufallszahlengeneratorneue Pseudozufallszahlengeneratoren konstruiert werden, die jeden Prozessoreines Clusters mit unabhangigen Pseudozufallszahlen versorgt. Dazu ist keiner-lei explizite Kommunikation zwischen den einzelnen Prozessoren notwendig,was diese Bibliothek vollkommen unabhangig von der verwendeten Interprozess-kommunikation macht. Neben gleichverteilten Pseudozufallszahlen konnen mitTRNG auch Zufallszahlen mit Exponential-, Normal-, Gamma- oder anderenVerteilungen erzeugt werden.

SPRNG (Scalable Parallel Pseudo Random Number Generators Library)

WWW: http://sprng.cs.fsu.eduSprache(n): C, C++, FORTRAN 77Modus: sequentiell, parallel (MPI)Beschreibung: SPRNG ist ahnlich wie TRNG eine Bibliothek zur Erzeugung von

Pseudozufallszahlen auf Parallelrechnern. Die Unterschiede dieser beiden Bi-bliotheken sind konzeptioneller Natur bzw. betreffen die unterstutzten Program-miersprachen und die unterstutzten Arten der Interprozesskommunikation. Wahr-end bei TRNG sich die auf den einzelnen Prozessen erzeugten Strome von Pseu-dozufallszahlen letztenendes immer wieder auf einen einzigen Pseudozufallszah-lengenerator zuruckfuhren lassen, ist dies bei den von SPRNG verwendeten Ge-neratoren nicht moglich ist. Darum lassen sich mit SPRNG nur sehr schwie-rig parallele Monte Carlo Simulationen schreiben, deren Ergebnisse unabhangigvon der Zahl der Prozesse sind, siehe Abschitt 11.4.2. Die Funktionen in SPRNGkonnen nur gleichverteilte Zufallszahlen generieren. Benotigt der Nutzer dieserBibliothek Zufallszahlen anderer Verteilung, so muss er selbst ein geeigneteTransformation programmieren, die aus gleichverteilten Zufallszahlen Folgenmit der gewunschten Verteilung erzeugt.

Page 349: [X.systems.press] Cluster Computing ||

346 11 Bibliotheken

11.1.9 Visualisierung

MPI-POV-Ray

WWW: http://www.verrall.demon.co.uk/mpipov/Sprache(n): CModus: parallel (MPI)Beschreibung: MPI-POV-Ray ist ein Patch fur das Raytracing-Programm POV-Ray

[135], siehe auch Abschnitt 6.2.5. Mit diesem Patch ist es moglich, die Berech-nung eines Bildes auf mehrere Computer zu verteilen. Dazu wird das Bild inmehrere Teilbilder zerlegt, von denen jeder Computer eins berechnet.

11.2 APPSPACK

11.2.1 Installation

Mit APPSPACK lassen sich hochdimensionale Optimierungsprobleme der Form

min f (x1,x2, . . . ,xn) fur li ≤ xi ≤ ui mit i = 1,2, . . . ,n . (11.2)

mit f : Rn → R∪{+∞} losen. Die zu minimierende Funktion bildet n reelle Para-

meter auf eine reelle Zahl oder Unendlich ab. APPSPACK lasst sich entweder alsfertiges Programm oder als Bibliothek verwenden. Hier soll nur die erste Moglich-keit beschieben werden.

Die Installation von APPSPACK beschrankt sich dank der GNU Autotools aufden vertrauten Dreiklang aus ./configure, make und make install. Um dieparallelen Fahigkeiten von APPSPACK nutzen zu konnen, muss dem Konfigurations-skript die Option --enable-mpi ubergeben werden. Falls das Konfigurations-skript die MPI-Wrappercompiler nicht selbstandig finden kann, geben Sie diese ex-plizit uber die Variablen CC (C-Compiler), CXX (C++-Compiler), F77 (FORTRAN-Compiler) und MPI CXX (C++-Wrapper-Compiler) bekannt.

bauke@server:˜/mpi/appspack-4.0$ CC=mpicc CXX=mpiCC F77=mpif77 \> MPI_CXX=mpiCC ./configure --enable-mpi

Mit make installwerden die APPSPACK-Bibliothek sowie die beiden Program-me appspack serial und appspack mpi, die die sequentielle bzw. paralleleVatiante der Optimierungssoftware darstellen, installiert.

11.2.2 Das Thomson-Problem

Das Optimierungsproblem, an dem die Benutzung von APPSPACK demonstriertwerden soll, ist das sog. Thomson-Problem. Beim Thomson-Problem besteht dieAufgabe darin, N sich abstoßende Einheitsladungen so auf der Oberflache einer Ein-heitskugel anzuordnen, dass die Gesamtenergie minimal ist. Jedes Ladungspaar tragt

Page 350: [X.systems.press] Cluster Computing ||

11.2 APPSPACK 347

Abb. 11.2. Verteilung von acht Einheitsladungen auf einer Einheitskugel (nicht gezeigt) mitminimaler elektrostatischer Energie.

einen Anteil zum Coulomb-Potential bei, der umgekehrt proportional zum Betrag desAbstandes der Ladungen ist. Das Gesamtpotential betragt also

E(r1,r2, . . . ,rN) = ∑1≤ j<k≤N

1|r j − rk| , (11.3)

wobei r j die Position der j-ten Ladung auf der Einheitskugel ist.Eine Ladungsverteilung zu finden, die die Energie (11.3) minimiert, ist gar nicht

so einfach, wie es vielleicht scheint. Das liegt zum einen daran, dass die Energie-funktion von vielen (2N) Freiheitsgraden abhangt. Zum anderen existieren sehr vielelokale Minima, deren Energie nur wenig uber dem globalen Minimum liegt. Au-ßerdem besitzen die Ladungsverteilungen mit geringster Energie kaum Symmetrien.Fur N = 4 bzw. N = 6 liegen die Ladungen an den Ecken eines Tetraeders bzw. ei-nes Oktaeders, also den Ecken von regularen Korpern. Naiv wurde man wohl aucherwarten, dass sich acht Ladungen in ihrer Konfiguration minimaler Energie so an-ordnen wurden, dass sie die Ecken eines Wurfels bilden. Dem ist jedoch nicht so. DieLadungsverteilungen geringster Energie entspricht hier einem ”gedrehten und leichtgestauchten Wurfel“, wie er in Abb. 11.2 zu sehen ist.

Die Programme appspack serial und appspack mpi sind Allzweckop-timierer. Damit man mit ihnen ein bestimmtes Minimierungsproblem losen kann,muss der Nutzer ein Programm schreiben, dass die zu minimierende Funktion (Ziel-funktion) an einem gegeben Punkt auswertet. Es ist vollkommen gleichgultig, inwelcher Sprache dieses Programm geschrieben wird. Wichtig ist nur, dass es sich aneinige wenige Konventionen halt.

• Die Parameter, an der die Funktion f (x1,x2, . . . ,xn) auszuwerten ist, sind auseiner Datei einzulesen.

• Der Name dieser Eingabedatei wird dem Programm als erstes Kommandozeilen-argument ubergeben.

• Die Eingabedatei besteht aus n + 1 Zeilen. Die erste Zeile enthalt die Anzahl nder Parameter, darauf folgen die n Parameter x1,x2, . . . ,xn.

• Nachdem das Programm die Zielfunktion berechnet hat, schreibt es das Ergebnisin eine Ausgabedatei.

Page 351: [X.systems.press] Cluster Computing ||

348 11 Bibliotheken

• Der Name dieser Ausgabedatei wird dem Programm als zweites Kommandozei-lenargument ubergeben.

• Bei Bedarf kann das Programm noch von einem dritten Kommandozeilenar-gument Gebrauch machen. Hierbei handelt es sich um eine Intergerzahl, diewahrend einer Minimierung nur ein einziges Mal vergeben wird. Diese Zahl kannz. B. dazu verwendet werden, einen einzigartigen Namen fur eine temporare Da-tei zu konstruieren.

In Listing 11.2 finden Sie ein kleines C-Programm, das die Zielfunktion (11.3) furdurch spharische Koordinaten auf einer Einheitskugel gegebene Punkte berechnet.In den Zeilen 41 bis 51 werden die spharischen Koordinaten eingelesen und in denZeilen 52 bis 55 wird das Coulomb-Potential dieser Ladungskonfiguration in die Aus-gabedatei geschrieben. Die Berechnung des Coulomb-Potentials (11.3) erfolgt durchdie Funktion potential in den Zeilen 17 bis 33. Da das Coulomb-Potential ei-nes Ladungspaars mit verschwindendem Abstand divergiert, wird, falls der Abstandzweier Ladungen zu klein ist, in Zeile 29 die Funktion potential verlassen unddie großte darstellbare Fließkommazahl zuruckgegeben.

Um ein Minimierungsproblem der Form (11.2) zu losen, benotigen wir neben derZielfunktion noch eine APPSPACK-Konfigurationsdatei, die die unteren und oberenSchranken der Variablen x j und andere Parameter spezifiziert, siehe Listing 11.1. Dadie Koordinaten der Ladungen in spharischen Koordinaten gegeben sind, liegen dieunteren Schranken bei 0 und die oberen bei π bzw. 2π . Neben diesen Schrankenenthalt die Konfigurationsdatei noch den Pfad zu dem Programm, das die Zielfunkti-on berechnet, und die Namen der Ein- und Ausgabedateien, uber die das Programmmit APPSPACK Funktionsargumente und Funktionswerte austauscht. Der letzte Teilder Konfigurationsdatei enthalt Parameter fur den Optimierer, wie z. B. Startwertefur die Funktionsargumente. Optional lassen sich fur den Optimierer noch weitereParameter spezifizieren. Diese werden in der APPSPACK-Dokumentation beschrie-ben.

Nachdem das Programm thomson, das die Zielfunktion berechnet, ubersetztwurde, kann APPSPACK auch schon versuchen, das Thomson-Problem zu losen.

Listing 11.1. APPSPACK-Konfigurationsdatei thomson.apps zur Losung des Thomson-Problems mit vier Ladungen.

@ "Bounds""Upper" vector 8 3.1416 6.2832 3.1416 6.2832 3.1416 6.2832 3.1416 6.2832"Lower" vector 8 0 0 0 0 0 0 0 0@@

5 @ "Evaluator""Executable Name" string "./thomson""Input Prefix" string "thomson_in""Output Prefix" string "thomson_out"@@

10 @ "Solver""Debug" int 1"Precision" int 2"Initial X" vector 8 2.179 .6912 1.389 .9551 2.137 .9604 .7892 .7634

Page 352: [X.systems.press] Cluster Computing ||

11.2 APPSPACK 349

Listing 11.2. Programm thomson.c zur Berechnung des Coulomb-Potentials von durchspharische Koordinaten auf einer Einheitskugel gegebene Punkte.

#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <math.h>

5 #include <float.h>

typedef struct { double phi, theta; } point;

void error(char *format, ...) { / * F e h l e r b e h a n d l u n g * /10 va_list args;

va_start(args, format);vfprintf(stderr, format, args);va_end(args);exit(EXIT_FAILURE);

15 }

double potential(int n, point *r) { / * e l e k t r i s c h e s P o t e n t i a l s * /int i, j;double E=0, x1, y1, z1, x2, y2, z2, dx, dy, dz, dr;

20 for (i=0; i<n; ++i) {x1=cos(r[i].theta)*sin(r[i].phi);y1=sin(r[i].theta)*sin(r[i].phi);z1=cos(r[i].phi);for (j=i+1; j<n; ++j) {

25 x2=cos(r[j].theta)*sin(r[j].phi);y2=sin(r[j].theta)*sin(r[j].phi);z2=cos(r[j].phi);dx=x1-x2; dy=y1-y2; dz=z1-z2; dr=sqrt(dx*dx+dy*dy+dz*dz);if (dr>n*2.0*DBL_MIN) E+=1.0/dr; else return DBL_MAX;

30 }}return E;

}

35 int main(int argc, char *argv[]) {int i, n; / * Z a h l e r und Zahl d e r Ladungen * /point *r; / * n−d i m e n s i o n a l e r Vek to r * /FILE* fd; / * F i l e d e s c r i p t o r * /if (argc<3)

40 error(” Verwendung : %s <e in> <aus>\n ”, argv[0]);if ((fd=fopen(argv[1], ” r ”))==NULL)

error(”Kann E i n g a b e d a t e i %s n i c h t o f f n e n .\ n ”, argv[1]);if ((fscanf(fd, ”%d ”, &n))!=1)

error(” F e h l e r beim Lesen d e r K o o r d i a n t e n a n z a h l .\ n ”);45 n/=2; / * Zahl d e r P a r a m e t e r = 2 * Zahl d e r Ladungen * /

if ((r=malloc(n*sizeof(*r)))==NULL)error(” S p e i c h e r v o l l .\ n ”);

for (i=0; i<n; ++i) / * K o o r d i n a t e n e i n l e s e n * /if ((fscanf(fd, ”%l e%l e ”, &r[i].phi, &r[i].theta))!=2)

50 error(” F e h l e r beim Lesen von r [%d ] aus %s .\ n ”, i, argv[1]);fclose(fd);if ((fd=fopen(argv[2], ”w”))==NULL)

error(”Kann A u s g a b e d a t e i %s n i c h t o f f n e n .\ n ”, argv[2]);fprintf(fd, ”%e\n ”, potential(n, r));

55 fclose(fd);free(r); / * S p e i c h e r f r e i g e b e n * /return EXIT_SUCCESS;

}

Page 353: [X.systems.press] Cluster Computing ||

350 11 Bibliotheken

bauke@server:˜/thomson$ gcc -ansi -o thomson thomson.c -lmbauke@server:˜/thomson$ mpirun -np 3 appspack_mpi thomson.apps

Da APPSPACKs parallele Variante nach dem Master-Worker-Schema arbeitet, musses mit mindestens zwei Prozessen (dem Master und einem Worker, siehe auch Ab-schnitt 9.1.3) gestartet werden.

Aus Platzgrunden zeigt Listing 11.1 eine APPSPACK-Konfigurationsdatei furdas Thomson-Problem mit nur vier Ladungen. Großere Systeme sind naturlich vielinteressanter, benotigen aber eine langere Konfigurationsdatei. Hier ist es gunstig,die APPSPACK-Konfigurationsdatei von einem kleinen Programm erstellen zu las-sen, siehe Listing 11.3. Unsere Experimente haben gezeigt, dass APPSPACK inAbhangigkeit von den Startwerten nicht immer das globale Minimum [62] des Thom-son-Problems findet. Stattdessen bleibt APPSPACK in einem hoherenergetischen lo-kalen Minimum hangen. Darum sollte ein Programm, das eine APPSPACK-Konfigu-rationsdatei erzeugt, die Startwerte zufallig wahlen und bei jedem Aufruf eine andereStartkonfiguration erzeugen.

11.2.3 APPSPACK als Bibliothek

Thomson-Probleme mit mehr Ladungen benotigen naturlich mehr Rechenzeit. Lei-der wird bei dem oben gezeigten Ansatz die meiste Rechenzeit dafur verschwendet,das Programm, das die Zielfunktion berechnet, zu starten bzw. uber DateizugriffeDaten zwischen diesem Programm und APPSPACK auszutauschen. Die eigentli-che Berechnung der Zielfunktion benotigt eine fast vernachlassigbare Rechenzeit.

Listing 11.3. Perl-Programm zur Erzeugung einer APPSPACK-Konfigurationsdatei fur dasThomson-Problem.

# ! / u s r / b i n / p e r l −w

if (defined($ARGV[0])) { $N=$ARGV[0]; } else { $N=5; }$pi=3.141592654;

5 print ”@ \” Bounds\”\n ”;print ”\” Upper\” v e c t o r ”.2*$N.” ”;for ($i=0; $i<$N; ++$i) { print $pi.” ”.2*$pi.” ”; }print ”\n ”;print ”\” Lower\” v e c t o r ”.2*$N.” ”;

10 for ($i=0; $i<2*$N; ++$i) { print ” 0 ”; }print ”\n ”;print ”@@\n ”;print ”@ \” E v a l u a t o r \”\n ”;print ”\” E x e c u t a b l e Name\” s t r i n g \ ” . / e l e c t r o n s \”\n ”;

15 print ”\” I n p u t P r e f i x \” s t r i n g \” e l e c t r o n s i n \”\n ”;print ”\” Outpu t P r e f i x \” s t r i n g \” e l e c t r o n s o u t \”\n ”;print ”@@\n ”;print ”@ \” S o l v e r \”\n ”;print ”\”Debug\” i n t 1\n ”;

20 print ”\” I n i t i a l X\” v e c t o r ”.2*$N.” ”;for ($i=0; $i<$N; ++$i) { print $pi*rand().” ”.rand().” ”; }print ”\n ”;print ”@@\n ”;

Page 354: [X.systems.press] Cluster Computing ||

11.3 FFTW 351

APPSPACK uber die Allzweckoptimierer appspack serial und appspackmpi zu verwenden, lohnt sich nur, wenn die Startzeit des Programms, das die Ziel-funktion berechnet, klein gegen seine Gesamtlaufzeit ist. Ist dies wie hier beim Thom-son-Problem nicht der Fall, kann APPSPACK auch als Bibliothek benutzt werden.Dadurch lassen sich Auswertung der Zielfunktion und Optimierung in ein einzigesProgramm integrieren und es mussen keine Daten uber ein langsames Dateisystemausgetauscht werden.

Wenn Sie APPSPACK als Bibliothek nutzen wollen, mussen Sie im Wesent-lichen nur eine von APPSPACK::Evaluator::Interface abgeleitete Klas-se implementieren, die die Zielfunktion berechnet. Im Quelltext der Programmeappspack serial bzw. appspack mpi kann dann die Klasse APPSPACK::Evaluator::SystemCall nur noch gegen diese neue Klasse ausgetauscht wer-den. Naheres erfahren Sie in der APPSPACK-Dokumentation.

11.3 FFTW

11.3.1 Schnelle Fouriertransformation

Die schnelle diskrete Fouriertransformation gehort wohl zu den wichtigsten Transfor-mationen uberhaupt. Sie findet Anwendung in so unterschiedlichen Problemstellun-gen wie Signalanalyse und -synthese, Bildverarbeitung, der exakten Multiplikationsehr großer Ganzzahlen, der Losung von partiellen Differentialgleichungen mittelsPseudospektralmethoden oder der Tomographie.

Unter der Fouriertransformation (y0,y1, . . . ,yn−1) eines komplexwertigen Vek-tors (x0,x1,xn−1) versteht man die eineindeutige Abbildung

yi =n−1

∑j=0

x je−2π i jn i i = 0,1, . . . ,n−1 . (11.4)

Ihre Umkehrabbildung

xi =1n

n−1

∑j=0

y je+2π i jn i i = 0,1, . . . ,n−1 (11.5)

heißt inverse Fouriertransformation und unterscheidet sich von der gewohnlichenFouriertransformation nur durch das Vorzeichen des Exponenten in der Exponential-funktion sowie eines Normierungsfaktors 1/n. Die Fouriertransformation lasst sichauch auf d-dimensionale Felder verallgemeinern.

yi1,...,id =n1−1

∑j1=0

. . .nd−1

∑jd=0

x j1,..., jd e−2π i1 j1n1

i · . . . · e−2π id jdnd

i (11.6)

xi1,...,id =1

n1 · . . . ·nd

n1−1

∑j1=0

. . .nd−1

∑jd=0

y j1,..., jd e+2π i1 j1n1

i · . . . · e+2π id jdnd

i (11.7)

Page 355: [X.systems.press] Cluster Computing ||

352 11 Bibliotheken

i1 = 0,1, . . . ,n1 −1 . . . id = 0,1, . . . ,nd −1

Eine naive Implementation der Gleichungen (11.4) und (11.5) wurde O(n2) Re-chenoperationen verlangen. Durch geschickte Anwendung des Prinzips ”teile undherrsche“ kann man aber einen Algorithmus finden, der nur O(n lnn) Rechenopera-tionen benotigt und darum schnelle Fouriertransformation (fast fourier transform)genannt wird.

Die Bibliothek FFTW stellt verschiedene sequentielle und parallele Implemen-tationen der schnellen Fouriertransformation zur Verfugung. Die Version 2.1.5 un-terstutzt auch Cluster-Computer und MPI. Das Besondere an dieser Bibliothek ist,dass sie keinen statischen Algorithmus fur die Berechnung der Fouriertransformati-on verwendet. Stattdessen muss, bevor eine Fouriertransformation berechnet werdenkann, ein Plan erstellt werden, der einzig von der Anzahl der verwendeten Prozes-soren und den Dimensionen des zu transformierenden Feldes abhangt. Dieser Planenthalt eine Beschreibung dafur, wie die Daten auf die Prozessoren aufzuteilen sind,sowie wie das teile-und-herrsche-Prinzip konkret auf einen Datensatz mit gegebe-ner Große anzuwenden ist. FFTW ermittelt einen solchen Plan entweder auf empiri-schem Wege, was eine Weile dauern kann, oder heuristisch, was etwas flinker gehtaber keinen optimalen Losungsalgorithmus garantiert.

11.3.2 Eindimensionale Transformationen

Die Installation der FFTW-Bibliothek ist recht einfach. Nachdem die Bibliothekvon [39] heruntergeladen und entpackt wurde, kann sie mit dem bekannten Drei-klang aus ./configure, make und make install installiert werden. Da-mit auch die MPI-Funktionen der Bibliothek kompiliert werden, mussen wir aller-dings das ./configure-Skript mit der Option --enable-mpi aufrufen. Nachmake install werden Headerdateien und Bibliotheken in /usr/local liegen-de Verzeichnisse kopiert.

Listing 11.4 zeigt ein kleines Beispielprogramm, das aus einer Datei einen ein-dimensionalen komplexwertigen Datensatz einliest, dessen (inverse) Fouriertransfor-mation berechnet und das Ergebnis in eine Ausgabedatei schreibt. Beim Uberset-zen muss das Programm gegen die FFTW-Bibliotheken (hier -lfftw mpi und-lfftw) gelinkt werden.

bauke@server:˜/src$ mpicc -o fft_1d fft_1d.c -lfftw_mpi -lfftw

FFTW kennt auch spezielle Funktionen fur die Transformation reeller Datensatze,die ca. um einen Faktor zwei schneller sind und weinger Speicher benotigen. Ver-wenden Sie in Ihrem Programm diese Funktionen, so mussen Sie zusatzlich gegen-lrfftw mpi und -lrfftw linken. Unser Beispielprogramm transformiert je-doch einen komplexwertigen Datensatz, da dies konzeptionell etwas einfacher ist.

Das Beispielprogramm 11.4 entnimmt dem ersten Kommandozeilenargumentdie Transformationsrichtung (--forward bzw. --backward). Darauf folgen dieLange des Datensatzes, der Name der Eingabedatei und der Name der Ausgabedatei.

Page 356: [X.systems.press] Cluster Computing ||

11.3 FFTW 353

Listing 11.4. Das Programm fft 1d.c berechnet parallel eine eindimensionale diskrete Fou-riertransformation.

#include <stdlib.h>#include <stdio.h>#include <string.h>#include <fftw_mpi.h>

5 #include ” mpi . h ”

void * secure_malloc(size_t size) {void * p=malloc(size);if (p==NULL)

10 MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);return p;

}

int main(int argc, char *argv[]) {15 int C_rank, C_size, size, i, j, n,

n1, start1, n2, start2, *n_g=NULL, *start_g=NULL;double time;fftw_mpi_plan plan;fftw_complex dummy, *data=NULL, *work=NULL, *buffer;

20 fftw_direction dir;FILE *fd;MPI_Datatype type[2]={MPI_DOUBLE, MPI_DOUBLE};int blocklen[2]={1, 1};MPI_Aint disp[2];

25 MPI_Datatype MPI_FFTW_COMPLEX;MPI_Status Status;

/ * MPI i n i t i a l i s i e r e n * /MPI_Init(&argc, &argv);

30 MPI_Comm_rank(MPI_COMM_WORLD, &C_rank);MPI_Comm_size(MPI_COMM_WORLD, &C_size);/ * MPI−D a t e n t y p f u r komplexe Zah len bauen * /MPI_Address(&dummy, disp);MPI_Address(&dummy.im, disp+1);

35 disp[1]-=disp[0]; disp[0]=0;MPI_Type_struct(2, blocklen, disp, type, &MPI_FFTW_COMPLEX);MPI_Type_commit(&MPI_FFTW_COMPLEX);/ * T r a n s f o r m a t i o n s r i c h t u n g und Zahl d e r Da tenpunk te best immen * /if (argc!=5)

40 MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);if (strcmp(argv[1], ”−−f o r w a r d ”))

dir=FFTW_FORWARD;else if (strcmp(argv[1], ”−−backward ”))

dir=FFTW_BACKWARD;45 else

MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);sscanf(argv[2], ”%i ”, &n);/ * P l an f u r T r a n s f o r m a t i o n e r s t e l l e n und l o k a l e P a r a m e t e r best immen * /plan=fftw_mpi_create_plan(MPI_COMM_WORLD, n, dir, FFTW_ESTIMATE);

50 fftw_mpi_local_sizes(plan, &n1, &start1, &n2, &start2, &size);/ * A r b e i t s s p e i c h e r a l l o z i e r e n * /data=secure_malloc(sizeof(*data)*size);work=secure_malloc(sizeof(*work)*size);if (C_rank==0) {

55 n_g=secure_malloc(sizeof(*n_g)*C_size);start_g=secure_malloc(sizeof(*start_g)*C_size);

}

Page 357: [X.systems.press] Cluster Computing ||

354 11 Bibliotheken

/ * Daten e i n l e s e n und an P r o z e s s e v e r t e i l e n * /MPI_Gather(&n1, 1, MPI_INT, n_g, 1, MPI_INT,0, MPI_COMM_WORLD);

60 MPI_Gather(&start1, 1, MPI_INT, start_g, 1, MPI_INT, 0, MPI_COMM_WORLD);if (C_rank==0) {

if ((fd=fopen(argv[3], ” r ”))==NULL)MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);

for (i=0; i<C_size; ++i) {65 buffer=secure_malloc(sizeof(*buffer)*n_g[i]);

for (j=0; j<n_g[i]; ++j)fscanf(fd, ”%l f%l f ”, &buffer[j].re, &buffer[j].im);

if (i!=0)MPI_Send(buffer, n_g[i], MPI_FFTW_COMPLEX, i, 0, MPI_COMM_WORLD);

70 elsememcpy(data, buffer, sizeof(*data)*n_g[i]);

free(buffer);}fclose(fd);

75 } elseMPI_Recv(data, n1, MPI_FFTW_COMPLEX, 0, 0, MPI_COMM_WORLD, &Status);

/ * Daten t r a n s f o r m i e r e n * /MPI_Barrier(MPI_COMM_WORLD);time=MPI_Wtime();

80 fftw_mpi(plan, 1, data, work);MPI_Barrier(MPI_COMM_WORLD);time=MPI_Wtime()-time;if (C_rank==0)

printf(”%i Da tenpunk te i n %g Sekunden a u f %i Knoten t r a n s f o r m i e r t \n ”,85 n, time, C_size);

/ * Daten einsammeln und ausgeben * /MPI_Gather(&n2, 1, MPI_INT, n_g, 1, MPI_INT, 0, MPI_COMM_WORLD);MPI_Gather(&start2, 1, MPI_INT, start_g, 1, MPI_INT, 0, MPI_COMM_WORLD);if (C_rank==0) {

90 if ((fd=fopen(argv[4], ”w”))==NULL)MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);

for (i=0; i<C_size; ++i) {buffer=secure_malloc(sizeof(*buffer)*n_g[i]);if (i!=0)

95 MPI_Recv(buffer, n_g[i], MPI_FFTW_COMPLEX, i, 0, MPI_COMM_WORLD,&Status);

elsememcpy(buffer, data, sizeof(*data)*n_g[i]);

for (j=0; j<n_g[i]; ++j)100 fprintf(fd, ”%g\ t%g\n ”, buffer[j].re, buffer[j].im);

free(buffer);}fclose(fd);

} else105 MPI_Send(data, n2, MPI_FFTW_COMPLEX, 0, 0, MPI_COMM_WORLD);

/ * S p e i c h e r wiede r f r e i geben * /free(n_g); free(start_g);free(data); free(work);fftw_mpi_destroy_plan(plan);

110 MPI_Finalize();return EXIT_SUCCESS;

}

Page 358: [X.systems.press] Cluster Computing ||

11.3 FFTW 355

bauke@server:˜/src$ mpirun -np 4 fft_1d --forward 8 data.dat data_out.dat8 Datenpunkte in 0.000847965 Sekunden auf 4 Knoten transformiert

Das Format von Ein- und Ausgabedatei besteht aus aus zwei Spalten, die je Real-und Imaginarteil einer Zahl enthalten.

Das Beispielprogramm in Listing 11.4 arbeitet wie folgt. Bis Zeile 5 werden allenotwendigen Headerdateien eingelesen. Die Headerdatei fftw mpi.h enthalt diePrototypen der Funktionen zur Berechnung von Fouriertransformationen komplex-wertiger eindimensionaler Datensatze. Wollen Sie mehrdimensionale oder reelle Da-tensatze transformieren, mussen Sie noch weitere Headerdateien einbinden, sieheFFTW-Dokumentation. In den Zeilen 15 bis 26 werden zunachst alle notwendigenVariablen deklariert. Die Funktionen in den Zeilen 29 bis 31 initialisieren die MPI-Umgebung. Die Programmiersprache C unterstutzt leider keine komplexen Zahlen(Notiz 11.2). Darum speichert FFTW diese in einer Struktur fftw complex derForm

typedef double fftw_real;

typedef struct {fftw_real re, im;

} fftw_complex;

und das Programm konstruiert in den Zeilen 33 bis 37 einen neuen MPI-Datentyp,der dieser Struktur entspricht. Danach werden Transformationsrichtung und Zahlder Datenpunkte von der Kommandozeile eingelesen. In Zeile 49 erstellt die Funk-tion fftw mpi create plan einen Transformationsplan. Die Argumente dieserFunktion bezeichnen den Kommunikator, dessen Prozesse die folgende Transforma-tion berechnen sollen, die Lange des Datensatzes, die Transformationsrichtung unddie Art, wie der Plan berechnet werden soll, empirisch (FFTW MEASSURE) oderheuristisch (FFTW ESTIMATE).

Damit FFTW eine Fouriertransformation gleichzeitig auf verschiedenen Kno-ten eines Clusters berechnen kann, muss der Datensatz naturlich auf die Knotenverteilt werden. FFTW verwaltet dafur ein virtuelles Feld und jeder Prozess be-kommt davon einen zusammenhangenden Happen ab. Welcher dieser Datenhap-pen jeweils bei einem Prozess vorliegt, hangt vom Transformationsplan ab, unddieser Plan kann im Zuge der Transformation geandert werden. Mit der Funktionfftw mpi local sizes bestimmt in Zeile 50 jeder Prozess, welcher Datenhap-pen fur ihn bestimmt ist. Nach dem Aufruf dieser Funktion steht in der Variablen n1die Zahl der Datenpunkte, die der Prozess vor dem Aufruf von fftw mpi verwal-tet, in n2 die Zahl der Datenpunkte, die der Prozess danach verwaltet. start1 undstart2 enthalten jeweils die Anfangsposition der vom Prozess verwalteten Datenvor und nach fftw mpi innerhalb des virtuellen Felds. In der Variablen size steht,wieviel Speicher jeder Prozess fur seine lokalen Daten reservieren muss. BeachtenSie, dass die Zahl in size großer als das Maximum von n1 und n2 sein kann.

Der in den Zeilen 52 bis 57 allozierte Speicher enthalt bei data die lokalen zutransformierenden Daten bzw. das lokale Ergebnis der Transformation. work zeigtauf einen Hilfsspeicher, den spater die Funktion fftw mpi verwenden wird. Die

Page 359: [X.systems.press] Cluster Computing ||

356 11 Bibliotheken

Felder n g und start g enthalten die globale Information daruber, wie das virtu-elle Datenfeld auf die Prozesse aufgeteilt ist. In den Zeilen 59 und 60 werden dieseInformationen vom Prozess mit dem Rang null eingesammelt. Danach liest dieserProzess die zu transformierenden Daten ein und verteilt sie auf die anderen Prozes-se.

In Zeile 80 wird schließlich die eigentliche Transformationsfunktion fftw mpiaufgerufen. Das erste Argument dieser Funktion ist der Transformationsplan, daszweite besagt, dass die bei data gespeicherten Daten nur ein einzelnes Feld re-prasentieren. Das letzte Argument work zeigt auf einen Hilfsspeicher, den die Funk-tion fur Zwischenergebnisse nutzt. Its diese Arguemnt der Nullzeiger, dann verzich-tet fftw mpi auf Zwischenspeicher, verursacht dadurch aber mehr Kommunikationzwischen den Prozessen.

Nachdem der Prozess mit dem Rang null noch die Zeit ausgegeben hat, die dieTransformation gedauert hat, sammelt er das Ergebnis der Transformation wiederein und speichert es in einer Datei ab. Zum Schluss werden ab Zeile 107 belegteRessourcen wieder freigegeben.

11.3.3 Multidimensionale Transformationen

Neben der im Beispielprogramm verwendeten Funktion fftw mpi kennt FFTWnoch die Funktionen fftwnd mpi und rfftwnd mpi, mit denen die Fouriertrans-formationen multidimensionaler komplex- und reellwertiger Datensatze berechnetwerden konnen und in der Dokumentation der FFTW-Bibliothek ausfuhrlich be-schrieben werden.

11.3.4 Rucktransformation

Bei der Verwendung aller FFTW-Transformations-Funktionen mussen Sie beachten,dass FFTW die Fourier-Rucktransformationen nicht nach (11.5) bzw. (11.7) errech-net. FFTW berucksichtigt nicht den Normierungsfaktor und berechnet stattdessen

xi1,...,id =n1−1

∑j1=0

. . .nd−1

∑jd=0

y j1,..., jd e2π i1 j1n1

i · . . . · e2π id jdnd

i (11.8)

i1 = 0,1, . . . ,n1 −1 . . . id = 0,1, . . . ,nd −1 .

Wenn Sie mit FFTW einen Datensatz transformieren und wieder rucktransformieren,so wird der Datensatz effektiv mit der Zahl der im Datensatz vorhandenen Daten-punkte multipliziert.

11.4 Tina’s Random Number Generator Library

11.4.1 Pseudozufallszahlen

Folgen von (Pseudo-)Zufallszahlen finden Anwendungen in den verschiedensten Be-reichen. Mit ihnen lassen sich z. B. stochastische Prozesse am Computer simulieren

Page 360: [X.systems.press] Cluster Computing ||

11.4 Tina’s Random Number Generator Library 357

oder hochdimensionale Integrale numerisch auswerten. Bei manchen Berechnungenist es nicht moglich, alle relevanten Falle zu untersuchen. Stattdessen kann manaber eine zufallige Stichprobe aus dieser Menge von Fallen wahlen und aus dieserSchlussfolgerungen auf die Gesamtmenge ziehen. Auch hierfur werden Zufallszah-len benotigt. Informatiker verwenden Zufallszahlen in randomisierten Algorithmen,oder um Eingabedaten zum Testen von Programmen zu erzeugen. Auch einige Ver-fahren der Bilderzeugung und -bearbeitung verwenden Zufallszahlen, ebenso wiediverse Protokolle in der Kryptographie. Verfahren, die auf Zufallszahlen basieren,werden allgemein als Monte-Carlo-Methoden bezeichnet.

Leider verhalt sich ein Computer ganz und gar nicht zufallig und Folgen von Zu-fallszahlen kann er schon gar nicht generieren, geschweige denn ”berechnen“. Com-puternutzer mussen sich darum mit weniger zufrieden geben, ihnen stehen nur Pseu-dozufallszahlen zur Verfugung. Unter einer Folge von Pseudozufallszahlen verstehtman eine endliche Zahlenfolge, die zwar nach einem deterministischen Verfahrenberechnet wurde, sich aber nicht durch statistische Tests von einer echten Zufalls-zahlenfolge unterscheiden lasst. Je langer eine Pseudozufallszahlenfolge ist, destogroßer ist die Chance, dass sie etwas von ihrem deterministischen Ursprung preisgibtund sich nennenswerte Unterschiede zu einer echten Zufallsfolge zeigen. Darum gilt,dass je mehr Pseudozufallszahlen eine Berechnung verschlingt, desto besser mussder Pseudozufallszahlengenerator eine echte Zufallsfolge nachahmen konnen.

Die C++-Bibliothek TRNG enthalt eine Palette von Pseudozufallszahlengenera-toren, die speziell fur die Verwendung auf Parallel-Computern entwickelt wurden.Eine Methode zur Berechnung von Pseudozufallszahlen ist der Lineare-Kongruen-zen-Generator. TRNG implementiert zwar andere Verfahren, an ihm lasst sich dieFunktionalitat von TRNG aber am besten erklaren. Wenn Sie tiefer in das ThemaPseudozufallszahlengeneratoren einsteigen wollen, so seien [85] und [49] empfoh-len.

Ein Lineare-Kongruenzen-Generator arbeitet iterativ. Aus einem Startwert (seed)r0 berechnet er nach der Vorschrift

ri = a · ri−1 mod m ri,a ∈ Zm\{0} (11.9)

eine Folge ganzer Zahlen, die alle großer als 0 und kleiner als m sind. Nach einer ge-wissen Zahl von Schritten erzeugt die Vorschrift (11.9) wieder den Startwert r0 unddie Folge beginnt, sich zu wiederholen. Da die ri uberhaupt nur m−1 verschiedeneWerte annehmen durfen, kann die Periode der Zahlenfolge ri hochstens m−1 betra-gen. Ob diese maximale Periode erreicht wird, hangt von Modulus m und vom Mul-tiplikator a ab. Soll die Periode eines Lineare-Kongruenzen-Generators nach (11.9)maximal sein, so muss m eine Primzahl sein und der Multiplikator a muss ein er-zeugendes Element der multiplikativen Gruppe modulo m sein. Diese Eigenschaftbedeutet nichts weiter, als dass ai mod m mit i ∈ Zm\{0} nacheinander alle ZahlenZm\{0} erzeugt. Wie folgende Tabelle zeigt, ist a = 7 fur m = 13 ein erzeugendesElement, a = 8 hingegen nicht.

Page 361: [X.systems.press] Cluster Computing ||

358 11 Bibliotheken

i 1 2 3 4 5 6 7 8 9 10 11 12 13

7i mod 13 7 10 5 9 11 12 6 3 8 4 2 1 78i mod 13 8 12 5 1 8 12 5 1 8 12 5 1 8

Sie sehen, durch fortwahrende Potenzierung von a = 7 modulo 13 lasst sich einerecht unregelmaßig erscheinende Permutation der Zahlen 1 bis 12 erzeugen. Die-se Eigenschaft machen sich Lineare-Kongruenzen-Generatoren zunutze. Allerdingswerden in der Praxis viel großere Moduli und Multiplikatoren verwendet.

Die Erzeugung von Pseudozufallszahlen auf Parallelrechnern ist etwas kompli-zierter. Wurden alle Prozesse eines Parallel-Computers den gleichen Pseudozufalls-zahlengenerator verwenden, so wurden auch alle Prozesse mit dem gleichen Stromvon Zufallszahlen arbeiten und die von den Prozessen berechneten Ergebnisse warenuntereinander hoch korreliert. Es gibt verschiedene Ansatze, dieses Problem zulosen.

Zentraler Server. Eine Strategie, Zufallszahlen auf einem Parallel-Computer zu er-zeugen, besteht darin, einen einzigen Prozess fur diese Aufgabe zu reservieren,der die anderen Prozesse bei Bedarf mit Zufallszahlen versorgt. Bedenkt manjedoch, dass bei Monte-Carlo-Simulationen auf heutigen CPUs in wenigen Mi-nuten 232 oder mehr Zufallszahlen erzeugt werden, wird deutlich, dass dieserAnsatz nicht praktikabel ist. Die Datenmenge, die je Minute vom Zufallszahlen-generator-Prozess abgefragt wurde, entsprache dem Inhalt einer großen Festplat-te.

Parametrisierung. Beim Parametrisierungsansatz hat jeder Prozess seinen eigenenGenerator. Damit aber jeder Pozess eine andere Folge erzeugt, benutzt jeder dengleichen Generatortyp mit einem anderen Parametersatz. So konnten z. B. al-le Prozesse einen Lineare-Kongruenzen-Generator mit gleichem Modulus aberunterschiedlichem Multiplikator verwenden. Dieser Ansatz wird von der Biblio-thek SPRNG verfolgt. Leider ist auch er nicht ganz unproblematisch. Dies liegtvorallem daran, dass es nicht gerade trivial ist, fur einen Generatortyp verschie-dene Parametersatzte zu finden, die Zahlenfolgen mit guten statistischen Eigen-schaften liefern. Daruberhinaus ist nicht garantiert, dass die statistischen Bezie-hungen zwischen verschiedenen Folgen auch denen echter Zufallsfolgen entspre-chen.

r

s

s

s

i

1, i

2, i

3, i

r

t

t

t

i

3, i

2, i

1, i

Abb. 11.3. Schematische Darstellung der Aufspaltung einer Pseudozufallszahlenfolge in dreiTeilfolgen. Links Aufteilung in zusammenhangende Blocke, rechts Splitten mit der leap-frog-Methode.

Page 362: [X.systems.press] Cluster Computing ||

11.4 Tina’s Random Number Generator Library 359

Unabhangige Zyklen. Einige Pseudozufallzahlengeneratoren besitzen unabhanigeZyklen. Mit einem solchen Generator lassen sich von jedem Prozess eines Paral-lel-Computers unabhangige Zufallszahlenfolgen erzeugen, obwohl sie den glei-chen Generator benutzen. Durch eine geschickte Wahl der Startwerte, kann jederProzess einen anderen Zyklus auswahlen. Da a = 10 kein erzeugendes Elementmodulo 13 ist, besitzt der Generator ri = 10 · ri−1 mod 13 mehrere unabhanigeZyklen (hier zwei). Mit r0 = 1 wird der erste Zyklus, mit r0 = 2 der zweiteZyklus des Generators ri = 10 · ri−1 mod 13 gewahlt.

ri = 10 · ri−1 mod 13i 0 1 2 3 4 5 6

ri 1 10 9 12 3 4 1ri 2 7 5 11 6 8 2

Blockaufteilung. Wenn a priori bekannt ist, wieviele Zufallszahlen ein Prozesswahrend einer Simmulation maximal benotigt (Sagen wir Nmax.), kann man eineZufallszahlenfolge in zusammenhangende Blocke der Lange Nmax aufteilen. Je-der Prozess bekommt einen solchen Block zugewiesen. Dazu springt jeder derp Prozesse von einem gemeinsamen Startwert um j ·Nmax ( j = 0,1, . . . , p− 1)Schritte in der Zahlenfolge vor und verwendet nur die Nmax folgenden Pseudo-zufallszahlen, siehe Abb. 11.3 links. Praktikabel ist diese Methode naturlich nur,wenn man in der Zahlenfolge vorspringen kann, ohne die j ·Nmax Folgengliederexplizit berechnen zu mussen. Bei einem Lineare-Kongruenzen-Generator kannman aus ri direkt ri+k berechnen, indem statt mit a mit ak multipliziert wird.

ri+k = ak · ri mod m (11.10)

Splitten. Das Splitten einer Pseudozufallszahlenfolge (auch leap frog genannt) funk-tioniert ahnlich wie die Blockaufteilung. Hier wird die Zahlenfolge in p Blockeder Lange eins aufgeteilt, die p Zufallszahlen den p Prozessen zugeordnet, dienachsten p Zufallszahlen werden wieder in p Blocke aufgeteilt usw. Jeder Pro-zess nutzt also jeweils eine Zahl der Folge und uberspringt die nachsten p− 1Zahlen, bevor er wieder eine Zufallszahl verwendet, siehe Abb. 11.3 rechts.

11.4.2 Die TRNG-Bibliothek

Die in TRNG implementierten Generatoren basieren auf sequentiellen Pseudozufalls-zahlengeneratoren mit sehr guten statistischen Eigenschaften und benutzten die Me-thoden der Blockaufteilung und des Splittens, um parallele Strome von Zufallszahlenzu erzeugen. Die Wahl fiel auf diese beiden Methoden, weil nur einmal ein guter Pa-rametersatz fur den sequentiellen Generator gesucht werden muss. Außerdem lassensich mit diesen Parallelisierungsmethoden parallele Algorithmen schreiben, die Er-gebnisse liefern, die unabhangig von der Zahl der Prozesse sind. Dadurch lassen sichdie Ergebnisse von Monte-Carlo-Simulationen besser reproduzieren und die Fehler-suche gestaltet sich etwas einfacher. Mit den anderen oben genannten Methoden istdies nicht oder nur mit sehr viel Aufwand moglich.

Page 363: [X.systems.press] Cluster Computing ||

360 11 Bibliotheken

TRNG ist eine recht kleine Bibliothek, entsprechend unkompliziert ist ihre In-stallation. Alles was dazu benotigt wird, sind ein C++-Compiler, der eine gute Un-terstutzung fur Templates hat und den 64-Bit-Integertyp long long kennt. Einaktueller GNU-C++-Compiler erfullt dieses Kriterium. Nach dem Herunterladenund Entpacken der Quellen, lasst sich die TRNG-Bibliothek mit make ubersetzenund mit make install unter /usr/local installieren. Mit make exampleskonnen Sie noch einige Test- und Beispielprogramme ubersetzen. Bei Bedarf solltenSie das Makefile Ihren Bedurfnissen anpassen.

Falls Sie bisher nur in C aber nicht in C++ programmiert haben, sollten das furSie kein Grund sein, vor der TRNG-Bibliothek zuruckzuschrecken. Diese Biblio-thek verwendet zwar intern Klassen und Templates, Sie benotigen jedoch kein tiefesVerstandnis dieser C++-Techniken, um TRNG in eigenen Programmen zu verwen-den.

Die verschiedenen Zufallszahlengeneratoren der TRNG-Bibliothek sind jeweilsals eine Klasse implementiert. Jede dieser Klassen hat die gleiche Schnittstelle, sodass ein Generator leicht gegen einen anderen ausgetauscht werden kann. Die wich-tigsten Methoden der Generatorenklassen sind, uniform, jump, split und derCall-Operator.

uniform. Die Methode uniform() gibt eine in [0,1) bzw. in der uberladenenVariante uniform(a,b) eine in [a,b) gleichverteilte Pseudozufallszahl alsdouble-Fließkommazahl zuruck.

jump. In dieser Methode ist die Blockaufteilung implementiert. jump(s) stellteinen Generator um s Schritte vor, bzw. jump(s,n) um n · s Schritte.

split. Hiermit lassen sich unabhangige Zufallszahlenfolgen nach der leap-frog-Methode erzeugen. split(s,n) spaltet eine Folge in s Folgen auf und wahltdie n-te dieser Folgen aus. Es muss 0 ≤ n < s gelten.

Call-Operator. Durch den Call-Operator genugen die TRNG-Zufallszahlengenera-toren den Richtlinien der C++ Standard Template Library. Ist R ein Zufallszah-lengeneratorobjekt und a eine positive Ganzzahl vom Typ long, so gibt R(a)eine in [0,a) gleichverteilte Ganzzahl zuruck, siehe auch Listing 11.6.

Die Zufallszahlengeneratorklassen besitzen noch mehr Methoden, die alle in derTRNG-Dokumentation ausfuhrlich beschrieben werden. Dazu gehoren z. B. Metho-den zur Erzeugung nicht gleichverteilter Zufallszahlen.

Listing 11.5 zeigt ein minimalistisches C++-MPI-Programm, das die Verwen-dung von TRNG verdeutlicht. In den Zeilen 1 bis 4 werden die ublichen C++-Headerdateien, die TRNG-Headerdatei trng.h und die MPI-Headerdatei mpi.heingebunden. Schreiben Sie Ihre MPI-Programme in C++, so konnen Sie entwederdie aus dem Teil III bekannten C-Funktionen oder die in MPI-2 definierten C++-Funktionen benutzen, siehe Abschnitt 7.6.3. In Listing 11.5 verwenden wir die Ih-nen vertraute C-Schnittstelle. Nach der Initialisierung der MPI-Umgebung in denZeilen 8 bis 10 wird in Zeile 11 ein Zufallszahlengeneratorobjekt vom Typ MRG3angelegt und in der darauf folgenden Zeile seine internen Parameter so verandert,dass er nach der leap-frog-Methode in soviele Teilfolgen aufgeteilt wird, wie derKommunikator MPI COMM WORLD Prozesse hat. Effektiv heißt dies, dass bei jeder

Page 364: [X.systems.press] Cluster Computing ||

11.4 Tina’s Random Number Generator Library 361

Listing 11.5. Dieses einfaches TRNG-Beispielprogramm trng simple.cc summiert aufjedem Prozess eine andere Folge von Zufallszahlen auf.

#include <cstdlib>#include <iostream>#include <trng.h>#include ” mpi . h ”

5int main(int argc, char *argv[]) {

int rank, size;MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD, &rank); / / P r o z e s s e i n MPI COMM WORLD

10 MPI_Comm_size(MPI_COMM_WORLD, &size); / / l o k a l e r P r o z e s s r a n gTRNG::MRG3 R; / / Z u f a l l s z a h l e n g e n e r a t o rR.split(size, rank); / / i n s i z e Fo lgen a u f s p a l t e n und Nr . r ank w ahlendouble sum(0.0);for (int i(0); i<100; ++i)

15 sum+=R.uniform();std::cout << ” Rang : ” << rank << ”\tSumme : ” << sum << ”\n ”;MPI_Finalize();return EXIT_SUCCESS;

}

Berechnung einer neuen Pseudozufallszahl statt um einen gleich um soviele Schrittenach vorne gesprungen wird, wie der Kommunikator MPI COMM WORLD Prozessehat. Ohne Zeile 12 wurden alle Prozesse die gleichen Pseudozufallszahlen benutzen.In den Zeilen 13 bis 16 werden nur zur Demonstration je Prozess hundert Zufalls-zahlen zwischen null und eins aufsummiert und die Summe ausgegeben. Zeile 16beendet schließlich die MPI-Umgebung. Das Programm trng simple wird mitdem C++-Wrapper-Compiler ubersetzt und gegen die TRNG-Bibliothek gelinkt.

bauke@server:˜/mpi$ mpiCC -o trng_simple trng_simple.cc -ltrngbauke@server:˜/mpi$ mpirun -np 5 trng_simpleRang : 0 Summe : 45.931Rang : 1 Summe : 52.5561Rang : 2 Summe : 48.6815Rang : 3 Summe : 51.0945Rang : 4 Summe : 49.3192

11.4.3 Selbstvermeidende Zufallswege

Das nachste TRNG-Beispiel-Programm erzeugt selbstvermeidende Zufallswege. Aufsolche Wege stoßt man u. a. bei der Untersuchung von Polymeren, der Faltung vonProteinen oder magnetischer Materialien. Wir betrachten hier Zufallswege auf ei-nem zweidimensionalen quadratischen Gitter. Einen Zufallsweg in seiner einfachs-ten Form wird konstruiert, indem ein gedachter Wanderer sich in Einheitsschrittenin nordliche, sudliche, ostliche oder westliche Richtung bewegt. Nach jedem Schrittwird die Richtung des nachsten Schrittes zufallig und unabhangig von den Schrit-ten davor gewahlt. Alle der vier Himmelsrichtungen sind gleich wahrscheinlich. Diemeisten statistischen Eigenschaften dieser Zufallswege lassen sich leicht mit Papier

Page 365: [X.systems.press] Cluster Computing ||

362 11 Bibliotheken

Abb. 11.4. Zwei typische Zufallswege einer Lange von 150 Schritten. Links ein einfacherZufallsweg, rechts ein selbstvermeidender Zufallsweg. Selbstvermeidende Zufallsweg konnennicht wieder zum Ursprung zuruckkehren und bewegen sich im Mittel weiter als einfacheZufallswege vom Ursprung weg.

und Bleistift ausrechnen, z. B. kann man zeigen, dass der mittlere quadratische Ab-stand vom Startpunkt nach N Schritten proportional zu N ist.

Eine etwas interessantere Variante von Zufallswegen sind selbstvermeidende Zu-fallswege. Sie werden genauso wie obige Zufallswege erzeugt, jedoch darf hier einGitterpunkt nie ein zweites Mal besucht werden. Schon einmal besuchte Punkte sindverboten. Naturlich kann es passieren, dass man sich so in eine Sackgasse manovriert.Diese verbotenen Punkte haben einen erheblichen Einfluss auf die Topologie der Zu-fallswege. Insbesondere befindet sich ein Wanderer auf einem selbstvermeidendenZufallsweg im Mittel deutlich weiter vom Ursprung entfernt als ein Wanderer aufeinem einfachen Zufallsweg nach der gleichen Zahl von Schritten. Der mittlere qua-dratische Abstand vom Startpunkt nach N Schritten wachst starker als proportionalzu N. Aber wie stark?

Diese Frage konnen Sie mit dem Programm in Listing 11.6 untersuchen. Es er-zeugt selbstvermeidende Zufallswege und gibt das Quadrat des Abstands vom Start-punkt nach einer vorgegebenen Zahl von Schritten aus. Der Clou an diesem Pro-gramm ist, dass seine Ergebnisse unabhangig von der Zahl der verwendeten Prozes-se sind und es bei verschiedenen Programmlaufen gezielt verschiedene Zufallswegeerzeugen kann.

Die Hauptarbeit ubernimmt in diesem Programm die Funktion generatewalk. Dieser Funktion sind zwei Argumente zu ubergeben, die Lange des WegesN und eine Nummer n, die den Weg eindeutig identifiziert. Da der Weg selbstver-meidend sein soll, kann man naturlich nicht ruckwarts gehen. Darum wahlt der Al-gorithmus zur Erzeugung eines selbstvermeidenden Zufallsweges vor jedem Schrittzufallig eine von drei moglichen Richtungen, links, rechts oder vorwarts. Welchedrei der vier Himmelsrichtungen erlaubt sind, hangt naturlich von der Richtung, indie der letzte Schritt ging, ab. Ging Wanderer z. B. im letzten Schritt nach Norden, so

Page 366: [X.systems.press] Cluster Computing ||

11.4 Tina’s Random Number Generator Library 363

Listing 11.6. Das Programm avoiding walk.cc erzeugt selbstvermeidende Zufallswege.

#include <cstdlib>#include <iostream>#include <algorithm>#include <trng.h>

5 #include <unistd.h>#include ” mpi . h ”

/ / Bewegungs r i ch tungentypedef enum { north=0, south, east, west } compass_t;

10/ / e i n Punkt i n d e r Ebenestruct point_t { int x, y; };

int generate_walk(int N, int n) {15 const compass_t allowd_dirs[4][3]=

{ {north, east, west}, {south, east, west},{north, south, east}, {north, south, west} };

TRNG::LCG64 R; / / Z u f a l l s z a h l e n g e n e r a t o r/ / Z u f a l l s z a h l e n g e n e r a t o r um n*N S c h r i t t e v o r s t e l l e n

20 R.jump(static_cast<long long>(n)*static_cast<long long>(N));point_t r={0, 0}; / / a k t u e l l e K o o r d i n a t epoint_t *visited=new point_t[N]; / / s p e i c h e r t a l l e b e s u c h t e n Punk tecompass_t dir=static_cast<compass_t>(R(4)); / / R i ch tung f u r 1 . S c h r i t tfor (int i=0; i<N; ++i) {

25 switch (dir) {case north:

++r.y; break;case south:

--r.y; break;30 case east:

++r.x; break;case west:

--r.x; break;}

35 visited[i]=r; / / neue K o o r d i n a t e merken/ / neue K o o r d i n a t e schon e inma l b e s u c h t ?for (int j=0; j<i; ++j)

if (visited[j].x==visited[i].x && visited[j].y==visited[i].y) {delete[] visited; / / j a , dann a b b r e c h e n

40 return -1;}

dir=allowd_dirs[dir][R(3)]; / / R i ch tung f u r n a c h s t e n S c h r i t t}delete[] visited;

45 return r.x*r.x+r.y*r.y;}

int main(int argc, char *argv[]) {int size, rank;

50 MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD, &rank); / / P r o z e s s e i n MPI COMM WORLDMPI_Comm_size(MPI_COMM_WORLD, &size); / / l o k a l e r P r o z e s s r a n gint length(20), n_walks(1000), start(0), c;/ / Weglange und Anzahl d e r Wege e i n l e s e n

55 while ((c=getopt(argc, argv, ”N: n : s : ”))!=-1) {switch (c) {

case ’N’:length=std::atoi(optarg); break;

Page 367: [X.systems.press] Cluster Computing ||

364 11 Bibliotheken

case ’ n ’:60 n_walks=std::atoi(optarg); break;

case ’ s ’:start=std::atoi(optarg); break;

default:/ / u n b e k a n n t e r Pa rame te r , Programmabbruch

65 MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);}

}/ / j e d e n s i z e −t e n Weg e r z e u g e nfor (int i(rank); i<n_walks; i+=size) {

70 int r2(generate_walk(length, i+start));/ / f a l l s Weg s e l b s t v e r m e i d e n d A b s t a n d s q u a d r a t ausgebenif (r2>=0)

std::cout << ” Rang : ” << rank<< ”\tWeg Nr . ” << i+start

75 << ”\ t A b s t a n d s q u a d r a t : ” << r2 << ’\n ’;}MPI_Finalize();return EXIT_SUCCESS;

}

darf er im Folgeschritt auf keinen Fall nach Suden gehen. Erlaubt sind nur Schritte inRichtung Norden, Osten oder Westen. Insgesamt sind jeweils folgende Richtungenerlaubt:

letzte Richtung erlaubte Richtungen

N N, O, WS S, O, WO N, S, OW N, S, W

Falls ein Schritt auf einen Punkt fuhrt, der schon fruher besucht wurde, so wird derWeg verworfen.

Einfach einen Schritt zuruckzugehen und dann eine andere Richtung einzuschla-gen, ist leider keine zulassige Strategie. Denn erstens kann man so in Sackgassengeraten und zweites lasst sich so keine gleichverteilte Stichprobe unter allen selbst-vermeidenden Zufallswegen einer bestimmten Lange ziehen. Man man kann zeigen,dass auf diese Weise bevozugt besonders kompakte Wege erzeugt werden [82].

Die Funktion generate walk verbraucht je Aufruf maximal N Zufallszahlen.Damit sie jedesmal andere Zahlen verwendet, wird in Zeile 19 der Zufallszahlenge-nerator durch die Methode jump um n ·N Schritte vorgestellt. In Abhangigkeit vomParameter n steht der Funktion generate walk jedesmal ein anderer Block vonZufallszahlen zur Verfugung.

Der selbstvermeidende Wanderer startet im Koordinatenursprung, seine aktuellePosition merkt sich die Funktion generate walk in der Variablen r, siehe Zei-le 21. Samtliche schon besuchten Punkte werden in der Liste visited gespeichert.Zu jedem Zeitpunkt enthalt die Variable dir die Richtung des nachsten Schritts.Die eigentliche Erzeugung des Weges erfolgt in der Schleife zwischen den Zeilen 24bis 43. In jedem Schleifendurchlauf bewegt sich der Wanderer in die aktuelle Rich-tung. Danach sucht das Programm in der Liste der schon besuchten Punkte nach der

Page 368: [X.systems.press] Cluster Computing ||

11.4 Tina’s Random Number Generator Library 365

aktuellen Position. Kann es sie darin finden, wird Kandidatenweg verworfen und dieFunktion generate walk abgebrochen. Andernfalls wird in Abhanigheit von deralten Richtung eine neue Richtung gewahlt und die Schleife fortgesetzt. Zum Schlussgibt die Funktion das Abstandsquadrat der Endposition zum Koordinatenursprungzuruck. Dass ein Kandidatenweg verworfen wurde, kann das Hauptprogramm daranerkennen, dass von der Funktion generate walk ein negativer Wert zuruckgege-ben wurde.

Das Hauptprogramm in Listing 11.6 initialisiert die MPI-Umgebung und liest dieKommandozeilenparameter ein. Gultige Kommandozeilenparameter sind:

-N. Lange des selbstvermeidenden Zufallsweges.-n. Anzahl der erzeugten Wege (inklusive der, die verworfen wurden).-s. Nummer des ersten Weges.

Die Lastverteilung erfolgt statisch (siehe Schleife in den Zeilen 70 bis 77). Jeder derp Prozesse in MPI COMM WORLD erzeugt jeden p-ten Weg. Falls der Weg selbstver-meidend ist, wird das Abstandsquadrat der Endposition zum Koordinatenursprungausgegeben.

Beim Ubersetzen des Programms mussen wir es wieder gegen die TRNG-Biblio-thek linken.

bauke@server:˜/src$ mpiCC -o avoiding_walk avoiding_walk.cc -ltrng

Danach konnen wir den ersten Testlauf wagen.

bauke@server:˜/src$ mpirun -np 5 avoiding_walk -N 28 -n 200Rang: 0 Weg Nr. 195 Abstandsquadrat: 34Rang: 2 Weg Nr. 72 Abstandsquadrat: 148Rang: 2 Weg Nr. 117 Abstandsquadrat: 26Rang: 2 Weg Nr. 137 Abstandsquadrat: 226Rang: 4 Weg Nr. 79 Abstandsquadrat: 80Rang: 4 Weg Nr. 184 Abstandsquadrat: 50Rang: 4 Weg Nr. 189 Abstandsquadrat: 324Rang: 1 Weg Nr. 96 Abstandsquadrat: 10Rang: 1 Weg Nr. 121 Abstandsquadrat: 116Rang: 1 Weg Nr. 131 Abstandsquadrat: 68Rang: 3 Weg Nr. 48 Abstandsquadrat: 130Rang: 3 Weg Nr. 143 Abstandsquadrat: 98Rang: 3 Weg Nr. 193 Abstandsquadrat: 202

Mit der Option -s ist es moglich, nach einem Programmlauf weitere neue selbstver-meidende Wege zu erzeugen, also da mit der Simulation weiter zu machen, wo derletzte Programmlauf endete.

Page 369: [X.systems.press] Cluster Computing ||

366 11 Bibliotheken

bauke@server:˜/src$ mpirun -np 5 avoiding_walk -N 28 -n 200 -s 200Rang: 0 Weg Nr. 220 Abstandsquadrat: 106Rang: 0 Weg Nr. 230 Abstandsquadrat: 144Rang: 0 Weg Nr. 255 Abstandsquadrat: 170Rang: 0 Weg Nr. 365 Abstandsquadrat: 242Rang: 0 Weg Nr. 375 Abstandsquadrat: 218Rang: 1 Weg Nr. 231 Abstandsquadrat: 64Rang: 1 Weg Nr. 281 Abstandsquadrat: 122Rang: 1 Weg Nr. 356 Abstandsquadrat: 202Rang: 1 Weg Nr. 371 Abstandsquadrat: 26Rang: 2 Weg Nr. 297 Abstandsquadrat: 148Rang: 2 Weg Nr. 337 Abstandsquadrat: 130Rang: 3 Weg Nr. 308 Abstandsquadrat: 162Rang: 3 Weg Nr. 363 Abstandsquadrat: 40Rang: 4 Weg Nr. 214 Abstandsquadrat: 50Rang: 4 Weg Nr. 219 Abstandsquadrat: 178Rang: 4 Weg Nr. 244 Abstandsquadrat: 98

Wie versprochen, sind die Ergebnisse von der Zahl der Prozesse unabhangig. Mitacht Prozessen erhalten wir die gleichen Ergebnisse wie mit nur funf.

bauke@server:˜/src$ mpirun -np 8 avoiding_walk -N 28 -n 200Rang: 0 Weg Nr. 48 Abstandsquadrat: 130Rang: 0 Weg Nr. 72 Abstandsquadrat: 148Rang: 0 Weg Nr. 96 Abstandsquadrat: 10Rang: 0 Weg Nr. 184 Abstandsquadrat: 50Rang: 1 Weg Nr. 121 Abstandsquadrat: 116Rang: 1 Weg Nr. 137 Abstandsquadrat: 226Rang: 1 Weg Nr. 193 Abstandsquadrat: 202Rang: 3 Weg Nr. 131 Abstandsquadrat: 68Rang: 3 Weg Nr. 195 Abstandsquadrat: 34Rang: 5 Weg Nr. 117 Abstandsquadrat: 26Rang: 5 Weg Nr. 189 Abstandsquadrat: 324Rang: 7 Weg Nr. 79 Abstandsquadrat: 80Rang: 7 Weg Nr. 143 Abstandsquadrat: 98

11.5 Notizen

11.1 Thomson-Problem. Um das Thomson-Problem ranken sich noch eine ganzeReihe verwandter Fragen und Problemstellungen. Eine Einfuhrung in diese Themenfinden Sie in [146].

11.2 Komplexe Zahlen in C. Dass C keine komplexen Zahlen unterstutze, stimmtnicht ganz. Seit der C99 genannten Uberarbeitung des C-Standards, sind auch Typenfur komplexe Fließkommazahlen Bestandteil der Programmiersprache C. Allerdingssind Compiler, die diese kennen, noch dunn gesat.

Page 370: [X.systems.press] Cluster Computing ||

12

Benchmarks

The performance of a computer is a complicated issue [...].

Jack J. Dongarra, Piotr Luszczek, Antoine Petitet [75]

In diesem Abschnitt beschaftigen wir uns mit den sportlichen Aspekten des Cluster-Computings, dem Benchmarking. Es gibt ganz verschiedene Motive, die Leistungeines Computers mittels eines Benchmarks zu untersuchen.

• Auf der Grundlage von Benchmarks lasst sich bewerten, welche Auswirkungeine bestimmte Veranderung der Hard- oder Softwarekonfiguration auf die Leis-tungsfahigkeit eines Clusters hat. Ein Vergleich der Benchmarkergebnisse vorund nach dem Eingriff zeigt, wie sich eine Konfigurationsanderung auswirkt undhilft, Fehlkonfigurationen zu finden.

• Mit Benchmarks konnen auch Systeme untereinander verglichen werden und hel-fen z. B. somit, eine Kaufentscheidung zu treffen. Allerdings sind solche Ver-gleiche nur sinnvoll, wenn sie sich auf klar umrissenen Fragestellungen grunden.Ansonsten vergleicht man schnell Apfel und Birnen.

• Außerdem ist da naturlich noch der sportliche Aspekt. Es ist einfach interessant,zu wissen, was der eigene Cluster zu leisten vermag.

Leider lasst sich die Leistung eines Computers nicht adaquat allein durch nur ei-ne Zahl charakterisieren. Darum gibt es eine Vielzahl von Benchmarks, die jeweilsverschiedene Komponenten eines Clusters charakterisieren. Diese Benchmarks sindso vielfaltig wie die verschiedenen Disziplinen im Sport. Einige Benchmarks unter-suchen die Fließkommaleistung, andere die Bandbreite und Latenz des Netzwerksoder die Performance von Dateioperationen. Andere Benchmarks, gewissermaßendie Zehnkampfe unter den Benchmarks, messen gleich eine ganze Reihe von Pa-rametern und untersuchen das Zusammenspiel verschiedener Komponenten eines(Cluster-)Computers. Zwei dieser Disziplinen werden wir in diesem Kapitel nahervorstellen, den Highly-Parallel LINPACK und die Intel MPI Benchmarks.

12.1 Highly-Parallel LINPACK

Der High-Performance LINPACK ist eine von drei Varianten des LINPACK-Bench-marks, siehe Abschnitt 1.4 und [75]. Bei diesem Test muss ein großes lineares Glei-

Page 371: [X.systems.press] Cluster Computing ||

368 12 Benchmarks

chungssystem gelost werden. Hat das System N Unbekannte, so werden fur dieLosung des Gleichungssystems etwa 2N3/3+2N2 Fließkommaoperationen benotigt.Aus der Systemgroße N und der Zeit T , die ein Computer zur Berechnung derLosung des Gleichungssystems benotigt, lasst sich die Fließkommaleistung R be-rechnen.

R =2N3/3+2N2

T(12.1)

Beim High-Performance LINPACK darf die Große des Gleichungssystem und diezu seiner Losung verwendete Software so gewahlt werden, dass eine großtmoglicheFließkommaleistung erreicht wird. Ansonsten unterliegt der Benchmark aber stren-gen Regeln. Insbesondere darf der Losungsalgorithmus als solcher nicht verandertwerden (wohl aber die Implementationsdetails). Die numerische Genauigkeit seinerImplementierung darf eine vorgeschriebene Grenze nicht unterschreiten.

Der Highly-Parallel LINPACK Benchmark (HPL-Benchmark) [68] ist eine por-table Implementation des High-Performance LINPACK fur Computer mit verteiltemSpeicher. Popular wurde der HPL-Benchmark vorallem, weil seine Ergebnisse dieListe der 500 schnellsten Computer der Welt [166] bestimmen. Diese Liste gibt furjeden Computer folgende Großen an:

• die theoretisch hochste Fließkommaleistung Rperk (peak performance),• die hochste tatsachlich gemessene Fließkommaleistung Rmax,• die Gleichungssystemgroße Nmax, bei der Rmax gemessen wurde, und• die Systemgroße N1/2, bei der die Fließkommaleistung auf Rmax/2 abfallt.

12.1.1 Algorithmus

Der HPL-Benchmark lost ein lineares Gleichungssystem

A · x = b A ∈ RN×N x,b ∈ R

N (12.2)

mit N Unbekannten. Dazu faktorisiert er die Koeffizientenmatrix A in zwei Dreiecks-matrizen L und U mit

L =

⎛⎜⎜⎜⎜⎜⎝

l1,1 0 . . . 0 0l2,1 l2,2 . . . 0 0

......

. . ....

...lN−1,1 lN−1,2 . . . lN−1,N−1 0lN,1 lN,2 . . . lN,N−1 lN,N

⎞⎟⎟⎟⎟⎟⎠

U =

⎛⎜⎜⎜⎜⎜⎝

u1,1 u1,2 . . . u1,N−1 u1,N0 u2,2 . . . u2,N−1 u2,N...

.... . .

......

0 0 . . . uN−1,N−1 uN−1,N0 0 . . . 0 uN,N

⎞⎟⎟⎟⎟⎟⎠

,

(12.3)so dass A = L ·U . Damit lasst sich das Gleichungssystem (12.2) als

A · x = (L ·U) · x = L · (U · x) = b (12.4)

schreiben. Bei einer LU-Faktorisierung sind N2 + N Unbekannte aus insgesamt nurN2 Gleichungen zu bestimmen. Die LU-Faktorisierung einer Matrix ist darum nicht

Page 372: [X.systems.press] Cluster Computing ||

12.1 Highly-Parallel LINPACK 369

� � �� � �� � �� � �

� � �� � �� � �� � �

� � �� � �� � �� � �

� � �� � �� � �� � �� � �� � �� � �� � �� � �� � �

� � �� � �� � �� � �� � �� � �

� � �� � �� � �� � �� � �� � �

� � �� � �� � �� � �� � �� � �

� � � �� � � �� � � �

� � �� � �� � �

� � �� � �� � �� � � �� � � �� � � �� � � �� � � �

� � �� � �� � �� � �� � �

� � � �� � � �� � � �� � � �� � � �

� � �� � �� � �� � �� � �

� � � �� � � �� � � �

� � �� � �� � �

� � � �� � � �� � � �� � � �

� � �� � �� � �� � �

� � � �� � � �� � � �

� � �� � �� � �� � � �� � � �� � � �� � � �� � � �� � � �

� � �� � �� � �� � �� � �� � �

� � � �� � � �� � � �� � � �� � � �� � � �

� � �� � �� � �� � �� � �� � �

� � � �� � � �� � � �

� � �� � �� � �

� � � �� � � �� � � �� � � �

! ! ! !! ! ! !! ! ! !! ! ! !

" " "" " "" " "" " "# # ## # ## # ## # ## # ## # #

$ $ $$ $ $$ $ $$ $ $$ $ $$ $ $

% % % %% % % %% % % %% % % %% % % %% % % %

& & && & && & && & && & && & &

' ' ' '' ' ' '' ' ' '' ' ' '

( ( (( ( (( ( (( ( ( ) ) ) )) ) ) )) ) ) )) ) ) )) ) ) )) ) ) )

* * ** * ** * ** * ** * ** * *

+ + + ++ + + ++ + + ++ + + ++ + + ++ + + +

, , ,, , ,, , ,, , ,, , ,, , ,

- - - -- - - -- - - -- - - -

. . .. . .. . .. . .

/ / / // / / // / / // / / // / / // / / /

0 0 00 0 00 0 00 0 00 0 00 0 0

1 1 1 11 1 1 11 1 1 11 1 1 11 1 1 11 1 1 1

2 2 22 2 22 2 22 2 22 2 22 2 2

3 3 3 33 3 3 33 3 3 33 3 3 3

4 4 44 4 44 4 44 4 45 5 5 5

5 5 5 55 5 5 55 5 5 5

6 6 66 6 66 6 66 6 6

7 7 7 77 7 7 77 7 7 77 7 7 7

8 8 88 8 88 8 88 8 89 9 99 9 99 9 99 9 99 9 99 9 9

: : :: : :: : :: : :: : :: : :

; ; ; ;; ; ; ;; ; ; ;; ; ; ;; ; ; ;; ; ; ;

< < << < << < << < << < << < <

= = = == = = == = = == = = =

> > >> > >> > >> > >? ? ?

? ? ?? ? ?? ? ?

@ @ @@ @ @@ @ @@ @ @

A A AA A AA A AA A A

B B BB B BB B BB B BC C CC C CC C CC C CC C CC C C

D D DD D DD D DD D DD D DD D D

E E EE E EE E EE E EE E EE E E

F F FF F FF F FF F FF F FF F F

G G GG G GG G GG G G

H H HH H HH H HH H H

I I II I II I II I I

J J JJ J JJ J JJ J J

K K KK K KK K K

L L LL L LL L LM M MM M MM M MM M MM M MM M M

N N NN N NN N NN N NN N NN N N

O O OO O OO O OO O OO O OO O O

P P PP P PP P PP P PP P PP P P

Q Q QQ Q QQ Q Q

R R RR R RR R R

S S SS S SS S S

T T TT T TT T T

U U UU U UU U U

V V VV V VV V VW W WW W WW W WW W WW W W

X X XX X XX X XX X XX X X

Y Y YY Y YY Y YY Y YY Y Y

Z Z ZZ Z ZZ Z ZZ Z ZZ Z Z

[ [ [[ [ [[ [ [

\ \ \\ \ \\ \ \ ] ] ] ]

] ] ] ]] ] ] ]

^ ^ ^^ ^ ^^ ^ ^

_ _ _ __ _ _ __ _ _ _

` ` `` ` `` ` `a a aa a aa a aa a aa a a

b b bb b bb b bb b bb b b

c c c cc c c cc c c cc c c cc c c c

d d dd d dd d dd d dd d d

e e e ee e e ee e e e

f f ff f ff f f g g g gg g g gg g g gg g g gg g g g

h h hh h hh h hh h hh h h

i i i ii i i ii i i ii i i ii i i i

j j jj j jj j jj j jj j j

k k k kk k k kk k k k

l l ll l ll l l

m m m mm m m mm m m mm m m m

n n nn n nn n nn n n

o o o oo o o oo o o o

p p pp p pp p pq q qq q qq q qq q qq q qq q q

r r rr r rr r rr r rr r rr r r

s s s ss s s ss s s ss s s ss s s ss s s s

t t tt t tt t tt t tt t tt t t

u u u uu u u uu u u u

v v vv v vv v v w w w ww w w ww w w ww w w ww w w ww w w w

x x xx x xx x xx x xx x xx x x

y y y yy y y yy y y yy y y yy y y yy y y y

z z zz z zz z zz z zz z zz z z

{ { { {{ { { {{ { { {

| | || | || | |

A2,1A

1,1A A 1,3A

2,3A

1,2

2,2

Prozessaufteilung

Prozessaufteilungzeilenweise

spaltenweise

PP

P P P

P

0 2 4

1 3 5

PP

P P P

P

0 1 2

3 4 5

2,5A2,4A

1,4A A 1,6A

2,6A

1,5

2,8A2,7A

1,7A A

A4,7A

3,7 A3,8

4,5A4,4A

3,4A A 3,6A

4,6A

3,5

4,2A4,1A

3,1A A 3,3A

4,3A

3,2

6,2A6,1A

5,1A A 5,3A

A

5,2

8,2A8,1A

7,1A A 7,3A

8,3A 8,5A8,4A

7,4A A 7,6A

8,6A

7,5

8,8A8,7A

7,7A A7,8

6,5A6,4A

5,4A A 5,6A

6,6A

5,5

6,8A6,7A

5,7A A5,8

1,8

7,2

6,3

A

4,8

Abb. 12.1. Blockzykliche Verteilung einer Koeffizientenmatrix A auf P×Q = 2×3 Prozesse.

eindeutig, insgesamt N der Eintrage in L und U konnen frei gewahlt werden. Ei-ne LU-Faktorisierung, bei der alle Diagonalelemente der Matrix U eins sind, heißtauch Crout-Faktorisierung. Beachten Sie, dass, wenn die Diagonalelemente einerder beiden Dreiecksmatrizen implizit vorgegeben sind, die beiden DreiecksmatrizenL und U in einer einzigen Matrix codiert werden konnen. Darum berechnet der HPL-Benchmark die LU-Faktorisierung auch in place, wobei er die Elemente der Aus-gangsmatrix A durch die nicht vorgegebenen Elemente von L und U ersetzt.

Der Vorteil von linearen Gleichungssystemen mit Koeffizentenmatrizen in Drei-ecksform besteht darin, dass sie sich sehr effizient in O(N2) Schritten durch Vorwarts-bzw. Ruckwartssubstitution losen lassen. Nach der Faktorisierung der Matrix Awird das Gleichungssystem (12.4) in zwei Schritten gelost. Zuerst wird durch eineVorwartssubstitution ein Vektor y berechnet, der L · y = b erfullt, aus diesem folgtdurch Ruckwartssubstitution in U · x = y die Losung von (12.2).

Damit der HPL-Benchmark die LU-Faktorisierung auf einem Computer mit ver-teiltem Speicher berechnen kann, muss er naturlich die Koeffizientenmatrix auf dieKnoten verteilen. Dazu wird die Matrix logisch in etwa (N/NB)× (N/NB) jeweilsNB ×NB große Teilmatrizen Ai, j zerlegt und die p = P×Q Prozesse P0,P1, . . . ,Pp−1werden logisch zeilen- oder spaltenweise auf einem P×Q-Prozessgitter angeordnet.Die Verteilung der Teilmatrizen Ai, j auf die Prozesse Pi erhalten Sie, indem Sie dasProzessgitter zyklisch dem Gitter der Teilmatrizen uberlagern, siehe Abb. 12.1.

Aus algorithmischer Sicht kann die Faktorisierung von A in die beiden Drei-ecksmatrizen L und U auf ganz verschiedene Weisen berechnet werden. Standard-implementationen einer LU-Faktorisierung, wie man sie in Lehrbuchern wie [136]findet, sind leider recht langsam. Die zeilen- bzw. spaltenorientierte Arbeitsweisedieser Verfahren harmoniert nicht mit der hierarchischen Speicherarchitektur heu-tiger Computer. Zu oft muss auf Daten zugegriffen werden, die sich gerade nichtim Cache befinden, was zu langsamen Speicherzugriffen bzw. unnotig vielen Daten-transfers zwischen Hauptspeicher und Cache fuhrt. Statt zu rechnen, wartet der Com-puter auf Daten, siehe auch Abschnitt 1.3. Bei Computern mit verteiltem Speichertritt dieses Problem besonders stark in Erscheinung. Effiziente Algorithmen zur LU-

Page 373: [X.systems.press] Cluster Computing ||

370 12 Benchmarks

right-looking

L 3,1 A3,2

A2,2L 2,1

L 1,1

U1,1U1,2 U1,3

A2,3

A3,3

L 1,1

U1,1

L 3,1 L 3,2

L 2,1

U1,2 U1,3

U2,3

A’3,3

L 2,2

U2,2

left-looking

L 3,1 L 3,2

L 2,1

U1,2 A1,3

A2,3

A3,3

L 2,2

U2,2

L 3,1 A3,2

A2,2L 2,1

L 1,1

U1,1A1,2 A1,3

A2,3

A3,3

U1,1

L 1,1

Crout

L 3,1 A3,2

A2,2L 2,1

L 1,1

U1,1U1,2 U1,3

A2,3

A3,3

L 1,1

U1,1

L 3,1 L 3,2

L 2,1

U1,2 U1,3

U2,3

A3,3

L 2,2

U2,2

Abb. 12.2. Schematische Darstellung jeweils eines Schrittes der im HPL-Benchmark im-plementierten LU-Faktorisierungsalgorithmen. Die Methoden right-looking und Crout unter-scheiden sich im Wesentlichen dadurch, dass bei der right-looking-Methode auch die Matrix-elemente in A3,3 transformiert werden, wahrend bei der Crout-Methode in A3,3 nur Zeilenvertauscht werden.

Faktorisierung sind darum so konzipiert, dass die Zahl kostspieliger Speicherzugrif-fe minimiert wird. Dies wird meist dadurch erreicht, dass solche Algorithmen nichtzeilen- bzw. spaltenorientiert sondern blockorientiert arbeiten. Aus diesem Grundverwendet der HPL-Benchmark die oben beschriebene blockzyklische Aufteilungder Koeffizientenmatrix.

Beim HPL-Benchmark kann gleich aus drei solcher blockorientierten LU-Fak-torisierungsalgorithmen gewahlt werden. In der HPL-Dokumentation werden diese

Page 374: [X.systems.press] Cluster Computing ||

12.1 Highly-Parallel LINPACK 371

right-looking, left-looking und Crout genannt. Eine ungefahre Vorstellung von derArbeitsweise dieser Algorithmen soll Ihnen Abb. 12.2 vermitteln. In jedem Schrittbesteht die Koeffizientenmatrix aus mit Li, j bzw. Ui, j bezeichneten Teilmatrizen, dieschon ihre endgultigen Werte haben (in Abb. 12.2 grau hinterlegt), und anderen mitAi, j bzw. A′

i, j bezeichneten Teilmatrizen, die noch in weiteren Schritten der Fak-torisierung zu bearbeiten sind. Teilmatrizen, die vor dem Faktorisierungschritt inAbb. 12.2 den gleichen Namen haben wie danach, werden in einem Schritt (bis aufZeilenvertauschungen) nicht verandert.

Der HPL-Benchmark berechnet die LU-Faktorisierung im Wesentlichen in zweiineinander geschachtelten Schleifen. Bei jedem Durchlauf der außeren Schleife wirdein Schritt der right-looking-Faktorisierung mit Zeilenpivotisierung durchgefuhrt,wobei jeweils NB Spalten und Zeilen der Dreiecksmatrizen berechnet werden. In je-dem Schritt der right-looking-Faktorisierung ist u. a. die LU-Faktorisierung der Ma-trix A2,2 zu berechnen, siehe Abb. 12.2. Dies geschieht rekursiv mit einem auf Ma-trix-Matrix-Operationen basierenden Algorithmus, der in jedem Teilschritt Ndiv neuekleinere Teilprobleme erzeugt bis die neuen Teilprobleme nur noch aus maximalNBmin Spalten bestehen. Bei einem klassischen Rekursionsverfahren sind Ndiv = 2und NBmin = 1. Ist die maximale Rekursionstiefe erreicht, lost der HPL das Teilpro-blem mit einem anderen auf Matrix-Vektor-Operationen basierenden Algorithmus.Sowohl fur den rekursiven auf Matrix-Matrix-Operationen basierenden Teil als auchden auf Matrix-Vektor-Operationen basierenden Teil kann der Algorithmus aus dennumerisch aquivalenten Varianten right-looking, left-looking und Crout gewahlt wer-den. Die HPL-Dokumentation nennt die Faktorisierung von A2,2 auch panel factori-zation. Durch die Zeilenpivotisierung werden einzelne Zeilen in A2,2 vertauscht, sodass die numerische Stabilitat gewahrleistet bleibt.

Nachdem die panel factorization berechnet wurde, mussen die Zeilenvertau-schungen in A2,2 naturlich auch in den Submatrizen L2,1 und A2,3 nachgeholt werden.Außerdem benotigen die Prozesse, die die Submatrix A2,3 speichern, die MatrizenL2,2, U2,2 und L3,2, um daraus U2,3 und A′

3,3 zu berechnen. Die Matrizen L2,2, U2,2und L3,2 sowie die Daten uber die Zeilenvertauschungen sendet der HPL-Benchmarkmit einer von sechs verschiedenen Broadcast-Varianten. Abbildung 12.3 zeigt die

t = 7

t = 1 t = 70P 1P 2P 3P 4P 5P 6P 7P

t t = 2 t = 3 t = 4 t = 5 t = 6= 0

0P 1P 2P 3P 4P 5P 6P 7P

t = 0 t = 1 t = 2 t = 3 t = 4 t = 5 t = 6

Abb. 12.3. Zwei von sechs HPL-Broadcast-Varianten, bei denen die Daten jeweils in einerNachrichtenkette weitergeleitet werden. Der Einfachheit halber wird in der Abbildung jeweilsProzess P0 als Broadcast-Quelle angenommen. Unter den Prozessen ist jeweils der Zeitpunktvermerkt, an dem ihn die Daten erreicht haben.

Page 375: [X.systems.press] Cluster Computing ||

372 12 Benchmarks

zwei einfachsten dieser Varianten. Eine Beschreibung der anderen Broadcast-Varian-ten finden Sie in der HPL-Dokumentation.

Hat der HPL-Benchmark das Gleichungssystem gelost, so setzt er noch das Er-gebnis in die Ausgangsgleichung ein und berechnet die skalierten Residuen

rN =||A · x−b||∞||A||1 ·N · ε , r1 =

||A · x−b||∞||A||1 · ||x||1 · ε und r∞ =

||A · x−b||∞||A||∞ · ||x||∞ · ε . (12.5)

Alle diese Residuen durfen nicht mit der Systemgroße N wachsen, ε ist die relativeRechengenauigkeit des verwendeten Computers, welche typischerweise bei ε = 2−52

liegt. Mit A ∈ RM×N sind die beiden in (12.5) benutzten Matrixnormen als

||A||1 = max1≤ j≤N

M

∑i=1

|ai, j| und ||A||∞ = max1≤i≤M

N

∑j=1

|ai, j| (12.6)

definiert.

12.1.2 Installation

Wollen Sie die Fließkommaleistung Ihres Clusters mit dem HPL-Benchmark messen,so benotigen Sie dafur

• die Implementierung des HPL-Benchmark [68],• eine MPI-Bibliothek und• eine fur Ihren Cluster optimierte BLAS-Bibliothek.

Eine MPI-Bibliothek sowie eine BLAS-Bibliothek haben Sie sicher schon auf IhremCluster installiert, wenn nicht holen Sie dies nun nach, siehe auch Abschnitte 6.1 und11.1. Wir gehen hier davon aus, dass LAM/MPI [89] und die BLAS-Implementationaus der ATLAS-Bibliothek verwendet werden. Falls Sie andere MPI- oder BLAS-Im-plementationen verwenden wollen, so konnen Sie die nun folgenden Ausfuhrungenleicht auf diese adaptieren.

Zunachst ist der HPL-Benchmark von [68] herunterzuladen und zu entpacken.

bauke@server:˜/mpi$ gunzip hpl.tgz; tar -xvf hpl.tarbauke@server:˜/mpi$ cd hpl

Die Ubersetzung des HPL-Benchmarks wird durch Makefiles gesteuert. Dazu gehortauch ein architekturspezifisches Makefile, in dem z. B. vermerkt ist, wo die MPI-und die BLAS-Bibliothek zu finden sind, und das Sie selbst erstellen mussen. ImVerzeichnis setup liegen einige Beispieldateien, die Ihnen dabei als Vorlage die-nen konnen. Das tatsachlich verwendete architekturspezifische Makefile muss imHauptverzeichnis des HPL-Benchmarks liegen und dessen Name aus dem PrafixMake. und einem frei wahlbaren Suffix (z. B. Linux atlas) bestehen. Dieser Zu-satz dient zur Identifizierung der Plattform, fur die der HPL-Benchmark kompiliertwird. Im architekturspezifischen Makefile mussen Sie einige Variablen deklarieren,siehe Listing 12.1.

Page 376: [X.systems.press] Cluster Computing ||

12.1 Highly-Parallel LINPACK 373

Listing 12.1. Architekturspezifisches Makefile fur den HPL-Benchmark.

# −−− P l a t t f o r m −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−ARCH = Linux_atlas# −−− S h e l l−Kommandos −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−SHELL = /bin/sh

5 CD = cdCP = cpLN_S = ln -sMKDIR = mkdirRM = /bin/rm -f

10 TOUCH = touch# −−− HPL V e r z e i c h n i s s t r u k t u r / HPL B i b l i o t h e k −−−−−−−−−−−−−−−−−−−−−−−−TOPdir = /home/bauke/mpi/hplINCdir = $(TOPdir)/includeBINdir = $(TOPdir)/bin/$(ARCH)

15 LIBdir = $(TOPdir)/lib/$(ARCH)HPLlib = $(LIBdir)/libhpl.a# −−− MPI B i b l i o t h e k −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−MPdir =MPinc = /usr/local/include

20 MPlib =# −−− L i n e a r e Algeb ra B i b l i o t h e k −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−LAdir = /usr/local/ATLASLAinc = $(LAdir)/includeLAlib = $(LAdir)/lib/Linux_ATHLONSSE1/libcblas.a \

25 $(LAdir)/lib/Linux_ATHLONSSE1/libatlas.a# −−− FORTRAN77−C−S c h n i t t s t e l l e −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−F2CDEFS =# −−− HPL H e a d e r d a t e i e n , B i b l i o t h e k e n , HPL s p e z i f i s c h e s −−−−−−−−−−−−−−−−HPL_INCLUDES = -I$(INCdir) -I$(INCdir)/$(ARCH) -I$(LAinc) -I$(MPinc)

30 HPL_LIBS = $(HPLlib) $(LAlib) $(MPlib)HPL_OPTS = -DHPL_CALL_CBLASHPL_DEFS = $(F2CDEFS) $(HPL_OPTS) $(HPL_INCLUDES)# −−− Compi le r und L i n k e r −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−CC = mpicc

35 CCNOOPT = $(HPL_DEFS)CCFLAGS = $(HPL_DEFS) -O3 -WallLINKER = mpiccLINKFLAGS = $(CCFLAGS)ARCHIVER = ar

40 ARFLAGS = rRANLIB = ranlib

ARCH. Diese Variable beschreibt die Architektur, fur die der HPL-Benchmark kom-piliert wird und sollte mit dem Suffix des Makefile-Namens ubereinstimmen.

SHELL, CD, CP, LN S, MKDIR, RM, TOUCH. Durch diese Variablen legen Sie fest,mit Hilfe welcher Befehle u. a. das Arbeitsverzeichnis gewechselt und Dateienkopiert oder geloscht werden.

TOPdir, INCdir, BINdir, LIBdir, HPLlib. In diesen Variablen stehen dieVerzeichnisse, in denen die Quellen, die Headerdateien, das Binarprogramm unddie Bibliotheken des HPL-Benchmarks liegen.

MPdir, MPinc, MPlib. Diese Variablen sind dazu gedacht, das Verzeichnis derMPI-Bibliothek, das Verzeichnis der MPI-Headerdateien und die MPI-Biblio-

Page 377: [X.systems.press] Cluster Computing ||

374 12 Benchmarks

thek aufzunehmen. Wenn Sie jedoch LAM/MPI richtig installiert haben, konnenSie den HPL-Benchmark mit den LAM/MPI-Wrapper-Compilern ubersetzenund mussen nur MPinc setzen.

LAdir, LAinc, LAlib. Hiermit legen Sie fest, welche BLAS-Implementation beider Ubersetzung des HPL-Benchmarks verwendet werden soll und wo dieBLAS-Headerdateien bzw. die BLAS-Bibliothek zu finden sind.

F2CDEFS. Der HPL-Benchmark ist in C geschrieben, die BLAS-Routinen, die erbenutzt, sind aber normalerweise in FORTRAN 77 programmiert. Leider gehenFORTRAN-77- und C-Compiler unterschiedlich mit Funktionsnamen, Ganzzah-len und Zeichenketten um, so dass es gar nicht so einfach ist, eine FORTRAN-77-Routine aus einem C-Programm heraus aufzurufen. Die Variable F2CDEFS be-schreibt, was dabei zu beachten ist, und muss dazu genau ein Schlusselwort ausjeder von drei Kategorien enthalten.1. FORTRAN-77-Compiler andern oft die interne Reprasentation eines Funkti-

onsnamen. Die erste Kategorie bestimmt, wie der FORTRAN-77-Compilerdie interne Reprasentation von Funktionsnamen andert.-DAdd . Funktionsnamen bestehen aus kleinen Buchstaben und der Com-

piler fugt ihm einen Unterstrich (” “) als Suffix hinzu. Im Zweifelsfalleprobieren Sie zuerst diese Option.

-DNoChange. Funktionsnamen bestehen aus kleinen Buchstaben, ansons-ten nimmt der FORTRAN-77-Compiler aber keine Modifikationen vor.

-DUpCase. Funktionsnamen bestehen aus großen Buchstaben, ansonstennimmt der FORTRAN-77-Compiler aber keine Modifikationen vor.

-DAdd . Funktionsnamen bestehen aus kleinen Buchstaben und der Com-piler fugt ihm zwei Unterstriche (” “) als Suffix hinzu.

2. Die Optionen der zweiten Kategorie verraten dem HPL, welcher C-Typ ei-nem FORTRAN 77 INTEGER entsprechen.-DF77 INTEGER=int. Ein FORTRAN 77 INTEGER entspricht in C ei-

nem int. Dies durfte in den allermeisten Fallen zutreffen.-DF77 INTEGER=long. Ein FORTRAN 77 INTEGER entspricht in C

einem long.-DF77 INTEGER=short. Ein FORTRAN 77 INTEGER entspricht in C

einem short.3. In der dritten Kategorie wird beschrieben, wie der FORTRAN 77-Compiler

Zeichenketten behandelt.-DStringSunStyle. Bei Funktionsaufrufen, die ein Zeichenkettenargu-

ment erwarten, wird die Adresse der Zeichenkette als Argument uberge-ben. Zusatzlich besitzt die Funktion ein weiteres implizites Argument inForm eines FORTRAN 77 INTEGER, das die Lange der Zeichenketteenthalt. Wahlen Sie im Zweifelsfalle diese Option.

-DStringStructPtr. Bei Funktionsaufrufen mit Zeichenkettenargu-menten wird die Adresse einer Struktur ubergeben, die Adresse undLange der Zeichenkette enthalt und in C das Aquivalent

struct { char *cp; F77_INTEGER len; }

Page 378: [X.systems.press] Cluster Computing ||

12.1 Highly-Parallel LINPACK 375

hat.-DStringStructVal. Funktionsaufrufe mit Zeichenkettenargumenten

werden wie bei -DStringStructPtr behandelt, jedoch wird statteines Zeigers auf eine Struktur die Struktur selbst ubergeben.

-DStringCrayStyle. Wahlen Sie diese Option, falls Sie einen Cray-Computer Ihr Eigen nennen konnen.

HPL INCLUDES, HPL LIBS. Der Inhalt dieser Variablen wird spater dem Compi-ler ubergeben, um ihm mitzuteilen, wo die Headerdateien und Bibliotheken desHPL-Benchmarks liegen.

HPL OPTS. Durch diese Variable konnen Sie die Kompilation des HPL-Benchmarkssteuern. Statt einer in FORTRAN 77 implementierten BLAS-Bibliothek konnenSie auch eine in C geschriebene BLAS-Bibliothek (-DHPL CALL CBLAS)oder eine VSIP genannte Bibliothek (-DHPL CALL VSIPL) verwenden. Mit-DHPL DETAILED TIMING erzeugt der HPL-Benchmark eine noch ausfuhrli-chere Statistik.

HPL DEFS. Hier werden lediglich einige Variablen zusammengefasst.CC, CCNOOPT, CCFLAGS. Bei diesen Variablen sind der Compiler und die Optio-

nen fur den Compiler mit und ohne Optimierung anzugeben.LINKER, LINKFLAGS, ARCHIVER, ARFLAGS, RANLIB. Durch diese Variablen

wahlen Sie die zur Erstellung von Bibliotheken benotigten Programme aus.

Unter Angabe des Namens der Zielarchitektur bzw. des Suffixes des architekturspezi-fischen Makefiles lasst sich der HPL-Benchmark nun kompilieren. Fur unsere Tests,bei denen wir die ATLAS-Bibliothek und LAM/MPI verwendeten, haben wir denHPL-Benchmark mit dem in Listing 12.1 gezeigten Makefile ubersetzt.

bauke@server:˜/mpi/hpl$ make arch=Linux_atlas

Im Verzeichnis bin/Linux atlas finden Sie nun zwei Dateien, das Benchmark-programm xhpl und die Konfigurationsdatei des Benchmarks HPL.dat. An denParametern in der Konfigurationsdatei konnen Sie nun nach Herzenslust ”schrauben“,um eine hochstmogliche Fließkommaleistung herauszuholen.

12.1.3 Konfiguration

Bei einem Programmlauf des HPL-Benchmark werden nacheinander mehrere Glei-chungssysteme verschiedener Große mit verschiedenen Parametern, die die interneArbeistweise des LU-Faktorisierungsalgorithmus beeinflussen, gelost. Fur diese Pa-rameter konnen jeweils gleich mehrere Werte in der Konfigurationsdatei angegebenwerden. Der HPL-Benchmark wird dann mit allen moglichen Kombinatinen von Pa-rameterwerten durchgefuhrt. Die Zahl der insgesamt gelosten Gleichungssysteme istsomit gleich dem Produkt der Multiplizitat dieser Parameter.

Der Aufbau der Konfigurationsdatei ist recht starr. Sie besteht aus insgesamt31 Zeilen, derer jede einen oder mehrere Parameter aufnimmt. Listing 12.2 zeigtein Beispiel fur eine HPL-Konfigurationsdatei. Die Kommentare jeweils hinter denParametern werden vom HPL-Benchmark ignoriert.

Page 379: [X.systems.press] Cluster Computing ||

376 12 Benchmarks

Listing 12.2. Beispielkonfigurationsdatei fur den HPL-Benchmark.

HPLinpack benchmark input fileInnovative Computing Laboratory, University of TennesseeHPL.out output file name (if any)6 device out (6=stdout,7=stderr,file)

5 3 # of problems sizes (N)1000 5000 125002 # of NBs60 120 NBs0 PMAP process mapping (0=Row-,1=Column-major)

10 1 # of process grids (P x Q)2 Ps2 Qs-16.0 threshold1 # of panel fact

15 0 PFACTs (0=left, 1=Crout, 2=Right)2 # of recursive stopping criterium2 4 NBMINs (>= 1)1 # of panels in recursion2 NDIVs

20 1 # of recursive panel fact.0 RFACTs (0=left, 1=Crout, 2=Right)1 # of broadcast0 BCASTs (0=1rg,1=1rM,2=2rg,3=2rM,4=Lng,5=LnM)2 # of lookahead depth

25 0 1 DEPTHs (>=0)0 SWAP (0=bin-exch,1=long,2=mix)64 swapping threshold0 L1 in (0=transposed,1=no-transposed) form0 U in (0=transposed,1=no-transposed) form

30 1 Equilibration (0=no,1=yes)8 memory alignment in double (> 0)

1.–2. Zeile. Die ersten beiden Zeilen enthalten lediglich Kommentare.3. Zeile. Falls die Resultate des HPL-Benchmark in eine Datei umgeleitet werden

sollen, so ist hier ihr Name anzugeben. Alles nach dem ersten Leerzeichen wirdignoriert und kann als Kommentar dienen.

4. Zeile. Hier wird durch einen numerischen Wert festgelegt, wohin der HPL-Bench-mark seine Ergebnisse schreibt. Eine 6 steht fur die Standardausgabe, eine 7 furdie Standardfehlerausgabe. Jede andere positive Ganzzahl lasst den Benchmarkseine Ergebnisse in die in Zeile 3 spezifizierte Datei schreiben.

5.–6. Zeile. In Zeile 5 steht die Anzahl der verschiedenen Systemgroßen (Sollte klei-ner als 20 sein.) und die darauf folgende Zeile enthalt die Systemgroßen selbst.

7.–8. Zeile. In der 7. Zeile steht die Anzahl (Sollte kleiner als 20 sein.) der verschie-denen Blockgroßen NB und die darauf folgende Zeile enthalt die Blockgroßen,siehe auch Abschitt 12.1.1.

9. Zeile. Diese Zeile bestimmt, wie die MPI-Prozesse und die Koeffizientenmatrixaufeinander abgebildet werden. Eine 0 steht fur eine zeilenweise, eine 1 fur einespaltenweise Zuordnung der Prozesse, siehe auch Abb. 12.1. Die Wahl der Pro-zessaufteilung hat auf die Fließkommaleistung nur dann einen Einfluss, wenndie Bandbreite, mit der Nachrichten zwischen je zwei Prozesse ausgetauscht

Page 380: [X.systems.press] Cluster Computing ||

12.1 Highly-Parallel LINPACK 377

werden konnen, nicht fur alle moglichen Paare von Prozessen gleich ist. Einesolche Asymmetrie ist z. B. bei Clustern mit SMP-Knoten gegeben, siehe Ab-schnitt 12.1.5. Bei homogenen Clustern aus Knoten mit nur einer CPU und mitsternformiger Topologie ist die Wahl der Prozessaufteilung praktisch ohne Rele-vanz.

10.–12. Zeile. Die 10. Zeile legt fest, wieviele verschiedene Prozessgitter verwendetwerden sollen. Die darauf folgenden Zeilen enthalen die Zahl der Zeilen (P) undSpalten (Q) der kartesischen Prozessgitter.

13. Zeile. Nachdem der HPL-Benchmark ein Gleichungssystem gelost hat, kann ersein Ergebnis in das Gleichungsystem einsetzen und so die Genauingkeit sei-ner Rechnung uberprufen und die reskalierten Fehlerwerte (12.5) errechnen. DieZahl in dieser Zeile legt eine obere Schranke fur diesen reskalierten Fehlerwertfest. Findet der HPL-Benchmark einen Fehler großer als diese Schranke, wirdder Test als nicht bestanden bewertet. Der Zahlenwert in dieser Zeile sollte etwa16 betragen. Ist er negativ, so unterbleibt die Uberprufung der Rechengenauig-keit, was etwas Rechenzeit spart.

14.–21. Zeile. Der HPL-Benchmark implementiert drei numerisch aquivalente LU-Faktorisierungsalgorithmen. Wie in Abschnitt 12.1.1 dargestellt, konnen der re-kursive auf Matrix-Matrix-Operationen basierenden Algorithmus als auch derin der innersten Schleife verwendete auf Matrix-Vektor-Operationen basierendeAlgorithmus frei gewahlt werden. In Zeile 14 steht, wieviele verschiedene nicht-rekursive Algorithmen in der innersten Schleife getestet werden, und in der fol-genden Zeile die Algorithmen selbst in Form von Zahlen: 2 (right-looking), 0(left-looking) oder 1 (Crout). Analog wird in den Zeilen 20 und 21 der im rekur-siven Teil zu verwendene Algorithmus festgelegt. In den Zeilen 16 und 17 stehendie Zahl der zu testenden Abbruchkriterien und die Abbruchkriterien NBmin derRekursion. Die Zahl, der in jedem Rekursionsschritt erzeugten neuen Teilproble-me Ndiv, wird in den Zeilen 18 und 19 festgelegt.

22.–23. Zeile. Zur Weiterleitung des Ergebnisses einer panel factorization imple-mentiert der HPL-Benchmark insgesamt sechs verschiedene Broadcast-Varian-ten, siehe auch Abb. 12.3. Durch eine Zahl zwischen 0 und 5 konnen Sie hiereine dieser Varianten wahlen. In unseren Experimeneten fanden wir, dass dieWahl der Broadcast-Variante kaum einen Einfluss auf die Performance hat. DieVarianten 1 und 3 durften meist eine gute Wahl sein.

24.–31. Zeile. Diese Zeilen beeinflussen weitere Details des Losungsalgorithmus.Ubernehmen Sie hier erst einmal die Standardwerte. Wenn Sie alle anderen Ein-stellmoglichkeiten schon ausgereizt haben, konnen Sie hier vielleicht noch einpaar Prozent herausholen. Nahres finden Sie in der HPL-Dokumentation.

Haben Sie die Konfigurationsdatei des HPL-Benchmark Ihren Wunschen angepasst,so konnen Sie ihn wie jedes andere MPI-Programm starten. Das großte in der Konfi-gurationsdatei spezifizierte Prozessgitter bestimmt, wieviele MPI-Prozesse zu startensind. In der Konfigurationsdatei 12.2 wurde ein 2× 2-Gittern angegeben, der HPL-Benchmark muss hier also mit vier Prozessen gestartet werden.

Page 381: [X.systems.press] Cluster Computing ||

378 12 Benchmarks

Listing 12.3. Ausgaben des HPL-Benchmark bei Verwendung der Konfigurationsdatei 12.2.============================================================================HPLinpack 1.0a -- High-Performance Linpack benchmark -- January 20, 2004Written by A. Petitet and R. Clint Whaley, Innovative Computing Labs., UTK============================================================================

5An explanation of the input/output parameters follows:T/V : Wall time / encoded variant.N : The order of the coefficient matrix A.NB : The partitioning blocking factor.

10 P : The number of process rows.Q : The number of process columns.Time : Time in seconds to solve the linear system.Gflops : Rate of execution for solving the linear system.

15 The following parameter values will be used:

N : 1000 5000 12500NB : 60 120PMAP : Row-major process mapping

20 P : 2Q : 2PFACT : LeftNBMIN : 2 4NDIV : 2

25 RFACT : LeftBCAST : 1ringDEPTH : 0 1SWAP : Binary-exchangeL1 : transposed form

30 U : transposed formEQUIL : yesALIGN : 8 double precision words

============================================================================35 T/V N NB P Q Time Gflops

----------------------------------------------------------------------------WR00L2L2 1000 60 2 2 0.78 8.578e-01WR00L2L4 1000 60 2 2 0.78 8.590e-01WR10L2L2 1000 60 2 2 0.71 9.472e-01

40 WR10L2L4 1000 60 2 2 0.70 9.573e-01WR00L2L2 1000 120 2 2 0.87 7.694e-01WR00L2L4 1000 120 2 2 0.86 7.742e-01WR10L2L2 1000 120 2 2 0.78 8.530e-01WR10L2L4 1000 120 2 2 0.78 8.584e-01

45 WR00L2L2 5000 60 2 2 24.64 3.384e+00WR00L2L4 5000 60 2 2 24.57 3.393e+00WR10L2L2 5000 60 2 2 25.76 3.236e+00WR10L2L4 5000 60 2 2 25.85 3.225e+00WR00L2L2 5000 120 2 2 24.95 3.342e+00

50 WR00L2L4 5000 120 2 2 24.92 3.346e+00WR10L2L2 5000 120 2 2 24.84 3.357e+00WR10L2L4 5000 120 2 2 24.91 3.347e+00WR00L2L2 12500 60 2 2 266.36 4.889e+00WR00L2L4 12500 60 2 2 266.17 4.893e+00

55 WR10L2L2 12500 60 2 2 290.98 4.476e+00WR10L2L4 12500 60 2 2 292.23 4.456e+00WR00L2L2 12500 120 2 2 250.51 5.199e+00WR00L2L4 12500 120 2 2 250.27 5.204e+00WR10L2L2 12500 120 2 2 266.66 4.884e+00

60 WR10L2L4 12500 120 2 2 266.91 4.879e+00============================================================================

Finished 24 tests with the following results:24 tests completed without checking,

65 0 tests skipped because of illegal input values.----------------------------------------------------------------------------

End of Tests.============================================================================

Page 382: [X.systems.press] Cluster Computing ||

12.1 Highly-Parallel LINPACK 379

W R 0 0 L 2 L 2Zeile 17Zeile 15Zeile 19Zeile 21Zeile 23Zeile 25Zeile 9ohne Bedeutung

Ndiv

rekursiver AlgorithmusBroadcast−Variante

Prozessaufteilung

Algorithmus in innerster SchleifeNBmin

Abb. 12.4. Bedeutung des Codes der ersten Spalte der HPL-Resultate.

bauke@server:˜/mpi/hpl/bin/Linux_atlas$ mpirun -np 4 xhpl

In Listing 12.3 sehen Sie die Ausgaben des HPL-Benchmarks. Nach einigen Kom-mentaren und einer Ubersicht uber die in der Konfigurationsdatei spezifizierten Pa-rameter folgen in einer Tabelle die Ergebnisse des HPL-Benchmark. In den erstenfunf Spalten stehen zum Teil in codierter Form die Parameter, mit denen jeweils einTest durchgefuhrt wurde. Die Kurzel in der ersten Spalte korrespondieren jeweilszu verschiedenen Parametern bzw. Zeilen der Konfigurationsdatei, siehe Abb. 12.4.Die zweite Spalte enthalt die Große des Gleichungssystems, die dritte die Block-große (7.–8. Zeile der Konfigurationsdatei), vierte und funfte Zeile geben die Großedes Prozessgitters wieder. In der sechsten Spalte steht die zur Berechnung der LU-Faktorisierung benotigte Zeit in Sekunden und in der letzten Spalte die sich darausergebende Fließkommaleistung in GFlops. Ist die Testgroße in Zeile 13 der Konfigu-rationsdatei positiv, so werden außerdem noch die Residuen (12.5) ausgegeben.

12.1.4 Optimierung

Wie Sie sehen, bietet die Konfigurationsdatei des HPL-Benchmarks zahlreiche Ein-stellmoglichkeiten. Aber welche Parameter soll man wahlen, nun eine moglichst ho-he Fließkommaleistung zu erreichen? Naturlich lasst sich diese Frage nicht allge-meingultig beantworten. Allerdings gibt es einige Faustregeln.

Zunachst sollten Sie unbedingt eine auf Ihre Hardware optimierte BLAS-Imple-mentation verwenden. Eine optimierte BLAS-Implementation kann bis zu einen Fak-tor funf schneller als die BLAS-Referenzimplementation sein. Basiert Ihr Cluster aufIntel-CPUs, so ist sicher Intels Math Kernel Library das richtige fur Sie. Fur AMD-Prozessoren gibt es die AMD Core Math Library, ATLAS lasst sich fur eine Vielzahlvon CPUs optimieren, siehe auch Abschnitt 11.1.2.

Fur die in der Konfigurationsdatei des HPL-Benchmarks zu spezifizierenden Pa-rameter gelten die folgenden Richtlinien.

Systemgroße (5.–6. Zeile). Je großer das zu losende Gleichungssystem ist, destoeffizienter kann dies in der Regel gelost werden. Das Gleichungssystem solltedarum moglichst groß sein. Wenn jedem der p Prozessoren des Clusters M ByteArbeitsspeicher zur Verfugung stehen, sollte, da eine Fließkommazahl typischer-weise acht Byte Speicher belegt, die Zahl N der Unbekannten des zu losenden

Page 383: [X.systems.press] Cluster Computing ||

380 12 Benchmarks

Gleichungssystems N ≈ √p ·M/8 sein. In einem inhomogenen Cluster, bei des-

sen Knoten die Arbeitsspeichergroße variiert, ist fur M die Große des kleinstenArbeitsspeichers anzusetzen. Tatsachlich ist die Gleichungssystemgroße kleinerzu wahlen, das Betriebssystem braucht ja auch noch etwas Platz.

Blockgroße (7.–8. Zeile). Die in den Zeilen sieben und acht spezifizierte Block-große beeinflusst sowohl die Aufteilung der Daten als auch die Granularitatder Rechnung. Einerseits sollte die Blockgroße fur eine gleichmaßige Lastver-teilung moglichst klein sein. Andererseits fuhrt eine kleine Blockgroße auchdazu, dass der Computer in sehr kurzen Abstanden immer wieder neue Datenaus dem Hauptspeicher in den Cache laden muss, was die CPU stark ausbremst.Nur wenn die Blockgroße hinreichend groß ist, kann die CPU den schnellenCachespeicher effizient nutzen. Erfahrungsgemaß liegen gunstige Blockgroßenirgendwo zwischen 32 und 256. Wo genau, das mussen Sie empirisch bestimmen.Dazu ist bei sonst fixen Parametern die Blockgroße zwischen 32 und 256 syste-matisch zu variieren. Die Systemgroße sollte dabei nicht zu klein sein (Richt-wert: zwischen 1000 und 5000). Meist treten gunstige Blockgroßen periodischauf, z. B. 60, 120 und 180. Bei sehr großen Gleichungssystemen sind die große-ren dieser Werte oft etwas besser als die kleinen, siehe dazu auch Listing 12.3.

Prozessaufteilung (9.–12. Zeile). Hat Ihr Cluster Knoten mit mehr als einer CPU,so probieren Sie sowohl eine zeilenweise als auch eine spaltenweise Zuweisungzwischen den MPI-Prozessen und der Koeffizientenmatrix. Bei sonst gleichenParametern ist eine dieser Methoden oft deutlich schneller als die andere. Nochwichtiger ist jedoch die Geometrie der Aufteilung. Das kartesische P×Q großeGitter, in dem die MPI-Prozesse auf die Koeffizientenmatrix abgebildet werden,sollte moglichst quadratisch sein. Zum Beispiel lassen sich in einem Cluster mitzwolf CPUs sechs Gitter verschiedener Geometrie formen: 1×12, 2×6, 3×4,4×3, 2×6 und 12×1. Im Sinne einer guten Lastverteilung sollte man hier einGitter der Form 3× 4 oder 4× 3 wahlen. Allerdings sind diese beiden Formennicht zwingend gleich gut.

Weitere Tuningtipps und Informationen zum HPL-Benchmark finden Sie in der HPL-Dokumentation und auf der Homepage von Jack Dongarra [30].

12.1.5 Ergebnisse

Auf einem kleinen Cluster aus sechs SMP-Knoten mit jeweils zwei mit 1,2 GHzgetakteten AMD Athlon Prozessoren haben wir einige Tests durchgefuhrt, anhandderer einige grundsatzliche Effekte des HPL-Benchmarks deutlich werden. Die Kno-ten waren uber Fast Ethernet untereinander verbunden. Fur den ersten Teil unsererTests haben wir jeweils nur eine CPU je Knoten verwendet.

Das Losen eines linearen Gleichungssystems gehort sicher nicht in die Klassevon Problemen, die naturlicherweise in unabhangige Teilprobleme zerfallen. Die Be-rechnung einer LU-Faktorisierung lasst sich nur parallelisieren, indem die Knotenimmer wieder Nachrichten untereinander austauschen. Wie stark wirkt sich unserdoch recht langsames Kommunikationsnetz auf das Skalierungsverhalten des HPL-Benchmarks aus?

Page 384: [X.systems.press] Cluster Computing ||

12.1 Highly-Parallel LINPACK 381

Um diese Frage zu beantworten, haben wir den HPL-Benchmark zunachst mitnur einem Prozess, d. h. auf einem 1×1-Prozessgitter gestartet und dann die Zahl derProzesse schrittweise erhoht. In Abb. 12.5 ist die Fließkommaleistung als Funktionder Gleichungssystemgroße dargestellt. Wenn der HPL-Benchmark mit nur einemProzess durchgefuhrt wird, misst er die Fließkommaleistung einer einzelnen CPU.Das Netzwerk schlagt hier noch nicht als limitierender Faktor zu. Wegen der super-skalaren Architektur des AMD Athlon Prozessors betragt die theoretische Hochst-leistung einer CPU 2,4 GFlops. Zumindest fur kleine Gleichungssysteme liegt dietatsachliche Fließkommaleistung jedoch deutlich darunter. Mit wachsender System-große wachst allerdings auch die Fließkommaleistung bis auf ca. 1,9 GFlops also ca.80 % der theoretischen Hochstleistung an. Dies ist ein recht guter Wert. Sollten Siein Ihren eigenen Experimenten mit dem HPL-Benchmark auf nur einer CPU Fließ-kommaleistungen unter 50 % der theoretischen Hochstleistung messen, so haben Siewahrscheinlich eine ungeeignete BLAS-Implementation verwendet.

Dass die Fließkommaleistung mit wachsender Gleichungssystemgroße ansteigt,ist ein ganz generelles Phanomen. Bei großen Gleichungssystemen liegt ein gunsti-geres Verhaltnis zwischen Rechenoperationen und Schreib-Lese-Operationen auf Ca-che und Hauptspeicher vor, denn hier arbeitet der HPL-Benchmark langer auf cache-lokalen Daten. Fur HPL-Benchmark-Tests auf einem Cluster gilt dies genau so wiefur Tests aus einem Einzelknoten. Hier kommt lediglich noch eine Speicherschichthinzu. Neben langsamen Schreib-Lese-Operationen auf Cache und Hauptspeicherkommen die noch viel langsameren Sende-Empfangs-Operationen zwischen den Pro-zessen hinzu.

An Abb. 12.5 kann man aber noch andere interessante Dinge ablesen, z. B. dassman mit mehr Knoten auch großere Probleme losen kann. Da die Knoten mit jeweils

0

1

2

3

4

5

6

7

8

0 5000 10000 15000 20000 25000

Flie

ßkom

mal

eist

ung

in G

flop

s

N

1 × 11 × 21 × 32 × 21 × 52 × 3

Abb. 12.5. Mit HPL-Benchmark ermittelte Fließkommaleistung als Funktion der Gleichungs-systemgroße N fur verschiedene Prozessgitter bzw. verschieden viele Prozesse.

Page 385: [X.systems.press] Cluster Computing ||

382 12 Benchmarks

1 GByte Arbeitsspeicher ausgestattet waren, konnten auf einem einzigen Knoten ma-ximal Systeme mit 11 585 Unbekannten gelost werden. Da das Betriebssystem auchnoch seinen Platz beansprucht, haben wir nur Systeme bis N = 10000 gelost. Be-trachtet man den Speicher als einzige begrenzende Ressource, so konnen mit mehrKnoten auch immer großere Probleme gelost werden. Insbesondere wachst die maxi-male Große der Gleichungsysteme monoton mit der Zahl der Knoten.

Aber kann man mit mehr Knoten die linearen Gleichungssysteme auch immerschneller losen? Abbildung 12.5 entnehmen wir: Ja, man kann, wenn sie groß genugsind. Falls die Gleichungssysteme mehr als 4 000 Unbekannte haben, dann sind meh-rere Knoten immer schneller als ein einzelner. Lauft der HPL-Benchmark auf meh-reren Knoten, steht potentiell eine großere Rechenleistung zur Verfugung, jedochmussen die Knoten ihre Arbeit uber das relativ langsame Netzwerk koordinieren.Erst bei großen Gleichungssystemen verschiebt sich die Zahl der Rechen- und Kom-munikationsoperationen zu Gunsten der Rechenoperationen. Wir sehen hier nichtsweiter als die praktischen Auswirkungen von feiner und grober Granularitat auf dieRechenleistung, die wir in Abschnitt 1.6 theoretisch diskutiert haben.

Auch wenn mehrere Knoten schneller sind als ein einzelner Knoten, heißt mehrnoch langst nicht immer schneller. Bei fester Systemgroße (großer als 4 000) sindzwei Knoten schneller als einer, drei ein wenig schneller als zwei, mit vier Knotenerreichen wir nocheinmal einen deutlichen Geschwindigkeitssprung. Nehmen wirjedoch einen weiteren Knoten hinzu, sinkt die Fließkommaleistung plotzlich. Erstmit sechs Knoten wird wieder ein weiterer Geschwindigkeitszuwachs erreicht. BeiBenchmarks mit drei und funf Knoten musste ein recht ungunstiges Prozessgitter mitsehr unterschiedlichen Langen gewahlt werden. Unter recht allgemeinen Annahmenuber den verwendeten Computer kann man zeigen [75], dass die Zeit, die der HPL-Benchmark auf einem P×Q-Prozessgitter zur Losung eines Gleichungssystems mitN Unbekannten benotigt, etwa

THPL = γ2N3

3PQ+β

N2(3P+Q)

2PQ+α

N((NB +1) logP+P)

NB(12.7)

betragt. Die Konstanten sind die Latenz (α), und inverse Bandbreite (β ) bei derKommunikation zwischen den Knoten sowie die inverse Fließkommaleistung einesKnotens (γ). Bei einer Aufteilung von p Prozessen auf ein Gitter mit P = 1 undQ = p bzw. P = p und Q = 1 ist die Laufzeit nach (12.7) deutlich schlechter alsfur P ≈ Q ≈√

p. Wie ungunstig eine stark asymmetrische Aufteilung ist, sieht manbesonders gut, wenn man fur eine feste Systemgroße den Speedup (1.2) bzw. die Ef-fizienz (1.11) auftragt, siehe Abb. 12.6. Mit nur vier Prozessoren maßen wir wegender gunstigen 2×2-Aufteilung einen großeren Speedup als mit funf Prozessoren beider ungunstigen 1×5-Aufteilung.

Die Knoten eines Cluster-Computers sind heute oft SMP-Systeme. Hier lasstsich der HPL-Benchmark auf zwei Arten durchfuhren. Die naheliegende Variantebesteht darin, auf jedem Knoten statt nur eines MPI-Prozess gleich soviele Prozessezu starten, wie ein Knoten CPUs hat. Bei der anderen Variante wird je Knoten nurein MPI-Prozess gestartet. Jeder MPI-Prozess ist diesmal aber ein Programm, dasmehrere Threads ausfuhrt. Ein Thread wickelt dabei die Kommunikation mit den

Page 386: [X.systems.press] Cluster Computing ||

12.1 Highly-Parallel LINPACK 383

0

0,5

1

1,5

2

2,5

3

1 2 3 4 5 6

Seed

upS

0

0,2

0,4

0,6

0,8

1

1 2 3 4 5 6

Eff

izie

nzε

Zahl der Prozessoren p

1 × 11 × 21 × 32 × 21 × 52 × 3

Abb. 12.6. Speedup und Effizienz bei konstanter Gleichungssystemgroße (N = 10000) alsFunktion der verwendeten Prozessoren.

anderen MPI-Prozessen ab, die anderen fuhren Funktionen einer auf der Basis vonThreads parallelisierten BLAS-Bibliothek aus. Auch auf diese Weise lassen sich alleCPUs des SMP-Knotens nutzen. Falls Sie den Benchmark in der zweiten Variantedurchfuhren wollen, mussen Sie den HPL-Benchmark nur gegen eine parallelisierteBLAS-Bibliothek linken. Zum Beispiel lasst sich ATLAS mit Threads-Unterstutzungkompilieren, siehe Abschnitt 11.1.2.

Fuhrt man den HPL-Benchmark in der ersten Variante durch, so ist die Kommu-nikation nicht mehr fur alle Paare von MPI-Prozessen gleich schnell. Wahrend dieKommunikation von MPI-Prozessen innerhalb eines Knotens recht schnell ist, lau-fen die Nachrichten zwischen MPI-Prozessen auf verschiedenen Knoten uber dasvergleichsweise langsame Netzwerk. Da nicht jeder MPI-Prozess mit jedem anderenProzess gleich haufig Daten austauscht, hat die Weise, wie die Prozesse auf demProzessgitter angeordnet werden, durchaus einen Einfluss auf die gemessene Fließ-kommaleistung.

Abbildung 12.7 zeigt vier mogliche Aufteilungen von zwolf MPI-Prozessen aufsechs SMP-Knoten mit je zwei CPUs bei der Verwendung eines 3×4-Prozessgitters.In Abb. 12.8 ist die Fließkommaleistung fur diese Aufteilungen zu sehen. Bei derzeilenweisen Aufteilung der CPUs auf das Prozessgitter wie in Abb. 12.7 b wird diegroßte Fließkommaleistung erreicht. Diese Beobachtung gilt nicht nur fur ein 3×4-Prozessgitter sondern auch fur großere Prozessgitter.

Page 387: [X.systems.press] Cluster Computing ||

384 12 Benchmarks

a)

� � � � �� � � � �� � � � �� � � � �� � � � �

� � � � �� � � � �� � � � �� � � � �� � � � �

� � � �� � � �� � � �� � � �� � � �� � � �� � � �� � � �

� � � �� � � �� � � �� � � �� � � �� � � �� � � �� � � �

� � � �� � � �� � � �� � � �� � � �� � � �� � � �� � � �

� � � �� � � �� � � �� � � �� � � �� � � �� � � �� � � �

� � � � �� � � � �� � � � �� � � � �� � � � �

� � � �� � � �� � � �� � � �� � � �

� � � �� � � �� � � �� � � �

� � � �� � � �� � � �� � � �

� � � � � � �� � � � � � �� � � � � � �� � � � � � �

� � � � �� � � � �� � � � �� � � � �� � � � �� � � � �� � � � �

� � � � �� � � � �� � � � �� � � � �� � � � �� � � � �� � � � � � � � � �� � � � �� � � � �� � � � �� � � � �� � � � �� � � � �

� � � �� � � �� � � �� � � �� � � �� � � �� � � �

� � � �� � � �� � � �� � � �

� � � �� � � �� � � �� � � �

� � � �� � � �� � � �� � � �

� � � �� � � �� � � �� � � �

� � � � � � � �� � � � � � � �� � � � � � � �� � � � � � � �

� � � � � � � �� � � � � � � �� � � � � � � �� � � � � � � �

P6 P7

P8 9P P10 P11

0P P1 P2 P3

P5P4

node2 node3 node4

node5 node6 node1 node2

node1

node3 node4 node5 node6 b)

� � � � �� � � � �� � � � �� � � � �� � � � �

� � � �� � � �� � � �� � � �� � � �

� � � �� � � �� � � �� � � �

� � � �� � � �� � � �� � � �

� � � � �� � � � �� � � � �� � � � �

� � � � �� � � � �� � � � �� � � � �

! ! ! ! ! ! !! ! ! ! ! ! !! ! ! ! ! ! !! ! ! ! ! ! !

" " " "" " " "" " " "" " " "" " " "

# # # ## # # ## # # ## # # ## # # #

$ $ $ $ $ $ $$ $ $ $ $ $ $$ $ $ $ $ $ $$ $ $ $ $ $ $

% % % % % % %% % % % % % %% % % % % % %% % % % % % %

& & & && & & && & & && & & && & & && & & && & & && & & &

' ' ' '' ' ' '' ' ' '' ' ' '' ' ' '' ' ' '' ' ' '' ' ' '

( ( ( ( (( ( ( ( (( ( ( ( (( ( ( ( (( ( ( ( (( ( ( ( (( ( ( ( (( ( ( ( (

) ) ) ) )) ) ) ) )) ) ) ) )) ) ) ) )) ) ) ) )) ) ) ) )) ) ) ) )) ) ) ) )

* * * * ** * * * ** * * * ** * * * ** * * * ** * * * ** * * * *

+ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + +

, , , ,, , , ,, , , ,, , , ,, , , ,, , , ,, , , ,

- - - -- - - -- - - -- - - -- - - -- - - -- - - -

. . . .. . . .. . . .. . . .

/ / / // / / // / / // / / /

0 0 0 0 00 0 0 0 00 0 0 0 00 0 0 0 0

1 1 1 1 11 1 1 1 11 1 1 1 11 1 1 1 1

P6 P7

P8 9P P10 P11

0P P1 P2 P3

P5P4

node4

node1

node5 node5 node6 node6

node1 node2

node3 node4

node2

node3

c)

2 2 2 2 22 2 2 2 22 2 2 2 22 2 2 2 22 2 2 2 2

3 3 3 3 33 3 3 3 33 3 3 3 33 3 3 3 33 3 3 3 3

4 4 4 4 44 4 4 4 44 4 4 4 44 4 4 4 4

5 5 5 5 55 5 5 5 55 5 5 5 55 5 5 5 5 6 6 6 66 6 6 66 6 6 66 6 6 66 6 6 66 6 6 66 6 6 66 6 6 6

7 7 7 77 7 7 77 7 7 77 7 7 77 7 7 77 7 7 77 7 7 77 7 7 7

8 8 8 88 8 8 88 8 8 88 8 8 88 8 8 88 8 8 88 8 8 8

9 9 9 99 9 9 99 9 9 99 9 9 99 9 9 99 9 9 99 9 9 9 : : : :: : : :: : : :: : : :: : : :: : : :: : : :: : : :

; ; ; ;; ; ; ;; ; ; ;; ; ; ;; ; ; ;; ; ; ;; ; ; ;; ; ; ;

< < < << < < << < < << < < << < < << < < << < < <

= = = == = = == = = == = = == = = == = = == = = => > > > >> > > > >> > > > >> > > > >> > > > >

? ? ? ?? ? ? ?? ? ? ?? ? ? ?? ? ? ?

@ @ @ @ @ @ @ @@ @ @ @ @ @ @ @@ @ @ @ @ @ @ @@ @ @ @ @ @ @ @

A A A A A A A AA A A A A A A AA A A A A A A AA A A A A A A A

B B B B B B BB B B B B B BB B B B B B BB B B B B B B

C C C C C C CC C C C C C CC C C C C C CC C C C C C C

D D D DD D D DD D D DD D D D

E E E EE E E EE E E EE E E E

F F F F FF F F F FF F F F FF F F F F

G G G GG G G GG G G GG G G GH H H H H

H H H H HH H H H HH H H H H

I I I II I I II I I II I I I

P6 P7

P8 9P P10 P11

0P P1 P2 P3

P5P4

node2 node3 node4

node1 node2 node3 node4

node1

node5 node5 node6 node6 d)

J J J J JJ J J J JJ J J J JJ J J J JJ J J J J

K K K KK K K KK K K KK K K KK K K K

L L L L LL L L L LL L L L LL L L L L

M M M M MM M M M MM M M M MM M M M M

N N N N N N NN N N N N N NN N N N N N NN N N N N N N

O O O O O O OO O O O O O OO O O O O O OO O O O O O OP P P P P

P P P P PP P P P PP P P P P

Q Q Q QQ Q Q QQ Q Q QQ Q Q Q R R R RR R R RR R R RR R R RR R R RR R R RR R R RR R R R

S S S SS S S SS S S SS S S SS S S SS S S SS S S SS S S S

T T T T TT T T T TT T T T TT T T T TT T T T TT T T T TT T T T T

U U U UU U U UU U U UU U U UU U U UU U U UU U U U V V V VV V V VV V V VV V V VV V V VV V V VV V V V

W W W WW W W WW W W WW W W WW W W WW W W WW W W W

X X X XX X X XX X X XX X X XX X X XX X X XX X X X

Y Y Y YY Y Y YY Y Y YY Y Y YY Y Y YY Y Y YY Y Y Y

Z Z Z ZZ Z Z ZZ Z Z ZZ Z Z ZZ Z Z Z

[ [ [ [[ [ [ [[ [ [ [[ [ [ [[ [ [ [

\ \ \ \\ \ \ \\ \ \ \\ \ \ \

] ] ] ]] ] ] ]] ] ] ]] ] ] ]^ ^ ^ ^ ^ ^ ^ ^

^ ^ ^ ^ ^ ^ ^ ^^ ^ ^ ^ ^ ^ ^ ^^ ^ ^ ^ ^ ^ ^ ^^ ^ ^ ^ ^ ^ ^ ^

_ _ _ _ _ _ _ __ _ _ _ _ _ _ __ _ _ _ _ _ _ __ _ _ _ _ _ _ __ _ _ _ _ _ _ _

` ` ` ` `` ` ` ` `` ` ` ` `` ` ` ` `

a a a a aa a a a aa a a a aa a a a a

P6 P7

P8 9P P10 P11

0P P2 P3

P5P4

P1

node1

node5 node6

node1

node2

node2

node3

node4

node4

node3

node5

node6

Abb. 12.7. Zwolf MPI-Prozesse P0, . . . ,P11 lassen sich bei der Verwendung von sechs SMP-Knoten mit je zwei CPUs auf verschiedene Weisen in einem 3×4-Gitter anordnen. Die Abbil-dung zeigt vier Varianten.

0

2

4

6

8

10

12

0 5000 10000 15000 20000 25000

Flie

ßkom

mal

eist

ung

in G

flop

s

N

a)b)c)d)

Abb. 12.8. Fließkommaleistungen fur die in Abb. 12.7 gezeigten Prozessaufteilungen bei ver-schiedenen Systemgroßen.

Nach Abb. 12.8 berechnet die Prozessaufteilung in Abb. 12.7 b, bei der Prozesseauf einem gemeinsamen Knoten jeweils zeilenweise nebeneinander angeordnet sind,die LU-Faktorisierung am effizientesten. Der Geschwindigkeitsvorsprung dieser Pro-zessaufteilung lasst sich leicht erklaren, wenn man bedenkt, dass nach jeder panelfactorization Daten entlang der Zeilen des Prozessgitters verschickt werden mussen.Da der Datenaustausch innerhalb eines Knotens deutlich schneller ist als zwischen

Page 388: [X.systems.press] Cluster Computing ||

12.2 Intel MPI Benchmarks 385

Knoten, minimiert die Anordnung der Prozesse in Abb. 12.7 b die Zeit, bis zu der ei-ne Nachricht alle Prozesse in einer Nachrichtenkette (siehe auch Abb. 12.3) erreichthat.

Im Gegensatz zur Prozessaufteilung b sind in der Aufteilung d die Prozesse auf ei-nem gemeinsamen Knoten jeweils spaltenweise untereinander angeordnet, wodurchder Nachrichtenaustausch entlang der Spalten des Prozessgitters optimiert wird. Dawahrend der panel factorization die Kommunikation gerade entlang dieser Spaltenerfolgt, wirkt sich auch die Aufteilung d positiv auf die Performance aus. Allerdingsist diese Aufteilung nicht ganz so gut wie Aufteilung b. In Aufteilung c sind Pro-zesse auf einem gemeinsamen Knoten zum Teil in Zeilen und zum Teil in Spaltenbenachbart. Die Performance dieser Aufteilung liegt entsprechend zwischen der vonAufteilung b und d.

Die geringste Fließkommaleistung haben wir bei der Prozessaufteilung a gemes-sen. Da hier gar keine Prozesse auf einem gemeinsamen Knoten auf dem Prozess-gitter benachbart sind, profitiert der HPL-Benchmark auch nicht von der schnellenKommunikation innerhalb eines SMP-Knotens. Fazit: Fur einen Cluster aus SMP-Knoten ergibt eine Prozessaufteilung, bei der Prozesse auf einem gemeinsamen Kno-ten jeweils zeilenweise nebeneinander angeordnet sind, die hochste Performance.

12.2 Intel MPI Benchmarks

Fast alle parallelen Programme, die heute auf einem Cluster-Computer laufen, benut-zen zur Kommunikation eine MPI-Bibliothek. Besonders kommunikationsintensiveProgramme verbringen einen wesentlichen Teil ihrer Laufzeit in Funktionen der MPI-Bibliothek. Von einer MPI-Implementation verlangt man darum nicht nur, dass siestandardkonform ist, sondern auch, dass sie effizient ist. Mit den Intel MPI Bench-marks konnen Sie verschiedene Funktionen Ihrer MPI-Implementation untersuchen.Die Intel MPI Benchmarks sind die Nachfolger der Pallas MPI Benchmarks.

12.2.1 Installation

Die Intel MPI Benchmarks sind Teil des Intel Cluster Toolkit [71] konnen aber aucheinzeln von Intels Webseiten heruntergeladen werden. Sie bestehen aus insgesamtdrei Teilen, die jeweils von einem Programm abgedeckt werden.

• Das Programm IMB-MPI1 untersucht Kommunikationsmuster, die allesamt mitFunktionen aus dem MPI-1-Standard implementiert sind.

• Mit IMB-EXT lassen sich Benchmarks bzgl. der einseitigen Kommunikationnach dem MPI-2-Standard durchfuhren.

• Das Programm IMB-IO misst die Performance der parallelen Dateifunktionendes MPI-2-Standards.

Durch die Teilung der Benchmark-Suite in drei Programme, konnen auch Nutzereiner MPI-Implementation, die nur die Version 1.1 des MPI-Standards unterstutzt,

Page 389: [X.systems.press] Cluster Computing ||

386 12 Benchmarks

Listing 12.4. Architekturspezifisches Makefile make lam fur die Intel MPI Benchmarks beider Verwendung von LAM/MPI.

MPI_HOME = /usr/localMPI_INCLUDE = $(MPI_HOME)/includeLIB_PATH =LIBS =

5 CC = ${MPI_HOME}/bin/mpiccOPTFLAGS = -OCLINKER = ${CC}LDFLAGS =CPPFLAGS =

die Intel MPI Benchmarks verwenden. Wir beschranken uns hier weitestgehend aufden MPI-1-Teil.

Alles, was Sie zur Ubersetzung der Intel MPI Benchmarks benotigen, sind eineMPI-Implementation, ein C-Compiler und das Programm make. Nach dem Entpa-cken der Benchmark-Suite liegen im Verzeichnis src deren Quelldateien. Damitdas Programm make die Benchmarks ubersetzen kann, muss es wissen, wo es dieMPI-Implementation findet. Diese und andere Informationen mussen Sie in einerDatei wie der in Listing 12.4 hinterlegen. Wenn Sie LAM/MPI, wie in Abschnitt 6.1beschrieben, installiert haben, konnen Sie die Datei make lam aus Listing 12.4 un-verandert ubernehmen. Die Variablen in Listing 12.4 haben folgende Bedeutung:

MPI HOME. Installationsverzeichnis der MPI-Implementation.MPI INCLUDE. Verzeichnis, in dem die Headerdateien der MPI-Implementation

liegen.LIB PATH. Verzeichnis, in dem die Bibliotheken der MPI-Implementation liegen.LIBS. Bibliotheken der MPI-Implementation.CC. C-Compiler.OPTFLAGS. Compileroptionen fur Optimierung.CLINKER. Linker.LDFLAGS. Linkeroptionen.CPPFLAGS. Optionen fur den C-Praprozessor.

Nachdem Sie ein architekturspezifisches Makefile nach dem Vorbild in Listing 12.4erstellt haben, ist dem eigentlichen Makefile noch die Zeile

include make_lam

hinzuzufugen, bevor das Programm IMB-MPI1 mit

bauke@server:˜/mpi/IMB_2.3/src$ make IMB-MPI1

ubersetzt werden kann. Die beiden anderen Benchmarks IMB-EXT und IMB-IOlassen sich analog mit make IMB-EXT und make IMB-IO ubersetzen.

Page 390: [X.systems.press] Cluster Computing ||

12.2 Intel MPI Benchmarks 387

Tabelle 12.1. Benchmarkmodi des MPI-1-Teils der Intel MPI Benchmarks.

single transfer parallel transfer collective

PingPong Sendrecv BcastPingPing Exchange Allgather

Multi-PingPong AllgathervMulti-PingPing AlltoallMulti-Sendrecv ReduceMulti-Exchang Reduce scatter

AllreduceBarrierMulti-BcastMulti-AllgatherMulti-AllgathervMulti-AlltoallMulti-ReduceMulti-Reduce scatterMulti-AllreduceMulti-Barrier

12.2.2 MPI-1-Benchmarks

Das Programm IMB-MPI1 verwendet fur seine Messungen die klassischen Nach-richtenaustauschfunktionen aus MPI-1. Dabei werden zwischen zwei oder mehr Pro-zessen Nachrichten variabler Lange ausgetauscht, die dafur benotigte Zeit gemessenund uber mehrere Pakete gemittelt. Die Benchmarks geben diese mittere Zeit undzum Teil die sich daraus ergebende Bandbreite in 220 Byte/s aus. Die MPI-1-Bench-marks lassen sich in die Kategorien single transfer, parallel transfer und collectiveeinordnen, siehe Tabelle 12.1.

Alle Benchmarks kommen in einer Standard- und einer Multi-Variante daher. DieMultivarianten unterscheiden sich von den Standard-Variante dadurch, dass die Pro-zesse des Kommunikators MPI COMM WORLD in mehrere Prozessgruppen aufgeteiltwerden, die jeweils gleichzeitig den entsprechenden Benchmark durchfuhren. DasProgramm IMB-MPI1 besitzt eine Option -multi, mit der zwischen der Standard-Variante (-multi 0) und der Multi-Variante (-multi 1) gewahlt werden kann.Wird die Option -multi nicht benutzt, fuhrt das Programm den Benchmark in sei-ner Standard-Variante durch.

Der Nutzer bestimmt beim Starten der Intel MPI Benchmarks, mit wievielenProzessen sie laufen. Jedoch werden nicht immer alle Prozesse fur die Benchmarksverwendet, so findet der Datenaustausch beim PingPong-Test (siehe unten) nur zwi-schen zwei Prozessen statt. Die Prozesse, die tatsachlich Daten austauschen und zumErgebnis des Benchmarks beitragen, heißen aktive Prozesse.

Page 391: [X.systems.press] Cluster Computing ||

388 12 Benchmarks

MPI_Send

Prozess 1 Prozess 2

MPI_Recv

MPI_Recv

MPI_SendT∆

T = ∆T /2

MPI_Isend

Prozess 1 Prozess 2

MPI_Isend

MPI_IsendMPI_Recv MPI_Recv

MPI_Isend

T∆

Abb. 12.9. Kommunikationsmuster beim PingPong- (links) bzw. beim PingPing-Benchmark(rechts).

Single-transfer-Benchmarks

Die single-transfer-Benchmarks zeichnen sich dadurch aus, dass jeweils eine einzigeNachricht zwischen zwei Prozessen ausgetauscht wird. Der PingPong-Benchmarkfolgt dem typischen Muster zur Messung von Latenz und Bandbreite beim Nachrich-tenaustausch zwischen zwei Prozessen, siehe Abb. 12.9. Zunachst sendet ein Pro-zess mit einem blockierenden MPI Send an einen zweiten Prozess eine Nachricht,die dieser mit einem blockierenden MPI Recv empfangt. Anschießend schickt derEmpfanger die Nachricht wieder an die Quelle zuruck. Die Zeit, die der PingPong-Benchmark ermittelt ist die Halfte der Zeit, die vergeht bis die Nachricht wiederbei der Quelle angekommen ist. Im Unterschied zum PingPong-Test verwendet derPingPing-Test die nicht blockierende Sendefunktion MPI Isend (siehe Abb. 12.9)und die beiden Nachrichten vom ersten zum zweiten Prozess bzw. vom zweiten zumersten Prozess sind quasi gleichzeitig unterwegs. Wahrend der PingPong-Benchmarkalso die monodirektionale Bandbreite misst, misst der PingPing-Benchmark die bidi-rektionale Bandbreite.

Sowohl PingPong- als auch PingPing-Benchmark mussen mit mindestens zweiProzessen gestartet werden.

bauke@server:˜/mpi/IMB_2.3/src$ mpirun -np 2 IMB-MPI1 PingPong

Zusatzliche Prozesse sind inaktiv, sie tauschen keine Nachrichten aus. In Listing 12.5sehen Sie die Ergebnisse eines PingPong-Tests mit 16 Prozessen, die uber ein FastEthernet kommunizieren. Beachten Sie, dass 14 der 16 Prozesse inaktiv sind. Die vierSpalten geben die Nachrichtenlange, die Anzahl der Wiederholungen, die mittlereZeit T sowie die mittlere effektive Bandbreite an. Die Zeit, die zum Ubertragen einesPakets der Lange null benotigt wird, ist die Latenzzeit.

In Abb. 12.10 sehen Sie die Ergebnisse einiger unserer PingPong-Messungen.Hier fallen einige Dinge ins Auge. Fur kleine Pakete ist die Kommunikation rela-tiv ineffizient, da hier die Ubertragungszeit von der Latenz dominiert wird. Erst beigroßeren Paketen kommen Fast Ethernet, Gigabit Ethernet und Myrinet in die Naheihrer theoretischen Bandbreite. Beim PingPong-Test auf einem Dual-Xeon Knotenvia shared memory liegt die maximale Bandbreite nicht bei großen Paketen sondernetwa bei einer Paketlange von ca. 64 KByte. Bei kleinen Paketlangen druckt auch

Page 392: [X.systems.press] Cluster Computing ||

12.2 Intel MPI Benchmarks 389

Listing 12.5. Resultate eines PingPong-Benchmark mit 16 durch Fast Ethernet vernetztenProzessen.

#---------------------------------------------------# Intel (R) MPI Benchmark Suite V2.3, MPI-1 part#---------------------------------------------------# Date : Tue Dec 14 09:58:24 2004

5 # Machine : i686# System : Linux# Release : 2.2.20PIII# Version : #3 SMP Wed Nov 27 12:50:33 CET 2002

#10 # Minimum message length in bytes: 0

# Maximum message length in bytes: 4194304## MPI_Datatype : MPI_BYTE# MPI_Datatype for reductions : MPI_FLOAT

15 # MPI_Op : MPI_SUM##

# List of Benchmarks to run:20

# PingPong

#---------------------------------------------------# Benchmarking PingPong

25 # #processes = 2# ( 14 additional processes waiting in MPI_Barrier)#---------------------------------------------------

#bytes #repetitions t[usec] Mbytes/sec0 1000 87.29 0.00

30 1 1000 86.84 0.012 1000 92.78 0.024 1000 88.73 0.048 1000 90.72 0.0816 1000 91.78 0.17

35 32 1000 100.29 0.3064 1000 105.15 0.58128 1000 113.88 1.07256 1000 146.69 1.66512 1000 192.44 2.54

40 1024 1000 295.96 3.302048 1000 423.65 4.614096 1000 604.94 6.468192 1000 973.02 8.0316384 1000 1692.99 9.23

45 32768 1000 3204.83 9.7565536 640 6309.89 9.91

131072 320 12751.20 9.80262144 160 23897.33 10.46524288 80 46321.37 10.79

50 1048576 40 90854.49 11.012097152 20 180578.65 11.084194304 10 358100.30 11.17

Page 393: [X.systems.press] Cluster Computing ||

390 12 Benchmarks

0

500

1000

1500

2000

2500

3000

3500

4000

4500

5000

20 22 24 26 28 210 212 214 216 218 220 222

Ban

dbre

ite in

MB

it/s

Paketgröße in Byte

Fast EthernetGigabit EthernetMyrinetshared memory Intel Xeon 3,06GHz

Abb. 12.10. Durch PingPong-Test ermittelte Bandbreiten bei Kommunikation uber unter-schiedliche Hardware.

hier die Latenz die effektive Bandbreite, zu lange Nachrichten passen nicht mehr inden Cache und werden durch den langsamen Hauptspeicher gebremst.

Parallel-transfer-Benchmarks

Die Multi-Varianten des PingPong- bzw. des PingPing-Test gehoren zu den parallel-transfer-Benchmarks. In diesen Multi-Varianten werden die p Prozesse des Kommu-nikators MPI COMM WORLD in �p/2� Gruppen mit je zwei Prozessen aufgeteilt, diejeweils gleichzeitig einen PingPong- bzw. PingPing-Test durchfuhren. Mit diesenMulti-Varianten lasst sich die Bisektionsbandbreite eines Switches bestimmen, sieheAbschnitt 2.2.

Der Sendrecv-Benchmark basiert auf der MPI Sendrecv-Funktion. Hierbeisenden P logisch in einer zyklischen Kette angeordneten Prozesse einem ihrer Nach-barn eine Nachricht bzw. empfangen vom anderen Nachbarn eine Nachricht gleicherLange, siehe Abb. 12.11. Dieses Szenario entspricht dem ”Ringtausch“, den wir inKapitel 7.4.3 diskutiert haben.

Auch beim Exchange-Benchmark sind P Prozesse logisch in einer zyklischenKette angeordnet. Jeder Prozess sendet durch die nicht blockierende SendefunktionMPI Isend an beide nachsten Nachbarn eine Nachricht und empfangt auch vonjedem Nachbarn eine Nachricht gleicher Lange, siehe Abb. 12.11. Das Kommuni-kationsmuster des Exchange-Benchmark wird haufig in MPI-Programmen zum Aus-tausch von Gitterranddaten verwendet.

Das Programm IMB-MPI1 fuhrt sowohl Sendrecv- als auch Exchange-Bench-mark mehrfach durch und variiert dabei die Zahl der aktiven Prozesse. Im erstenDurchlauf betragt die Zahl aktiver Prozesse P = Pmin. In den darauf folgenden

Page 394: [X.systems.press] Cluster Computing ||

12.2 Intel MPI Benchmarks 391

T∆

MPI_Sendrecv

MPI_Sendrecv

Prozess

MPI_Sendrecv

MPI_Sendrecv

Prozess + 1

MPI_Sendrecv

MPI_Sendrecv

i iProzess − 1 i

MPI_Isend

MPI_Isend

MPI_Waitall

MPI_Recv

MPI_Recv

MPI_Isend

MPI_Isend

MPI_Waitall

MPI_Recv

MPI_Recv

MPI_Isend

MPI_Isend

MPI_Waitall

MPI_Recv

MPI_RecvT∆

Prozess Prozess + 1i iProzess − 1 i

Abb. 12.11. Kommunikationsmuster beim Sendrecv- (oeben) bzw. beim Exchange-Bench-mark (unten).

Durchlaufen wird die Zahl der aktiven Prozesse solange verdoppelt, solange sie nochkleiner als die Zahl p der Prozesse im Kommunikator MPI COMM WORLD ist. ZumSchluss folgt noch eine Messung mit P = p Prozessen. Die minimale ProzesszahlPmin betragt normalerweise zwei, kann aber durch die Option -npmin frei gewahltwerden. Mit

bauke@server:˜/mpi/IMB_2.3/src$ mpirun -np 27 IMB-MPI1 -npmin 3 Sendrecv

wird der Sendrecv-Benchmark also mit 3, 6, 12, 24 und 27 Prozessen durchgefuhrt.Bei den Multi-Varianten des Sendrecv- und des Exchange-Benchmarks werden

die p Prozesse des Kommunikators MPI COMM WORLD in g Prozessgruppen aufge-teilt. In den verschiedenen Durchlaufen besteht jede Gruppe aus P = 20 ·Pmin,21 ·Pmin, . . . ,2k ·Pmin, p Prozessen, wobei k die großte naturliche Zahl mit 2k ·Pmin < pist. Die Zahl g der Prozessgruppen nimmt naturlich mit der Zahl der Prozesse jeProzessgruppe ab und betragt g = �p/P�. Ein Beispiel:

bauke@server:˜/mpi/IMB_2.3/src$ mpirun -np 27 IMB-MPI1 -multi 1 -npmin 3 \> Sendrecv

Die Zahl der Prozesse im Kommunikator MPI COMM WORLD betragt hier p = 27.

1. Durchgang: g = 9 Gruppen zu je P = 3 Prozessen, keine inaktiven Prozesse2. Durchgang: g = 4 Gruppen zu je P = 6 Prozessen, 3 inaktive Prozesse3. Durchgang: g = 2 Gruppen zu je P = 12 Prozessen, 3 inaktive Prozesse4. Durchgang: g = 1 Gruppe zu P = 24 Prozessen, 3 inaktiven Prozesse5. Durchgang: g = 1 Gruppe zu P = 27 Prozessen, keine inaktiven Prozesse

Page 395: [X.systems.press] Cluster Computing ||

392 12 Benchmarks

Collective-Benchmarks

Die Benchmarks aus dem Bereich collective verwenden die gleichnamigen MPI-Funktionen, so basiert der Reduce-Test auf MPI Reduce, der Bcast-Test auf MPIBcast usw. Auch diese Test werden mit einer variablen Anzahl aktiver Prozessedurchgefuhrt. Das Aufteilungsschema in aktive und passive Prozesse ist dasselbe wiebeim Sendrecv- bzw. beim Exchange-Benchmark. Die Multi-Varianten der Bench-marks aus dem Bereich collective arbeiten analog den Multi-Varianten des Sendrecv-bzw. des Exchange-Benchmark.

12.3 Notizen

12.1 Von Apfeln und Birnen. Der HPL-Benchmark charakterisiert einen Parallel-Computer einzig durch die Fließkommaleistung, mit der er ein dichtes lineares Glei-chungssystem lost. Wenn ein Computer beim HPL besser als ein anderer abschneidet,heißt dies nur, dass ersterer schneller dichte lineare Gleichungssysteme losen kann,nicht mehr. Bei anderen Anwendungen mag der zweite die Nase vorn haben. DerVergleich zweier Parallel-Computer einzig aufgrund des HPL ist wegen seiner ein-geschrankten Aussagekraft kaum moglich. Um dieses Manko zu uberwinden, wurdeder HPC Challenge Benchmark [67] geschaffen. Diese Benchmark-Suite enthalt eineganze Palette von Tests, zu denen neben dem HPL noch sechs andere gehoren.

12.2 Weitere Benchmarks. Es gibt noch eine Reihe weiterer nutzlicher Benchmarks.Dazu zahlen u. a.:

SKaMPI. Der Special Karlsruher MPI-Benchmark [152] genannte Benchmark istmit den MPI-1-Tests der Intel MPI Benchmarks vergleichbar, bietet jedochweit großere Konfigurationsmoglichkeiten. Als Besonderheit enthalt er ein Perl-Skript, das aus Rohdaten des Benchmarks einen komplexen Report in Form einerPostScript-Datei erstellt.

NetPIPE. NetPIPE [113] ist ein protokollunabhangiger Benchmark, der mit Hil-fe eines einfachen Ping-Pong-Tests die Netzwerkperformance verschiedensterNetzwerkarchitekturen und -protokolle misst. NetPIPE verschickt Nachrichtenverschiedener Große. Die Große wird dabei in leicht irregularer Weise variiert,wodurch u. a. vermieden wird, dass nur Pakete, deren Lange eine Potenz vonzwei ist, ausgetauscht werden.

NAS Parallel Benchmarks. Die NAS Parallel Benchmarks [111] bestehen aus ei-ner Programmsammlung zur Evaluierung von Parallelrechnern, die ihren Ur-sprung in der Fluiddynamik haben.

Effective I/O Bandwidth Benchmark. Dieser Benchmark [33] charakterisiert dieEin- und Ausgabeleistung von MPI-Programmen mit parallelem Dateizugriff.Dabei werden verschiedenste Zugriffsmuster berucksichtigt.

SPEC. Anfang 2005 hat die Standard Performance Evaluation Corporation, kurzSPEC, begonnen einen eigenen MPI-Benchmark zu entwickeln und die Cluster-Computing-Gemeinde aufgefordert hier mitzuwirken. Uber den aktuellen Standdieser Entwicklung konnen Sie sich unter [155] informieren.

Page 396: [X.systems.press] Cluster Computing ||

13

Checkpoint-Restart

So etwas passiert hier immer mal wieder [. . . ]alles ganz normal.

erste Reaktion des SPIEGEL-Korrespondenten JanFleischhauer beim Stromausfall, der 2003 50 MillionenMenschen Nordamerikas vom Strom abschnitt

Technisch-wissenschaftliche Berechnungen dauern selbst mit Cluster-Computern oftTage, Wochen oder gar Monate. Wahrend dieser Zeit kann es immer wieder zuUnterbrechungen durch Stromausfalle, technische Probleme (z. B. defekte Lufter)oder Wartungsarbeiten kommen. Ohne spezielle Vorkehrungen bedeutet die Unter-brechung eines Programms, dass seine bisherigen Berechnungen verloren sind unddas Programm noch einmal vollkommen neu gestartet werden muss.

Mit einem Checkpoint-Restart-System lasst sich von einem laufenden Programmvor einer geplanten Unterbrechung oder in periodischen Abstanden eine Momentauf-nahme (checkpoint) machen. Mit den Informationen einer solchen Momentaufnahmekann das Programm spater wieder rekonstruiert und fortgesetzt werden (restart). Soverlieren unvorhergesehene Unterbrechungen ihren Schrecken.

13.1 Uberblick

13.1.1 Anforderungen an Checkpoint-Restart-Systeme

Checkpoint-Restart-Systeme konnen auf Kernel-, User- oder Application-Level ar-beiten, siehe Abschnitt 6.2.3. Beim Application-Level-Checkpointing sorgt der An-wendungsprogrammierer selbst dafur, dass alle zum Fortfuhren eines Programmsnotwendigen Daten gesichert werden. Fur einen Restart des Programms unwichtigeDaten konnen dabei auch unberucksichtigt bleiben.

Erfolgt das Checkpointing auf Kernel- oder User-Level, so sind Checkpoint undRestart vollkommen transparent. Ein Programm ”weiß“ nichts davon, dass von ihmeine Momentaufnahme gemacht bzw. es spater wieder fortgefuhrt wird. Anderer-seits ist dem Checkpoint-Restart-System nicht bekannt, welche Daten eines Pro-gramms unbedingt zu seiner Weiterfuhrung gesichert werden mussen. Darum sichernCheckpointing-Systeme auf Kernel- oder User-Level im Idealfall alle potentiell not-wendigen Prozessdaten. Dazu gehoren:

Page 397: [X.systems.press] Cluster Computing ||

394 13 Checkpoint-Restart

• alle Register,• der komplette Adressraum samt Code, Daten, Stack und Bibliotheken,• Informationen uber offene Dateien, deren Zugriffsrechte und Dateipositionen,• die Umgebungsliste, die die Umgebungsvariablen eines Prozesses enthalt,• vom Prozess abhangige Prozesse, falls es sich um eine Prozessgruppe handelt

(Eine Prozessgruppe besteht aus einem Prozess und seinen Nachkommen.),• Informationen bzgl. der Interprozesskommunikation uber Pipes, Sockets, Signale

oder gemeinsam genutzten Speicher und• verschiedene weitere Informationen, wie z. B. die Prozessnummer (PID), effekti-

ve User-ID oder Ressourcenlimits.

Leider ist es eine technisch recht anspruchsvolle Aufgabe, alle oben genannten Pro-zesseigenschaften wahrend eines Checkpoints zu sichern und spater bei einem Rest-art wieder zu rekonstruieren. Ein Checkpoint-Restart-System hat zum einen zahl-reiche softwaretechnische Herausforderungen zu meistern. Zum anderen konnenmanchmal bestimmte Prozesseigenschaften nicht rekonstruiert werden, weil zum Re-startzeitpunkt benotigte Ressourcen mittlerweile von anderen Prozessen belegt wer-den. So rekonstruiert BLCR (siehe unten) normalerweise die PID eines Prozesses. Daunter Linux die Menge der Prozessnummern begrenzt ist, werden PIDs bei Bedarf

”recycelt“. So kann es passieren, dass ein Prozess nicht wieder aufgesetzt werdenkann, weil seine PID inzwischen von einem anderen Prozess belegt wird. Die Band-breite der Merkmale, die ein Checkpoint-Restart-System tatsachlich rekonstruierenkann, bestimmt welche Art von Programmen sich tatsachlich transparent restartenlasst.

Weil in der Praxis nicht alle Prozesseigenschaften wiederhergetstellt werdenkonnen, ist es wunschenswert, wenn ein Checkpoint-Restart-System einem Program-men es gestattet, den Zeitpunkt, an dem ein Checkpoint durchgefuhrt wird, frei zubestimmen (synchrones Checkpointing) oder bei Bedarf ein Checkpoint wenigstenszu unterbinden. Falls ein Checkpoint-Restart-System z. B. Informationen uber offe-ne Dateien nicht wiederherstellen kann, so lasst sich so sicherstellen, dass ein Check-point nie ausgefuhrt wird, wahrend noch Dateien geoffnet sind. In der Regel wirdein Checkpoint aber von außen, also nicht durch das Programm selbst, initiiert. Hierspricht man von asynchronem Checkpointing. Das kann z. B. durch Signale gesche-hen, die an das betroffene Programm gesandt werden.

Allerdings lassen sich durch synchrones Checkpointing langst nicht alle potentiel-len Probleme losen, die im Zusammenhang mit Dateien und Checkpointing auftreten.Wie soll ein Checkpoint-Restart-System reagieren, wenn ein Programm ein Check-point durchfuhrt, eine Datei offnet, Daten an die Datei anhangt, die Datei auch nochordnungsgemaß schließt aber absturzt, noch bevor der nachste Checkpoint geschrie-ben wird? Startet man das Programm erneut von seinem letzten Checkpoint aus, sowerden die Daten zweimal in die Datei geschrieben. Zwar gibt es Ansatze, die z. B.auf Schattenkopien beruhen und einige der im Zusammenhang mit Dateien auftreten-den Probleme losen. Jedoch existiert kein einziges Checkpoint-Restart-System, dassalle diese Probleme unter allen Umstanden losen kann.

Page 398: [X.systems.press] Cluster Computing ||

13.1 Uberblick 395

Ein ahnlich schwieriges Thema sind alle Formen der Interprozesskommunikati-on, wie Netzwerkverbindungen und Sockets. Auch diese konnen in der Praxis nichtimmer wiederhergestellt werden und es konnen Daten verloren gehen. Dies hat u. a.zur Folge, dass sich MPI-Programme, die meist uber TCP/IP-Sockets kommunizie-ren, nicht ohne Weiteres durch ein Checkpoint-Restart-System wieder aufsetzen las-sen. Gleiches gilt auch fur andere Formen der Interprozesskommunikation und Mul-tithread-Programme.

13.1.2 Implementationen von Checkpoint-Restart-Systeme

Unter Linux gibt es eine ganze Reihe verschiedener auf Kernel- oder User-Levelarbeitende Checkpoint-Restart-Systeme, die zum Teil mit ganz verschiedenen Ziel-setzungen entwickelt wurden. So steht bei einigen Systemen Aufallsicherheit, beianderen Prozessunterbrechung (preemption) oder Prozessmigration im Vordergrund.Keines dieser Systeme kann den Zustand eines Prozesses vollstandig abspeichernund wieder restaurieren. Je nach verwendetem System mussen die Nutzer mit ver-schiedenen Einschrankungen leben. Im Folgenden stellen wir einige dieser Systemekurz vor und beschreiben in den darauf folgenden Abschnitten zwei Systeme im De-tail.

Libckpt

Die Bibliothek Libckpt [94] ist eine der altesten Checkpoint-Restart-Systemen furunixartige Betriebssysteme, kann aber nur eine recht kleine Zahl von Prozessparame-tern restaurieren. Allerdings implementiert es einige interessante Methoden, die dieGroße der Checkpointdateien minimieren und unterstutzt synchrones Checkpointing.In der Standardkonfiguration wird alle zehn Minuten ein asynchroner Checkpointdurchgefuhrt.

Libckpt ist nicht 100-prozentig transparent. Der Programmierer muss den Namendes C-Hauptprogramms von main in ckpt target andern und sein Programmstatisch gegen die Libckpt-Bibliothek linken. Dieses System lasst sich also nicht aufProgramme anwenden, deren Quellen man nicht besitzt.

Ckpt

Ckpt [19] ist eine weitere Programm- und Bibliothekssammlung fur das Userlevel-Checkpointing. Der Hauptvorteil dieses Systems gegenuber vielen anderen liegt dar-in, dass Programme nicht neu gelinkt oder gar deren Quelltext modifiziert werdenmussen. Ckpt lasst sich sogar nachtraglich in schon laufende Programme injizieren.Die von Ckpt verwendeten Checkpointmethoden funktionieren nicht, wenn das Pro-gramm statisch gelinkt ist sowie auf Systemen, die den Exec-Shield-Kernel-Patchverwenden. Diese Kernel-Erweiterung wird von einigen Distibutionen eingetzt, umdas Ausnutzen von Sicherheitslucken in Programmn zu erschweren. Dazu gehorenz. B. Fedora und Red Hat Enterprise Linux. Die Verwendung von Ckpt beschreibenwir in Abschnitt 13.2 genauer.

Page 399: [X.systems.press] Cluster Computing ||

396 13 Checkpoint-Restart

Condor

Zum Batch-System Condor [21] gehort eine User-Level-Checkpointing-Bibliothek,die von diesem Batch-System normalerweise dazu genutzt wird, Jobs innerhalb einesNOW von einem Knoten zu einem anderen zu migrieren. Die Condor-Checkpointing-Bibliothek kann aber auch ohne das Batch-System verwendet werden.

Um das Checkpointing mit Condor zu ermoglichen, muss die Anwendung ge-gen Condors Checkpointing-Bibliothek gelinkt werden. Dazu muß der Quell- oderwenigstens der Objektcode der Anwendung vorliegen. Die ausfuhrbare Datei alleinreicht nicht aus. Eine Modifikation des Quelltextes ist jedoch nicht notwendig. DasSchreiben einer Checkpointdatei wird veranlasst, in dem der Nutzer an das Pro-gramm ein bestimmtes Signal sendet.

Bei der Verwendung der Condor Checkpointing-Bibliothek muß der Quelltextnicht geandert werden. Allerdings bietet Condor einige Funktionen, die man in denQuelltext einbauen kann um eine großere Kontrolle uber das Checkpointing zu er-halten. Damit kann ein Programm z. B. selbst das Schreiben einer Checkpointdateiauslosen oder in bestimmten Programmabschnitten verbieten.

SCore

Das Checkpointing-System der parallelen Programmierumgebung SCore [148] hebtsich dadurch von den meisten anderen Checkpointing-Systemen ab, dass es von An-fang an fur parallele Programme entwickelt wurde. Auch hier handelt es sich um eineUser-Level-Implementation in Form einer Bibliothek. SCore realisiert das Check-pointing in seinen grundlegenden Kommunikations- und Laufzeitbibliotheken. Da-durch arbeiten SCores Checkpoint/Restart-Funktionen mit den meisten parallelenProgrammen zusammen, ohne dass Anderungen am Quellcode notwendig waren.Mit der SCore eigenen MPI-Implementation funktioniert auch das Checkpointingvon MPI-Programmen.

Checkpoints werden periodisch in frei wahlbaren Abstanden ausgefuhrt. Dabeischreibt jeder der parallelen Prozesse einen Teil der Checkpointdaten auf seine lokaleFestplatte. Neben den eigentlichen Checkpointdaten werden zusatzlich noch Paritats-daten gespeichert. Dadurch konnen mit SCore parallele Programme auch dann wie-der aufgesetzt werden, wenn ein Schaden an einer Festplatte aufgetreten ist. Mit denzusatzlichen Paritatsdaten lasst sich ein paralleles Programm mit p Prozessen nacheiner Unterbrechung auch dann noch fortfuhren, wenn die Checkpointdaten von nurp−1 Prozessen vorliegen.

CHPOX

CHPOX (CHeckPOinting for linuX) [18] ist eine aus einem Kernelmodul bestehen-de Kernel-Level-Checkpointing-Implementation fur Linux 2.4.x auf verschiedenenHardwarearchitekturen (Intel i386, Power-PC und IBM s390). Eine Unterstutzungfur Kernel der Serie 2.6.x ist geplant. CHPOX arbeitet auch mit MOSIX und open-Mosix [153] zusammen. Mit diesen beiden Erweiterungen des Linux-Kernels verhalt

Page 400: [X.systems.press] Cluster Computing ||

13.2 Ckpt 397

Tabelle 13.1. Checkpoint-Restart-Systeme fur Linux im Uberblick.

Lib

ckpt

Ckp

t

Con

dor

SCor

eC

HPO

XB

LC

R

Register � � � � � �

Adressraum � � � � � �

Datei Deskriptoren � � � � �

Signale � � � � �

Unix-Domain-Sockets �

Internet-SocketsUmgebung � �

Multithreadprogramme �

MPI-Programme � �

sich ein Cluster-Computer wie ein großes SMP-System. CHPOX baut auf den alterenCheckpoint-Systemen VMADUMP, EPCKPT und CRAK auf, wird aber im Gegen-satz zu diesen noch aktive gepflegt. Da CHPOX auf Kernel-Level arbeitet, mussenProgramme weder gegen eine spezielle Bibliothek gelinkt noch deren Quellcodeverandert werden. Das CHPOX-Kernel-Modul lauft auch auf SMP-Systemen kor-rekt, unterstutzt aber keine Programme mit mehreren Threads.

Berkeley Lab Checkpoint/Restart

Berkeley Lab Checkpoint/Restart (BLCR) [11] ist eine weitere Kernel-Level-Check-pointing-Implementation fur Linux 2.4.x auf Intels i386-Architektur. Die Unterstutz-ung fur Kernel der Serie 2.6.x gilt noch als experimentell. Sie besteht aus einigen Ker-nelmodulen, Hilfsprogrammen und Bibliotheken. Auf der Grundlage dieser Biblio-theken lasst sich das Checkpointing steuern und erweitern. Mit ihr konnen Anwen-dungen das Checkpointing temporar verhindern und in den Checkpoint- bzw. Rest-artprozess eingreifen. Diese Erweiterungsmoglichkeiten werden z. B. von LAM/MPIgenutzt, um das Checkpointing von MPI-Programmen zu ermoglichen. Im Ab-schnitt 13.3 werden wir dies naher besprechen.

13.2 Ckpt

In diesem Abschnitt beschreiben wir Ckpt als Beispiel fur eine User-Level-Imple-mentation eines Checkpoint-Restart-Systems. Die Quellen dieser Bibliothek erhal-ten Sie unter [19]. Nach dem Entpacken des Quellpaketes, sollten Sie zunachstdas Makefile Ihren lokalen Bedurfnissen anpassen. Dies betrifft vorallem den ver-wendeten Compiler und die Verzeichnisse, in die spater die Bibliotheken und Pro-gramme kopiert werden. Ubersetzung und Installation erfolgen durch make bzw.make install.

Die Checkpointing-Bibliothek Ckpt lasst sich durch verschiedene Umgebungsva-riablen steuern.

Page 401: [X.systems.press] Cluster Computing ||

398 13 Checkpoint-Restart

CKPT NAME. Die Zeichenkette in dieser Variablen bestimmt, wo die Checkpointda-ten gespeichert werden. Ist sie leer, so werden die Checkpointdaten eines Pro-gramms foo in der Datei foo.ckpt gespeichert. Mit dem Wert in CKPTNAME lasst sich dieser Standardname uberschreiben, z. B. mit 2ter versuchoder file://2ter versuch. Beide Formen sind gleichwertig.Alternativ lasst sich eine Checkpointdatei auch auf einem entfernten Rechnerspeichern. Dazu muss mit

bauke@server:˜ $ ckptsrv

bzw.

bauke@server:˜ $ ckptsrv -p PORT

zunachst auf dem entfernten Rechner ein Checkpointserver gestartet werden.Dieser lauscht am Port 10301 (bzw. den durch PORT spezifizierten Port), nimmtvon dort Checkpointdateien entgegen und speichert sie unter /tmp. In die-sem Fall enthalt die Variable CKPT NAME einen Namen der Form cssrv://HOSTNAME[:PORT]/NAME.

CKPT CONTINUE. Nach dem Schreiben einer Checkpointdatei wird das Programmnormalerweise beendet. Hat die Variable CKPT CONTINUE den Wert 1, so lauftdas Programm stattdessen weiter.

CKPT ASYNCSIG. Diese Variable legt fest, welches Signal das asynchrone Schrei-ben einer Checkpointdatei auslost. Standardmaßig ist dies 20 (SIGTSTP), sieheauch Manpage signal(7). Hat die Variable den Wert 0, so wird das asynchroneCheckpointing verhindert.

CKPT MSPERIOD. Die in dieser Variablen gespeicherte Ganzzahl bestimmt, in wel-chen Abstanden periodisch ein Checkpointing erfolgt. Sie enthalt die Zeit zwi-schen zwei Checkpoints in Millisekunden. Ist ihr Wert 0, so wird das periodischeCheckpointing deaktiviert, was die Standardeinstellung ist.Diese Funktion ist in Ckpt durch die Nutzung von Signalen und einem Timerrealisiert. Darum ist beim Einsatz periodischen Checkpointings mit Problemenbei Programmen zu rechnen, die die Funktionen signal, alarm oder sleepverwenden.

Die Benutzung von Ckpt lasst sich am besten an Hand eines Beispielprogramms, wiedem in Listing 13.1 zeigen. Startet man ein Programm durch ckpt, so lasst sich zueinem beliebigen Zeitpunkt ein Checkpointing auslosen.

bauke@node1:˜/src $ ckpt ./checkpoint1 10i = 0 sum = 636766.737980i = 1 sum = 637174.249178i = 2 sum = 636416.164831i = 3 sum = 636438.344471i = 4 sum = 636598.508627

Mit der Tastenkombination Steuerung-Z, wird an das Programm checkpoint1 dasSignal SIGTSTP gesendet, eine Checkpointdatei checkpoint1.ckpt angelegt

Page 402: [X.systems.press] Cluster Computing ||

13.2 Ckpt 399

und das Programm beendet. Die von der Ckpt-Bibliothek erzeugten Checkpointda-teien sind selbst ausfuhrbare Dateien. Starten wir checkpoint1.ckpt, so wirddas gerade unterbrochene Programm fortgefuhrt, als hatte es die Unterbrechung niegegeben.

bauke@node1:˜/src $ ./checkpoint1.ckpti = 5 sum = 636975.666839i = 6 sum = 636590.875571i = 7 sum = 636000.633279i = 8 sum = 637021.900651i = 9 sum = 636810.521302ckpt!

Naturlich konnen Sie das Signal SIGTSTP auch von einem anderen Terminal ausdurch das Programms kill senden. Mit der Nachricht ckpt! meldet Ckpt uns,dass ein Checkpointing durchgefuhrt wurde.

Das Programm ckpt akzeptiert neben dem Namen des abzusichernden Program-mes und dessen Kommandozeilenparametern noch weitere, eigene Parameter.

-n NAME. Setzt die Umgebungsvariable CKPT NAME auf NAME.-c. Setzt die Umgebungsvariable CKPT CONTINUE auf 1.-a SIGNAL. Setzt die Umgebungsvariable CKPT ASYNCSIG auf SIGNAL.-z PERIODE. Setzt die Umgebungsvariable CKPT MSPERIOD auf PERIODE.-p PID. Hier mit wird der Code der Checkpointing-Bibliothek in das bereits lau-

fende Programm mit der Prozessnummer PID injiziert.

Dass Programme fur die Verwendung von Ckpt nicht verandert werden mussen,ist sicher einer der großten Vorzuge dieses Checkpointing-Systems. Wenn Sie al-le Moglichkeiten der Ckpt-Bibliothek ausnutzen wollen, sollten Sie das Ckpt-APIverwenden. Die Bibliothek stellt einige Funktionen zur Verfugung, mit denen dasCheckpointing aus einem Programm selbst gesteuert werden kann. Die vier wichtigs-ten sind:

Listing 13.1. Checkpointing-Demonstrationsprogramm checkpoint1.c.

#include <stdlib.h>#include <stdio.h>#include <math.h>

5 int main(int argc, char *argv[]) {int i, j, i_max=1;double sum, x;if (argc>1)

i_max=atoi(argv[1]);10 for (i=0; i<i_max; ++i) {

sum=0.0;for (j=0; j<1000000; ++j)

sum+=sin((double)rand()/(double)RAND_MAX*3.141592654);printf(” i = %i \ tsum = %f\n ”, i, sum);

15 }return EXIT_SUCCESS;

}

Page 403: [X.systems.press] Cluster Computing ||

400 13 Checkpoint-Restart

int ckpt_ckpt(char *name)void ckpt_on_preckpt(void (*f)(void *), void *arg)void ckpt_on_postckpt(void (*f)(void *), void *arg)void ckpt_on_restart(void (*f)(void *), void *arg)void ckpt_config(struct ckptconfig *cfg, struct ckptconfig *old)

Die Funktion ckpt ckpt lost ein Checkpointing aus und sicher den Zustand desProgramms in einer Checkpointdatei. Ist das Argument name kein Nullzeiger, sowird damit der Name fur die Checkpointdatei festgelegt, sonst gilt der Wert in denUmgebungsvariablen CKPT NAME. Die restlichen drei Funktionen dienen zur Regis-trierung von Funktionen, die vor bzw. nach einem Checkpointing oder vor einem Re-start ausgefuhrt werden, so genannte Call-Back-Funktionen. Jede dieser Call-Back-Funktionen hat den Ruckgabewert void und verlangt als Argument einen Zeiger aufvoid. Call-Back-Funktionen werden spater mit dem Argument aufgerufen, das beider Registrierung als zweites Argument angegeben wurde. Werden fur jeweils einender drei Einsprungpunkte mehrere Call-Back-Funktionen registriert, so werden die-se nacheinander in der Reihenfolge ausgefuhrt, in der sie registriert wurden. Uberdie Funktion ckpt config lassen sich die Parameter, die das Verhalten von Ckptsteuern, setzten oder abfragen. Diese Parameter werden dazu in einer Struktur derForm

struct ckptconfig {char name[CKPT_MAXNAME]; / * CKPT NAME * /unsigned int asyncsig; / * CKPT ASYNCSIG * /unsigned int continues; / * CKPT CONTINUE * /unsigned int msperiod; / * CKPT MSPERIOD * /int flags;

};

hinterlegt. Falls old kein Nullzeiger ist, werden durch ckpt config die aktuellenParameter in der Struktur, auf die old zeigt, kopiert. Ist new kein Nullzeiger, so wer-den die Ckpt-Parameter neu gesetzt. Die Variable flags enthalt eine Bitmaske. Siecodiert, welche der vier Parmeter durch ckpt config tatsachlich geandert werdensollen.

In Listing 13.2 sehen Sie, wie man diese Funktionen verwenden kann, um einProgramm, das Dateizugriffe ausfuhrt, halbwegs gut abzusichern. Es wird mit

bauke@server:˜ $ gcc -o checkpoint2 checkpoint2.c -lckpt -lm

ubersetzt. Zur Erinnerung: Ckpt rettet keine Informationen uber offene Dateien. Dahier aber die Checkpoints synchron aus dem Programm selbst heraus ausgefuhrtwerden, besteht hierin aber kein Informationsverlust. Wenn in Zeile 37 die Check-pointdatei geschrieben wird, sind ja gar keine offenen Dateien mehr vorhanden. DieCall-Back-Funktion logging gibt vor und nach jedem Checkpointing eine kurzeStatusmeldung aus.

Das Schreiben einer Checkpointdatei ist eine relativ kostspielige Aktion. Immer-hin muss der gesamte Adressraum eines Programms auf Festplatte gesichert werden.Dieser kann bei technisch-wissenschaftlichen Anwendungen leicht mehrere hundertMegabyte betragen. Darum sollte ein Checkpointing nicht allzu oft geschehen. Ein

Page 404: [X.systems.press] Cluster Computing ||

13.3 Berkeley Lab Checkpoint/Restart 401

Listing 13.2. Das Checkpointing-Demonstrationsprogramm checkpoint2.c fuhrt Check-points synchron aus.

#include <stdlib.h>#include <stdio.h>#include <signal.h>#include <math.h>

5 #include <ckpt.h>

void logging(void *str) {fprintf(stderr, ”%s ”, str);

}10

int main(int argc, char *argv[]) {int i, j, i_max=1;double sum, x;FILE *out;

15 const char *file_name=” c h e c k p o i n t 2 . l o g ”;struct ckptconfig conf;/ * Ca l l−Back−F u n k t i o n e n r e g i s t r i e r e n * /ckpt_on_preckpt(logging, ” s i c h e r n . . . \ t ”);ckpt_on_postckpt(logging, ” und nun w e i t e r . . . \ n ”);

20 / * Ckpt−P a r a m e t e r s e t z e n * /conf.asyncsig=SIGTERM; / * a n s y n c h r o n e s C h e c k p o i n t i n g durch SIGTERM * /conf.continues=1; / * nach Checkpo in t we i t e rmachen * /conf.msperiod=0; / * k e i n p e r i o d i s c h e s C h e c k p o i n t i n g * /conf.flags=CKPT_ASYNCSIG | CKPT_CONTINUE | CKPT_MSPERIOD;

25 ckpt_config(&conf, NULL);

if (argc>1)i_max=atoi(argv[1]);

remove(file_name);30 for (i=0; i<i_max; ++i) {

sum=0.0;for (j=0; j<10000000; ++j)

sum+=sin((double)rand()/(double)RAND_MAX*3.141592654);out=fopen(file_name, ”w+”); / * D a t e i o f f n e n und . . . * /

35 fprintf(out, ” i = %i \ tsum = %f\n ”, i, sum);fclose(out); / * . . g l e i c h wiede r s c h l i e ß e n * /ckpt_ckpt(NULL); / * C h e c k p o i n t * /

}return EXIT_SUCCESS;

40 }

Checkpointing nach jeweils ca. funf bis zehn Minuten ist in den meisten Fallen voll-kommen ausreichend.

13.3 Berkeley Lab Checkpoint/Restart

Mit Berkeley Lab Checkpoint/Restart (BLCR) [11] steht unter Linux ein Checkpoin-ting-System auf Kernel-Level zur Verfugung, das selbst Multithread-Anwendungenund MPI-Programme unterstutzt. Allerdings arbeitet BLCR nicht mit allen MPI-Im-plementationen zusammen. Genaugenommen kummert sich BLCR nicht selbst um

Page 405: [X.systems.press] Cluster Computing ||

402 13 Checkpoint-Restart

das Checkpointing von MPI-Programmen. Stattdessen stellt es einige Bibliotheks-funktionen bereit, auf Grundlage derer eine MPI-Bibliothek Checkpointing parallelerProgramme implementieren kann. LAM/MPI ist bisher die einzige Message-Passing-Bibliothek, die BLCR nutzt.

13.3.1 Installation

Da BLCR zum Teil aus Kernel-Modulen besteht, benotigen Sie zur Installationneben den ublichen Entwicklungswerkzeugen noch die konfigurierten Headerda-teien des von Ihnen eingesetzten Kernels. Konfiguriert bedeutet hier insbesondere,dass die Headerdateien include/linux/version.h und die unter include/linux/modules/ zu dem von Ihnen verwendeten Kernel passen. Haben Sie IhrenKernel selbst gebaut, so liegen die notwendigen Headerdateien wahrscheinlich nochunter /usr/src/linux/. Verwenden Sie einen vorkompilierten Kernel Ihrer Dis-tribution, so konnen Sie oft ein dazu passendes Paket mit den Kernel-Headerdateieninstallieren.

Haben Sie sich die BLCR-Quellen von [11] besorgt und entpackt, so ist BLCRwie gewohnt mit ./configure zu konfigurieren und schießlich durch die beidenKommandos make und make install zu installieren. Das Konfigurationsskriptversucht, die Headerdateien selbstandig zu finden. Gelingt dies nicht oder soll BLCRfur einen anderen als den gerade laufenden Kernel ubersetzt werden, so konnen Siemit der Option --with-linux=DIR dem Konfigurationsskript mitteilen, wo sichdie Kernel-Headerdateien befinden. Dabei bezeichnet DIR den Ort des Kernelquell-baums. In seltenen Fallen benotigt das Konfigurationsskript noch weitere Informatio-nen. Mit der Option --help, erfahren Sie, wie Sie dem Konfigurationsskript nochweiterhelfen konnen. Bei der Installation mit make install werden

• die Programme cr run, cr checkpoint, cr restart,• die dazugehorigen Manpages,• die Kernelmodule blcr.o und vmadump blcr.o,• die BLCR-Bibliothek und• die dazugehorigen Headerdateien

in Verzeichnisse unter /usr/local (Oder was immer Sie mit der Konfigurations-skriptoption --prefix bestimmt haben.) kopiert.

Die eigentliche Checkpointing-Funktionalitat von BLCR ist in den beiden Ker-nelmodulen implementiert. Diese sind mit dem Befehl insmod zu laden, zuerstvmadump blcr.o dann blcr.o.

root@node1:˜ # insmod /usr/local/lib/blcr/2.4.29/vmadump_blcr.oroot@node1:˜ # insmod /usr/local/lib/blcr/2.4.29/blcr.o

Lief alles glatt, finden Sie diese beiden Module nun in der Ausgabe von lsmod.

Page 406: [X.systems.press] Cluster Computing ||

13.3 Berkeley Lab Checkpoint/Restart 403

Listing 13.3. Init-Skript blcr zum Laden der Berkeley Lab Checkpoint/Restart Module.

# ! / b i n / sh

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/binNAME=” b l c r ”

5 DESC=” c h e c k p o i n t r e s t a r t e n v i r o n m e n t ”RELEASE=‘uname -r‘

case ” $1 ” instart)

10 echo -n ” S t a r t i n g $DESC : $NAME”insmod /usr/local/lib/blcr/$RELEASE/vmadump_blcr.oinsmod /usr/local/lib/blcr/$RELEASE/blcr.oecho ” . ”;;

15 stop)echo -n ” S t o p p i n g $DESC : $NAME”rmmod blcrrmmod vmadump_blcrecho ” . ”

20 ;;

*)N=/etc/init.d/$NAMEecho ” Usage : $N { s t a r t | s t o p }”exit 1

25 ;;esac

exit 0

root@node1:˜ # lsmodModule Size Used by Not taintedblcr 41460 0 (unused)vmadump_blcr 14864 0 [blcr]uhci 27036 0 (unused)ehci-hcd 18988 0 (unused)usbcore 41476 0 [uhci ehci-hcd]e1000 71244 1

Beachten Sie, dass der letzte Teil des Pfades zum Verzeichnis, in dem sich die Mo-dule befinden, ist die Versionsnummer des verwendeten Kernels. Diese erfahren Sieauch durch das Programm uname.

root@node1:˜ # uname -r2.4.29

Um sich das manuelle Laden der Module nach jedem Reboot zu ersparen, konnendiese z. B. durch ein Init-Skript wie das in Listing 13.3 geladen werden.

13.3.2 Anwendung

Das Programm cr checkpoint erzeugt eine Checkpointdatei eines laufenden Pro-zesses bzw. einer Prozessgruppe. Obwohl bei BLCR die wichtigsten Checkpointig-funktionen in Kernelmodulen implementiert sind, lassen sich mit Checkpoints nur

Page 407: [X.systems.press] Cluster Computing ||

404 13 Checkpoint-Restart

von Programmen erzeugen, die die BLCR-Bibliothek geladen haben. Dazu kann manein Programm entweder mit den Linkeroptionen -lpthread und -lcr explizit ge-gen die BLCR-Bibliothek linken oder mit dem Programm cr run starten. Als erstesArgument ist cr run das zu startende Programm zu ubergeben. Alle weiteren Argu-mente reicht cr run an das gestartete Programm weiter.

bauke@node1:˜/src $ cr_run ./checkpoint1 100i = 0 sum = 636766.737980i = 1 sum = 637174.249178i = 2 sum = 636416.164831i = 3 sum = 636438.344471i = 4 sum = 636598.508627...

Wahrend das Programm lauft, kann von einem anderen Terminal aus eine Check-pointdatei erzeugt werden. Dazu mussen Sie zunachst mit ps oder pidof die Pro-zessnummer des Programms herausfinden.

bauke@node1:˜/tmp $ ps -A | grep checkpoint124194 pts/1 00:00:12 checkpoint1bauke@node1:˜/tmp $ cr_checkpoint 24194

Wenn nur ein einziger Prozess namens checkpoint1 auf dem Computer lauft,konnen Sie auch

bauke@node1:˜/tmp $ cr_checkpoint ‘pidof checkpoint1‘

verwenden. Die Checkpointdatei wird ins momentane Arbeitsverzeichnis des Pro-gramms cr checkpoint abgelegt. Sein Name setzt sich aus context. und derProzessnummer zusammen, in unserem Beispiel ist er also context.24194. Beierfolgreichem Checkpointing wird eine eventuell schon vorhandene Datei gleichenNamens uberschrieben. Mit der Option --backup lassen sich alte Checkpointda-teien vor dem Uberschreiben retten. Sie werden stattdessen umbenannt und erhaltendie zusatzlichen Suffixe .∼1∼, .∼2∼ usw.

Normalerweise beeintrachtigt die Erzeugung einer Checkpointdatei das laufendeProgramm nicht, es lauft danach ganz normal weiter. Allerdings kann man mit crcheckpoint zusatzlich ein Signal an das Programm senden, das es zwingt, sichzum beenden. Die Optionen --stop, --term bzw. --abort veranlassen crcheckpoint das Signal SIGSTOP, SIGTERM bzw. SIGABRT zu senden. Einigeweitere Kommandozeilenoptionen finden Sie in der Manpage cr checkpoint(1).

Das Programm cr restart dient dazu, ein Programm mit Hilfe einer Check-pointdatei wieder zu starten. Dazu benotigt es lediglich die Checkpointdatei als Ar-gument.

bauke@node1:˜/tmp $ cr_restart context.24194

Der mit cr restart wiederaufgesetzte Prozess (bzw. die Prozessgruppe) hat wei-testgehend die gleichen Eigenschaften wie der von dem die Checkpointdatei erzeugtwurde. Dies betrifft sogar die Prozessnummer, nicht aber die Prozessnummer des

Page 408: [X.systems.press] Cluster Computing ||

13.3 Berkeley Lab Checkpoint/Restart 405

Elternprozesses (siehe Manpage getppid(2)). Nach einem Restart gibt die System-funktion getppid immer die Prozessnummer von cr restart zuruck. Fur diemeisten Programme durfte diese Einschrankung jedoch ohne Relevanz sein. Fallsirgendwelche benotigeten Ressourcen (z. B. die Prozessnummer) mittlerweile voneinem anderen Prozess belegt werden, scheitert der Restartversuch mit einer Feh-lermeldung. Waren die Standardein- oder Standardausgaben des Programms vor ei-nem Checkpointing mit einem Terminal verbunden, so werden sie nun mit dem Ter-minal verbunden, in dem cr restart aufgerufen wurde. Das Arbeitsverzeichnisist nach einem Restart jedoch das alte, es wird nicht auf das Abeitsverzeichnis voncr restart geandert.

13.3.3 Checkpointing von Multithread- und MPI-Programmen

Da BLCR mit seinen Kernelmodulen in den Betriebssystemkern eingreift, ist esdeutlich leistungsfahiger als ein Checkpointing-System, das ausschließlich auf User-Level arbeitet, wie z. B. Ckpt. Das zeigt sich auch darin, dass man mit BLCR Check-pointdateien von Programmen erzeugen kann, die mit mehreren Threads arbeiten.Starten Sie unter Linux 2.4.x ein Multithread-Programm wie z. B. threadint.cauf Seite 43, so sehen Sie mit ps fur jeden Thread einen eigenen Eintrag in der Pro-zesstabelle. Ubergeben Sie hier die kleinste Prozessnummer an cr checkpoint,wenn Sie eine Checkpointdatei erzeugen wollen. Unter Linux 2.6.x sind Threads et-was anders implementiert, hier bekommt nicht jeder Thread eine eigene Prozessnum-mer und es ergibt sich in Bezug auf die Verwendung von BLCR kein Unterschiedzwischen Multithread-Programmen und sequentiellen Programmen.

Wie schon oben angedeutet wurde, kann BLCR nicht nur mit sequentiellensondern—im Zusammenspiel mit LAM/MPI—auch mit MPI-Programmen umgehen.Das Checkpointing von MPI-Programmen ist deutlich schwieriger zu realisieren alsdas von sequentiellen Programmen. Hier reicht es ja nicht, eine Momentaufnahmeeines einzigen (lokalen) Prozesses zu speichern. MPI-Programme bilden normaler-weise eine ganze Gruppe von auf verschiedenen Knoten verteilt laufenden Prozessen,die uber TCP/IP oder ein anderes Protokoll kommunizieren. Das Checkpointing vonMPI-Programmen funktioniert deshalb nur, weil BLCR und LAM/MPI eng verzahntmiteinander interagieren.

Um mit BLCR und LAM/MPI von MPI-Programmen ein Checkpointing erstel-len und MPI-Programme wieder aufsetzen zu konnen, sind einige Vorbereitungennotwendig.

• BLCR muss auf allen Knoten installiert sein.• Alle Knoten mussen uber ein gemeinsames Netzwerkdateisystem verfugen. In

diesem werden spater die Checkpointdateien abgelegt.• LAM/MPI muss uber das Checkpointing Modul blcr und das RPI-Modul crtcp

verfugen, siehe Abschnitt 6.1.1.

Ob Ihre LAM/MPI-Version uber alle notwendigen Module verfugt, erfahren Siedurch das Programm laminfo, siehe Terminal Session 13.1. Wenn Sie LAM/MPI

Page 409: [X.systems.press] Cluster Computing ||

406 13 Checkpoint-Restart

Terminal Session 13.1. Die mit SSI cr beginnenden Zeilen der Ausgabe des Programmslaminfo zeigen, dass die verwendete LAM/MPI-Version die Checkpointingmodule self undblcr enthalt.bauke@server:˜ $ laminfo

LAM/MPI: 7.1.2b18Prefix: /usr/local

Architecture: i686-pc-linux-gnuConfigured by: rootConfigured on: Mon Mar 21 17:46:37 CET 2005Configure host: halMemory manager: ptmalloc2

C bindings: yesC++ bindings: yes

Fortran bindings: yesC compiler: gcc

C++ compiler: g++Fortran compiler: g77Fortran symbols: double_underscore

C profiling: yesC++ profiling: yes

Fortran profiling: yesC++ exceptions: noThread support: yesROMIO support: yesIMPI support: noDebug support: noPurify clean: no

SSI boot: globus (API v1.1, Module v0.6)SSI boot: rsh (API v1.1, Module v1.1)SSI boot: slurm (API v1.1, Module v1.0)SSI coll: lam_basic (API v1.1, Module v7.1)SSI coll: shmem (API v1.1, Module v1.0)SSI coll: smp (API v1.1, Module v1.2)SSI rpi: crtcp (API v1.1, Module v1.1)SSI rpi: lamd (API v1.0, Module v7.1)SSI rpi: sysv (API v1.0, Module v7.1)SSI rpi: tcp (API v1.0, Module v7.1)SSI rpi: usysv (API v1.0, Module v7.1)SSI cr: blcr (API v1.0, Module v1.1)SSI cr: self (API v1.0, Module v1.0)

vor BLCR installiert haben, wird in der Ausgabe von laminfo das Checkpoin-tingmodul blcr fehlen. Sie mussen dann, nachdem Sie BLCR erfolgreich einge-richtet haben, LAM/MPI noch einmal neu kompilieren. Das LAM/MPI-Konfigura-tionsskript findet BLCR normalerweise automatisch und konfiguriert LAM/MPI ent-sprechend. Andernfalls teilen Sie dem LAM/MPI-Konfigurationsskript mit der Op-tion --with-cr-blcr mit, wo die BLCR-Bibliothek zu finden ist. Naheres zurLAM/MPI-Installation steht in Abschnitt 6.1.1 bzw. im LAM/MPI-Installationshand-buch.

MPI-Programme kommunizieren standig uber TCP/IP oder andere Kanale. InTabelle 13.1 sehen Sie aber, dass BLCR den Zustand von Internet-Sockets gar nichtspeichern und restaurieren kann. Wie kann so das Checkpointing von MPI-Program-men funktionieren? Der Trick besteht darin, das RPI-Modul crtcp zu verwenden. ImFalle eines Checkpoints werden von diesem Modul kurzzeitig alle Kommunikations-

Page 410: [X.systems.press] Cluster Computing ||

13.3 Berkeley Lab Checkpoint/Restart 407

kanale geschlossen und danach wieder geoffnet. Die Verwendung des Moduls blcrimpliziert einige Fahigkeiten und Einschrankungen.

• Der Quelltext eines MPI-Programms muss nicht speziell fur das Checkpointingangepasst werden. Es darf allerdings keine MPI-2-Funktionen verwenden.

• Die Checkpoint-Restart-Funktionalitat betrifft nur das MPI-Programm selbst.Das LAM-Universum muss gegebenenfalls vor einem Restart von Hand mitlamboot wiedererschaffen werden.

• Ein Checkpointing kann nur durchgefuhrt werden, nachdem alle Prozesse MPIInit und bevor alle Prozesse MPI Finalize aufgerufen haben.

• Das Modul crtcp verursacht leicht erhohte Kommunikationskosten.• Eine Kommunikation uber Myrinet oder InfiniBand ist nicht moglich, es sei denn,

man betreibt uber das Myrinet- bzw. das InfiniBand-Protokoll TCP/IP.

Im Gegensatz zu sequentiellen Programmen werden MPI-Programme fur das Check-pointing nicht uber cr run gestartet. Stattdessen kommt wie gewohnt mpirun zumEinsatz. Folgendes Kommando startet das Programm checkpoint mpi mit vierProzessen und aktivierter Checkpointfunktion.

bauke@server:˜/src $ mpicc -o checkpoint_mpi checkpoint_mpi.c -lmbauke@server:˜/src $ mpirun -np 4 -ssi rpi crtcp -ssi cr blcr \> checkpoint_mpi

Durch das Modul crtcp wird ein chechkpointfahiges Kommunikationsprotokoll akti-viert. Als Checkpoint-Modul wurde blcr gewahlt.

Mit cr checkpoint lasst sich wie bei sequentiellen Programmen auch voneinem laufenden MPI-Programm eine Momentaufnahme machen. In diesem Falleist cr checkpoint die Prozessnummer des mpirun-Prozesses zu ubergeben, derdas betreffende Programm gestartet hat. Nehmen wir an sie sei 4055.

bauke@server:˜ $ cr_checkpoint --term 4055

Durch die Option --term wurde das MPI-Programm auch gleich beendet. WennSie nun einen Blick in das Heimatverzeichnis werfen, so finden Sie da gleich mehrereCheckpointdateien.

bauke@server:˜ $ ls -w 1 context.4055*context.4055context.4055-n0-4056context.4055-n0-4057context.4055-n1-2038context.4055-n1-2039

In der Datei context.4055 liegt die Momentaufnahme von mpirun. Die ande-ren Checkpointdateien enthalten jeweils die Momentaufnahmen der MPI-Prozesse.In ihren Namen ist jeweils der Knoten, auf dem der Prozess lief, und die Nummerdes Prozesses codiert. Beachten Sie, dass diese Checkpointdateien nur erfolgreich an-gelegt werden konnen, wenn das Heimatverzeichnis in einem Netzwerkdateisystemliegt, auf das alle Knoten schreiben konnen. Mit

Page 411: [X.systems.press] Cluster Computing ||

408 13 Checkpoint-Restart

bauke@server:˜ $ cr_restart context.4055

lasst sich das MPI-Programm wieder fortfuhren. Dadurch wird zunachst der mpirun-Prozess rekonstruiert, der seinerseits auf allen Knoten die Prozesse das MPI-Pro-gramms wieder aufsetzt.

Wir haben uns hier darauf beschrankt zu beschreiben, wie man mit BLCR einProgramm manuell startet, ein Checkpointing durchfuhrt und das Programm wiederaufsetzt. In einer Cluster-Umgebung ist Checkpoint/Restart aber idealerweise in dasBatch-System integriert. Zu beschreiben, wie dies fur alle denkbaren Batch-Systemefunktioniert, geht jedoch uber den Rahmen dises Buches hinaus. In [134] finden Sieeine Anleitung zur Integration von BLCR in die Sun Grid Engine.

13.4 Notizen

13.1 LAM/MPI-Version. Die Checkpointfunktionalitat ist seit der Version 7.0 Be-standteil von LAM/MPI. Allerdings war die Betaversion 7.1.2b10 die erste mit derwir sie tatsachlich nutzen konnten. Sowohl BLCR als auch die Checkpointfunktiona-litat in LAM/MPI sind recht neu und entwickeln sich noch. Falls Sie Probleme beider Verwendung der Checkpointfunktionalitat in LAM/MPI haben, steht man Ihnenauf den Mailinglisten von LAM/MPI und BLCR mit gutem Rat zur Seite.

13.2 self, ein weiteres LAM/MPI-Checkpointing Modul. Neben blcr gibt es nochdas Checkpointmodul self. Dies ist fur MPI-Programme gedacht, die das Checkpoin-ting auf Application-Level implementieren. Naheres erfahren Sie in der LAM/MPI-Dokumentation.

13.3 BLCR-Bibliothek. Ahnlich wie fur Ckpt beschrieben konnen Ihre Program-me auch aktiv Checkpointfunktionen der BLCR-Bibliothek nutzen. Dazu mussen siedie Headerdatei libcr.h einbinden und mit -lpthread und -lcr gegen dieBLCR-Bibliothek gelinkt werden. Die Dokumentation der BLCR-Bibliothek ist al-lerdings bisher recht sparlich und besteht im Wesentlichen aus den Kommentaren inlibcr.h.

Page 412: [X.systems.press] Cluster Computing ||

Teil V

Anhang

Page 413: [X.systems.press] Cluster Computing ||

14

Die C-Schnittstelle des MPI-Standards

C is often described, with a mixture of fondness and disdainvarying according to the speaker, as “language that combinesall the elegance and power of assembly language with all thereadability and maintainability of assembly language”.

The Jargon File

Dieser Anhang beschreibt kurz die C-Funktionen aus MPI-1.2 sowie einiger wenigeraus MPI-2. Fur eine genauere Dokumentation finden Sie jeweils Verweise auf dieentsprechenden Stellen in den MPI-Standards [59, 103] bzw. diesem Buch.

14.1 Konstanten

Tabelle 14.1. Die MPI-Datentypen.

MPI-Datentyp C-Datentyp Bemerkung

MPI CHAR char im ZeichenkontextMPI SIGNED CHAR signed char MPI-2, im ZahlkontextMPI UNSIGNED CHAR unsigned char im ZahlkontextMPI WCHAR wchar t MPI-2, siehe stddef.hMPI SHORT shortMPI UNSIGNED SHORT unsigned shortMPI INT intMPI UNSIGNED unsigned intMPI LONG longMPI UNSIGNED LONG unsigned longMPI LONG LONG INT long long optionalMPI UNSIGNED LONG LONG unsigned long long MPI-2, optionalMPI FLOAT floatMPI DOUBLE doubleMPI LONG DOUBLE long doubleMPI BYTE keine Entsprechung ein Byte, siehe MPI-1.1 §3.2.2MPI PACKED keine Entsprechung siehe Funktion MPI Pack

Page 414: [X.systems.press] Cluster Computing ||

412 14 Die C-Schnittstelle des MPI-Standards

Tabelle 14.2. MPI-Reduktionsoperationen, siehe auch MPI-1.1 §4.9. Die logischen und bit-weisen Operationen sind nur fur Ganzzahltypen definiert.

Operation Bedeutung

MPI MAX MaximumMPI MIN MinimumMPI SUM SummeMPI PROD ProduktMPI MAXLOC Maximum mit Positionsbestimmung, siehe MPI-1.1 §4.9.3MPI MINLOC Minimum mit Positionsbestimmung, siehe MPI-1.1 §4.9.3MPI BAND bitweise Und-VerknupfungMPI BOR bitweise Oder-VerknupfungMPI BXOR bitweise Exklusiv-Oder-VerknupfungMPI LAND logische Und-VerknupfungMPI LOR logische Oder-VerknupfungMPI LXOR logische Exklusiv-Oder-Verknupfung

Tabelle 14.3. Verschiedene Konstanten.

Konstante Bedeutung

MPI BOTTOM Beginn des Adressraumes eines Datentyps, siehe MPI-1.1§3.12.2 ff.

MPI PROC NULL kann als Rang in Sende- oder Empfangsfunktionen verwendetwerden, entsprechende Funktion bleibt dann wirkungslos, sie-he MPI-1.1 §3.11

MPI ANY SOURCE kann als Rang in Empfangsfunktionen verwendet werden,passt auf jeden Rang, siehe MPI-1.1 §3.2.4

MPI ANY TAG kann als Etikett (Tag) in Empfangsfunktionen verwendet wer-den, passt auf jede Etikett, siehe MPI-1.1 §3.2.4

MPI UNDEFINED wird von manchen Funktionen zuruckgegeben, wenn ein Feh-ler auftrat

MPI BSEND OVERHEAD obere Schranke fur die Große des Speichers mit Verwaltungs-information, der von MPI Bsend benotigt wird

MPI KEYVAL INVALID siehe MPI-1.1 §5.7

Tabelle 14.4. Null-Handle-Konstanten.

Konstante Null-Handle fur

MPI GROUP NULL GruppenMPI COMM NULL KommunikatorenMPI DATATYPE NULL DatentypenMPI REQUEST NULL RequestsMPI OP NULL kollektive OperatorenMPI ERRHANDLER NULL Fehler-Behandlungs-Funktionen

Page 415: [X.systems.press] Cluster Computing ||

14.2 MPI-Umgebung 413

Tabelle 14.5. MPI-Fehlerklassen.

Fehlercode Bedeutung

MPI SUCCESS kein Fehler aufgetretenMPI ERR BUFFER ungultiger PufferzeigerMPI ERR COUNT ungultige AnzahlMPI ERR TYPE ungultiger MPI-DatentypMPI ERR TAG ungultige Etikett (Tag)MPI ERR COMM ungultiger KommunikatorMPI ERR RANK ungultiger RangMPI ERR REQUEST ungultiger RequestMPI ERR ROOT ungultiger Quell- oder empfangender RangMPI ERR GROUP ungultige GruppeMPI ERR OP ungulige OperationMPI ERR TOPOLOGY ungulige TopologieMPI ERR DIMS ungulige DimensionMPI ERR ARG unguliges ArgumentMPI ERR UNKNOWN unbekannter FehlerMPI ERR TRUNCATE unvollstandig empfangene NachrichtMPI ERR OTHER unbekannter FehlerMPI ERR INTERN interner Fehler der MPI-ImplementationMPI ERR IN STATUS Fehlercode befindet sich im StatusargumentMPI ERR LASTCODE letzter FehlercodeMPI ERR PENDING noch ausstehende Anfrage

14.2 MPI-Umgebung

MPI Init

Syntax:

int MPI_Init(int *argc, char ***argv)

Argumente:argc: Pointer auf das erste Argument der main-Funktionargv: Pointer auf das zweite Argument der main-Funktion

Funktion: Diese Funktion initialisiert die MPI-Umgebung. Keine andere Funktion der MPI-Bibliothek (außer MPI Initialized) darf vor MPI Init aufgerufen werden. BeideArgumente durfen nach MPI-2 auch auf NULL zeigen.

siehe auch: MPI-1.1 §7.5, MPI Initialized, MPI Finalize, Abschnitt 7.1

MPI Finalize

Syntax:

int MPI_Finalize(void)

Funktion: Beendet die MPI-Umgebung, außer MPI Initialized darf keine andere MPI-Funktion nach MPI Finalize aufgerufen werden.

siehe auch: MPI-1.1 §7.5, Abschnitt 7.1

Page 416: [X.systems.press] Cluster Computing ||

414 14 Die C-Schnittstelle des MPI-Standards

MPI Abort

Syntax:

int MPI_Abort(MPI_Comm comm, int errorcode)

Argumente:comm: Kommunikatorerrorcode: Fehlercode

Funktion: Beenet alle Prozesse, die implementationsabhangig entweder zum angegebenenKommunikator oder zu MPI COMM WORLD gehoren. Der Fehlercoded wird u. U. vomProgramm an die Laufzeitumgebung (Shell) zuruckgegeben.

siehe auch: MPI-1.1 §7.5, Abschnitt 7.3.5

MPI Get processor name

Syntax:

int MPI_Get_processor_name(char *name, int *resultlen)

Argumente:name: Adresse, ab der der Pozessorname abgelegt wirdresultlen: Lange des Pozessornamens

Funktion: Gibt Namen des Pozessors zuruck, auf dem der Prozess momentan lauft. Ab derAdresse name muss Platz fur mindestens MPI MAX PROCESSOR NAME Zeichen reser-viert worden sein. Der MPI-Standard garantiert nicht, dass der zuruckgegebene Stringnull-terminiert ist.

siehe auch: MPI-1.1 §7.1.1.4, Abschnitt 7.1

MPI Wtime

Syntax:

double MPI_Wtime(void)

Funktion: Gibt die auf einen willkurlichen Startpunkt bezogene Zeit in Sekunden zuruck.Falls die Uhren aller Prozesse synchron laufen, so hat das Symbol MPI WTIME ISGLOBAL den Wert 1. Die Funktion MPI Wtick gint Auskunft uber die Auflosung derUhr.

siehe auch: MPI-1.1 §7.4, Abschnitt 7.4.2

Verwandte Funktionen

• MPI Initialized, MPI-1.1 §7.5, Anmerkung 7.2• MPI Finalized, MPI-2 §4.9, Anmerkung 7.2• MPI Wtick, MPI-1.1 §7.4• MPI Errhandler create, MPI-1.1 §7.2, Abschnitt 8.2 (in MPI-2 als deprecated ge-

kennzeichnet und durch die Funktion MPI Comm create errhandler ersetzt)• MPI Comm create errhandler, MPI-2 §4.13.1

Page 417: [X.systems.press] Cluster Computing ||

14.3 Blockierende Punkt-zu-Punkt-Kommunikation 415

• MPI Errhandler set, MPI-1.1 §7.2, Abschnitt 8.2 (in MPI-2 als deprecated gekenn-zeichnet und durch die Funktion MPI Comm det errhandler ersetzt)

• MPI Comm set errhandler, MPI-2 §4.13.1• MPI Errhandler get, MPI-1.1 §7.2, Abschnitt 8.2 (in MPI-2 als deprecated gekenn-

zeichnet und durch die Funktion MPI Comm get errhandler ersetzt)• MPI Comm get errhandler, MPI-2 §4.13.1• MPI Errhandler free, MPI-1.1 §7.2, Abschnitt 8.2• MPI Error string, MPI-1.1 §7.2, Abschnitt 8.2• MPI Error class, MPI-1.1 §7.2, Abschnitt 8.2• MPI Get version, MPI-1.2 §3.1

14.3 Blockierende Punkt-zu-Punkt-Kommunikation

MPI Send

Syntax:

int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest,int tag, MPI_Comm comm)

Argumente:buf: Sendepuffercount: Zahl der Datenelemente im Sendepufferdatatype: MPI-Datentypdest: empfangender Rangtag: Etikettcomm: Kommunikator

Funktion: Standardfunktion zum Senden von count Daten des Typs datatype an den Pro-zess dest im Kommunikator comm. Das Argument buf ist ein Zeiger auf einen Puffer,der die zu senden Daten enthalt. Mit dem Etikett tag konnen verschiedene Nachrichtenunterschieden werden. Nach dem Aufruf dieser Funktion darf der Puffer sofort wieder mitneuen Daten beschrieben werden, die Nachricht muss aber noch nicht beim Empfangerangekommen sein.

siehe auch: MPI-1.1 §3.2.1, §3.5, Abschnitt 7.2

MPI Recv

Syntax:

int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source,int tag, MPI_Comm comm, MPI_Status *status)

Argumente:buf: Empfangspuffercount: Zahl der Datenelemente, die der Empfangspuffer maximal aufnehmen kanndatatype: MPI-Datentypsource: sendender Rangtag: Etikettcomm: Kommunikator

Page 418: [X.systems.press] Cluster Computing ||

416 14 Die C-Schnittstelle des MPI-Standards

status: StatusFunktion: Funktion zum Empfangen von count Daten des Typs datatype vom Prozess

source im Kommunikator comm. Das Argument buf ist ein Zeiger auf einen Puffer,in dem die empfangenen Daten gespeichert werden. Mit dem Etikett tag konnen ver-schiedene Nachrichten unterschieden werden. Fur die Quelle und das Etikett sind diePlatzhalter MPI ANY SOURCE bzw. MPI ANY TAG erlaubt. Sie passen auf alle Quellenbzw. Etiketten. Der Status enthalt Information uber die Anzahl tatsachlich empfangenerDaten, den sendenden Rang und dem Etikett. Wird die Statusinformation nicht benotigt,so kann ab MPI-1.2 die Statusvariable auch MPI STATUS IGNORE sein.

siehe auch: MPI-1.1 §3.2.4, §3.5, Abschnitt 7.2

MPI Get count

Syntax:

int MPI_Get_count(MPI_Status *status, MPI_Datatype datatype,int *count)

Argumente:status: Statusdatatype: MPI-Datentypcount: Zahl der Datenelemente

Funktion: Nachdem status in Empfangsfunktion verwendet wurde, so schreibt MPI Getcount die Anzahl der tatsachlich empfangenen Daten vom Typ datatype nachcount.

siehe auch: MPI-1.1 §3.2.5, Abschnitt 7.2

MPI Sendrecv

Syntax:

int MPI_Sendrecv(void *sendbuf, int sendcount, MPI_Datatype sendtype,int dest, int sendtag,void *recvbuf, int recvcount, MPI_Datatype recvtype,int source, int recvtag,MPI_Comm comm, MPI_Status *status)

Argumente:sendbuf: Sendepuffersendcount: Zahl der Datenelemente im Sendepuffersendtype: MPI-Datentyp der zu sendenden Datendest: Zielrangsendtag: Sendekennzeichnungrecvbuf: Empfangspufferrecvcount: Zahl der Datenelemente im Empfangspufferrecvtype: MPI-Datentyp der zu empfangenden Datensource: Quellrangrecvtag: Empfangskennzeichnungcomm: Kommunikatorstatus: Empfangsstatus

Page 419: [X.systems.press] Cluster Computing ||

14.4 Nicht blockierende Punkt-zu-Punkt-Kommunikation 417

Funktion: Mit dieser blockierenden Kommunikationsfunktion konnen gleichzeitig Datenempfangen und gesendet werden. Quell- und Zielrang durfen identisch sein. Eine mitMPI Sendrecv verschickte Nachricht kann mit jeder normalen Empfangsfunktion emp-fangen werden, andererseits konnen damit auch Nachrichten herkomlicher Sendefunktio-nen empfangen werden.

siehe auch: MPI-1.1 §3.10, Abschnitte 7.4.3 und 9.2.3

MPI Probe

Syntax:

int MPI_Probe(int source, int tag, MPI_Comm comm, MPI_Status *status)

Argumente:source: sendender Rangtag: Etikettcomm: Kommunikatorstatus: Status

Funktion: Diese Funktion kehrt zuruck, sobald eine Nachricht vom Rang source des Kom-munikators comm eintrifft. Danach kann diese mit MPI Recv empfangen oder mitMPI Cancel erworfen werden. Mit Hilfe dieser Funktion konnen Nachrichten mita priori unbekannter Langer empfangen werden. Die Informationen in status konnendazu verwendet werden, vor dem Aufruf der Enpfangsfunktion ausreichend Speicher zureservieren.

siehe auch: MPI-1.1 §3.8, MPI-2 §3.2.9, MPI Iprobe, MPI Cancel, MPI Recv, Ab-schnitt 7.2

Verwandte Funktionen

• MPI Bsend, MPI-1.1 §3.4, Abschnitt 7.4.1• MPI Ssend, MPI-1.1 §3.4, Abschnitt 7.4.1• MPI Rsend, MPI-1.1 §3.4, Abschnitt 7.4.1• MPI Buffer attach, MPI-1.1 §3.6, Abschnitt 7.4.1• MPI Buffer detach, MPI-1.1 §3.6, Abschnitt 7.4.1• MPI Sendrecv replace, MPI-1.1 §3.10, Abschnitt 7.4.3

14.4 Nicht blockierende Punkt-zu-Punkt-Kommunikation

MPI Isend

Syntax:

int MPI_Isend(void *buf, int count, MPI_Datatype datatype, int dest,int tag, MPI_Comm comm, MPI_Request *request)

Argumente:buf: Sendepuffercount: Zahl der Datenelemente im Sendepuffer

Page 420: [X.systems.press] Cluster Computing ||

418 14 Die C-Schnittstelle des MPI-Standards

datatype: MPI-Datentypdest: empfangender Rangtag: Etikettcomm: Kommunikatorrequest: Request

Funktion: Standardfunktion zum nicht blockierenden Senden von count Daten des Typsdatatype an den Prozess dest im Kommunikator comm. Das Argument buf ist einZeiger auf einen Puffer, der die zu senden Daten enthalt. Mit dem Etikett tag konnen ver-schiedene Nachrichten unterschieden werden. Nach dem Aufruf dieser Funktion darf derPuffer nicht sofort wieder mit neuen Daten beschrieben werden. Mit Hilfe der Request-Variablen und der Funktionen MPI Wait oder MPI Test muss erst das Ende der (sen-derseitigen) Kommunikation abgewartet werden.

siehe auch: MPI-1.1 §3.7, speziell MPI-1.1 §3.7.2, Abschnitt 7.5

MPI Irecv

Syntax:

int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source,int tag, MPI_Comm comm, MPI_Request *request)

Argumente:buf: Empfangspuffercount: Zahl der Datenelemente, die der Empfangspuffer maximal aufnehmen kanndatatype: MPI-Datentypsource: sendender Rangtag: Etikettcomm: Kommunikatorrequest: Request

Funktion: Nicht blockierende Kommunikationsfunktion zum Empfangen von count Datendes Typs datatype vom Prozess source im Kommunikator comm. Das Argumentbuf ist ein Zeiger auf einen Puffer, in dem die empfangenen Daten gespeichert werden.Mit dem Etikett tag konnen verschiedene Nachrichten unterschieden werden. Mit Hilfeder Request-Variablen und der Funktionen MPI Wait oder MPI Test muss erst dasEnde der Kommunikation abgewartet werden, ehe auf den Empfangspuffer zugegriffenwerden darf.

siehe auch: MPI-1.1 §3.7, speziell MPI-1.1 §3.7.2, Abschnitt 7.5.1

MPI Iprobe

Syntax:

int MPI_Iprobe(int source, int tag, MPI_Comm comm, int *flag,MPI_Status *status)

Argumente:source: sendender Rangtag: Etikettcomm: Kommunikator

Page 421: [X.systems.press] Cluster Computing ||

14.4 Nicht blockierende Punkt-zu-Punkt-Kommunikation 419

flag: Signalstatus: Status

Funktion: Die Funktion testet nicht blockierend, ob passende Nachrichten anliegen. Ist diesder Fall, so enthalt die Signalvariable einen Wert ungleich null.

siehe auch: MPI-1.1 §3.8

MPI Wait

Syntax:

int MPI_Wait(MPI_Request *request, MPI_Status *status)

Argumente:request: Requeststatus: Status

Funktion: Diese Funktion wartet, bis die duch den Requenst gegebene Kommunikation been-det ist und speichert Statusinformationen in status.

siehe auch: MPI-1.1 §3.7, speziell MPI-1.1 §3.7.3, Abschnitt 7.5

MPI Test

Syntax:

int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status)

Argumente:request: Requestflag: Signalstatus: Status

Funktion: Diese Funktion testet, ob die duch den Requenst gegebene Kommunikation been-det ist und speichert gegebenenfalls Statusinformationen in status. Ist die der Kommu-nikationsvorgang tatsachlich beendet, so enthalt die Signalvariable einen Wert ungleichnull.

siehe auch: MPI-1.1 §3.7, speziell MPI-1.1 §3.7.3, Abschnitt 7.5.1

Verwandte Funktionen

• MPI Ibsend, MPI-1.1 §3.7, speziell MPI-1.1 §3.7.2, Abschnitt 7.5.1• MPI Issend, MPI-1.1 §3.7, speziell MPI-1.1 §3.7.2, Abschnitt 7.5.1• MPI Irsend, MPI-1.1 §3.7, speziell MPI-1.1 §3.7.2, Abschnitt 7.5.1• MPI Request free, MPI-1.1 §3.7, speziell MPI-1.1 §3.7.3• MPI Waitany, MPI-1.1 §3.7, speziell MPI-1.1 §3.7.5, Abschnitt 7.5.3• MPI Testany, MPI-1.1 §3.7, speziell MPI-1.1 §3.7.5, Abschnitt 7.5.3• MPI Waitall, MPI-1.1 §3.7, speziell MPI-1.1 §3.7.5, Abschnitt 7.5.3• MPI Testall, MPI-1.1 §3.7, speziell MPI-1.1 §3.7.5, Abschnitt 7.5.3• MPI Waitsome, MPI-1.1 §3.7, speziell MPI-1.1 §3.7.5, Abschnitt 7.5.3• MPI Testsome, MPI-1.1 §3.7, speziell MPI-1.1 §3.7.5, Abschnitt 7.5.3• MPI Cancel, MPI-1.1 §3.8• MPI Test canceled, MPI-1.1 §3.8

Page 422: [X.systems.press] Cluster Computing ||

420 14 Die C-Schnittstelle des MPI-Standards

14.5 Persistente Kommunikation

Verwandte Funktionen

• MPI Send init, MPI-1.1 §3.9, Abschnitt 7.5.4• MPI Bsend init, MPI-1.1 §3.9, Abschnitt 7.5.4• MPI Ssend init, MPI-1.1 §3.9, Abschnitt 7.5.4• MPI Rsend init, MPI-1.1 §3.9, Abschnitt 7.5.4• MPI Recv init, MPI-1.1 §3.9, Abschnitt 7.5.4• MPI Start, MPI-1.1 §3.9, Abschnitt 7.5.4• MPI Startall, MPI-1.1 §3.9, Abschnitt 7.5.4

14.6 Abgeleitete Datentypen

MPI Type contiguous

Syntax:

int MPI_Type_contiguous(int count, MPI_Datatype oldtype,MPI_Datatype *newtype)

Argumente:count: Anzahl der Datenelemeneoldtype: Basis-MPI-Datentypnewtype: neuer MPI-Datentyp

Funktion: Erzeugt neuen Datentyp newtype, der aus count kontinuierlich im Speicherangeordneten Elementen des Types oldtype besteht.

siehe auch: MPI-1.1 §3.12, speziell MPI-1.1 §3.12.1, Abschnitt 8.3.3

MPI Type vector

Syntax:

int MPI_Type_vector(int count, int blocklength, int stride,MPI_Datatype oldtype, MPI_Datatype *newtype)

Argumente:count: Anzahl der Datenblockeblocklength: Anzahl der Datenelemente vom Typ old type je Datenblockstride: Anzahl der Datenelemente vom Typ old type zwischen dem ersten Daten-

element des ersten Blocks und dem ersten Datenelement des zweiten Datenelementsoldtype: Basis-MPI-Datentypnewtype: neuer MPI-Datentyp

Funktion: Erzeugt neuen Datentyp newtype, der aus count Blocken besteht. Jeder dieserBlocke besteht aus length Elementen des Typs oldtype. Elemente innerhalb einesBlocks liegen kontinuierlich im Speicher aber der Abstand zweier Datenblocke betragtstride Elemente.

siehe auch: MPI-1.1 §3.12, speziell MPI-1.1 §3.12.1, Abschnitt 8.3.3

Page 423: [X.systems.press] Cluster Computing ||

14.6 Abgeleitete Datentypen 421

MPI Type indexed

Syntax:

int MPI_Type_indexed(int count, int *array_of_blocklengths,int *array_of_displacements,MPI_Datatype oldtype, MPI_Datatype *newtype)

Argumente:count: Anzahl der Datenblockearray of blocklengths: Feld, das fur jeden Datenblock die Anzahl der Datenele-

mente vom Typ old type enthaltarray of displacements: Feld, das fur jeden Datenblock seine Position codiertoldtype: Basis-MPI-Datentypnewtype: neuer MPI-Datentyp

Funktion: Erzeugt neuen Datentyp newtype, der aus count Blocken besteht. Jeder die-ser Blocke besteht aus in array of blocklengths gegebenen Elementen des Typsoldtype. Elemente innerhalb eines Blocks liegen kontinuierlich im Speicher. Der An-fang eines Datenblocks ist durch array of displacements gegeben.

siehe auch: MPI-1.1 §3.12, speziell MPI-1.1 §3.12.1, Abschnitt 8.3.3

MPI Type struct

Syntax:

int MPI_Type_struct(int count, int *array_of_blocklengths,MPI_Aint *array_of_displacements,MPI_Datatype *array_of_types,MPI_Datatype *newtype)

Argumente:count: Anzahl der Datenblockearray of blocklengths: Feld, das fur jeden Datenblock die Anzahl der Datenele-

mente vom Typ old type enthaltarray of displacements: Feld, das fur jeden Datenblock seine Position codiertarray of types: Feld, das fur jeden Datenblock den Basis-MPI-Datentyp enthaltnewtype: neuer MPI-Datentyp

Funktion: Erzeugt neuen Datentyp newtype, der aus count Blocken besteht. Jeder die-ser Blocke besteht aus in array of blocklengths gegebenen Elementen des inarray of types gegbenen Typs. Elemente innerhalb eines Blocks liegen kontinuier-lich im Speicher. Der Anfang eines Datenblocks ist durch array of displacementsgegeben.

siehe auch: MPI-1.1 §3.12, speziell MPI-1.1 §3.12.1, Abschnitt 8.3.3 (in MPI-2 als depreca-ted gekennzeichnet und durch die Funktion MPI Type create struct ersetzt)

MPI Type commit

Syntax:

int MPI_Type_commit(MPI_Datatype *datatype)

Page 424: [X.systems.press] Cluster Computing ||

422 14 Die C-Schnittstelle des MPI-Standards

Argumente:datatype: MPI-Datentyp

Funktion: Macht einen mit MPI Type contiguous oder verwandten Funktionen erzeug-ten Datentyp dem System bekannt. Erst danach kann er wirklich verwendet werden.

siehe auch: MPI-1.1 §3.12, speziell MPI-1.1 §3.12.4, Abschnitt 8.3.3

MPI Type free

Syntax:

int MPI_Type_free(MPI_Datatype *datatype)

Argumente:datatype: MPI-Datentyp

Funktion: Macht die Wirkung von MPI Type commit ruckgangig. MPI-Datentypen, dievom Datentyp datatype abgeleitet wurden, sind davon in keiner Weise beeinflusst.

siehe auch: MPI-1.1 §3.12, speziell MPI-1.1 §3.12.4, Abschnitt 8.3.3

MPI Address

Syntax:

int MPI_Address(void *location, MPI_Aint *address)

Argumente:location: Zeiger auf Objekt, dessen Adresse ermittelt werden solladdress: Adresse

Funktion: Rechnet einen Zeiger in eine Speicheradresse um.siehe auch: MPI-1.1 §3.12, speziell MPI-1.1 §3.12.2, Abschnitt 8.3.3 (in MPI-2 als depreca-

ted gekennzeichnet und durch die Funktion MPI Get address ersetzt)

MPI Type extent

Syntax:

int MPI_Type_extent(MPI_Datatype datatype, MPI_Aint *extent)

Argumente:datatype: Datentypextent: Ausdehnung

Funktion: Ermittelt die Ausdehnung eines Datentyps.siehe auch: MPI-1.1 §3.12, speziell MPI-1.1 §3.12.2, Abschnitt 8.3.3 (in MPI-2 als depreca-

ted gekennzeichnet und durch die Funktion MPI Type get extent ersetzt)

Page 425: [X.systems.press] Cluster Computing ||

14.6 Abgeleitete Datentypen 423

MPI Type lb

Syntax:

int MPI_Type_lb(MPI_Datatype datatype, MPI_Aint *displacement)

Argumente:datatype: Datentypdisplacement: untere Beschrankung

Funktion: Ermittelt die untere Beschrankung eines Datentyps.siehe auch: MPI-1.1 §3.12, speziell MPI-1.1 §3.12.2, Abschnitt 8.3.3 (in MPI-2 als depreca-

ted gekennzeichnet und durch die Funktion MPI Type get extent ersetzt)

MPI Type ub

Syntax:

int MPI_Type_ub(MPI_Datatype datatype, MPI_Aint *displacement)

Argumente:datatype: Datentypdisplacement: obere Beschrankung

Funktion: Ermittelt die obere Beschrankung eines Datentyps.siehe auch: MPI-1.1 §3.12, speziell MPI-1.1 §3.12.2, Abschnitt 8.3.3 (in MPI-2 als depreca-

ted gekennzeichnet und durch die Funktion MPI Type get extent ersetzt)

MPI Get elements

Syntax:

int MPI_Get_elements(MPI_Status *status, MPI_Datatype datatype,int *count)

Argumente:status: Statusdatatype: Datentypcount: Anzahl

Funktion: Ermittelt wieviele MPI-Grundtypen (siehe Tabelle 14.1) in einer Nachricht empfan-gen wurden. Dazu muss status vorher in einer Empfangsfunktion verwendet wordensein.

siehe auch: MPI-1.1 §3.12, speziell MPI-1.1 §3.12.2, Abschnitt 8.3.3 (in MPI-2 als depreca-ted gekennzeichnet und durch die Funktion MPI Type get extent ersetzt)

Page 426: [X.systems.press] Cluster Computing ||

424 14 Die C-Schnittstelle des MPI-Standards

Verwandte Funktionen

• MPI Type hvector, MPI-1.1 §3.12, speziell MPI-1.1 §3.12.1 (in MPI-2 als deprecatedgekennzeichnet und durch die Funktion MPI Type create hvector ersetzt)

• MPI Type create hvector, MPI-2 §4.14.1• MPI Type indexed, MPI-1.1 §3.12, speziell MPI-1.1 §3.12.1, Abschnitt 8.3.3 (in

MPI-2 als deprecated gekennzeichnet und durch die Funktion MPI Type createindexed ersetzt)

• MPI Type create indexed, MPI-2 §4.14.1• MPI Type hindexed, MPI-1.1 §3.12, speziell MPI-1.1 §3.12.1• MPI Get address, MPI-2 §4.14.1• MPI Type get extent, MPI-2 §4.14.2• MPI Type size, MPI-1.1 §3.12, speziell MPI-1.1 §3.12.2• MPI Pack, MPI-1.1 §3.13• MPI Unpack, MPI-1.1 §3.13• MPI Pack size, MPI-1.1 §3.13• MPI Type create resized, MPI-2 §4.14.2• MPI Type get true extent, MPI-2 §4.14.3• MPI Type create subarray, MPI-2 §4.14.4• MPI Type create darray, MPI-2 §4.14.4

14.7 Kollektive Kommunikation

MPI Barrier

Syntax:

int MPI_Barrier(MPI_Comm comm)

Argumente:comm: Kommunikator

Funktion: Blockiert den aufrufenden Prozess, bis alle Prozesse des Kommunikators dieseFunktion aufgerufen haben.

siehe auch: MPI-1.1 §4.3, Abschnitt 7.3.2

MPI Bcast

Syntax:

int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype,int root, MPI_Comm comm)

Argumente:buffer: Sende- bzw. Empfangspuffercount: Zahl Datenelemente in Sende- bzw. Empfangspufferdatatype: MPI-Datentyproot: sendender Rangcomm: Kommunikator

Funktion: Verteilt eine Nachricht vom Prozess root an alle anderen Prozesse des Kommuni-katos comm. Dazu mussen alle Prozesse des Kommunikators diese Funktion mit konsiten-ten Argumenten aufrufen. Insbesondere mussen die Argumente root und comm gleichsein.

siehe auch: MPI-1.1 §4.1 und §4.4, Abschnitt 7.3.1

Page 427: [X.systems.press] Cluster Computing ||

14.7 Kollektive Kommunikation 425

MPI Gather

Syntax:

int MPI_Gather(void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, int recvcount, MPI_Datatype recvtype,int root, MPI_Comm comm)

Argumente:sendbuf: Sendepuffersendcount: Zahl der Datenelemente im Sendepuffersendtype: MPI-Datentyp der zu sendenden Datenrecvbuf: Empfangspufferrecvcount: Zahl der von jedem einzelnen Prozess zu empfangenden Datenelemente

(nur fur empfangenden Prozess relevant)recvtype: MPI-Datentyp der zu empfangenden Datenelementeroot: empfangender Rangcomm: Kommunikator

Funktion: Jeder Prozess des Kommunikators comm sendet die Daten des Sendepuffers anden Prozess root. Dieser speichert die empfangenen Daten in Rangreihenfolge im Emp-fangspuffer. Das Argument das, den Empfangspuffer spezifiziert, wird bei allen Prozessenaußer dem root-Prozess ignoriert. Der root-Prozess empfangt von jedem Prozess diegleiche Anzahl von Datenelementen. Sollen variable Datenmengen empfangen werden,so ist MPI Gatherv zu benutzen.

siehe auch: MPI-1.1 §4.1 und §4.5, Abschnitt 7.3.3

MPI Gatherv

Syntax:

int MPI_Gatherv(void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, int *recvcounts, int *displs,MPI_Datatype recvtype, int root, MPI_Comm comm)

Argumente:sendbuf: Sendepuffersendcount: Zahl der Datenelemente im Sendepuffersendtype: MPI-Datentyp der zu sendenden Datenrecvbuf: Empfangspufferrecvcounts: Feld, dessen Lange gleich der Zahl der Prozesse des Komnunikators

comm ist, das die Zahl der Elemente enthalt, die von jedem Prozess empfangen wer-den (nur fur empfangenden Prozess relevant)

displs: Feld, dessen Lange gleich der Zahl der Prozesse des Komnunikators comm ist,das fur jeden Prozess die Position, an der die von ihm emfangen Daten im Empfangs-puffer abgelegt werden, enthalt (nur fur empfangenden Prozess relevant)

recvtype: MPI-Datentyp der zu empfangenden Datenelementeroot: empfangender Rangcomm: Kommunikator

Funktion: Diese Funktion wirkt wie MPI Gather, jedoch kann hier die Zahl der Datenele-mente je Prozess variabel sein.

siehe auch: MPI-1.1 §4.1 und §4.5, Abschnitt 7.3.4

Page 428: [X.systems.press] Cluster Computing ||

426 14 Die C-Schnittstelle des MPI-Standards

MPI Allgather

Syntax:

int MPI_Allgather(void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, int recvcount, MPI_Datatype recvtype,MPI_Comm comm)

Argumente:sendbuf: Sendepuffersendcount: Zahl der Datenelemente im Sendepuffersendtype: MPI-Datentyp der zu sendenden Datenrecvbuf: Empfangspufferrecvcount: Zahl der von jedem einzelnen Prozess zu empfangenden Datenelementerecvtype: MPI-Datentyp der zu empfangenden Datenelementecomm: Kommunikator

Funktion: Diese Funktion wirkt wie MPI Gather, jedoch empfangen hier alle Prozesse dieeingesammelten Daten.

siehe auch: MPI-1.1 §4.1 und §4.7, Abschnitt 7.3.3

MPI Allgatherv

Syntax:

int MPI_Allgatherv(void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, int *recvcounts, int *displs,MPI_Datatype recvtype, MPI_Comm comm)

Argumente:sendbuf: Sendepuffersendcount: Zahl der Datenelemente im Sendepuffersendtype: MPI-Datentyp der zu sendenden Datenrecvbuf: Empfangspufferrecvcounts: Feld, dessen Lange gleich der Zahl der Prozesse des Komnunikators

comm ist, das die Zahl der Elemente enthalt, die von jedem Prozess empfangen wer-den

displs: Feld, dessen Lange gleich der Zahl der Prozesse des Komnunikators comm ist,das fur jeden Prozess die Position, an der die von ihm emfangen Daten im Empfangs-puffer abgelegt werden, enthalt

recvtype: MPI-Datentyp der zu empfangenden Datenelementecomm: Kommunikator

Funktion: Diese Funktion wirkt wie MPI Allgather, jedoch kann hier die Zahl der Daten-elemente je Prozess variabel sein.

siehe auch: MPI-1.1 §4.1 und §4.7, Abschnitt 7.3.4

Page 429: [X.systems.press] Cluster Computing ||

14.7 Kollektive Kommunikation 427

MPI Scatter

Syntax:

int MPI_Scatter(void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, int recvcount, MPI_Datatype recvtype,int root, MPI_Comm comm)

sendbuf: Sendepuffersendcount: Zahl der zu jedem Prozess zu sendenden Datenelemente (nur fur senden-

den Prozess relevant)sendtype: MPI-Datentyp der zu sendenden Datenrecvbuf: Empfangspufferrecvcount: Zahl der Datenelemente im Empfangspufferrecvtype: MPI-Datentyp der zu empfangenden Datenelementeroot: sendender Rangcomm: Kommunikator

Argumente: Diese Funktion ist das Gegensuck zu MPI Gather zum Verteilen von Daten.Der sendende Rang verteilt die Daten in sendbuff gleichmaßig auf alle Prozesse imKommunikator comm in Rangreihenfolge. Jeder Prozess erhalt genau recvcount Da-tenelemente. Sollen variable Datenmengen gesendet werden, so ist MPI Scatterv zubenutzen.

Funktion: MPI-1.1 §4.1 und §4.6, Abschnitt 7.3.3

MPI Scatterv

Syntax:

int MPI_Scatterv(void *sendbuf, int *sendcounts, int *displs,MPI_Datatype sendtype, void *recvbuf, int recvcount,MPI_Datatype recvtype, int root, MPI_Comm comm)

sendbuf: Sendepuffersendcounts: Feld, dessen Lange gleich der Zahl der Prozesse des Komnunikators

comm ist, das die Zahl der Elemente enthalt, die an jedem Prozess gesendet werden(nur fur sendenden Prozess relevant)

displs: Feld, dessen Lange gleich der Zahl der Prozesse des Komnunikators comm ist,das fur jeden Prozess die Position, an der die von ihm emfangen Daten im Empfangs-puffer abgelegt werden, enthalt (nur fur empfangenden Prozess relevant)

sendtype: MPI-Datentyp der zu sendenden Datenrecvbuf: Empfangspufferrecvcount: Zahl der Datenelemente im Empfangspufferrecvtype: MPI-Datentyp der zu empfangenden Datenelementeroot: sendender Rangcomm: Kommunikator

Argumente: Diese Funktion ist das Gegensuck zu MPI Gather zum Verteilen von Daten.Der sendende Rang verteilt die Daten in sendbuff gleichmaßig auf alle Prozesse imKommunikator comm in Rangreihenfolge. Jeder Prozess erhalt genau recvcount Da-tenelemente. Sollen variable Datenmengen gesendet werden, so ist MPI Scatterv zubenutzen.

Funktion: MPI-1.1 §4.1 und §4.6, Abschnitt 7.3.3

Page 430: [X.systems.press] Cluster Computing ||

428 14 Die C-Schnittstelle des MPI-Standards

MPI Alltoall

Syntax:

int MPI_Alltoall(void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, int recvcount, MPI_Datatype recvtype,MPI_Comm comm)

Argumente:sendbuf: Sendepuffersendcount: Zahl der Datenelemente, die an jeden Prozess gesendet werdensendtype: MPI-Datentyp der zu sendenden Datenrecvbuf: Empfangspufferrecvcount: Zahl der von jedem Prozess zu empfangenden Datenelementerecvtype: MPI-Datentyp der zu empfangenden Datenelementecomm: Kommunikator

Funktion: Diese Funktion ist eine Erweiterung von MPI Allgather, bei der jeder Prozesszu jedem Empfanger einen anderen Datenblock sendet.

siehe auch: MPI-1.1 §4.1 und MPI-1.1 §4.8, Abschnitt 7.3.3

MPI Alltoallv

Syntax:

int MPI_Alltoallv(void *sendbuf, int *sendcounts, int *sdispls,MPI_Datatype sendtype,void *recvbuf, int *recvcounts, int *rdispls,MPI_Datatype recvtype, MPI_Comm comm)

Argumente:sendbuf: Sendepuffersendcounts: Feld, dessen Lange gleich der Zahl der Prozesse des Komnunikators

comm ist, das die Zahl der Elemente enthalt, die an jedem Prozess gesendet werdensdispls: Feld, dessen Lange gleich der Zahl der Prozesse des Komnunikators comm

ist, das fur jeden Prozess die Position, an der die zu ihm gesendeten Daten im Sende-puffer liegen, enthalt

sendtype: MPI-Datentyp der zu sendenden Datenrecvbuf: Empfangspufferrecvcounts: Feld, dessen Lange gleich der Zahl der Prozesse des Komnunikators

comm ist, das die Zahl der Elemente enthalt, die von jedem Prozess empfangen wer-den

rdispls: Feld, dessen Lange gleich der Zahl der Prozesse des Komnunikators commist, das fur jeden Prozess die Position, an der die vo ihm empfangenen Daten imSendepuffer abgelegt werden, enthalt

recvtype: MPI-Datentyp der zu empfangenden Datenelementeroot: sendender Rangcomm: Kommunikator

Funktion: Diese Funktion wirkt wie MPI Alltoall, jedoch kann hier die Zahl der Daten-elemente je Prozess variabel sein.

siehe auch: MPI-1.1 §4.1 und §4.7, Abschnitt 7.3.4

Page 431: [X.systems.press] Cluster Computing ||

14.7 Kollektive Kommunikation 429

MPI Reduce

Syntax:

int MPI_Reduce(void *sendbuf, void *recvbuf, int count,MPI_Datatype datatype, MPI_Op op, int root,MPI_Comm comm)

Argumente:sendbuf: Sendepufferrecvbuf: Empfangspuffercount: Zahl der zu bearbeitenden Datenelementedatatype: MPI-Datentypop: Reduktionsoperation, siehe Tabelle 14.2root: Rang, der das Ergebnis erhaltcomm: Kommunikator

Funktion: Diese Funktion kombiniert die Elemente der Sendepuffer aller Prozesse des KOm-munikators comm durch die assiziative Operation op und speicher das Ergebnis im Emp-fangspuffer des Prozesses mit dem Rang root. Enthalten die Puffer mehr als ein Daten-elemnet, so wird die OPeation elementweise angewandt. Es konnen vordefinierte Opera-tionen aus Tabelle 14.2 oder selbst definierte Operationen verwendet werden.

siehe auch: MPI-1.1 §4.9, speziell MPI-1.1 §4.9.4-5, Abschnitt 7.3.5

MPI Allreduce

Syntax:

int MPI_Allreduce(void *sendbuf, void* recvbuf, int count,MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)

Argumente:sendbuf: Sendepufferrecvbuf: Empfangspuffercount: Zahl der zu bearbeitenden Datenelementedatatype: MPI-Datentypop: Reduktionsoperation, siehe Tabelle 14.2comm: Kommunikator

Funktion: Die Funktion MPI Allreducewirkt im Wesentlichen wie MPI Reduce, jedochkennt hier nach der Reduktion jeder Prozess deren Ergebnis.

siehe auch: MPI-1.1 §4.9.5, Abschnitt 7.3.5

MPI Reduce scatter

Syntax:

int MPI_Reduce_scatter(void *sendbuf, void *recvbuf, int *recvcounts,MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)

Argumente:sendbuf: Sendepufferrecvbuf: Empfangspuffer

Page 432: [X.systems.press] Cluster Computing ||

430 14 Die C-Schnittstelle des MPI-Standards

recvcounts: Feld, dessen Lange gleich der Zahl der Prozesse des Komnunikatorscomm ist, das die Zahl der Elemente enthalt, die nach der Reduktionsoperation anjeden Prozess gesendet werden. Die Summe aller Elemente dieses Feldes ist gleichder Anzahl der Datenelemente im Sendepuffer.

datatype: MPI-Datentypop: Reduktionsoperation, siehe Tabelle 14.2comm: Kommunikator

Funktion: Die Funktion MPI Reduce scatter ist funktionell aquivalent zu einem Aufrufvon MPI Reduce mit count= ∑irecvcounts[i] gefolgt von MPI Scatter mitsendcounts= recvcounts.

siehe auch: MPI-1.1 §4.10, Abschnitt 7.3.5

MPI Scan

Syntax:

int MPI_Scan(void *sendbuf, void *recvbuf, int count,MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)

Argumente:sendbuf: Sendepufferrecvbuf: Empfangspuffercount: Zahl der Datenelemente im Sendepufferdatatype: MPI-Datentypop: Reduktionsoperation, siehe Tabelle 14.2comm: Kommunikator

Funktion: MPI Scan fuhrt eine Prafixreduktion auf Daten, die uber die Prozesse des Kom-munikators comm verteilt sind, durch. Danach steht im Emfangspuffer des Rangs r dasErgebnis br = a0 ⊕ a1 ⊕ · · ·⊕ ar.

siehe auch: MPI-1.1 §4.10, Abschnitt 7.3.5

MPI Op create

Syntax:

int MPI_Op_create(MPI_User_function *function, int commute, MPI_Op *op)

Argumente:function: Reduktionsfunktioncommute: ungleich null falls Reduktionsfunktion kommunierend, sonst nullop: MPI-Reduktionsoperation

Funktion: Diese Funktion bindet die Funktion function an op und erzeugt dadurch eineneue MPI-Reduktionsoperation.

siehe auch: MPI-1.1 §4.9.4, Abschnitt 7.3.5

Page 433: [X.systems.press] Cluster Computing ||

14.8 Einfache Gruppen, Kontexte und Kommunikatoren 431

MPI Op free

Syntax:

int MPI_op_free(MPI_Op *op)

Argumente:op: MPI-Reduktionsoperation

Funktion: Die Bindung der MPI-Reduktionsoperation op an eine Nutzerfunktion wird aufge-hoden.

siehe auch: MPI-1.1 §4.9.4, Abschnitt 7.3.5

14.8 Einfache Gruppen, Kontexte und Kommunikatoren

MPI Group size

Syntax:

int MPI_Group_size(MPI_Group group, int *size)

Argumente:group: Gruppesize: Große

Funktion: Ermittelt die Anzahl der Prozesse in einer Gruppe.siehe auch: MPI-1.1 §5.3, speziell MPI-1.1 §5.3.1, Abschnitt 8.1

MPI Group rank

Syntax:

int MPI_Group_rank(MPI_Group group, int *rank)

Argumente:group: Grupperank: Rang

Funktion: Ermittelt den Rang eines Prozesses in einer Gruppe.siehe auch: MPI-1.1 §5.3, speziell MPI-1.1 §5.3.1, Abschnitt 8.1

MPI Group translate ranks

Syntax:

int MPI_Group_translate_ranks(MPI_Group group1, int n, int *ranks1,MPI_Group group2, int *ranks2)

Argumente:group1: erste Gruppen: Zahl der Range in beiden Gruppenranks1: Range in der erste Gruppegroup2: zweite Grupperanks2: Range in der zweiten Gruppe

Funktion: Diese Funktion liefert in ranks2 die Range der Prozesse in grp2, die in derGruppe grp1 die Range ranks1 haben. Falls in grp2 zu einem Prozess in grp1 keinkorrespondierender Rang existiert, wird MPI UNDEFINED zuruckgegeben.

siehe auch: MPI-1.1 §5.3, speziell MPI-1.1 §5.3.1, Abschnitt 8.1

Page 434: [X.systems.press] Cluster Computing ||

432 14 Die C-Schnittstelle des MPI-Standards

MPI Group compare

Syntax:

int MPI_Group_compare(MPI_Group group1, MPI_Group group2, int *result)

Argumente:group1: erste Gruppegroup2: zweite Grupperesult: Ergebnis

Funktion: Diese Funktion vergleicht zwei Gruppen und liefert in result den Wert MPIIDENT zuruck, falls die Prozesse und deren Anordnung in beiden Gruppen identisch sind.Sind die Prozesse identisch aber verschieden angeordent, ist result MPI SIMILAR,ansonsten MPI UNEQUAL.

siehe auch: MPI-1.1 §5.3, speziell MPI-1.1 §5.3.1, Abschnitt 8.1

MPI Comm group

Syntax:

int MPI_Comm_group(MPI_Comm comm, MPI_Group *group)

Argumente:comm: Kommunikatorgroup: zum Kommunikator korrespondierende Gruppe

Funktion: Liefert einen Handle auf die zum Kommunikator korrespondierende Gruppe.siehe auch: MPI-1.1 §5.3, speziell MPI-1.1 §5.3.2, Abschnitt 8.1

MPI Group union

Syntax:

int MPI_Group_union(MPI_Group group1, MPI_Group group2,MPI_Group *newgroup)

Argumente:group1: erste Gruppegroup2: zweite Gruppenewgroup: neue Gruppe

Funktion: Konstruiert aus der Vereinigungsmenge der Prozesse der ersten beiden Gruppeneine neue Gruppe.

siehe auch: MPI-1.1 §5.3, speziell MPI-1.1 §5.3.2, Abschnitt 8.1

Page 435: [X.systems.press] Cluster Computing ||

14.8 Einfache Gruppen, Kontexte und Kommunikatoren 433

MPI Group intersection

Syntax:

int MPI_Group_intersection(MPI_Group group1, MPI_Group group2,MPI_Group *newgroup)

Argumente:group1: erste Gruppegroup2: zweite Gruppenewgroup: neue Gruppe

Funktion: Konstruiert aus der Schnittmenge der Prozesse der ersten beiden Gruppen eineneue Gruppe.

siehe auch: MPI-1.1 §5.3, speziell MPI-1.1 §5.3.2, Abschnitt 8.1

MPI Group difference

Syntax:

int MPI_Group_difference(MPI_Group group1, MPI_Group group2,MPI_Group *newgroup)

Argumente:group1: erste Gruppegroup2: zweite Gruppenewgroup: neue Gruppe

Funktion: Konstruiert aus der Differenzmenge der Prozesse der ersten beiden Gruppen eineneue Gruppe.

siehe auch: MPI-1.1 §5.3, speziell MPI-1.1 §5.3.2, Abschnitt 8.1

MPI Group incl

Syntax:

int MPI_Group_incl(MPI_Group group, int n, int *ranks,MPI_Group *newgroup)

Argumente:group: alte Gruppen: Zahl der Elemente in ranksranks: Range der Prozesse, die in der neuen Gruppe enthalten sein sollennewgroup: neue Gruppe

Funktion: Konstruiert eine neue Gruppe, die aus den in ranks gelisteten Prozessen der altenGruppe besteht. Der Prozess mit dem Rang i ist der Prozess mit dem Rang rank[i] deralten Gruppe. Das Feld ranks darf keinen Rang zweimal enthalten, ist es leer (n= 0),so ist die neue Gruppe gleich MPI GROUP EMPTY. Diese Funktion kann auch dazu ver-wendet werden, die Prozesse einer Gruppe umzuordnen.

siehe auch: MPI-1.1 §5.3, speziell MPI-1.1 §5.3.2, Abschnitt 8.1

Page 436: [X.systems.press] Cluster Computing ||

434 14 Die C-Schnittstelle des MPI-Standards

MPI Group excl

Syntax:

int MPI_Group_excl(MPI_Group group, int n, int *ranks,MPI_Group *newgroup)

Argumente:group: alte Gruppen: Zahl der Elemente in ranksranks: Range der Prozesse, die nicht in der neuen Gruppe enthalten sein sollennewgroup: neue Gruppe

Funktion: Konstruiert eine neue Gruppe, die aus Prozessen der alten Gruppe besteht, aber diein ranks gelisteten Prozesse nicht enthalt. Das Feld ranks darf keinen Rang zweimalenthalten, ist es leer (n= 0), so ist die neue Gruppe gleich der alten.

siehe auch: MPI-1.1 §5.3, speziell MPI-1.1 §5.3.2, Abschnitt 8.1

MPI Group free

Syntax:

int MPI_Group_free(MPI_Group *group)

Argumente:group: Gruppe

Funktion: Loscht die Gruppe group und setzt den Handle auf MPI GROUP NULL.siehe auch: MPI-1.1 §5.3, speziell MPI-1.1 §5.3.3, Abschnitt 8.1

MPI Comm size

Syntax:

int MPI_Comm_size(MPI_Comm comm, int *size)

Argumente:comm: Kommunikatorsize: Anzahl der Prozesse

Funktion: Ermittelt die Anzahl der Prozesse in einem Kommunikator.siehe auch: MPI-1.1 §5.4.1 und §5.5.1, Abschnitt 7.1

MPI Comm rank

Syntax:

int MPI_Comm_rank(MPI_Comm comm, int *rank)

Argumente:comm: Kommunikatorrank: Rang

Funktion: Ermittelt den Rang eines Prozesses in einem Kommunikator.siehe auch: MPI-1.1 §5.4.1 und §5.5.1, Abschnitt 7.1

Page 437: [X.systems.press] Cluster Computing ||

14.8 Einfache Gruppen, Kontexte und Kommunikatoren 435

MPI Comm compare

Syntax:

int MPI_Comm_compare(MPI_Comm comm1,MPI_Comm comm2, int *result)

Argumente:comm1: erster Kommmunikatorcomm2: zweiter Kommmunikatorresult: Ergebnis

Funktion: Diese Funktion vergleicht zwei Kommmunikatoren und liefert in result denWert MPI IDENT zuruck, falls beide Kommmunikatoren sowohl bzgl. ihrer Gruppenals auch ihres Kontextes vollkommen ubereinstimmen. Unterscheiden sie sich nur imKontext, hat result den Wert MPI CONGRUENT. Sind die Prozesse in ihren Grup-pen identisch aber darin verschieden angeordent, ist result MPI SIMILAR, ansonstenMPI UNEQUAL.

siehe auch: MPI-1.1 §5.4, speziell MPI-1.1 §5.4.1

MPI Comm dup

Syntax:

int MPI_Comm_dup(MPI_Comm comm, MPI_Comm *newcomm)

Argumente:comm: Kommunikatornewcomm: neuer Kommunikator

Funktion: Erzeugt ein neuen Kommunikator als Kopie eines alten.siehe auch: MPI-1.1 §5.4, speziell MPI-1.1 §5.4.2, Abschnitt 8.1

MPI Comm create

Syntax:

int MPI_Comm_create(MPI_Comm comm, MPI_Group group, MPI_Comm *newcomm)

Argumente:comm: Kommunikatorgroup: Gruppenewcomm: neuer Kommunikator

Funktion: Erzeugt einen neuen Kommunikator, dessen Kommunikationsgruppe durch groupgegeben ist. Diese Funktion muss von allen Prozessen des Komminikators comm aufge-rufen werden, selbst wenn sie selbt nicht Bestandteil des neuen Kommunikators sind. Beidiesen ist newcomm nach dem Funktionsaufruf gleich MPI COMM NULL.

siehe auch: MPI-1.1 §5.4, speziell MPI-1.1 §5.4.2, Abschnitt 8.1

Page 438: [X.systems.press] Cluster Computing ||

436 14 Die C-Schnittstelle des MPI-Standards

MPI Comm split

Syntax:

int MPI_Comm_split(MPI_Comm comm, int color, int key,MPI_Comm *newcomm)

Argumente:comm: Kommunikatorcolor: Farbekey: Schlusselnewcomm: neuer Kommunikator

Funktion: Diese Funktion teilt die Gruppe eines Kommunkators in disjunkte Teilgruppen. DieZuordnung zu einer Gruppe erfolgt uber das Farbargument. Jede Teilgruppe enthalt alleProzesse mit der selben Farbe. Innerhalb der Teilgruppe erfolgt die Ordnung durch denSchlussel. Bei gleichen Schlusseln ist die Ordnung in der alten Gruppe maßgeblich. Furjede Teilgruppe wird ein neuer Kommunikator angelegt und zuruckgegeben. Ein Farb-wert MPI UNDEFINED fuhrt zum Kommunikator MPI COMM NULL. Negative Farbwer-te sind nicht erlaubt.

siehe auch: MPI-1.1 §5.2, speziell MPI-1.1 §5.4.2, Abschnitt 8.1

MPI Comm free

Syntax:

int MPI_Comm_free(MPI_Comm *comm)

Argumente:comm: Kommunikator

Funktion: Loscht den Kommunikator comm und setzt den Handle auf MPI COMM NULL.siehe auch: MPI-1.1 §5.4, speziell MPI-1.1 §5.4.2, Abschnitt 8.1

Verwandte Funktionen

• MPI Group range incl, MPI-1.1 §5.3, speziell MPI-1.1 §5.3.2, Abschnitt 8.1• MPI Group range excl, MPI-1.1 §5.3, speziell MPI-1.1 §5.3.2, Abschnitt 8.1• MPI Comm test inter, MPI-1.1 §5.6, speziell MPI-1.1 §5.6.1• MPI Comm remote size, MPI-1.1 §5.6, speziell MPI-1.1 §5.6.1• MPI Comm remote group, MPI-1.1 §5.6, speziell MPI-1.1 §5.6.1• MPI Intercomm create, MPI-1.1 §5.6, speziell MPI-1.1 §5.6.2• MPI Intercomm merge, MPI-1.1 §5.6, speziell MPI-1.1 §5.6.2• MPI Keyval create, MPI-1.1 §5.7, speziell MPI-1.1 §5.7.1 (in MPI-2 als deprecated

gekennzeichnet und durch die Funktion MPI Comm create keyval ersetzt)• MPI Comm create keyval, MPI-2 §8.8.1• MPI Keyval free, MPI-1.1 §5.7, speziell MPI-1.1 §5.7.1 (in MPI-2 als deprecated

gekennzeichnet und durch die Funktion MPI Comm free keyval ersetzt)• MPI Comm free keyval, MPI-2 §8.8.1• MPI Attr put, MPI-1.1 §5.7, speziell MPI-1.1 §5.7.1 (in MPI-2 als deprecated gekenn-

zeichnet und durch die Funktion MPI Comm set attr ersetzt)

Page 439: [X.systems.press] Cluster Computing ||

14.9 Kommunikatoren mit Topologie 437

• MPI Comm set attr, MPI-2 §8.8.1• MPI Attr get, MPI-1.1 §5.7, speziell MPI-1.1 §5.7.1 (in MPI-2 als deprecated gekenn-

zeichnet und durch die Funktion MPI Comm get attr ersetzt)• MPI Comm get attr, MPI-2 §8.8.1• MPI Attr delete, MPI-1.1 §5.7, speziell MPI-1.1 §5.7.1 (in MPI-2 als deprecated

gekennzeichnet und durch die Funktion MPI Comm delete attr ersetzt)• MPI Comm delete attr, MPI-2 §8.8.1

14.9 Kommunikatoren mit Topologie

MPI Cart create

Syntax:

int MPI_Cart_create(MPI_Comm comm_old, int ndims, int *dims,int *periods, int reorder, MPI_Comm *comm_cart)

Argumente:comm old: Ausgangskommunikatorndims: Anzahl der Dimensionendims: Feld der Lange ndims mit Anzahl der Prozesse in den verschiedenen Dimensio-

nenperiods: Feld der Lange ndims, das Periodizitat der Dimensionen codiertreorder: Signal zur Umnumerierungcomm cart: neuer Kommunikator

Funktion: Erstellt aus den Prozessen des Kommunikators comm old einen neuen Kommuni-kator comm cart mit kartesischer Topologie. Falls des Argument reorder ungleichnull ist, so durfen die Prozesse im neuen Kommunikator einen anderen Rang haben als imalten. Werte ungleich Null im Feld periods entsprechen Dimensionen mit periodischenRandern.

siehe auch: MPI-1 §6.4 und §6.5.1, Abschnitt 9.2.4

MPI Dims create

Syntax:

int MPI_Dims_create(int nnodes, int ndims, int *dims)

Argumente:nnodes: Anzahl der Prozessendims: Anzahl der kartesischen Dimensionendims: Feld der Lange ndims mit Anzahl der Prozesse in den verschiedenen Dimensio-

nenFunktion: Diese Hilfsfunktion erlaubt es, nnodes moglichst gleichmaßig auf ein kartesi-

sches Gitter der Dimension ndims aufzuteilen. Wenn das Feld dims vor dem Funkti-onsaufruf nur Nullen enthalt, so berechnet die Funktion, fur jeder der ndims Dimensio-nen die Anzahl der Prozesse in den jeweiligen Dimensionen. Sind bestimmte Elementedes Feldes dims positiv, so werden sie durch den Funktionsaufruf nicht verandert. Dabeimuss vor dem Funktionsaufruf

Page 440: [X.systems.press] Cluster Computing ||

438 14 Die C-Schnittstelle des MPI-Standards

ndims−1

∏i=0,dimsi �=0

dimsi

ein Vielfaches von nnodes sein. Nach einem erfolgreichen Funktionsaufruf gilt

ndims−1

∏i=0

dimsi = nnodes .

siehe auch: MPI-1 §6.4 und §6.5.2, Abschnitt 9.2.4

MPI Cart rank

Syntax:

int MPI_Cart_rank(MPI_Comm comm, int *coords, int *rank)

Argumente:comm: Kommunikatorcoords: Feld mit Koordinatenrank: Rang

Funktion: Ubersetzt die durch coords gegebenen logischen kartesischen Koordinaten ineinen Prozessrang.

siehe auch: MPI-1 §6.4 und §6.5.4, Abschnitt 9.2.4

MPI Cart coords

Syntax:

int MPI_Cart_coords(MPI_Comm comm, int rank, int maxdims, int *coords)

Argumente:comm: Kommunikatorrank: Rangmaxdims: Lange des Feldes coordscoords: Feld mit Koordinaten

Funktion: Ubersetzt einen Prozessrang in logische kartesische Koordinaten. Das Argumentmaxdims ist in der Regel mit ndims in MPI Cart create identisch.

siehe auch: MPI-1 §6.4 und §6.5.4, Abschnitt 9.2.4

Verwandte Funktionen

• MPI Cart shift, MPI-1.1 §6.5, speziell MPI-1.1 §6.5.1, Abschnitt 9.2.4• MPI Cart sub, MPI-1.1 §6.5, speziell MPI-1.1 §6.5.5, Abschnitt 9.2.4• MPI Cartdim get, MPI-1.1 §6.5, speziell MPI-1.1 §6.5.4, Abschnitt 9.2.4• MPI Cart get, MPI-1.1 §6.5, speziell MPI-1.1 §6.5.4, Abschnitt 9.2.4• MPI Cart map, MPI-1.1 §6.5, speziell MPI-1.1 §6.5.7, Abschnitt 9.2.4• MPI Graph create, MPI-1.1 §6.5, speziell MPI-1.1 §6.5.3• MPI Graph get, MPI-1.1 §6.5, speziell MPI-1.1 §6.5.4• MPI Graph neighbors count, MPI-1.1 §6.5, speziell MPI-1.1 §6.5.4• MPI Graph neighbors, MPI-1.1 §6.5, speziell MPI-1.1 §6.5.4• MPI Graph map, MPI-1.1 §6.5, speziell MPI-1.1 §6.5.7• MPI Graphdims get, MPI-1.1 §6.5, speziell MPI-1.1 §6.5.4• MPI Topo test, MPI-1.1 §6.5, speziell MPI-1.1 §6.5.4

Page 441: [X.systems.press] Cluster Computing ||

15

Argumente aus der Kommandozeile einlesen

In the Beginning . . . was the Command Line

Neal Stephenson

Unter Unix ist es ublich, das Verhalten von Programmen uber Optionen und Argu-mente aus der Kommandozeile zu steuern. Denken Sie nur an die Optionen fur IhrenCompiler oder den Befehl ls. Diesen Mechanismus der Kommandozeilenargumentekonnen Sie auch fur Ihre eigenen C-Programme nutzen.

Die C-Laufzeitumgebung zerlegt die Kommandozeile in eine Folge von Worten,die durch Leerzeichen voneinander getrennt sind. Die Liste dieser Worte wird dermain-Routine des gestarteten C-Programms als Parameter ubergeben:

int main(int argc, char *argv[])

Der erste Parameter (argc fur argument count) enthalt die Anzahl der Komman-dozeilenargumente, der zweite Parameter (argv fur argument vector) eine Listevon Verweisen auf die Argumente selbst. Beim Aufruf eines Programms namenssimulate mit Parametern,

bauke@newton:˜$ simulate 1000 1.4 test

hat argc den Wert 4 und argv[0] bis argv[3] sind Pointer auf nullterminierteZeichenketten mit dem Inhalt ”simulate“, ”1000“, ”1.4“ und ”test“. Beachten Sie,dass der Name des Programms selbst als Argument gilt und in argv[0] ubergebenwird.

Da argv alle Argumente als Strings liefert, mussen numerische Werte indouble oder int ungewandelt werden. Dazu stellt die C-Sandardbibliothek eini-ge nutzliche Funktionen bereit. Die Routinen

• double atof(const char *s)• int atoi(const char *s)• long atol(const char *s)

wandeln den String s in double, int bzw. long um. In der Headerdateistdlib.h sind noch weitere Umwandlungsfunktionen definiert [81], aber in denmeisten Fallen reichen diese drei Funktionen aus. Mehr Moglichkeiten zur Umwand-lung bietet die Funktion sscanf.

Page 442: [X.systems.press] Cluster Computing ||

440 15 Argumente aus der Kommandozeile einlesen

Listing 15.1. Das Programm add.c berechnet die Summe seiner Argumente.

#include <stdio.h>#include <stdlib.h>

int main(int argc, char *argv[]) {5 double sum;

int i;

sum=0.0;for (i=1; i<argc; ++i)

10 sum+=atof(argv[i]);printf(”sum i s %g\n ”, sum);return EXIT_SUCCESS;

}

Im Programm add.c in Listing 15.1 haben wir diese Umwandlungsfunktionenbenutzt. Dieses Beispielprogramm interpretiert seine Argumente als Fließkommazah-len und gibt deren Summe aus.

Der einfache Mechanismus mit argc und argv funktioniert problemlos, solan-ge alle Argumente vollig aquivalent sind, wie in unserem Summationsprogramm.Meistens hat ein Programm jedoch unterschiedliche Parameter. Nehmen wir als Bei-spiel ein Programm, das beim Start folgende Parameter erwartet:

• Systemgroße: N (Typ long)• simulierte Zeitschritte: T (Typ long)• Flag fur den Umfang der Ausgabe: v (fur verbose, Typ char)

Naturlich kann man festlegen, dass die Argumente in der Kommandozeile immerin dieser Reihenfolge anzugeben sind. Bei drei Argumenten kann sich der Nutzerdas vielleicht noch merken, aber selbst bei wenigen Argumenten ist diese Losungfehlertrachtig. Das Programm hat in der Regel keine Moglichkeit, Vertauschungenetwa von N und T festzustellen. Außerdem ware es komfortabel, wenn es fur alleParameter voreingestellte Werte gabe (etwa fur v), und auf der Kommandozeile nurnoch die Parameter spezifiziert werden mussten, die davon abweichende Werte habensollen. Die Losung dieses Problems wird uns von den Unix-Kommandos vorgemacht.Sie verwenden argumentbehaftete Optionen. Bei unserem Programm (nennen wir esargs) sahe das dann so aus:

bauke@newton:˜$ args -T 5000 -v -N 300

Die Optionen beginnen mit einem - gefolgt von einem Buchstaben. Die Optionen-T und -N haben jeweils ein Argument. Mit diesem Aufruf wird dem Programmargs mitgeteilt, dass N = 300 und T = 5000 sind. Außerdem verlangen wir mit derOption -v eine ausfuhrliche Ausgabe. Das besondere an Optionen ist, dass derenReihenfolge egal ist. Außerdem kann jede Option auch weggelassen werden, wasnaturlich nur sinnvoll ist, wenn das Programm fur den entsprechenden Parametereinen Default-Wert annimmt. In argv kommt die obige Kommandozeile fein sauber-lich zerlegt an, d. h. in sechs Strings ”args“, ”-T“, . . . , ”300“. Es ist relativ muhsam,

Page 443: [X.systems.press] Cluster Computing ||

15 Argumente aus der Kommandozeile einlesen 441

Listing 15.2. Das Programm args.c wertet Kommadozeilenargumente mit getopt aus.

#include <stdio.h>#include <stdlib.h>#include <unistd.h> / * g e t o p t * /

5 void print_help(const char *name, FILE *fp) {fprintf(fp, ” Verwendung : %s [−T Z e i t ] [−N Große ] [−v ] [−h ]\ n ”, name);

}

int main(int argc, char *argv[]) {10 long T, N;

char verbose;int c;

/ * S t a n d a r d w e r t e * /15 T=1000;

N=200;verbose=0;/ * Kommandozeile a u s w e r t e n * /while ((c=getopt(argc, argv, ”T :N: vh ”))!=-1) {

20 switch (c) {case ’T ’:

T=atol(optarg);break;

case ’N’:25 N=atol(optarg);

break;case ’ v ’:

verbose=1;break;

30 case ’ h ’:print_help(argv[0], stdout);exit(EXIT_SUCCESS);

default:print_help(argv[0], stderr);

35 exit(EXIT_FAILURE);}

}printf(” P a r a m e t e r :\ n T = %l d\n N = %l d\n ”, T, N);printf(” Ausgaben s i n d %s g e s c h a l t e t .\ n ”, (verbose ? ” e i n ” : ” aus ”));

40 return EXIT_SUCCESS;}

daraus die richtigen Informationen zu extrahieren, aber das mussen Sie nicht selbermachen.

Die meisten C-Compiler unter POSIX-konformen Betriebssystemen stellen Ih-nen fur diesen Zweck in der Headerdatei unistd.h die Funktion

int getopt(int argc, char *const argv[], const char *optstring)

zur Verfugung. Die ersten beiden Argumente der Funktion getopt entsprechenden Argumenten von main. Im dritten Argument werden die Optionen spezifiziert:optstring enthalt fur jede Option das entsprechende Zeichen. Auf Optionen,die ein Argument haben, folgt dabei ein Doppelpunkt. In unserem Beispiel wareoptstring also gleich ”vT:N:“. Bei jedem Aufruf liefert getopt eine gultige

Page 444: [X.systems.press] Cluster Computing ||

442 15 Argumente aus der Kommandozeile einlesen

Option aus der Kommandozeile, ein Fragezeichen, ein Doppelpunkt oder −1 zuruck.Ein Fragezeichen bedeutet, dass der Nutzer eine Option angegeben hat, die nicht inoptstring spezifiziert wurde. Dass der Nutzer vergessen hat, das Argument fureine argumentbehaftete Option anzugeben, erkennen Sie dies am Doppelpunkt. BeiOptionen mit Argument enthalt die externe Variable optarg dieses Argument.

Listing 15.1 zeigt die typische Benutzung von getopt in unserem Beispielpro-gramm args.c. Neben den bereits diskutierten Optionen ”T:N:v“ erlaubt args.cauch die Option -h. Durch diese Option wird das Programm veranlasst, einen kurzenHilfe-Text mit allen erlaubten Optionen auszugeben. Das ist sehr nutzlich, besonderswenn Ihr Programm viele Optionen hat und wenn Sie es langere Zeit nicht benutzthaben.

Findet getopt eine Option in der Kommandozeile, die nicht in optstringangegeben wurde, gibt das Programm eine Fehlermeldung auf die Standardfehler-ausgabe aus. Das gleiche passiert, wenn eine Option ein Argument benotigt aber aufder Kommandozeile nicht angegeben wurde. Die Ausgabe der dierekt von getopterzeugten Fehlermeldungen kann durch setzen der externen Variable opterr auf 0abschalten.

Wie sich getopt bei Kommandozeilen verhalt, die sowohl Optionen als auchgewohnliche Argumente enthalten, hangt von der speziellen Implementierung ab.Spatestens hier sollten Sie einen Blick in die entsprechende Manpage werfen. Dortfinden Sie auch Informationen zur Funktion get opt long. Sie verarbeitet Optio-nen, die aus mehr als einem Zeichen bestehen.

Page 445: [X.systems.press] Cluster Computing ||

Literaturverzeichnis

1. K. Agouros: Zahlen Meister! Linux Magazin Februar (2002) Seiten 54–592. G.M. Amdahl: The validity of the single processor approach to achieving large scale

computing capabilities. In: AFIPS conference proceedings, Spring Joint Computing Con-ference, vol 30 (1967) Seiten 483–485

3. M. Amersdorfer. Using openldap on debian woody to serve linux and samba users.http://aqua.subnet.at/∼max/ldap/.

4. AutoYaST. http://www.suse.de/∼nashif/autoinstall/.5. J. Baker, B. Brugmann, M. Campanelli, C. Lousto, R. Takahashi: Plunge Waveforms

from Inspiralling Binary Black Holes. Phys. Rev. Lett. 97 (2001) Seite 1211036. L.A. Barroso, J. Dean, U. Holzle, Google: Web Search for a Planet: The Google Cluster

Architecture. IEEE Micro 232 (2003) Seiten 22–287. H. Bauke, S. Mertens. Cluster Computing: die Webseite. http://www.clustercomputing.

de.8. Benchweb. http://www.netlib.org/benchweb.9. Beowulf-Artikel bei Wikipedia. http://de.wikipedia.org/wiki/Beowulf.

10. Beowulf-Projekt. http://www.beowulf.org.11. Berkeley Lab Checkpoint/Restart (BLCR). http://ftg.lbl.gov/checkpoint.12. Boost.org. http://www.boost.org.13. Bootable Cluster CD. http://bccd.cs.uni.edu.14. BpBatch. http://www.bpbatch.org.15. C3. http://www.csm.ornl.gov/torc/C3/.16. Champion/pro. http://www.mpi-softtech.com/products/cluster/championpro/.17. M. Chetty, R. Buyya: Weaving computational grids: How analogous are they with elec-

trical grids? Computing in Science and Engineering (2002) Seiten 61–7118. CHPOX – CHeckPOinting for linuX. http://www.cluster.kiev.ua/tasks/chpx eng.html.19. Ckpt – A process checkpoint library. http://www.cs.wisc.edu/∼zandy/ckpt/.20. Clebsch Diagonal Cubic. http://mathworld.wolfram.com/ClebschDiagonalCubic.html.21. Condor. http://www.cs.wisc.edu/condor/.22. c’t-Puzzle. http://www.heise.de/ct/puzzle/.23. DCF77. http://www.dcf77.de.24. DE-NIC. http://www.de-nic.de.25. Debian Cluster Components. http://www.irb.hr/en/cir/projects/dcc/.26. Deutscher Wetterdienst. Numerische wettervorhersage. http://www.dwd.de/de/FundE/

Analyse/Modellierung/Modellierung.htm.

Page 446: [X.systems.press] Cluster Computing ||

444 Literaturverzeichnis

27. A.K. Dewdney: Computer Recreations. Scientific American 8 (1988)28. Distributed Shell. http://www.netfort.gr.jp/∼dancer/software/dsh.html, http://dsh.

sourceforge.net.29. Dolphin Interconnect Solutions. http://www.dolphinics.com.30. J. Dongarra. Frequently Asked Questions on the Linpack Benchmark and Top500. http:

//www.netlib.org/utk/people/JackDongarra/faq-linpack.html.31. J. Dongarra: Performance of Various Computers Using Standard Linear Equations Soft-

ware. Technical Report, Computer Science Department, University of Tennessee (2001)32. K. Dowd, C.R. Severance: High Performance Computing, 2. Aufl. (O’Reilly & Associa-

tes, Sebastopol 1998)33. Effective I/O Bandwidth Benchmark. http://www.hlrs.de/organization/par/services/

models/mpi/b eff io/.34. Einstein@home: discovering gravitational waves by distributed computing. http://

physics2005.org/events/einsteinathome/.35. R. Engler, T. Wenzel. VIA-RPI fur LAM-MPI. http://www.tu-chemnitz.de/informatik/

HomePages/RA/projects/cocgrid/viarpi/.36. Etherboot. http://etherboot.sourceforge.net.37. R. Ferri: Remote Linux Explained. Linux Journal 93 (2002)38. R.P. Feynman, R.B. Leighton, M. Sands: Feynman Vorlesungen uber Physik Mechanik,

Strahlung und Warme, vol 1 (Oldenbourg, 2001)39. FFTW (Fastest Fourier Transform in the West). http://www.fftw.org.40. B. Finkbeiner: Knoten-Kommunikation. Linux Magazin Sonderheft 2 (2004) Seiten 96–

10041. M. Flynn: Very high speed computing systems. Proc. IEEE 54 (1966) Seiten 1901–190942. Folding@home: Predicting proteine structure by distributed computing. http://folding.

stanford.edu.43. I. Foster, C. Kesselman: The Grid 2 Blueprint for a New Computing Infrastructure (Mor-

gan Kaufmann, 2003)44. Fully Automatic Installation. http://www.informatik.uni-koeln.de/fai/.45. Ganglia. http://ganglia.info/.46. P.H. Ganten, W. Alex: Debian GNU/Linux, 2. Aufl. (Springer, 2004)47. R.A. van de Geijn: Using PLAPACK (MIT Press, 1997)48. General Parallel File System. http://www-1.ibm.com/servers/eserver/clusters/software/

gpfs.html.49. J.E. Gentle, W. Haerdle, Y. Mori, Editoren. Handbook of Computational Statistics,,

chapter Random Number Generation, Seiten 35–70. Springer, 2004.50. GIMPS: the giant internet Mersenne prime search. http://www.mersenne.org.51. Globus Toolkit. http://www.globus.org/toolkit/.52. GNU Debugger. http://www.gnu.org/software/gdb/.53. H. de Goede. Root over NFS clients & server Howto. http://www.tldp.org/HOWTO/

Diskless-root-NFS-HOWTO.html.54. G. Gousios. Root over NFS – Another Approach. http://www.tldp.org/HOWTO/

Diskless-root-NFS-other-HOWTO.html.55. A.Y. Grama, A. Gupta, V. Kumar: Isoefficiency: Measuring the Scalability of Parallel

Algorithms and Architectures. IEEE Parallel & Distributed Technology 13 (1993) Seiten12–21

56. Grind Engie. http://grindengine.sunsource.net.57. W. Gropp, E. Lusk, A. Skjellum: Using MPI (The MIT Press, Cambridge, Massachusetts

1996)

Page 447: [X.systems.press] Cluster Computing ||

Literaturverzeichnis 445

58. W. Gropp, E. Lusk, T. Sterling: Beowulf Cluster Computing with Linux (MIT Press,2003)

59. W. Gropp, S. Otto, S. Huss-Lederman et al: MPI – The Complete Reference (The MITPress, Cambridge, Massachusetts 1998)

60. J.L. Gustafson: Reevaluating Amdahl’s Law. Comm. ACM 315 (1988) Seiten 532–53361. J.L. Gustafson, G.R. Montry, R.E. Brenner: Development of parallel methods for a 1024-

processor hypercube. SIAM J. Sci. Stat. Comput. 94 (1988) Seiten 609–63862. R.H. Hardin, N.J.A. Sloane, W.D. Smith. Minimal energy arrangements of points on a

sphere. http://www.research.att.com/∼njas/electrons/index.html.63. Hardware-Monitoring fur Linux. http://secure.netroedge.com/∼lm78/.64. W.W. Hargrove, F.M. Hoffman, T. Sterling: Der selbst gebastelte Supercomputer. Spek-

trum der Wissenschaft 3 (2002) Seiten 88–9665. B. Hayes: Digital Diffraction. American Scientist 843 (1996) Seiten 210–21466. B. Hayes: Collective Wisdom. American Scientist 862 (1998) Seiten 118–12267. HPC Challenge. http://icl.cs.utk.edu/hpcc.68. HPL – A Portable Implementation of the High-Performance Linpack Benchmark for

Distributed-Memory Computers. http://www.netlib.org/benchmark/hpl/.69. C. Hunt: TCP/IP Netzwerk-Administration, 2. Aufl. (O’Reilly, 1998)70. InfiniBand Trade Association. http://www.infinibandta.org.71. Intel Cluster Toolkit. http://www.intel.com/software/products/cluster/clustertoolkit/.72. Intel MPI Library. http://www.intel.com/software/products/cluster/mpi/.73. InterMezzo. http://www.inter-mezzo.org.74. ICS. http://www.isc.org.75. P.L. Jack J. Dongarra, A. Petitet: The LINPACK Benchmark: past, present and future.

Concurrency and Computation: Practice and Experience 159 (2003) Seiten 803–82076. B. Jeunhomme. Network Boot and Exotic Root HOWTO. http://www.tldp.org/

HOWTO/Network-boot-HOWTO.77. A.H. Karp, H.P. Flatt: Measuring Parallel Processor Performance. Comm. ACM 335

(1990) Seiten 539–54378. W.J. Kaufmann, L.L. Smarr: Supercomputing and the Transformation of Science (Scien-

tific American Library, 1993)79. kernel.org. http://www.kernel.org.80. B.W. Kernighan, R. Pike: Programmierpraxis. Prinzipien zur effizienten Programmie-

rung (Addison-Wesley, Munchen 2000)81. B.W. Kernighan, D.M. Ritchie: Programmieren in C (Carl Hanser Verlag, Munchen

1990)82. W. Kinzel, G. Reents: Computational Physics Programming of Physical Problems Using

Mathematica and C (Springer, 1998)83. O. Kirch, T. Dawson: he Linux Network Administrator’s Guide (O’Reilly, 2000)84. Knoppix. http://www.knopper.net/knoppix.85. D.E. Knuth: The Art of Computer Programming, vol 2: Seminumerical Algorithms (Ad-

dison-Wesley Publishing Company, Reading, Massachusetts 1997)86. D.E. Knuth. Selected Papers on Analysis of Algorithms, chapter Estimating the Efficency

of Backtrack Programs. Center for the Study of Language and Information, 2000.87. M. Kofler: Linux Installation, Konfiguration, Anwendung, 7 Aufl. (Addison-Wesley,

2004)88. E. Korpela, D. Werthimer, D. Anderson, J. Cobb, M. Lebofsky: SETI@home – Massive-

ly Distributed Computing for SETI. Computing in Science and Engineering 31 (2001)Seiten 78–83

Page 448: [X.systems.press] Cluster Computing ||

446 Literaturverzeichnis

89. LAM/MPI. http://www.lam-mpi.org.90. C. Larson, R. Hanson, D. Kincaid, F. Krogh: Basic linear algebra subprograms for

Fortran usage. ACM Trans. Math. Softw. 53 (1979) Seiten 308–32391. LCFG. http://www.lcfg.org.92. LEDA. http://www.algorithmic-solutions.com/leda.htm.93. A. Lewis. LVM HOWTO. http://www.tldp.org/HOWTO/LVM-HOWTO/.94. Libckpt – A Portable Checkpointer for Unix. http://www.cs.utk.edu/∼plank/plank/www/

libckpt.html.95. The LINPACK benchmark. http://www.netlib.org/benchmark/.96. Linux InfiniBand Project. http://infiniband.sourceforge.net.97. Linux Terminal Server Project. http://www.ltsp.org.98. Lustre. http://www.lustre.org.99. B. Marshall. System Authentication using LDAP. http://quark.humbug.org.au/

publications/ldap/system auth/sage-au/system auth.html.100. Maui. http://supercluster.org/maui.101. K. Mehlhorn, S. Naher: Leda: A Platform for Combinatorial and Geometric Computing

(Cambridge University Press, 1999)102. Message Passing Interface Forum. MPI: A message-passing interface standard. http:

//www.mpi-forum.org, June 1995.103. Message Passing Interface Forum. MPI-2: Extensions to the message-pasing interface.

http://www.mpi-forum.org, July 1997.104. Motherboard monitor. http://mbm.livewiredev.com.105. MPI-Plugin fur KDevelop. http://sourceforge.net/projects/mpiplugin.106. MPI-POV. http://www.verrall.demon.co.uk/mpipov/.107. MPICH. http://www-unix.mcs.anl.gov/mpi/mpich/, http://www-unix.mcs.anl.gov/mpi/

mpich2/.108. InfiniBand Unterstutzung fur MPICH. http://www.tu-chemnitz.de/informatik/RA/

cocgrid/Infiniband/pmwiki.php.109. MPI/Pro. http://www.mpi-softtech.com/products/cluster/mpi pro.110. Myricom. http://www.myri.com.111. NAS Parallel Benchmarks. http://www.nas.nasa.gov/Software/NPB/.112. Netboot. http://netboot.sourceforge.net.113. NetPIPE. http://www.scl.ameslab.gov/netpipe/.114. NFS fur Linux. http://nfs.sourceforge.net.115. NFS-Swap. http://nfs-swap.dot-heine.de.116. B. Nichols, D. Buttlar, J.P. Farrell: Pthreads Programming (O’Reilly & Associates, Se-

bastopol 1996)117. NIS fur Linux. http://www.linux-nis.org.118. NTP. http://www.ntp.org.119. OOMPI. http://www.osl.iu.edu/research/oompi/.120. Open InfiniBand Alliance. http://www.openib.org.121. Open MPI. http://www.open-mpi.org.122. OpenGFS. http://opengfs.sourceforge.net.123. OpenMP. http://www.openmp.org.124. OpenPBS. http://www.openpbs.org.125. OpenSSH. http://www.openssh.com.126. OSCAR. http://oscar.openclustergroup.org.127. HA-OSCAR. http://xcr.cenit.latech.edu/ha-oscar/.128. Thin-OSCAR. http://thin-oscar.ccs.usherbrooke.ca.

Page 449: [X.systems.press] Cluster Computing ||

Literaturverzeichnis 447

129. J. Østergaard, E. Bueso. The Software-RAID HOWTO. http://www.tldp.org/HOWTO/Software-RAID-HOWTO.html.

130. P.S. Pacheco: Parallel Programming with MPI (Morgan Kaufmann Publishers, Inc., SanFrancisco, California 1997)

131. Parallel Virtual File System. http://www.pvfs.org.132. ParallelKnoppix. http://pareto.uab.es/mcreel/ParallelKnoppix/.133. K. Pearson. Internet-based distributed computing projects. http://www.aspenleaf.com/

distributed.134. L. Peng, L.K. Ng. Checkpointing and Berkeley Lab Checkpoint/Restart. http://

gridengine.sunsource.net/howto/APSTC-TB-2004-005.pdf.135. POV-Ray. http://www.povray.org.136. W.H. Press, S.A. Teukolsky, W.T. Vetterling, B.P. Flannery: Numerical Recipes in C, 2

Aufl. (Cambridge University Press, 1992)137. PVM. http://www.csm.ornl.gov/pvm/pvm home.html.138. Quadrics. http://www.quadrics.com.139. T. Rauber, G. Runger: Parallele und verteilte Programmierung (Springer-Verlag, Berlin

Heidelberg New York 2000)140. J. Rech: Ethernet: Technologien und Protokolle fur die Computervernetzung (Heise,

Hannover 2002)141. Rechenkraft. http://www.rechenkraft.de.142. RFC. http://www.faqs.org/rfcs/.143. Rocks Cluster Distribution. http://www.rocksclusters.org.144. http://www-unix.mcs.anl.gov/romio/.145. R. Russell. Linux 2.4 NAT HOWTO. http://www.netfilter.org/documentation/HOWTO/

NAT-HOWTO.html.146. E.B. Saff, J.K. Arno B. Distributing many points on a sphere. Mathematical Intelli-

gencer 191 (1997) Seiten 5–11147. Scali. http://www.scali.com.148. SCore. http://www.pccluster.org.149. SETI@home Projekt. http://setiathome.ssl.berkeley.edu/index.html.150. J.G. Siek, L.-Q. Lee, A. Lumsdaine: The Boost Graph Library (Addison-Wesley, 2002)151. H.D. Simon. The future of scientific computing. Keynote presentation at the 16th Inter-

national Supercomputer Conference, Heidelberg, 2001.152. SKaMPI. http://liinwww.ira.uka.de/∼skampi/.153. J.D. Sloan: High Performance Linux Clusters with OSCAR, Rocks, openMoix, and MPI

(O’Reilly, 2005)154. The Standard Performance Evaluation Corporation. http://www.spec.org.155. SPEC MPI2005. http://www.spec.org/mpi/.156. R.M. Stallman, R.H. Pesch, S. Shebs, other: Debugging With GDB: The GNU Source-

Level Debugger (Free Software Foundation, 2002)157. T. Sterling: Auf dem Weg zum Billiarden-Rechner. Spektrum der Wissenschaft 1 (2002)

Seiten 78–96158. T. Sterling, D. Savarese, D.J. Becker et al: BEOWULF: A Parallel Workstation for Scien-

tific Computation. In: Proceedings of the 24th International Conference on Parallel Pro-cessing (1995) Seiten I:11–14

159. H. Stern, M. Eisler, R. Labiaga: Managing NFS and NIS Help for Unix System Adminis-trators (O´Reilly, 2001)

160. W.R. Stevens: TCP/IP Illustrated, vol 1 (pAW, pAWadr 1994)161. Q.F. Stout. What is parallel computing? a not too serious explanation. http://www.eecs.

umich.edu/∼qstout/parallel.html.

Page 450: [X.systems.press] Cluster Computing ||

448 Literaturverzeichnis

162. syslinux / pxelinux. http://syslinux.zytor.com.163. System Installation Suite. http://sisuite.org.164. SystemImager. http://www.systemimager.org.165. Tina. http://tina.nat.uni-magdeburg.de.166. Top 500. http://www.top500.org.167. TORQUE. http://clusterresources.com/products/torque/.168. TotalView. http://www.etnus.com/TotalView/.169. Trace Analyzer. http://www.intel.com/software/products/cluster/tanalyzer/.170. T. Ungerer: Parallelrechner und parallele Programmierung (Spektrum Akademischer

Verlag, Heidelberg Berlin 1997)171. C. Vilsbeck. So funktioniert DRAM. http://www.tecchannel.de/hardware/173.172. H. Weiß, H. Domgorgen, M. Grimm, S. Steiger: Ausgeschlafen NT-Workstations als

Feierabend-Cluster. c’t 22 (2000) Seiten 246–251173. K.G. Wilson: Grand Challenges to Computational Science. Future Generation Computer

Systems 5 (1989) Seite 171174. C. Wolf: Doppelt reißfest. Linux Magazin (2004) Seiten 68–71175. V. Zweije. Remote X Apps mini-HOWTO. http://www.tldp.org/HOWTO/

Remote-X-Apps.html.

Page 451: [X.systems.press] Cluster Computing ||

Sachverzeichnis

Aufrechte Seitenangaben im Sachverzeichnis verweisen auf den Hauptteil des Buches, kursiveSeitenangaben hinter Funktionen und Konstanten des MPI-Standards beziehen sich auf denAnhang 14, in dem große Teile der C-Schnittstelle des MPI-Standards dokumentiert werden.

$DISPLAY, 319–321$GMON OUT PREFIX, 323$LAMRANK, 316, 31719-Zoll-Format, 67

Advanced Regional Prediction System, 341Advanced Technology Attachments, 63aliasing, 179, 187Amdahls Gesetz, 10–13, 16, 19Applikations-Schema, 150APPSPACK, siehe Asynchronous Parallel

Pattern Search, 346–351ARPS, siehe Advanced Regional Prediction

Systemasynchrone Kommunikation, 222Asynchronous Parallel Pattern Search, 344ATA, siehe Advanced Technology

AttachmentsATLAS, siehe Automatically Tuned Linear

Algebra SoftwareAutomatically Tuned Linear Algebra

Software, 337AutoYaST, 104

Backfill, 152backplane, 68backplane bandwidth, 55Backtracking, 280–281Bandbreite, 24, 59, 95, 196

bidirektionale 388bandwidth, siehe BandbreiteBank-Queue-Schema, siehe Master-Worker-

Schema

Basic Linear Algebra Subprograms, 335,372, 379

Batch-System, 31, 76, 151–160Funktionsweise 151–152

Becker, Donald J., 27Benchmarks, 8–10, 367–393Beowulf, 27–28, 35Berkeley Lab Checkpoint/Restart, 397,

401–408Berkeley-r-Kommandos, 112–113big-endian, 221bisection bandwidth, siehe Bisektionsband-

breiteBisektionsbandbreite, 26, 56, 57, 390BLAS, siehe Basic Linear Algebra

SubprogramsBLCR, siehe Berkeley Lab Checkpoint/Rest-

artblockierende Kommunikation, 189–194blockzykliche Verteilung, 369, 370Bonding-Interface, 91, 126BOOTP, 141Bootschema, 147BpBatch, 130Broadcast, 55Broadcast-Adresse, 79Bus, 26butterfly, 188

C+, 216–217Cache, 7, 62, 73cache misses, 7Cache-Koharenz, 21, 22Cactus, 339

Page 452: [X.systems.press] Cluster Computing ||

450 Sachverzeichnis

CAM, siehe Community Atmosphere ModelChaMPIon/Pro, 144, 214channel bonding, 30, 86, 125–128, 141checkpoint, 393Checkpointing, 153–154, 393–408

asynchrones 394synchrones 394

Chombo, 340CHPOX, 396Ckpt, 395, 397–401Classless Inter-Domain Routing, 78CLAWPACK, siehe Conservation LAWs

PACKageClient-Server-Modell, 218Cluster Command and Control, 141Cluster-Management-Systeme, 76, 160–164Clusterdateisysteme, 64–65Community Atmosphere Model, 341Condor, 155–156, 396Conservation LAWs PACKage, 340Crossbar, 22

Datagramme, 78Dateihandle, 246Dateisicht, 245, 246Dateityp, 246Datenkollision, 26Datenparallelitat, 37–39ddd, 321deadlock, 197–201, 296deadlocks, 324Debugger, 317–321DHCP, siehe Dynamic Host Configuration

ProtocolDifferentialgleichungen, 339–340displacement, 235, 245Displaynummer, 319Distanzadresse, 245distributed computing, siehe verteiltes

Rechnendistributed memory, siehe Speicher, verteilterDistributed Parallel Multipole Tree

Algorithm, 342Distributed Shell, 116DNS, siehe domain network servicedomain decomposition, siehe Gebietszerle-

gungdomain network service, 79, 94dot quad notation, 78

DPMTA, siehe Distributed ParallelMultipole Tree Algorithm

Dynamic Host Configuration Protocol,121–125

dynamische Lastverteilung, 205

Effective I/O Bandwidth Benchmark, 392Effizienz, 12, 17, 382, 383

konstante 17EGO, 342embarrassingly parallel, 259Etherboot, 130Ethernet, 24, 26, 54, 57–58

switched 27Tuning 94–96

ethtool, 95Etikett, 171Exclusive, 153Ext3, 83extend, 236eXtensible multi-dimensional Simulator, 340external32, 248

FAI, 104Fairness, 203Fairshare, 152Fast Ethernet, siehe EthernetFastest Fourier Transform in the West, 343fat-tree-Topologie, 56Fehlerbehandlung, 230–234

MPI-2 256parallele Ein- und Ausgabe 253–256

Fehlercode, 168, 230FFTW, siehe Fastest Fourier Transform in

the West, 351–356First-Come-First-Served, 152Fließkommaleistung, 5Fließkommaleistung, 53, 368Flops, 5Flynn’sche Klassifikation, 34FORTRAN, 37, 217

MPI 215–216Fortschrittsgarantie, 208Fouriertransformation, 343, 351front end node, siehe Knoten, Server-KnotenFunktionsparallelitat, 39

GADGET, 343Ganglia, 164

Page 453: [X.systems.press] Cluster Computing ||

Sachverzeichnis 451

Gateway, 79, 92, 119Gebietszerlegung, 181, 290–291Geisterpunkte, 290General Parallel File System, 65Gerris, 341ghost points, siehe GeisterpunkteGigabit Ethernet, siehe EthernetGlobal Arrays Toolkit, 335GNU Scientific Library, 334golden client, 97GPFS, siehe General Parallel File Systemgprof, 322Grand Challenges, 18Granularitat, 13–15, 186Grid-Computing, 32–34GSL, siehe GNU Scientific LibraryGustafsons Gesetz, 16

Halbduplexmodus, 54Handle, 224Hardware-Monitoring, 66–67, 69, 84–90HDF5, siehe Hierarchical Data Format 5head node, siehe Knoten, Server-KnotenHierarchical Data Format 5, 335high availability computing, 31high performance computing, 31high throughput computing, 31High-Performance BLAS, 336High-Performance Linpack, 9High-Performance LINPACK, 367Highly-Parallel LINPACK, 367–385Hostnummer, 78HPC Challenge, 19, 392HPC-Linpack, siehe LinpackHPL, siehe Highly-Parallel LINPACKHydrodynamik, 341Hyperkubus, 24, 309hypre, 338

ICMP echo request, 92ifconfig, 91ifenslave, 125, 126image server, 97InfiniBand, 60inharent parallel, 259Init-Skript, 89

DHCP-Server 124Hardware-Monitoring 89Network Address Translation 121

Network Information Service 111Network Time Protocol 117

Intel MPI BenchmarksPingPing-Test 388

Intel MPI Benchmarks, 385–392PingPong-Test 388

Intel MPI Library, 145Interconnect, 21interface, 54, 78, 91

Name 91, 141InterMezzo, 65internal, 248Internet-Adresse, 78IP-Adresse, siehe Internet-Adresse, 91IP-Masquerading, siehe Network Address

TranslationIP-Router, siehe GatewayIsoeffizienz-Funktion, 17, 18

JFS, 83Job, 151Job-Migration, 153Joker, 172, 205Journaling-Dateisysteme, 83, 140jumbo frames, 96

Kornigkeit, siehe GranularitatKuhlung, 67Karp-Flatt-Metrik, 16, 186kartesisches Gitter, 24KDevelop, 332Kickstart, 104Knoten, 23, 51

compute node 51diskless node 53, 65–66, 86, 129–140Ersatzknoten 73Knoten-Hardware 53Server-Knoten 52

Kommandozeilenargumente, 168, 439–442Kommunikation

einseitige 219–220kollektive 174

Kommunikator, 169, 173, 223, 298mit Topologie 298–302

Kontext, 173KProf, 324KVM-Switch, 70

LAM/MPI, 143–150

Page 454: [X.systems.press] Cluster Computing ||

452 Sachverzeichnis

Damon 147, 316Programme 149

lamboot, 148, 149lamhalt, 148laminfo, 146LAMMPS, siehe Molecular Dynamics

Simulatorlamnodes, 148, 320LAPACK, LAPACK95, 337Lastverteilung, 11

dynamische 265–275statische 260–265

latency, siehe LatenzLatenz, 24, 26, 59, 95, 196Laufzeitmessungen, 194–197LDAP, siehe Lightweight Directory Access

ProtocolLibckpt, 395Lightweight Directory Access Protocol, 111line buffered output, 220, 314lineare Algebra, 335–338Linpack, 9, 10, 19LINPACK, 337Linux, 30–31, 82, 140little-endian, 221Lm sensors, 84–90login node, siehe Knoten, Server-KnotenLoopback-Interface, 79, 91Low Profile Extended Format, 68lower bound, 236LPX-Format, siehe Low Profile Extended

FormatLustre, 65

MAC-Adresse, 55, 121, 122, 141Master, 265Master-Servant-Schema, siehe Master-

Worker-SchemaMaster-Worker-Bibliothek, 267–275Master-Worker-Schema, 265–275Maui-Scheduler, 156–157Maximum Transmission Unit, 96Message Passing Interface, 30, 45, 143

Implementationen 143–145Standard 213–220

MIMD, 34MISD, 34Molecular Dynamics Simulator, 343Molekulardynamik, 342–343

Moore’sches Gesetz, 19MPE, siehe Multi Processing EnvironmentMPI, siehe Message Passing InterfaceMPI-Datentypen

Aufbau 235–236nutzerspezifische 234–244Senden und Empfangen 238–240

MPI-POV-Ray, 346mpi.h, 167MPI/Pro, 144MPI Abort, 185, 414MPI Address, 238, 422MPI Aint, 238MPI Alleduce, 188MPI Allgather, 178, 426MPI Allgatherv, 182, 426MPI Allreduce, 187, 429MPI Alltoall, 179, 428MPI Alltoallv, 182, 428MPI ANY SOURCE, 172, 205, 412MPI ANY TAG, 172, 205, 412MPI Attr delete, 437MPI Attr get, 437MPI Attr put, 436MPI BAND, 412MPI Barrier, 177, 196, 424MPI Bcast, 173, 424MPI BOR, 412MPI BOTTOM, 412MPI Bsend, 190, 417MPI Bsend init, 420MPI BSEND OVERHEAD, 412MPI Buffer attach, 190, 417MPI Buffer detach, 191, 417MPI BXOR, 412MPI BYTE, 411MPI Cancel, 419MPI Cart coords, 300, 438MPI Cart create, 298, 304, 437MPI Cart get, 299, 438MPI Cart map, 438MPI Cart rank, 300, 308, 438MPI Cart shift, 300, 301, 308, 438MPI Cart sub, 299, 438MPI Cartdim get, 299, 438MPI CHAR, 411MPI Comm compare, 435MPI Comm create, 226, 435MPI Comm create errhandler, 414

Page 455: [X.systems.press] Cluster Computing ||

Sachverzeichnis 453

MPI Comm create keyval, 436MPI Comm delete attr, 437MPI Comm dup, 225, 435MPI Comm free, 226, 436MPI Comm free keyval, 436MPI Comm get attr, 437MPI Comm get errhandler, 415MPI Comm get name, 328MPI Comm group, 226, 432MPI COMM NULL, 226, 299, 412MPI Comm rank, 169, 434MPI Comm remote group, 436MPI Comm remote size, 436MPI COMM SELF, 223, 249MPI Comm set attr, 437MPI Comm set errhandler, 415MPI Comm set name, 328MPI Comm size, 169, 434MPI Comm split, 225, 299, 436MPI Comm test inter, 436MPI COMM WORLD, 223MPI DATATYPE NULL, 412MPI Dims create, 299, 304, 437MPI DOUBLE, 411MPI ERR ARG, 413MPI ERR BUFFER, 413MPI ERR COMM, 413MPI ERR COUNT, 413MPI ERR DIMS, 413MPI ERR GROUP, 413MPI ERR IN STATUS, 413MPI ERR INTERN, 413MPI ERR LASTCODE, 413MPI ERR OP, 413MPI ERR OTHER, 413MPI ERR PENDING, 413MPI ERR RANK, 413MPI ERR REQUEST, 413MPI ERR ROOT, 413MPI ERR TAG, 413MPI ERR TOPOLOGY, 413MPI ERR TRUNCATE, 413MPI ERR TYPE, 413MPI ERR UNKNOWN, 413MPI Errhandler create, 231, 414MPI Errhandler free, 231, 256, 415MPI Errhandler get, 231, 415MPI ERRHANDLER NULL, 231, 412MPI Errhandler set, 231, 415

MPI Error class, 230, 415MPI Error string, 231, 415MPI ERRORS ARE FATAL, 230MPI ERRORS RETURN, 230MPI File close, 249MPI File create errhandler, 255,

256MPI File errhandler fn, 256MPI File get errhandler, 255MPI File open, 246MPI File read all, 250MPI File seek, 251MPI File set errhandler, 256MPI File set view, 248MPI File write all, 250MPI Finalize, 168, 413MPI Finalized, 414MPI FLOAT, 411MPI Gather, 178, 425MPI Gatherv, 182, 425MPI Get address, 424MPI Get count, 172, 239, 416MPI Get elements, 240, 423MPI Get processor name, 169, 414MPI Get version, 415MPI Graph create, 438MPI Graph get, 438MPI Graph map, 438MPI Graph neighbors, 438MPI Graph neighbors count, 438MPI Graphdims get, 438MPI Group, 226MPI Group compare, 229, 432MPI Group difference, 228, 433MPI GROUP EMPTY, 228MPI Group excl, 227, 434MPI Group free, 229, 434MPI Group incl, 227, 433MPI Group intersection, 228, 433MPI GROUP NULL, 229, 412MPI Group range excl, 228, 436MPI Group range incl, 227, 436MPI Group rank, 229, 431MPI Group size, 229, 431MPI Group translate ranks, 229,

431MPI Group union, 228, 432MPI Handler function, 231MPI Ibsend, 419

Page 456: [X.systems.press] Cluster Computing ||

454 Sachverzeichnis

MPI IDENT, 229MPI INFO NULL, 247MPI Init, 168, 220, 316, 413MPI Initialized, 220, 414MPI INT, 411MPI Intercomm create, 436MPI Intercomm merge, 436MPI Iprobe, 418MPI Irecv, 206, 418MPI Irsend, 419MPI Isend, 205, 417MPI Issend, 419MPI Keyval create, 436MPI Keyval free, 436MPI KEYVAL INVALID, 412MPI LAND, 412MPI LB, 236, 253MPI LONG, 411MPI LONG DOUBLE, 411MPI LONG LONG INT, 411MPI LOR, 412MPI LXOR, 412MPI MAX, 412MPI MAX ERROR STRING, 231MPI MAX OBJECT NAME, 329MPI MAX PROCESSOR NAME, 170, 414MPI MAXLOC, 412MPI MIN, 412MPI MINLOC, 412MPI MODE APPEND, 247MPI MODE CREATE, 247MPI MODE DELETE ON CLOSE, 247MPI MODE EXCL, 247MPI MODE RDONLY, 247MPI MODE RDWR, 247MPI MODE SEQUENTIAL, 247MPI MODE UNIQUE OPEN, 247MPI MODE WRONLY, 247MPI NULL PROC, 300MPI Offset, 248MPI Op create, 183, 430MPI Op free, 185, 431MPI OP NULL, 185, 412MPI Pack, 256, 411, 424MPI Pack size, 424MPI PACKED, 411MPI Probe, 173, 417MPI PROC NULL, 227, 297, 412MPI PROD, 412

MPI Recv, 171, 415MPI Recv init, 213, 420MPI Reduce, 182, 188, 221, 222, 429MPI Reduce scatter, 188, 429MPI Register datarep, 249MPI Request, 205MPI Request free, 212, 419MPI REQUEST NULL, 205, 209, 212, 412MPI Rsend, 193, 417MPI Rsend init, 420MPI Scan, 188, 430MPI Scatter, 177, 427MPI Scatterv, 179, 427MPI SEEK CUR, 251MPI SEEK END, 251MPI SEEK SET, 251MPI Send, 170, 193, 415MPI Send init, 210, 420MPI Sendrecv, 200, 296, 416MPI Sendrecv replace, 200, 417MPI SHORT, 411MPI SIGNED CHAR, 411MPI SIMILAR, 229MPI Ssend, 192, 417MPI Ssend init, 420MPI Start, 210, 420MPI Startall, 420MPI STATUS, 172MPI STATUS IGNORE, 416MPI SUCCESS, 230, 413MPI SUM, 412MPI Test, 206, 419MPI Test canceled, 419MPI Testall, 209, 419MPI Testany, 209, 419MPI Testsome, 209, 419MPI Topo test, 438MPI Type commit, 236, 421MPI Type contiguous, 237, 420MPI Type create darray, 256, 424MPI Type create hvector, 424MPI Type create indexed, 424MPI Type create resized, 256, 424MPI Type create subarray, 256, 424MPI Type extent, 238, 422MPI Type free, 236, 422MPI Type get extent, 424MPI Type get name, 328MPI Type get true extent, 256, 424

Page 457: [X.systems.press] Cluster Computing ||

Sachverzeichnis 455

MPI Type hindexed, 424MPI Type hvector, 424MPI Type indexed, 237, 421, 424MPI Type lb, 238, 423MPI Type set name, 328MPI Type size, 424MPI Type struct, 238, 421MPI Type ub, 238, 423MPI Type vector, 237, 420MPI UB, 236, 253MPI UNDEFINED, 225, 229, 240, 412MPI UNEQUAL, 229MPI Unpack, 256, 424MPI UNSIGNED, 411MPI UNSIGNED CHAR, 411MPI UNSIGNED LONG, 411MPI UNSIGNED LONG LONG, 411MPI UNSIGNED SHORT, 411MPI User function, 183MPI Wait, 205, 419MPI Waitall, 209, 419MPI Waitany, 209, 419MPI Waitsome, 209, 419MPI WCHAR, 411MPI Wtick, 414MPI Wtime, 196, 414MPI WTIME IS GLOBAL, 414mpicc, 147mpiCC, 147MPICH, 144MPICH G2, 144MPICH-GM, 144mpif77, 147mpirun, 316MTU, siehe Maximum Transmission UnitMulti Processing Environment, 218Multicomputer, 23Multiprozessor, 21

symmetrischer 22, 61, 85Mutex-Variable, 42Myrinet, 58–59

Nachrichtentransfer, 44–47NAS Parallel Benchmarks, 392NAT, siehe Network Address Translationnative, 248Netboot, 130NetPIPE, 392network address translation, 86

Network Address Translation, 93, 118–121Network File System, 64, 86, 105–108Network Information Service, 108–111network link, 54network of workstations, 70Network Time Protocol, 116–118Netzmaske, 78, 91Netzwerknummer, 78Netzwerktechnologien, 53–61Netzwerktopologie, siehe TopologieNFS, siehe Network File SystemNFS-Root, 130nicht blockierende Kommunikation, 189,

205–213NIS, siehe Network Information ServiceNIS+, 111NIS-Domane, 108NIS-Maps, 109N-Korperprobleme, 342–343node, siehe Knotennon uniform memory access, 22, 35NOW, siehe network of workstationsNTP, siehe Network Time ProtocolNUMA, siehe non uniform memory access

Object Oriented MPI, 217Offset, 246OOMPI, siehe Object Oriented MPIOpen MPI, 163, 214OpenGFS, 65OpenPBS, 154OPT+, 344Optionen, 440OSCAR, 162–163

PAM, siehe Pluggable AuthenticationModules

Parallel Linear Algebra Package, 338parallel random access machine, 35Parallel Virtual File System, 65, 105Parallel Virtual Machine, 30, 48, 219parallele Ein- und Ausgabe, 244–256Parallelisierung

geometrische 289–309perfekte 259–289

ParallelKnoppix, 164ParMETIS, 344PBS, siehe Portable Batch SystemPBS Pro, siehe Portable Batch System

Page 458: [X.systems.press] Cluster Computing ||

456 Sachverzeichnis

peak performance, 6, 61, 368persistente Kommunikation, 210–213PETSc, 339ping, 92Ping-Pong, 194–197

Intel MPI Benchmarks 388Pipeline, 6PLAPACK, siehe Parallel Linear Algebra

PackagePluggable Authentication Modules, 113Port, 55Portable Batch System, 154Portnummer, 79, 119Ports, 26POSIX-Threads, 41–44POV-Ray, 158Prafixsummenalgorithmus, 185PRAM, siehe parallel random access

machinePre-Boot Execution Environment, 66, 101,

130Preemtion, 153Profiler, 322–324Profiling-Interface, 217–218, 331Prozess, 39Prozessgruppen, 226–230Pseudozufallszahlen, 356–359pthread create, 42PThreads, siehe POSIX-ThreadsPunkt-zu-Punkt-Kommunikation, 171Purify Plus, 324PVFS, siehe Parallel Virtual File SystemPVM, siehe Parallel Virtual MachinePXE, siehe Pre-Boot Execution Environment

QsNet, 60–61Quallity of Service, 157Queue, 152Queuing-System, siehe Batch-System

Ruckkehrsemantik, 192, 207race condition, 176Raiser-Karte, 68, 95Rang, 169RARP, 141recon, 149Reduktionsoperatoren, 183

selbstdefinierte 183Register, 6

Reiser-FS, 83Request for Comments, 77restart, 393RFC, siehe Request for CommentsRingtausch, 198–201Rocks Cluster Distribution, 163ROMIO, 65Router, 79rsync, 98

Sicherheit 103

SAN, siehe supercomputer at nightSATA, siehe Serial Advanced Technology

AttachmentsScalable Coherent Interconnect, 59–60ScaLAPACK, 338Scali MPI Connect, 144Scheduler, 152–153SCI, siehe Scalable Coherent InterconnectSCore, 396SCSI, siehe Small Computer System

InterfaceSecure Shell, 112–116

Portforwarding 330Serial Advanced Technology Attachments,

63SETI@home, 32–34shared memory, siehe Speicher, gemeinsa-

merSIMD, 34SISD, 34SKaMPI, siehe Special Karlsruher

MPI-BenchmarkSmall Computer System Interface, 63SMP, siehe Multiprozessor, symmetrischerSPEC, 8, 392Special Karlsruher MPI-Benchmark, 392Speedup, 10–12, 186, 382, 383

skalierter 16superlinearer 20

Speichergemeinsamer 21–23Hauptspeicher 62verteilter 21–23virtueller 62

SPMD, 47, 170SPRNG (Scalable Parallel Pseudo Random

Number Generators Library), 345Standard-Gateway, 92

Page 459: [X.systems.press] Cluster Computing ||

Sachverzeichnis 457

Standardausgabe, 314Standardeingabe, 314Standardfehlerausgabe, 314StarCrash, 341stderr, siehe Standardfehlerausgabestdin, siehe Standardeingabestdout, siehe StandardausgabeSterling, Thomas, 27Stern, 24Stromverbrauch, 69, 73, 81Subnetz, 79Sun Grid Engine, 154–155

Verwendung 157–160supercomputer at night, 35Switch, 26, 54switched network, 55SystemImager, 97–104

Taktfrequenz, 5TCP, siehe Transmission Control ProtocolTCP-Wrapper, 107TCP/IP, siehe Transmission Control

Protocol/Internet ProtocolTFTP, siehe Trivial File Transfer Protocoltftp-hpa, 131Thomson-Problem, 346–350Thread, 41Threads, 39–44Tina’s Random Number Generator Library,

345, 356–366Top 500, 15, 27Topologie, 24, 25

virtuelle 298TORQUE, 154Torus, 24TotalView, 332Trace Analyzer, 332Trace-Datei, 325Transmission Control Protocol, 78

Transmission Control Protocol/InternetProtocol, 77–80

Trivial File Transfer Protocol, 130TRNG, siehe Tina’s Random Number

Generator Librarytrunking, 56, 125Typbeschreibung, 235type map, siehe TypbeschreibungTypsignatur, 235

Uberholverbot, 204, 208UDP, siehe User Datagram ProtocolUMA, siehe uniform memory accessundurchsichtige Objekte, 223–224uniform memory access, 22upper bound, 236User Datagram Protocol, 78

Vektorprozessor, 6Verbindungsnetzwerke, 24–27verteiltes Rechnen, 32view, 245, 246virtual memory, siehe Speicher, virtuellerVollduplexmodus, 54, 222von-Neumann-Flaschenhals, 7–8, 15, 21von-Neumann-Modell, 6VTune Performance Analyser, 324

Wettervorhersage, 3, 18Worker, 265working node, siehe Knoten, compute nodeWrapper-Compiler, 148

XFS, 83xhost, 319XmdS, siehe eXtensible multi-dimensional

SimulatorXMPI, 324–328

Zufallszahlen, siehe Pseudozufallszahlen