Whitepaper - IT

Transcription

Whitepaper - IT
Der
Clusterkonfigurator
von Leonardo Lapeira, transtec AG
Die optimale Ausstattung definieren
Die Leistung eines HPC-Clusters mathematisch zu beschreiben und
vorherzusagen, ist bislang kaum versucht worden. Ein präziser Algorithmus
würde die Optimierung im Alltag deutlich vereinfachen. Im Rahmen eines
Forschungsprojekts wurden die hierfür notwendigen Grundlagen erarbeitet.
Der Clusterkonfigurator
LEONARDO LAPEIRA
transtec AG, Tübingen
Copyright 2003 - 2007©
Dieses Werk ist geistiges Eigentum der transtec AG.
www.transtec.de
Es darf ohne Zustimmung des Autors und der transtec AG weder kopiert noch auszugsweise
abgedruckt oder in einer anderen Form vervielfältigt werden.
Alle in diesem Buch enthaltenen Informationen wurden mit größter Sorgfalt zusammengestellt.
Dennoch können fehlerhafte Angaben nicht völlig ausgeschlossen werden. Die transtec AG und
der Autor haften nicht für etwaige Fehler und deren Folgen.
Die in diesem Buch verwendeten Soft- und Hardwarebezeichnungen sind häufig eingetragene
Warenzeichen. Sie werden in diesem Buch ohne Gewährleistung der freien Verwendbarkeit
genutzt. Das Abdrucken von Waren- und Handelsnamen auf den folgenden Seiten berechtigt
nicht zu der Annahme, diese Namen als frei im Sinne der Markenschutzgesetzgebung zu
betrachten.
Autor:
Leonardo Lapeira
Redaktion: Dr. Andreas Koch, Bernd Zell, Johannes Wiedmann
Grafiken: Leonardo Lapeira, Johannes Wiedmann
-2-
Inhaltsverzeichnis
KAPITEL 1 - Einführung
5
KAPITEL 2 - Die Aufgabestellung
7
KAPITEL 3 - Erste theoretische Grundlagen
9
3.1 Rechnerarchitekturen
9
3.1.1 SISD Rechner
9
3.1.2 MIMD Rechner
10
3.2 Shared Memory – Distributed Memory
10
3.2.1 Shared Memory Systeme
10
3.2.2 Distributed Memory Systeme
11
3.3 Verteilte Rechensysteme
11
3.4 Die Clusterhardware
12
3.4.1 CPU
13
3.4.2 Die CPU Register
13
3.4.3 Level 1 – Cache oder First Level Cache
14
3.4.4 Level 2 – Cache oder Second Level Cache
14
3.4.5 RAM
14
3.4.6 Bus Mastering und Direct Memory Access (DMA)
14
3.4.7 Das Verbindungsnetzwerk
15
KAPITEL 4 - Performancebestimmung verteilter Rechensysteme
16
4.1 Parallelisierungsgrad
16
4.2 Speedup und Effizienz
16
4.3 Faktoren, die den Speedup auf Applikationsebene limitieren
18
4.4 Das Gesetz von Amdahl
18
4.5 Latenz und Bandbreite
20
4.6 Ein einfaches Performancemodell
21
KAPITEL 5 - Performancebestimmung in der Praxis
23
5.1 Performancebestimmung nach der Methode des sequentiellen Anteils
23
5.2 Theoretische Peakperformance
23
5.3 Rechenleistung bei einer spezifischen Applikation
12
5.4 Gesamtrechenzeit
24
5.5 Effizienz
24
5.6 Der Linpack Benchmark
24
5.7 Bestimmung der Latenz und Bandbreite einzelnen Komponenten
25
5.7.1 nbench
25
5.7.2 Cachebench
26
5.7.3 ping / fping
28
5.7.4 bing
29
KAPITEL 6 - Bottlenecks 31
6.1 Superlineare Speedups
31
6.2 Applikationseigenschaften und Hardware Bottlenecks
32
6.3 Dual CPU Systeme
33
6.4 Netzwerkflaschenhals
34
6.5 Input / Output
35
KAPITEL 7 - Mathematische Grundlagen zum Optimierungsverfahren
37
7.1 Lineare Optimierung
37
7.2 Problemstellung
37
-3-
7.3 Geometrische Deutung: Maximum- und Minimum-Optimierung im R ²
38
7.4 Der Simplex-Algorithmus und die Bildung des Simplextableaus
39
7.5 Schritte zur Berechnung des Simplexes
41
7.6 Künstliche Variablen
80
KAPITEL 8 - Das Konfigurationsproblem
45
8.1 Die Definition einer Zielfunktion
45
8.2 Die Randbedingungen
46
8.3 Problemabhängige Randbedingungen: Eine Beispielkonfiguration.
49
8.4 Der Clusterkonfigurator
51
8.5 Eine Beispielberechnung mit Hilfe des Clusterkonfigurators
55
KAPITEL 9 - Schlussfolgerungen und Ausblick
62
Anhang A: Einrichtung eines Linux-Clusters
64
A.1 Hardware
64
A.2 Systemsoftware
64
A.2.1 Der Masterknoten: Betriebssysteminstallation
65
A.2.1.1 Namensauflösung
67
A.2.1.2 PXE fähiges DHCP
68
A.2.1.3 TFTP Server
69
A.2.1.4 NIS (Network Information Service)
69
A.2.1.5 NFS (Network File System)
71
A.2.1.6 rsh/ssh
72
A.2.1.7 Zeitausgleich durch einen XNTP Server
73
A.2.1.8 Batch Queuing System
74
A.2.1.9 Automatisierung durch Skripte
77
A.2.1.10 Sicherheitsaspekte
78
-4-
KAPITEL 1 - Einführung
Supercomputer kommen zum Einsatz wenn es um die Simulation realer Vorgänge geht, deren hohe Komplexität die Nutzung von
herkömmlichen Rechenarchitekturen unmöglich macht. Oft sind diese Simulationen selbst auf den modernsten Einzelprozessorrechenanlagen nicht innerhalb einer befriedigenden Zeitspanne zu bewältigen. Hat man zufällig mit Berechnungen zu tun, die wegen einer sehr feinen Diskretisierung mit sehr großen Datenmengen arbeiten müssen, so ist die Ausführung der Simulation sogar
auf der schnellsten Einprozessormaschine nicht mehr möglich. Die technisch maximal einsetzbare Speichergröße auf Einzelprozessormaschinen stellt hierbei eine unüberwindbare Hürde dar.
Supercomputer stellen praktisch ohne Ausnahme den einzigen Weg zur Verbesserung unseres Verständnisses über die Funktionsweise vielschichtiger Systeme dar. In der Tat ist für fast jeden Forscher, der sich mit solchen Aufgaben beschäftigt, ein Supercomputer das ideale Werkzeug wertvolle Erkenntnisse so schnell wie möglich zu erhalten. Die Problemstellungen, die nach Rechenpower auf Supercomputerniveau verlangen, erstrecken sich somit von der Hochenergiephysik bis hin zur Erstellung von „Special
Effects“ für Kinofilme. Wenn man noch dazu betrachtet, dass Wirtschaft und Industrie ebenfalls sinnvolle Nutzungsmöglichkeiten
für solche Systeme gefunden haben, kann man durchaus verstehen, warum High Performance Computing ein aktuelles Thema
bleibt.
So beliebt wie High Performance Computing (HPC) in den verschiedenen akademischen und industriellen Kreisen auch ist, bleibt
die Anschaffung eines Supercomputers meistens aus. Die finanziellen Mittel die zur Verfügung stehen reichen nur selten, den
hohen Preis eines solchen Systems begleichen zu können. Diese hohen Kosten waren eben einer der wichtigsten Gründe, warum
Anfang der 90er Jahre Thomas Sterling und Don Backer, damalige Mitarbeiter einer Forschungsgruppe bei der amerikanischen
Luft- und Raumfahrt Behörde (NASA) sich mit der Entwicklung von Rechenarchitekturen beschäftigten, die deutlich kostengünstiger werden sollten als es das traditionelle Supercomputing bis dato war.
Das Ergebnis, eine Ansammlung von 16 Prozessoren des Typs Intel 80486, welche über channel bonding1) Ethernet miteinander
kommunizierten und unter dem Namen Beowulf2) im Sommer 1994 bekannt gegeben wurde. Die Sache war von Anfang an ein
Erfolg. Sofort wurden in zahlreichen Universitäten überall auf der Welt ähnliche Systeme gebaut. Diese gewannen dermaßen an
Bedeutung, dass schließlich auch die Industrie darauf aufmerksam wurde und für den eigenen Bedarf ähnliche Systeme einsetzte.
Beowulf-Cluster oder auch Computing Cluster (die Bezeichnung Beowulf ist seitdem etwas in Vergessenheit geraten) stellen also
die wirtschaftlichste Realisierung eines Supercomputers dar. Cluster sind im Prinzip Ansammlungen von Computern, deren Hardwarekomponenten größtenteils aus handelsüblichen PC-Komponenten bestehen und durch eine bestimmte Netzwerktechnologie
miteinander kommunizieren. Hinzu kommt eine besondere Softwarekonfiguration, die diese vernetzten Maschinen aus der Sicht
des Anwenders wie ein einziges und einheitliches System erscheinen lassen.
Durch die steigende Nachfrage an Rechenleistung in Form von Clustern ist ein Markt entstanden, in welchem nun auch großen Firmen wie Sun, SGI, HP, IBM, etc. Platz gefunden haben. Die meisten Anbieter konzentrierten sich auf die Entwicklung von administrativen Softwarewerkzeugen, die dem Anwender die Arbeit mit dem System erleichtern sollen. Es gibt also zahlreiche Clustertools,
auch wenn diese in den meisten Fällen nur zusammen mit der entsprechenden hauseigenen Hardware bzw. dem Betriebsystem
richtig arbeiten und/oder deren Nutzung durch Software-Lizenzen geregelt wird.
Was für uns auffällig war ist die absolute Abwesenheit von Studien, Softwaretools o. ä., die sich mit den Möglichkeiten auseinandersetzen, solche HPC-Systeme noch wirtschaftlicher zu machen. Cluster stellen sicherlich die billigste Hochleistungscomputerarchitektur dar, die man zurzeit kaufen kann. Dies heißt aber noch lange nicht, dass sie schon alle ihre Vorteile ausgespielt hat.
Das Hauptziel des hier vorgestellten Projekts ist es deswegen, mit Hilfe wissenschaftlicher Methoden die Durchführung einer
genauen Analyse. Falls realisierbar, soll ein Softwaretool entwickelt werden, ein so genannter Clusterkonfigurator, welcher uns
in die Lage versetzen soll, maßgeschneiderte Hardwarekonfigurationen solcher Cluster sowohl für unseren Kunden als auch für
unser Unternehmen wirtschaftlicher zu gestalten. Wirtschaftlich heißt also, dass durch die Ergebnisse des Clusterkonfigurators eine
Anzahl von Aussagen getroffen werden soll, die sowohl unsere Angebotserstellung als auch die Kaufentscheidung des Kunden
optimal beeinflussen sollte.
In diesem Sinne wird es notwendig sein, zuerst die Aufgabestellung so genau wie möglich zu definieren. Erst dann werden wir
den entsprechenden theoretischen und praktischen Rahmen aufbauen können, in dem wir uns zu der gewünschten Lösung, dem
Clusterkonfigurator, bewegen werden.
Viele haben mir in der einen oder anderen Weise geholfen, diese Arbeit fertig zu schreiben; ihnen allen schulde ich Dank. Insbe1) Der Begriff channel bonding bezeichnet eine besondere Netzwerkkonfiguration, in der zwei oder mehrere Netzwerkkarten zu einem einzigen Kommunikationskanal gebündelt werden. Während sich für den Benutzer nichts an der Funktionalität des Netzes ändert, steigert sich jedoch die Netzwerkperformance durch das additive Verhalten des Datendurchsatzes.
2) Beowulf, eine epische Erzählung über die Abenteuer eines großen skandinavischen Kriegers aus dem sechsten Jahrhundert, wurde in einer alten Form der
englischen Sprache aus der zehnten Jahrhundert geschrieben. Dass die Maschine von Sterling und Becker mit diesem Namen benannt wurde, hat eher mit
den literarischen Vorlieben der Architekturdesigner zu tun.
-5-
sondere möchte ich Herrn Dpl. Phys. Martin Konold wegen seiner wertvollen Beiträge und Anregungen erwähnen; diese haben die
Entwicklung des Projektes maßgeblich beeinflusst. Andere Leute haben verschiedene Teilabschnitte früherer Textversionen durchgelesen und zahlreiche hilfreiche Verbesserungsvorschläge gemacht: Herrn Dr. Andreas Koch, Herrn Bernd Zell und Herrn Johannes
Wiedmann. Herrn Wiedmann möchte ich auch für seine Hilfe in Sachen JavaScript und wegen der Verbesserung mehrerer Bilder
meinen Dank aussprechen.
-6-
KAPITEL 2 - Die Aufgabenstellung
Die Leistung traditioneller Supercomputer basiert auf stark spezialisierten Hardwarekomponenten. Die meist an die vorgegebene
Aufgabe angepassten Recheneinheiten greifen auf einen gemeinsamen Speicherbestand zu. Die Interkommunikation zwischen
den verschiedenen Systemkomponenten erfolgt über Kommunikationskanäle, deren Architektur vom Maschinenhersteller selbst
entworfen wurde. Der größte Vorteil eines Clustersystems gegenüber anderen Supercomputerklassen ist ein deutlich besseres
Preisleistungsverhältnis. Dieses wird, wie oben bereits erwähnt, insbesondere durch den Einsatz von handelsüblichen Hardwarekomponenten erreicht. Jedes Mal wenn die Leistung einer im Clusterbau eingesetzten PC-Komponente steigt und/oder deren Preis
sinkt, sind wir in der Lage ein besseres System anzubieten.
So viel Flexibilität und relative Simplizität auf der Hardwareebene hat jedoch ihren Preis. Wir werden etwas später deutlich erkennen können, warum sich die Supercomputerklasse zu der Computercluster gehören, als einfach zu bauen aber schwierig zu
programmieren charakterisieren lässt. Damit ist gemeint, dass eine gute Portion an Optimierungsmöglichkeiten in der Codeoptimierung liegt und somit letztendlich beim Anwender. Das Grundprinzip der Clusterarchitektur, die zum Erfolg des Modells führt,
entpuppt sich somit für uns ebenfalls als wichtiges Hindernis für ein einfaches Erreichen der optimalen Clusterkonfiguration. Denn
genau der Aspekt der Softwareoptimierung ist der Teil, auf den wir am wenigsten Einfluss nehmen können.
Wir sind uns gleich von vorneherein darüber im Klaren, dass eine theoretische Lösung für das Problem der Optimierung einer
Clusterkonfiguration das Thema für eine Dissertation im Fachgebiet der Informatik werden kann. Die Umsetzung lässt sich beliebig
kompliziert gestalten. Damit wir auf konkrete Ergebnisse überhaupt kommen, müssen wir unsere Ziele entsprechend beschränken.
Aus dem Grund verstehen wir unsere Aufgabe als die methodische Suche nach einer möglichen Lösung für folgendes Problem:
Wie kann man die höchste Performance für eine möglichst breite Palette von rechenleistungshungrigen Anwendungen erzielen,
bei einer innerhalb einer gegebenen Zeitspanne der im PC-Bereich zur Verfügung stehenden Hardware und einem meist vom Kunden fest vorgegebenen Budget? Wir werden im Laufe der vorliegenden Arbeit dieses Problem als Konfigurationsproblem bezeichnen, auch wenn wir es später ein wenig anders formulieren werden.
Als erster allgemeiner Lösungsansatz für das Konfigurationsproblem wollen wir folgenden Weg einschlagen: Wir werden erstmals
versuchen die wichtigsten Merkmale zu erkennen, die für die Beschreibung eines Clusters nach dem Supercomputermodell gelten.
Wir sind der Überzeugung, dass aus diesem Prozess sich ausreichend grundlegende Erkenntnisse gewinnen lassen, die später
durch eine geeignete Interpretation in Form eines mathematischen Modells festgehalten werden können. Die Lösung des in dem
Modell implizit enthaltenen mathematischen Problems werden wir anschließend als Ergebnis des Clusterkonfigurators darstellen.
Auf diese Weise wird der Clusterkonfigurator als Referenzpunkt im Bezug auf die Zusammenstellung einer optimalen Clusterkonfiguration und das entsprechende optimale Kundenangebot dienen.
Um die Übersichtlichkeit der Darstellung so effektiv wie möglich zu gestalten, haben wir dieses Dokument in sieben weitere Kapitel
gegliedert: Im Kapitel 3 setzen wir uns mit den ersten nötigen theoretischen Grundlagen auseinander, die wir für die Definition
und Entwicklung unseres mathematischen Modells für nötig halten. Wir beschreiben zuerst einige parallele Architekturen. Insbesondere betrachten wir das Modell, welches die theoretische Informatik für die sog. Distributed Memory Computer standardmäßig
definiert (Cluster gehören eindeutig zu dieser Supercomputerklasse). Zum Abschluss dieses Kapitels betrachten wir kurz die Hardwarekomponenten, die diesen Architekturtyp eindeutig charakterisieren.
Kapitel 4 beschäftigt sich mit grundlegenden Begriffen, die ebenfalls aus der theoretischen Informatik stammen (Speedup, Effizienz, Amdahl’sches Gesetz, usw.), so dass wir erstmals über eine Quantifizierung der Systemleistung sprechen können. Mit Hilfe
zweier grundlegender Kennzahlen, nämlich der Latenz und der Bandbreite, wird ein Performancemodell aufgestellt, das für den
Rest des Weges als Referenz für die Bestimmung der Clusterperformance gelten soll.
In Kapitel 5 behandeln wir einige Standardmethoden zur praktischen Bestimmung der Rechenleistung eines Clusters. Dabei werden Methoden betrachtet, die es uns erlauben die gesamte Performance eines Clusters zu ermitteln. Wir werden jedoch einige
weitere Benchmarks betrachten, die uns Informationen über die Leistung spezifischer Hardwarekomponenten liefern können. Wir
versuchen dadurch unser Clustermodell zu verfeinern und weitere Aspekte des Konfigurationsproblems besser zu verstehen.
Mit Bottlenecks beschäftigt sich Kapitel 6. Dort betrachten wir in ausführlicher Form die wichtigsten Leistungsbremser eines Clustersystems und versuchen zu verstehen wo diese entstehen, wie man sie charakterisieren kann und ihre negativen Auswirkungen
in das Modell sinnvoll einzubauen hat.
Kapitel 7 stellt thematisch den sogenannten Simplex-Algorithmus in den Mittelpunkt, ein Lösungsverfahren, das wir für die Lösung
eines linearen Optimierungsproblems benötigen. Wir wollen damit den Weg für die Aufstellung eines einfachen mathematischen
Modells zur Beschreibung des Konfigurationsproblems im nächsten Kapitel möglich machen.
In Kapitel 8 versuchen wir durch eine praktische Umsetzung aller Begriffe, die in den Kapiteln 3 bis 7 beleuchtet wurden, die Implementierung eines ersten funktionalen Lösungsverfahrens für das Konfigurationsproblem abzugeben. Es wird z. B. die mathematische Darstellung des Modells betrachtet und erste Versuche zur Generierung einer “optimale Lösung“ vorgestellt. Anschließend
-7-
werden die Ergebnisse dieser Untersuchungen in Form eines Computerprogramms zusammengefasst und mit den theoretischen
Vorhersagen verglichen. Die Struktur des Clusterkonfigurators und einige, durch seinen Einsatz gewonnene Ergebnisse stehen hier
im Mittelpunkt.
Kapitel 9 beschreibt schließlich unsere gesamten Ergebnisse und kann als zusammenfassende Analyse der Vorteile, Anwendungsmöglichkeiten und potentiellen weiteren Entwicklung der vorliegenden Studie und ihrer Softwareumsetzung verstanden werden.
Als Abschluss und Ergänzung dieser Arbeit liefern wir im Anhang A eine ausführliche Beschreibung der Arbeitschritte, die für die
Installation und Inbetriebnahme eines Clusters notwendig sind. Damit wollen wir dem interessierten Leser die Gelegenheit bieten,
das Thema Cluster aus einer praktischen Perspektive kennen zu lernen.
-8-
KAPITEL 3 - Erste theoretische Grundlagen
Wie oben bereits angedeutet, haben wir in diesem Kapitel hauptsächlich mit Grundbegriffen zu tun, welche die theoretische
Informatik für die Charakterisierung der Eigenschaften von Parallelrechnern entwickelt hat. Wir werden hier besonders auf Performanceanalyse und Verfahren zur Performancemessung solcher Parallelerechner etwas detaillierter eingehen. Dabei werden wir
versuchen nicht nur die Menge an theoretischen Grundlagen, die den Rahmen unseres Lösungsansatzes bilden, sinnvoll einzuschränken, sondern uns von vorneherein ein Bild von der Komplexität des Problems zu verschaffen.
3.1 Rechnerarchitekturen
Hochleistungsrechnen bedeutet meistens paralleles Rechnen. Während bei traditionellen, sequentiellen Berechnungen (auf Einprozessorsystemen) ein Befehl nach dem anderen abgearbeitet wird, werden bei der parallelen Bearbeitung des gleichen Problems
mehrere Befehle gleichzeitig ausgeführt, indem mehrere Prozessoren gleichzeitig eingesetzt werden und die Rechenlast auf diese
verteilt wird. Die Arbeit jedes Rechners, egal ob er über einen einzigen oder mehrere Prozessoren verfügt, ist jedoch stets die
gleiche:
• Ein Instruktionsset (das Programm) steuert die vom Rechner auszuführenden Aktionen.
• Ein Datenset (Data Stream) wird vom Programm überarbeitet und modifiziert.
Aus dieser Beziehung zwischen einem gegebenen Instruktionsset und seinem zu bearbeitenden Datenset hat Flynn 1966 ein Schema zur Klassifizierung von Rechnerarchitekturen eingeführt, das sich bis dato als sehr hilfreich erwiesen hat.
SISD
Single Instruction,
Single Data
Das sind herkömmliche Einzelprozessorsysteme
SIMD
Single Instruction,
Multiple Data
„Massiv Parallele“ Rechner und Vektor Rechner
lassen sich hier klassifizieren.
MISD
Multiple Instruction,
Single Data
Nicht in kommerzieller Form auf dem Markt
vorhanden
MIMD
Multiple Instruction,
Multiple Data
Die meisten Parallelrechner lassen sich hier
unterbringen
Tabelle 3.1: Klassifizierungsschema nach Flynn.
Tabelle 3.1. listet die Rechenarchitekturen nach diesem Schema. Unter den vier Architekturtypen nach Flynn sind für uns tatsächlich nur zwei von Interesse: SISD und MIMD, deswegen wollen wir Sie etwas ausführlicher betrachten.
3.1.1
SISD Rechner
SISD Rechner sind Rechnersysteme wie konventionelle PCs oder Workstations. Ein einziger Prozessor arbeitet mit einem einzigen
Instruktionsset und operiert auf ein einziges Datenset. Das Instruktionsset wird in sequenzieller Form durchgeführt (Abb. 3.1).
Kontroll-Einheit
Instruktionsset
Prozessor
Datenset
Speicher
Abbildung 3.1: SISD Rechner schematisch.
Man spricht also von einem Befehl pro CPU Rechenzyklus und per Datenelement. Heutzutage besitzen Mainframes mehr als eine
CPU, diese CPUs führen jedoch unabhängige Programme durch. In dem Sinne sind solche Systeme ebenfalls als SISD Maschinen
zu betrachten, die auf unabhängige Datensets operieren. Beispiele von den eben genanten SISD Maschinen findet man in den
Workstations von DEC, HP, Sun usw.
Obwohl diese Rechenarchitektur nichts mit Parallelismus zu tun hat, wollen wir sie näher betrachten, denn einige Performanceeigenschaften von Clustern lassen sich innerhalb des Einprozessormodells einfacher verstehen.
-9-
3.1.2
MIMD Rechner
Die zweite für uns wichtige Rechnerarchitektur ist die nach Flynn benannte MIMD Architektur (s. Tab 3.1).
Abbildung 3.2: Es gibt N Prozessoren, N Instruktionssets und N Datensets.
Bei MIMD-Maschinen arbeiten die Recheneinheiten nach dem Programm, das von der eigenen Kontrolleinheit des Prozessors
durchgeführt wird. Die Gesamtheit der Prozessoren ist also nicht nur in der Lage mehrere unterschiedliche Instruktionssets gleichzeitig auszuführen, sondern auch auf unterschiedlichen Datensets zu operieren. Im Gegensatz zu den oben erwähnten Multi-Prozessor SISD Maschinen sind bei MIMD Instruktions- und Datensets untereinander abhängig. Beide stellen unterschiedliche Teile der
gleichen Rechenaufgabe dar. Auf diese Weise können MIMD Maschinen die gleichzeitige Ausführung mehrerer kleiner Jobs unterstützen und dadurch die gesamte Ausführungszeit des Hauptjobs deutlich verkürzen. Es gibt zahlreiche Beispiele solcher MIMD
basierten Rechensystemen, angefangen bei einem herkömmlichen Dualprozessorsystem bis hin zu der SGI/Cray T3E mit tausenden
von Prozessoren.
3.2
Shared Memory – Distributed Memory
Das Klassifizierungs-Schema von Flynn reicht leider nicht aus, um die Hauptmerkmale von Supercomputern vollständig zu definieren. Ein weiteres grundlegendes Unterscheidungsmerkmal, das uns bei der Analyse von HPC-Systemen unterstützen kann, ist die
Struktur des Datenzugriffs seitens der einzelnen Prozessoren. Prozessoren müssen auf Datenbestände operieren, die sich im Allgemeinen im Hauptspeicher des Computers befinden. Die Art und Weise,in der die Prozessoren mit den Daten interagieren,hängt mit
der Speicherarchitektur zusammen. Die zwei wichtigsten Speicherarchitekturen sind unter folgenden Namen bekannt:
• Shared Memory
• Distributed Memory
3.2.1
Shared Memory Systeme
Shared Memory Systeme besitzen mehrere CPUs und alle teilen sich einen gemeinsamen Speicher-Adressraum (Abb. 3.3).
Abbildung 3.3: Parallelrechner mit gemeinsamem Speicher (Shared Memory). Die Prozessoren P1 bis Pn greifen auf einem gemeinsamen Speicher zu.
- 10 -
Die CPU-Speicherzugriffe erfolgen mit der gleichen Priorität, so dass zu einem gegebe-nen Zeitpunkt nur eine bestimmte Speicheradresse von einem einzigen Prozessor benutzt werden darf. Shared Memory Systeme sind sowohl bei den SIMD als auch bei den
MIMD Rechenarchitekturen zu finden, so dass sie kurz auch als SM-SIMD und SM-MIMD bezeichnet werden.ezeichnet werden.
3.2.2
Distributed Memory Systeme
Bei Rechnern mit verteiltem Speicher (distributed memory) hat jeder Prozessor Pi, (i = 1,…, n,) einen eigenen lokalen Speicher, auf
den nur er zugreifen kann (Abb. 3.4).
Netzwerk
P1
P2
Pn
M1
M2
Mn
Abbildung 3.4: Parallelrechner mit verteiltem Speicher (Distributed Memory).
Die Prozessoren kommunizieren miteinander über ein bestimmtes Netzwerk, so dass je-der Prozessor in der Lage ist, Daten aus
seinem eigenen Speicher mit anderen Prozesso-ren auszutauschen. Ähnlich wie im Fall von Shared Memory Systemen findet man
Distri-buted Memory Systeme sowohl unter den Single Instruction Multiple Data Maschinen (DM-SIMD) als auch unter den Multiple Instruction Multiple Data Systemen (DM-MIMD).
3.3
Verteilte Rechensysteme
Mit den SM-MIMD und DM-MIMD Architekturtypen haben wir alle Rechnerklassen
behandelt, die in der Welt der Hochleistungscomputer von Bedeutung sind. Wir können nun versuchen clusterartige Hochperformancesysteme innerhalb einer der oben definier-ten Klassen einzustufen. Die Abbildung 3.5 zeigt zuerst eine schematische
Darstellung der Standard Hardware Hauptkomponenten in einer typischen Clusterkonfiguration.
Switch
100/1000 Mbit
Internet
eth0
eth1
eth0
eth0
eth0
node 32
Master Knoten
node 1
node 2
CPU
Speicher
Festplatte
CPU
Speicher
Festplatte
CPU
Speicher
Festplatte
..............
CPU
Speicher
Festplatte
Abbildung 3.5: Schematische Darstellung einer Standard Clusterkonfiguration
- 11 -
Man erkennt an diesem Bild zunächst einmal die Struktur eines Distributed Memory Systems wieder (jede CPU besitzt eigenen
Speicher). Die Prozessoren, die bei den üblichen Clusterkonfigurationen eingesetzt werden, sind ausnahmslos vollwertige RISC-Prozessoren (sie verfügen über eigene Kontrolleinheiten). Es ließe sich auch behaupten, dass Cluster in die Klasse der MIMD Maschinen einzustufen sind3).
Wenn wir diese Gedankenlinie verfolgen, können wir Cluster insgesamt als ein gut gelungenes Beispiel der DM-MIMD Architektur
ansehen. Es gibt leider zwei wichtige Tatsachen, welche die Allgemeingültigkeit einer solchen Behauptung in Frage stellen: Die
Rechenknoten eines Clusters kommunizieren durch (Gigabit) Ethernet (im besten Fall über SCI oder Myrinet Netzwerkkomponenten) und arbeiten gleichzeitig an verschiedenen Teilen eines gegebenen Programms. Im Prinzip unterscheidet sich das nicht vom
Konzept der DM-MIMD Architektur, da aber die Kommunikationsgeschwindigkeit zwischen den Prozessoren bei Clustersystemen
um einige Größenordnungen langsamer ist als die von dedizierten DM-MIMD Maschinen, kann man nicht von echtem Parallelismus sprechen. Man bezeichnet deswegen Clustersysteme besser als verteilte Rechensysteme (Distributed Processing Systems
oder Multicomputers), damit man eben diesem wichtigen Unterschied Rechnung trägt.
Der zweite Punkt der unsere Analyse noch zu verkomplizieren vermag, hat mit der Tatsache zu tun, dass bei der Hardwarekonfiguration von Standard Clustern der Einsatz von Dualprozessorfähigen Maschinen als Rechenknoten bevorzugt wird. SMP 4) Rechner
(Dual Athlon, Pentium III oder Xeon Systeme) sind aber nicht anderes als SM-MIMD Maschinen, deren zwei Prozessoren auf einen
gemeinsamen Hauptspeicher zugreifen. Als erste Zusammenfassung lässt sich also sagen: Cluster sind verteilte Rechensysteme (die
dem Konzept von DM-MIMD Systemen ähneln), deren einzelne Bestandteile sich jedoch häufig besser als SM-MIMD beschreiben
lassen.
Als direkte Konsequenz dieser Erkenntnis haben wir es bei einem Cluster mit einem System zu tun, das mit den Vorteilen aber
auch mit den Nachteilen beider Systemarchitekturen behaftet ist. So sind die Rechenknoten eines Clusters in der Lage, mehrere
Teile eines Jobs gleichzeitig auszuführen, was die Gesamtausführungszeit des Hauptjobs deutlich verkürzen kann. Die Synchronisationsaufgaben, die für die Koordination der Prozessoren am Ende des parallelen Anteils eines Jobs notwendig sind, können jedoch
stark zunehmen. Das könnte den Zeitgewinn bei der Parallelausführung des Programms im Endeffekt zunichte machen.
Andererseits bringen die Distributed Memory Eigenschaften eines Clusters z.B. als Vorteil mit, dass die Speichergröße direkt mit der
Anzahl der CPUs steigt. Eine größere Anzahl von Prozessoren lässt also die Speichergröße und die Bandbreite steigen, der Benutzer ist aber für das Senden und Empfangen von Daten zwischen den Unterprozessen verantwortlich. Die meisten Daten werden
zwar nur zwischen Prozessor und lokalem Speicher wie bei einem sequentiellen Rechner transportiert, dies ist aber für die praktische Programmierung ein wesentlicher Nachteil: Wenn Daten von anderen Prozessoren benötigt werden, sind diese durch spezielle
Befehle zum Versenden über das Netzwerk zu transportieren. Es ist also eine besondere Softwareschnittstelle (auch Parallelbibliothek5) genannt) notwendig, um diese Form der Rechenprozessverteilung zu ermöglichen. Die Leistung einer bestimmten parallelen
Anwendung hängt somit nicht nur mit der Leistung der im Cluster eingesetzten Hardware zusammen, sondern auch stark mit der
intrinsischen Leistung der implementierten Parallelbibliotheken.
Letzteres führt uns zu der Erkenntnis, dass das Erreichen der optimalen Leistung eines clusterartigen Hochleistungscomputers
sowie die Programmierung geeigneter Anwendungen, die diese potentielle Leistung sinnvoll ausnutzen, keinesfalls einfach sind.
Glücklicherweise stehen die Anschaffungskosten sowie der Zeitaufwand für den Zusammenbau eines Clusters im positiven Verhältnis zu den oben genannten Nachteilen.
3.4
Die Clusterhardware
Wir haben oft genug erwähnt, dass Cluster sich von anderen High Performance Rechensystemen unterscheiden, weil man für ihre
technische Realisierung auf handelsübliche Hardwarekomponenten zurückgreift. Die einzelnen Rechenknoten eines Clusters sind
also genau genommen normaler PCs6). In der Abbildung 3.6 geben wir eine neue schematische Darstellung eines verteilten
3) RISC steht für Reduced Instruction Set Computer, und entspricht einer Prozessorarchitektur, die für die Ausführung einer beschränkten Anzahl von
Instruktionstypen konzipiert worden ist. Die dahinter liegende Idee ist die Menge an Transistoren und Schaltkreisen, die für die Ausführung jedes neuen
Instruktionssets notwendig sind, so niedrig wie möglich zu halten und auf diese Weise die Komplexität der Funktionsweise eines Mikroprozessors stark zu
reduzieren.
4) SMP (Symmetric Multi Processing) bezeichnet die Rechenarchitektur, die die Zusammenarbeit von zwei oder mehr CPUs innerhalb desselben Computers
möglich macht. Symmetrisch heißt hier: gleichwertige Prozessoren mit gleichen Speicherzugriffsrechten.
5) Die wohl bekanntesten Beispiele solcher Parallelbibliotheken sind PVM (Parallel Virtual Machine) und MPI (Message Passing Interface). Sie unterscheiden
sich zwar in vielen Details, basieren aber auf dem gleichen Konzept: Man erstellt - wie bei den üblichen sequenziellen Programmen- ein Programm, das dann
auf mehreren Computern ausgeführt wird. Die einzelnen Kopien des Programms differenzieren sich nach dem Start nur durch eine Zahl, den sog. Rang, der
von 0 bis zur Anzahl der Kopien minus eins läuft. Aufgrund des Rangs können die Programmkopien dann unterschiedliche Teile des Programms lösen. Die
hohe Akzeptanz, von der Cluster seit einigen Jahren profitieren, ist nicht zuletzt auf die starke Verbreitung dieses Programmierungsschemas zurückzuführen.
6) In den meisten Fällen verfügen jedoch die Rechenknoten über keine Aus- und Eingabegeräte wie Graphikkarte, Maus oder Tastatur. Weniger üblich ist die
Abwesenheit von Festplatten in den Knoten.
- 12 -
Rechensystems wieder. Es sind im Vergleich zum Schema auf Abbildung 3.5 zu dem Rechenknoten einige Komponenten dazu
gekommen, die bei einer genauen Analyse der Faktoren die zu der gesamten Rechenleistung eines Clusters beitragen, unbedingt
beachtet werden müssen. Wir geben hier nur eine kurze Beschreibung dieser Hardwarekomponenten (die allgemeine Funktion die
ser Bestandteile innerhalb eines Computers sind meistens gut bekannt) und konzentrieren uns später im Kapitel 6 auf ihre Rolle im
Bezug auf die tatsächlich erreichbare Leistung eines verteilten Rechensystems
DMA
NODE 1
NODE n
RAM
RAM
Level 2
Cache
Level 1
Cache
CPU
Register
Level 2
Cache
Level 1
Cache
CPU
Register
CPU0
CPU0
PIO
HDD
eth0
DMA
DMA
.....................
PIO
eth1
Level 2
Cache
Level 1
Cache
CPU
Register
CPU0
CPU0
PIO
PCI Bus/Daten Bus
myrinet
Level 2
Cache
Level 1
Cache
CPU
Register
HDD
Infiniband
eth0
DMA
PIO
PCI Bus/Daten Bus
eth1
myrinet
Infiniband
SWITCHED NETWORK
MYRINET
INFINIBAND
Abbildung 3.6: Schematische Darstellung eines Clusters aus der Hardwaresicht.
3.4.1
CPU
Der Hauptprozessor (Central Processing Unit, kurz CPU) stellt das Kernstück eines PCs dar. Die CPU steuert, regelt und
kontrolliert Arbeitsprozesse. Sie steht in ständigem Signalaustausch mit Bausteinen des Motherboards. Die CPU besteht, wie fast
jeder Mikroprozessor, aus integrierten Schaltungen, welche die unterschiedlichen Funktionseinheiten des Prozessors beinhalten.
CPUs weisen in der Regel zwei solche Funktionseinheiten auf: Zum einen, die sog. Verarbeitungseinheit EU (Execution Unit) und
zum anderen die Busverbindungseinheit BIU (Bus Interface Unit). Die EU ist zuständig für die Ausführung der Maschinenbefehle
und die Dekodierung derselben. Hauptaufgabe der BIU ist das Ausführen sämtlicher Busoperationen für die EU. Zu diesen
Einheiten gehören weitere wichtige Subelemente wie die Control Unit (CU), der Coprozessor, die Adress- und Datenbusse oder
die Arithmetic Logic Unit (ALU). Diese Komponenten lassen sich jedoch einheitlich in Verbindung mit einer bestimmten CPU
Architektur bringen, so dass wir uns nicht im Einzelnen um sie kümmern werden.
Im Allgemeinen wird die Geschwindigkeit eines Computersystems durch die Taktfrequenz seiner CPU definiert. Diese Frequenz
wird durch einen Oszillator, bestehend aus einem Quarz in einem kleinen Zinnbehälter, vorgegeben. Wird Spannung angelegt,
beginnt dieser mit einer gleichmäßigen Frequenz zu schwingen. Jede Anweisung, die der Prozessor ausführt, dauert eine bestimmte
Anzahl von Taktimpulsen. Wie viel Taktimpulse pro Sekunde der Taktgeber gibt, wird in Hertz angegeben (1 Megahertz = 1 Millon
Taktimpulse pro Sekunde).
3.4.2
Die CPU Register
Um auf wichtige Daten während der Ausführung eines Jobs schnell zugreifen zu können verfügt die Control Unit der CPU über
mehrere Speicherplätze innerhalb des Prozessors, die so genannten Register. Es gibt Befehlsregister, Register für Operanden und
Ergebnisse, Spezialregister, die z.B. für die Hauptspeicheradressierung zuständig sind oder ein Statusregister, mit dessen Hilfe
bestimmte Zustände nach Ausführung von Befehlen abgefragt werden können.
- 13 -
3.4.3
Level 1 – Cache oder First Level Cache
Im Cache eines Prozessors werden Daten gespeichert, auf die der Prozessor wiederholt zugreifen muss. Diese Daten können
entweder richtige Daten sein, oder auch Programmcode, der abgearbeitet werden muss. Aufgrund dieser Trennung wird der Level
1 - Cache meistens in zwei Bereiche aufgeteilt: Ein Cache für Daten und ein Cache für Programmcode. Der Level 1 – Cache wird
mit vollem Core Takt betrieben und seine typische Große rangiert zwischen 32 KB und 1 MB7).
3.4.4
Level 2 – Cache oder Second Level Cache
Der Level 2 – Cache ist die zweite Stufe des Cachespeichers. Er ist zwar langsamer als der L1 – Cache, aber immer noch schneller
als der Hauptspeicher. Er ist wesentlich größer als der L1 – Cache (zwischen 256 KB und 2 MB). Auch dort werden häufig
benötigte Daten zwischengespeichert. Der L2 – Cache wird abhängig vom Prozessor mit halben oder vollem Core Takt betrieben.
3.4.5
RAM
Random Access Memory. Das RAM ist der Arbeitspeicher (Hauptspeicher) eines Rechners, also der physikalische Ort, an dem
das Hauptsteuerprogramm (das Betriebssystem) eines Computers sowie der Ausführungscode und die Daten aller aktiven
Applikationen geladen und der CPU zur Verfügung gestellt werden. Da die Zugriffszeit für alle Speicherzellen sowohl beim Lesen
als auch beim Schreiben in etwa gleich ist, bezeichnet man das RAM als Speicher mit wahlfreiem Zugriff (daher “Random Access“).
Zurzeit werden hauptsächlich die sog. Double Data Rate RAM (DDR - RAM) Hauptspeichermodule im PC Bereich eingesetzt, eine
Speicherarchitektur die nicht nur doppelt so viele Daten pro Bustakt überträgt (verglichen mit der vorherigen SD-RAM Hauptspeicherarchitektur), sondern auch höhere Bustaktfrequenzen unterstützt. So kann z.B. DDR266 mit 133 MHz, DDR333 mit bis zu 166
MHz arbeiten. In Zusammenhang mit der Intel Xeon CPU Architektur besteht die Möglichkeit, so genannten RAMBUS Speicher
einzusetzen (auch RDRAM genannt), welcher einen Bustakt von mehr als 400MHz verträgt.
3.4.6
Bus Mastering und Direct Memory Access (DMA)
Während der Ausführung einer bestimmten Aufgabe findet am Computer eine beachtliche Menge an Kommunikationsaktivitäten
zwischen den Hardwarekomponenten statt. Für unsere Zwecke ist die Art und Weise, wie diese Kommunikation zwischen CPU,
Speicher, PCI Bus und Festplatte erfolgt, von großer Bedeutung. Aufgrund dessen beschäftigen wir uns kurz mit dem aktuellen
Kommunikationsmodell zwischen CPU und Hardwareperipherie.
Durch die schnellen Datenbusse (PCI, AGP, etc.) fließen pro Sekunde große Datenmengen. Über eine lange Zeit war es die Aufgabe
der CPU, den Transfer dieser Informationen zu kontrollieren. Der Prozessor agiert praktisch als Vermittler zwischen dem Betriebsystem und den spezifischen Hardwarekomponenten8). Um die CPU von diesen Aufgaben zu befreien und dabei die Multitasking Fähigkeiten der CPUs allgemein zu verbessern wurde das Konzept von Bus Mastering eingeführt. Die neuen Hardwarekomponenten,
die sog. Bus Masters, sind in der Lage, die Kontrolle über den Datenbus zu übernehmen und ihre spezifischen Aufgaben selbst zu
erledigen. Die notwendigen Kontrollfähigkeiten sind in den Chipsatz eingebaut, so dass die verschiedenen Anfragen zur Kontrollübernahme des Datenbusses problemlos erfolgen. Zurzeit ist Bus Mastering in der PC Welt meistens bei den Geräten für den PCI
Bus zu finden (Soundkarten, Netzwerkkarten, etc.), sowie bei IDE/ATA Devices (Festplatten, DVD Laufwerke, etc).
Im Fall der IDE/ATA Devices ist die Bus Mastering Fähigkeit solcher Laufwerke eher unter den Namen Ultra DMA bekannt. DMA
steht für Direct Memory Access und bezeichnet das Datentransferprotokoll, bei dem das beteiligte Gerät seine Informationen
direkt in den Hauptspeicher schreibt bzw. aus dem Speicher liest, ohne jegliche Beteiligung vom Prozessor. Ultra DMA ist eine
Form von Bus Mastering, denn während diese DMA Transfers stattfinden übernimmt das Laufwerk die Kontrolle über den IDEDatenbus. Verschiedene DMA Modi sind der IDE/ATA Schnittstelle bekannt, standardmäßig beherrschen jedoch heutige Festplatten
mindestens den so genannten UDMA/100 Modus.
Während der Bustakt (der Takt des Motherboards, mit dem die CPU auf den Speicher zugreifen kann) zurzeit bei mindestens 133 MHz liegt, arbeiten CPUs
mit einem Vielfachen dieses Taktes. Der Multiplikator, mit dem der Bustakt vervielfacht wird, ist entweder in der CPU fest eingestellt oder lässt sich auf dem
Motherboard manuell einstellen.
7)
Bis zur Mitte der 90er Jahre war das sog. Programmed I/O (PIO) Protokoll die einzige Methode um Daten zwischen der CPU und anderen Peripheriegeräten
zu transportieren. Dies ist eine Technik, bei der sich die CPU direkt um die Kontrolle des Datentransfers zwischen den Hardwarekomponenten kümmert.
Diese Technik funktioniert sehr gut bei langsamen Geräten wie Tastaturen, Diskettenlaufwerken oder Modems, nicht aber bei Komponenten wie Festplatten
oder CD-ROM Laufwerken, die auf hohe Datentransferleistungen angewiesen sind. PIO provoziert eine starke Ausbremsung der Systemperformance, denn
die CPU wird von ihren spezifischen Aufgaben abgelenkt wenn Lese-Schreibereignisse auf solche schnellen Komponenten erfolgen. PIO ist nicht in der Lage,
mit der Leistung der heutigen Festplatten mitzuhalten. Trotzdem werden die PIO Modes von den meisten PC Systemen nicht nur aus Kompatibilitätsgründen
mit alter Hardware weiter unterstützt, sondern auch weil PIO als letzte Grundlage gilt, wenn Treiberprobleme oder Softwarefehler Schwierigkeiten bei Ultra
DMA Zugriffen verursachen.
8)
- 14 -
3.4.7
Das Verbindungsnetzwerk
Das Verbinden mehrerer Computer zu einem Clustersystem verlangt die Anwesenheit von mindestens einer Netzwerkschnittstelle
NIC9) pro PC und einem bzw. mehreren Netzwerkswitches um den Informationsaustausch zwischen den PCs zu beschleunigen.
Obwohl es natürlich andere Möglichkeiten für die Realisierung der Kommunikation zwischen den Knoten gibt, hat sich diese
Switched Netzwerktopologie in der Clusterwelt als Standard durchgesetzt, vor allem wegen ihrer hohen Skalierbarkeit (zusätzliche
Knoten lassen sich vergleichsweise sehr einfach in eine vorhandene Clusterstruktur einbinden).
Je mehr Rechenknoten man an einen Cluster einbinden will, desto wichtiger wird auch das Verbindungsnetzwerk. Oft
steckt in diesem die Hälfte der Gesamtkosten eines Systems, da man sich als Ziel gesetzt hat, die Prozessorleistung optimal
auszunutzen. Bei einer falschen Wahl der Netzwerktechnik würden die schnellen Prozessoren die meiste Zeit nur auf Daten von
Ihren Nachbarprozessoren warten, anstatt zu rechnen. Wie wir später sehen werden (s. §4.6) gibt es zwei Größen, die bei der
Leistungsbestimmung sämtlicher Hardwarekomponenten, nicht nur der Netze, ausschlaggebend sind: Der Durchsatz, meist in Bit
pro Sekunde gemessen, und die Latenzzeit, in Mikrosekunden (µs) gemessen.
Der Begriff Durchsatz, auch Bandbreite genannt, bezieht sich hier auf die Menge an Daten, die das Netz zwischen zwei
Netzwerkknoten in der Sekunde transportieren kann. Die Latenzzeit gibt die Zeit an, die vom Aufruf der Sendefunktion bis zur
Rückkehr der Empfangsoperation für eine kurze Nachricht vergeht. Während gewöhnliche Netze wie Ethernet oder Fast-Ethernet
mit einem theoretischen Durchsatz von 10 bzw. 100 Mbits/s und einer Latenzzeit von etwa 250 bis 150 µs die meist benutzten
Netzwerkschnittellen sind, findet man spezielle Netzwerktechnologien wie SCI oder MYRINET, die für die Bearbeitung paralleler
Applikationen genau abgestimmt sind. Diese zeichnen sich durch einen ausgesprochen hohen Durchsatz von bis zu 4 Gbits/s
(Gigabits pro Sekunde) und eine niedrige Latenzzeit von weniger als 10 µs aus.
Solch gewaltige Unterschiede sind teils in der Hardware zu suchen, teils aber auch in der Software. Da für paralleles Rechnen
nur geringe Distanzen überbrückt werden müssen (alle Rechner stehen normalerweise in einem Raum), lässt sich die Hardware
zu diesem Zweck optimieren, was sich zu Gunsten der höheren Bandbreite entwickelt. Die Unterschiede in der Latenzzeit lassen
sich eher auf der Softwareebene verstehen: Auf Ethernet setzt praktisch immer TCP/IP als Protokollstack auf. Die Abarbeitung des
gesamten Stacks verbunden mit betriebssystembedingten Aktivitäten und Interrupt-Behandlung kostet dabei viel CPU-Zeit. Eine
Lösung dieses Problems besteht darin, TCP/IP und das Betriebssystem zu umgehen. Es ist dazu notwendig, Teile der Hardware für
Anwendungen (und Bibliotheken) direkt in den Benutzeradressraum einzubetten. Die wohl bekanntesten Netze, die diese Technik
anwenden, sind die oben erwähnten SCI (Scalable Coherent Interface) und MYRINET. SCI ist durch IEEE 1596 standardisiert,
während MYRINET dem ANSI/VITA 26-1998 Standard entspricht. Sowohl für SCI als auch für MYRINET gibt es momentan jeweils
nur einen Anbieter. Die Schwedische Firma Dolphin für SCI und die US-Amerikanische Firma MYRICOM für MYRINET. Genau diese
fehlende Konkurrenz zusammen mit den geringen Stückzahlen, die im Vergleich mit Standardnetzwerktechnologien verkauft
werden, haben leider sehr hohe Preise zur Folge. Eine wichtige Alternative zu diesen Netzwerktechnologien wird in die Zukunft die
sog. INFINIBAND NetzwerkStandard darstellen, welcher nicht nur einen offenen Standard ist sondern einen besseren Preis-/Leistung
Verhältnis im Vergleich zu SCI und MYRINETaufweist. Zurzeit wird die INFINIBAND Hardwaremarkt von der US-Unternehmen
MELLANOX dominiert.
9)
Die Bezeichnung NIC (Network Interface Card) wird regelmäßig eingesetzt um Netzwerkschnittstellen / Netzwerkarten in kompakter Form zu benennen.
- 15 -
KAPITEL 4 - Performancebestimmung verteilter Rechensysteme
Eine der ersten Fragen, mit denen man sich während des Entwurfs und Aufbaus eines Clusters beschäftig, ist natürlich die nach
der Rechenleistung, welche sich bei dem System erwarten lässt. Performance ist in den meisten Fällen die Hauptmotivation für die
Anschaffung eines Clusters, und aus diesem Grund ist die Messung der Rechenleistung und der Vergleich zwischen verschiedenen
einsetzbaren Architekturen und Clusterkonfigurationen von relevanter Bedeutung.
Um das Problem der Bestimmung der Rechenleistung von Parallelrechnern richtig verstehen zu können müssen wir weiterhin auf
grundlegende Begriffe der theoretischen Informatik zurückgreifen. Erst dann können einige wichtige Messmethoden sinnvoll
erläutert werden und die entsprechenden quantitativen Aussagen über die Systemperformance eines gegebenen Systems liefern.
4.1
Parallelisierungsgrad
Ein Paralleler Algorithmus kontrolliert die Durchführung eines Programms, welches seinerseits die simultane Ausführung von zwei
oder mehr Prozessen auf zwei oder mehr CPUs steuert. Drei wichtige Parameter, die die Qualität eines parallelen Algorithmus
bestimmen sind der Parallelisierungsgrad, der Speedup und die Effizienz:
Der Parallelisierungsgrad eines Algorithmus ist die Anzahl P der theoretisch maximal, parallel ausführbaren Operationen.
Beispielsweise hat die Addition zweier n – komponentiger Vektoren den Parallelisierungsgrad P=n, da die n Additionen
unabhängig voneinander und somit zeitgleich ausgeführt werden können.
4.2
Speedup und Effizienz
Zur Charakterisierung der Leistungsfähigkeit eines parallelen Programms wird meist der Speedups verwendet. Um diesen Begriff
besser zu verstehen betrachten wir die Zeit TP die man benötigt, um die Lösung eines gegebenen Problems mit dem schnellsten
bekannten seriellen Algorithmus auf einem Prozessor zu erhalten und mit TP die Zeit, die man zur Lösung des gleichen Problems
auf dtem Parallelrechner mit N solcher Prozessoren benötigt. Der Speedup eines parallelen Algorithmus ist
S=
TS
TP
(4.1)
Ein Wort müssen wir noch zu der genauen Bedeutung von Ts sagen, also der Zeit die benötigt wird, um den schnellsten bekannten
seriellen Algorithmus auf einem Prozessor durchzuführen. Man kann hier einen Prozessor aus dem parallelen Computer nehmen
oder wir können die schnellste sequenzielle Maschine benutzen, die zu dem Zeitpunkt des Vergleichs auf dem Markt existiert.
Letzteres wäre in der Tat das genaueste Verfahren um die Leistung des parallelen Algorithmus zu messen, ist jedoch in der Praxis
nicht ohne weiteres machbar. Der schnellste Prozessor auf dem Markt steht nicht jedem zur Verfügung, so dass eine Messung
unter diesen Bedingungen in der Regel nicht durchführbar ist.
Eine leicht modifizierte Definition des Speedups ist folgende: Die von dem parallelen Algorithmus benötigte Laufzeit auf einem
Prozessor T1 geteilt durch die Laufzeit TP desselben Algorithmus auf N Prozessoren:
S=
Gewöhnlich gilt T1 ≠ TS meistens ist T1 ≥ TS
T1
TP
(4.2)
Eng verknüpft mit der Definition des Speedup ist die Effizienz eines parallelen Programms. Die Effizienz eines parallelen
Algorithmus bei einer Berechnung mit N Prozessoren ist
S
N
e=
wobei S durch die Beziehung (4.1) gegeben ist und für e Definitionsgemäß e ≤1gilt.
(4.3)
Die Effizienz lässt sich folgendermaßen interpretieren: Ist e nahe bei 1, so ist der Parallelrechner durch den verwendeten
Algorithmus gut genutzt. Im Idealfall ist ein Algorithmus vollständig parallelisierbar. Dann gilt e=1 und man hat die ideale
1
Beschleunigung im Vergleich zur seriellen Berechnung, d.h. S=P. Das Problem kann somit durch den Algorithmus in der Zeit ⋅ T1
P
10)
gelöst werden .
Applikationen mit solch hohem Effizienzgrad werden EPC Applikationen genannt (EPC steht für „Embarrassingly Parallel Computations“). Diese
Applikationen weisen einen sehr hohen Parallelisierungsgrad n auf, so dass ihre absolute Effizienz von Rechensystem unabhängig ist.
10)
- 16 -
In aller Regel ist aber e < 1, da nicht 100% eines Algorithmus parallelisierbar ist und im Allgemeinen Daten zwischen den Prozessoren
auszutauschen sind, so dass wegen der entstehenden Kommunikation auch Zeit benötigt wird.
Ein kleines numerisches Beispiel zeigt deutlich die Beziehung zwischen den beiden Größen: Wenn der schnellsten bekannten
serielle Algorithmus z.B. 8 Sekunden für die Berechnung braucht, also TS = 8, der parallele Algorithmus jedoch 2 Sekunden auf 5
Prozessoren für die gleiche Berechnung benötigt, dann gilt:
S = TS /Tp = 8/2 = 4
e=S/N = 4/5 = 0.8 = 80%
und der parallele Algorithmus weißt einen Speedup von 4 bei der Verwendung von 5 Prozessoren auf, sowie eine Effizienz von
80%.
In Abbildung 4.1 haben wir die theoretische Laufzeit für ein Parallelprogramm, das auf
mehreren Prozessoren durchgeführt wird, gegen die Anzahl der eingesetzten CPUs aufgetragen. Die helle Kurve wird aus den
theoretischen, die dunkle Kurve aus der tatsächlich gemessenen Laufzeitwerten gewonnen.
1,2
real
1
theoretisch
Laufzeit
0,8
0,6
0,4
0,2
0
0
2
4
6
8
10
12
CPU Anzahl
Abbildung 4.1: Theoretische gegen gemessene Laufzeitwerte für ein typisches Parallelprogramm.
Wie die Abbildung zeigt befindet sich ein Punkt auf der Effizienzkurve, ab dem die Addition von weiteren Prozessoren keine
Reduzierung der Laufzeit mehr mit sich bringt. Sehr oft ist sogar auf der Effizienzkurve einen Punkt zu finden, ab dem der Einsatz
zusätzlicher CPUs eine langsamere Ausführungszeit zur Folge hat.
Oft ist aufgrund der Problemgröße eine sequentielle Berechnung nicht mehr möglich, so
dass Ts oder T1 nicht vorliegen. In solchen Fällen macht der inkrementelle Speedup
Laufzeit auf P2 P
r ozessoren
Laufzeit auf P P
r ozessoren
Si (N ) =
(4.4)
eine entsprechende Aussage über die Qualität des parallelen Verfahrens (etwas mehr dazu ist im Kapitel 5 unter Superlineare
Speedups zu finden)
- 17 -
4.3
Faktoren, die den Speedup auf Applikationsebene limitieren
Unter den Hauptfaktoren, die das Erreichen eines höheren Speedups stark beeinträchtigen, finden wir den sog. Software
Overhead. Mit dem Begriff will man der Tatsache Rechnung tragen, dass im Allgemeinen die Anzahl der zu bearbeitenden
Programminstruktionen bei Parallelprogrammen höher ist als die des sequentiellen Pendants.
Der Speedup wird ebenfalls durch die Performance der langsamsten Komponente, die an der Berechnung teilnimmt, entscheidend
beeinflusst. Man spricht in diesem Zusammenhang von Load Balancing und versucht dann zu gewährleisten, dass die Gesamtlast
auf alle Recheneinheiten gleichmäßig verteilt wird.
In dem ungünstigen Fall, dass die Kommunikationsvorgänge zwischen Prozessen und den rein rechnerischen Aufgaben eines
Parallelprogramms sich nicht überlappen, braucht man extra Zeit, um die direkte Kommunikation zwischen den Prozessoren zu
ermöglichen, also den Anschluss zu finden. Diese zusätzliche Zeitspanne, bei der die Prozessoren tatsächlich nichts rechnen, wird
negative Auswirkungen auf den Speedup haben. Ziel des Programmierers beim Entwurf eines parallelen Algorithmus soll also sein,
die relative Menge an Rechenarbeit, die zwischen Kommunikationsakten bzw. Synchronisationsprozessen erfolgt, so groß wie
möglich zu machen. Man nennt diese Eigenschaft die Granularitätsgröße11) eines Algorithmus.
4.4
Das Gesetz von Amdahl
Die Idee, eine Computerberechnung durch die Implementierung eines parallelen Algorithmus zu beschleunigen, ist alles andere als
neu. Zu Beginn der Ära der Digitalcomputer gab es bereits Anwendungen, die nach hoher Rechenleistung verlangten. IBM hatte
damals als Lösungsansatz gleich die Nutzung eines Parallelenrechners für dieses Problem in Erwägung gezogen. Die Forscher bei
IBM fanden jedoch ziemlich rasch heraus, dass die Geschwindigkeit bei der Ausführung einer Parallelapplikation durch den Einsatz
zusätzlicher Prozessoren nicht ohne weiteres steigen kann. Diese Beobachtungen wurden durch das sog. Gesetz von Amdahl
festgehalten (Gene AMDAHL 1967).
Um auf die explizite Form des Gesetzes von Amdahl zu kommen müssen wir zuerst eine Definition der Geschwindigkeit eines
Programms geben. Aus der Physik kennen wir die Definition der Durchschnittsgeschwindigkeit als der Länge der durchgefahrenen
Strecke geteilt durch die gesamte Zeit, die für die Fahrt benötigt wurde. Bei Computern führt man eine Arbeit durch, anstatt eine
Distanz zu überbrücken, so dass die Geschwindigkeit eines Algorithmus sich sinnvoll als der Quotient der verrichteten Arbeit W
und der dafür verwendeten Zeit T definieren lässt:
W
T
R=
(4.5)
R bezeichnet man als die Geschwindigkeit oder Geschwindigkeitsrate der Applikationsausführung.
Sei nun TS die Zeit, die der Prozessor benötigt um den seriellen Anteil eines Programms durchzuführen (die Teile des Programms,
die sich ausschließlich eines nach dem anderen bearbeiten lassen) und TP die entsprechende Zeit, die der gleiche Prozessor braucht
für die Ausführung von Programmteilen, die parallel durchgeführt werden können. Dann ist die Gesamtdurchführungszeit eines
Programms wie folgt gegeben:
T = T +T
(4.6)
W
R(1) =
TS + TP (4.7)
S
P
und (4.5) lässt sich wie folgt umschreiben.
Die (1) verweist auf die Anzahl von Prozessoren, die an dem Problem rechnen.
Definieren wir α als die Mindestzeit für die Ausführung des sequenziellen Anteils eines Programms und (1 - α) als den
verbleibenden parallelisierbaren Anteil dieses Programms, dann gilt
TS
T
= S
TS + TP
T
α=
(4.8)
und aus dieser Beziehung ebenfalls
Ein Programm ist dann stark oder besser gesagt grob granular, wenn die notwendige Zeit für Kommunikationsakte zwischen Prozessen sehr klein ist im
Vergleich mit der Zeit, welche die Prozessoren für Berechnungen aufwenden. Der negative Effekt der Interprozesskommunikation auf den Speedup wird also
reduziert wenn die Größe der Granularität steigt.
11)
- 18 -
(1 − α ) = 1 − TS
T − TS
T
T
=
(4.9)
Wenn N Prozessoren für die Durchführung des parallelen Anteils eingesetzt werden, erhalten wir für die Geschwindigkeitsrate des
Programms im idealen Fall:
W
TS + (TP N )
R( N ) =
(4.10)
Der Geschwindigkeitsgewinn oder Speedup S der Applikation durch den Einsatz von N Prozessoren lässt sich also durch den
Quotienten R(N)/R(1) ausdrücken (Gl.(4.7) und (4.10)):
S=
R( N ) W (TS + (TP N ))
=
R(1)
W TS + T P
Wir eliminieren W und benutzen Gleichung (4.6) um die obige Gleichung etwas umzuformen
TS + T p
T
=
TP
T
TS +
TS + P
N
N
S=
(4.11)
Aus (4.6) folgt TS = T - TS und wegen (4.8) gilt α * T = TS, so dass sich TP in TP = T - α * T = T (1 - α) umschreiben lässt. Wir setzen
diese zwei Beziehungen in (4.11) und erhalten
T
T
=
T (1 − α )
(1 − α ) 
T ⋅α +
T α +

N
N 

1
=
(
1−α)
α+
N
S(N ) =
(4.12)
Die Gleichungen (4.11) und (4.12) stellen zwei unterschiedliche mathematische Ausdrücke des berühmten Gesetzes von Amdahl
dar, wobei die Form bei (4.12) in der Literatur häufiger vorkommt.
Um die Bedeutung dieser Beziehungen besser zu verstehen stellen wir uns folgende Situation vor: Wir haben ein Programm, das
aus 100 Instruktionen besteht. Jede Instruktion braucht zur Durchführung immer die gleiche Zeit. Wenn 80 dieser Instruktionen
sich parallel ausführen lassen (TP = 80) und 20 Instruktionen sequentiell durchgeführt werden müssen (TS = 20), dann ergibt sich
beim Einsatz von 80 Prozessoren (N = 80) aus (4.11)
S (80) = 100 / (20 + 80/80) = 100 / 21 < 5
d.h. ein Speedup von nur 5 ist für dieses Problem zu erreichen, unabhängig davon wie viele Prozessoren für diese Berechnung
eingesetzt werden.
In der Form (4.12) lässt sich aus dem Amdahl Gesetz noch mehr Information herausholen. Stellen wir uns jetzt vor, dass wir einen
Algorithmus haben dessen sequentieller Anteil nur α = 0.01 beträgt. Damit ist mit 10 Prozessoren nach (4.12) höchstens ein
Speedup
S=
1
≈ 9.17 erreichbar. Mit 100 Prozessoren kann aber höchstens noch
0.109
S=
1
≈ 50 .25 erzielt werden. Für große Prozessorenzahl N wird eine Sättigung erreicht (Abbildung 4.1), denn es gilt
0.0199
1
1
=
P →∞ α + (1 − α )/ N
α
lim S = lim
N →∞
- 19 -
Speedup
150
α=0
100
50
α=0.01
P
50
100
150
Abbildung 4.2: Maximal erreichbarer Speedup nach dem Gesetz von Amdahl
Für den Extremfall α = 0, d.h. ein Programm ohne sequentiellen Anteil, wäre S(N) = N, also der Idealfall. Ist dagegen α = 1, d.h.
das Programm weist überhaupt keinen Parallelismus auf, so ist S(N) = 1, unabhängig davon wie viele Prozessoren eingesetzt
werden. All diese Tatsachen lassen uns begreifen was das Gesetz von Amdahl tatsächlich ausdrücken will:
Unabhängig von der Anzahl der Prozessoren, die an der Ausführung eines parallelen Algorithmus gleichzeitig arbeiten, wird der
erreichbaren Speedup S(N) durch die Anzahl der Programminstruktionen, die sequentiell abgearbeitet werden müssen, effektiv
eingeschränkt.
Da fast jedes Parallelprogramm etwas sequentiellen Code enthält, könnte man ja zu dem traurigen Schluss kommen, dass es in
keinem Fall eine sinnvolle Investition ist, Parallelcomputer mit einer hohen Anzahl von Prozessoren zu bauen, da diese nie einen
brauchbaren Speedup erreichen werden. Glücklicherweise gibt es zahlreiche wichtige Anwendungen, die parallelisiert werden
können (oder müssen) und eine sehr kleine sequenzielle Fraktion aufweisen (α < 0.001). Einige davon fallen sogar in der Kategorie
derr EPC Applikationen (s. 4.2).
4.5
Latenz und Bandbreite
Die ersten Erkenntnisse, die wir aus der Diskussion des Gesetzes von Amdahl gewonnen haben, lassen uns zu Recht vermuten,
dass für uns das Problem der Performancebestimmung eines Clustersystems von entscheidender Relevanz ist. Ein für uns
geeignetes Performancemodell muss in der Lage sein, etwas kompliziertere Systemzusammenhänge zu beschreiben, als es
das schlichte Gesetz von Amdahl tatsächlich kann. Aus praktischen Gründen darf es aber nicht den Komplexitätsgrad eines
wissenschaftlichen Modells aus der theoretischen Informatik erreichen.
Um das Problem der Performancebestimmung erstmals angreifen zu können, müssen wir zwei sehr wichtige Begriffe klar
definieren: Latenz und Bandbreite. Diese haben wir im Zusammenhang mit dem Kommunikationsnetzwerk bereits im Kapitel 3
angedeutet, wir möchten sie hier aber etwas allgemeiner betrachten.
Stellen wir uns also vor, dass eine beliebige Hardwarekomponente bestimmte Information von einer zweiten Komponente
benötigt, damit sie an einem laufenden Job weiter arbeiten kann bzw. diesen starten kann. Die erste Komponente sendet
dementsprechend ein Signal über den Kommunikationskanal zwischen den beiden Komponenten, welches die zweite
Komponente über die Art des Datentransfers informiert. Die zweite Komponente stellt dann die verlangten Daten der ersten
Komponente bereit.
Die minimal mögliche Zeitspanne tL zwischen dem Senden des Signals und dem Moment, in dem die Daten tatsächlich zur
Verfügung stehen, wird als Latenzzeit bezeichnet. Die Bandbreite B bezeichnet hingegen die maximale Datenmenge, die in einer
Sekunde über den Kommunikationskanal transferiert werden kann, gemessen ab dem Zeitpunkt, an dem der Informationstransfer
- 20 -
tatsächlich angefangen hat. Die Latenzzeit wird in Zeiteinheiten gemessen (typisch Sekunden bis Mikrosekunden), während die
Bandbreite in Megabyte bzw. Gigabyte pro Sekunde angegeben wird.
Eine sehr wichtige Eigenschaft dieser zwei Größen ist es, dass sie eine ausreichende Charakterisierung der Leistung beliebiger
Hardwaresubsysteme ermöglichen. Wir wollen daher während des nächsten Abschnitts ausschließlich diese beiden Größen als
Basis für die Entwicklung eines Modells benutzen, bei dem die relevanten Züge der Clusterarchitektur erhalten bleiben und
nebenbei die Bestimmung der Performance von solchen Clustersystemen vereinfacht wird. Dieses Vorgehen wird eine klare
Rechtfertigung später finden, wenn wir uns mit der Erstellung des mathematischen Modells für das Konfigurationsproblem
beschäftigen werden.
4.6
Ein einfaches Performancemodell
Als Ausgangspunkt bei der Entwicklung eines solchen Performancemodells wollen wir die Ausführungszeit T einer Applikation
definieren und diese als zu bestimmende Größe betrachten. T wird also in diesem Zusammenhang eine Funktion der Latenzzeit tL
und der Bandbreite B sein. Somit lässt sich eine erste Beziehung, die das Problem beschreibt, in allgemeiner Form schreiben als
T = f ( tL, B)
(4.13)
Als nächstes definieren wir die gesamte Ausführungszeit eines parallelen Programms auf einer Multiprozessormaschine als die
Zeitspanne, die zwischen dem Starten der ersten Programminstruktion auf dem ersten Prozessor bis zum Ausführen der letzten
Programminstruktion auf dem letzten Prozessor vergeht. Während der Programmausführung ist jeder Prozessor eines Clusters
entweder am Rechnen, versucht mit einem anderen Prozessor zu kommunizieren oder befindet sich im Leerlauf. Wir bezeichnen
i
i
i
diese Intervalle entsprechend als TRe ch , TKomm und Tleer .
i
Die Rechenzeit ( TRe ch ) ist die Zeit, in der das parallele Programm ausschließlich CPU Aktivität generiert. Wenn (4.13) gelten soll,
hängt die Dauer der Zeit in erste Linie von tL und B12) ab. Die Latenzzeit einer CPU lässt sich mit der minimalen Zeit verknüpfen
die notwendig ist, um eine einzige CPU-Instruktion durch die EU- und BIU-Einheiten der CPU zu evaluieren und mit ihrer
Durchführung zu starten (s. 3.4.1).
Die erreichbare Bandbreite steht hingegen mit der Kommunikation zwischen der CPU und dem Memory Subsystem in Verbindung,
sie hängt also direkt von der Geschwindigkeit ab, mit der die Daten von First-, Second Level Cache und Hauptspeicher zur CPU
transportiert werden können und umgekehrt.
i
Die Kommunikationszeit eines Algorithmus TKomm
bezeichnet die Zeitspanne, in welcher der Algorithmus sich mit Sende- und
Empfangsoperationen von Daten beschäftigt. Wir müssen zwischen zwei Typen von Kommunikationsvorgängen in einem
Cluster unterscheiden: Interprozessorkommunikation und Intraprozessorkommunikation. Bei der Interprozessorkommunikation
lokalisieren sich die Sende- und Empfangakte auf unterschiedliche Prozessoren. Diese Art der Kommunikation wird immer dann
auftreten, wenn der parallele Algorithmus einen Job pro Prozessor startet. Bei der Intraprozessorkommunikation finden zwei
Kommunikationsvorgänge innerhalb desselben Prozessors statt (Kommunikationsakte zwischen den zwei Prozessoren eines Dual
Prozessorssystems können auf Grund der schnellen Busverbindung ebenfalls als Intraprozessorkommunikation behandelt werden).
In Clusterumgebungen, wo die Rechenknoten unter normalen Umständen über Ethernet kommunizieren, ist natürlich die Intraprozessorkommunikation viel schneller als die Interprozessorkommunikation.
Wie bereits im Abschnitt 3.4.7 angedeutet, kann die Netzwerkkommunikation zwischen zwei Prozessoren ebenfalls durch die
Latenzzeit tL und die Bandbreite der vorhandenen Netzwerkinfrastruktur, welche die zwei Prozessoren verbindet, in ausreichender
Form beschrieben werden, so dass die Funktion (4.13) hier ebenfalls Gültigkeit findet.
Die letztere der oben erwähnten Zeitspannen, nämlich die Leerlaufzeit (TLeer) ist in ihrer Bedeutung leicht nachvollziehbar, jedoch
in der Regel schwierig zu bestimmen, weil sie mit zahlreichen Faktoren verknüpft ist. Ein Prozessor kann sich im Leerlauf befinden
weil er zu dem gegebenen Zeitpunkt keine Instruktionen oder keine Daten zur Bearbeitung bekommen hat. Diese Situationen
sind entweder softwarebedingt (die Anordnung der Programminstruktionen kann die Länge der Leerlaufzeitspanne entscheidend
beeinflussen), oder entstehen durch die begrenzte Leistung von bestimmten Hardwarekomponenten (mehr dazu im Kapitel 6).
Wir können jetzt die gesamte Ausführungszeit T auf zwei Arten definieren: Als die Summe der Rechen-, Kommunikations- und
Leerlaufzeiten bei einem bestimmten Prozessor j, also
j
J
T = TRej ch + TKomm
+ Tleer
Andere Faktoren wie die Problemgrösse, also die Anzahl von Instruktionen, die einen Algorithmus bilden, sowie der Anzahl von Jobs bzw.
Unterprozessen, die gestartet werden müssen, spielen sicherlich dabei keine so unbedeutende Rolle. Wir werden jedoch diese Faktoren nicht in ihre tiefe
Bedeutung berücksichtigen, denn ansonsten würden wir auf keinen Fall auf ein einfaches Modell stoßen können.
12)
- 21 -
oder als die Summe dieser drei Zeitspannen über alle Prozessoren geteilt durch die Anzahl P der vorhandenen Prozessoren:
T=
1
(TRe
P
T=
1  P −1 i
 ∑ TRe
P  i =0
ch
+ TKomm + Tleer )
ch
P −1
P −1
i
i 
+ ∑ TKomm
Tleer

∑
i =0
i =0

Die letzte Definition ist etwas nützlicher, denn es ist natürlich einfacher, die gesamte Rechen- und Kommunikationszeit eines
parallelen Algorithmus zu bestimmen, als die Zeiten für Rechen- und Kommunikationstätigkeiten auf einzelnen Prozessoren zu
messen.
Aus dem oben Gesagten lässt sich deutlich erkennen, dass das Performanceproblem sich als ein Kommunikationsproblem
interpretieren lässt, bei dem die Geschwindigkeit des Informationsaustausches eine wesentliche Rolle spielt. Der Vorteil bei
einer solchen Interpretation ist, dass wir in der Lage sind, ein sehr einfaches Kommunikationsmodell zu bilden, das mit nur zwei
Parametern für die Beschreibung des Problems auskommt: Die uns bereits bekannte Latenzzeit tL, also die notwendige Zeit, um
die Kommunikation zwischen zwei Prozesse erstmals starten zu können, und die sog. Transferzeit pro Wort tW (typisch vier Byte
Länge), welche durch die Bandbreite des Kommunikationskanals, der die zwei Prozesse verbindet, bestimmt wird. Somit schreiben
wir die Funktion (4.13) wie folgt um:
(
)
T = f t L , tW
(4.14)
Die Zeitfunktion T hat nun tatsächlich zwei Komponenten und ihre Form kann auf einfache Weise bestimmt werden.
}
T = Zeit
}
tW = Transferzeit pro Word
tL = Latenz
L = Nachrichtengröße
Abbildung 4.3: Einfaches Modell für Kommunikationszeit. Man hat hier die Zeit gegen die Größe der gesendeten Nachrichten in
Bytes aufgetragen. Die Steigung der Geraden entspricht der Transferzeit pro Wort und der y-Achsenabschnitt stellt die Latenzzeit
dar.
In der Abbildung 4.3 lässt sich ablesen, dass die benötigte Zeit um ein Signal der Länge L zu schicken durch die folgende
Beziehung gegeben ist:
T = tL + tw L
Diese einfache Beziehung eignet sich für die Bestimmung von
deswegen wird sie uns bald wieder begegnen.
TRei
ch
und
i
TKomm
(4.13)
in zahlreichen Hardwarekonfigurationen und
Die Tabelle 4.1 auf der nächsten Seite zeigt noch eine Liste von den auf verschiedenen Architekturen gemessenen Werten für
tL und tW. Aufgrund der kontinuierlichen Entwicklung und Verbesserung von Hardwarekomponenten lassen sich diese Werte
natürlich nur mit Vorsicht genießen. Man kann trotzdem dabei erkennen wie stark die Schwankungen in den Werten für tL und tW
sind. Wie erwartet, weisen verschiedene Systeme deutlich unterschiedliche Performanceeigenschaften auf.
Maschine
tL
tL
IBM SP2
40
0.11
Intel DELTA
77
0.54
Intel Paragon
121
0.54
Meiko CS-2
87
0.08
nCUBE-2
154
2.4
Thinking Maschines CM-5
82
0.44
1500
5.0
Workstations über Ethernet
Tabelle 4.1: Näherungswerte für die Parameter tL und tW auf einigen Parallelenmaschinen, gegeben in Mikrosekunden (µsec).
- 22 -
KAPITEL 5 - Performancebestimmung in der Praxis
In den letzten Abschnitten haben wir wichtige Hintergrundinformationen behandelt, so dass wir jetzt in der Lage sind einige der
oft eingesetzten Performance Messmethoden zu besprechen. Die beschriebenen Methoden sind teilweise direkt aus theoretischen
Ergebnissen abgeleitet worden, andere dagegen folgen einem vollkommen praktischen Ansatz.
5.1
Performancebestimmung nach der Methode des sequentiellen Anteils
Die Gleichung (4.12) lässt sich nach α auflösen, somit ergibt sich
1 S(N ) −1 N
1−1 N
α=
(5.1)
Der so erhaltene Wert von α ist nützlich weil die Gleichung (4.11) für den Speedup einen stark idealisierten Fall beschreibt, nämlich
dass alle Prozessoren a priori genau gleich viel rechnen, also ein perfektes „Load Balancing“ vorliegt. Aus diesem Grund lassen sich
eventuell vorhandene Probleme auf Software- bzw. Hardwareebene nicht unmittelbar aus dem Speedup bzw. aus der Effizienz
identifizieren. Betrachten wir die Ergebnisse auf Tabelle 5.1.
Hätten wir die Werte für α nicht mittabelliert, könnten wir praktisch nicht ausmachen wie gut oder schlecht die Ergebnisse für
S und e sind. Warum z.B. sinkt die Effizienz ständig? Da α fast konstant bleibt, können wir schließen, dass dieses Verhalten sehr
wahrscheinlich auf eine beschränkte Parallelisierbarkeit der Applikation zurückzuführen ist. Würden dagegen die erhaltenen α
Werte ständig und stetig wachsen, erhielten wir dann ein Zeichen dafür, dass die Granularitätsgröße der Applikation zu klein ist.
N
Speedup (S(N))
Effizienz (e)
α
2
1.95
97
0.024
3
2.88
96
0.021
4
3.76
94
0.021
8
6.96
87
0.021
Tabelle 5.1: Werte für S(N), e und α in Abhängigkeit von N:
5.2
Theoretische Peakperformance
Dieser Performancewert wird einfach durch die Summe der maximalen Leistung, die eine bestimmte Systemkomponente rein
theoretisch erreichen kann, definiert. Zum Beispiel, für den Fall wissenschaftlicher Applikationen, in der die CPU Leistung eine
wesentliche Rolle spielt, kann dies durch die folgende Beziehung ausdruckt werden:
P = N * C * F * R
(5.2)
P ist hier die addierte CPU Performance, N die Anzahl von Knoten, C die Anzahl von CPUs pro Knoten, F die Anzahl von
Floatingpointoperationen per Clock Takt, und R die Clock Rate (gemessen in Zyklen pro Sekunde). P wird typischerweise in
Millionen von Floatingpointoperationen pro Sekunde (MFlop/s) oder in Milliarden von Floatingpointoperationen pro Sekunde
(GFlop/s). Für Applikationen nichtwissenschaftlicher Natur werden Integeroperationen pro Sekunde statt Floatingpointoperationen
benutzt, so dass die Leistung in Mip/s (Millionen Instruktionen pro Sekunde) oder Gips (Milliarden Instruktionen pro Sekunde)
gemessen werden.
Der Vorteil dieser Methode ist, dass sie relativ einfach zu berechnen ist und noch dazu sehr viele Messungen dieser Art ständig
publiziert werden, so dass ein Leistungsvergleich ebenfalls unkompliziert durchzuführen ist. Der größte Nachteil liegt natürlich
darin, dass diese Leistung für echte Benutzerapplikationen unmöglich zu erreichen ist. Dieser Wert wird trotzdem benutzt um die
Effizienz einer Anwendung zu ermitteln, also der Quotient zwischen der theoretischen maximalen Leistung und der tatsächlich
erreichten Performance (mehr dazu später).
5.3
Rechenleistung bei einer spezifischen Applikation
Dieser Wert (P) wird uns durch die Anzahl von durchgeführten Operationen während der Ausführung einer spezifischen
Anwendung (W), geteilt durch die gesamte Ausführungszeit (T) gegeben:
P=
W
T
- 23 -
(5.3)
Ähnlich wie bei der theoretischen Peakperformance, wird P hier in MFlop/s, GFlop/s, Mip/s oder Gips angegeben. Dieser
Wert ist als Aussage für die zu erwartende Leistung des Systems offensichtlich bedeutungsvoller als der Wert aus der
theoretischen Peakperformance, seine Bestimmung kann jedoch schwieriger zu erreichen sein. Selbst wenn die Anwendung
die Parallelumgebung bereits ausnutzen kann (die Anwendung wurde parallelisiert), muss trotzdem die Anzahl der von der
Anwendung ausgeführten Floatingpoint- bzw. Integer-Operationen genau ermittelt werden. Trotzdem lassen sich sehr nützliche
Informationen gewinnen, wenn man diese Methode richtig einsetzt.
5.4
Gesamtrechenzeit
Wählt man eine spezifische Testapplikation mit einer vorgegebenen Problemgröße und misst man die exakte CPU-Zeit die benötigt
wird, um diese Berechnung durchzuführen, kann man diese Zeitangabe als Maß der Performance eines Parallelrechners benutzen.
Das Verfahren ist denkbar einfach und als zusätzlicher Vorteil kommt hinzu, dass die Ermittlung der genauen Anzahl der
Rechenoperationen entfällt, die z.B. bei der Angabe der Rechenleistung nach 5.2 notwendig ist. Hinsichtlich der gesamten
Systemperformance eines parallelen Rechners liefert diese Methode eine absolute Aussage über die tatsächliche Leistung des
Systems. Man muss sich aber im Klaren sein, dass dieses Ergebnis nur von Bedeutung ist, wenn man es mit der erhaltenen
Zeitmessungen derselben Testberechnung auf anderen Parallelrechnersystemen vergleichen kann.
5.5
Effizienz
Wenn wir die Rechenleistung eines Systems bei der Berechnung einer bestimmten Applikation messen, und diesen Wert mit dem
theoretisch zu erwartenden maximalen Leistungswert für dieselbe Applikation vergleichen, erhalten wir eine Aussage über die
prozentuale Nutzung der maximale Systemleistung für die spezifische Anwendung. Diese Methode ist natürlich sinnvoll wenn
man wissen will, in wieweit eine Applikation die zur Verfügung stehende Rechenleistung des Systems wirklich benutzt. Ein viel zu
niedriger Prozentualenwert würde z.B. bedeuten, dass eine vorhandene Clusterkonfiguration bzw. die Anwendung selbst stark
anpassungsbedürftig ist. Ein viel zu hoher Wert würde andererseits andeuten, dass es sich bei der ausgewählten Applikation
möglicherweise um eine EPC Applikation handelt, welche zum einen fast auf jeder Clusterarchitektur eine ähnliche hohe
prozentuale Performanceleistung erreichen würde, zum anderen keine sinnvolle Information über die tatsächliche Rechenleistung
der spezifischen Hardwarekonfiguration liefert.
5.6
Der Linpack Benchmark
Man erkennt anhand des oben Gesagten, dass es keine absolute Performancemessmethode gibt, die einerseits einfach einzusetzen
ist und andererseits uns eine vollständige Beschreibung der Rechenleistung einer Clusterkonfiguration liefert. Diese variieren sehr
stark in ihrer Bedeutung und der Art und Weise, mit der sich die relevanten Werte gewinnen lassen. Man kann dazu tendieren,
die am einfachsten einsetzbare Methode zu favorisieren, nämlich die Messung der Ausführungszeit für die Applikation auf dem
spezifischen System. Es gibt allerdings die Schwierigkeit, dass die jeweiligen Messungen nur ausgeführt werden können, wenn
man das System bereits aufgebaut hat. Damit sind nachträgliche Änderungen der Systemkonfiguration entsprechen schwierig und
teuer. Selbst wenn man Zugriff auf die gewünschte Konfiguration hätte und die Leistungsmessungen durchführen könnte, müsste
man zunächst klären wie die Ergebnisse zu interpretieren sind. Ebenfalls zu überprüfen ist, wie man die erhaltenen Leistungswerte
mit anderen Resultaten sinnvoll vergleichen kann, damit ein konkretes Bild der Systemperformance entsteht.
All diese Schwierigkeiten hat die Benutzergemeinde von Parallelcomputern und Clustern dazu bewegt, ihre
Performancemessungen durch einige wenige Standard Benchmark Programme durchzuführen. Auf diese Weise lässt sich leichter
bestimmen, ob eine gegebene Konfiguration effektiver als eine andere ist (als direktes Ergebnis der Benchmark-Tests). Die Relevanz
solcher Vergleiche im Bezug auf eine spezifische Applikation kann man prinzipiell in Frage stellen. Aber die Erfahrung zeigt, dass
es relativ gut dokumentierte Benchmarks gibt, welche uns eine sinnvolle Korrelation mit der entsprechenden eigenen Applikation
aufbauen lassen.
Das berühmteste Beispiel dafür ist der Linpack Benchmark. Der Linpack Benchmark wurde 1975 von Jack Dongarra ins Leben
gerufen als er mit der Ansammlung von Messergebnissen begann, die sich auf die Geschwindigkeit eines Systems bei der Lösung
eines 100 x 100 großen linearen Gleichungssystem bezogen haben. Während die Größe dieser Aufgabe schon lange nicht
mehr eine Herausforderung für einen Supercomputer ist, kann sie trotzdem gut verwenden, um die Rechenperformance eines
Computers zu bestimmen. Insbesondere kann man auf diese Weise die Performance der einzelnen Rechenknoten in einem Cluster
bestimmen.
1988 wurde der so genannte „Scalable Linpack Benchmark“, auch als „Parallel Linpack Benchmark“ bekannt, von Dongarra
freigegeben. Dieser Benchmark wurde für die Messung der Rechenleistung mittelgroßer bis großer paralleler und verteilter
Rechensystem entwickelt und lief bisher auf zahlreichen Computersystemen. Im Gegensatz zum ersten Linpack Benchmark wird
bei der parallelen Version die Größe der Matrix nicht vorgegeben. Stattdessen wird dem Benutzer die Freiheit gegeben, das größte
lineare Gleichungssystem, das mit den vorhandenen Speicherressourcen optimal berechnet werden kann, zu lösen. Ferner wird der
Benutzer nicht verpflichtet, einen vorgegebenen Programmcode zu benutzen, wie es beim Standard Linpack Benchmark
- 24 -
der Fall war. Es besteht somit die Möglichkeit, jede denkbare Programmiersprache und Parallelbibliothek zu benutzen (sogar
Assemblercode Bibliotheken sind erlaubt).
Seit 12 Jahren pflegen Dongarra und Strohmaier eine Liste mit den 500 schnellsten Computersystemen der Welt, die den parallelen
Linpack Benchmark als Maßstab verwendet. Die aktuelle Liste lässt sich auf der Webseite www.top500.org betrachten. Die Linpack
Benchmarks sind denkbar einfach einzusetzen. Die Umrechnungen für die Performancebestimmung erfolgen mühelos wenn man
die Zeitmessungen durchgeführt hat. Der Hauptvorteil liegt jedoch in der Tatsache, dass es eine sehr große Menge an Ergebnissen
gibt, mit denen man sehr leicht die eigene Konfiguration mit ähnlichen Hardwarekonfigurationen vergleichen kann.
Es gibt natürlich auch Nachteile bei der Nutzung von beiden Linpack Benchmarks (Single Prozessor und parallele Version):
Beide liefern ein etwas verzerrtes Bild der echten Systemperformance. Dies liegt in der Tatsache begründet, dass die Benchmark
Algorithmen aus Matrizenberechnungen bestehen, welche auf Hardwareebene eine sehr hohe Datenlokalisierbarkeit
aufweisen (mehr dazu im Kapitel 6). Aus dem Benchmark abgeleitete Effizienzwerte von über 50% sind keine Seltenheit. Echte
wissenschaftliche Applikationen erreichen hingegen nur selten Effizienzwerte über 20% auf parallelen Rechnern (vgl. gleich. 4.3).
5.7
Bestimmung der Latenz und Bandbreite einzelnen Komponenten
Man kann natürlich andere Methoden zur Messung der Performancecharakteristika eines Clusters einsetzen. Diese konzentrieren
sich jedoch meistens auf ganz bestimmte Eigenschaften der Systemkomponenten wie Latenz und Bandbreite, oder sie versuchen
die Auslastung systemspezifischer Ressourcen (I/O, Speicher, Netzwerkleistung, etc.) in Erfahrung zu bringen. Diese Tatsache macht
diese Methoden weniger geeignet wenn es darum geht, eine allgemeingültige Aussage über die Gesamtleistung eines parallelen
Rechners zu ermitteln, sie können uns jedoch bei der Aufgabe helfen, das von uns im §4.6 dargestellte Performancemodell zu
überprüfen und zu verfeinern.
Wir beschreiben im Folgenden einige Linux Betriebssystemtools sowie Standard Open Source Benchmarks, welche entweder
Teil der Linux Systemtools sind oder sehr leicht im Internet zu finden sind. Wir werden uns dabei auf die Messung von CPU- und
Speicherperformance konzentrieren. I/O Performance lassen wir vorerst unbetrachtet.
5.7.1
nbench
nbench-byte ist eine verbesserte und aktualisierte Version von der BYTEmark Benchmark Suite, welche ursprünglich von Rick
Grehan mit der Unterstützung der Computer Fachzeitschrift BYTE entwickelt worden ist. Die Aufgabe der Linux/UNIX Portierung
wurde von Uwe F. Mayer übernommen und er selbst ist zurzeit für die Pflege und die weitere Entwicklung des Benchmarkcodes
zuständig.
nbench-byte 2.2.1 benutzt 10 unterschiedliche Algorithmen, die repräsentativ für CPU intensive Aufgaben gewählt worden sind
und generiert damit drei so genannte „Index figures“: Ein Integer Index, ein Floatingpoint Index und ein Memory Index. Der
Memory Index trägt der Tatsache Rechnung, dass bei den meisten CPUs das Memory Subsystem den größten Leistungsbremser
darstellt (mehr dazu im nächsten Kapitel).
Eine der auffälligsten Eigenschaften von nbench-byte ist, dass er die Messergebnisse selbst kalibriert, d.h. die so erhaltenen Werten
werden anschließend mit denen aus einem AMD K6/233 CPU System verglichen, das mit 32 MB Hauptspeicher und 256KB L2Cache ausgestattet ist. Ferner führt das Benchmark Programm bei jedem der zu startenden Tests die Bestimmung der minimalen
Schrittanzahl durch, die für eine genaue Messung der Durchführungszeit notwendig ist. Dann wird diese Routine fünfmal
nacheinander gestartet und anschließend eine statistische Analyse der jeweiligen Ergebnisse durchgeführt, um die Konsistenz der
Ergebnisse zu überprüfen13).
Ist das nicht der Fall, dann wird nbench-byte diese Tests bis zu 25 Mal erneut durchfahren und die statistische Konsistenz dabei
stets überprüfen. Wird die minimal nötigte Konsistenz trotzdem nicht erreicht, liefert nbench eine Warnung zusammen mit den
entsprechenden Ergebnissen.
Wir vermissen allerdings eine wichtige Eigenschaft bei nbench-byte. nbench ist kein multi-threaded Benchmark, er kann also nicht
den Speedup bestimmen, der durch den Einsatz von Multiprozessor Hardware entstehen sollte. Die Datei 5.1 zeigt am Beispiel des
AMD Athlon MP 2000+ Prozessors wie die Standardausgabe von nbench-byte aussieht:
Die statistische Überprüfungsroutine verifiziert, ob wenigstens 95% der Ergebnisse eine Maximalabweichung von 5% bezüglich des Mittelwertes aller
Messungen aufweist.
13)
- 25 -
BYTEmark* Native Mode Benchmark ver. 2 (10/95)
Index-split by Andrew D. Balsa (11/97)
Linux/Unix* port by Uwe F. Mayer (12/96,11/97)
TEST
: Iterations/sec. : Old Index
: New Index
:
: Pentium 90* : AMD K6/233*
-----------------:------------------:-------------:-----------NUMERIC SORT
:
947.84 :
24.31 :
7.98
STRING SORT
:
128.49 :
57.41 :
8.89
BITFIELD
:
3.3458e+08 :
57.39 :
11.99
FP EMULATION
:
81.175 :
38.95 :
8.99
FOURIER
:
17480 :
19.88 :
11.17
ASSIGNMENT
:
17.256 :
65.66 :
17.03
IDEA
:
2429.2 :
37.15 :
11.03
HUFFMAN
:
1173.4 :
32.54 :
10.39
NEURAL NET
:
22.382 :
35.96 :
15.12
LU DECOMPOSITION :
770.16 :
39.90 :
28.81
=================ORIGINAL BYTEMARK RESULTS====================
INTEGER INDEX
: 42.432
FLOATING-POINT INDEX: 30.551
Baseline(MSDOS*) :Pentium* 90, 256 KB L2-cache, Watcom*compiler
10.0
====================LINUX DATA BELOW==========================
CPU
: Dual AuthenticAMD AMD Athlon(tm)Processor 667MHz
L2 Cache
: 256 KB
OS
: Linux 2.4.20-64GB-SMP
C compiler : gcc version 3.3 20030226 (prerelease)(SuSE Linux)
libc
: ld-2.3.2.so
MEMORY INDEX : 12.197
INTEGER INDEX : 9.523
FLOATING-POINT INDEX: 16.945
Baseline (LINUX): AMD K6/233*,512 KB L2-cache, gcc 2.7.2.3,
libc-5.4.38
* Trademarks are property of their respective holder.
Datei 5.1: Ausgabe von nbench-byte auf dem AMD Athlon MP 2000+.
Anhand dieses Ergebnisses können wir zum Beispiel leicht erkennen, dass die Floating Point Leistung eines einzelnen AMD Athlon
MP 2000+ etwa 17 Mal höher ist als die der Standard Benchmark CPU (AMD K6/233).
5.7.2
Cachebench
Cachebench ist ein Benchmark, der für die Performanceevaluierung sämtlicher eventuell vorhandener Levels (L1- L2,
Hauptspeicher) in der Speicherhierarchie eines Computers konzipiert worden ist. Das Programm wurde von Philip J. Mucci
geschrieben und liegt derzeit in der Version 2.0 vor14).
Wie im Abschnitt 3.4 erwähnt sind Caches grundsätzlich sehr kleine und schnelle Speicherausführungen, die für die
Beschleunigung von Berechnungen ausgelegt sind, die mit regelmäßig auftretenden Datensets arbeiten. Durch den
Einsatz von Cachebench will man also erfahren, wie effizient eine Speicherhierarchie unter der Wirkung einer sehr hohen
Floatingpointauslastung arbeiten kann.
Cachebench besteht zurzeit aus acht verschiedenen Testroutinen. Jede Routine führt wiederholte Zugriffe auf unterschiedlich
großen Datensets durch. Die Zugriffszeiten für jede Datensetgröße über eine bestimmte Anzahl von Iterationen werden
festgehalten. Wenn man die Anzahl von Iterationen mit der jeweiligen Datengröße multipliziert bekommt man die genaue Anzahl
von Bytes, auf die zugegriffen worden ist. Diese Zahl wird durch die gesamte Zugriffszeit dividiert, so dass man einen Wert in
Megabyte pro Sekunde bekommt. Neben diesem Durchsatzwert werden auch die Zugriffszeiten für die entsprechenden Datensets
geliefert.
Sowohl Cachebench als auch nbench-byte stehen per FTP oder HTTP auf dem Server des „Linux Benchmarking Project“ zum Download bereit, und zwar
im Verzeichnis www.tux.org/pub/bench.
14)
- 26 -
Die verschiedenen Testroutinen sind:
•
•
•
•
•
•
•
Cache Read
Cache Write
Cache Read/Modify/Write
Hand Tuned Cache Read
Hand Tuned Cache Write
memset() Aus der C Standardbibliothek
memcpy() Aus der C Standardbibliothek
Auf diese Weise werden 8 Kurven generiert, die das Verhalten von den Speichersubsystemen ziemlich detailliert wiedergeben.
Cache Performance of AMD Athlon MP 2000+
18000
Read
Write
RMW
Tuned Read
Tuned Write
Tuned RMW
memset()
memcpy()
16000
14000
MB/Sec
12000
x
*
10000
8000
6000
4000
2000
0
64
256
1024
4096
16384 65536 262144 1.04858e+06
1.1943e+06 1.67772e+07
Vector Length
Abbildung 5.1: Ergebnisse von Cachebench auf einen Single AMD Athlon MP 2000+.
Die Abbildung 5.1 zeigt die Ergebnisse des Benchmarks auf dem AMD Athlon MP 2000+. Man kann leicht erkennen, wie
die Bandbreite der Kommunikation zwischen CPU und L1, L2 oder Hauptspeicher von der Problemgröße abhängt. Wenn die
Größe des Registervektors kleiner als die Cachegröße ist, kommen alle angeforderten Dateien direkt aus dem L1-Cache und die
Bandbreite erreicht ihren höchsten Wert.
Beim Übertreffen der L1-Cache Größe (im vorliegenden Fall 64 KByte), können die Daten noch in den L2-Cache passen, so dass
die Bandbreite auf die vom den L2-Cache zu erwartende Leistung sinkt. Der letzte Leistungssprung nach unten ist zu beobachten,
wenn die Größe der aufgeforderten Daten regelmäßig die L2-Cache Größe übertrifft (hier 256 KByte). Dann können wir höchsten
den charakteristischen Datendurchsatz für den Hauptspeicher erreichen.
- 27 -
Cache Performance of AMD Athlon MP 2000+
18000
Read
Write
RMW
Tuned Read
Tuned Write
Tuned RMW
memset()
memcpy()
16000
14000
MB/Sec
12000
x
*
10000
8000
6000
4000
2000
0
64
256
1024
4096
16384 65536 262144 1.04858e+06
1.1943e+06 1.67772e+07
Vector Length
Abbildung 5.2: Ergebnisse von Cachebench auf dem Pentium III 450MHz.
Anschließen präsentieren wir zum Vergleich die Ergebnisse von Cachebench auf einem älteren Pentium III Prozessor mit 450
MHz. Man erkennt anhand dieser Kurven, in wieweit modernere CPUs mit dem Cachespeicher effizienter zusammenarbeiten.
Die maximalen Werte liegen um einen Faktor 2 unter denen des AMD Athlon MP 2000+. Der Abfall der Kurven bei 256 KByte ist
wieder auf den niedrigeren L2-Cache Performance zurückzuführen.
5.7.3
ping / fping
ping steht für Packer Internet Groper. Das Tool ist hauptsächlich für die Überprüfung der Erreichbarkeit einer entfernten Maschine
über das Netz konzipiert worden. Das Programm arbeitet so, dass ein sog. „ICMP echo_request“, (also eine Antwortaufforderung
nach dem ICMP Protokoll15) zu dem entfernten System geschickt wird. Dieses echo request ist eine Anforderung, die die entfernte
Maschine beantworten muss, falls sie zu dem Zeitpunkt operativ ist.
Jedes der von Ping gesendeten ICMP Pakete wird mit einem Zeitstempel und einer internen Kodierung versehen. Damit ist
Ping in der Lage zu erfahren, ob die Pakete unterwegs verschwunden sind, oder ob diese dupliziert bzw. mit einer geänderten
Ordnungsreihe zurückgeschickt worden sind, usw. Für uns jedoch ist vor allem der Zeitstempel von Bedeutung, denn damit lässt
sich die sog. RTT (Round Trip Time) ermitteln, also die minimale Zeitspanne, die für das Senden und Empfangen eines einzigen
echo request benötigt wird. Diese Zeit ist in der Tat eine sehr gute Messung der Latenzzeit eines IP Netzwerkes.
15)
ICMP: Das Internet Control Message Protocol enthält Informationen über die Kommunikation zwischen zwei Computern.
- 28 -
Die Datei 5.2 zeigt uns ein Beispiel von dem Einsatz des ping Befehls:
fantasma:/# ping www.host.de
PING 153.94.0.82 (153.94.0.82) 56(84) bytes of data.
64 bytes from 153.94.0.82: icmp_seq=1 ttl=128 time=1.50 ms
64 bytes from 153.94.0.82: icmp_seq=2 ttl=128 time=0.306 ms
64 bytes from 153.94.0.82: icmp_seq=3 ttl=128 time=0.313 ms
64 bytes from 153.94.0.82: icmp_seq=4 ttl=128 time=0.302 ms
64 bytes from 153.94.0.82: icmp_seq=5 ttl=128 time=0.301 ms
64 bytes from 153.94.0.82: icmp_seq=6 ttl=128 time=0.298 ms
64 bytes from 153.94.0.82: icmp_seq=7 ttl=128 time=0.323 ms
64 bytes from 153.94.0.82: icmp_seq=8 ttl=128 time=0.346 ms
64 bytes from 153.94.0.82: icmp_seq=9 ttl=128 time=0.320 ms
64 bytes from 153.94.0.82: icmp_seq=10 ttl=128 time=0.295 ms
--- 153.94.0.82 ping statistics --10 packets transmitted,10 received, 0% packet loss,time 9006ms
rtt min/avg/max/mdev = 0.295/0.431/1.508/0.359 ms
Datei 5.2: Ausgabe des ping Befehls ohne Parameter.
Unter den Informationen, die die Ausgabe von ping liefert, steht die IP Adresse des entfernten Systems, die ICMP Sequenzzahlen
und die Round Trip Zeiten in Millisekunden. Eine Zusammenfassung der Informationen ist in der letzten Zeile zu finden. Dort sind
die Anzahl von gesendeten, empfangenen und verloren gegangenen Paketen, sowie die Statistiken über gesamte Laufzeit der
Kommunikation zu finden, und ebenso eine statistische Auswertung für RTT.
fping ist ein ping ähnliches Programm, das genauso auf der Nutzung des ICMP Protokolls aufbaut um die Aktivität eines
entfernten Systems zu registrieren. fping unterscheidet sich von ping, weil bei fping die Möglichkeit besteht, nicht nur eine
Zielmaschine auf der Kommandozeile für die Rückmeldung zu definieren besteht. Man hat ebenfalls die Möglichkeit, eine Datei
mit den Namen bzw. IP Adressen der zu überprüfenden Hosts zu erstellen. fping wird dann der Reihe nach ein einziges „echo
request“ Paket zu den Systemen auf der Liste verschicken.
Die Defaulteinstellungen von fping bewirken, dass bei der Antwort einer Zielmaschine diese sofort aus der Liste der Zielmaschinen
ausgetragen wird und als „alive“ gemeldet wird. Antwortet die Maschine nach einer gewissen Zeit bzw. nach einer bestimmten
Anzahl von erneuten Versuchen nicht, wird die betroffene Maschine als unerreichbar („unreachable“) gemeldet. Die Datei 5.3
enthält ein einfaches Beispiel der Standardausgabe von fping:
- fantasma:~ # fping 192.168.0.38 192.168.0.39 192.168.0.40
- 192.168.0.38 is alive
- 192.168.0.39 is alive
- 192.168.0.40 is unreachable
Datei 5.3: Die Standardausgabe des fpings Befehls
Interessant für eine schnelle Messung der Latenzzeit eines Netzes ist der Einsatz von fping zusammen mit den Optionen –C und -q.
Die Datei 5.4 zeigt eben die Ausgabe von fping –C 4 -q:
- fantasma:~ # fping –C 4 –q 192.168.0.30
- 192.168.0.30 : 1.7 0.7 0.7 0.7
Datei 5.4: Ausgabe des fpings Befehls mit den –C und –q Parameter
Wir sehen, dass nur die Antwortzeit in Millisekunden auf jedes der vier ICMP ECHO_REQUEST Pakete ausgegeben wird, was uns
eine schnelle Abschätzung der Latenzzeit einer Verbindung erlaubt. Die Messung der Latenzzeiten mit Hilfe von ping/fping lassen
sich nicht nur bei Fast Ethernetverbindungen durchführen, die Latenz von Gigabit Ethernet und Myrinet Netzen können ebenso
unproblematisch in Erfahrung gebracht werden.
- 29 -
5.7.4
bing
bing ist ein Netzwerktool, das die Bandbreite einer point-to-point Netzwerkverbindung bestimmen kann, und zwar durch das
Senden von ICMP ECHO_REQUEST Pakete und die darauf folgende Messung der RTT für die von Programm automatisch
wechselnden Paketgroßen an jeder Seite der Verbindung.
Wenn sich der gemessene Wert von RTT bei der Übertragung einer bestimmten Paketgröße ändert, wird der neue Durchsatz
angegeben, sonst werden diese Informationen defaultmäßig von bing unterdrückt.
fantasma:~ # bing 192.168.0.10 192.168.0.1
BING 192.168.0.10 (192.168.0.10) and 192.168.0.1 (192.168.0.1)
44 and 108 data bytes
1024 bits in 0.000ms
1024 bits in 0.014ms: 73142857bps, 0.000014ms per bit
1024 bits in 0.015ms: 68266667bps, 0.000015ms per bit
1024 bits in 0.014ms: 73142857bps, 0.000014ms per bit
1024 bits in 0.015ms: 68266667bps, 0.000015ms per bit
1024 bits in 0.014ms: 73142857bps, 0.000014ms per bit
1024 bits in 0.013ms: 78769231bps, 0.000013ms per bit
1024 bits in 0.014ms: 73142857bps, 0.000014ms per bit
1024 bits in 0.013ms: 78769231bps, 0.000013ms per bit
1024 bits in 0.014ms: 73142857bps, 0.000014ms per bit
1024 bits in 0.013ms: 78769231bps, 0.000013ms per bit
--- 192.168.0.10 statistics --bytes out in dup loss rtt (ms): min
avg
max
4435035283503528
0%
0.008 0.009 89.851
10835035283503528
0%
0.008 0.009 90.168
--- 192.168.0.1 statistics --bytes out in dup loss rtt (ms): min
avg
max
4435035283503528
0%
0.061 0.064 93.252
10835035283503527
0%
0.074 0.077 94.628
--- estimated link characteristics --estimated throughput 78769231bps
minimum delay per packet 0.044ms (3471 bits)
average statistics (experimental) :
packet loss: small 0%, big 0%, total 0%
warning: rtt big host1 0.009ms < rtt small host2 0.009ms
average throughput 78769231bps
average delay per packet 0.046ms (3597 bits)
weighted average throughput 78769220bps
Datei 5.5: Standardausgabe des bings Befehls
Wird das Programm mit den richtigen Parametern aufgerufen, dann arbeitet bing so lange, bis eine maximale Anzahl von
Iterationen erreicht wird, oder das Programm durch ein sigint Signal (Stgr + C) unterbrochen wird. Gleichzeitig wird eine kurze
Zusammenfassung der Aktivitäten abgegeben. Die Datei 5.5 oben zeigt eine Beispielausgabe von bing. Eine einfache Rechnung
zeigt uns anschließend, dass der Link aus dem Beispiel 5.5 einen Durchsatz von ca. 9.85MB/s aufweist, was die Leistung einer
100MBit Ethernet Anbindung entspricht.
- 30 -
KAPITEL 6 - Bottlenecks
Rechner bestehen aus zahlreichen Hardwarekomponenten. Diese wechselwirken in der Regel auf komplizierte Weise. Die Arbeiten,
die diese Komponenten für die CPU verrichten, erfolgen mit stark unterschiedlicher Geschwindigkeit. Gelegentlich muss die CPU
warten bis die spezifischen Jobs von diesen Hardwaresubsystemen erledigt werden, manchmal sind die Rechnerkomponenten
diejenigen, die auf die CPU warten müssen. Man tendiert dazu, die CPU als die schnellste Komponente im System zu identifizieren.
Auch wenn sie in den meisten Fällen diejenige Komponente ist, welche die größte Leerlaufzeit besitzt, müssen wir als wichtigste
Tatsache festhalten, dass die Rechenleistung des Systems leidet, wenn es häufig die beschriebenen Warte- und Leerlaufzeiten gibt.
Versuchen wir eine bestimmte Anzahl von miteinander kommunizierenden Maschinen in einen einzigen Computer zu verwandeln,
so erreichen solche Performanceprobleme einen noch höheren Komplexitätsgrad. Ein einziger im Leerlauf befindlicher Prozessor
kann durch das Warten auf bestimmte Operationen bzw. Ergebnisse dermaßen abgebremst werden, dass die auf allen
Rechenknoten verteilte Berechnung entscheidend verlangsamt wird.
Wenn es zwei oder mehr wechselwirkende Ressourcen eines Computersystems gibt und davon eine oder mehrere ihre maximale
Leistung deutlich früher als die restlichen Ressourcen erreichen, so spricht man von einem Bottleneck (zu Deutsch: Flaschenhals).
Wir sind natürlich daran interessiert, so viel wie möglich über solche Leistungsbremser zu lernen, da sie eine grundlegende Rolle
in unserem Verständnis über die Performance von Parallelrechnern spielen. Wir werden jedoch nur die klassischen Bottlenecks
betrachten, die bei den meisten Computerberechnungen von Bedeutung sind: Der CPU Cache (Größe und Geschwindigkeit), der
CPU-Speicherbus, das Kommunikationsnetzwerk und die Schreib/Leseoperationen der Festplatte.
6.1
Superlineare Speedups
Um jetzt ein besseres Bild über die Motivationen dieses Kapitels zu geben, wollen wir folgendes Beispiel betrachten:
Angenommen, wir verfügen über einen Cluster, der aus Rechenknoten ohne Festplatten besteht und 128 MB Hauptspeicher
pro Knoten aufweist. Wir haben weiterhin eine Applikation, welche insgesamt 128 MB Hauptspeicher während der Ausführung
benötigt, andererseits jedoch eine Aufteilung der gesamten Problemgröße zulässt. Man kann also die Applikation bequem in 32
MB große Speichersegmente aufteilen, so dass sie z.B. auf 4 Knoten parallel auf dem Cluster laufen könnte.
Würden wir zuerst diese Applikation auf einem einzigen Rechenknoten ausführen, müsste der Job ständig auf Swapspeicher
zugreifen. In unserem Fall ist die einzige Möglichkeit Swapspeicher zu benutzen der Zugriff über das Netzwerk auf die Festplatte
eines entfernten Fileservers. Swapping ist jedoch sehr nachteilig, was die Performance einer Applikation angeht. Festplatten
sind 2 bis 3 Zehnerpotenzen langsamer als der direkte Hauptspeicherzugriff, und Swapping über das Netzwerk macht dies noch
schlimmer. Werden ständig Zugriffe auf die entfernte Festplatte benötigt, um die Speicherinhalte zu laden bzw. zu entladen, so
kann die Zeit zur Ausführung der Applikation stark ansteigen.
Diese negativen Auswirkungen können so weit gehen, dass selbst der Sequentiellanteil des Programms viel langsamer ausgeführt
wird. Die Ursache dafür liegt in der Tatsache, dass sowohl der Parallel- als auch der Sequentiellanteil regelmäßig aus dem Speicher
ausgelagert und wieder geladen werden müssen, abhängig vom berechneten Programmteil.
Wenn dieselbe Applikation hingegen auf 4 Knoten des Clusters läuft, muss man sicherlich mit Zeitverlusten rechnen, die auf die
notwendigen Kommunikationsvorgängen zwischen den Prozessen zurückzuführen sind. Die Jobs auf den Knoten müssen jetzt
aber nicht mehr auf Swapspeicher schreiben. Diese verteilten Jobs passen in den Hauptspeicher der Knoten und es bleibt noch
Speicherplatz übrig für das Laden des Betriebsystems, Programmbibliotheken, Buffers, etc. Durch die geeignete Verteilung der Jobs
auf dem Cluster kann es sogar vorkommen, dass der dadurch erreichte Speedup sehr groß wird und eine Verletzung des Gesetzes
von Amdahl möglich ist16).
Dieses Ergebnis kann etwas überraschend wirken, lässt sich aber beim näheren Hinsehen relativ leicht erklären. In der Tat hat
das im Kapitel 4 abgeleitete Gesetz von Amdahl eine gewisse Stetigkeit vorausgesetzt bezüglich des durch den Parallel- und
Sequentiellanteil definierten Zeitquotienten (s. Gleichung 4.11). Insbesondere haben wir vorausgesetzt, dass die Zeiten TS und TP
sich bei der Aufteilung der N parallelen Jobs nicht großartig unterscheiden. Es ist also kein außergewöhnliches Beispiel notwendig
gewesen um zu zeigen, dass diese Annahme in der Welt der echten Computerapplikationen nicht mehr gilt, da reale Systeme
über begrenzte Ressourcen verfügen oder weil nicht alle vorhandenen Ressourcen innerhalb der gleichen Zeitskala miteinander
kommunizieren können.
Speedups, die das einfache Gesetz von Amdahl verletzen, werden als superlineare Speedups bezeichnet und werden in
zahlreichen Fachpublikationen detailliert behandelt. Im Grunde genommen entsteht ein superlinearer Speedup, wenn der erreichte
Speedup
Man kann sich eine noch extremere Situation vorstellen und sich fragen, welchen Speedup man erreichen würde wenn diese Rechenknoten überhaupt
keine Möglichkeit zum Swapping hätten (z.B. wenn keine entfernten Festplatten für die Auslagerung vorhanden sind). In diesem Fall würde der Job auf
einem einzigen Knoten nicht laufen können und man hätte eine unendliche Ausführungszeit für diese Applikation zur Folge. Mit dem Einsatz von vier
Knoten bei der Berechnung der Applikation würde man aber eine endliche Ausführungszeit bekommen und somit einen unendlichen Speedup erreichen,
was die oben gemeinte Verletzung des Gesetzes von Amdahl deutlich darstellt.
16)
- 31 -
nach der Parallelisierung einer Applikation viel schneller skaliert als N. In den meisten praktischen Fällen lässt sich dieses Verhalten
des Speedups auf die breite Palette der in einem Computersystem existierenden Hardwarezugriffszeiten zurückführen.
6.2
Applikationseigenschaften und Hardware Bottlenecks
Werfen wir nun einen Blick auf die wichtigsten Bottlenecks, die die Performance von parallelen Applikationen bedeutend
beeinträchtigen können. Wir beginnen mit einer einfachen Tabelle, welche die unterschiedlichen Bottlenecks zeigt, sowie die
Leistungswerte, die diese Bottlenecks charakterisieren.
Bottleneck
L1 Cache
L2 Cache
Hauptspeicher
Festplatte (lokal)
Festplatte (NFS)
Netzwerk
Beschreibung
Latenz
Bandbreite
Lesen/Schreiben von CPU auf L1
Cache
Lesen/Schreiben von
L1 auf L2 Cache
Lesen/Schreiben von
L2 Cache auf Speicher
Lesen/Schreiben von CPU auf
Festplatte
Lesen/Schreiben von CPU auf
NFS Dateisystem
0.4 - 5 ns
(1 CPU Takt)
Bis zu 20 GB/s
4 – 10 ns
400-1000 MB/s
40 – 80 ns
100-400 MB/s
5 - 15 ms
1-80 MB/s
5 - 20 ms
0.5-70 MB/s
Schreiben von CPU zu CPU
5 - 50 µs
0.5-100 MB/s
Tabelle 6.1: Typische Leistungswerte für wichtige Bottlenecks.
Man erkennt gleich beim ersten Blick auf die Tabelle, dass die eingetragenen Zeiteinheiten für die verschiedene Hardwarekomponenten sich zwischen sieben oder mehr Zehnerpotenzen unterscheiden. Vergleichen wir die Latenzzeit eines CPU Taktzyklus
beim Zugriff auf eine bestimmte Speicheradresse innerhalb des L1 – Cache, welche weniger als eine Nanosekunde beträgt, mit der
Latenzzeit von 5 oder mehr Millisekunden, die für den Zugriff auf eine bestimmte Adresse auf der Festplatte nötig ist.
Ähnlich dramatisch fällt der Vergleich zwischen Bandbreiten im Bereich von einem Megabyte pro Sekunde bei Datentransfers über
Standardethernet mit den Durchsatzraten im Bereich von Gigabyte pro Sekunde im Fall des L1- Caches aus.
Noch ein weiterer interessanter Aspekt, der sich aus der Tabelle entnehmen lässt, hat mit der Hierarchie der im System
vorhandenen Speicherelemente zu tun. Die großen Unterschiede in den Latenz- und Zugriffszeiten bei den verschiedenen
Speicherarten machen sie für eine Performanceanalyse schwierig zu handhaben. Man kann aber diese Unterschiede hinter
einer Durchschnittslatenz verstecken und dadurch die Performanceanalyse für spezifische Applikationen vereinfachen. Dieser
Durchschnittswert wird einfach durch die Anzahl von Zugriffen, die auf den verschiedenen Speicherarten erfolgen, bestimmt
(dabei lassen sich Festplatten und Datentransfers über das Netzwerk ebenfalls als Speicherelemente behandeln).
Was wir haben ist, mathematisch ausgedrückt, eine Wahrscheinlichkeitsverteilung. Nehmen wir an, Pi ist die Wahrscheinlichkeit,
die von der gegebenen Applikation unmittelbar benötigte Datei bzw. den Programmcode innerhalb der i-ten Speicherart zu
finden und Li ist die entsprechende Latenzzeit für diesen Speicher (die Speicherarten entsprechen den auf der Tabelle 5.1
bereits erwähnten). Auf diese Weise ist die durchschnittliche Zeit L , die das System warten muss, bis die Daten oder die
Programmbefehle erstmals verfügbar sind (gesamte Latenzzeit) durch folgende Beziehung gegeben
∑
L =
pi ⋅ Li
i
(6.1)
Beispiel: Wenn wir die folgenden Zugriffswahrscheinlichkeitswerte PLI = 0.05, PL2 = 0.9 und PL2 = 0.05 für eine Berechnung hätten,
die vollständig innerhalb des Hauptspeichers passt, erhält man aus (6.1)
L = 0.05 * 1 + 0.9 * 8 + 0.05 * 50 = 9.75
(6.2)
in Nanosekunden. Die Abschätzung der Gesamtlatenzzeit für das System wäre natürlich noch komplizierter, wenn wir
jede Hardwarekomponente betrachten würden. Die wirklich relevante Tatsache ist hier jedoch eine andere: Solange die
Speicherhierarchie des vorliegenden Systems bei einer durchschnittlichen Latenzzeit und Bandbreite bleibt, deren Wert vernünftig
nah an den Standardwerten von L1 und/oder L2 Cache für die gegebene Applikation liegt, gibt es keinen guten Grund mehr Geld
in eine noch teurere Speicherhierarchie zu investieren.
- 32 -
Es ist natürlich üblich, dass die Vorteile eines großen L2 Cache z.B. von den CPU Herstellern überdimensioniert dargestellt werden,
denn sie sind logischerweise daran interessiert, noch teurere (und rentablere) CPUs zu verkaufen. Die Erfahrung zeigt jedoch,
dass es eine breite Palette von parallelen Applikationen gibt, die von der Nutzung größerer Cachespeicher nicht richtig profitieren
können. Noch dazu kommt der Preisunterschied, der sich zwischen CPUs mit kleinem bzw. großem Cache bis zum Faktor 10
bewegt. Für solche Algorithmen beispielsweise, könnte man sicherlich besser beraten sein, wenn man statt einem einzigen Xeon
System mit 2 MB Cachegröße gleich 3 komplette Celeron Systeme kauft.
Natürlich gibt es eine andere Klasse von Anwendungen die sich dadurch auszeichnet, dass ganze Instruktionssets bzw.
Datenbestände in den Cachespeicher passen. Solche Anwendungen sind aufgrund dessen deutlich schneller als normale
Anwendungen, welche auf den Hauptspeicher zugreifen müssen17). Die Ursache für solche hohe Leistungen liegt in der Tatsache
begründet, dass diese Algorithmen eine relativ kleine Anzahl von Programmschleifen durchführen, die aus sequentiellen
Instruktionen bestehen. Diese Struktur lässt das Laden ganzer Datenblöcke aus dem Hauptspeicher in den Cache zu und diese
Datenbestände reichen für lange Berechnungsphasen vollständig aus.
Im günstigen Fall kann der Algorithmus ständig im L1 Cache „leben“ und somit über lange Zeit mit der vollen CPU
Geschwindigkeit abgearbeitet werden. Die Bedingung hierfür lautet PL1 + PL2 >> PM , so dass die CPU häufig bereits im
Cachespeicher die für die Berechnung notwendigen Daten findet, ohne auf den langsamen Hauptspeicher zugreifen zu müssen.
Solche Applikationen nutzen die verfügbare CPU Leistung sehr effizient aus.
Was passiert nun, wenn ein Algorithmus die Addition von beliebig positionierten Datenbytes aus einem 1 MB großen Datenbereich
regelmäßig durchführt? Dann wird die Wahrscheinlichkeit für das Programm, die unmittelbar benötigten Daten innerhalb des
Caches zu finden, deutlich geringer. Mit einem 128 KB großen L2-Cache könnte diese Wahrscheinlichkeit nicht größer als 1/10
sein, so dass 90% der Zeit etwa 60 ns benötigt werden um das nächste zu addierende Byte aus dem Hauptspeicher zu holen,
während die restlichen 10% der Zeit nur 10 ns (oder weniger) für diese Aufgabe gebraucht werden. Man erhält also einen
Durchschnittswert von einem Byte pro 55 ns (plus ein CPU Takt für die eigentliche Additionsaufgabe).
Mit einem 512 KB großen L2 Cache steigt die Wahrscheinlichkeit, die unmittelbar benötigte Datei im Cache zu finden auf das
Doppelte und die durchschnittliche Latenzzeit reduziert sich auf 35 ns. Mit einem 1 GB L2 großen Cache befinden sich die Daten
ständig im Cache und wir kommen auf eine Latenzzeit von ungefähr 10 ns, also einen Faktor 6 schneller als mit dem 128 KB
großen Cache. Solche Applikationen wie die hier beschriebene weisen eine stark „nicht lokalisierte“ Speicherzugriffsstruktur auf
und profitieren daher am meisten von größeren Caches.
Beim näheren Hinschauen kann man auch sogar behaupten, dass Applikationen dieser Klasse - bei geeigneter Parallelisierung
- sehr gute Chancen haben, einen superlinearen Speedup zu erreichen. In der Tat, wenn wir den oben erwähnten 1 MB großen
Datenbereich in 10 Datensektoren jeweils mit einer Größe von 100 KB aufteilen, dann würden die 10 so verteilten Jobs im Cache
eines kleineren Prozessors (z.B. Celeron mit 128 KB Cache) mit ungefähr der sechsfachen Geschwindigkeit laufen. Dazu kommt
ein Faktor 10 auf Grund der parallelen Ausführung der Additionen. Diese Bedingungen zusammen mit der Wahl einer geeigneten
Granularitätsgröße können der Applikation zu einer noch höheren Effizienz verhelfen. Im Endeffekt bekommen wir eine
Parallelumgebung, die für den betroffenen Algorithmus einen noch höheren Speedup aufweisen kann als es von einem einfachen
10 Knoten-Cluster zu erwarten wäre, bei dem man den Cacheflaschenhals ignoriert hat.
6.3
Dual CPU Systeme
Es gibt eine Fülle von Programmen bzw. Benutzerapplikationen, deren Berechnungszeit (sei es auf einer parallelen oder einer
sequentiellen Maschine) sehr stark von der Geschwindigkeit abhängt, mit der die Daten oder die Programminstruktionen aus
dem Hauptspeicher geholt werden können. Die CPU Leistung spielt dabei eine etwas untergeordnete Rolle. Unter diesen sog.
Memory Bound Applikationen findet man Programme, die sehr große Matrizen multiplizieren oder viele sequentielle Operationen
mit Daten aus großen Datenblöcken ausführen. Während der Programmsausführung werden ständig neue Datenblöcke aus dem
Hauptspeicher geholt und in den Cachespeicher abgelegt (und umgekehrt), so dass der Speicherbus kontinuierlich unter starker
Belastung steht. Unter diesen Umständen taucht ein weiterer wichtiger potentieller Bottleneck bei Clusterkonfigurationen auf.
Es hat sich innerhalb der Clusterwelt die Routine etabliert, mehr CPU Rechenleistung in Form von Dual SMP Systemen (auch
einfach Dual Prozessorsysteme genannt) zu erreichen. Dual CPU Motherboards sind nur wenig teurer als die Single CPU
Pendants. Die CPUs teilen sich jedoch dabei alle anderen Hardwarekomponenten wie Speicher, Gehäuse, Festplatten, Netzteil,
etc. untereinander. Auf diese Weise erhofft man sich durch eine relativ kleine zusätzliche Investition eine höhere Rechenleistung
pro Knoten. Falls der erreichbare Speedup für eine bestimmte Applikation sehr stark von der CPU Leistung abhängt, stellen SMP
Systeme die optimale Hardwarebasis für diese Applikation dar. Im Falle einer sehr starken CPU-Abhängigkeit des Algorithmus kann
Hierzu ist das ebenfalls von J. Dongarra initiierte ATLAS Projekt (Automatically Tuned Linear Algebra System) zu erwähnen. Dieses Projekt versucht,
die Generierung von optimierten Algorithmen für lineare Algebra Berechnungen zu automatisieren, so dass die notwendigen Programmschleifen und
Speicherblockgrößen an die Cachegröße des Computers angepasst werden. Dadurch wird der Speedup für die jeweilige Applikation um den Faktor 2 bis 3
beschleunigt.
17)
- 33 -
man es sogar mit einer EPC Applikation zu tun haben, denn die Zahl der verarbeiteten Instruktionen ist proportional zur Anzahl
der CPUs. Handelt es sich hingegen bei dem spezifischen Job um einen speicherbedingten Job, so stellt man schnell fest, dass
durch den Einsatz von Dual Prozessor Systemen der Speicherbus stärker belastet wird. Wenn zwei CPUs gleichzeitig Daten aus
dem Speicher zu holen versuchen - und zwar so schnell wie sie es können - muss in der Regel einer von beiden Prozessoren
warten, bis der Datenbus wieder frei wird. Dieses Verhalten kann also in der Tat die Leistung solcher speichergebundenen Jobs
auf SMP Systemen so stark beeinträchtigen, dass wir in der Regel nur 140-160% Leistungszuwachs beobachten werden, statt
der durch den Einsatz zweier CPUs zu erwarteten 200%. Die unmittelbare Schlussfolgerung lautet also, dass speichergebundene
Applikationen im Allgemeinen auf Einzelprozessor Systemen bessere Chancen haben, eine höhere Effizienz zu erreichen.
6.4
Netzwerkflaschenhals
Außer Speicherbedingten und CPU - bedingten Applikationen gibt es auch solche, die sehr stark von der Leistung der Kommunikat
ionsschnittstelle zwischen den Prozessoren abhängen. Diese sind innerhalb des Clustermodells als netzwerkbedingte Applikationen
einzustufen. Es gibt leider zahlreiche Aspekte die man in Betracht ziehen muss, wenn man es mit netzwerkbedingten
Applikationen zu tun hat: Ist es sinnvoll zwei NICs pro Rechenknoten zu verwenden um den Datendurchsatz zu erhöhen?
Ist der Job etwa auch speicherleistungsabhängig, (die Netzwerkarten werden eben über den Speicherbus angesprochen),
oder will man doch noch SMP Systeme benutzen? Diese können nämlich unter Umständen eine viel effizientere Nutzung der
Netzwerkressourcen ermöglichen, denn die Übertragung von Daten über das Netz dauert deutlich länger, wenn der Zielprozessor
während der Kommunikation mit der Durchführung anderer Tätigkeiten beschäftigt ist (eine zweite CPU kann da Abhilfe
schaffen). Wir können aus diesem Grund keine allgemeingültige Regel aufstellen, die uns eine einfache Entscheidung über die
bessere Hardwarearchitektur für netzwerkbedingte Applikationen ermöglicht. Wir betrachten jedoch kurz den wichtigsten Aspekt,
der mit der Performance einer netzwerkbedingten Applikation verbunden ist, nämlich die Konkurrenz für die Bandbreite und
schildern dabei, wie das Netzwerk zum Flaschenhals werden kann.
Stellen wir uns die Frage was passiert, wenn zwei Prozessoren zum gleichen Zeitpunkt versuchen, Daten über dieselbe Leitung zu
schicken. Unter normalen Umständen erfolgt ein einziger Transfer über die Datenleitung, der zweite Transfer muss darum auf eine
Warteschleife gestellt werden oder er wird zurückgewiesen. Statt sich auf die Aktivität der einzelnen Prozessoren zu konzentrieren
erweist es sich in der Praxis als vorteilhafter, den ganzen Prozess so zu modellieren, als ob die beiden Prozessoren sich die zur
Verfügung stehende Bandbreite teilen müssten. Bei dem Kommunikationsterm im Performancemodell aus Abschnitt 4.6 bedeutet
dies, dass der Term tw L für das Volumen des Datentransfers geeicht werden soll und zwar durch die Anzahl n der Prozessoren, die
miteinander bei dem Senden auf der gleichen Datenleitung konkurrieren. Die Gleichung 4.13 wird entsprechend umgeformt zu
TKomm Begrenz = t L + tW n ⋅ L
(6.3)
Der Eichfaktor n trägt nun der Tatsache Rechnung, dass die effektive Bandbreite für jeden Prozessor nur den Bruchteil 1/n der
echten Bandbreite beträgt.
Die negative Auswirkung der Konkurrenz auf die Bandbreite zeigt sich im Prinzip sehr deutlich, wenn die Granularitätsgroße der
Applikation zu klein ist (s. §4.3) und zahlreiche Kommunikationsprozesse generiert werden, so dass entsprechend viele Daten über
die Netzwerkleitung geschickt werden. Ebenfalls sind sog. synchrone Algorithmen anfällig, also Algorithmen, die das gleichzeitige
Senden und Empfangen von Prozessordaten erlauben (oder Algorithmen, bei denen die Prozessoren während des Wartens auf
weitere Prozessdaten im Leerlauf bleiben).
Asynchrone Algorithmen können im Gegensatz dazu während des Wartens auf nötige Daten andere Jobs für die CPUs starten und
sind somit vom Problem der Konkurrenz für die Bandbreite nur bedingt betroffen.
Anschließend müssen wir noch bemerken, dass bei der Gleichung 6.3 eine wichtige Tatsache unberücksichtigt bleibt. Bei den
Kollisionen von Daten, die gleichzeitig auf derselben Leitung gesendet werden, kommt es zu neuen Kommunikationsvorgängen
beim Datensender und das wiederum kostet nochmals wertvolle Zeit. Im Clusterumfeld arbeitet man jedoch fast ausnahmslos mit
Switched Netzwerken, und genau deswegen erlauben wir uns, die negativen Auswirkungen dieses zeitraubenden Faktors außer
acht zu lassen18).
Die meisten Kommunikationsnetzwerke bei Clusterkonfigurationen benutzen weniger als N² Datenleitungen um N Prozessoren zu verbinden. Es
müssen also Netzwerk Switches benutzt werden, um die Daten aus einem Quellprozessor optimal ins Ziel zu transportieren. Die Aufgabe des Switches
ist es, die Daten anzuhalten oder umzuleiten wenn mehrere Zugriffe gleichzeitig auf demselben Netzwerkkanal stattfinden. Die Anzahl von Switches die
kontaktiert werden müssen, um Daten aus dem Sendeprozessor bis zum Zielprozessor zu schicken, wird als Abstand zwischen den Prozessoren bezeichnet.
Der Abstand zwischen zwei Prozessoren und die Länge des benötigten Kabels sind in der Regel nicht von Bedeutung, wenn es um die Bestimmung der
Netzwerkperformance eines Systems geht. Man darf aber nicht vergessen, dass der Einsatz besonders langer Kommunikationskabel und mehrerer Switches
gerade bei hochwertigen Netzwerkinterfaces wie Myrinet, die Hardwareanschaffungskosten eines Clusters in die Höhe treiben können.
18)
- 34 -
6.5
Input / Output
Ein letzter noch zu berücksichtigender, relevanter Faktor bei der Bestimmung der Performance einiger paralleler Applikationen
ist die Zeit welche benötigt wird, um Daten aus dem Hauptspeicher in die sekundären Speicher zu transportieren, also die Zeit
für Standard Schreib/Leseoperationen auf der Festplatte. Unter den Applikationen, die einen starken I/O Charakter aufweisen,
erkennen wir folgende:
•
Checkpoints: Es gibt bestimmte Applikationen mit beträchtlich großer Laufzeitspanne. Eine periodische Sicherung des
Berechnungszustands zu einem gegebenen Zeitpunkt mit Hilfe des sog. Checkpointings, ist in diesem Fall von großer
Bedeutung, damit man die Risiken und Folgen von Systemausfällen sinnvoll minimieren kann. Die Zustandssicherung
großer Berechnungen kann viele Gigabytes in Anspruch nehmen.
•
Simulationen: Applikationen aus der Wissenschaft und der Technik verfolgen die Entwicklung physikalischer Systeme
im Laufe der Zeit und ermöglichen auf diese Weise die Visualisierung und Analyse des betrachteten Systems. Solche
Simulationen können erstaunlich große Datenmengen erzeugen (hunderte von Gigabytes pro Laufzeitperiode)
•
Virtual Memory Berechnungen: Einige Applikationen arbeiten mit Datenstrukturen, die größer sind als der im System
zur Verfügung stehende Hauptspeicher. Im Prinzip kann ein virtuelles Speichersystem (Swapbereich) die notwendigen
Datentransfers zwischen Speicher und Harddisk realisieren (auch wenn diese deutlich langsamer sind als reine
Speicherzugriffe). Das Problem dabei ist, dass nicht jede Clusterkonfiguration einen virtuellen Speicher zur Verfügung
stellt. Selbst wenn virtueller Speicher vorhanden ist, so ist die Leistung der Applikation trotzdem durch eine optimierte
Gestaltung der Datentransfers über das I/O System deutlich steigerbar.
•
Datenanalyse: Andere parallele Applikationen sind für die Analyse sehr großer Datenbestände konzipiert, zum Beispiel
für die Ergebnisse von Klimasimulationen. Die aus Wetterstationen gesammelten Daten können nach extremen Werten
durchsucht werden (z.B. wo liegen die höchsten Temperatur- oder Luftfeuchtigkeitswerte, etc). Eine Videodatenbank
lässt sich nach spezifischen Bildern durchsuchen oder eine Datenbank mit Informationen über Kreditkarten wird
nach bestimmten Merkmalen durchsucht, die trügerische Transaktionen charakterisieren. Solche Applikationen für
Datenanalysen sind aus der Sicht des I/O Systems sehr belastend, da zahlreiche kleine Rechenaufgaben auf Daten
erfolgen, die ständig von der Festplatte geholt werden müssen.
Wir können in der Regel unsere Erkenntnisse aus dem Bereich Interprozesskommunikation direkt auf den Bereich I/O übertragen
und dadurch wichtige Rückschlüsse über dessen Auswirkung auf die Systemperformance ziehen. Man betrachtet hierfür
die Schreib-Leseoperationen als eine Art Interprozessorkommunikation, in denen die Festplatten eine Sonderrolle spielen.
Die Struktur eine Schreib/Lese Operation auf Festplatte lässt sich wie beim Netzwerk durch eine Latenzzeit und eine Zeit pro
Nachrichtentransfer (Durchsatz) verstehen. Wir können somit die gleiche Beziehung benutzen
T = t L + tW L
(6.4)
(T = Kommunikationszeit, tL = Latenzzeit, tW = Transferzeit pro Wort, L = Größe der gesendeten Nachricht). Wir müssen dabei nur
berücksichtigen, dass die Latenzzeit typischerweise viel größer ist als im Falle des Netzwerks. In gleicher Form wie bei der Interproz
esskommunikation ist der Schlüssel zu höherer Leistung die Maximierung der Nutzung der verfügbaren Kommunikationskanäle bei
gleichzeitiger Minimierung der Kommunikationsprozesse.
Wenn ein Computersystem nur eine Festplatte hat, oder wenn mehrere Platten mit einem einzigen Prozessor verbunden sind, kann
man sehr wenig für die Optimierung der I/O Leistung einer parallelen Anwendung erreichen. In der Praxis sind aber die meisten
Clusterkonfigurationen mit mehreren I/O Kommunikationsleitungen versehen, entweder durch die Anwesenheit von speziellen I/O
Knoten (Plattenarrays), oder weil auf jedem Rechenknoten eine Festplatte vorhanden ist. Von Architekturen dieser Art profitieren
hauptsächlich Anwendungen, die so programmiert sind, dass die Prozessoren konkurrierende Schreib/Lese Operationen asynchron
starten können.
- 35 -
I/O Pfade
P
Prozessoren
F
Festplatten
Abbildung 6.1: I/O Architektur eines Clusters. P Prozessoren sind durch mehrere I/O Kanäle mit D Festplatten verbunden.
Wir wollen diesen Abschnitt mit der Bemerkung abschließen, dass uns die Eins zu Eins Übertragung des Netzwerkkommunikationsmodells auf das Problem der Disk-Prozessor Interkommunikation ebenfalls auf eine Granularitätsgröße bei Schreib/Lese Operationen sprechen lässt. Es gibt also eine gewisse Anzahl von unterschiedlichen Schreib/Lese Operationen, die für
den Datentransfer zwischen Platte und Hauptspeicher (und umgekehrt) notwendig sind. Je weniger solcher Operationen pro
Rechenzyklus generiert werden, desto niedriger ist die Auswirkung der I/O Leistung auf die gesamte Performance des Systems und
der darauf laufenden Applikationen.
- 36 -
KAPITEL 7 - Mathematische Grundlagen zum Optimierungsverfahren
Unser Ziel ist, wie wir es im Kapitel 2 bereits angedeutet haben, ein mathematisches Modell zu entwickeln, das uns den Prozess
der Konfiguration und Angeboterstellung eines HPC Clusters (oder kurz: Das Konfigurationsproblem) optimieren lässt. Diese
Optimierung verstehen wir als die vereinfachte Suche nach einem Gleichgewicht zwischen Rechenleistung und Wirtschaftlichkeit
eines Systems. Wenn wir als Unternehmen das allgemeine Problem der Erstellung eines Angebots für ein Clustersystem näher
betrachten erkennen wir die Existenz von zwei Standardsituationen, die sich nur leicht voneinander unterscheiden: Es gibt Kunden
mit einem fest vorgegebenen Budget, diese wollen die beste Rechenleistung für das zur Verfügung stehende Geld bekommen. Das
Gegenteil ist auch möglich (obwohl etwas seltener zu sehen): Der Kunde legt eine vorgegebene minimale Rechenleistung fest und
will den besten Preis für diese Systemperformance bekommen. Beides Mal erkennen wir die Existenz eines Optimierungsproblems,
dessen erfolgreiche Lösung sowohl von technischen als auch von wirtschaftlichen Faktoren abhängt.
Wir haben in den letzten drei Kapiteln viele Aspekte behandelt die uns erst in die Lage versetzen, die Hardwarestruktur eines
Clusters sowie die Wechselwirkung dieser Hardware mit spezifischen Eigenschaften paralleler Applikationen zu verstehen.
Der nächste Schritt in die oben genannte Richtung besteht natürlich darin, eine solide Verbindung zwischen diesen technisch
orientierten Informationen und denjenigen Aspekten, die mit der Kostenoptimierung zu tun haben, aufzubauen.
Schon seit Anfang der vierziger Jahre versucht man, optimierte Lösungen für diverse Problemstellungen durch den Einsatz der
so genannten Simplexmethode zu erreichen, einem mathematischen Verfahren, das aus dem Gebiet der linearen Optimierung
bekannt ist. Wir wollen in diesem Kapitel das Verfahren genauer vorstellen, denn wir möchten dieses später als Ansatzpunkt
für die Lösung des Konfigurationsproblems benutzen. Dabei werden wir so viel vom Thema linearer Optimierung bzw. SimplexVerfahren in diesem Kapitel behandelt, wie es für die Analyse des Problems und die Erstellung eines mathematischen Modells
notwendig sein wird.
7.1
Lineare Optimierung
Im Jahre 1947 wurde von George B. Dantzing das Thema „lineare Optimierung“ mathematisch begründet. Dieses damals
ausschließlich für die Optimierung militärischer Einsätze konzipierte Verfahren wurde jedoch in den darauf folgenden Jahren als
Standardverfahren für die Optimierung verschiedener Probleme aus der Wirtschaft eingesetzt, einem Gebiet, in dem auch heute
noch ihre hauptsächliche Anwendung liegt.
Als eine ihrer bekanntesten Anwendungen ist sicherlich das Rundreiseproblem (engl. travelling salesman) zu nennen: Man sucht
nach der kürzesten Reiseroute zwischen n verschiedenen Orten, die alle Orte genau einmal besucht und am Ende wieder zum
Ausgangspunkt zurückkehrt. Auch das Transportproblem oder das Reihenfolgeproblem sind bekannte Anwendungsgebiete der
linearen Optimierung19). Kurz gesagt, es existieren in der Praxis zahlreiche unterschiedliche Optimierungsprobleme, die mit dem
Lösungsverfahren der linearen Optimierung, der Simplexmethode, gelöst werden können. Wir sind der Ansicht, dass sich das
Konfigurationsproblem mit dem wir uns hier befassen, unter bestimmte Voraussetzungen auf diese Weise lösen lässt. Daher wird
im Folgenden eine allgemeine Beschreibung des Verfahrens geliefert.
7.2
Problemstellung
In der Mathematik spricht man von einem Optimierungsproblem, wenn man die Bestimmung des Optimalen Wertes (Maximum
oder Minimum) einer sogenannten Zielfunktion zu erreichen versucht. Der Zielfunktion unterliegt einer bestimmten Anzahl von
Nebenbedingungen (auch Restriktionen genannt), welche die Funktionsbildenden Variablen direkt beeinflussen. Es gibt zahlreiche
Methoden, die für die Lösung solcher Probleme in der Mathematik eingesetzt werden können. Welche davon in der Tat benutzt
wird, hängt einzig und allein von der Form der Zielfunktion ab.
Lineare Optimierung20) ist das Verfahren, welches für die Lösung eines Optimierungsproblems angewendet wird, wenn die
Zielfunktion eine lineare Funktion ist und die Nebenbedingungen ebenfalls lineare Gleichungen bzw. lineare Ungleichungen sind.
Ein lineares Optimierungsproblem lässt sich letztlich stets in folgende Form bringen:
Das Transportproblem versucht die Transportkosten eines bestimmten Produktes zu minimieren, welche in n verschiedene Fabriken hergestellt wird. Die
Abnehmer des Produktes befinden sich an verschiedenen Orten und benötigen im Allgemeinen unterschiedliche Mengen des Produktes, so dass die Kosten
für den Transport je nach Entfernung der Fabriken und der Abnehmer unterschiedlich hoch sind. Das Reihenfolgeproblem versucht seinerseits die kürzeste
Gesamtlauf zu finden, die die Herstellung von n Produkten auf m Maschinen ermöglichen soll.
19)
Früher auch als „lineare Programmierung“ bezeichnet. Programmierung bedeutete damals noch in ihrem eigenen Sinn eine Planung, also das Aufstellen
eines Arbeitsplanes und wurde erst später mit dem wachsenden Einfluss des Computers mit dem Erstellen eines Computerprogramms in Zusammenhang
gebracht.
20)
- 37 -
Gesucht sind solche Werte der n reellen Variablen x1 , x2 , K, xn für welche die Zielfunktion
P(x) = p1x1 + p2x2 + K + pnxn
(7.1)
ihren Minimalwert annimmt, wenn alle Punkte betrachtet werden, deren Koordinaten die Nebenbedingungen
a11x1 + a12x2 + K + a1nxn = b1
a21x1 + a22x2 + K + a2nxn = b2
........................................... am1x1 + am2x2 + K + amnxn = bm
a11x1 + a12x2 + K + a1nxn = b1
erfüllen. Die Koeffizienten aij , bi , pj (i = 1.2, K , m, j = 1,2,K, n) sind dabei reelle Zahlen.
(7.2)
Ein Übergang von P(x) zu P(x) + const ändert nichts bezüglich der Minimalstelle. In
n
Matrizenschreibweise mit x ∈ R , der (m,n)-Matrix A = (aij), p = (p1 , p2 , K, pn )T,
T
b = b1 , K , bm
≥ o21) lässt sich die lineare Optimierungsaufgabe so formulieren:
(
)
Ax = b
x≥0
P(x) = pTx = Min!.
Ist das Maximum einer Zielfunktion gesucht, so ist dieses gleichbedeutend mit
P(x) = - P(x) = (- p1)x1 + K + (-pn)xn = Min!
Treten Ungleichungen als Nebenbedingungen auf, z.B. ai1x1 + K + ainxn ≤ bi , so kann man durch Definition einer neuen Variablen
w, einer sogenannten Schlupfvariablen, zur Gleichung ai1x1 + K + ainxn + w = bi übergehen. Auch für die neue Variable w gilt w ≥
0. In der Zielfunktion ordnen wir der Schlupfvariablen den Koeffizienten 0 zu.
Ein x = (x1, …,xn)T, das allen Nebenbedingungen genügt, heißt zulässiger Punkt. Die Menge aller zulässigen Punkte heißt zulässiger
Bereich. Ändert sich durch das Weglassen einer Nebenbedingung der zulässige Bereich nicht, so heißt diese Nebenbedingung
überflüssig.
7.3
Geometrische Deutung: Maximum- und Minimum-Optimierung im R ²
Bei Problemen mit zwei Variablen kann man darauf verzichten, von Ungleichungen durch Einführen einer Schlupfvariablen zu
Gleichungen überzugehen. Eine lineare Ungleichung a1x1 + a2x2 ≤ b lässt sich unmittelbar geometrisch interpretieren: Alle Punkte,
die dieser Ungleichung genügen, liegen auf der Geraden a1x1 + a2x2 = b und in einer der Halbebenen, in die diese Gerade
die Ebene teilt. So lassen sich im R ² die Nebenbedingungen durch lineare Ungleichungen mit zwei Variablen sowie durch die
Nichtnegativitätsbestimmungen der beiden Variablen darstellen. Dadurch wird ein begrenztes oder auch offenes Gebiet, eine
konvexe Menge, festgelegt22).
Diese konvexe Menge kann entweder beschränkt (Abb. 6.1 a und b) oder unbeschränkt (Abb. 6.1 c) sein: eine solche beschränkte
konvexe Menge nennt man auch ein Simplex.
x2
x2
a)
x1
x2
b)
x1
c)
x1
Abbildung 7.1: Verschiedene Arten zulässiger Bereiche für Maximum-Optimierung
21)
x ≥ o heißt also x1 ≥ 0, K ,xn ≥ 0
Eine Menge S in einem n-dimensionalen Raum wird als konvexe Menge bezeichnet, wenn jedes Segment, das zwei beliebige Punkte innerhalb der Menge
verbindet, sich vollständig innerhalb von S befindet.
22)
- 38 -
Alle Elemente, die eine zulässige Lösung für das Problem darstellen, müssen folglich auch Elemente dieser konvexen Menge sein.
Da sämtliche Ungleichungen aus „≤“-Zeichen bestehen, gehören auch die Rand- und Eckpunkte zu dieser Menge. Von diesen
verschiedenen zulässigen Lösungen gilt es nun, denjenigen Wert zu finden, für den die Zielfunktion ihr absolutes Maximum
oder auch Minimum annimmt. Je nach Art der Zielfunktion und der dazugehörigen Lösungsmenge gibt es natürlich auch
unterschiedliche Lösungsmöglichkeiten: Beim ersten Beispiel von Abb. 7.1 gibt es genau einen Punkt, für den die Zielfunktion
einen maximalen Wert annimmt: diesen Punkt nennt man auch Lösung der Maximum Optimierung.
Anders beim Beispiel b) in der Abb. 7.1; hier existiert eine ganze Strecke als Lösung, die von zwei Eckpunkten beschränkt wird.
Einen solchen Fall nennt man eine mehrdeutige Lösung: Es gibt mehrere Optimalpunkte, mit denen jeweils derselbe optimale
Wert erreicht wird; in der Praxis erfolgt in einem solchen Fall die Auswahl aus den verschiedenen Lösungen nach anderen
Gesichtspunkten, wie z.B. Flexibilität, Skalierbarkeit, etc. Ist die Menge der zulässigen Lösungen unbeschränkt, wie in c), so kann
man kein absolutes Maximum und somit auch keine Lösung finden. In diesen beiden letzten Fällen treten bei der rechnerischen
Lösung Unstimmigkeiten auf, aus denen man die Art der Lösung leicht erkennen und dann passende Maßnahmen ergreifen kann.
Ebenfalls möglich ist der Fall, dass überhaupt kein Bereich von zulässigen Elementen existiert, es also z.B. keinen Punkt gibt, der
zwei Ungleichungen gleichzeitig erfüllt. In diesem Fall kann natürlich auch keine optimale Lösung gefunden werden.
Bei einer Minimum Optimierung treten Unterschiede genau diesbezüglich auf (Abb. 7.2):
x2
x2
a)
x1
x2
b)
x1
c)
x1
Abbildung 7.2: Verschiede Arten zulässiger Bereiche für Maximum Optimierung
Es lässt sich aus der Abbildung 7.2 sofort entnehmen, dass hier eine unbeschränkte konvexe Menge nicht unbedingt bedeuten
muss, dass keine Lösung gefunden werden kann.
Ganz im Gegenteil gibt es bei einer Minimum Optimierung immer mindestens eine Lösung: entweder ein Eckpunkt, wie bei dem
Fall in a), eine Strecke als Lösung in b) oder gar, wie beim letzten Fall, den Ursprung (0,0) als absolutes Minimum. Da die Nicht
negativitätsbedingungen notwendigerweise ein Teil jeder Optimierungsaufgabe sind, sollte diese Tatsache eigentlich nicht sehr
verwundern. Dies bedeutet einfach, dass auf jeden Fall ein Minimum gefunden werden kann, unabhängig davon, ob die Menge
der zulässigen Lösungen unbeschränkt ist oder nicht.
Speziell in kleineren Dimensionen kann die rechnerische Lösung (wie wir sie im kommenden Abschnitt behandeln werden)
zu aufwändig im Vergleich zu der graphischen Lösung sein. Dieses graphische Verfahren findet nur in zwei, höchstens drei
Dimensionen eine vernünftige Anwendung. In größeren Dimensionen kann man Optimierungsaufgaben nicht mehr auf einfache
Weise graphisch darstellen. Solche mehrdimensionalen Aufgaben werden ausschließlich durch Computerberechnungen gelöst.
Wir haben das graphische Lösungsverfahren trotzdem hier mitbehandelt, weil wir dadurch einige wichtige Aspekte der linearen
Optimierung übersichtlicher darstellen können.
7.4
Der Simplex-Algorithmus und die Bildung des Simplextableaus
Der erste Schritt beim Simplex-Algorithmus besteht darin, alle Nebenbedingungen eines Linearen Optimierungsproblems (LOP) so
umzuschreiben, dass sie einen positiven konstanten Wert auf der rechten Seite der Ungleichungen aufweisen. Dann wandeln wir
alle Ungleichungen in Gleichungen, durch die Einführung der oben genannten Schlupfvariablen, um.
Zum Beispiel lassen sich die Ungleichungen –x + 2y ≤ 6 und 5x + 4y ≤ 40 entsprechend als –x + 2y + w1 = 6 und
5x + 4y + w2 = 40 umschreiben, wobei w1 und w2 Variablen sind, die positive Werte (oder den Wert Null) annehmen können und 1
als Koeffizient aufweisen. Diese neuen Variablen werden benötigt, um eine Justierung der linken Seite der Gleichungen bezüglich
der konstanten Terme auf der rechten Seite zu ermöglichen. Betrachten wir folgendes Beispiel.
Das Maximum der Zielfunktion P(x,y) = x + 4y wird gesucht. P(x) unterliegt folgenden Restriktionen: –x + 2y ≤ 6 und 5x + 4y ≤
40. Da ständig x, y ≤ 0 schreiben wir die Nebenbedingungen wie oben erläutert
- 39 -
–x + 2y + w1
= 6
5x + 4y
+ w2 = 40
und die Zielfunktion
(7.3)
P – x – 4y = 0
Ein LOP, das in der oben genannten Form vorliegt, befindet sich in der kanonischen Form. Ein LOP in kanonischer Form kann in
einer Tabelle folgender Art gespeichert werden: Wir konstruieren zuerst eine Variablen Identifizierungszeile wie unten abgebildet
(der Einfachheit halber benutzen wir hierfür das Beispiel oben)
x
y
w1
w2
b
Verif
Als nächstes tragen wir die Koeffizienten der Problemvariablen sowie die von der Schlupfvariablen in der Tabelle ein. Ebenso
werden die Konstanten (6, 40) auf der rechten Seite von (6.3) in der Spalte b aufgeschrieben. Wir erhalten
x
y
w1
w2
b
Verif
-1
2
1
0
6
5
4
0
1
40
Die letzte Spalte „Verif“ auf der rechten Seite der Tabelle wird eingeführt um die Verifizierung der Zwischenergebnisse von der
Berechnung zu vereinfachen. Wir tragen dort die Summe der Koeffizienten jeder Zeile ein, wobei der Term auf der Spalte b
mitberücksichtig wird. Dies liefert
ProblemVariablen
SchlupfVariablen
Konstanten
Basis
x
y
w1
w2
b
Verif
w1
-1
2
1
0
6
8
w2
5
4
0
1
40
50
Kern
Einheitsmatrix
Ein kurzer Blick auf die Tabelle zeigt uns, dass die zwei vorhandenen Nebenbedingungen (n=2) nun vier Variablen aufweisen
(m = 4). Wir tragen die Basisvariablen in eine separate Spalte auf der linken Seite der Tabelle ein. Ferner merken wir, dass die
Spalten mit den Koeffizienten der Schlupfvariablen eine Einheitsmatrix bilden.
Als letztes betrachten wir die Zielfunktion P = x + 4y. Wir schreiben sie wie folgt um: P - x + 4y = 0, und tragen ihre Koeffizienten
in der letzten Zeile, der sog. Indexzeile unten im Tableau ein, also:
Basis
x
y
w1
w2
b
Verif
w1
-1
2
1
0
6
8
w2
5
4
0
1
40
50
P
-1
-4
0
0
0
-5
Somit haben wir ein so genanntes Simplextableau für das LOP in (7.3) vervollständigt und wir können uns der Lösung desselben
widmen.
- 40 -
7.5
Schritte zur Berechnung des Simplexes
i)
Wir selektieren die Spalte mit dem größten negativen Koeffizienten auf der Indexzeile, in unserem Fall -4. Diese Spalte
wird als Pivotspalte bezeichnet. Wir markieren sie hier mit einem Kästchen.
Basis
x
y
w1
w2
b
Verif
w1
-1
2
1
0
6
8
w2
5
4
0
1
40
50
P
-1
-4
0
0
0
-5
Pivotspalte
ii)
Bei jeder Zeile dividieren wir den Wert in der Spalte b jeweils durch die positiven Koeffizienten aus der Pivotspalte. Der
40
6
kleinste Quotient bestimmt nun die sog. Pivotzeile. Für die Zeile 1 (w1), r = = 3 , für die Zeile 2 (w2), r =
= 10 . Die Zeile 1 wird
4
2
also unsere Pivotzeile. Wir markieren sie ebenfalls mit einem Kasten:
Pivotelement
Basis
x
y
w1
w2
b
Verif
w1
-1
2
1
0
6
8
w2
5
4
0
1
40
50
P
-1
-4
0
0
0
-5
Pivotzeile
Das Tabellenelement bei dem sich Pivotzeile und Pivotspalte treffen ist das Pivotelement: Hier die Zahl 2.
iii)
Als nächstes dividieren wir alle Einträge in der Pivotzeile durch das Pivotelement um diese in eine 1 umzuwandeln. In
dem unten stehenden Simplextableau haben wir dieses Element mit einem Kreis markiert. Die neue so entstehende Zeile wird als
Hauptzeile bezeichnet. Die restlichen Elemente des Tableaus bleiben unverändert, so dass wir folgendes erhalten
Einheitspivot
Basis
x
y
w1
w2
b
Verif
w1
-½
1
½
0
3
4
w2
5
4
0
1
40
50
P
-1
-4
0
0
0
-5
Hauptzeile
Indexzeile
Pivotspalte
iv)
Nun benutzen wir die Hauptzeile um auf den anderen Zeilen des Tableaus zu operieren (einschließlich der Indexzeile).
Somit lassen sich die anderen Koeffizienten in der Pivotspalte auf Null reduzieren. Die Hauptzeile bleibt dabei unverändert. Die
neuen Einträge in den restlichen Positionen auf dem Tableau, inklusive der in der b Spalte und der Verifizierungsspalte, lassen sich
wie folgt bestimmen:
Neuer Wert = Alter Wert – Produkt der entsprechenden Einträge auf der Pivotzeile und der Pivotspalte
1
A
B
K
Hauptzeile
K
wird durch
K - (A X B) ersetzt
Zum Beispiel in der zweiten Zeile (w2):
5 wird durch 5 – (–½) · (4) = 5 + 2 = 7 ersetzt
4 wird durch 4 – (1) · (4) = 4 – 4 = 0 ersetzt
0 wird durch 0 – (½) · (4) = 0 – 2 = –2 ersetzt
50 wird durch 50 – (4) · (4) = 50 –16 = 34 ersetzt, etc.
- 41 -
Und für die Indexzeile:
–1 wird durch –1 – (–½) · (–4) = –1 – 2 = –3, etc.
Wenn wir auf diese Weise weitermachen und die Operationen für die Zeile (P) vervollständigen, erhalten wir23)
Basis
x
y
w1
w2
b
Verif
w1
-½
1
½
0
3
4
w2
7
0
-2
1
28
34
P
-3
0
2
0
12
11
v)
Änderung der Basisvariablen: In ihrer Endform besteht die Pivotspalte aus einer einzigen Eins und sonst Nullen. Die 1
taucht in der Spalte y auf, das bedeutet, dass die Variable w1 auf der Basisspalte sich durch y ersetzen lässt.
Basis
x
y
w1
w2
b
Verif
-½
1
½
0
3
4
w2
7
0
-2
1
28
34
P
-3
0
2
0
12
11
y w1
Es gibt nun zwei Spalten, die aus einer 1 und sonst nur Nullen bestehen. Diese sind y und w2, welche ab jetzt die Basisvariablen auf
der linken Spalte darstellen. Wenn wir die Werte auf der b Spalte ablesen, können wir eine neue Basis angeben, nämlich y = 3 und
w2= 28. Jede andere Variable, die auf der Basisspalte nicht auftaucht, hat nun den Wert Null. Eine LOP Lösung in diesen Moment
würde lauten x = 0, y = 3, w2 = 28. Wir sind jedoch noch nicht fertig. Die Indexzeile (P) enthält noch einen negativen Eintrag, so
dass wir das obige Verfahren wiederholen müssen.
Basis
x
y
w1
w2
b
Verif
y
-½
1
½
0
3
4
w2
7
0
-2
1
28
34
P
-3
0
2
0
12
11
Pivotzeile
Pivotspalte
Jetzt dividieren wir die Pivotzeile durch das Pivotelement (7) um dieses auf 1 zu reduzieren. Somit erhalten wir:
Basis
x
y
w1
w2
b
w1
-½
1
w2
1
P
-3
Verif
½
0
3
4
0
2 7
-/
1 7
/
4
34 7
0
2
0
12
11
/
Pivotzeile
Hier können wir die Rolle der Verifizierungsspalte deutlich erkennen. Wenn die erhaltenen Werte in dieser Spalte nicht mit den Summen der Elemente auf
den entsprechenden Zeilen übereinstimmen, ist mit Sicherheit einen Fehler während der Berechnung unterlaufen.
23)
- 42 -
Wir benutzen die Hauptzeile erneut, um auf die anderen Zeilen des Tableaus zu operieren und dadurch die in der Pivotspalte
enthaltenen Einträge auf Null zu reduzieren:
Basis
x
y
w1
w2
b
Verif
y
0
1
5 14
/
1 14
/
5
45 7
w2
1
0
-2/7
1 7
/
4
34 7
P
0
0
8 7
/
3 7
/
24
179 7
/
/
/
Wir merken nun, dass w2 in der Basisspalte sich durch x substituieren lässt. x war eben der Name der Spalte, die das letzte
Pivotelement enthalten hat. Wir bekommen schließlich:
Basis
x
y
w1
w2
b
Verif
y
0
1
5 14
/
1 14
/
5
45 7
x
1
0
2 7
-/
1 7
/
4
34 7
P
0
0
8 7
/
3 7
/
24
179 7
/
/
/
Eine neue Basis besteht jetzt aus x = 4 und y = 5. Ferner, da wir keine negativen Einträge mehr in der Indexspalte finden, sind wir
auf die optimale Lösung für das LOP Problem (7.3) gekommen. Der optimale Wert von P ist aus der b Spalte abzulesen: Pmax = 24.
Wir haben hier eine mehr oder weniger detaillierte Darstellung des Simplexalgorithmus abgeliefert, wenn auch nur in zwei
Variablen. Obwohl das Konfigurationsproblem sicherlich mehr als zwei Variable enthalten wird, können wir erkennen, dass das
soeben ausführlich beschriebene Simplex-Verfahren grundsätzlich gleich bleibt, auch wenn wir es auf Probleme mit mehr als zwei
Variablen einsetzen möchten.
Die Tatsache, dass es sich bei dem Simplex-Verfahren um einen Iterationsprozess handelt, welcher so oft wiederholt werden
muss, bis die Indexseile keine negativen Einträge mehr aufweisen, macht es leicht durch den Einsatz eines Computerprogramms
Lösungen für LOP Probleme mit mehreren Variablen zu finden. Eine Lösung des Konfigurationsproblems in Softwareform wird uns
daher später nahe gelegt.
7.6
Künstliche Variablen
Bevor wir unseren Ausflug in die mathematischen Grundlagen der Optimierung abschließen, müssen wir noch eine Methode
betrachten, die das Simplex-Verfahren in seiner Anwendbarkeit kräftig erweitert. Dazu nehmen wir folgendes Beispiel: Wir wollen
die Funktion P = 7x + 4y maximieren, die mit den Restriktionen: 2 x + y ≤ 150, 4 x + 3 y ≤ 350 und x + y ≥ 80 (x, y ≥ 0) versehen
ist. Wenn wir diese Ungleichungen durch die Einführung von Schlupfvariablen in Gleichungen umwandeln, bekommen wir:
= 150
2 x + y + w 1
4x+3y
+ w 2
= 350
(6.4)
x+ y
- w 3 = 80
und die Zielfunktion lautet: P - 7x - 4y = 0. Die dritte Restriktion ist eine „Größer als“ Bedingung, so dass man die positive
Schlumpfvariable (w3) subtrahieren muss, um die Gleichung zu erhalten. Wir bilden unser erstes Tableau
Basis
x
y
w1
w2
w3
b
Verif
w1
2
1
1
0
0
150
152
w2
4
3
0
1
0
350
358
w3
1
1
0
0
-1
80
81
P
-7
-4
0
0
0
0
-11
- 43 -
Wir stehen jetzt vor einem Problem, denn wir haben keine Einheitsmatrix im Tableau, mit der wir nach dem Simplex-Verfahren
vorgehen können. Die Spalte w3 enthält das Element -1 und somit ist es für uns unmöglich, durch irgendeine arithmetischen
Operation gleichzeitig eine positive 1 in der Spalte w3 zu bekommen und alle Elemente in der Spalte (b) der Konstanten noch
positiv zu halten (die Konstanten in b sind per Definition positiv). Die Ursache des Problems liegt eigentlich in der Anwesenheit
eines negativen Terms bei der Schlumpfvariablen in (6.3). Wir können trotzdem die Situation lösen, und zwar durch die Einführung
einer neuen kleinen positiven Variablen (w4), so dass w1, w2 und w4 einer Einheitsmatrix bilden und die Anwendung des SimplexVerfahren wieder möglich wird. Selbstverständlich ist w4 von fiktivem Charakter und muss daher verschwindend klein gewählt
werden. Sie darf ebenfalls beim Endergebnis nicht mehr auftauchen.
Um all diese Bedingungen zu erfüllen, führen wir in die Zielfunktion den neuen Term -Mw4 ein, wobei M ein sehr großer, positiver
Koeffizient ist. Dies garantiert uns letztendlich, dass w4 aus dem Endergebnis verschwinden wird. Wir schreiben dann: P = 7x +
4y – Mw4. Die neue Variable w4 wird künstliche Variable genannt. Die dritte Nebenbedingung in 6.4 wird zu
x + y - w 3 + w4 = 80
Wir schreiben das System (6.4) erneut um:
2x + y + w 1
4x + 3y
+ w 2
x+ y
- w 3 + w4
P - 7x - 4y + Mw4
= 150
= 350 = 80
= 0
(6.5)
Als nächstes wird das Simplextableau wie üblich gebildet:
Basis
x
y
w1
w2
w3
w4
b
Verif
w1
2
1
1
0
0
0
150
152
w2
4
3
0
1
0
0
350
358
w4
1
1
0
0
-1
1
80
81
P
-7
-4
0
0
0
M
0
M-11
Merken wir uns:
i)
Die Spalten w1, w2 und w4 bilden nun eine Einheitsmatrix
ii)
Es gibt jetzt 6 Variable und 3 Nebenbedingungen, das heißt, n = 6 und m = 3, so dass aus (n – m), 6 -3 = 3. Es
müssen also 3 Variablen gleich Null gestellt werden. Wir starten mit x, y und w3 als Null. w1, w2 und w 4 bilden die
erste Basislösung mit den Koeffizienten in der b Spalte.
Wir verfahren nun wie im Abschnitt 6.5 bereits beschrieben und arbeiten nach dem Verfahren so lange an dem Tableau, bis kein
weiterer negativer Eintrag in der Indexzeile zu finden ist. Wir wollen auf die nötigen Zwischenberechnungen verzichten und eher
das Tableau bis zu diesem Punkt gleich angeben:
Basis
x
y
w1
w2
w3
w4
b
Verif
x
1
0
3 2
/
-½
0
0
50
52
w3
0
0
-½
½
1
-1
20
20
y
0
1
-2
1
0
0
50
50
P
0
0
5 2
/
-½
0
M
550
M-553
Die optimale Lösung für das Problem (6.4) bzw. (6.5) lautet am Ende:
Pmax = 500
mit
x = 50, y = 50
- 44 -
KAPITEL 8 - Das Konfigurationsproblem
Nachdem wir in Kapitel 7 die mathematischen Grundlagen zur Lösung von allgemeinen linearen Optimierungsproblemen
nach dem Simplex-Verfahren diskutiert haben, können wir nun zum ersten Mal versuchen eine quantitative Aussage über das
Konfigurationsproblem zu liefern. Dafür müssen wir in der Lage sein, dieses Problem in algebraischer Form umzuschreiben und
zwar in Form einer linearen Funktion. Die entsprechenden Restriktionen denen die Funktion unterliegt, müssen ebenfalls eine
Gruppe von linearen Gleichungen bzw. Ungleichungen bilden, wenn das Simplex-Verfahren hier Anwendung finden soll.
An dieser Stelle müssen wir uns im Klaren sein, dass es sich bei dem hier dargestellten Lösungsansatz um einen ersten Versuch
handelt, der uns zu einem besseren Verständnis der Zusammenhänge verhelfen soll. Es ist durchaus möglich, dass auf Grund der
komplexeren Natur des Konfigurationsproblems die Anwendung anderer mathematischer Methoden bzw. Optimierungsverfahren
notwendig sein wird, um praxistaugliche Ergebnisse durch den Einsatz des Clusterkonfigurators zu erreichen. Wir würden jedoch
ohne diese erste Evaluierung nicht tiefer in die Analyse des Konfigurationsproblems gehen können.
8.1
Die Definition einer Zielfunktion
Die Entwicklung eines mathematischen Modells, das die Gegebenheiten eines konkreten Problems so akkurat wie möglich
wiedergeben soll, verfolgt immer ein ähnliches Muster. Die Hauptmerkmale, die das Problem charakterisieren, müssen
als mathematische Variablen dargestellt werden und die Art und Weise wie diese Problemcharakteristika untereinander
Wechselwirken, muss in Form von mathematischen Funktionen ausgedrückt werden. Diese Funktionen können ebenfalls
wichtige limitierende Faktoren innerhalb des Problems in algebraische Form ausdrücken. Wir werden dieses Schema verfolgen.
Es müssen aber dazu noch einige vernünftige, vereinfachende Annahmen gemacht werden, um unsere erste Annäherung zu der
algebraischen Form des Konfigurationsproblems nicht unnötig zu erschweren.
Wir wissen, z.B. dass das Konfigurationsproblem zwei grundlegende, wenn auch leicht unterschiedliche Ziele, verfolgen kann: Man
will die Leistung einer bestimmten Clusterkonfiguration bei einen vorgegebenen Preis optimieren, also
Leistung = max!
Preis
}
= const.
(8.1)
oder man hat als Vorgabe eine bestimmte Leistung zu erreichen und will für derer Anschaffung so wenig wie möglich bezahlen:
Leistung = max!
Preis
}
= min!
(8.2)
Wir werden ansatzweise das Konfigurationsproblem in der Form (8.2) in Angriff nehmen, wir hätten jedoch genauso gut mit der
Form (8.1) starten können. Von zentraler Bedeutung für die geeignete mathematische Deutung des Problems, ist das Aufstellen
einer linearen Funktion, die sowohl als Zielfunktion im mathematischen Sinne fungieren muss und die Gegebenheiten des
Problems in guter Annäherung wiedergeben kann.
In Übereinstimmung mit der Gleichung (6.1) definieren wir zunächst einen sog. Preisvektor P, dessen Komponenten, den auf dem
Markt zum gegebenen Zeitpunkt geltenden Hardwarepreisen entsprechen.
1
2
3 4
5
6
(8.3)
pi stellt den Preis für die i-te Hardwarekomponente dar. Die pi sind also reine skalare Größen und die Variable i ( i = 1, 2, K , N ) zählt
die relevanten Hardwarekomponente durch, welche am Aufbau des Clusters beteiligt sind (also CPU, RAM, NIC, usw.).
Nun definieren wir einen zweiten Vektor, nämlich der Stückzahlvektor N, dessen Komponenten nun die auftretenden Mengen des
i-ten Hardwareteils angeben, z. B. 32 Netzwerkkarten, 64 CPUs, etc:
1
2
3
4
5
6
- 45 -
(8.4)
Durch die Bildung des Skalarproduktes dieser zweier Vektoren lässt sich eine lineare Funktion bilden, die wir als Kostenfunktion
K(p) bezeichnen werden. Also
K = N T · p
(8.5)
Formal ausgedrückt bekommen wir für (8.4) 24)
N
T
Ni ⋅ p j
K = (N i ) ⋅ p j = δ i j
i , j =1
0 falls i ≠ j
wobei die Koeffizienten δ i j wie folgt definiert sind: δ i j = 
. Die obere Beziehung ist jedoch nichts anderes als
1
falls
i
=
j
eine lineare Funktion der Form (v. Gl. (6.1):

( )
∑
K (p) = N1p1 + N2p2 + K + Nnpn (8.6)
Diese einfache Funktion wollen wir als Zielfunktion für das Konfigurationsproblem betrachten und wie aus der Formulierung (8.2)
zu entnehmen ist, muss sie eben minimiert werden:
K (p) = N T p = min !.
8.2
(8.7)
Die Randbedingungen
Der nächste Schritt zur mathematischen Formulierung des Problems besteht darin, die in Betracht kommenden Randbedingungen
im Sinne von Gl. (6.2) zu definieren. Abhängig von der Form des Konfigurationsproblems unterliegt der Funktion (8.6) eine
variable Anzahl solcher Bedingungen. Einige davon sind sicherlich allgemeiner Natur, so dass sie unter Umständen innerhalb
jedes Konfigurationsproblems, welches wir in der Form (8.2) formulieren können, Gültigkeit finden. Es gibt jedoch andere
Anfangsbedingungen, deren Form sehr stark von den Besonderheiten einer spezifischen Konfiguration abhängt. Im Folgenden
behandeln wir die allgemeingültigen Anfangsbedingungen. Die Diskussion über die problemabhängigen Randbedingungen
verschieben wir auf den nächsten Abschnitt. Dort werden wir uns mit einer Beispielkonfiguration ausführlich beschäftigen und
anschließend einen ersten Einsatz des Clusterkonfigurators versuchen.
Obwohl die erste Randbedingung mit der wir uns hier beschäftigen ziemlich trivial wirkt, muss sie bei der Mathematik des
Problems unbedingt betrachtet werden. Sie lautet:
N1 ≥ 0, N2 ≥ 0, NN ≥ 0
(8.8)
Diese Beziehungen entsprechen der logischen Vorstellung, dass jede Hardwarekomponente mindestens einmal bei der
Clusterkonfiguration vorkommt. Bei der Lösung des Konfigurationsproblems (8.2) kann jedoch häufiger die Bedingung auftreten.
N1 ≥ m, N2 ≥ m, K, NN ≥ m
(8.9)
Diese Beziehung, im Gegenteil zu (8.7), fixiert die Mindestanzahl von Knoten im Cluster auf den Wert m. Daraus lässt sich
gleichfalls entnehmen, dass jede relevante Hardwarekomponente mindestens einmal pro Knoten vorkommen muss.
Man könnte hierzu einwenden, dass die Zahl m der Knoten eigentlich nicht vorgegeben sein sollte, also erst durch den Einsatz
des Clusterkonfigurators in Erfahrung gebracht werden müsste. Die Praxis zeigt uns jedoch, dass dieses Vorgehen in der Tat
notwendig ist, denn es gibt ja bekanntlich verschiedene technische Grenzen, welche die Festlegung einer unteren Grenze bei der
Knotenzahl erzwingen25). Wir müssen dabei beachten, dass die Zahl m keineswegs die endgültige Knotenzahl für die gegebene
Clusterkonfiguration darstellt. Sie ist nur dazu da, um uns bei der Aufgabe zu helfen, deutlich plausiblere Ergebnisse zu erzielen.
Die zweite Randbedingung mit einem allgemeingültigen Charakter besagt, dass eine geforderte Gesamtperformance erreicht
werden muss. Diesem entspricht die Aussage Leistung = const. aus (8.2). Da wir nach dem Simplex-Verfahren vorgehen
wollen, haben wir also nach einer linearen Beziehung zu suchen, die in der Tat einiges gewährleisten muss. Zum einen muss sie
Änderungen an der Hardwarekonfiguration zulassen und die unterschiedliche Leistungswerte für die jeweiligen Komponenten
zum Ausdruck bringen. Zum anderen muss die Funktion in der Lage sein, den Einfluss von einer gegebenen Applikation auf die
gesamte Performance zu berücksichtigen. Diese Beziehung bzw. Funktion wird anschließend dem konstanten, vorgegebenen Wert
für die Performance gleichgestellt.
24)
Zur Erinnerung: Aus einer gegebenen n X m-Matrix A lässt sich durch Spiegelung der Elemente an der Hauptdiagonalen (gebildet durch die Elemente
a11, a22, a33, K ...) die sog. transponierte m x n-Matrix AT bilden. Also AT = aijT = a ji Vektoren sind Matrizen mit einer einzigen Spalte.
Die theoretische maximale Leistung heutiger CPUs liegt nur knapp über der 3 GFlop/s Grenze, so dass eine Leistung von z.B. 100 Gflop/s prinzipiell erst ab
40 CPUs erreicht werden kann.
25)
- 46 -
Um die Form einer solchen Funktion zu bestimmen haben wir zwei wichtige Richtlinien zu verfolgen: Einerseits muss die Funktion,
wie oben gesagt, eine lineare Form aufweisen, andererseits muss sie die Leistung der jeweiligen Hardwarekomponenten bzw.
Subsysteme durch zwei Kennzahlen beschreiben, nämlich die Latenzzeit und die Bandbreite (s. 4.6). Auf dieser Weise können wir
erwarten, die durch den Einsatz des Clusterkonfigurators stark von einander abweichenden Clusterkonfigurationen beschreiben
zu können.
Wir führen hierzu einen Performancevektor s wie folgt ein
s =
 s1 
 
r  s2 
si =  
M
 
s 
 N
(8.10)
dessen Komponenten sich durch die jeweiligen Leistungswerte der performancerelevanten Hardwarebestandteile ausdrücken
lassen. In Abschnitt 4.6 haben wir allerdings das Performanceproblem in ein Kommunikationsproblem uminterpretiert. Dabei sind
wir zu dem Schluss gekommen, dass wir die Leistung sämtlicher Hardwarekomponenten mit Hilfe ihrer charakteristischen Werte
für die Latenzzeit und die Bandbreite bei der Interprozesskommunikation bestimmen können.
Wir bringen gerade dies zum Ausdruck, indem wir die Komponenten si des Vektors s mit der Interprozesseskommunikationszeit
t identifizieren, so wie sie durch die Beziehung (4.13) im Abschnitt 4.6 definiert wurde: t = tL + tW L (tL = Latenzzeit, tW =
Transferzeit, L = Größe der übertragenen Nachricht). Für den Netzwerkkommunikationsanteil nehmen wir statt (4.13) natürlich die
Beziehung (6.3): t = tL + tW n L, welche zusätzlich die Konkurrenz für die Bandbreite zwischen n kommunizierenden Prozessoren
berücksichtig. Wir machen außerdem von der Tatsache gebraucht, dass B ≡ tW L und schreiben die Komponenten des Vektors
(8.10) in ausführlicher Form wie folgt:
s
 (t L + B )1 


 (t L + B )2 
M 
r 

= si = 
 (t L + nB )j 

M 

 (t + B ) 
k 
 L
(8.11)
wobei wir die Komponente j mit dem Netzwerkanteil identifiziert haben, n die Anzahl von Prozessoren ist und k < N 26).
Laut (8.11) hängt die Leistung des Systems von der Anzahl der performancerelevanten Komponenten und ihrer entsprechenden
Interprozesskommunikationsleistung ab. Wir haben dabei dennoch die Auswirkungen der Applikationseigenschaften auf der
gesamten Leistung des Clusters noch nicht betrachtet. Um diesem wichtigen Faktor ins Modell einfließen zu lassen, führen wir eine
sog. Gewichtungsmatrix G mit der Form
0
 g1

 0 g2
 M

 0 K

0 

M
G=

O

g kk 
K
(8.12)
ein, deren Elemente gij sog. Gewichtungsfaktoren sind. Diese Elemente erlauben uns den Aufbau einer Beziehung zwischen einer
Applikation und den spezifischen Hardwareressourcen, die von dieser Applikation beansprucht werden. Die Matrix G ist auf 1
normiert, also gilt | G | = 1. Dieses heißt in der Praxis, dass jede Komponente gij einen Wert zwischen 0 und 1 annimmt, so dass
folgende Beziehung gilt
n
∑δ
ij
g i = g1 + g 2 + L + g n = 1
i , j =1
(8.13)
26)
Der Unterschied zwischen den Zahlen N und k der Komponenten lässt sich am besten verstehen wenn man bedenkt, dass der Vektor N solche
Hardwarekomponenten wie Hauptplatine, Gehäuse, Netzteile, usw. berücksichtigen muss. Diese sind hinsichtlich der Performancebestimmung mehr oder
weniger unbedeutsam.
- 47 -
wobei die Koeffizienten
δ ij
0
1
wieder die Bedingungen δ i j = 
falls i ≠ j
falls i = j
erfüllen. Die durch die Beziehung
s´ = G s
(8.14)
definierte Transformation des Performancevektor s liefert uns den Vektor s´, den wir hier Gewichtetenperformancevektor nennen.
Die Komponenten von s´ sehen wie folgt aus
s´ =
0
 g1

 0 g2
 M

 0 K

0 

M


g kk 
K
O
 (t L + B )1 


 (t L + B )2 

M 


 (t L + nB )j 

M 

 (t + B ) 
k 
 L
Das ist
 g1 (t L + B )1 


 g 2 (t L + B )2 

M
r 

s´ = s ′ = 
 g j (t L + nB )j 


M




(
)
g
t
+
B
k 
 k L
(8.15)
Um auf die Gesamtperformance zu kommen, brauchen wir nur noch einen neuen Stückzahlvektor M, der sich aber vom
Stückzahlvektor (8.4) unterscheidet, indem er, ähnlich wie die Vektoren s und s´, nur die performancerelevanten Komponenten
durchzählt.
M=
 M1 


r
 M2 
Mj =
M


M 
 k
Wir bilden schließlich das Skalarprodukt zwischen den zwei Vektoren s´ und Nk um die von uns gesuchte lineare Funktion
Performance = const zu erhalten. Wir bekommen wie üblich
S = M T · s´
(8.16)
Formal ausgedrückt bekommen wir für (8.16)
( )
k
S = (M i )T ⋅ s ′j = δ i j
M i ⋅ s ′j
i , j =1
also
S (s´) = M 1 s1′ + M 2 s 2′ + K + M k s k′
Die von uns gesuchte zweite Randbedingung, lautet nun einfach:
M 1 s1′ + M 2 s 2′ + K
oder mit Hilfe von (8.15)
∑
+ M n s n′
= const
(8.17)
M 1 g1 (t L + B )1 + M 1 g1 (t L + B )1 + L + M j g j (t L + nB )j + K + M k g k (t L + B )k = const
(8.18)
- 48 -
Für eine erste Annäherung zu der Form der Leistungsfunktion soll uns Gleichung (8.18) genügen, ansonsten würde der
Komplexitätsgrad des Modells deutlich über die Maßen steigen.
8.3
Problemabhängige Randbedingungen: Eine Beispielkonfiguration.
Bisher haben wir die Form von zwei allgemeingültigen Randbedingungen betrachtet, die bei der Analyse eines beliebigen
Konfigurationsproblems eine gesonderte Rolle spielen. Die Gemeinsamkeiten unter den verschiedenen Konfigurationsproblemen
hören jedoch an dieser Stelle gleich auf. Von einfachen Tatsachen ausgehend, wie die Anzahl von Rechenknoten oder die
Technologie des Kommunikationsnetzwerkes bis hin zu der parallelen Applikationen selbst die Vielfältigkeit der Faktoren, die
bei der Konfiguration eines Clusters eine Rolle spielen ist einfach enorm. Aus diesem Grund glauben wir, dass eine verständliche
Darstellung des Verfahrens mit dem wir das Konfigurationsproblem zu lösen versuchen am besten erreicht ist, wenn wir gleich zu
einem konkreten Beispiel Bezug nehmen.
Gesucht ist die optimale Konfiguration für einen Cluster, auf dem eine stark CPU belastende Parallelapplikation laufen wird und
eine Rechenleistung von mindestens 80 GFlop/s erreicht werden soll. Abhängig von der Leistung der gewählten CPUs sollte diesem
die Rechenleistung von einem mit mindestens 20 Knoten ausgestatteten Cluster entsprechen. Wir werden im Folgenden die
notwendigen Schritten beschreiben, die hier als Vorbereitung für den Einsatz des Clusterkonfigurators dienen.
Die Untersuchung beginn mit folgenden Definitionen: Seien NCPU die Anzahl von CPUs (in Stück), die für den Aufbau eines Clusters
benötigt werden, NRAM die über den Knoten dieses Clusters verteilter Hauptspeicherkapazität (in GB), NNIC die gesamte Anzahl
von eingebauten NICs (in Stück) und NGsys die dazu notwendige Anzahl von Grundsystemen27), (ebenfalls in Stück). Aufgrund der
Performanceeigenschaften der Beispielapplikation, die wir auf dem Cluster laufen lassen werden, setzen wir ebenfalls voraus, dass
eine Dualprozessorarchitektur für die Knoten, wie auch dem Masterknoten, die bessere Wahl darstellt.
Rein theoretisch kann eine moderne CPU ca. eine Instruktion pro Taktzyklus durchführen. Wenn wir eine CPU nehmen, die mit
einer Taktfrequenz von 3 GHz arbeitet, würde das bedeuten, dass wir eine theoretische Maximalleistung von 3 GFlop/s aus dieser
CPU erwarten könnten. Aus verschiedenen Gründen, die wir bereits relativ ausführlich im Kapitel 4 betrachten haben, können
wir leider diese theoretische CPU Leistung nicht als gültigen Wert für die effektive Rechenleistung eines Systems nehmen. Wir
berücksichtigen diese Tatsache und benutzen nur 60% der theoretischen Maximalleistung als effektive CPU-Leistung für die
Rechnerknoten. Die eingesetzten CPUs liefern somit eine Peak Leistung von ca. 1,8 GFlop/s.
Nach einer einfachen Rechnung 80/1.8 = 44,4 kommen wir zu dem Schluss, dass wir mindestens 44 solcher 3 GHz CPUs
benötigen würden, um die Performancevorgabe zu erreichen. Dies ist wiederum mit dem Einsatz von mindestens 22 Knoten auf
Dual Prozessor Basis verbunden. Formal ausgedrückt heißt das also m ≥ 22.
Mittels Gl (8.3) bilden wir als nächstes den Preisvektor mit beispielhaften Komponentenpreisen wie folgt:
•
•
•
•
Einzelpreis einer CPU: pCPU = 300 €
Preis eines Gigabytes Hauptspeichers: p RAM = 100 €
Netzwerkkartenpreis p NIC = 60 € 28)
Grundsystempreis pGsys = 350 €
Also
p = (300, 100, 60, 350)
Durch die Angabe der Komponenten des Preisvektors haben wir automatisch die relevanten Hardwarekomponenten benannt, die
von der Preisfunktion mitberücksichtigt werden. Da es eine direkte Beziehung zwischen dem Preis von Hardwareteilen und ihrer
entsprechenden Leistung besteht, lassen sich ebenfalls über den Preisvektor (und die damit verbundene Zielfunktion) Unterschiede
bei der zu erwartende Hardwareleistung des Systems leicht in Erwägung ziehen. Besteht z.B. der Preisvektor aus Komponenten
pi , die überall niedrige Werte aufweisen, können wir sofort daran erkennen, dass es sich um Hardwareteile handelt, die keine
überdurchschnittliche Leistung liefern können.
Unter der Komponente, die wir für unsere erste Analyse gewählt haben, vermissen wir insbesondere die Abwesenheit von 1stund 2nd Level Cache als Komponenten des Preisvektors. Die Erklärung hierfür ist jedoch leicht zu ersehen, denn es liegen keine
Preisinformationen für L1- bzw. L2 vor, die in irgendeine Form eine Trennung vom CPU Preis ermöglichen könnten. Während
unseres ersten Versuchs werden wir ebenfalls auf die Betrachtung von I/O Subsystemen verzichten.
Ein Grundsystem bezeichnet hier die Ansammlung der restlichen Hardwarekomponenten wie Hauptplatine, Gehäuse, Netzteil, etc, die nach unserem
Modell keine bedeutende Rolle bei der Performancebestimmung spielen sollten, jedoch für die Bestimmung des Endpreises unbedingt berücksichtigt werden
müssen.
28)
Die Kosten der Netzwerkinfrastruktur (Switches, Netzverkabelung, etc.) werden bei den Netzwerkkartenstückpreisen miteinbezogen.
27)
- 49 -
In unserer Beispielkonfiguration nimmt die Kostenfunktion (also die Zielfunktion) (8.6) die spezifische Form
K(p) =
300 N CPU + 100 N RAM + 60 N NIC + 350 N Gsys = min !
(8.19)
ein. Die Preisfunktion muss unter folgenden Randbedingungen (rb) minimiert werden:
•
Jede Komponente muss nach (8.9) mindestens einmal verbaut werden. 2 CPUs und mindestens 2 GB Hauptspeicher
sollten jedem Knoten zugeteilt werden. Da m ≥ 22 gilt also: rb_1. .
•
Die geforderte Gesamtperformance von 80 GFlop/s muss mindestens erreicht werden: rb_2.
′ + M RAM s ′RAM + M NIC s ′NIC = 80.
M CPU sCPU
N CPU ≥ 4 , N RAM ≥ 4 , N NIC ≥ 2 , N Gsys ≥ 2
Spätestens in diesem Augenblick werden wir ernsthaft mit dem Problem konfrontiert, auf welche Weise die Rechenleistung s i′
= g i (t L + B )i der einzelnen performancerelevanten Hardwarekomponenten zu bestimmen ist damit die Messergebnisse in die
Performanceformel sinnvoll eingebettet werden können. Genauer gesagt müssen wir Methoden definieren, mit denen sich diese
Performanceergebnisse sinnvollerweise in reinen MFlop/s bzw. GFlop/s Zahlen ausdrücken lassen.
Es ist offensichtlich so, dass die Bestimmung dieser für uns geeigneten Form der Performanceformel einen Schritt von
entscheidender Bedeutung darstellt. Wir können hier jedoch nicht dem Anspruch gerecht werden, diese komplexe Aufgabe
im Rahmen der vorliegenden Arbeit zu lösen. Dazu gehören unzählige Stunden von intensiven Performancemessungen und
Ergebnisanalysen, welche eigentlich das Thema eines separaten Forschungsprojekts werden können29).
Unsere Absicht an der Stelle ist vielmehr zu überprüfen, ob unsere ursprüngliche Idee, nämlich das Problem der Konfiguration
eines Clusters mit Hilfe eines mathematischen Modells zu lösen, praktikabel ist oder nicht. In diesem Sinne wollen wir vorerst
nur eine plausible Beziehung für die Performanceformel liefern, so wie die nötigen Randbedingungen angeben, die sich aus dem
Beispielproblem in logischer Form herleiten lassen.
Ein wichtiger Aspekt, den wir hierfür unbedingt berücksichtigen müssen, ist dass die Gesamtperformance von der Applikation
abhängig ist. Nehmen wir mal an, dass unsere Parallelapplikation die Systemressourcen folgendermaßen belastet: 60% CPU, 30%
Speicher, 10% Netzwerk. Damit sieht die Matrix G wie folgt aus
G=
0 
 0.6 0


 0 0.3 0 
 0
0 0.1

Die lineare Beziehung für die Performanceformel, also rb_2, könnte wie folgt aussehen
0.6 M CPU + 0.3M RAM + 0.1M NIC ≥ 80
(8.20)
Unter der Beziehung (8.20) verbergen sich einige vereinfachende Annahmen, zum Beispiel, dass die Speicherperformance
prozentual bzw. linear in die Performance eingeht oder dass die Gesamtperformance von der Zahl der Netzwerkkarten unabhängig
ist, solange mindestens eine Netzkarte pro Knoten verbaut wird. Weitere wichtige Randbedingungen sind:
•
•
•
•
•
•
M CPU − N Gsys ≥ 0 . Wir haben mindestens so viele Knoten wie CPUs
M CPU − 2 N Gsys ≤ 0 . Die maximale Anzahl von CPUs pro Knoten ist 2
rb_5: M NIC − N Gsys ≥ 0 . Wir haben mindestens eine Netzwerkkarten pro Knoten
rb_6: M NIC − 2 N Gsys ≤ 0 . Es dürfen nicht mehr als 2 Netzwerkkarten pro Knoten eingesetzt werden.
rb_7: M
. Es muss mindestens 1 GB Hauptspeicher pro Knoten verbaut werden.
RAM − N Gsys ≥ 0
rb_8: M RAM − 4 N Gsys ≤ 0 . Wir wollen ein Maximum von 4 GB Hauptspeicher pro Knoten zulassen30).
rb_3:
rb_4:
′ . Die
Um nur ein Gefühl zu bekommen, mit welcher Art von Problem wir es hier zu tun haben, betrachten wir kurz die Komponente s CPU
Gesamtperformance der CPUs ergibt sich aus der theoretischen Einzelperformance scpu multipliziert mit der Anzahl der CPUs (M) und diskontiert um den
Performanceverlust durch den sequentiellen Anteil α (vgl. Amdahl’sches Gesetz, Abschnitt 4.4). Nehmen wir für unser Testproblem α = 0.1% an. Es gilt
′ = S M = (1 / 0.1 + 0.9M ) M. Diese Beziehung ist bereits nicht mehr linear in
also nach Gl. (4.12): S = 1 / α – (1 – α)/ M = 1 / 0.1 + 0.9M . Damit ist s CPU
der Variable M, so dass wir sie in eine sog. Taylorreihe (Annäherung an eine Funktion durch Polynome) entwickeln müssen, um eine lineare Approximation
′ zu bekommen (Linearitätsbedingung). Das Ergebnis dieser Taylorentwicklung lautet: = M – M(M-1)α + M(M-1)² α² + M²(M-1)³ α³ +…. Wenn wir
für s CPU
nur den Linearanteil der Entwicklung nehmen, kommen wir zu dem Ergebnis = M. Man stellt also fest, dass hier die Linearisierung den Sachverhalt zu sehr
vereinfacht und es darf deshalb nicht linear gerechnet werden. Nichtlineare Optimierungsverfahren sind jedoch um einiges komplizierter als sein lineares
Pendant, so dass wir hier auf eine Behandlung des Problems in nichtlinearer Form verzichten müssen.
30)
Die tatsächlich erreichbare Hauptspeicherkapazität eines Computers ist durch das Produkt der maximalen Größe der auf dem Markt verfügbaren
Speichermodule mal der Anzahl von Speicherbänken, die die eingesetzte Hauptplatine aufweist, obwohl 8 GB Hauptspeicher zur Zeit möglich sind,
wollen wir bei der 4 GB Grenze bleiben, damit die gegebenen Motherboards für den INTEL Xeon oder AMD Athlon MP Prozessor, welche maximal 4 GB
Hauptspeicher annehmen, hier mitberücksichtigt werden können.
29)
- 50 -
8.4
Der Clusterkonfigurator
Wir hatten bereits in Abschnitt 7 angedeutet, dass aufgrund des iterativen Charakters des Simplex-Verfahrens die Nutzung eines
Computeralgorithmus zur effizienten Lösung des Konfigurationsproblems sich als eine vorteilhafte Möglichkeit erweisen kann. Die
dahinter liegende Idee besteht einfach darin, ein Computerprogramm zu erstellen, das die Formulierung des zu optimierenden
Problems als Eingabe zulässt und eine Lösung, ohne weiteren Einfluss eines externen Benutzers, nach dem Simplex-Verfahren
liefern kann.
Wir wollen hier natürlich weder eine erneute Analyse des Simplex-Verfahrens durchführen, noch die Struktur des Codes für den
Clusterkonfigurator in allen Einzelheiten beschreiben (Der Quellcode zum Programm lässt sich mit Hilfe eines Internet Browsers
anschauen, indem man z.B. das Pulldown-Menü Ansicht öffnet und die Option Quelltext anzeigen wählt). Stattdessen versuchen
wir die Struktur des Verfahrens in Form eines Kontrollflussdiagramms zusammenfassend darzustellen, so dass man sich dabei einen
schnellen Überblick über die interne logische Struktur des Clusterkonfigurators als Programm verschaffen kann (s. Abbildung 8.1
auf S. 98). Zur Erinnerung können wir noch das lineare Optimierungsproblem (7.2) in der folgenden kompakten Form schreiben:
a rs x s = br , wobei die folgende Terminologie beachtet werden muss (s. Kapitel 7):
s
xs
r
αrs br
:
:
:
:
:
Pivotspalte
Problemvariablen
Anzahl von Spalten in der Matrix
Koeffizienten der Matrix A in Gleichungssystem (s. Gl. 7.2)
Summenelemente
- 51 -
Start
Gibt
es ein s,
so dass xs das
richtige Vorzeichen hat und eine
Verbesserung
zulässt
Nein
Eine optimale Lösung wurde
gefunden. Das Ergebnis wird
ausgegeben.
HALT
Ja
Ein solches xs wird ausgewählt.
Ja
Gibt es ein r, so
dass ars>0.
Nein
Es gibt keine optimale Lösung
für das Problem.
HALT
Es wird r so gewählt um den
Quotienten br / ars zu minimieren,
mit ars>0.
Es wird ars pivotiert um ein neues
Tableau mit x zu bilden, die alte
Basisvariable wird ersetzt.
Abbildung 8.1: Kontrollflussdiagramm für den Simplex-Algorithmus
- 52 -
Sind Aufgabenstellung und Ziel des Programms vom Programmierer eindeutig verstanden worden, geht es als nächstes um die
Wahl der Computersprache, die eingesetzt wird, um die Umsetzung des Problems in eine für die Maschine verständliche Sprache
zu ermöglichen. Die Wahl der Computersprache, in die der Algorithmus letztendlich implementiert wird, hängt zum größten Teil
vom Programmierer, aber auch von der Natur des zu lösenden Problems ab.
Das Programm, welches das Konfigurationsproblem für uns lösen soll, hat einige wichtige Vorgaben zu erfüllen. Außer den
logischen Aufgaben, die das Programm zu meistern hat, wie z.B. das Empfangen und Interpretieren von Benutzereingaben, die
Durchführung der Lösungsberechnung nach dem Simplex-Verfahren, das Abfangen von fehlerhaften Eingaben, etc. wäre es
natürlich wünschenswert, wenn sich das Tool sehr einfach benutzen ließe.
Um diese Vorgaben zu erfüllen haben wir uns zuerst für die Nutzung der Programmiersprache C entschieden, denn C lässt
bekanntlich die Erstellung von höchsteffizientem Code zu und genießt außerdem im Linux Umfeld sehr große Beliebtheit. Gleich
zu Beginn der Softwareentwicklungsphase waren wir uns im Klaren, dass wir das Rad nicht neu erfinden wollten. Aufgrund des
breiten Anwendungsspektrums, bei welchem der Einsatz von linearen Optimierungsverfahren möglich wird, konnte erwartetet
werden, dass einige öffentliche, per Internet zugängliche Programme existieren, die das Simplex-Verfahren implementieren. Unsere
Aufgabe beschränkte sich somit auf die Durchführung der nötigen, an unsere Gegebenheiten angepassten Codemodifikationen
und die anschließende Erstellung einer hierfür geeigneten Benutzerschnittstelle. Diese sollte für die korrekte Eingabe der Daten
und die geeignete Darstellung der Programmergebnisse sorgen.
Während unserer Internetrecherche sind wir jedoch auf einem Tool gestoßen, das 1998 von S. Waner und S.R. Costenoble an
der Fakultät für Mathematik der Hofstra Universität, New York, entwickelt wurde. Das Simplex-Method Tool entsprach in vielen
Punkten unserer Vorstellung. Dass es in JavaScript implementiert war erwies sich schnell als ein Vorteil, denn JavaScript ist für seine
hervorragende Portierbarkeit (auf Architektur und Betriebssystemebene) bekannt.
Wie bei allen anderen Scriptsprachen besteht ein JavaScript Programm aus einer Ansammlung von direkten Anweisungen
(sog. Funktionen), die mit einander kommunizieren um ein bestimmtes Ziel zu erreichen. Die Komponenten der Sprache, sog.
grammatikale Elemente wie z.B. Ausdrücke und Operatoren, lassen sich auf einfache Weise kombinieren und auch wenn sie die
Mächtigkeit einer höhere Sprache wie C nicht erreichen können, führen sie in zahlreichen Fällen zur schnellen Erstellung völlig
funktioneller Programme31).
JavaScript ist eine Programmiersprache „für das Web“ und wurde dementsprechend an die spezifischen Bedürfnissen von Web
Entwickler angepasst. Die unterschiedlichen Sprachmodule spiegeln also die Eigenschaften vom
allgemeinen Webdesign wieder, so dass JavaScript dazu fähig ist, Webseiten dynamisch zu ändern, zu manipulieren und auf
interaktive Änderungen zu reagieren.
Ausschlaggebend für die Entscheidung, den JavaScript Code gegenüber dem C Code zu favorisieren, war also die Tatsache, dass
sich in dieser Form der Clusterkonfigurator mit Hilfe eines beliebigen Webbrowsers denkbar einfach aufrufen und von dort aus
direkt bedienen ließe. Die plattformunabhängige Nutzung des Programms wäre somit bestens gewährleistet.
Die Abbildung 8.2 auf der nächsten Seite zeigt die interaktive Schnittstelle des Clusterkonfigurators, die mit Hilfe eines
Browsers (Internet Explorer, Netscape, Opera, etc.), geladen wird. Wie man hier sieht präsentiert sich das Programm mit zwei
Hauptsektionen: Die erste Sektion gibt einige wichtige Informationen zur Bedienung des Tools. Die Bemerkungen beschreiben
etwas detaillierter, was man zum Beispiel bei der Eingabe von großen Zahlen oder Dezimalziffern beachten muss und was die
Wahl des Ausgabetyps unten „Typ“ im Arbeitsfenster bei der Darstellung der Ergebnisse bewirkt.
Es gibt unterschiedliche JavaScript Versionen, die von bestimmten Browsern unterstützt werden. Dies kann leider nicht nur zur Verwirrung, sondern auch
zu erheblichen Inkompatibilitäten führen. Einige Zeit später, nachdem Netscape die Unterstützung von JavaScript eingeführt hatte, versuchte Microsoft
ähnliches beim Internet Explorer in Form von sog. „JScript“. Die Microsoft Implementierung des JavaScripts war jedoch sehr instabil und verursachte
zahlreiche Schwierigkeiten. Ein wichtiger Schritt zur Standardisierung der Sprache ist durch die Freigabe der offiziellen Version von EMACScript language
Specification für die JavaScript Sprache gemacht worden.
31)
- 53 -
Abbildung 8.2: Die Startmaske des Clusterkonfigurators
- 54 -
Die zweite Sektion, das eigentliche Arbeitsfenster, enthält verschiedene Buttons, deren Funktion eigentlich nach einem kurzen
Blick auf die Seite leicht zu verstehen sein sollte. Wenn wir auf den „Beispiel“ Knopf darauf drücken erscheint im oberen Feld ein
Beispielproblem, das zum Aufklärung der richtigen Formateingabe des Problems in das Eingabefenster dienen soll und natürlich
durch Betätigung des „Lösung“ Knopfs gelöst werden kann. Genauso interessant sind die Zusatzinformationen, die gleichzeitig
am unteren Fenster erscheinen. Diese erklären in noch ausführlicherer Form wie ein Konfigurationsproblem eingegeben werden
muss, damit es vom Tool fehlerfrei gelöst werden kann. In der Abbildung 8.3 können wir die Ausgabemaske betrachten, die nach
der Betätigung des „Beispiel“ Knopfs angezeigt wird.
Abbildung 8.3: Ausgabemaske nach einem Klick auf den „Beispiel“ Knopf
Ganz am Ende der Seite ist noch eine Warnung angebracht, die dem Benutzer über eventuelle Risiken bei der Nutzung von
rechenintensiven JavaScript Tools informieren soll (s. Abbildung 8.2). Als letzte wichtige Anweisung zur Bedienung des Tools
müssen wir erwähnen, dass während des Eintippens der Problemdefinitionen im Eingabefeld keine leeren Zeilen entstehen dürfen,
auch nicht am Ende der Eingabe. Das Tool will sonst diese leere Zeilen als Ungleichungen auswerten und meldet sofort einen
Fehler, was für den unerfahrenen Benutzer verwirrend wirken kann.
8.5
Eine Beispielberechnung mit Hilfe des Clusterkonfigurators
Da der Clusterkonfigurator bei der Eingabe von Variablen momentan nur einzelne Buchstaben unterstützt, müssen wir das
Konfigurationsproblem aus Abschnitt 8.3 in einer noch kompakteren Form ausdrücken, so dass die Eingabe der nötigen
Beziehungen vom Programm erstmals abgearbeitet werden können. Folgende Definitionen werden hierfür verwendet:
x
y
z
w
:
:
:
:
Anzahl CPUs in Stück
Anzahl von GB (RAM)
Anzahl NICs in Stück
Anzahl Grundsysteme in Stück (Gehäuse, Hauptplatine, usw.)
Beispiel Preisvektor in €: p =
(p
cpu
, pram , pnic , p gsys )= (300, 100, 60, 350)
- 55 -
Preisformel oder Zielfunktion: Summe über Teilsummen von Anzahl mal Preis der Komponenten
xp
+ yp
+ zp
+w
p
cpu
ram
nic
Die Randbedingungen rb_1 bis rb_8 lauten nun:
•
•
•
•
•
•
•
•
rb_1:
rb­_2:
rb_3:
rb_4:
rb_5:
rb_6:
rb_7:
rb_8:
gsys
= 300 x + 100 y + 60 z + 350 w = min!
x ≥ 4 , y ≥ 4 , z ≥ 2 ,w ≥ 2
0,6 x + 0.3 y + 0.1z ≥ 80 Performanceformel
x−w≥0
x − 2w ≤ 0
z−w≥0
z − 2w ≤ 0
y−w≥0
y − 4w ≤ 0
Wir geben diese Beziehungen im Eingabefeld ein und bevor wir auf den „Lösung“ Knopf drücken, setzen wir die Anzahl von
signifikanten Ziffern bei „Rundung“ auf 2 zurück, denn ein Ergebnis in Dezimal- bzw. Bruchdarstellung würde in unserem Fall
eher weniger Sinn machen. Die Ergebnismaske für dieses Konfigurationsproblem ist auf Abbildung 8.4 unten zu sehen.
Abbildung 8.4: Ausgabemaske des Clusterkonfigurators für das Konfigurationsproblem aus Abschnitt 8.3.
- 56 -
Während auf dem Lösungsfeld nun das Ergebnis für das angegebene Problem erscheint, zeigt uns das untere Feld wie erwartet
sämtliche Tableaus, also alle Zwischenberechnungen bis zum Erhalten der Endlösung. Für das oben stehende Problem werden 11
Tableaus generiert und 10 Zwischenberechnungen durchgeführt um das Ergebnis zu bekommen. Der Lösungsvektor, der auf dem
Lösungsfeld erscheint lautet:
Optimale Lösung: p = 45000; x = 64, y = 130, z = 32, w = 32
Die Interpretation des Lösungsvektors ist denkbar einfach. Das Tool schlägt zuerst den Einsatz von 32 Knoten vor, so dass wir
insgesamt 64 CPUs für die Konfiguration benutzen müssen und eine theoretische Peakperformance von ca. 115,2 GFlop/s
erhalten. 130 GByte RAM sind unter den Knoten zu verteilen, so dass jeder der Knoten 4 GByte Hauptspeicher bekommen soll.
Im Bereich des Kommunikationsnetzwerks, muss eine Netzwerkkarte pro Knoten eingebaut werden. Der Clusterkonfigurator
berechnet einen minimalen Preis für diese optimale Konfiguration, der im vorliegenden Fall 45.000 € beträgt. Die einzelnen
Werte und die Lösung sind soweit schlüssig. Wir können trotzdem keine weiteren Rückschlüsse über die Tauglichkeit des
Clusterkonfigurators ziehen, solange wir keine weitere Situationen und mögliche Konfigurationen mit Hilfe des Tools analysieren.
In diesem Sinne wollen wir eine kurze Reihe von Gedankenexperimenten durchführen, die uns mit den nötigen Informationen
zur Evaluierung der Aussagekraft dieses Algorithmus versehen sollen. Fragen wir uns zum Beispiel, was würde passieren wenn
wir unsere Leistungsvorgabe verdoppeln, also 160 statt 80 GFlop/s erreichen müssten. Die Problemformulierung würde wie folgt
aussehen:
Minimize p = 300x + 100y + 60z + 350w subject to
0.6x + 0.3y + 0.1z >= 160
x >= 44, y >= 44, z >= 22, w >= 22
x - w >= 0
x - 2w <= 0
z - w >= 0
z - 2w <= 0
y - w >= 0
y - 4w <= 0
wobei wir hier sehr stark von der Annahme Gebrauch gemacht haben, dass aufgrund der hohen CPU Abhängigkeit unserer
Beispielapplikation die Leistung derselben nahezu linear mit dem Einsatz zusätzlicher CPUs skaliert. Die Mindestanzahl von CPUs
muss also rein theoretisch verdoppelt werden und somit auch die minimale Systemspeichergröße. Der Clusterkonfigurator liefert
für dieses Problem folgenden Lösungsvektor (Abb. 8.5):
Optimale Lösung: p = 90000; x = 130, y = 260, z = 64, w = 64
Alle Werte, bis auf die Anzahl der CPUs, haben sich wie erwartet verdoppelt, so dass die nötige interne Konsistenz der
Programmlösungen vorhanden zu sein scheint.
- 57 -
Abbildung 8.5: Ausgabemaske des Clusterkonfigurators für den Fall einer verdoppelten Leistungsvorgabe.
Obwohl der Lösungsvektor erneut einen fundierten Eindruck macht, ist uns hier der Wert für die Anzahl der CPUs ein wenig zu
hoch. Auch wenn wir bedenken, dass 2 CPUs weniger zu nehmen sind (64 Knoten auf Dualbasis benötigen 128 und nicht 130
Prozessoren). Unseren Abschätzungen nach würden wir mit der effektiven Prozessorleistung von 128 CPUs auf eine theoretische
Rechenkapazität von etwa 230 GFlop/s kommen, einen Wert, der bereits 37,5% über der Leistungsvorgabe liegt. Hier könnte man
sogar 10 Knoten weniger nehmen, so dass wir immer noch eine Leistung von 194 GFlop/s anbieten können und 8100 € einsparen
würden.
Eine Erklärung hierfür ist sicherlich auf die Tatsache zurückzuführen, dass wir durch die extrem lineare Annäherung, die zur
Analyse des Sachverhalts verfolgt haben, wichtige Informationen auf dem Weg zur Lösung verlieren und dies sich wiederum in der
Form unserer Lösungsvektoren widerspiegelt. Betrachten wir aber einige weitere exemplarische Situationen.
Der nächste wichtige Test besteht daran, Änderungen an den Komponentenpreisen einzuführen um zu beobachten, inwieweit
diese sich in dem Lösungsvektor widerspiegeln. Nehmen wir zum Beispiel an, dass sich der Preis für ein Grundsystem um 20%
280€. Das Konfigurationsproblem lautet nun:
reduziert hat, also dass p gsys ==280
Minimize p = 300x + 100y + 60z + 280w subject to
0.6x + 0.3y + 0.1z >= 80
x >= 44, y >= 44, z >= 22, w >= 22
x - w >= 0
x - 2w <= 0
z - w >= 0
z - 2w <= 0
y - w >= 0
y - 4w <= 0
Der Lösungsvektor wird vom Programm berechnet zu (Abb. 8.6)
Optimale Lösung: p = 43000; x = 64, y = 130, z = 32, w = 32
- 58 -
Abbildung 8.6: Die Berechnung für den Fall, dass der Grundsystempreis um 20% sinkt
Dieses Ergebnis entspricht in der Tat unseren Erwartungen. Dass die Werte für die Komponenten des Lösungsvektors, die mit
den performancerelevanten Hardwarekomponenten verknüpft sind, sich nicht ändern wenn keine großen Änderungen an der
Grundsystempreis-Komponente p gsys des Preisvektors auftritt, wurde erwartet. Nur der Endpreis hat sich logischerweise geändert
und ist um 2000 € gesunken.
Nun berücksichtigen wir eben den Fall, dass sich der Preis einer leistungsrelevanten Komponente sehr deutlich ändert. Sagen wir
zum Beispiel, dass der Preis pro Gigabyte Hauptspeicher, der erfahrungsgemäß sehr stark schwanken kann, zum Zeitpunkt der
Angebotserstellung um beachtliche 50% sinkt. Somit hätten wir p ram == 50
50 €. Aus der Zielfunktion
p = 300x + 50y + 60z + 350w
erhalten wir vom Clusterkonfigurator folgenden Lösungsvektor:
Optimale Lösung: p = 38000; x = 44, y = 160, z = 41, w = 41
Hier ist etwas durchaus Interessantes geschehen. Angesichts des stark verbilligten Speicherpreises gibt der Clusterkonfigurator
sogar die Dualprozessor- zu Gunsten einer Einzelprozessorarchitektur auf. Dafür wird die Anzahl der Knoten natürlich erhöht und
aufgrund der neuen CPU Anzahl eine Rechenleistung von 1.8x44 = 79.2 GFlop/s angeboten. Man kann hier vielleicht noch Protest
erheben, denn immerhin stimmt beim Lösungsvektor die Anzahl von Knoten nicht mit der von CPUs überein. Wichtiger ist jedoch
die Aussage zu erkennen, dass unter den neuen Preisbedingungen die tatsächlich wirtschaftlichere Konfiguration seitens der Einz
elprozessorarchitektur liegen könnte. Genauer betrachtet erkennen wir jedoch zwei wichtige Argumente, die dagegen sprechen
würden.
Zum einen müssten wir zusätzliche 3 Knoten nehmen, um von den vorgeschlagenen 41 auf 44 Knoten zu kommen. Nur auf diese
Weise liegen wir wirklich nah an der Performancevorgabe von 80 GFlop/s. Der Betrag für die 3 Knoten errechnet sich leicht zu
3x(300 + 50 + 60 + 350) = 2280 €. Mit 38000 + 2280 = 40280 € liegen wir natürlich 4720 € unter dem Preis, den der Kunde für
die Dualprozessorkonfiguration hätte zahlen müssen. Die Höhe dieses Betrages könnte zwar unter Umständen die Entscheidung
des Kunden zu Gunsten der Einzelprozessorkonfiguration wenden, es gibt aber auch eine schlechte Nachricht: Der Kunde
- 59 -
bekommt 68,7% weniger Leistungspotential bei einer solchen Konfiguration. Das hier ist also ein erstes deutliches Beispiel
einer Situation an welchem wir leicht erkennen können, dass unser mathematisches Modell für den Clusterkonfigurator noch
verbesserungsbedürftig ist.
Noch ein letztes Konfigurationsproblem wollen wir analysieren, bevor wir zu einer zusammenfassenden Diskussion unserer
bisherigen Ergebnisse übergehen. Eine in der Tat nicht ganz triviale Frage lautet, wie ändern sich die Verhältnisse wenn wir eine
Applikation betrachten würden, die durch andere Terme gii in der Matrix G gekennzeichnet wäre? Betrachten wir hierzu eine
Applikation, deren G Matrix wie folgt gegeben ist
0 
 0.5 0


G0= 0.2 0 
 0
0 0.3 

so dass die Performancefunktion in Korrespondenz mit unserer ersten Definition in (8.20) folgende Gestalt einnimmt:
0.5x + 0.2y + 0.3z ≥ 80. Es handelt sich hier um eine Applikation, welche die Systemressourcen im Netzwerkbereich stärker
in Anspruch nimmt (20% mehr im Vergleich zu der ursprünglichen Applikation) dafür CPU- und Hauptspeicherressourcen
insgesamt um 10% weniger. Die zu diesem Konfigurationsproblem passenden Angaben für den Clusterkonfigurator lassen sich
folgendermaßen aufschreiben:
Minimize 300x + 100y + 60z + 350w subject to
0.5x + 0.2y + 0.3z >= 80
x >= 44, y >= 44, z >= 22, w >= 22
x - w >= 0
x - 2w <= 0
z - w >= 0
z - 2w <= 0
y - w >= 0
y - 4w <= 0
Der entsprechende Lösungsvektor ergibt sich nach dem Einsatz des Clusterkonfigurators zu:
Optimale Lösung: p = 49000; x = 67, y = 130, z = 67, w = 33
Die stärkere Belastung der Netzwerkressourcen wird von dem Lösungsvektor deutlich wiedergegeben. Außer der Tatsache, dass
diese letzte Applikation eine etwas teuerere Hardwarekonfiguration erfordert, kann man noch zu der Lösung sagen, dass z.B.
unsere anfängliche Standardvorgabe, die den Einsatz einer Dualprozessorarchitektur vorzieht, weiterhin verfolgt wird. Genauso
werden, wie bisher gemacht, 4 GByte RAM pro Maschine zugeteilt (die gesamte Anzahl von CPUs und GB Speicher muss etwas
nach unten korrigiert werden, denn hier sind 32 Knoten statt 33 sinnvoll, so dass x = 64, y = 128 und z = 64). Was wir aufgrund
der neuen Gestalt der Leistungsfunktion erwartet haben und tatsächlich aufgetreten ist, ist die Erhöhung der vom Algorithmus
berechneten Anzahl von NICs in dem Lösungsvektor. Man kann dies natürlich als einen kleinen Erfolg des Modells betrachten,
denn auch wenn wir nicht über eine exakte Beziehung für die Leistungsfunktion verfügen, ist das Modell durchaus in der Lage auf
solchen Veränderungen zu reagieren.
Eine noch gründlichere Analyse der Lösung lässt uns aber zusätzliche Faktoren erkennen, die unbedingt mitberücksichtig
werden müssen. Mit dem Einsatz von 64 Netzwerkarten haben wir deutlich die magische Grenze von 48 überstiegen, die
aufgrund des Einsatzes von Netzwerkswitches zwangsläufig beachtet werden muss. Standardmäßig weist ein Netzwerkswitch
nur bis zu 32 Knoten auf, so dass wir durch die zusätzlichen 32 NICs dazu automatisch gezwungen werden, mehr Geld in das
Kommunikationsnetzwerk zu investieren32).
Wenn wir eine realistischere Preisangabe überhaupt erreichen wollen, müssen diese nachvollziehbaren Zusatzkosten, die von
der Erhöhung der Netzwerkartenanzahl verursacht wurden, zusammen mit der Preisjustierung aufgrund der nicht benötigten
Komponenten zusammen betrachtet werden. Die Komponenten, die nicht eingesetzt werden (1 Grundsystem weniger, 3
CPUs weniger, etc), ergeben zusammen einen Betrag von 2090 €, während für den extra Netzwerkswitch sich bis zu 600 €
einberechnen sind. Wir kommen somit auf eine Summe von ca. 1500 €, die vom Clusterkonfigurator Endpreis abgezogen
werden muss. Der korrigierte Preis für das System lautet im Endeffekt etwa 47000€, also doch noch rund 2000 € teurer als die
Startkonfiguration.
32)
Es gibt Netzwerkswitches mit bis zu 72 Ports auf dem Markt, diese sind aber um einiges teuerer als die Standard 24 oder 32 Port Switches.
- 60 -
Aus diesem Ergebnis könnten wir vielleicht zu dem Schluss kommen, dass netzwerkbelastende Applikationen zu
kostspieligeren Konfigurationen führen. Die Bestätigung einer solchen Aussage würde natürlich die Analyse weiterer ähnlicher
Konfigurationsprobleme erfordern. Ein letztes Beispiel und die Praxis ganz im Allgemeinen sagen uns jedoch, dass dies tatsächlich
der Realität entspricht.
Eine Frage zu der oben erhaltenen Lösung ist jedoch berechtigt, nämlich ob das Problem der Netzwerkbelastung auf
Applikationsebene ständig vom Clusterkonfigurator durch den mehr oder weniger simplen Einsatz mehrerer Netzwerkkarten
gelöst wird. Die Antwort wird wohl momentan ja lauten, weil wir einfach noch keine dedizierte Kontrollstrukturen im Programm
eingebaut haben, die z.B. dem Programm selbständige Entscheidungen zwischen existierenden Netzwerktechnologien
ermöglichen können, welche für das gegebene Konfigurationsproblem am besten geeignet sind.
Wir können jedoch wie gesagt durch das Preis-Leistung Verhältnis der Hardwarekomponenten auf indirekter Weise die
Performancewerte einer Komponente beeinflussen. Als leichtes Beispiel hierfür lässt sich für die Netzwerkkomponente p nic ein
Preis definieren, sagen wir 500 €, der fast so hoch ist wie der Geldwert eines ganzen Knoten. Diese Verhältnisse kennen wir bereits
aus dem Einsatz von hochleistungsfähigen Netzwerkkomponenten wie Myrinet, SCI oder ähnlichem. Unter diesen Umständen gilt
für die Preisfunktion
300x + 100y + 500z + 350w = min!
Mit der Performanceformel 0.5x + 0.2y + 0.3z >= 80 und den üblichen Randbedingungen erhalten wir für den Lösungsvektor in
dieser Situation
Optimale Lösung: p = 70000; x = 76, y = 150, z = 38, w = 38
Es wird also wieder eine einzige Netzwerkschnittsstelle pro Knoten eingesetzt, wobei der Endpreis für die Konfiguration, wie
erwartet, durch die Nutzung von solchen speziellen Netzwerklösungen ganz deutlich in die Höhe geht.
- 61 -
KAPITEL 9 - Schlussfolgerungen und Ausblick
Ganz nach unserer Erwartungen entfaltete sich die Lösung des Konfigurationsproblems zu einem recht komplexen Unterfangen.
Wir haben mit relativer Ausführlichkeit die Schritte überarbeitet, die zum einen die nötigen Grundlagen zum Verständnis des
Problems vermitteln und zum anderen das Erstellen eines mathematischen Modells für die Beschreibung desselben ermöglichen.
Die im Hintergrund stehende Zielsetzung, nämlich aus dieser mathematischen Darstellung und ihrer entsprechenden Lösung ein
Softwarealgorithmus zu entwickeln lag somit in greifbarer Nähe.
Im Großen und Ganzen hat sich dieses Vorgehen als adäquat erwiesen. Die Ergebnisse des Clusterkonfigurators am Ende des
letzten Kapitels spiegeln in sehr guter Näherung die Realität wieder. Dieses Tool besitzt ein großes Potential, nicht nur weil es
bereits brauchbare Resultate liefert, sondern weil sich das Konzept um den Clusterkonfigurator als sehr ausbauungswürdig erweist.
Der alles entscheidende Fortschritt wäre natürlich vor allen Dingen die Bestimmung einer viel effizienteren und realistischeren
Performancefunktion. Aber auch sehr interessante Erweiterungen lassen sich in Zukunft implementieren, welche zum Beispiel in
Verbindung mit spezifischen, weit verbreiten Kundenapplikationen stehen (LSDYNA, Gaussian, Fluid, etc.).
Wie momentan gesehen sind wir nur in der Lage, ein Konfigurationsproblem zu analysieren, das mathematisch ausgedrückt
ausschließlich in linearer Form vorliegt. Wenn wir die Wechselwirkung unter den verschiedenen performancerelevanten
Hardwarekomponenten besser verstehen würden, könnten wir eine weitaus mächtigere mathematische Darstellung des
Sachtverhalts erreichen und somit auch die Aussagekraft des Clusterkonfigurators deutlich steigern. Dies bedeutet natürlich, dass
andere mathematische Methoden zur Lösung des Problems eingesetzt werden müssen. Durch die vorliegende Arbeit wurde jedoch
deutlich bewiesen, dass unser im Kapitel 2 formuliertes Konfigurationsproblem eine mathematische und eine darauf basierte
Softwarelösung zulässt.
Wir haben mit der Gleichung (8.18) im Prinzip gezeigt, dass wir allein mit Hilfe von zweier Kennzahlen, der Latenzzeit und der
Bandbreite, das Leistungsprofil von performancerelevanten Hardwarekomponenten wiedergeben können. Dies hat eine echte
Simplifizierung der Zusammenhänge bezüglich des Konfigurationsproblems zur Folge. Wir gehen ebenfalls davon aus, dass die
aus einem nichtlinearen mathematischen Modell hergeleitete Performanceformel ziemlich anders als in (8.18) aussehen wird, die
charakteristischen Größen tL und B, aber auf jeden Fall in der endgültigen Form derselben erhalten bleiben werden. Mehr als die
Schwierigkeiten bei der Messung von tL und B geht es uns eher um eine andere Problematik: Wie lassen sich diese Messgrößen in
Form von reinen Performancezahlen (MFlop/s, GFlop/s, etc.) angeben, so dass wir hier trotzdem ein nicht lineares mathematisches
Lösungsverfahren erfolgreich einsetzen können. Wir müssen also eine sinnvolle Methode finden um diese „Übersetzung“ zu
realisieren.
Als nächstes erwarten wir, dass ein für die Lösung nichtlinearer Konfigurationsprobleme geeignetes mathematisches
Verfahren nicht nur eine komplexere Mathematik beinhaltet, sondern nicht-lineare Lösungsverfahren in der Regel auch
schwieriger zu programmieren und mit einem höheren Rechenaufwand verbunden sind. Hier können wir also eine Stelle mit
Entwicklungspotential erkennen, im Falle dass man sich für eine Fortführung in der Entwicklung des Clusterkonfigurators
entscheidet.
Die Aufgaben, die nach dem Abschluss dieses Projekts noch offen stehen sind also nicht wenige. Wir wollen sie zusammenfassend
in zwei Hauptgruppen unterteilen. Zum einen haben wir Aufgaben grundlegender Natur:
•
•
•
•
Entwicklung eines realistischeren mathematischen Modells für die Beschreibung des Konfigurationsproblems.
Herleiten einer besseren Performancefunktion aus dem neuen Modell
Festlegung eines hierzu geeigneten mathematischen Lösungsverfahrens
Implementierung der notwendigen Softwareanpassungen, die aufgrund der Verbesserungen in dem mathematischen
Modell entstehen werden.
Die zweite Gruppe enthält hingegen Verbesserungen, die eher mit der Benutzungsfreundlichkeit und der besseren Funktionalität
des Tools verbunden sind:
•
•
•
Automatische Überprüfung der Definition für die technisch bedingten Hardwareparameter. Nicht realisierbare
Clusterkonfigurationen sollten gleich bei der Eingabe abgelehnt und die Ursachen hierfür dem Benutzer deutlich bekannt
gegeben werden.
Einführung von Kontrollstrukturen im Programm, die spezifische Architekturänderungen an einer Clusterkonfiguration
durch programmeigenständige Entscheidungen zulassen.
Das Eingabefeld muss noch benutzerfreundlicher werden. Statt der bisher verwendeten algebraischen Notation sollten
wir die Dateneingabe eines Konfigurationsproblems für den Benutzer noch intuitiver gestalten. Das Programm sollte die
Benutzereingabe im Hintergrund auf die notwendige algebraische Form bringen.
Während die ersten 4 aufgelisteten Aufgaben, wie oben kurz geschildert, erhebliche Schwierigkeiten aufbereiten können, sind die
letzten 3 verhältnismäßig leicht zu bewerkstelligen. In diesem Zusammenhang dürfte klar sein, dass eine eventuelle Überarbeitung
des Tools weiterhin mit Hilfe von JavaScript implementiert wird, da JavaScript aufgrund seiner Portierbarkeit und Simplizität hierfür
- 62 -
sehr gut geeignet ist.
Wir möchten an der Stelle noch deutlich zum Ausdruck bringen, welche entscheidende Rolle der Entwurf eines Softwaretools
zur Konfigurationsoptimierung von Clustersystemen in der ständigen Verbesserung der Qualität der HPC Produkte der Firma
Dr. Koch Computertechnik AG gespielt hat. In der Tat konnten mit der Durchführung des Projekts die Kenntnisse im Umgang
mit hoch optimierten Clustern erheblich gesteigert werden. Auch die zusätzlichen Aktivitäten, die im Zusammenhang mit der
Förderung für ein Projekt dieser Art Unterstützung fanden, wie zum Beispiel der Besuch von spezialisierten Schulungen und
Messeveranstaltungen, stellten sich als eine echte Bereicherung für die Dr. Koch Computertechnik AG heraus.
Im diesem Sinne ist einer der Wünsche der Firma transtec AG nach der Übernahme von der Firma Dr. Koch Computertechnik AG,
von all diesen positiven Erfahrungen gezielt zu profitieren. Die transtec AG hat sich aus diesem Gründen dafür entschieden, die
weitere Entwicklung des Clusterkonfigurators zu unterstützen, sofern dies von der Förderung für sinnvoll gehalten wird. Es sei
jedoch wohlgemerkt, dass andere förderungswürdige Projektgebiete der transtec AG ebenfalls in Frage kämen.
Welches Projekt auch immer am Schluss Unterstützung finden sollte, stehen grundsätzlich die positiven Konsequenzen einer
solchen Projektausführung im Vordergrund, wie zum Beispiel die Verbesserungen in der Qualität der transtec Produkte und
Dienste im HPC Umfeld und die damit verbundene Steigerung der Beständigkeit und Konkurrenzfähigkeit des Unternehmens. In
einer so stark umkämpften Branche der Computerdienstleistungen, wie sich derzeit die HPC Branche darstellt, kann zweifellos die
Differenzierung, die sich durch die Forschung in speziellen technologischen Gebieten erreichen lässt, die mittel- und langfristige
Konsolidierung eines jeden Unternehmens entscheidend beeinflussen.
Anhang A: Einrichtung eines Linux-Clusters
Bisher sind Linux HPC Cluster mehr oder weniger das Hauptthema durch unsere gesamte Arbeit gewesen. Wir halten deswegen
für sinnvoll, die von uns über die gesamte Projektzeit gesammelten Erfahrungen mit Clustereinrichtungen zu dem Hauptdokument
als Anhang in zusammenfassender Form hinzuaddieren. Im folgendem werden also die Standard Arbeitschritte, von der
Hardwareauswahl über die Vermittlung der nötigen Kenntnisse zum Betriebsystem und zur Systemverwaltung bis hin zum Einsatz
von parallelen Programmbibliotheken und paralleler Software, beschrieben.
A.1
Hardware
Als ersten Schritt beim Aufbau eines Clusters wollen wir die Auswahl der dafür benötigten Hardware betrachten33). Das
Charakteristische bei Cluster ist deren Aufbau aus Einzelrechnern und das Verbinden dieser sog. Knoten über ein Netzwerk. Damit
hören die Gemeinsamkeiten unter Clustern aber auch schon auf. Sowohl bei der Auswahl der Hardware für die Knoten als auch
für das Netzwerk stehen sehr viele Möglichkeiten offen. Aus diesem Grund kann hier keine komplette Beschreibung gegeben
werden, sondern es soll stattdessen exemplarisch an der hier verwendeten Hardwarekonfiguration gezeigt werden, wie ein solches
System aussehen kann und worauf man achten sollte.
Die Abbildung A.1 zeigt das schematische Bild eines 32 Knoten großen Clusters und seiner Verbindungsstruktur.
Wir gehen davon aus, dass man vor der Hardwareanschaffung geeignete Untersuchungen durchgeführt hat um die Leistungsmerkmale der auf den
Cluster zu fahrenden Applikationen genauer zu verstehen. Auf dieser Weise lässt sich die Auswahl der Clusterhardware optimal gestalten.
33)
- 63 -
Myrinet Switch
Internet/LokaleNetzwerkinfrastruktur
Switch
100/1000 Mbit
IP:192.168.0.254
Netmask:255.255.255.0
IP:129.13.114.105
Netmask:255.255.0.0
eth0
eth1
Master Knoten
2 CPUs
2GB Hauptspeicher
VGA Karte
2 HDD (RAID s)
CD-ROM/DVD)
Floppy
Streamer/CD-Brenner
IP:10.0.0.1
Netmask:255.0.0.0
IP:192.168.0.1
Netmask:255.255.255.0
eth0
myri0
eth0
node 1
2 CPUs
2GB Hauptspeicher
HDD (Swap/Scratch)
IP:10.0.0.32
Netmask:255.0.0.0
IP:192.168.0.32
Netmask:255.255.255.0
myri0
node 2
2 CPUs
2GB Hauptspeicher
HDD (Swap/Scratch)
eth0
..............
myri0
node 32
2 CPUs
2GB Hauptspeicher
HDD (Swap/Scratch)
Externes Disk Array (~1,2 TB RAID 5)
Abbildung A1: Vernetzungsstruktur und Komponentenkonfiguration für den geplanten Linux Cluster (Masterknoten + 32
Rechenknoten)
Der Masterknoten besitzt im Gegensatz zu den Knoten zwei Netzwerkkarten, eine für die interne Kommunikation mit den anderen
Knoten und eine für die Integration des Rechners (und somit auch vom Cluster selbst) an eine vorhandene Netzwerkinfrastruktur
bzw. das Internet. Der Masterknoten weist jedoch zusätzliche Komponenten auf, die ihn von den Rechenknoten unterscheiden:
Die Betriebssysteminstallation auf dem Masterknoten ist, wie wir sehen werden, viel aufwändiger und komplexer als die von den
Rechenknoten. Von daher wird sie durch den Einsatz eines IDE-RAID Controllers und zweier gleich großer, im RAID 1 Modus
gespiegelte Festplatten, gesichert (Kapazität ~ 40 GB. Ferner wird an dem Masterknoten wegen der zentralen Verwaltung und
Lagerung der Benutzerkonten und Daten ein externes SCSI to IDE Festplattensystem angeschlossen (typisch im RAID 5 Modus,
gelegentlich auch im RAID 10 Modus konfiguriert), deren Kapazitätsgröße von der zu verwaltenden Datenmenge direkt abhängt.
Der Masterknoten verfügt ebenfalls über zusätzlichen I/O Geräte wie z.B. CD-ROM bzw. DVD und Floppy Laufwerke. Nicht ganz
untypisch sind Komponenten wie Tape-Streamer und CD- oder DVD-Brenner bei der Hardwarekonfiguration des Masterknotens,
welche als Backup Subsystem fungieren. Die Größe des Hauptspeichers ist bei allen Maschinen gleich (2 GB DDRAM). Die
Verbindung der Knoten unter sich erfolgt über einen 100 MBit/s Ethernet Switch. Für die einzelnen Knoten (einschließlich der
Masterknoten) wurden wegen des besseren Preis-Leistungs-Verhältnisses Dual Prozessor Systeme gewählt. Dies hat zur Folge,
dass die beiden Prozessoren sich die Netzwerkbandbreite teilen müssen, aber intern direkt über einen schnellen Bus miteinander
kommunizieren können.
Als besonderes Merkmal bei der vorliegenden Hardwarekonfiguration erkennen wir die Anwesenheit von Myrinet
Netzwerkkomponenten, welche aufgrund ihrer hohe Bandbreite und sehr niedriger Latenzzeiten eine optimale Umgebung für
den Einsatz paralleler Applikationen anbieten (s. §3.4.7). Wie man hier sehen kann, ist es nicht unbedingt erforderlich, den
Masterknoten mit einer Myrinet Netzwerkschnittstelle zu versehen. Schließlich will man nicht, dass der Masterknoten, der ja eher
mit zahlreichen Koordinationsaufgaben beschäftig ist, mit Ressourcenaufwändigen Berechnungen noch zusätzlich belastet wird.
Sind die Hardwarekomponenten endgültig ausgewählt, dann ist der erste Schritt zum Aufbau eines Clusters vollzogen.
A.2
Systemsoftware
Um auf die Hardwareressourcen, die im letzten Abschnitt ausgesucht und physikalisch miteinander verbunden wurden, zugreifen
zu können, benötigt man ein geeignetes Betriebsystem. Für die Prozessorarchitektur, die sich auf dem Mark durchgesetzt hat
(die sog. X86-Prozessorarchitektur), kämmen dabei eine Vielzahl von Variationen in Frage. Einige wie etwa Windows 2000 von
Microsoft, Solaris von Sun Microsystems, BeOS von Be Inc, sind kommerzielle Produkte, während anderen wie Linux und FreeBSD
sog. Open Source Betriebsysteme sind. Aus den folgenden Gründen ist für die Einrichtung des
- 64 -
Clusters die Wahl auf Linux gefallen34):
•
•
•
•
•
Linux ist freie Software, wodurch nur geringe Kosten bei der Beschaffung des Betriebsystems anfallen. Bei einem Cluster,
bestehend aus 32 Knoten, wären Beispielweise bei einem kommerziellen System 32-mal Lizenzgebühren zu entrichten.
Bei Linux hingegen ist nur der einmalige Anschaffungspreis zu bezahlen (oder sogar gar keinen, wenn man bedenkt, dass
die meisten Linux Distributionen für den Download kostenlos zur Verfügung stehen). Außerdem sind bei kommerziellen
Systemen Programmentwicklungswerkzeuge, die bei Linux meistens zum Lieferumfang dazu gehören, oftmals noch
separat zu kaufen.
Linux ist ein Multiuser/Multitasking Betriebsystem. Daher können mehrere Benutzer auf einem Rechner gleichzeitig
arbeiten, ohne sich gegenseitig zu behindern.
Linux bietet eine stabile und sichere Netzwerkumgebung. Dies ist einerseits wichtig bei der Verbindung der einzelnen
Knoten des Clusters miteinander, aber vor allem beim Zugriff auf dem Cluster von außerhalb.
Linux unterstützt Symmetric Multi Processing (SMP). In einem Rechner können dabei mehrere Prozessoren an
unterschiedlichen Aufgaben arbeiten, Linux Cluster können somit als eine Art MIMD Rechner betrieben werden (s. Kap.
3).
Unter Linux stehen diverse Standardbibliotheken zur parallelen Programmierung zur Verfügung (PVM, MPI, LAM), was die
Portierbarkeit von parallelen Applikationen enorm steigert.
Nicht verschweigen sollte man dabei auch, dass Linux einige Nachteile mit sich bringt:
•
•
•
Linux bietet keinen Support, der mit dem Produkt miterworben wird. Wird professionelle Unterstützung benötigt, so ist
diese separat zu kaufen (allerdings muss man sagen, dass dies bei kommerziellen Betriebsysteme nicht viel anders wäre).
Linux gibt keine Garantie für das Funktionieren von Betriebsystemteilen. Durch eine ständige Weiterentwicklung sind viele
Werkzeuge noch in der Entwicklungsphase und es ist möglich, dass bestimmte nicht zufrieden stellend funktionieren.
Aber selbst bei fertig gestellten Programmen übernimmt kein Entwickler eine Funktionsgarantie. Die Programme werden
zumeist von freiwilligen Programmierern in deren Freizeit erstellt. Damit ist es verständlich, dass diese keine Garantie
geben, für ein Produkt an dem sie nichts verdienen.
Linux ist immer noch ein System, das wegen fehlender graphischer Werkzeuge schwierig administrierbar zu sein scheint
(hinsichtlich dazu hat sich in letzter Zeit jedoch sehr viel getan). Einige Programme sind nicht so dokumentiert, wie man
sich das vielleicht wünschen würde. Darum ist ein gewisses Eigenengagement und Wissen nötig, um komplexere Dinge,
wie den Aufbau eines Clusters zu verwirklichen.
Bevor nun auf die Installation des Betriebsystems im Einzelnen eingegangen wird, seien noch ein paar allgemeine Dinge erwähnt.
Der Masterknoten und die Rechenknoten werden unterschiedlich eingerichtet. Dabei ist zu beachten, dass auf allen Rechenknoten
die gleiche Softwarekonfiguration eingespielt wird, um Inkompatibilitäten durch unterschiedliche Programmversionen oder
fehlende Betriebsystemkomponenten zu verhindern. Der Masterknoten benötigt neben den Client-Programmen für bestimmte
Netzwerkdienste und Protokolle zusätzlich noch die Server-Programme. Weiterhin ist die Installation von Applikationen,
Bibliotheken, Compilern und ein Batch Queuing System zu erledigen (dazu später mehr), so dass der Masterknoten mehr oder
weniger als Referenzpunkt für alle Clustertätigkeiten dienen kann. Als die einzige Maschine im Cluster, die mit der Außenwelt
kommunizieren darf, ist ebenfalls eine sinnvolle Absicherung dieses Rechners durch einige Firewallregeln zu unternehmen.
Die Konfiguration eines Linux Clusters erfordert spezifische Vorkenntnisse über das Betriebsystem, die den Rahmen der
vorliegenden Einführung sehr leicht sprengen würden. Daher werden wir uns also nur an den Stellen aufhalten, wo die
spezifischen Themen zur Clusterkonfiguration behandelt werden müssen, betriebsystemspezifische Begriffe werden hingegen
ohne all zu große Ausführlichkeit angesprochen.
A.2.1
Der Masterknoten: Betriebssysteminstallation
Im Folgenden soll die Installation der Linux Distribution auf dem Masterknoten beschrieben werden. Doch bevor wir die
Einzelheiten hierfür behandeln, müssen wir noch ein paar Worte über die Linux Distribution sprechen, die für unsere Zwecke am
besten passt. Obwohl es zahlreiche Linux Distributionen auf dem Mark gibt, haben sich in Europa vorwiegend die Distributoren
Red Hat, SuSE und Debian deutlich etabliert.
Red Hat ist die meist eingesetzte Linux Distribution weltweit, was natürlich die Kompatibilität der Installation mit einer
beiteren Palette an Softwaretools am besten garantieren kann. Für SuSE spricht die Tatsache, dass die Distribution über sehr
anwenderfreundliche Installation- und Konfigurationstools verfügt, die viele Systemadministratoren zu schätzen wissen. Debian
GNU/Linux ist eine Distribution, die sehr viel Wert auf Stabilität legt und wird wegen ihrer längeren Versionszyklen in speziellen
Die Argumente, die für den Einsatz von Linux sprechen, gelten meistens genauso für FreeBSD. Obwohl FreeBSD eine ähnliche Leistung und Stabilität
wie Linux aufweisen kann, muss man als entscheidenden Vorteil von Linux sagen, dass die Unterstützung von neuer Hardware unter Linux viel schnellere
Fortschritte macht als unter FreeBSD. Nicht zuletzt spielt ein Know-how Faktor eine Rolle, denn es ist viel einfacher, Leute mit fundierten Linux-Kenntnissen
zu finden, als das unter FreeBSD der Fall ist.
34)
- 65 -
Kreisen bevorzugt. Welche Distribution auf das Festplattensystem des Masterknoten schließlich installiert wird hat nicht zuletzt mit
den persönlichen Vorlieben und Gewohnheiten desjenigen zu tun, der sich mit der Aufgabe der Clusterkonfiguration in der Praxis
beschäftig.
Für unsere Beispielinstallation werden wir die SuSE Distribution in der Version 8.2 einsetzen. Das Vorgehen zur Installation einer
anderen Distribution wird im Einzelnen von dem hier beschriebenen abweichen, insgesamt gesehen sind die Installationsroutinen
jedoch ähnlich.
Zunächst wird von der ersten CD-ROM bzw. von der ersten DVD gebootet. Das SuSE Linux Installationsprogramm wird dann vom
Medium geladen und die Vorinstallationsphase beginnt. Der Startbildschirm zeigt mehrere Auswahlmöglichkeiten für den weiteren
Verlauf der Installation. Da wir ein komplett neues System einrichten wollen, wählen wir die Option Installation mit den PfeilTasten aus. Die Installationsroutine lädt nun ein minimales Linux System, das den weiteren Installationsvorgang kontrolliert. Zum
Abschluss des Ladevorgangs wird das Installationsprogramm YaST gestartet und nach wenigen Sekunden sehen wir die graphische
Oberfläche, die uns durch die Installation führen wird.
Die Installationsroutine beginnt mit der Auswahl der Sprache und den entsprechenden Tastaturlayouts. Eine Standardzeitzone wird
ebenfalls definiert. Nach dem der Menüpunkt Neuinstallation ausgewählt wird, startet die Installationsroutine mit der Erkennung
der vorhandenen Hardware. Einige Voreinstellungen zur Installation und Konfiguration des Systems werden ebenfalls angezeigt.
An dieser Maske kann man vieles an den Standardinstallationseinstellungen ändern bzw. justieren. Im Normalfall ist der Partitionier
ungsvorschlag von YaST sinnvoll, für einen Masterknoten sind aber wichtige Besonderheiten zu beachten.
Während die Linux Standardpartitionen auf die zwei im RAID 1 Modus konfigurierten Systemfestplatten wie üblich eingerichtet
werden, muss man beachten, dass die /home Partition, wo die ganzen Benutzerdaten in Zukunft gespeichert werden, auf das
externe Festplatten RAID gelegt wird35). Mit 40 GB Festplattenplatz für die Installation des Betriebssystem und die Applikationen
steht uns da reichlich Platz zur Verfügung. Wir Partitionieren das RAID 1 System wie folgt:
/boot
swap
/
100 MB Linux Native (ext2)
1 GB Linux Swap
Rest
Linux Native(reiserfs)
Datei A.1: Partitionierungsvorschlag für das RAID 1 auf dem Masterknoten
Durch die Zuweisung des restlichen freien Speicherplatzes auf der Festplatte zum Root Dateisystem „/“ hängen automatisch alle
Linux Verzeichnisse (/usr, /var, /bin, etc) direkt an /. Somit können sie relativ problemlos nach Bedarf wachsen.
Wir nehmen zuerst als Basis für die Softwarekonfiguration des Masterknotens den SuSE Standard Vorschlag an, dann selektieren
wir per Hand diejenige Pakete zur Installation, die für unsere Zwecke notwendig sind und nicht automatisch markiert wurden.
Dabei wird es auch wichtig sein, während dieser Selektierungsphase gleich nach Softwarepaketen Ausschau zu halten, die in
einer Clusterumgebung keine Nutzung finden um diese zu deselektieren. Auf diese Weise erhalten wir ein viel schlankeres und
effizienteres System. Hierfür klicken wir in der Maske Installationseinstellungen auf Software und dann auf Standard-System.
Darauf folgend klicken wir auf Erweiterte Auswahl.
Die Hauptgruppen, die zu der Standard Softwareauswahl gehören sind mit einem Haken markiert und man kann als erstes den
Haken bei der Gruppe Büroanwendungen entfernen, denn der Masterknoten sollte nicht unter normalen Umständen für die
Ausführung solche Aufgaben wie Textbearbeitung oder ähnliches vorgesehen sein. Damit bleiben die Selektionen Graphisches
Grundsystem, KDE Desktop Umgebung, Dokumentation zu Hilfe und Support und C/C++ Compiler und Werkzeuge bestehen. Als
nächstes gehen wir in dieser Maske auf Filter und klicken dort auf den Eintrag Paketgruppen.
Es werden zahlreiche Möglichkeiten angezeigt. Unter diesen sind für uns die Subgruppen Languages, Libraries, Sources, Clustering
und Networking hauptsächlich von Interesse (eventuell kann auch Scientific mitberücksichtig werden). Wir listen jetzt die
Softwarepakete auf, die für unsere Zwecke installiert werden müssen:
Da die Partitionen in einem laufenden System nur mit relativ großem Aufwand geändert werden können, sollte man bei der Partitionierung und der
darauffolgenden Definition der Dateisysteme eines Masterknotens immer die Vorteile der Einrichtung eines Logical Volume Manager (LVM) nutzen. Ein so
angelegtes Dateisystem lässt sich nicht nur im laufenden Betrieb vergrößern oder verlagern, sondern erlaubt auch die konsistente Durchführung von Backups
während des laufenden Betriebs. Anleitung und wichtige Informationen des „Logical Volume Manager“ befinden sich an erste Stelle im offiziellen LVM
Howto. Die Einrichtung eines LVMs unter SuSE wird ausführlich im SuSE Administrationshandbuch beschrieben.
35)
- 66 -
•
•
•
•
•
•
Languages: cpp, gcc, gcc-c++, gcc-f77, perl.
Libraries: mpich, eventuell auch pvm
Sources: kernel-source
Clustering: eventuell OpenPBS36), xpvm, xmpi
Networking: dhcp-server, dhcp-tools, xinetd oder inetd, nfs-utils oder nfs-server, rsh-server, rsync, tftp, xntp, ypbind und
yptools.
Scientific: blas,lapack.
Nachdem wir mit der Auswahl der Software zufrieden sind und die letzten Installationseinstellungen zur Sprache und Zeitzone
sowie für den Bootmanager überprüft haben,
kann man mit einem Klick auf Weiter den Vorschlag mit all den eben durchgeführten Änderungen annehmen. Wir bekommen
einen grünen Bestätigungsdialog zu sehen und klicken auf ja, um mit der eigentliche Installation zu beginnen. Je nach
Rechnerleistung und Softwareauswahl dauert das Kopieren der Pakete meist zwischen 15 und 30 Minute.
Sind das System und die ausgewählte Software fertig installiert sind, müssen wir noch ein Passwort für den Systemadministrator
(Benutzer Root) festlegen. Anschließend bekommen wir die Gelegenheit, während der Installation einen Internet-Zugang und
eine Netzwerkverbindung zu konfigurieren. Auf diese Weise ist es möglich, im Rahmen der Installation Softwareupdates für SuSE
Linux einzuspielen und ggf. Namensdienste für die zentrale Verwaltung der Benutzer in einer vorhandenen Netzwerk Infrastruktur
einzurichten. In unseren Beispiel nehmen wir jedoch an, dass keine Namensdienstbasierte Benutzerauthentifizierung im lokalen
Netz vorhanden ist, so dass wir dieses auf dem Masterknoten einrichten müssen (s. A.2.1.3 weiter unten).
Zum Abschluss der Installation präsentiert YaST noch einen Dialog, in dem wir die Möglichkeit haben, die Graphikkarte sowie
verschiedene am System angeschlossene Komponenten einzurichten. Wir stellen die Graphikkarte auf die von uns gewünschten
Werte ein und klicken schließlich auf Installation abschließen.
Nach einem letzten Reboot ist SuSE Linux installiert und wir können uns an das System
anmelden. Der Masterknoten steht nun zum Arbeiten zur Verfügung. Was noch fehlt, um den Rechner für seine administrativen
Aufgaben vorzubereiten, ist die Einrichtung der Netzwerkdienste und der Programmbibliotheken zur Ausführung paralleler
Applikationen. Das dazu notwendige Vorgehen wird nachfolgend beschrieben.
A.2.1.1 Namensauflösung
Ein weit verbreiteter Gebrauch im Umgang mit Computersystemen, die über Netzwerke miteinander kommunizieren, ist die
Umsetzung von IP-Adressen (z.B. 127.0.0.1) in eingängigen, gut zu behaltenden Namen und umgekehrt.
Für Rechner, die mit dem Internet verbunden sind, wird diese Umsetzung normalerweise durch einen DNS-Server vorgenommen37).
Von Rechnern, die nur mit dem internen Netzwerk des Linux Clusters verbunden sind, ist aber das Internet nicht direkt erreichbar.
Außerdem wurden für die einzelnen Knoten IP-Adressen aus einem privaten Bereich verwendet, die nicht in DNS-Tabellen
eingetragen werden. Deswegen muss auf die Möglichkeit zurückgegriffen werden, solche Namenseintragungen auf jedem
einzelnen Knoten in der Datei /etc/hosts vorzunehmen. Die folgende Beispieldatei zeigt das Vorgehen hierfür:
#/etc/hosts
#
127.0.0.1localhost
192.168.0.254
192.168.0.1
192.168.0.2
192.168.0.3
....
192.168.0.32
master.cluster.de
node1.cluster.de
node2.cluster.de
node3.cluster.de
....
node32.cluster.de
master
node1
node2
node3
node32
Datei A.2: /etc/hosts: Namensauflösung für den Cluster
In die erste Spalte schreibt man die IP-Adresse, in die zweite den so genannten Full-Qualified-Hostname, das sind der Rechnername
plus der Domainname, und in die dritte Spalte trägt man den Rechnernamen ein. Zum Einloggen auf Knoten 1 kann es nun
wesentlich kürzer ssh node1 anstelle von ssh 192.168.0.1 verwendet werden.
Wir nennen Open PBS hier, weil dieses Batch Queuing System sehr weit verbreitet ist. Wir werden jedoch bei der Wahl der RessourcenVerwaltungssoftware auf das Grid Engine System von Sun setzen (mehr dazu später).
37)
Das Domain Name System (DNS) ist eine verteilte Datenbank, die Informationen über Rechner im Inter-/Intranet enthält. Die gespeicherten Daten
enthalten im allgemeinen Rechnernamen, IP-Adressen und Mail-Routing-Informationen.
36)
- 67 -
A.2.1.2 PXE fähiges DHCP
Das so genannte Dynamic Host Configuration Protocol dient dazu, Einstellungen in einem Netzwerk zentral von einem Server
aus zu vergeben, statt diese dezentral an einzelnen Arbeitsstationen oder wie bei uns hier, an jedem einzelnen Rechenknoten
vorzunehmen. Ein mit DHCP konfigurierter Client verfügt selbst nicht über statische Adressen, sondern konfiguriert sich nach den
Vorgaben des DHCP-Servers. Um den Masterknoten als DHCP-Server einzuschalten müssen wir unter SuSE Linux folgenden Befehl
eingeben:
# insserv /etc/init.d/dhcpd /etc/init.d/rc5.d
Letztes bewirkt, dass der DHCP-Server beim jeden Start des Betriebssystems im Run Level 5 (dem graphischen Modus) automatisch
zur Verfügung steht38). Unsere Netzwerkkonfiguration (s. Abb. A.1) setzt voraus, dass das interne Netz mit der zweiten
Netzwerkkarte auf dem Masterknoten bedient wird (Device eth1). Damit diese Netzwerkschnittstelle auch die DHCP Anfragen
bekommt bzw. bearbeiten kann, müssen wir in der Datei /etc/sysconfig/dhcpd, die Variable dhcp_interface gleich „eth1“ setzen.
Anschließend muss die zentrale Konfigurationsdatei /etc/dhcpd.conf eingestellt werden und zwar so, dass der DHCP-Server
die sog. PXE Erweiterungen benutzen kann39). Nur so ist der Server in der Lage, das Boot Loader Programm an den Knoten zu
übertragen. Die Datei A.3 auf der darauf folgenden Seite zeigt eine Beispieldatei dhcpd.conf, die genau das macht.
Aus den in der Datei enthaltenen Einstellungen lässt sich entnehmen, dass wir eine statische IP Konfiguration für die Rechenknoten
benutzen wollen, denn jeden Knoten bekommt immer die gleiche IP Adresse vom DHCP Server zugewiesen. Diese VorgehensWeise ist für die Cluster Konfiguration erforderlich, damit die verschiedenen Automatisierungsscripte sowie bestimmten
Applikationen korrekt funktionieren.
# DHCP Service configuration, version 3.0 ISC
ddns-update-style none;
option domain-name „cluster.de“;
option domain-name-servers 192.168.0.254;
use-host-decl-names on;
default-lease-time 86400;
max-lease-time 86400;
# Specific options for the PXE protocol
option
option
option
option
option
option
option
option
space PXE;
PXE.mtftp-ip
code
PXE.mtftp-cport
code
PXE.mtftp-sport
code
PXE.mtftp-tmount
code
PXE.mtftp-delay
code
PXE.discovery-control
code
PXE.discovery-mcast-addr code
1
2
3
4
5
6
7
=
=
=
=
=
=
=
ip-address;
unsigned integer
unsigned integer
unsigned integer
unsigned integer
unsigned integer
ip-address;
16;
16;
8;
8;
8;
subnet 192.168.0.0 netmask 255.255.255.0 {
class „pxeclients“ {
match if substring (option vendor-class-identifier, 0, 9)=“PXE Client“;
option vendor-class-identifier „PXEClient“;
vendor-option-space PXE;
option PXE.mtftp-ip 0.0.0.0;
filename „pxelinux.0“;
next-server 192.168.0.254;
}
host node01 {
hardware ethernet 00:04:76:1b:35:4f;
fixed-address 192.168.0.1;
}
Bootet man lieber in den Textmodus (Run Level 3 unter SuSE) würde der Befehl nur leicht vom oberen abweichen: # insserv /etc/init.d/dhcpd /etc/init.d/
rc3.d
39)
PXE ist ein offener, industrieller Standard, der von zahlreichen Software- und Hardwareherstellern entwickelt wurde. Von der Firma Intel ins Leben gerufen,
wurde PXE sehr schnell von anderen Unternehmen wie 3Com, HP, Dell, Compaq etc, weiter unterstützt. PXE arbeitet zusammen mit einer Netzwerkkarte
(NIC) im PC und lässt diese als Boot Device agieren.
38)
- 68 -
}
host node02 {
hardware ethernet 00:04:76:eb:f1:e3;
fixed-address 192.168.0.2;
}
host node03 {
hardware ethernet 00:04:76:22:17:43;
fixed-address 192.168.0.3;
}
M
host node32 {
hardware ethernet 00:01:02:a8:2b:1d;
fixed-address 192.168.0.32;
}
}
Datei A.3: /etc/dhcpd.conf auf master.
A.2.1.3 TFTP Server
Wie wir in Kurze sehen werden, ist pxelinux das Ladeprogramm, welches wir für das Hochfahren der Rechenknoten über das
Netzwerk benötigen (s. §A.2.2.4). Pxelinux erfordert seinerseits die Anwesenheit eines TFTP Servers41) im Netz (in der Regel wird
das DHCP-Server System diese Rolle ebenfalls übernehmen), der die sog. TSIZE (transfer size) Option verstehen kann. Diese Option
ist im Grunde genommen ein Mechanismus, mit dem pxelinux in der Lage versetzt wird, die Größe einer Datei zu Bestimmen bevor
sie übertragen wird.
tftp-hpa, eine modifizierte Version des Standard BSD TFTP Servers, funktioniert hierfür ausgezeichnet (der Suffix „-hpa“ steht
für H. Peter Anvin, Autor dieser tftp Version und von dem oben genannten pxelinux Programm). Ein wichtiger Punkt bei der
Konfiguration des TFTP Servers ist, dass der TFTP Dämon „in.tftpd“ immer von einem so genannten Meta-Dämon, wie inetd oder
xinetd, gesteuert wird. Man muss sich also vergewissern, dass der aktive Meta-Dämon die richtige Konfiguration für TFTP enthält.
Die relevanten Dateien hierzu sind /etc/inetd.conf für inetd oder /etc/xinetd.d/tftp für xinetd42). Will man inetd verwenden, muss
man einfach das „#“ Zeichen aus der Zeile:
tftp
dgram
udp
wait
root
/usr/sbin/in.tftpd in.tftpd –s /tftpboot
in der Datei /etc/inetd.conf entfernen. Beim xinetd editieren wir die Datei
/etc/xinetd.d/tftp so, dass die Variable disable auf „no“ gesetzt wird. Der Parameter –s informiert den Dämon in.tftpd über die
Position der Dateien, die die TFTP Clients herunterladen können. In unserem Fall ist dies das Verzeichnis /tftpboot.
Schließlich müssen wir einen automatischen Start des Meta-Dämons beim Booten veranlassen. Der Befehl würde im allgemeinen Fall so aussehen:
# insserv /etc/init.d/<meta-dämon> /etc/init.d/rc5.d
wobei <meta-dämon> für inetd oder xinetd steht.
A.2.1.4 NIS (Network Information Service)
NIS ermöglicht es, alle Benutzer des Clusters zentral auf dem Masterknoten einzurichten und dann diese Benutzerinformationen
über den ganzen Cluster zu verteilen43).
TFTP steht für Trivial File Transfer Protocol und ist eine vereinfachte Form des wohl bekanntesten FTP Protokoll. TFTP benutzt den UDP (User Datagram
Protocol) als Übertragungsfundament und, anders als FTP, arbeitet es ohne Sicherheitsvorkehrungen. Er wird ausschließlich für die Übertragung von
Startdateien verwendet, die das Booten von X-Terminals, Routers, Disklessclients, etc. ermöglichen und auf hohe Sicherheit nicht angewiesen sind.
42)
Der Meta-Dämon inetd ist standardmäßig durch xinetd in praktisch jeder modernen Linux Distribution abgelöst worden. SuSE Linux bietet inetd jedoch
noch als Option zu xinetd für diejenigen, die mit der alten inetd Konfiguration besser vertraut sind.
43)
Der heute mit NIS bezeichnete Network Information Service hieß zuerst yellow pages. Da dieser Name aber durch die Firma Britisch Telecom geschützt
war, wurde das Programm in NIS umbenannt. Dennoch heißen die Pakete, die die Software für NIS zur Verfügung stellen, bei den meisten Linux
Distributionen nach wie vor ypclient und ypserv.
41)
- 69 -
Der Administrator spart damit Arbeit, sich auf allen Knoten einzuloggen und alle Benutzer auf jedem einzelnen einzurichten. Der
Masterknoten soll ebenfalls die Aufgabe des Servers übernehmen und alle anderen Knoten inklusive der Masterknotens selbst
sollen ihre Informationen als Clients von diesem bekommen.
Auf der Knotenseite ist nicht viel zu tun, um auf den NIS Server zugreifen zu können. Im Wesentlichen muss nur das RPM Paket
ypclient eingespielt werden und in der Datei /etc/yp.conf die IP-Adresse (Achtung: Generischer Name funktioniert nicht!) des
Servers bekannt gegeben werden:
# /etc/yp.conf
#
ypserver 192.168.0.254
Datei A.3: Die Datei /etc/yp.conf
Welche Informationen über NIS bezogen werden und welche lokal verfügbar sind, wird in der Datei /etc/nsswitch.conf (Name
Service Switch) festgelegt. Diese Datei ist im Paket ypclient enthalten und kann für die hier benötigten Standardaufgaben
unverändert verwendet werden. Wir müssen ferner /etc/init.d/ypclient zu den Startscripten auf allen Knoten hinzufügen (auch auf
den Masterknoten), so dass ypbind ebenfalls gleich nach dem Start gestartet wird und eine Verbindung zum NIS Server auf dem
Master herstellt:
# insserv /etc/init.d/ypclient /etc/init.d/rc3.d
Möchte ein Benutzer in einer NIS Umgebung sein Passwort ändern, so kann er nicht den Befehl passwd verwenden, sondern muss
stattdessen mit dem Befehl yppasswd die Passwortänderung dem Masterknoten bekannt geben, damit dieser sie dann über das
ganze Netzwerk verteilen kann. Damit ein Benutzer nicht versehentlich sein Passwort nur lokal ändert, sollte der Administrator
dafür sorgen, dass passwd nicht verfügbar ist, indem er passwd umbenennt oder löscht.
Auf der Server-Seite, also auf dem Masterknoten, muss das RPM-Paket ypserv installiert werden. Danach müssen die
Informationen, die über NIS verteilt werden sollen, zuerst einmal in so genannten Maps abgelegt werden. Diese Maps kann man
einfach durch das Ausführen des Befehl make im Verzeichnis /var/yp erzeugen lassen.
Sind nun die Informationen in den entsprechenden Maps gespeichert, so muss noch bestimmt werden, welche Informationen
überhaupt über NIS verteilt werden. In der Datei /etc/ypserv.conf auf dem Masterknoten können Optionen und
Zugriffsberechtigungen für den NIS Server festgelegt werden. Optionen werden in der Form: option: [yes|no] angegeben.
Zugriffsberechtigungen haben die Syntax:
host:map:security:mangle[:field]
In der Beispielkonfigurationsdatei weiter unten bedeutet beispielsweise die Option dns: no, dass der Server, wenn Anfragen von
Clients kommen, die nicht in der Hosts-Map verzeichnet sind, keine Anfrage an einen DNS Server stellt. Dies ist für den LinuxCluster sinnvoll, da alle Knoten IP Adressen aus einem privaten Bereich haben und somit nicht im DNS Server eingetragen werden.
Bei der ersten Zugriffsberechtigung steht im Feld host ein Stern als Wildcard für alle Rechner, die auf den Server zugreifen. Die
Map, für die Berechtigungen festgelegt werden sollen, ist shadow.byname. Die Angabe port im security Feld erlaubt nur Anfragen
von Ports mit Nummern niedriger als 1024. Dies sind so genannte privilegierte Portnummern, die den Benutzern nicht zur
Verfügung stehen, sondern exklusiv für das System reserviert sind. Die Angabe yes im mangle Feld besagt, das bei Anfragen, die
nicht von privilegierten Ports kommen, ein x als Ergebnis zurückgeliefert wird.
# /etc/ypserv.conf
#
dns: no
*
*
*
: shadow.byname
: passwd.adjunct.byname
: *
: port
: port
: port
: yes
: yes
: yes
Datei A.4: /etc/ypserv.conf
Auch der Start des NIS Serverdienstes erfolgt wie schon der der Knoten Dienste während des Bootvorgangs durch Startup Scripte.
Hierfür geben wir ein:
# insserv /etc/init.d/ypserv
# insserv /etc/init.d/yppasswdd
- 70 -
Das Script /etc/init.d/ypserv startet den NIS-Server ypserv und das Script /etc/init.d/yppasswd startet das Programm rpc.yppasswdd,
das dem Benutzer das Ändern seines Passwortes erlaubt.
A.2.1.5 NFS (Network File System)
Im letzten Abschnitt ist beschrieben worden, wie es möglich ist, die Benutzer des Parallelrechners zentral zu verwalten. Hier soll
es nun darum gehen, wie man diesen Benutzern, die sich auf jedem Knoten des Parallelrechners einloggen können, überall die
gleiche Arbeitsumgebung zur Verfügung stellt, und wie man ihnen den Zugriff auf die Dateien aus ihrem Home-Verzeichnis
ermöglichen kann. Dabei soll nicht auf allen Festplatten der einzelnen Knoten für den Benutzer ein Home Verzeichnis vorhanden
sein, sondern die Arbeitsverzeichnisse sollen von einem zentralen Rechner bezogen werden. Damit verhindert man unnötiges
Hin- und Herkopieren zwischen den einzelnen Knoten und erreicht gleichzeitig, dass der Benutzer immer mit der aktuellen Datei
arbeitet.
Das Network File System (NFS), das 1984 von der Firma Sun Microsystems entwickelt wurde, ist der geeignete Weg zur
Realisierung dieser Wünsche. NFS ist ein Server-Client System, bei dem der Server die Anfragen (in diesem Fall Lese-Schreibzugriffe
auf eine Festplatte) der Clients bedient.
Üblicherweise wird man den NFS Server auf dem Masterknoten aufsetzen und in unserer Beispielkonfiguration hatten wir ein
externes RAID (SCSI to IDE) System für die zentrale Datenspeicherung vorgesehen (s. Abb. A.1). Man installiert dazu das Paket
nfs-utils oder das Paket nfs-server. Die Entscheidung zwischen den Paketen nfs-utils und nfs-server fällz fast immer zu Gunsten
von nfs-utils, denn dieser Server ist direkt im Linux Kernel eingebettet und weist dadurch höhere Performance auf. Es gibt aber
Situationen, bei denen der Einsatz von den sog. User Space NFS Servern dem Vorzug gegeben wird (Paket nfs-server). Dies ist
vor allem dann der Fall, wenn man z.B. ein NFS Dateisystem aus dem lokalen Netz zum master exportieren muss und dieses vom
Masterknoten den Rechenknoten ebenfalls per NFS zur Verfügung gestellt werden soll (sog. NFS reexport). Diese Reexport Option
wird vom Paket nfs-utils nicht unterstützt.
Auf einem NFS Server müssen die folgenden Netzwerkserver gestartet werden:
•
•
•
RPC Portmapper (portmap)
RPC Mount Dämon (rpc.mount)
RPC NFS Dämon (rpc.nfsd)
Diese Programme werden beim Hochfahren des Systems von den Scripten /etc/init.d/portmap und /etc/init.d/nfsserver gestartet.
Wie bei den anderen bisher betrachteten Netzwerkdiensten, müssen auch diese Dienste beim Hochfahren des Masterknotens
automatisch gestartet werden. Hierzu verwendet man unter SuSE Linux:
# insserv /etc/init.d/portmap
# insserv /etc/init.d/nfsserver
Neben dem Start dieser Dämonen muss noch festgelegt werden, welche Dateisysteme an welche Rechner exportiert werden
sollen. Dies geschieht in der Datei /etc/exports:
# /etc/exports
#
/usr
192.168.0.254/24(ro,no_root_squash)
/home 192.168.0.254/24(rw,sync,no_wdelay,no_root_squash)
/opt
192.168.0.254/24(rw,sync,no_wdelay,no_root_squash)
Datei A.5: Die Datei /etc/exports wird von mountd und nfs gelesen.
Je Verzeichnis, welches exportiert werden soll, wird eine Zeile benötigt, in der festgehalten ist, welche Rechner wie darauf
zugreifen dürfen. Alle Unterverzeichnisse eines exportierten Verzeichnisses werden automatisch ebenfalls exportiert. Die
berechtigten Rechner werden üblicherweise mit ihren Namen (inklusive Domainname) angegeben, es ist aber auch möglich, mit
den Jokerzeichnen `*´ und `?´ zu arbeiten, die die aus bash bekannte Funktion haben, oder durch Angabe einer bestimmten IP
Adresse bzw. eines Adressenbereichs. Werden keine Angaben gemacht, so hat jeder Rechner mit Netzverbindung zu master die
Erlaubnis, auf dieses Verzeichnis (mit den angegebenen Rechten) zuzugreifen.
Die Rechte, mit denen das Verzeichnis exportiert wird, werden in einer von Klammern umgebenen Liste nach dem Rechnernamen
angegeben. Die Berechtigung rw steht zum Beispiel für Lese- und Schreibberechtigung. root_squash bewirkt, dass die dem
Benutzer `root´ auf dem Clientrechner zustehenden Sonderrechte auch für das importierte Verzeichnis gewährt werden, obwohl er
auf einem anderen Rechner seine `home´ Verzeichnis hat. In der vorhergehenden Beispielkonfigurationsdatei werden z.B. allen
- 71 -
Rechner in der Subnetzmaske 192.168.0.0 die Verzeichnisse /home und /opt zum Lesen und Schreiben zur Verfügung gestellt.
Das Verzeichnis /usr wird hingegen nur zum Lesen bereitgestellt, der Benutzer `root´ behält aber in jedem Fall seine Sonderrechte.
Weitere wichtige Optionen für die NFS Zugriffsrechte lassen sich aus dem NFS Howto entnehmen.
Auf der Knotenseite können beim Start des Rechners alle über NFS zu beziehenden Verzeichnisse automatisch gemountet werden,
indem man zuerst den Prozess nfs in den geeigneten Runlevel einträgt, z.B:
# insserv /etc/init.d/nfs /etc/init.d/rc3.d
(wir werden später genauer betrachten, wie man auf den Knoten die nötigen Dienste einträgt). Um mount mitzuteilen, welche
Verzeichnisse aus dem Masterknoten über NFS zu beziehen sind, dient die Datei /etc/fstab:
# /etcfstab
#
/dev/ram0 /
ext2
defaults 11
/dev/hda1 swap
swap
pri=42 00
/dev/hda2
/scratch reiserfs defaults
00
master:/usr /usr nfs ro,timeo=7,acregmin=10,acregmax=120 0 0
master:/opt /opt nfs rw,timeo=7,acregmin=10,acregmax=120 0 0
master:/home /home
nfs rw
devpts
/dev/pts devpts mode=0620,gid=5 0 0
proc
/proc
proc
defaults 00
00
Datei A.6: /etc/fstab: Definition der Optionen für den mount Befehl.
Hier werden die NFS Verzeichnisse aus master genauso wie lokale Verzeichnisse eingetragen. Anstelle des Device (z.B. /dev/hda1)
schreibt man nun den Namen des NFS Servers und den dortigen Verzeichnisnamen. Als Dateisystemtyp verwendet man nfs. Der
Mountpoint wird, wie bei lokalen Verzeichnissen, in die zweite Spalte eingetragen und auch die anderen mount Parameter (z.B. ro,
rw, etc.) haben die gleiche Bedeutung wie bei lokalen Verzeichnisse.
A.2.1.6 rsh/ssh
Nachdem nun die Benutzer auf allen Knoten des Clusters einen Account besitzen und
nach dem Einloggen dort auch ihr Homeverzeichnis vorfinden, müssen wir noch das Einloggen von einem Knoten des Clusters
auf einen anderen Knoten ohne Passwortabfrage ermöglichen. Dies ist insbesondere dann sinnvoll, wenn von master aus auf
jedem Knoten ein Programm gestartet werden soll. In diesem Fall wäre nämlich ansonsten für jeden einzelnen Knoten jeweils eine
Passwortabfrage nötig.
Sowohl das Programm rsh als auch das Programm ssh ermöglichen ein solches Einloggen ohne Passwortanfrage, weshalb auch
beide hier kurz besprochen werden sollen. Bei rsh (Remote Shell) kann jeder Benutzer in seinem Homeverzeichnis eine Datei ~/
.rhosts anlegen, in die die Namen aller Rechner eingetragen werden, von denen aus ein Einloggen ohne Passwortabfrage erfolgen
darf. Wenn man also eine Datei mit dem folgenden oder ähnlichen Inhalt erzeugt, so wird diese in das Bootimage für den Knoten
angelegt (dazu natürlich später mehr) und ein passwortfreies Einloggen auf allen Rechnern ist verwirklicht.
# ~/.rhosts
master
node01
node02
node32
Datei A.7: Die Datei ~/.rshosts: Remotezugriff ohne Passwort.
Um dem einzelnen Benutzer die Arbeit, sich eine Datei .rhosts zu erzeugen, abzunehmen, legt der Administrator entweder eine
globale Datei /etc/hosts.equiv an, die dann für alle Benutzer gilt und nur von root verändert werden kann, oder er legt eine Datei
/etc/skel/.rhosts an, die beim Einrichten eines neuen Benutzers automatisch in dessen Homeverzeichnis kopiert wird und von ihm
dort unverändert benutzt oder modifiziert werden kann. Als letzte Hürde für das passwortfreie Einloggen steht die Datei /etc/
securetty, welche mit den Einträgen für rlogin und rexec versehen werden muss.
Das Starten des Programms rsh wird allerdings ähnlich wie TFTP von einem Meta Dämon gesteuert. Falls wir hierzu inetd benutzen,
müssen wir das Zeichen `#´ aus den folgenden Zeilen entfernen:
- 72 -
shell stream
shell stream
login stream
login stream
exec stream
tcp
tcp
tcp
tcp
tcp
nowait
nowait
nowait
nowait
nowait
root /usr/sbin/tcpd
root /usr/sbin/tcpd
root /usr/sbin/tcpd
root /usr/sbin/tcpd
root /usr/sbin/tcpd
in.rshd -L
in.rshd –aL
in.rlogind
in.rlogind -a
in.rexecd
Falls xinetd hingegen der aktive Meta Dämon ist, dann müssen wir nur die Dateien rexec, rlogin und rsh im Verzeichnis /etc/
xinetd.d editieren, und zwar jedes Mal die Variable disable einfach auf „no“ setzen. Da wir bereits einen Meta Dämon beim
Hochfahren von master automatisch starten (s. TFTP Server §A.2.1.3), brauchen wir uns an der Stelle nicht weiter über das
automatische Starten der rsh Server zu kümmern.
Für das Programm ssh (Secure Shell) ist das Vorgehen, um sich passwortfrei einloggen zu können ein wenig anders. Zuerst erzeugt
sich jeder Benutzer mit dem Befehl ssh-keygen einen so genannten privaten- und einen öffentlichen Schlüssel. Nach Ausführen
des Programms findet man dann in Verzeichnis ~/.ssh den öffentlichen Schlüssel identit.pub und den privaten Schlüssel identity
vor. Alle Rechner, auf denen der öffentlichen Schüssel in der Datei authorized_keys eingetragen ist, erlauben nun ein einloggen
ohne Abfrage des Passwortes. Kopiert man also die Datei identity.pub in die Datei authorized_keys um und kopiert man diese
automatisch an der geeigneten Stelle beim Hochfahren des Knoten, so kann man passwortfrei zwischen den einzelnen Knoten
wechseln.
Beim ersten Einloggen auf den Knoten von master aus, sind diese Rechner für das Programm ssh unbekannt. Deswegen wird die
Meldung erscheinen:
Host key not found from the list of known hosts.
Are you sure you want to continue connecting (yes/no)?
Die Frage ist mit yes zu beantworten. Bei weiteren Einloggvorgängen sind die Knoten dann in der Datei know_hosts eingetragen
und es findet keine weitere Abfrage mehr statt. Der ssh Server ist per Default in der SuSE Distribution automatisch beim Start aktiv
und daher sind während der Masterknoten-Konfiguration keine sonderlichen Einstellungen hierzu erforderlich.
A.2.1.7 Zeitausgleich durch einen XNTP Server
Der NTP Server (Network Time Protocol) wird eingesetzt, wenn eine Zeitsynchronisierung zwischen einer oder mehreren Maschinen
und einer Referenzzeitquelle stattfinden soll. Das ist insbesondere auf Clustersystemen sinnvoll, denn viele Applikationen, die
unterschiedliche Prozesse auf mehreren Knoten starten, überprüfen die Zeitstempel einiger Dateien um die Entstehung von
korrupten Daten zu verhindern.
Nach der Installation des Pakets xntp legt SuSE die Konfigurationsdatei xntpd.conf wie üblich im Verzeichnis /etc an. Für
den Masterknoten kann die relevante Sektion dieser Datei wie auf die darauf folgende Seite aussehen. Man sieht aus der
unterstehenden Datei, dass master über das Internet mit mehreren Zeitservern eine Verbindung aufbauen kann, welche
ihrerseits Atomuhren als Zeitquelle verwenden. Dadurch ist man in der Lage, eine Genauigkeit beim Zeitabgleich im Bereich von
Millisekunden zu erreichen. Wir veranlassen einen automatischen Start des Zeitservers auf master durch den Befehl:
- 73 -
# insserv /etc/init.d/xntpd
# /etc/ntp.conf
#
# Sample NTP configuration file.
# See package ‚xntp-doc‘ for documentation, Mini-HOWTO and FAQ.
##
## Outside source of synchronized time
##
## server xx.xx.xx.xx
# IP address of server
# time server eingeben hus 08 05 2003
#
server ntp.rz.uni-ulm.de.
version 3
server ntp.physik.uni-ulm.de.
version 3
server ntp.mathematik.uni-ulm.de. version 3
##
Datei A.8: Ausschnitt aus der Datei /etc/xntpd.conf für master
Auf der Seite der Rechenknoten soll das Programm xntpd ebenfalls automatisch beim Hochfahren aktiviert werden, allerdings
benutzen diese Maschinen den Masterknoten als Zeitserver. Der relevante Abschnitt bei der Datei /etc/xntpd.conf entspricht dem
in der Datei A.9 dargestellten.
# /etc/ntp.conf
#
##
## Outside source of synchronized time
##
## server xx.xx.xx.xx
# IP address of server
# time server eingeben hus 08 05 2003
server 192.168.0.254
Datei A.9: Ausschnitt aus der Datei /etc/xntpd.conf für die Rechenknoten
A.2.1.8 Batch Queuing System
Die potentiell hohe Leistung eines Clusters kann nur mit größter Effektivität ausgenutzt werden, wenn die anfallende
Arbeit intelligent auf alle Ressourcen verteilt ist. Die Aufgabe von der so genannter Batch Queuing System oder auch
Jobverwaltungssysteme (JVS) besteht eben daran, eine möglichst hohe Systemauslastung aufrecht zu erhalten. JVS erfüllen
weiterhin andere wichtige Aufgaben: Sie werden eingesetzt, wenn mehrere Benutzer um dieselben Betriebsmittel konkurrieren
und dabei Anwendungen einsetzen, die sich in Art und Umfang ihres Ressourcenverbrauchs stark unterscheiden können. Dabei
handelt es sich sowohl um Batch Anwendungen als auch um interaktive Applikationen. Da die Kapazitäten begrenzt sind, können
in der Regel nicht alle Benutzer zur gleichen Zeit bedient werden.
Das zentrale Konzept von JVS ist daher die Queue, in der Aufträge (Jobs) gesammelt werden, die dann bei passender Gelegenheit
zur Ausführung kommen. Die Schwierigkeit besteht darin, zu entscheiden, nach welchen Kriterien die Aufträge abzuarbeiten sind.
Außer das Erreichen einer optimalen Lastverteilung, spielen hier andere Faktoren eine Rolle, zum Beispiel, eine möglichst große
Fairness, eine möglichst kurze Abarbeitung der Jobs (so bald sie erst zur Ausführung kommen) oder eine intelligente Ausnutzung
von begrenzten Mittel wie CPU Zeit oder Speicher. Diese Ziele stehen teilweise in Widerspruch zu einander. Man muss also
Prioritäten setzen, die das Systemverhalten in die eine oder andere Richtung lenkt.
Um ein Beowulf Cluster mit der Funktionalität eines JVS zu versehen, gibt es sowohl kommerzielle als auch frei verfügbare, auf
Open Source Software basierende Lösungen, die die oben geschilderten Anförderungen erfüllen können. Das bekannteste Beispiel
davon ist das Open Portable Batch System, häufig Open PBS genannt, das bis von Kurzen das JVM im Clusterumfeld schlechthin
darstellte. Wir werden unserer Aufmerksamkeit hier jedoch einer vergleichsweise neu JVM-Software schenken, die innerhalb der
Open Source Gemeinde unter den Namen Sun Grid Engine bekannt ist und nach unsere Meinung auf den guten Weg ist Open
PBS als Standard abzulösen.
- 74 -
Durch die Übernahme der Firma Gridware und des Produkts Codine im Jahre 2000 hatte sich die Firma Sun Microsystems für
einen schnellen Einstieg in die Welt des Cluster-Computings entschieden. Codine ist dabei eine kommerzielle Weiterentwicklung
des freien DQS (Distributed Queuing System), das am Supercomputer Computations Research Institute der Florida State University
entwickelt wurde. Sun nannte Codine in Grid Engine um, unterwarf es einiger Simplifizierungen, fügte noch einige sinnvolle
Features hinzu und gab den Sourcecode im Juli 2001 frei.
Die Architektur von Grid Engine ähnelt der des PBS: Es gibt einen eigenen Master- und Scheduler-Prozess, und ein Exec-Dämon
ist für die Ausführung der Jobs und das Ressourcen-Management verantwortlich. Für die Kommunikation zwischen den Prozessen
sorgt ein spezieller Kommando-Dämon. Von Vorteil ist, dass zu dem Master-Prozess „sge_qmaster“ zusätzlich Shadow-Server
definiert werden können, die bei einem Ausfall des Master-Dämons die Arbeit übernehmen.
Für die Konfiguration bietet Grid Engine ein komfortables und vollständiges grafisches Interface an. Mit dem Kommando „qmon“
können jedoch alle Funktionen der Oberfläche genauso effektiv bedient werden. Jede vorgenommene Änderung, sei es per GUI
oder per Kommandoseile, wirkt sich sofort auf das System aus; Dämonen müssen nicht neu gestartet werden.
Beim Queuing-System verfolgt Grid Engine ein grundsätzlich anderes Konzept als die meisten JVM-Systeme (Open PBS, PBS Pro,
LFS, etc). Hier gibt es keine Netzwerkqueues, Queues sind stattdessen immer einem Host zugeordnet. Daher wird jeder Job nach
dem Abschicken zunächst in eine globale Holding Area gestellt, von wo aus der Scheduler den Job erst dann in eine Queue stellt,
wenn ein geeigneter Platz frei wird.
Die SuSE Linux Distribution liefert die Sun Grid Engine (SGE) Software in rpm Format schon von werk aus. Die Installation
und Konfiguration sind also denkbar einfach. Installiert man ein frisches System, dann wählt man das Paket grindengine-5.3125.i586.rpm zur Installation. Auf ein bereits installiertes System kann man, nach dem mounten des CD-Rom Laufwerks mit
folgendem Befehl die Installation von Grid Engine nachholen:
# rpm –ivh /media/cdrom/grindengine-5.3-125.i586.rpm
SuSE Linux installiert SGE per Default im Verzeichnis /opt. Um den SGE Master zu konfigurieren, wechseln wir in dem Verzeichnis
/opt/gridengine. Es gibt einzig und allein zwei Stellen wo wir selber tätig werden müssen bevor wir mit der Konfiguration
eines SGE Masters unter SuSE 8.2 starten wollen. SuSE legt während der Installation von der SGE Software eine Datei namens
„configuration“ in das Verzeichnis /opt/gridengine/default/common. Diese enthält Pfade für die Lokalisierung wichtiger SGE
Komponenten, die nicht mit den Defaultwerte der Installationsroutine von Sun kompatible sind. Dieses Problem, dass zum
Abbruch der Installation führt, lässt sich am einfachsten vermeiden in dem man mit der Installation erst anfängt, wenn man
die Datei configuration gelöscht hat. Der zweite Schritt zur reibungslosen Installation der SGE Software muss nicht unbedingt
durchgeführt werden, kann uns aber schon bei Installationen ab 16 Knoten viel Zeit sparen. Hierzu wird die Erstellung eine Datei
empfohlen, die sämtliche Namen alle Knoten enthält. Bei unserer Beispielkonfiguration heißen die Knoten einfach node1 bis
node32. Mit dem Bash Befehl
# for i in `seq 1 32`; do echo node$i >> nodelist; done
erstellen wir eine Textdatei namens nodelist, die eine Liste der Clusterknoten enthält. Diese Namen müssen allerdings in der Datei
/etc/hosts, wie im Abschnitt A.2.1.1 (Namensauflösung) angetragen sein.
Dann wechseln wir ins Verzeichnis /opt/gridengine und rufen wir von dort einfach das Script install_qmaster auf:
/opt/gridengine #./install_qmaster
Welcome to the Grid Engine installation
--------------------------------------Grid Engine qmaster host installation
------------------------------------Before you continue with the installation please read these hints:
- Your terminal window should have a size of at least
80x24 characters
- The INTR character is often bound to the key Ctrl-C.
The term >Ctrl-C< is used during the installation if you
have the possibility to abort the installation
- 75 -
The qmaster installation procedure will take approximately 5-10 minutes.
Hit <RETURN> to continue >>
Ab diesem Punkt kann man ohne bedenken die Defaultwerte der Installationsroutine annehmen. Diese reichen für die ersten
Erfahrungen mit SGE vollkommen aus. Auf die Frage:
Adding Grid Engine hosts
-----------------------Please now add the list of hosts, where you will later install your execution
daemons. These hosts will be also added as valid submit hosts.
Please enter a blank separated list of your execution hosts. You may
press <RETURN> if the line is getting too long. Once you are finished
simply press <RETURN> without entering a name.
You also may prepare a file with the hostnames of the machines where you plan
to install Grid Engine. This may be convenient if you are installing Grid
Engine on many hosts.
Do you want to use a file which contains the list of hosts (y/n) [n] >> y
beantworten wir mit y und geben wir den Pfad zu der oben erstellten Datei /root/nodelist an. Somit wird die automatische
Einrichtung der Hostqueues gestartet:
Adding admin and submit hosts from file
--------------------------------------Please enter the file name which contains the host list: /root/nodelist
node1.cluster.de added to administrative host list
node1.cluster.de added to submit host list
node2.cluster.de added to administrative host list
node2.cluster.de added to submit host list
node3.cluster.de added to administrative host list
node3.cluster.de added to submit host list
node32.cluster.de added to administrative host list
node32.cluster.de added to submit host list
Finished adding hosts. Hit <RETURN> to continue >>
Auf dem SGE Master ist damit die Arbeit getan. Auf der Knoten Seite erfolgt die SGE Konfiguration noch unproblematischer. Das
Verzeichnis /opt auf dem Master wird dem Knoten per NFS zur Verfügung gestellt, so dass wir nach dem Einloggen einfach ins
Verzeichnis /opt/gridengine wechseln und das Kommando:
node1#./install_exec
ausführen. Wir werden folgenden Dialog zu sehen bekommen:
Welcome to the Grid Engine execution host installation
If you haven’t installed the Grid Engine qmaster host yet, you must execute this step (with >install_qmaster<) prior the execution
host installation. For a sucessfull installation you need a running Grid Engine qmaster. It is also neccesary that this host is an
administrative host. You can verify your current list of administrative hosts with the command:
# qconf -sh
You can add an administrative host with the command:
# qconf -ah <hostname>
The execution host installation will take approximately 5 minutes
Hit <RETURN> to continue >>
- 76 -
Nach der einen Konfiguration für den Rechenknoten auf dem Server angelegt wird, wird der notwendigen Prozess auf dem
Knoten „sge_qexecd“ gestartet und die Konfigurationsroutine abgeschlossen:
Grid Engine execution daemon startup
Starting execution daemon. Please wait ... done
Ist der sge_execd Programm auf jedem Rechenknoten gestartet, kann man nun anfangen Jobs an das JVM-System zur
Bearbeitung zu schicken. Im Verzeichnis /opt/gridengine/examples findet man sehr nützliche Beispiele, die für die Erstellung eigener
Jobscripte von großer Hilfe sein können.
A.2.1.9 Automatisierung durch Skripte
Viele Aufgaben, die auf einem Cluster zu erledigen sind, betreffen nicht nur einen einzelnen Knoten, sondern müssen auf eine
bestimmte Anzahl von Knoten bzw. auf allen Knoten durchgeführt werden. Um ein manuelles Einloggen auf jedem Rechner des
Clusters und dann die manuelle Durchführung der Aufgabe auf dem entsprechenden Rechner zu vermeiden, kann man Skripte zur
Automatisierung verwenden.
Sinnvolle Skripte wären beispielsweise ein Skript namens cps, das alle laufenden Prozesse auf allen Knoten des Clusters ausgibt,
ckill, das alle Prozesse eines bestimmten Namens auf dem ganzen Cluster beendet, creboot oder chalt, die den Cluster neu starten
oder herunterfahren. Beispielhaft soll hier das Skript chalt vorgestellt werden:
#!/bin/bash
##################################
# Halt all nodes of the cluster #
##################################
BASENAME=“node“
LASTNODE=0
NUM=32
NAME=$BASENAME$NUM
ERROR=“ok“
until [ $BASENAME$LASTNODE = $NAME ]
do
echo $NAME
if ping -c 1 -i 1 $NAME >/dev/null 2>&1 ; then
ssh $NAME /sbin/halt -n
else
echo $NAME „ not responding“
ERROR=“not_responding“
fi
NUM=$[$NUM - 1]
NAME=$BASENAME$NUM
done
if [ $ERROR = „not_responding“ ] ; then
echo „Halt not successfull!!!“
else
echo „Halt successfull“
/sbin/halt -n
fi
Datei A.10: Skript chalt zum Herunterfahren allen Rechenknoten eines Clusters
Dieses Skript ist auf master zu starten und sollte deswegen auch nur dort installiert sein. Außerdem sollte nur root die
Berechtigung dazu haben, dieses Skript auszuführen.
Wenn auf master das Skript gestartet wird, so wird beginnend bei node32 bis zu node1 durch die until-Schleife immer wieder die
gleiche Aufgabe erledigt. Zuerst wird mittels des Kommandos ping geprüft, ob der Rechner erreichbar ist. Falls ja, wird ihm mittels
des Kommandos halt mitgeteilt, er solle sich herunterfahren. Ist er nicht erreichbar, so wird eine Fehlermeldung ausgegeben
- 77 -
und ein Flag gesetzt. Waren nun alle Rechner erreichbar, so kann sich der Masterknoten nach Beendigung der Schleife selbst
herunterfahren. War aber mindestens einer der Rechner nicht erreichbar, so wird eine Fehlermeldung ausgegeben und master
nicht heruntergefahren, um root die Möglichkeit zu geben, manuelle Maßnahmen zu ergreifen, um den nicht antwortenden
Rechner herunterzufahren.
Auf ganz ähnliche Weise kann man auch die oben vorgeschlagenen Skripte ckill, creboot usw. verwirklichen, indem man einfach
das Kommando halt gegen ein entsprechendes Kommando austauscht. Noch besser wäre es natürlich ein einziges Skripttool zur
Hand haben, das alle wichtigen administrativen Aufgaben im Cluster durch die Eingabe von Steuerparameter erledigen könnte.
Die Entwicklung eines solchen Tools erfordert jedoch etwas mehr Erfahrung in der Bash-Programmierung. Einheitliche Tools wie
die eben beschriebene gehören in aller Regel zu dem Lieferumfang beim kommerziellen Clusteranbieter.
A.2.1.10Sicherheitsaspekte
Das passwortfreie Wechseln zwischen den einzelnen Knoten bedingt eine gewisse zusätzliche Gefahr für Clusterkonfigurationen,
die Statusinformationen, oder sogar das ganze Betriebsystem lokal auf der Festplatte gespeichert haben. Gelingt es einem Hacker,
auf dem Masterknoten einzudringen, so hat er auch Zugang zu allen anderen Knoten des Clusters. Richtet er auf den einzelnen
Knoten Schäden an, die eine Neuinstallation notwendig machen, so ist nicht ein Rechner, sondern es sind alle Rechner des Clusters
neu zu installieren, was einen enormen Arbeitsaufwand bedeutet. Deswegen kommt dem Schutz von dem Masterknoten, als
Zugangsrechner für den Cluster, eine besondere Bedeutung zu. Obwohl diese Gefahr beim Clusterkonfigurationen, die RAM-Disk
Images verwenden, nicht so extrem ist, die Schaden, die durch einen Hackereinbruch im System entstehen können, sollten auf
keinen Fall unterschätzt werden.
Jeder Benutzer sollte sich aus diesem Grund von außen auf dem Cluster nur per ssh einloggen, welches die Authentifizierungsund Sessions-Daten in verschlüsselter Form überträgt. Das Programm rsh sollte auf keinen Fall zum externen Einloggen verwendet
werden, da es alle Daten in unverschlüsselter Form ans Netz gibt und ein Hacker, der an diesem Netz lauscht, so die Passwörter im
Klartext mitlesen kann. Bei Einloggvorgängen innerhalb des Clusters ist eine Verschlüsselung, wenn man den eigenen Benutzern
vertraut, nicht notwendig, da jemand der das interne Netz abhören will, Zugang zu mindestens einem Knoten des Clusters haben
muss.
Um niemanden in die Versuchung zu führen, sich unverschlüsselt bei dem Masterknoten anzumelden, sollte der Administrator
Zugänge über rsh generell, auch im internen Netzwerk, verbieten. Dazu ist der rsh-Dienst in der Datei /etc/inetd.conf
auszukommentieren. Das Programm ssh bietet als weiteren Vorteil gegenüber rsh automatisches X11-Forwarding, d. h. die
Ausgabe von X11-basierten Programmen wird automatisch an den richtigen Bildschirm weitergeleitet.
Auch das Programm ftp überträgt übrigens die Passwörter im Klartext und sollte daher vermieden werden. Als Ersatz hierfür kann
das Programm scp (secure copy) zum Einsatz kommen, das im gleichen Paket wie das Programm ssh enthalten ist.
- 78 -