Parallele Programmierung

Werbung
Parallele Programmierung
Prof. Dr. R. Loogen
10. Januar 2008
Inhaltsverzeichnis
Inhaltsverzeichnis
i
1 Einführung
1.1 Programmieren von parallelen Rechnern . . . . . . . . . . . . . .
1.1.1 Erwartungen . . . . . . . . . . . . . . . . . . . . . . . .
1.1.2 Probleme: „grand challenges“ „scientific computing“ . . .
1.1.3 Algorithmen Kernidee: „Divide et impera!“ . . . . . . . .
1.1.4 Bewertungskriterium für parallele Systeme / Algorithmen
1.1.5 Parallelrechner . . . . . . . . . . . . . . . . . . . . . . .
1.1.6 Gegenüberstellung und Zusammenfassung . . . . . . . .
1.2 Parallele Programmiermodelle . . . . . . . . . . . . . . . . . . .
1.2.1 Parallelität vs. Nebenläufigkeit . . . . . . . . . . . . . . .
1.2.2 Prozesse vs. Threads . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
1
1
1
1
3
4
5
5
6
6
2 Entwurf paralleler Programme
2.1 PCAM-Methode nach Foster (1995) . . . . . . . . . . . . . .
2.1.1 Partitionierung (P) . . . . . . . . . . . . . . . . . . .
2.1.2 Kommunikation (C) . . . . . . . . . . . . . . . . . .
2.1.3 Parallele Matrixmultiplikation nach Gentlement (1978)
2.1.4 Agglomeration (A) . . . . . . . . . . . . . . . . . . .
2.1.5 Mapping (M) . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
8
8
9
10
11
12
16
.
.
.
.
.
.
.
.
.
.
17
17
17
18
20
21
22
22
23
23
31
3 Grundkonzepte paralleler Programme
3.1 Synchronisation von Speicherzugriffen . . . . . . . . .
3.1.1 Synchronisationskonstrukte . . . . . . . . . .
3.1.2 Synchronisationsformen . . . . . . . . . . . .
3.1.3 Barrierensynchronisation . . . . . . . . . . . .
3.2 Monitore . . . . . . . . . . . . . . . . . . . . . . . .
3.2.1 Monitordeklaration . . . . . . . . . . . . . . .
3.2.2 Signalisierungsmethoden . . . . . . . . . . . .
3.3 Synchronisation und Kommunikation über Nachrichten
3.3.1 Kommunikationsmodelle . . . . . . . . . . . .
3.4 Verteilte Programmierung in MPD . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
i
INHALTSVERZEICHNIS
INHALTSVERZEICHNIS
4 Die Bibliothek MPI
4.1 Grundkonzepte . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2 Kommunikation . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3 Kommunikatoren, Prozessgruppen und Topologieinformationen
4.3.1 Prozessgruppen: Konstruktion, Analyse, Manipulation .
4.3.2 Kommunikatoren . . . . . . . . . . . . . . . . . . . . .
4.3.3 Virtuelle Topologien . . . . . . . . . . . . . . . . . . .
4.3.4 Zugriffsroutinen . . . . . . . . . . . . . . . . . . . . .
4.3.5 Interkommunikatoren . . . . . . . . . . . . . . . . . . .
4.4 Abgeleitete Datentypen . . . . . . . . . . . . . . . . . . . . . .
4.4.1 Spezifikation neuer Datentypen . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
35
35
37
41
43
44
45
46
47
47
48
5 Parallele Algorithmen
5.1 Das PRAM- Rechnermodell . . . . . . . . . . . . . . . . . . . . . .
5.2 Rechnermodelle mit verteiltem Speicher . . . . . . . . . . . . . . . .
5.3 Paralleles Sortieren . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.3.1 Ein CRCW-Verfahren mit konstantem Zeitaufwand . . . . . .
5.3.2 Sortiernetze . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.3.3 Der Algorithmus von Cole . . . . . . . . . . . . . . . . . . .
5.4 Graphen Algorithmen . . . . . . . . . . . . . . . . . . . . . . . . . .
5.4.1 Bestimmung der Zusammenhangskomponenten eines Graphen
5.4.1.1 Algorithmus von Hirschberg (1976) . . . . . . . .
5.4.2 Kürzeste Wege . . . . . . . . . . . . . . . . . . . . . . . . .
5.4.3 Minimal spannende Bäume . . . . . . . . . . . . . . . . . . .
5.4.3.1 Algorithmus von Prim . . . . . . . . . . . . . . . .
5.4.3.2 Algorithmus von Sollin (1977) . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
49
49
54
56
56
57
62
67
67
69
72
73
73
75
6 Algorithmische Skelette
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
78
Literaturverzeichnis
I
Abbildungsverzeichnis
II
ii
1 Einführung
1.1 Programmieren von parallelen Rechnern
Problem
®¶
Paralleler Algorithmus
KS
kX
XXXXX
XXXXX
XXXXX
XX
ParallelesKS Programm o
ffff große Wechselwirkung
f
f
f
f
f
fffff
sfffff
®¶
®¶
Parallelrechner
1.1.1 Erwartungen
• mehr Rechenleistung
• besseres Preis-/ Leistungsverhältnis
• bessere Verfügbarkeit durch Redundanzen
• besser verständliche Programme durch mehr Information über die Problemstruktur
1.1.2 Probleme: „grand challenges“ „scientific computing“
• Probleme aus Naturwissenschaft und Technik, meist Simulationen technischer und natürlicher Vorgänge.
• verteilte Datenbanksysteme
• Telekommunikationsbereiche
1.1.3 Algorithmen Kernidee: „Divide et impera!“
Divide
et
/
Zerlegung in
unabhängige Teile
impera
\
paralleles lösen
der Teile
1
KAPITEL 1. EINFÜHRUNG
1.1. PROGRAMMIEREN VON PARALLELEN RECHNERN
Beispiele:
Datenparallelität:
Vektoraddition „Feingranulare Parallelität“
(a1 ,
...
, an )
+ (b1 ,
...
, bn )
(a1 + b1 , . . . ,an + bn )
| {z }
| {z }
unabhängige Teile
Kontrollparallelität:
Summation von n Zahlen
n−1
X
ai , n = 2k
i=0
sequentiell: n − 1 Additionen
parallel:
„rekursives Doppeln“
a0 @
@Â
a1
s
ysss
+ II
II
$
a ...a
aK2
+
a
3
n−2
n−1
PPP
KKK
n
PP( {www
% vnnnn
...
+
o+
uu
ooo
u
zu
wooo
+
%
+
v
n/2 Additionen
n/4 Additionen
1 Addition
k
X
n
= . . . = n − 1 Additionen in k = log n parallelen Schritten bei n Ar2i
i=1
beitseinheiten.
Sortieren von n Zahlen: ā =< a1 , . . . , an >, n ≥ 1 paarweise verschiedene ai
Ranksort:
Definition: rangā (i) = |{aj |aj < ai }|
Rang des i-ten Elementes von ā
−→ Position in der sortierten Folge.
Verfahren: Für jedes Element (Datenparallelität):
• Bestimme den Rang durch Vergleiche mit allen übrigen Elementen
• Ordne Element in sortierter Folge an entsprechender Position ein
sequentieller Aufwand: n2
paralleler Aufwand: n Schritte (bei n Verarbeitungseinheiten)
Beispiel: für ein nicht parallelisierbares Problem
k
Berechnung einer großen Potenz von x ∈ R : x2 mit k ≫ 1 sequentielles Vorgehen: sukzessi-
2
KAPITEL 1. EINFÜHRUNG
1.1. PROGRAMMIEREN VON PARALLELEN RECHNERN
ves Quadrieren
= x2
= x4
= x8
..
.
(1)
(2)
(3)
..
.
x∗x
x2 ∗ x2
x4 ∗ x4
(k)
xk ∗ xk = xk
2
1.1.4 Bewertungskriterium für parallele Systeme / Algorithmen
Parameter:
• Problemgröße n ∈ N
• Anzahl der Prozessoren p ≥ 1
1. Zeitkomplexität: Tp (n) , Tp (n, A)
# Zeitschritte zur Durchführung von Algorithmus A mit Eingabedaten der Größe n auf p Prozessoren
(Laufzeit auf p Prozessoren)
Seq. Zeit: T1 (n) sequentieller Algoithmus.
2. Beschleunigung: (speedup) : Sp = TTp1
Maß für Zeitgewinn durch Parallelverarbeitung
i. Allg. gilt : 1 ≤ Sp ≤ p
• Slowdown (Sp ≤ 1)
möglich wegen Zusatzaufwand für Parallelität
• Superlinearen Speedup(Sp > p)
Cache-Effekte,
Suchverfahren / brach-and-bound Verfahren
S
3. Effizienz: Ep = pp
Maß für Prozessorauslastung bei identischer Anzahl von Berechnungsschritten im parallelen und sequentiellen Fall.
4. Skalierbarkeit: Abhängigkeit eines Verfahrens von der Rechnerkonfiguration
5. Kommunikationskomplexität: Datentransferaufwand
Beispiel:
• rekursives Doppeln:
T1 (n) = n − 1
Tp (n) = log2 n mit p ≥
³
´
Ep ∈ O log1 n
n
2
¾
=⇒ Sp =
n−1
log n
∈O
³
n
log n
´
• Ranksort:
¾
T1 (n) = n2 (sequentieller Ranksort)
=⇒ Sn = n „relativer Speedup“
Tn (n) = n
3
KAPITEL 1. EINFÜHRUNG
1.1. PROGRAMMIEREN VON PARALLELEN RECHNERN
relativer Speedup: Vergleich – selben Algorithmus auf 1 und p Prozessoren
absoluter Speedup: Vergleich – (optimalen) sequentiellen Algorithmus mit parallelen Algorithmus auf p
Prozessoren
T1opt (n) = n log n =⇒ Snopt = log2 n
Amdahls Gesetz1 Sp ≤
1
f
Jeder Algorithmus hat eine sequentielle Komponente die den parallelen Speedup bremst.
Berechnung mit n Schritten und p Prozessoren
Sei f , 0 ≤ f ≤ 1, der Anteil an Schritten, die sequentiell ausgeführt werden müssen.
=⇒
f · n sequentielle Schritte
(1 − f ) · n parallel ausführbare Schritte
T1 = n
(1 − f ) · n
p
1
T1
1
≤
=
(1−f
)
Tp
f
f+ p
Tp = f · n +
Sp =
1.1.5 Parallelrechner
MIMD: Multiple Instruction Multiple Data
• speichergekoppelte Systeme
– gemeinsamer Adressraum (logische Sicht)
– Kommunikation und Synchronisation über gemeinsame Variablen
• nachrichtengekoppelte Systeme
– prozessorlokale Adressräume
– Kommunikation und Synchronisation durch Austausch von Nachrichten
1
4
Gene Amdahl
KAPITEL 1. EINFÜHRUNG
1.2. PARALLELE PROGRAMMIERMODELLE
Speicher
Adressräume
gemeinsam
global
SMP:
symmetrischer Multiprozessor
physikalisch verteilt
DSM:
distributed shared memory
UMA:
uniform memory access
NUMA:
Non UMA
Multicomputer, distributed memory
verteilt
1.1.6 Gegenüberstellung und Zusammenfassung
SMP
gemeinsam
global
Kriterien
Adressraum
Speicher
Komm. / Synch.
gemeinsame Variablen
Skalierbarkeit
Lastverteilung
begrenzt
leicht
mangelnde Skalierbarkeit und
Konflikte beim Speicherzugriff
Probleme
DSM
gemeinsam
verteilt
gemeinsame Variablen
mit internen Nachrichten
leicht
„leicht“
Cache-Kohärenz
DM
verteilt
verteilt
Nachrichten
leicht
schwierig
globale Synchronisation
1.2 Parallele Programmiermodelle
gemeinsamer Adressraum2 (MPD, PRAM)
Nachrichtenkopplung
• Prozess-Kanal-Modell (Ian Foster)
• Prozess-Nachrichten-Modell (MPI3 , PVM4 )
SPMD5
• statisches Prozesssystem
• Nachrichtenkopplung
2
shared memory, logische Sicht
Message Parssing Interface
4
Parallel Virtual Machine
5
Single Program Multiple Data
3
5
KAPITEL 1. EINFÜHRUNG
1.2. PARALLELE PROGRAMMIERMODELLE
• Modellierung von Datenparallelität
Datenparallelität (HPF6 , NESL7 )
• Bereitstellung von datenparallelen Grundoperationen
– hoher Abstraktionsgrad
1.2.1 Parallelität vs. Nebenläufigkeit
Nebenläufigkeit(concurrency, multithreading)
• reaktive Systeme
System Umgebung
←−−−−−−−→
Parallelität
• transformationelle Systeme
Input System Output
−−−−→
−−−−−→
1.2.2 Prozesse vs. Threads
Definition von Prozess:
• „sequenzielle“ Folge von Aktivitäten durch die eine in sich geschlossene Aufgabe bearbeitet wird
oder
• funktionelle Einheit aus
– Zeitlich invarianten Programm
– Satz von Daten
– Zeitlich variantem Zustand
Jeder Prozess besitzt Umgebung und Kontext
Umgebung: geschützter Adressbereich eines Prozesses, d. h.
• Codebereiche und Datenbereiche im Speicher
• geöffnete Dateien
• Ressourcenverweise
Kontext: „Registerwerte“, d. h.
• Befehlszähler
• Zeiger auf Laufzeitkeller
• Aktivierungsblock
6
7
6
High Performance Fortran
A Nested Data-Parallel Language
KAPITEL 1. EINFÜHRUNG
1.2. PARALLELE PROGRAMMIERMODELLE
• usw.
Prozesse:
• eigene Umgebung und Kontext
Threads:
• eigener Kontext
• teilen sich Umgebung mit anderen Threads
7
2 Entwurf paralleler Programme
2.1 PCAM-Methode nach Foster (1995)
PCAM: Partitioning Communication Agglomeration Mapping
P-Partitionierung
problemabhängige Zerlegung der Berechnung und der Daten in Teile (tasks)
ohne Berücksichtigung der Zielarchitektur
−→ maximale inhärente Parallelität Skalierbarkeit beachten
C-Communication
Analyse der Datenabhängigkeit
Festlegung der Kommunikationsanforderungen
A-Agglomeration
Zusammenfassung stark zusammenhängender Teile zu größeren Tasks.
Ziel: Effizienzsteigerung durch Kostenminimierung
M-Mapping (Abbildung)
8
KAPITEL 2. ENTWURF PARALLELER PROGRAMME
2.1. PCAM-METHODE NACH FOSTER (1995)
Abbildung der resultierenden Struktur auf konkrete Zielarchitektur
Ziel: Maximierung der Prozessorauslastung
−→ statisch oder mit dynamischer Lastverteilung
2.1.1 Partitionierung (P)
Ziele:
• möglichst feinkörnige Zerlegung der Berechnung / Datenbasis
• Vermeidung der Duplizierung von Daten und Berechnungen
• maximal vorhandene Parallelität
Methoden:
• Bereichszerlegung (domain decomposition)
• funktionale Zerlegung (functinal decomposition)
Beispiel: Matrix-Multiplikation
A = (aij )1≤i,j≤n B = (bij )1≤i,j≤n
C = (cij )1≤i,j≤n mit cij =
n
X
aik bkj
k=1
mögliche Bereichszerlegungen:
a) −→ Eingabematrizen 2n2 Tasks
b) −→ Ausgabematrix
n2 Tasks
¾
Datenparallelität
funktionale Zerlegung:
c) −→ n2 · n
n2 (n − 1)
Multiplikationen
Additionen
¾
Kontrollparallelität
Checkliste:
• # Tasks ≫ # Prozessoren?
– Flexibilität
• keine redundanten Berechnungen, keine redundanten Speicheranforderungen?
– Skalierbarkeit
• vergleichbare Größe der Tasks?
– Lastausgleich
• alternative Partitionierung?
– Flexibilität
• # Tasks skaliert mit Problemgröße? (nicht Größe der Tasks)
– Skalierbarkeit
9
KAPITEL 2. ENTWURF PARALLELER PROGRAMME
2.1. PCAM-METHODE NACH FOSTER (1995)
2.1.2 Kommunikation (C)
Ziel:
Identifikation der Kommunikationen, die erforderlich sind, um Tasks mit den von ihnen benötigten Daten zu versorgen.
Kommunikationsmuster:
•
•
•
•
lokal vs. global
strukturiert vs. unstrukturiert
statisch vs. dynamisch
synchron vs. asynchron
Checkliste:
• reguläre Struktur, d. h. Anzahl der Kommunikation in allen Tasks etwa gleich?
−→ Skalierbarkeit −→ Balancierung
• möglichst lokale Kommunikation?
−→ Effizienz
• Kommunikation nebenläufig (zu den Berechnungen)?
−→ Effizienz
Beispiel: Matrix-Multiplikation


 aik

Zerlegung A: 







bkj






Jedes aik wird mit n bkj (1 ≤ j ≤ n) multipliziert
Task Aik sendet Element aik zu den n Tasks Bkj (1 ≤ j ≤ n).
Task Bkj erhält n Werte aik (1 ≤ i ≤ n) von Tasks Aik und berechnet n Produkte
aik bkj (1 ≤ j ≤ n).
Die zur Berechnung von cij notwendigen Produkte befinden sich in der j-ten Spalte der BTasks. Verwende etwa rekursives Doppeln zum Aufsummieren der n Produkte.
Analyse:
• sehr unausgeglichene Tasks
• viele Kommunikationen
• ungünstige Datenverteilung
Zerlegung B: Task Cij benötigt i-te Zeile von A und die j-te Spalte von B. Mit diesen Daten kann ohne
weitere Kommunikation cij berechnet werden.
Problem: Die Eingangsmatrizen werden n-mal repliziert.
Beobachtung: Task Cij kann zu jedem Zeitpunkt höchstens ein Produkt aik · bkj berechnen und benötigt
dazu je ein Element von A und B
10
KAPITEL 2. ENTWURF PARALLELER PROGRAMME
2.1. PCAM-METHODE NACH FOSTER (1995)
Idee: Rotiere Zeilen von A und Spalten von B so in Zeilen / Spalten von C, dass zu jedem Zeitpunkt
passende, d. h. zu multiplizierende A/B-Werte in C-Tasks zur Verfügung stehen.
Beispiel: n = 3
Abbildung 2.1: Matrix-Multiplikation n=3
a11
b11
a12
b12
a13
b13
a11
b11
a12
b22
a13
b33
a21
b21
a22
b22
a23
b23
a22
b21
a23
b32
a21
b13
a31
b31
a32
b32
a33
b33
a33
b31
a31
b12
a32
b23
Rotiere die Zeilen von A und die Spalten von B, so dass jede C-Task eine Multiplikation durchführen kann.
i-te Zeile von A wird um i − 1 Positionen nach links rotiert (1 ≤ i ≤ n)
j-te Spalte von B wird um j − 1 Positionen nach oben rotiert (1 ≤ j ≤ n)
2.1.3 Parallele Matrixmultiplikation nach Gentlement (1978)
n2 Tasks Cij (1 ≤ i, j ≤ n) mit Elementen aij , bij der Eingangsmatrizen, die jeweils cij berechnen sollen.
als Kommunikationsstruktur: Torusvernetzung der Größe n × n
Analyse:
• synchrones Verfahren
• Tasks gleich komplex
• Kommunikation:
– lokal
– nebenläufig zur Berechnung
– nebenläufig in Zeilen / Spalten
funktionale Zerlegung:
Ausgangspunkt: n3 Tasks, die jeweils ein Produkt aik bkj berechnen sollen
=⇒ 3- dimensionale Struktur (Würfeltopologie)
11
KAPITEL 2. ENTWURF PARALLELER PROGRAMME
2.1. PCAM-METHODE NACH FOSTER (1995)
Listing 1 Parallele Matrixmultiplikation nach Gentlement
– Rotiere i-te Zeile von Matrix A um i − 1 Positionen nach links
– Rotiere j-te Spalte von B um j − 1 Positionen nach oben
– Anschließend führt jeder Task folgende Anweisungen durch:
var a, b, c : real;
sum := 0;
for i=1 to n do{
sende a an linke Nachbartask
sende b an obere Nachbartask
sum := sum + a * b;
empfange a von rechter Nachbartask
empfange b von unterer Nachbartask
}
od
cij := sum;
1
2
3
4
5
6
7
8
9
10
11
i
C
A
k
j
B
Broadcast von A in Dimension j
Broadcast von B in Dimension i
=⇒ parallele Produktberechnung
Aufsummieren aller Produkte in Dimension k
2.1.4 Agglomeration (A)
Ziele:
• Zusammenfassung von stark interagierenden Teilberechnungen
−→ Reduktion der Kommunikation
– Flexibilität bezüglich Skalierbarkeit
– Reduktion der Software-Entwicklungskosten
Methoden:
• Dimensionsreduktion
12
KAPITEL 2. ENTWURF PARALLELER PROGRAMME
2.1. PCAM-METHODE NACH FOSTER (1995)
Oberflächen ↑
Kommunikation
Volumen - Effekt
↑
Berechnungen
Beispiel: 8 × 8-Gitter
Jeder Knoten verwaltet ein Element und schickt dieses an alle Nachbarn.
y 64 ∗ 4 = 256 bidirektionale Kommunikationen von ebenso vielen Datenelementen.
a) Dimensionsreduktion: Zeilenweise
y 8 Tasks, die je 8 Datenelemente verwalten
y 8 ∗ 2 = 16 bidirektionale Kommunikation mit Austausch von 16 ∗ 8 = 128
Datenelemente.
b) Blockaufteilung in 2 × 2 Grid:
y jeder Knoten verwaltet 16 Elemente und tauscht Randdaten mit allen Nachbarn.
y 4 ∗ 4 = 16 bidirektionale Kommunikation mit Austausch von 16 ∗ 4 = 64
Datenelemente.
Methoden:
(Agglomeration)
• Granularitätserhöhung durch
a) Dimensionsreduktion
b) Blockbildung
−→ Teilblöcke in Mehrdimensionalen Gitterstrukturen
Beispiel: Gentleman Verfahren
• Granularität einzelner Tasks ist im Allgemeinen zu gering
13
KAPITEL 2. ENTWURF PARALLELER PROGRAMME
2.1. PCAM-METHODE NACH FOSTER (1995)
–
–
–
–
Einteilung der Matrizen in m2 Submatrizen der Dimension
Standartmatrixmultiplikation für Teilmatrizen
Verhältnis Kommunikationsaufwand
sinkt
Berechnungsaufwand
gute Skalierbarkeit
n
m
c) Baumstrukturen
Agglomeration der Baumstruktur für Reduktion
Beispiel: für Replikation von Berechnungen in der Agglomerationsphase.
Betrachte Reduktion mit anschließendem Broadcast des Reduktionsergebnisses
=⇒ 2 log2 N Schritten bei N Prozessoren
à Hypercube-Topologie (Abb. 2.2)
Abbildung 2.2: Hypercube
(a) k = 1
14
(b) k = 2
(c) k = 3
KAPITEL 2. ENTWURF PARALLELER PROGRAMME
2.1. PCAM-METHODE NACH FOSTER (1995)
Abbildung 2.3: Butterfly-Vernetzung
4 Prozessoren
↑ Mehrfachberechnung
Ein Hypercube der Dimension k (Abb. 2.4) enthält 2k Knoten und erlaubt Reduktionen / Broadcast in k-Schritten
Abbildung 2.4: Hypercube der Dimension k
i
C
A
k
j
B
−→ Matrixmultiplikation im Hypercube1
Verteile Matrixelemente so in einem Hypercube der Dimension 3q und q = ⌈log2 n⌉, so dass
• alle n3 ≤ 23⌈log2 n⌉ Multiplikation gleichzeitig erfolgen können
• Broadcast der Eingabematrizen in O (log2 n)
• Summation der Produkte in O (log2 n) möglich
=⇒ Gesamtaufwand O (log2 n)
Beispiel: n = 3
y ⌈log2 n⌉ = 2 = q
y Hypercube der Dimension 6 mit 26 = 64 Knoten
Checkliste:
(Agglomeration)
•
•
•
•
•
•
1
Reduktion der Kommunikationskosten durch Verbesserung der Lokalität?
Mehraufwand durch Replikation von Daten / Berechnungen gerechtfertigt?
Skalierbarkeit?
Verhältnis Kommunikation – Berechnungen?
Balancierung der Task-Komplexität?
weitere Zusammenfassung?
Deckel, Nassimi and Sahni 1981
15
KAPITEL 2. ENTWURF PARALLELER PROGRAMME
2.1. PCAM-METHODE NACH FOSTER (1995)
2.1.5 Mapping (M)
(Abbildung auf Rechner)
Ziele:
• Verteilung der verbleibenden Tasks auf die Prozessoren des Zielrechners
• Platzierung von häufig kommunizierenden Tasks auf den selben Prozessor und unabhängige Tasks auf unterschiedlichen Rechner
Methoden:
• statische vs. dynamische Lastverteilung
• explizite Task-Verteilung
−→ Master-Worker-Algorithmus
Checkliste:
• alle Alternativen berücksichtigt?
• Implementierungskosten vertretbar?
16
3 Grundkonzepte paralleler Programme
−→ MPD:1 Multithreaded, Parallel and Distributed
3.1 Synchronisation von Speicherzugriffen
Problem:
• Speicherzugriffe auf gemeinsame Variablen müssen koordiniert werden
• nicht atomare Operationen (können unterbrochen werden) erfordern exklusiven Zugriff auf globale
Daten
3.1.1 Synchronisationskonstrukte
• Semaphore2
Ein Semaphor ist ein abstrakter Datentyp mit:
– nicht negativer Integer-Variablen (Semaphorzähler)
– zwei unteilbare Operationen:
∗ P (passieren)
∗ V (verlassen)
in MPD:
Semaphor-Deklaration: sem identifier[subscripts]= expression
Operationen:
P(identifier [subscripts])
V(identifier [subscripts])
1
2
Gregory R. Andrews
Edsger W. Dijkstra, 1965
17
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.1. SYNCHRONISATION VON SPEICHERZUGRIFFEN
3.1.2 Synchronisationsformen
a) Wechselseitiger Ausschluss (mutual exclusion)
Beispiel: Geschützter Zugriff auf gemeinsame Ressourcen
b) einseitige Synchronisation
Ereignissynchronisation (events)
Bedingungssynchronisation (conditions)
Ein Prozess wartet auf Bedingung oder Ereignis, dass von einem anderen ausgelöst wird.
Beispiel: Erzeuger-Verbraucher mit unbeschränktem Puffer
c) Barrierensynchronisation
Eine Gruppe von Prozessen muss an einer sogenannten Barriere warten, bis alle Prozesse der Gruppe
die Barriere erreicht haben.
Beispiel: Synchronisation von Schleifendurchläufen paralleler Prozesse.
Synchronisationskonstrukte
• Semaphoren (Dijkstra)
Ein Semaphor S ist ein abstrakter Datentyp mit
– nicht-negativer Integer Variable (Semaphorzähler)
– zwei unteilbare Operationen
P (passieren) , V (verlassen)
P(S)(atomar):
Wenn S > 0, dann S := S − 1;
sonst wird der ausführende Prozess suspendiert
V(S)(atomar): Wenn Prozesse bei Ausführung von P(S) suspendiert wurden, reaktiviere einen Prozess;
sonst: S := S + 1
Beispiel: einseitige Synchronisation
Erzeuger / Verbraucher - Problem: Verbraucher kann erst konsumieren, wenn Erzeuger produziert hat.
Annahme: unbeschränkter
Puffer
½
sem mutex = 1
Semaphorvariablen:
sem full = 0
18
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.1. SYNCHRONISATION VON SPEICHERZUGRIFFEN
Listing 2 Erzeuger Verbraucher - Problem
process producer()
int item;
while (true){
produce(item);
P(mutex);
enter(item);
V(mutex);
V(full);
}
1
2
3
4
5
6
7
8
9
process consumer()
int item;
while (true){
P(full);
P(mutex);
remove(item);
V(mutex);
consume(item);
}
11
12
13
14
15
16
17
18
19
Fallstudie: Leser- / Schreiberproblem
Mehrere Prozesse arbeiten auf gemeinsamen Speicherbereich. Gleichzeitige Lesezugriffe sind erlaubt Schreibzugriffe müssen exklusiv erfolgen.
=⇒ CREW3
Lösungsansatz: [P. J. C OURTOIS , F. H EYMANNS , D. L. PARNAS ACM 1971]
Idee: Verwalte Zähler readcount für Leseranzahl
Listing 3 Zwei Semaphoren
sem writing = 1 −→ Sperre für exklusiven Schreibzugriff
sem rcount_mutex = 1 −→ Schutz für readcount
Korrektheit:
Das Semaphor writing schützt den Speicherbereich.
• Schreiber aktiv (in critical section) y writing ist gesetzt
– kein weiterer Schreiber kann passieren
– 1. Leser bei P(writing) blockiert
– weitere Leser bei P(rcount_mutex) blockiert
• Leser aktiv y writing ist gesetzt durch 1. Leser
– weitere Leser passieren writing nicht, sondern erhöhen nur readcount
– Schreiber werden bei P(writing) blockiert.
3
Concurrent Read Exclusive Write
19
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.1. SYNCHRONISATION VON SPEICHERZUGRIFFEN
Problem:
Schreiber werden ausgehungert, falls readcount nie Null wird, weil ständig neue Leser hinzukommen, bevor aktive Leser den kritischen Bereich verlassen.
Lösung:
Blockiere neue Leser, sobald ein Schreiber wartet.
−→ Zähler für Leser und für wartende Schreiber writecount.
neue Semaphore:
sem wcount_mutex = 1
sem reading = 1 (Sperre für Leser, falls Schreiber wartet)
Wenn nicht bekannt ist, nach welcher Strategie bei ’reading’ blockierte Prozesse reaktiviert werden,
können Schreiber immer noch ausgehungert werden, falls immer wieder wartende Leser reaktiviert werden.
=⇒ Sorge dafür, dass bei reading höchstens ein Schreiber und keine weiteren Leser blockiert werden.
=⇒ weiteres Semaphor: sem r_protect = 1;
3.1.3 Barrierensynchronisation
Prozesse dürfen nur passieren, wenn alle Prozesse der Gruppe die Barriere erreicht haben.
klassisches Beispiel:
Iterationsverfahren zum Lösen partieller Differentialgleichungen
Zweidimensional Temperaturverteilungsproblem
Ermittle die Temperatur in Gitterpunkten im stabilen Zustand
ϕx,y =
1
(ϕx−1,y + ϕx+1,y + ϕx,y−1 + ϕx,y+1 )
4
−→ Iterationsverfahren (Jacobi, 1845)
ϕ0x,y -geschätzter Anfangswert
20
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.2. MONITORE
ϕi+1
x,y =
¢
1¡ i
ϕx−1,y + ϕix+1,y + ϕix,y−1 + ϕix,y+1
4
einfache Zählbarriere hat Aufwand O (n) −→ lineare Barriere
Optimierung: Turniertechnik −→ Aufwand O (log n)
Die globale Barriere ist eine sehr starke und entsprechend teure Form der Synchronisation. Oft ist es möglich, eine globale Synchronisation durch eine lokale zu ersetzen.
Beispiel: lokale Synchronisation eines Zeilenprozesses mit beiden Nachbarzeilenprozessen
Symmetrische Barriere für zwei Prozesse mit zwei Semaphoren: sem b1=0; sem b2=0;
3.2 Monitore
abstrakte Datenstruktur mit impliziten Synchronisationseigenschaften.
Zugriffsoperationen werden im wechselseitigen Ausschluss ausgeführt
−→ verborgene Implementierung der Zugriffsoperationen und der Synchronisation
21
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.2. MONITORE
3.2.1 Monitordeklaration
monitor <m_name> {
<variable declaration>
<initialization statements>
<procedure declaration>
}
Aufruf eines Monitorprozesses: <m_name> . <procedurename> (<args>)
Für Synchronisation innerhalb von Monitoren (bedingte Synchronisation) ist eine Erweiterung des Basiskonzeptes erforderlich:
Bedingungsvariablen (condition variables): condvar <name>
Operationen auf Bedingungsvariablen
• wait(c) „Warte auf Erfüllt sein von c“
Der ausführende Prozess wird suspendiert und in die Warteschlange zu c eingereiht. Der
Monitor wird freigegeben.
• signal(c) „Signalisiere, dass c gilt“
Der ausführende Prozess reaktiviert den „ältesten“ Prozess in der Warteschlange zu c.
Damit gegenseitiger Ausschluss gewährt bleibt, muss festgelegt werden, welcher Prozess den
Monitor erhält.
3.2.2 Signalisierungsmethoden
• signal_and_exit „Concurrent Pascal“
– Signal nur am Ende von Monitorproz. erlaubt
• signal_and_continue „SR“
– signalisierender Prozess bleibt aktiv, reaktivierter Prozess muss sich neu um Monitorzugang
bewerben.
• signal_and_wait „Modula“
– signalisierender Prozess muss sich neu um Monitor bewerben.
Beispiel:
22
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.3. SYNCHRONISATION UND KOMMUNIKATION ÜBER NACHRICHTEN
Listing 4 monitor bounded_buffer
monitor bounded_buffer
typeT buf[n];
int front = 0, rear = 0, count = 0;
condvar not_full, not_empty;
procedure enter (typeT data){
while (count == n) wait(not_full);
buf[rear] = data; count++;
rear = (rear+1) mod n;
signal(not_empty);
}
1
2
3
4
5
6
7
8
9
10
3.3 Synchronisation und Kommunikation über Nachrichten
• meist bei verteiltem Speicher
−→ kein gemeinsamer Speicher
−→ keine globalen Variablen
−→ keine zu schützenden Datenbereiche
• Kommunikation über „Kanäle“ und Nachrichtenaustausch (message passing)
Modell:
Sender =⇒ Empfänger
Statt schreiben / lesen gemeinsamer Variablen senden / empfangen von Nachrichten
• Synchronisation indirekt dadurch, dass Nachrichten erst nach dem Senden empfangen werden können.
• Kanäle sind Abstraktionen vorhandener Verbindungsnetzwerke
• Kommunikationsaufwand bestimmender Faktor für die Leistung von Verfahren
3.3.1 Kommunikationsmodelle
Basiskonzepte:
• Prozesse & Kanäle
• Sende- und Empfangsprimitiven
sende „Nachricht“ an „Empfänger“
empfange „Nachricht“ (von „Sender“)
Merkmale:
(a) Bezeichnung von Quelle und Ziel der Infomationsübertragung – direkte Prozessbenennung4 vs. Kanäle5
(b) Anzahl der Kommunikationspartner / Art der Kanäle
4
5
„implizite Kanäle zwischen jedem Paar von Prozessen“
mehrere Kommunikationswege zwischen gleichen Prozessen möglich
23
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.3. SYNCHRONISATION UND KOMMUNIKATION ÜBER NACHRICHTEN
1:1
1:n
m:n
m:1
Punkt-zu-Punkt-Kommunikation
Broadcast, Multicast
Briefkasten (mailbox), schwarzes Brett (black board)
Briefkasten mit einem Empfänger (ports)
(c) Synchronisation
• asynchron:
Sender braucht nicht auf Empfang der Daten zu warten
– Kanalpuffer erforderlich
∗ beschränkter Puffer (evtl. Blockade durch vollem Puffer)
∗ unbeschränkter Puffer
– gepuffertes Senden: Nachricht wird aus Sendepuffer in Systempuffer, bevor sie aufs Verbindungsnetzwerk geschrieben wird
– ungepuffertes Senden: vom Sendepuffer ins Netz
– nicht blockierendes Senden: Anstoß des Nachrichtenversandes mit direkter Weitergabe der Kontrolle an Nachfolgeinstruktionen
– blockierendes Senden: wartet, bis Sendepuffer ausgelesen ist
• synchron: Sender und Empfänger warten auf Kommunikation, keine Pufferung, direkte Übertragung
(d) Sichtbarkeit und Direktionalität
• symmetrisch: Kommunikationspartner kennen einander in gleicher Weise
−→ meist datenorientierten Nachrichtenaustausch
• asymmetrisch: Sender kennt Empfänger, aber nicht umgekehrt
−→ meist aktionsorientierte Kommunikation
Beispiel: Client / Server-Systeme
C1
Au
ftra
Server braucht
Client nicht zu
kennen
g
S
Cn
Beispielsprachen: Occam (Vorläufer CSP Hoare 1978)
• unidirektionale 1 - 1 Kanäle
• symmetrische, synchrone Kanäle
• statisches Kanalkonzept: Festlegung aller Kanäle zur Compilezeit
• selektive Kommunikationskommandos
−→ gleichzeitiges Warten auf mehreren Eingabekanälen
24
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.3. SYNCHRONISATION UND KOMMUNIKATION ÜBER NACHRICHTEN
ALT
B1& I n p u t _ G u a r d _ 1
EXPR1
..
.
Bn& I n p u t _ G u a r d _ n
EXPRn
in CSP: Sende- und Empfangsanw. in Guards
P1 `B
C1
BB
B
C3
P3
/ P2
|
|
|~ |
C2
P2 : ALT
C1 ?X
C2 !X
EXPR1
EXPR2
Wie muss ein Protokoll aussehen, das diese Situation klärt und Verklemmungen vermeidet.
Beispiel: Puffer in Occam
• als Fließband
Listing 5 Fließband Buffer
1
2
3
4
5
6
7
8
9
10
11
12
PROC buffer (CHAN OF INT source, sink)
WHILE true
INT local;
SEQ
source ? local
sink ! local
[n+1]CHAN OF INT stream;
PAR
producer(stream[0])
PAR index = 0 FOR n
buffer (stream[n], stream[n+1])
consumer (stream(n+1))
• Paralleler Buffer
25
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.3. SYNCHRONISATION UND KOMMUNIKATION ÜBER NACHRICHTEN
Listing 6 Paralleler Buffer
1
2
3
4
5
6
7
8
9
10
11
12
13
PROC buffer ([n] CHAN OF INT source, sink)
WHILE true
INT local;
PAR index = 0 FOR n
SEQ
source[index] ? local
sink[index] ! local
"TOP-LEVEL"
[n]CHAN OF INT in, out
PAR
producer(in)
buffer(in, out)
consumer(out)
Ada (1980, DoD)
• synchrone Kommunikation
• Rendezvous-Konzept
• asymmetrisch
• 1:1
SR / MPD
• Modellierung verschiedener Konzepte
• Kernkonzept: Operationen
– Aufruf einer Operation
∗ asynchron send
∗ synchron call
• Ausführung einer Operation
– mittels proc −→ „eigener Prozess“
– mittels in −→ „bestehender Prozess“
Aufruf
Ausführung
proc
in
call
Prozeduraufruf (auch remote)
synchrone Komm. (rendezvous)
Beispiel: Simulation von Semaphoren
26
send
dynamische Prozesserzeugung (fork)
asynchrone Kommunikation
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.3. SYNCHRONISATION UND KOMMUNIKATION ÜBER NACHRICHTEN
Listing 7 Simulation von Semaphoren
4
sem s = e , op s(){send}
int n=e
for (i = 1 to n)
send s();
6
P(s)
, receive s()
8
V(s)
, send s()
1
2
3
#s nur mit send aufrufen
#generiere n Eintrittskarten (tickets)
#empfange Eintrittskarte
Deklaration von Operationen in MPD
op <name> (<params>) {<invocations>}
send
call
send,call
Deklaration von Prozess- und Prozedurrümpfen
proc <name> ( <params>){
<body>
}
procedure
→ Operation mit call-Restriction
process
→ Operation mit send-Restriction
Auch Kanäle werden in MPD mit Operationen modelliert. Obige Operationsdeklaration ohne Implementierung wird als m : n Kanal betrachtet. Ein Aufruf „send <name> (<params>)“ entspricht dem nicht
blockierenden Senden einer Nachricht. Mittels „receive <name> (<variables>)“ können Nachrichten aus dem Kanal <name> empfangen werden.
Beispiel: (a) Mischen geordneter Folgen
Listing 8 Mischen geordneter Folgen
1
2
3
4
5
6
7
8
9
10
11
12
13
send stream1(v)
...
(ONE)\
send stream1(EOS)
\
\
-----------(MERGE) receive stream1(x1)
/
receive stream2(x2)
send stream2(v)
/
while(x1<EOS) or (x2<EOS){
...
(TWO)/
if(x1<=x2) {
write(x1)
send stream2(EOS)
receive stream1(x1)
}
else{write(x2); receive stream2(x2);}
}
27
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.3. SYNCHRONISATION UND KOMMUNIKATION ÜBER NACHRICHTEN
Beispiel: (b) Erzeuger- / Verbraucher
Listing 9 Erzeuger- / Verbraucher
############
|−−−−−−−−−−−|
############
# p r o d u c e r # −−−−> |
KANAL
| −−−−> # c o n s u m e r #
############
|−−−−−−−−−−−|
############
|
op b u f f e r ( i t e m _ t y p e ) { s e n d }
|
|
|
send b u f f e r ( item )
r e c e i v e b u f f e r ( item )
Fallstudie: Auflösen von Dreiecksgleichungssystemen
Ax = b mit unterer Dreiecksmatrix



A=

a11
a21
..
.
0
a22
..
.
···
0
..
.
···
···
..
.
0
0
..
.
an1 an2 an3 . . . ann





, x = 



x1
..  , b = 

. 
xn
Lösung:
x1 =
x2 =
..
.
xn =
b1
a11
(b2 − a21 x1 )
a22
³
bn −
Pn−1
j=1
ann
aij xj
´
yPipeline-Algorithmus
Berechne x1 −→ Berechne x2 −→ . . . −→ Berechne xn −→ Ausgabe von x
• elementares ’message passing’ , ’goto’ der parallelen Programmierung
=⇒ Suche nach abstraktere Kommunikationskonstrukte
typisches Kommunikationsmuster:
P1(Client)
P2(Server)
send "Auftrag" to P2
<
--> receive "Auftrag" from P1
>
<
<
>
>
<
<
>
>
<-- send "Antwort" to P1
receive "Antwort" from P2
28

b1
.. 
. 
bn
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.3. SYNCHRONISATION UND KOMMUNIKATION ÜBER NACHRICHTEN
RPC - remote procedure call
P1 (Client) {call} service (input_args, result_args)
(in MPD als proc)
Aufruf einer Prozedur, die von einem anderen Prozess, der meist eigens generiert wird, ausgeführt wird.
Implizit:
•
•
•
•
Senden der Eingabeargumente / Parameter
Ausführen des Auftrags (durch eigenen Prozess)
Rücksenden der Ergebnisse
Zuweisen an Variablenparameter.
Beispiel: Stack Ressource, ggfs auf anderer virtueller / phys. Maschine:
Listing 10 Stack Ressource
1
2
3
4
6
7
8
9
10
11
12
13
14
15
17
18
19
20
21
22
23
24
25
26
27
28
29
resource Stack{
type result= enum(OK, OVERFLOW, UNDERFLOW)
op push(val int item) returns result r
op pop(var int item) returns result r
body Stack (int size)
int store[1,...,size], int top = 0
proc push(item) returns r{
if (top<size){store[++top]=item, r=OK}
else if (top==size){r= OVERFLOW}
}
proc pop (item) returns r{
... item = ...
}
}
resouce Stack_User()
import Stack
Stack.result x
cap Stack s1, s2
int y
s1 = create Stack(10);
s2 = create Stack(20);
[call] s1.push(25);
s2.push(15);
x=s1.pop(y)
if(x != OK) {...}
...
end Stack_User
Beispiel: dynamische Pipeline zum sortieren durch Einfügen
29
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.3. SYNCHRONISATION UND KOMMUNIKATION ÜBER NACHRICHTEN
Jeder Worker generiert nach Bedarf zunächst seinen Nachfolger, der als Ergebnis seinen Eingabekanal zurückliefert. Anschließend wird die Liste der zu sortierenden Werte gelesen, der
kleinste erhaltene Wert wird gespeichert und größere Werte werden weitergesendet. Nach Erhalt
von i Werten sendet worker(i) den gespeicherten Wert mit der Position i über einen globalen
Antwortkanal an den sort-Prozess zurück.
Rückgabeanweisungen in MPD:
- return Ende des Prozeduraufrufs
Rückgabe der Resultate, Var.- par.
- reply
Kontroll- und Ergebnisrückgabe an aufrufenden Prozess;
Fortsetzung der Prozedurbearbeitung
Rendezvous: Bedienung des Clients durch bestehenden (Server-) Prozess; Vermeidung der Generierung eines separaten Prozesses
P2 (Server): accept service (input_pars, var_params) → body
→Verallgemeinerung synchroner Kommunikation
Das Rendezvous-Konzept ist flexibler als der RPC.
Beispiel: Bounded Buffer in Ada
• Task Spezifikation
– Deklaration des Namens und der Prozeduren
– für alle Prozesse sichtbar
Listing 11 Task Spezifikation
1
2
3
4
task buffer is
entry Append (I: in Integer)
entry Task (I: out Integer)
end buffer;
30
(in MPD: in)
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.4. VERTEILTE PROGRAMMIERUNG IN MPD
• Task Implementierung
Definition der Prozeduren
Listing 12 Task Implementierung
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
task body buffer is
N: constant Integer := 100;
B: array (0...N-1) of Integer;
anfang (ende, anzahl : Integer := 0;
begin
loop
select
when anzahl < N =>
accept Append (I : in Integer)
do B[ende]:= I
end Append
anzahl:= anzahl +1
ende:= (ende+1) mod N
or
when anzahl > 0 =>
accept Take (I : out Integer)...
Die in-Anweisung in MPD verallgemeinert die select-/ accept- Konstrukte von Ada.
Syntax in <op_command> [ ]. . .[ ] <op_command> ni
mit <op_command> der From
<operation> (<formal_id_list>) {return <result_id>}
st <guard_expr> → <block>
Ein Prozess, der eine in- Anweisung ausführt, wird suspendiert, bis eine der Operationen aufgerufen wird.
Die Bedingungsausdrücke <guard_expr> dürfen Operationsparameter referenzieren.
Die receive- Anweisung ist ein Spezialfall der in-Anweisung.
receive op(v1, v2) wird impliziert durch:
in op(p1, p2) →
v1=p1; v2=p2
ni
3.4 Verteilte Programmierung in MPD
Aufspaltung von Programmen in mehrere Addressräume sog. virtuelle Maschinen
• dynamische Erzeugung
31
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.4. VERTEILTE PROGRAMMIERUNG IN MPD
• Platzierung auf spez. physikalischen Maschinen
• transparente Komm.
1. Erzeugung virtueller Maschine
cap vm c
c = create vm()6 on exp78
Ressourcen müssen explizit auf VMen erzeugt werden
create res_name(args) on c←−Verweis auf VM
Globals werden implizit beim Importieren erzeugt. Jede VM erzeugt eigene Instanz importierter Globals.
2. Termination von VMs
destroy expr
destroy cap vm
→ Termination aller Ressourcen mit final code-Ausführung anschließend Terminierung aller Globals mit final
code.
6
erzeugt Verweis auf virtuelle Maschine
optional Platzierung
8
phy. Maschine als String (oder Integer)
7
32
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.4. VERTEILTE PROGRAMMIERUNG IN MPD
Listing 13 Termination von VMs
1
2
3
4
5
6
7
8
10
11
12
13
14
15
17
18
19
20
21
22
24
25
26
27
28
29
30
31
32
33
global glob
int x=0;
sem mutex=1;
body glob
final {
write(x);
}
end
resource test(int N, int n, cap () signal)
import glob
process p [i=1 to N] {
P(mutex); x+=n; V(mutex); send signal()
}
end
resouce main()
import test
const int N = 5;
op done()
cap vm vmcap
cap test t1, t2
t1 = create test(N, 1, done)
vmcap = create vm() on "oran"
t2 = create test(N, 2, done) on vmcap
for [i=1 to 2*N] {
receive done()
}
destroy t1;
destroy t2;
destroy vmcap;
end
locate(n, hostname)
mymachine
myvm
→ Assoziation von Nummer mit Rechner hostname
→ liefert Nummer der eigenen Maschine
→ liefert Verweis auf virtuelle Maschine
33
KAPITEL 3. GRUNDKONZEPTE PARALLELER PROGRAMME
3.4. VERTEILTE PROGRAMMIERUNG IN MPD
Listing 14 tin
1
2
3
4
5
6
7
8
9
11
12
13
14
resource main()
import pipe
const int n = 4
const int m = 10
const string[10] hosts[n] = ("maseru","harare","bamako","bukavu")
cap vm vmcap[m]
int inp
op chan[1:m+1] (int)
op ret (int)
for [i=1 to n] { locate(i,hosts[i]) }
for [i=1 to m] { vmcap[i] = create vm() on ((i-1) mod n)+1;
write(hosts[((i-1) mod n)+1]," bereit")
}
21
write("Bitte Werte eingeben")
for [i=1 to m] { read(inp); send chan[1](inp) }
for [i=1 to m] { create pipe(i,m,chan[i],chan[i+1],ret) on vmcap[i] }
for [i=1 to m] { receive chan[m+1](inp); writes(inp,"
") }
# for [i=1 to m] { receive ret(inp); writes(inp,"
") }
write()
23
end main
16
17
18
19
20
Listing 15 tin2
1
2
3
5
6
7
resource pipe(int i, int m, cap(int) inp, cap(int) out, cap(int) result)
int my_el
int value
process test {
receive inp(my_el)
for [j= 1 to m-i] {
8
9
10
12
write("Prozess ",i," ermittelte Element ",my_el)
14
for [j = 1 to i-1] {
15
16
17
send out(my_el)
19
# send result(my_el)
}
end
20
21
34
receive inp(value);
if (my_el <= value) { send out(value) }
else
{ send out(my_el); my_el = value }
}
receive inp(value)
send out(value)
}
4 Die Bibliothek MPI
• MPI – Message Passing Interface (de-facto Standard)
• MPI-Forum = ca. 40 Organisationen aus Industrie, Universitäten und Forschungslabors
– 1992 Gründung auf Supercomputing Conference
– 1994 MPI-1
– 1997 MPI-2
∗ http://www.mpi-forum.org
• Ziele:
–
–
–
–
–
–
Quellcodeportabilität
Kontinuität der parallelen Programmentwicklung
Effizienz
Flexibilität, Funktionalität ( > 128 Funktionen )
C, C++, Fortran Anbindung
Unterstützung heterogener Architekturen
• In Übungen: LAM-MPI
4.1 Grundkonzepte
• SPMD-Programmstruktur
• 6 Basisfunktionen
→
→
→
→
→
→
MPI_Init
MPI_Finalize
MPI_Comm_rank
MPI_Comm_size
MPI_Send
MPI_Recv
-
Initialisierung
Terminierung
Prozess-ID abfragen
#Prozesse bestimmen
Senden von Nachrichten
Empfangen von Nachrichten
Listing 4.1: The „skeleton“ of an MPI program in C
1
#include "mpi.h"
35
KAPITEL 4. DIE BIBLIOTHEK MPI
4.1. GRUNDKONZEPTE
3
4
5
main(int argc, char **argv)
{
int my_rank, nprocs
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
7
8
9
.
.
.
11
12
13
MPI_Finalize();
15
16
}
int MPI_Init(int *argc, char **argv)
z
}|
{
Adressen der Argumente von main
Initialisiert die MPI-Umgebung und definiert den Kommunikator MPI_COMM_WORLD. Ein Kommunikator
definiert eine Gruppe von Prozessen und einen Kommunikationskontext.
int MPI_Comm_size(MPI_Comm comm,
int *size)
← in
← out
ermittelt die Anzahl der Prozesse im Kommunikator comm
int MPI_Comm_rank(MPI_Comm comm, int *rank)
bestimmt Identifikation eines Prozesses innerhalb eines Kommunikators. Prozesse werden von 0 bis #P rozesse−
1 nummeriert.
int MPI_Finalize()
beendet MPI
int MPI_Send(void *buf,
int count,
MPI_datatype datatypes,
int dest,
int tag,
MPI_Comm comm)
int MPI_Recv(void *buf,
int count,
MPI_datatype datatypes,
int source,
int tag,
MPI_Comm comm,
MPI_Status *status)
36
\
> zu übertragende
/ Daten
→ Rang des Empfängers
→ Kennung
→ Kommunikator
\
> zu empfangende Daten
/
→ Rang des Empfängers
→ Kennung
→ Kommunikator
→ Quelle, Tag, Anz.
tatsächlich
empfangener Daten
KAPITEL 4. DIE BIBLIOTHEK MPI
4.2. KOMMUNIKATION
Beim Nachrichtenempfang können mittels MPI_ANY_TAG und MPI_ANY_SOURCE Nachrichten mit beliebigem Tag bzw. von beliebigem Sender empfangen werden.
−→ VORSICHT: Nichtdeterminismus
In diesem Fall kann man mit dem Status Argument die tatsächlichen Werte abfragen.
Felder:
→ status.MPI_SOURCE
→ status.MPI_TAG
→ in
→ in
→ out
int MPI_Get_count(MPI_Status *status,
MPI_DATATYPE type,
int *count)
liefert Anzahl tatsächlich empfangener Daten
Listing 4.2: MPI pairwise interactions program
1
#include "mpi.h"
/* Include file */
3
main(int argc, char *argv[]) {
int myid, np, ierr, lnbr, rnbr;
real x[300], buff[300], forces[300];
MPI_Status status;
/* Main program */
4
5
6
16
ierr = MPI_Init(&argc, &argv);
if(ierr != MPI_SUCCESS) {
fprintf(stderr,"MPI initialization error\n");
exit(1);
}
MPI_Comm_size(MPI_COMM_WORLD, &np);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
lnbr = (myid+np-1)%np;
rnbr = (myid+1)%np;
18
initialize(x, buff, forces);
20
for (i=0; i<np-1; i++) {
/* Circulate messages */
MPI_Send(buff, 300, MPI_FLOAT, rnbr, 0, MPI_COMM_WORLD);
MPI_Recv(buff, 300, MPI_FLOAT, lnbr, 0, MPI_COMM_WORLD,
&status);
update_forces(x, buff, forces);
}
8
9
10
11
12
13
14
15
21
22
23
24
25
print_forces(myid, forces);
MPI_Finalize();
27
28
29
/* Initialize */
/* Check return code */
/*
/*
/*
/*
Number of procs */
My process id */
Id of left neighbor */
Id of right nbr */
/* Print result */
/* Shutdown */
}
4.2 Kommunikation
MPI unterscheidet
(a)
Punkt-zu-Punkt-Kommunikation
37
KAPITEL 4. DIE BIBLIOTHEK MPI
4.2. KOMMUNIKATION
(b)
kollektive Kommunikation
• ad (a) Kommunikationsmodi 4 Arten von Sendefunktionen
Standard:
gepuffert:
synchron:
ready:
MPI_Send (globale Operation)
MPI_BSend (lokale Operation)
Nachricht wird gepuffert, damit das Senden unabhängig vom Empfangen abgeschlossen
werden kann.
MPI_SSend (globale Operation)
Senden endet, wenn Datenempfang begonnen wurde.
MPI_RSend (locale Operation)
Sendender Prozess sendet sofort. Es muss gewährleistet sein, dass der Empfänger zum
Empfang bereit ist.
→ Leistungssteigerung
Diese 4 Sendearten können blockierend oder nicht-blockierend sein.
nicht-blockierend:
– der Sendevorgang wird initiiert
– Überlappung von Kommunikation und Berechnungen
MPI_ISend MPI_ISSend
MPI_IBSend MPI_IRSend
Es gibt nur eine Empfangsoperation MPI_Recv, die auch nicht-blockierend sein kann (MPI_IRecv)
explizite Pufferverwaltung:
Bereitstellen:
MPI_Buffer_attach(void* buffer, int size)
Freigabe:
MPI_Buffer_detach(void* buffer, int size)
Bei nicht-blockierenden Sende-/Empfangsroutinen wird über ein zusätzliches Ausgabeargument:
MPI_Request *request
getestet werden, ob die Anweisung abgeschlossen ist:
MPI_Wait(request, status)
← warten bis abgeschlossen
MPI_Test(request, flag, status) ← Kontrolle kommt zurück
• ad (b) kollektive Kommunikationsoperatoren Typen:
– globale Barrieren
– globale Datenbewegungen
– Reduktionen
38
KAPITEL 4. DIE BIBLIOTHEK MPI
4.2. KOMMUNIKATION
MPI_Barrier(MPI_Comm comm)
→ globale Synchronisation aller Prozesse in comm
MPI_Bcast(void* inbuf, int count,
MPI_Datatype type, int root, MPI_Comm comm)
→ Broadcast von Prozess root an alle anderen Prozesse in comm
MPI_Gather("Eingabepuffer", "Ausgabepuffer",
int root, MPI_Comm comm)
MPI_Scatter("Eingabepuffer", "Ausgabepuffer",
int root, MPI_Comm comm)
MPI_Reduce(void* inbuf, void* outbuf,
int count, MPI_Datatypes type,
MPI_Op op, int root, MPI_Comm comm)
MPI_Allreduce(void* inbuf, void* outbuf,
int count, MPI_Datatypes type,
MPI_Op op, MPI_Comm comm)
– Mögliche Operatoren
MPI_SUM
MPI_PROD
MPI_MAX, MPI_MIN
MPI_LOR, MPI_LAND, MPI_LXOR
MPI_BOR, MPI_BAND, MPI_BXOR
Synchronisierung am Ende
Beispiel: Berechnung von π durch Integration
Z 1
0
4
dx = π
1 + x2
Listing 4.3: Berechnung von π durch Integration
1
2
3
4
5
6
7
8
10
#include "mpi.h"
#include <stdio.h>
#include <math.h>
int main( int argc, char *argv[] )
{
int n, myid, numprocs, i;
double PI25DT = 3.141592653589793238462643;
double mypi, pi, h, sum, x;
MPI_Init(&argc,&argv);
39
KAPITEL 4. DIE BIBLIOTHEK MPI
4.2. KOMMUNIKATION
MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);
while (1) {
if (myid == 0) {
printf("Enter the number of intervals: (0 quits) ");
scanf("%d",&n);
}
MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (n == 0)
break;
else {
h
= 1.0 / (double) n;
sum = 0.0;
for (i = myid + 1; i <= n; i += numprocs) {
x = h * ((double)i - 0.5);
sum += (4.0 / (1.0 + x*x));
}
mypi = h * sum;
MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
if (myid == 0)
printf("pi is approximately %.16f, Error is %.16f\n",
pi, fabs(pi - PI25DT));
}
}
MPI_Finalize();
return 0;
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
}
Beispiel:
• eindimensionales Temperaturproblem
• Glätten von Bilddaten
allgemeine Beschreibung:
Vektor X = (X0 , . . . , XN −1 )
Berechne X (t) mit X (0) = X
(t+1)
Xi
(t)
=
(t)
(t)
Xi−1 +2Xi +Xi+1
4
mit 0 ≤ i ≤ N − 1 0 ≤ t ≤ T − 1
→Algorithmus: Iteration mit abwechselnden Kommunikationen und Berechnungen
Listing 4.4: Outline of an MPI finite difference algorithm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
40
main(int argc, char *argv[]) {
MPI_Comm com = MPI_COMM_WORLD;
MPI_Init(&argc, &argv);
MPI_Comm_size(com, &np);
MPI_Comm_rank(com, &me);
if (me == 0) {
read_problem_size(&size);
buff[0] = size;
}
/* Global broadcast propagates this data to all processes */
MPI_Bcast(buff, 1, MPI_INT, 0, com);
/* Extract problem size from buff; allocate space for local data */
lsize = buff[0]/np;
local = malloc(lsize+2);
/* Read input data at process 0; then distribute to processes */
KAPITEL 4. DIE BIBLIOTHEK MPI
4.3. KOMMUNIKATOREN, PROZESSGRUPPEN UND TOPOLOGIEINFORMATIONEN
if (me == 0) { work = malloc(size); read_array(work); }
MPI_Scatter(work, lsize, MPI_FLOAT, local+1, lsize,
MPI_FLOAT, 0, com);
lnbr = (me+np-1)%np;
/*Determine my neighbors in ring */
rnbr = (me+1)%np;
globalerr = 99999.0;
while (globalerr > 0.1) {
/* Repeat until termination */
/* Exchange boundary values with neighborts */
ls = local+lsize;
MPI_Send(local+2, 1, MPI_FLOAT, lnbr, 10, com);
MPI_Recv(local+1, 1, MPI_FLOAT, rnbr, 10, com, &status);
MPI_Send(ls-2, 1, MPI_FLOAT, rnbr, 20, com);
MPI_Recv(ls-1, 1, MPI_FLOAT, lnbr, 20, com, &status);
compute(local);
localerr = maxerror(local);
/* Determine local error */
/* Find maximum local error, and replicate in each process */
MPI_Allreduce(&localerr, &globalerr, 1, MPI_FLOAT,
MPI_MAX, com);
}
/* Collect results at process 0 */
MPI_Gather(local, lsize, MPI_FLOAT, work, size,
MPI_FLOAT, 0, com);
if (me == 0) { write_array(work); free(work); }
MPI_Finalize();
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
P0
P0
}
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
| lsize | lsize | . . . . . | lsize |
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
||
||
||
\/
\/
\/
−−−−−− −−−−−−
−−−−−−−−−
| P0 |
| P1 |
| Pnp−1 |
−−−−−− −−−−−−
−−−−−−−−−
||
||
||
\/
\/
\/
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
| lsize | lsize | . . . . . | lsize |
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
( G r a f i k s t i m m t NICHT )
alternative Realisierung des Datenaustauschs
MPI_Irecv(ls+1, 1, MPI_FLOAT, rnbr, 10, com, &r1)
MPI_Rsend(local, 1, MPI_FLOAT, lnbr, 10, com)
MPI_Irecv(local, 1, MPI_FLOAT, lnbr, 20, com, &r2)
MPI_Rsend(ls, 1, MPI_FLOAT, rnbr, 20, com)
¾
MPI_Wait (r1, &status)
MPI_WAITALL (2, req, status)
|
{z
}
MPI_Wait (r2, &status)
Felder
compute (local)
4.3 Kommunikatoren, Prozessgruppen und Topologieinformationen
in fast allen Kommunikationsbibliotheken
41
KAPITEL 4. DIE BIBLIOTHEK MPI
4.3. KOMMUNIKATOREN, PROZESSGRUPPEN UND TOPOLOGIEINFORMATIONEN
• Nachrichtenkennungen (tags)
• Prozessgruppen
neu in MPI:
• Kommunikatoren
– bessere Kapselung von Bibliotheksfunktionen
– Erleichterung des Umgangs mit Prozessgruppen und virtuellen Topologie
Ein Kommunikator
• bestimmt eine Gruppe von Prozessen das heißt eine geordnete Menge von Prozessen mit
lokalem Rang ∈ {0, . . . , #P rozesse − 1}
• definiert einen Kontext für Kommunikationen
→ Einführung separater, sicherer d. h. sich nicht beeinflussender Universen zum Nachrichtenaustausch
Beispiel:
Was geschieht, wenn P2 verzögert wird?
DEADLOCK
42
KAPITEL 4. DIE BIBLIOTHEK MPI
4.3. KOMMUNIKATOREN, PROZESSGRUPPEN UND TOPOLOGIEINFORMATIONEN
Vordefinierte Kommunikatoren:
MPI_COMM_WORLD
MPI_COMM_SELF
MPI_COMM_NULL
"Gruppe aller Prozesse"
"Prozess selbst"
"ungültiger Kommunikator"
4.3.1 Prozessgruppen: Konstruktion, Analyse, Manipulation
MPI_Comm_group(MPI_Comm comm, MPI_Group *group)
liefert Prozessgruppe zu Kommunikator comm
MPI_Group_union(MPI_Group group1,
MPI_Group group2, MPI_Group *group)
MPI_Group_intersection(MPI_Group group1,
MPI_Group group2, MPI_Group *group)
MPI_Group_difference(MPI_Group group1,
MPI_Group group2, MPI_Group *group)
Vereinigung und Schnitt sind assoziativ, aber wegen der Prozessordnung nicht kommutativ.
→ leere Gruppe MPI_GROUP_EMPTY
MPI_Group_size(MPI_Group group, int *size)
MPI_Group_rank(MPI_Group group, int *rank)
Falls Prozess nicht in Gruppe, Ergebnis MPI_UNDEFINED
MPI_Group_incl(group, n, ranks,
newgroup)
MPI_Group_excl(group, n, ranks,
newgroup)
←
←
←
←
in
out
in
out
erzeugt eine neue Gruppe mit n Prozessen, die in group die Ränge ranks [0] . . . ranks [n − 1] haben und
in newgroup die Ränge 0 . . . n − 1
→ auch Umordnung von Prozessen in Gruppe möglich
Die excl-Variante streicht die durch ranks angegebenen Prozesse aus group.
MPI_Group_free(group) deallokiert Prozessgruppe
43
KAPITEL 4. DIE BIBLIOTHEK MPI
4.3. KOMMUNIKATOREN, PROZESSGRUPPEN UND TOPOLOGIEINFORMATIONEN
4.3.2 Kommunikatoren
Neue Kommunikatoren können aus bestehenden Kommunikatoren oder Prozessgruppen gebildet werden.
MPI_Comm_dup(MPI_Comm comm, MPI_Comm *newcomm)
→ neuer Kommunikatoren mit derselben Prozessgruppe, aber neuem Kontext.
MPI_Comm_create(comm, group,
newcomm)
← in
← out
group muss Teilmenge der Prozessgruppe von comm sein.
MPI_Comm_split(comm, color, key, ← in
newcomm) ← out
Aufteilung der Prozessgruppe von comm in disjunkte Teilgruppen gemäß color, Ordnung innerhalb der
Teilgruppen gemäß key, bei identischen Schlüsseln Ordnung aus comm.
MPI_Comm_free(MPI_Comm *comm)
(A)
MPI_Comm comm, newcomm;
int myid, color;
MPI_Comm_rank(comm, &myid);
color = myid % 3;
MPI_Comm_split(comm, color, myid, &newcomm)
(B) Master-/ Worker-Schema mit separatem Kommunikator für Worker-Prozess
44
KAPITEL 4. DIE BIBLIOTHEK MPI
4.3. KOMMUNIKATOREN, PROZESSGRUPPEN UND TOPOLOGIEINFORMATIONEN
Abschlusskriterium: Genauigkeit der Approximation < ε1
→ MPI_ALLREDUCE auf Worker
P0
P1
l i b _ c a l l ( comm_b )
l i b _ c a l l ( comm_b )
MPI_RECV . . . <−−−−−−−− MPI_SEND . . .
MPI_RECV . . .
<−−\
MPI_BARRIER
\ 2 MPI_BARRIER
l i b _ c a l l ( comm_b )
\ l i b _ c a l l ( comm_b )
MPI_RECV . . .
\ MPI_SEND . . .
MPI_RECV . . .
P2
l i b _ c a l l ( comm_b )
MPI_SEND . . .
MPI_BARRIER
l i b _ c a l l ( comm_b )
MPI_SEND . . .
4.3.3 Virtuelle Topologien
Unterstützung von festen Kommunikationsstrukturen
• effizientere Abbildung auf physikalische Zielmaschine
• einfachere Benennung von Prozessen
• Verbesserung der Lesbarkeit von Programmen
zwei Arten:
• kartesische Topologien
– Gitter, Würfel, Torus, Hypercube
• Graphentopologie
feste Assoziation mit Kommunikator
Erzeugung führt zu neuem Kommunikator
MPI_Cart_create(
MPI_Comm comm_old,
int ndims,
←− #Dimensionen
[int] dims,
←− Ausdehnung in den Dimensionen
[bool] periods,
←− Boolsche Werte, die pro
Dimensionen zyklische Verbindungen
erlauben oder nicht
bool reorder,
←− False verbietet die Umordung von
Prozessen bzgl. der Ränge
MPI_Comm *comm_cart)
1
2
Parameter
back-masking Problem
45
KAPITEL 4. DIE BIBLIOTHEK MPI
4.3. KOMMUNIKATOREN, PROZESSGRUPPEN UND TOPOLOGIEINFORMATIONEN
Beispiel:
dims[0] = 4
ndims = 2
dims[1] = 3
periods[0]= periods[1]= false
reorder = true
Dim
0↓
1→
−−
(0, 0)0
(1, 0)3
(2, 0)6
(3, 0)9
(0, 1)1
(1, 1)4
(2, 1)7
(3, 1)10
(0, 2)2
(1, 2)5
(2, 2)8
(3, 2)11
Die Kommunikation
wird nicht auf
diese Topologie
eingeschränkt
Hypercube: n−dim Torus (zyklisch) mit je genau 2 Proz. pro Dimension
4.3.4 Zugriffsroutinen
←− in
←− out
MPI_Cart_rank(comm, coords,
rank)
comm - Kommunikator mit kartesischer Topologie
MPI_Cart_coords(comm, rank, maxdims,
coords)
←− in
←− out
coords - Koordinaten zu Prozess mit Rang rank
MPI_Cart_shift(comm, direktion, disp,
rank_source, rank_dest)
←− in
←− out
direktion - Dimension für shift
disp - #shif t − pos
Beispiel: comm mit zwei dimensionaler Torusstruktur und Feld a, dass elementweise verteilt ist. Verschieben der i−ten Spalte um i Elemente (Rotieren)
MPI_Comm_rank(comm, &rank);
MPI_Cart_coords(comm, rank, maxdims, &coords);
MPI_Cart_shift(comm, 0, coords[1], &source, &dest);
MPI_Sendrecv_replace3 (a, 1, MPI_REAL, dest, 0,
source, 0, comm, &status);
Bestimmen einer balancierten Gitterstruktur zu einem Kommunikator
MPI_Dims_create(nnodes, ndims,
dims)
3
Senden und Empfangen auf dem selben Datenbereich
46
←− in
←− out
KAPITEL 4. DIE BIBLIOTHEK MPI
4.4. ABGELEITETE DATENTYPEN
Im Feld dims können Felder vorbesetzt werden. Dabei muss nnodes Vielfaches von
Y
dims [i]
i mit dims[i]6=0
sein.
Beispiel:
dims vor Aufruf
(0,0)
(0,3,0)
Aufrufparameter
(6,2,dims)
(7,2,dims)
(6,3,dims)
(7,3,dims)
dims nach Aufruf
(3,2)
(7,1)
(2,3,1)
ERROR
4.3.5 Interkommunikatoren
bisher: Intrakommunikator −→ Kommunikator innerhalb von Prozessgruppen
Interkommunikatoren dienen der Kommunikation zwischen disjunkten Prozessgruppen.
Sie erlauben nur Punkt-zu-Punkt Kommunikation.
Erzeugung über MPI_Intercomm_create
4.4 Abgeleitete Datentypen
Nachrichten
Abbildung 4.1: Zusammenhängender Puffer
Um nicht zusammenhängende Speicherbereiche bzw. Objekte mit unterschiedlichen Teiltypen
zu versenden, können eigene Datentypen definiert werden.
47
KAPITEL 4. DIE BIBLIOTHEK MPI
4.4. ABGELEITETE DATENTYPEN
4.4.1 Spezifikation neuer Datentypen
Eine Typabbildung (type map) ist eine Folge von Paaren der Form:
< typei , dispi |0 ≤ i < n >
wobei typei Basistypen und dispi ganze Zahlen / relative Adressen (displacements) sind.
Die Folge der Typen < typei |0 ≤ i < n > heißt Typsignatur der Typabbildung. Mit einer
Basisadresse buf spezifiziert eine Typabbildung einen Komm.- Puffer mit n Einträgen. Eintrag
i beginnt an Adresse buf + dispi und hat Typ typei .
Beispiel:
MPI_INT hat Typabb. <(int, 0)>
<(int, 0), (char, 4)>
bezeichnet
[0 ---------- int ------------][4-char-]
MPI_Type_Contignous(count,
←− ⇒ 0
oldtype, newtype)
←− MPI_Datatype
MPI_Send(buf, count, type,. . .)
MPI_Type_Contignous(count, type, newtype)
MPI_Send(buf, 1, newtype,. . .)
MPI_Type_vector(count, blocklength, stride,
oldtype, newtype)
Beispiel:
count=2, blocklength=3, stride=5
oldtype [//]
newtype [//][//][//][--][--][//][//][//][--][--]
1.Block
2.Block
-----------------Schrittweite (Stride)
Beispiel: Sende 5−te Spalte einer Zeilenweise gespeicherten Matrix.
double results [IMAX][JMAX],
MPI_Datatype col,
MPI_Type_vector(IMAX, 1, JMAX, MPI_DOUBLE, &col)
MPI_Send(&result4 [0][4], 1, col,. . .)
4
5te Spalte
48
5 Parallele Algorithmen
5.1 Das PRAM- Rechnermodell
PRAM: Parallel Random Access Machine (F ORTUNE , W YLLIE 1978)
einfach, unrealistisch, da Vernachlässigung von Interprozessorkommunikation, konstanter Zugriff auf
globalen Speicher für alle Prozessoren
→ SIMD (Single Instruktion Multiple Data) Modell
Abbildung 5.1: Aufbau einer PRAM
Arbeitsweise:
• Ein- / Ausgabe über den globalen Speicher
• Die Berechnung beginnt mit einem einzelnen aktiven PE.
• In einem Berechnungsschritt kann ein aktives PE ein anderes PE aktivieren
– eine einzelne RAM Operation: ALU-Ops, Sprünge,. . .
– einen lokalen oder globalen Speicherplatz lesen oder schreiben
– Alle aktiven PEs führen dieselbe Instruktion aus.
• Die Berechnung terminiert, wenn der letzte aktive Prozessor stoppt.
Kosten einer PRAM-Berechnung
#Proz ∗ parallele Zeitkomplexität z. B. Θ (p log p)
Speicherorganisation:
49
KAPITEL 5. PARALLELE ALGORITHMEN
5.1. DAS PRAM- RECHNERMODELL
• EREW (Exclusive Read Exclusive Write)
keine Lese- / Schreibkonflikte erlaubt
• CREW (Concurrent Read Exclusive Write)
gleichzeitiges Lesen erlaubt, gleichzeitiges Schreiben nicht „Default-Modell“
• CRCW (Concurrent Read Concurrent Write)
gleichzeitiges Lesen und Schreiben erlaubt
Auflösen von Schreibkonflikten bei CRCW:
• COMMON: Alle in eine Speicherposition schreibenden Proz. schreiben den selben Wert
• ARBITRARY: zufällige Auswahl
• PRIORITY: Der Proz. mit kleinstem Index darf schreiben.
Satz 1.1: Ein p-Proz. CRCW-PRIORITY-PRAM kann durch eine p-Proz. EREW-PRAM simuliert werden.
Dabei wird die Zeitkomplexität um einen Faktor (log p) erhöht.
Beispiel: PRAM mit N = 2k Prozessoren
In einem unsortierten Datenbereich mit n ≥ N Plätzen soll ein Element x gesucht werden.
sequentieller Algorithmus: lineare Suche
worst case: n Schritte
average case:
n
2
Schritte
EREW-PRAM: Sei Pi der i-te Proz. 0 ≤ i ≤ N − 1
Vorphase:
Aktivierung der N Proz. und Broadcast des Wertes x (wegen ER)
→ log N Schritte
Berechnungsphase:
Aufteilung des Datenbereichs in N Teilbereiche der Größe (n div N ) bzw. (n div N ) + 1.
Jeder Prozessor Pi , 0 ≤ i ≤ N − 1, durchläuft im Gleichtakt mit den anderen Prozessoren seinen
Teilbereich und sucht x.
Was geschieht, wenn x von einem Prozessor gefunden wird? Jeder Prozessor schreibt sein Endsignal
in einen eigenen Platz im Speicher. Nach jedem Vergleichschritt wird eine globale Reduktion mit
logischer Oder-Verknüpfung der Endsignale durchgeführt. Im Schritt j, (0 ≤ j ≤ k − 1) wenden die
Prozessoren Pi , 0 ≤ i ≤ 2k − 1 − j die Verknüpfung auf ihr eigenes Endsignal und das von Pi+2k−1−j
an und schreiben das Ergebnis in die Speicherzelle von Pi
50
KAPITEL 5. PARALLELE ALGORITHMEN
5.1. DAS PRAM- RECHNERMODELL
P0
P1
P7
Anschließend Broadcast des Ergebnis in k-Schritten
→ worst case Zeitkomplexität
lnm
log N +
∗ (1 + 2 log N )
N
CREW-PRAM
Anfängliches Broadcast des Wertes x
Statt Reduktion / Broadcast der Endsignale integriertes Butterfly-Schema
XXXXXXXXXXXXXXXXXXXXXXfX..fXfff fffff fffff fffff
XXXXXXXXXXfXfXfXfXfXfXfX. fXfXfXfXfXfXfXffffffffff
fXfXfXfX XfXfXfXf fXfXfXfX XfXfXfXf
ffffffffffXfXfXfXfXfXfXfXfXfXfXfXfXfXfXXXXXXXXXX
fQffffffQfffffffffffffffXfXfXXX XXQXXX XXQXXX XXXXX
QQQ mQmQmQ mmm
QQQ mQmQmQ mmm
Qm Qm
mQmQmQQQmmmQmQmQQQ
m
mmmQQQ mmmQQQQQ
m
Q
mm
mm Q
mmm mmQmQ
CC {
CC {
CC {
CC {
C{C{
{C{CC
{C{CC
{C{CC
{
{
{
{
{
{
{{ C
→ worst case Zeitkomplexität
1+
lnm
N
∗ (1 + log N )
CRCW-PRAM
gemeinsames Schreiben der Endsignale in globalen Speicher.
→ worst case Zeitkomplexität
lnm
∗ (1 + 1)
1+
N
Elementare PRAM-Algorithmen
• Broadcast / Reduktion
– → ⌈log p⌉ Schritte für p Prozessoren
Reduktion von n Werten mit assoziativen binären Operationen auf
Θ (log n) Schritten
n
2
Prozessoren mit
• Präfixsummen (Scans) – für n Werte in ⌈log n⌉ parallelen Schritten (n − 1 Prozessoren)
51
KAPITEL 5. PARALLELE ALGORITHMEN
5.1. DAS PRAM- RECHNERMODELL
Gegeben: n Werte a0 , . . . , an−1 und assoziative Operation ⊕
a0
a0
Bestimme n Werte: a0
⊕
⊕
a1
a1
..
.
⊕
a2
a0
⊕
a1
⊕
a2
⊕
···
⊕
an−1
CREW-Verfahren:
• globale Variablen: n, A [0 . . . (n − 1)] , j
• Anfangsbedingung: A [0 . . . (n − 1)] enthält Eingabeliste
• Endbedingung: A [i] enthalte a0 ⊕ . . . ⊕ ai
1
2
3
4
5
6
7
8
9
10
begin
spawn(P1 , . . . , Pn−1 )
for all Pi where 1 ≤ i ≤ n − 1 do
for j=0 to ⌈log n⌉ − 1 do
``
´
´
if
i − 2j ≥ 0 then
ˆ
˜
A [i] ← A [i] ⊕ A i − 2j
fi
od
od
end
Beispiel:
A
0
P1
P2
P3
P4
P5
P6
1
2
3
4
5
6
0 EE
4 EE
2 EE
6 EE
5
1 EE
EE
EE
EE
EE
EE
BB
EE
BB
EE
EE
EE
EE
j=0
EE
BB ²
EE ²
EE ²
EE ²
EE ²
¹
" ²
!
"
"
"
"
11
3 QQQQ 4 RRRR 1 RRRR 4 RRRR 6 RRRR 8
RRR
RRR
QQQ
RRR
RRR
Q
R
R
R
R
Q
R
R
RR
RR
QQQ
R
R
j=1
QQQ ² RRRRR ² RRRRR ² RRRRR ² RRRRR ²
¹
Q(
R(
R(
(
(
3 XXXXXXX4XXXXXXXX4X XXXXXXX8X
12
17
7
XXXXX XXXXXX XXXXXX
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
j=2
XXXXX
XXXXXXXXXXXX² XXXXXXXXXX² XXX
¹
XXX,
XXX,
XXX, ²
3 BB
Schritt 1
Schritt 2
Schritt 3
3
4
4
8
10
16
21
Kosten: n − 1 Prozessoren, Θ (log n) Schritte
Definition: Ein paralleler Algorithmus heißt kostenoptimal, wenn seine Kosten (#Proz. * parallele Laufzeit)
in derselben Komplexitätsklasse liegen wie ein optimaler sequenzieller Algorithmus.
Analyse der elementaren Verfahren
• Reduktion
– parallele Kosten: Θ (n log n) (nicht optimal!)
52
KAPITEL 5. PARALLELE ALGORITHMEN
5.1. DAS PRAM- RECHNERMODELL
– optimaler sequenzieller Algorithmus: Θ(n)
– Anzahl der Operationen:
P n
Plog(n−1) i
−i =
par. Algorithmus: log
2 =n−1
i=1 n · 2
i=0
seq. Algorithmus: n − 1
• Präfixsummen
– par. Kosten Θ (n · log n) (nicht optimal)
opt. seq. Alg. Θ (n)
– Anzahl der Operationen
¢
P⌈log n⌉−1 ¡
n − 2i · 1 = . . . = Θ (n log n)
par. Alg.: i=0
seq. Alg.: n − 1
Satz 1.2 (B RENT 1974): Sei A ein paralleler Algorithmus mit Ausführungszeit t. Falls A m-Operationen
ausführt, so kann A mit p-Prozessoren in der Zeit t + (m−t)
ausgeführt werden.
p
Beweis Satz
Pt 1.2. Sei si die Anzahl der Operationen die im i-ten Schritt ausgeführt werden, 1 ≤ i ≤ t.
Es gilt: i=1 si = m
l m
Mit nur p Prozessoren kann der i-te Schritt von A in
Anzahl der Schritte mit p Prozessoren:
t » ¼
X
si
i=1
p
≤
t
X
si + p − 1
i=1
p
si
p
=t+
Schritten simuliert werden. Damit folgt für die
t
X
si − 1
i=1
p
=t+
m−t
p
• Um ein kostenoptimales Verhalten zur parallelen Reduktion zu bestimmen, kann man versuchen, die
Anzahl Prozessoren zu reduzieren.
n−1
• Um n − 1 Operationen in log n Schritten kostenoptimal auszuführen, sollten nur p = log
n =
´
³
Θ logn n Prozessoren eingesetzt werden. Mit Brents Theorem folgt, dass sich die parallele Laufzeit
wie folgt erhöht:
µ
¶
n − 1 − ⌈log n⌉
log n log2 n
k
j
⌈log n⌉ +
= Θ log n + log n −
−
= Θ (log n)
n
n
n
log n
=⇒
Die Komplexitätsklasse des parallelen Algorithmus wird durch
j die
k Reduktion der Pron
zessorzahl nicht verändert, d. h. die parallele Reduktion auf log n Prozesse ist kostenoptimal.
• Zur Herleitung eines kostenoptimalen Algorithmus für die Präfixsummenberechnung genügt es kaum,
die Anzahl der Prozessoren zu reduzieren. Besser ist es den Berechnungen der Prozessoren auf den
ihnen zugeordneten Datenseqmenten das optimale sequenzielle Verfahren einzusetzen.
• Berechnung der Präfixsummen von n Werten mit p < n − 1 Prozessoren
53
KAPITEL 5. PARALLELE ALGORITHMEN
5.2. RECHNERMODELLE MIT VERTEILTEM SPEICHER
– Aufteilung der n Werte in p Teilbereiche mit max
l m
n
p
Werten
– Die p Prozessoren rechnen mit dem optimalen sequenziellen Verfahren die Präfixsummen auf
ihrenlTeilbereichen
m
−→ np − 1 Schritte
– Die ersten p−1 Prozessoren berechnen die Präfixsummen der Gesamtsummen ihrer Teilbereiche
mit dem parallelen Verfahren:
−→ ⌈log (p − 1)⌉ Schritte.
– Die letzten p − 1 Prozessoren addieren die Gesamtsummen der niedrigeren Blöcke auf alle
Elemente
l m ihrer Teilbereiche:
−→ np Additionen
l m
´
l m
³
Gesamtaufwand: np − 1 + ⌈log (p − 1)⌉ + np = Θ np + log p
Beispiel: n = 14, ⌈log n⌉ = 4, p = 4
A
2
1
4
−3
0
−2
5
1
−1
2
4
0
3
7
Schritt(iii)
2
3
7
0
−2
3
1
5
10
3
7
4
2
7
7
9
13
5
9
13
13
3
2
4
8
8
8
−1
(iv)
4
4
4
4
16
23
Gesamtzahl der Operationen:
µ» ¼
¶
» ¼
n
n
p·
− 1 + Θ (p log p) + (p − 1) ·
= Θ (n + p log p)
p
p
³
³
´
dann folgt der Gesamtaufwand: Θ nn + log logn n = Θ (log n)
log n
´
³
=⇒ Kosten: Θ logn n · Θ (log n) = Θ (n)
=⇒ Kostenoptimalität
´
³
Gesamtzahl der Operationen: Θ n + logn n log logn n = Θ (n)
Sei: p = Θ
n
log n
´
5.2 Rechnermodelle mit verteiltem Speicher
• bestimmendes Element: Verbindungsnetzwerk
– feste Knoten-zu-Knoten-Verbindungen
• Bewertungskriterien:
– Durchmesser , längster Abstand zwischen zwei Knoten
54
KAPITEL 5. PARALLELE ALGORITHMEN
5.2. RECHNERMODELLE MIT VERTEILTEM SPEICHER
– Halbierungsbreite , minimale Anzahl von Verbindungslinien, die durchtrennt werden, um das
Netzwerk in zwei etwa gleichgroße Teile zu zerlegen.
– Verbindungsgrad , Anzahl der Verbindungen pro Knoten
Beispiel:
• Gitter mit q Dim. und k Knoten pro Dim. −→ k q Knoten
Durchmesser: (k − 1) ∗ q
Halbierungsbreite: k (q−1)
Verbindungsgrad: 2q
• Torus , Gitter mit zyklischen Verbindungen in allen Dimensionen
¥ ¦
Durchmesser: q ∗ k2
Halbierungsbreite: 2 ∗ k (q−1)
Verbindungsgrad: 2q
• Binärbaum der Tiefe k → 2k+1 − 1 Knoten
Durchmesser: 2k
Halbierungsbreite: 1
Verbindungsgrad: 3
• Hypercube der Dimension k
Durchmesser: k
Halbierungsbreite: 2(k−1)
Verbindungsgrad: k
• Shuffle–Exchange–Netzwerk
2k Knoten mit Nummerierung von 0 bis 2k−1 , zwei verschiedene Verbindungen:
Exchange-Verbindung: (bk−1 . . . b1 0)2 ↔ (bk−1 . . . b1 1)2
Shuffle-Verbindung: (bk−1 bk−2 . . . b0 )2 → (bk−2 . . . b0 bk−1 )2
Beispiel: Shuffle–Exchange–Netzwerk
•o
´
/•l
(
•o
/•k
+•o
/•h
,•o
´
/•
000
001
010
011
100
101
110
111
/ • 000
000 •
001 • YYYYYYYYYY pp8 • 001
YYpYpYY
010 • TTTTT ppppp , • 010
TTp
011 • NNpNpppp TTTTTjTjTjj5 • 011
p
p NN
jj TT)
100 • jjNjNjNjNjNj
• 100
NNN
jjj
2
e
N
e
101 •
•
e
eeeee NNN& 101
eeeeee
e
110 •
• 110
/
111 •
• 111
55
KAPITEL 5. PARALLELE ALGORITHMEN
5.3. PARALLELES SORTIEREN
Shuffle-Exchange-Reduktion
000
010
001
011
100
101
110
111
• Basisidee: Reduktion von zwei Zwischenergebnissen pro Schritt −→ log viele Schritte
Zu kombinierende Werte werden in aufeinander folgende Shuffle-Exchange-Schritten zusammengebracht.
• allgemeine Verfahren: Parameter in #Prozessorelementen n = 2k
1
2
3
4
5
6
7
8
9
10
11
12
lokal val, tmp
begin
for j=0 to k-1 do
for all Pi where 0 ≤ i < n do
send val to Pi
receive val from Pi
send val to P<i>
receive tmp from P<i>
val := val + tmp
od
od
end
//shuffle
//shuffle
//exchange
//exchange
Beispiel:
6
−4
6−9
1.Schritt
2.Schritt
3.Schritt
−3
6
26
2
19
−9
0
7
5
−4
6
26
9
20
26
9
20
26
24
20
26
24
20
26
−4 − 0
−3
6
26
−4
6
26
5.3 Paralleles Sortieren
im sequentiellen Fall: Aufwand Ω (n log n) bei vergleichsbasierten Verfahren.
Ziel im parallelen Fall: poly. log. Aufwand mit binearer Proz.-Zahl.
5.3.1 Ein CRCW-Verfahren mit konstantem Zeitaufwand
n2 Proz. einer CRCW-PRAM können n Elemente in konstanter Zeit sortieren, falls
• der Aktivierungsaufwand (O (log n)) vernachlässigt werden kann und
• beim CW die Summe der Werte geschrieben wird
Ansatz: „Ranksort“
56
KAPITEL 5. PARALLELE ALGORITHMEN
5.3. PARALLELES SORTIEREN
Vergleiche jedes Element mit jedem anderen und zähle die Anzahl der kleineren Elemente
−→ Position in sortierter Liste
Algorithmus: Parameter n = # zu sortierende Elemente
Globale Vars:
a [0 . . . (n − 1)]
position [0 . . . (n − 1)]
sorted [0 . . . (n − 1)]
zu sortierende Elemente
Position der Elemente in sortierter Liste
Listing 16 „Ranksort“
1
2
3
4
5
6
7
8
begin
spawn Pi,j with 0 ≤ i, j < n
for all Pi,j with 0 ≤ i, j < n do
position\left[i\right]:=0
if a [i] > a [j] or (a [i] = a [j] and i > j)
then position\left[i\right]:=1 fi
od
for all Pi,0 with 0 ≤ i < n do sorted[position[i]]:=a[i]
par. Zeit O (1)¡ ¢
par. Kosten O n2
−→ nicht kostenoptimal
5.3.2 Sortiernetze
BATCHER 1968: Netze zum Sortieren in polylogarithmischer Zeit
hier: odd-even-merge-sort
Beispiel: klassische sequentielle Verfahren zum Mischen sortierter Listen mit i bzw. j Elementen im worst case: i + j − 1
Beobachtung: Welche Elemente verglichen werden, hängt von vorherigen Vergleichen ab.
−→ wissenabhängige Verfahren (non-oblivious)
im folgenden: festes Vergleichsschema
−→ wissensunabhängige Verfahren (oblivious)
Beispiel: Tunierschema beim Tennis
Sieger
Sieger
Ein Komparator erhält zwei Eingaben und produziert zwei Ausgaben, das Minimum und das Maximum der
beiden Eingaben:
57
KAPITEL 5. PARALLELE ALGORITHMEN
5.3. PARALLELES SORTIEREN
a
b
+
min(a, b)
max(a, b)
Im folgenden nehmen wir an, dass gleichlange Folgen der Länge n = 2k zu Mischen sind.
¡
¢
Induktive Konstruktion eines (n, n)-Mergers n = 2k
(−→ odd-even-merger)
Gegeben seien zwei sortierte Folgen:
A = (a1 , . . . , an )
B = (b1 , . . . , bn )
n = 1: Komparator ist (1, 1)-Merger.
n = 2:
a1
min
c1
a2
max
c2
b1
min
c3
b2
max
c4
beliebiges n > 1
Voraussetzung: Es stehen
x
¡n
n
2, 2
¢
-Merger zur Verfügung.
Notation: [k]
l bezeichne die Teilliste von Xi die mit dem k-ten Folgenglied beginnt und jedes l-te nachfolgende Glied wählt < Xk+i∗l | i ≥ 0 >
A[1] B[1]
2 , 2
Teillisten der Elemente mit ungeradem Index.
Satz 5.1.: Die Resultatfolge C ist sortiert.
58
KAPITEL 5. PARALLELE ALGORITHMEN
5.3. PARALLELES SORTIEREN
Beispiel: (4, 4)-Merger
(2,2)-Merger
1
5
6
2
3
7
8
4
5
1
2
6
7
3
4
8
(2,2)-Merger
Es werden Folgen D und E hergestellt, die so ineinander geschoben werden (interleaving), dass die resultierende Folge bis auf eventuelle Nachbarvertauschungen sortiert ist.
Interleaving-Schema
d1
d2 OOO
d3 OOO
d4 PPP. . . . . . dn TTTT
TTTT
OOO
OOO
PPP
TT)
OO'
OO'
PP'
...
en−1
e1
e2
e3 . . .
en
/
d1
d2 e1
d3 e2
d4 e3
. . . . . . dn en−1
en
Satz 5.2. (0-1-Prinzip): Ein Sortieralgorithmus bestehe nur aus vorherbestimmten, d. h. eingabeunabhängigen Vergleichen-Austausch-Anweisungen. Dann gilt: Sortiert der Algorithmus jede Eingabefolge, die nur
aus Nullen und Einsen besteht, so sortiert er jede Eingabefolge.
Beweis von Satz 5.2 durch Widerspruch:
Annahme: Die Eingabefolge X1 , . . . , Xn wird von dem wissensunabhängigen Sortierverfahren
nicht korrekt sortiert, d. h. nicht in die Reihenfolge
Xπ(1) ≤ Xπ(2) ≤ . . . ≤ Xπ(n)
gebracht.
59
KAPITEL 5. PARALLELE ALGORITHMEN
5.3. PARALLELES SORTIEREN
• Sei k die erste Stelle, an der sich die sortierte Folge von der Ausgabe des Algorithmus
Xσ(1) , . . . , Xσ(n)
unterscheidet d. h. Xσ(k) > Xπ(k)
Definiere zu X1 , . . . , Xn und k eine 0-1-Folge
½
0, f alls xi ≤ xπ(k)
yi :=
1, f alls xi > xπ(k)
Wird diese Folge dem wissensunabhängigem Sortieralgorithmus übergeben, so finden die gleichen Vergleichs-/ Austauschschritte statt, denn Xi ≥ Xj y Yi ≥ Yj . Insbesondere steht an der k-ten Stelle der
Ausgabefolge yσ(k) = 1 und irgendwo rechts daneben der Wert yπ(k) = 0. Die 0-1-Folge wird nicht richtig
sortiert. (W IDERSPRUCH)
Beweis von Satz 5.1. mit dem 0-1-Prinzip. A und B seien sortierte 0-1-Folgen. Sei ak die letzte Null der
Folge A und bl die letzte Null der Folge B, d. h.
0 1 . . . 1)
A = (0 . . . |{z}
0 1 . . . 1) B = (0 . . . |{z}
l
k
Es gilt: 0 ≤
k
|{z}
,l≤
nur Einsen
n
|{z}
nur N ullen
Dann gilt für die Teilfolgen
§k¨
§l¨
A[1]
B[1]
2 hat 2 Nullen, 2 entsprechend 2
¥k¦
¥l¦
B[2]
A[2]
2 hat 2 Nullen, 2 entsprechend 2
§ ¨ § ¨
Damit hat die Folge D γ := k2 + 2l Nullen
¥ ¦ ¥ ¦
und die Folge E δ := k2 + 2l Nullen
Für die Differenz ∆ := γ − δ gilt nach Definition der Gaußklammern:


1
2
0
z
}|
{ z
}|
{ z
}|
{
∆ ∈ beide gerade, eins gerade eins ungerade, beide ungerade


Wir betrachten die Interleaving-Schemata für diese 3 Fälle:
∆=2
D
...
0
0
E
...
...
...
0
...
0
0
\
60
1
\
0
0
0
...
...
1
1
...
...
\
1
1
1
KAPITEL 5. PARALLELE ALGORITHMEN
5.3. PARALLELES SORTIEREN
∆=1
D
...
0
0
0
\
E
...
...
...
0
...
0
...
0
0
1
...
\
0
0
0
0
0
...
...
1
...
...
\
1
1
0
∆=0
D
0
\
E
...
...
...
0
...
0
1
\
0
0
0
1
\
0
0
0
...
...
\
0
0
1
1
1
...
1 ...
Aufbau eines Sortiernetzes aus (n, n)-Merger
O.B.d.A. n = 2k
Durchlaufzeit: (Zahl vertikaler Komparatorstufen) t(n) =
(n, n)-Mergers sei.
Komparatorzahl: N (n) =
k
X
Pk
i
i=0 τ (2 ),
wobei τ (n) die Durchlaufzeit eines
2k−i ∗ ν(2i ), wobei ν(n) die Komparatoranzahl eines (n, n)-Mergers sei.
i=0
Bestimme τ (n) und ν(n) durch Analyse der (n, n)-Merger:
τ (1) = 1;
ν(1) = 1
τ (2n) = τ (n) + 1; ν(2n) = 2ν(n) + n − 1
Mit vollst. Induktion zeigt man leicht:
τ (n) = 1 + log n; ν(n) = 1 + n · log n
Damit folgt:
t(n) =
k
X
(1 + i) =
(k+1)(k+2)
2
∈ O(k 2 ) = O(log2 n)
i=0
k
X
∈ O(n log2 n)
2k−i (1 + i ∗ 2i ) = . . . = 2k+1 − 1 + 2k k(k+1)
2
N (n) =
i=0
=⇒ parallele Kosten: O(n log4 n)
61
KAPITEL 5. PARALLELE ALGORITHMEN
5.3. PARALLELES SORTIEREN
5.3.3 Der Algorithmus von Cole
optimale Lösung auf CREW-PRAM, d. h. O(log n) Zeit mit O(n) Prozessoren.
„paralleler Mergesort im vollständigem Binärbaum“
Hilfsmittel: Skelette von Folgen
Definition. 5.3.: X und Y seien sortierte endliche Folgen ganzer Zahlen. [X] entstehe aus X durch Hinzunahme der Elemente −∞ und +∞.
(a)
Seien a < b und x ∈ X.
x heißt zwischen a und b:y a < x ≤ b
(b)
X heißt Skelett von Y , in Zeichen X ∝ Y , falls für alle k ≥ 2 zwischen je k Elementen von
[X] höchstens 2k − 1 Elemente von Y liegen.
• X gemeinsames Skelett von Y und Z
Y
X∝
Z
Notation:
• X&Y sei die Verschmelzung.
(merge) von X und Y
Beispiel: Skelette von Folgen
Y
= (1, 4, 6, 9, 11, 12, 13, 16, 19, 20)
X = (5, 10, 12, 17)
Z = (2, 3, 7, 8, 10, 14, 15, 17, 18, 21)
k = 2: Zwischen je zwei Elementen von X liegen
−→ 2 ≤ 2k − 1 = 3 Elemente von Y
−→ maximal 3 Elemente von Z
k = 3: Zwischen je drei Elementen von X liegen
−→ 4 ≤ 2k − 1 = 5 Elemente von Y
−→ maximal 5 Elemente von Z
k = 4: Zwischen je zwei Elementen von X liegen
−→ 6 ≤ 2k − 1 = 7 Elemente von Y
−→ maximal 6 Elemente von Z
k = 5, 6 analog
Listen dürfen maximal 11 Elemente haben
=⇒ X ∝
62
Y
Z
KAPITEL 5. PARALLELE ALGORITHMEN
5.3. PARALLELES SORTIEREN
Haben zwei Folgen ein gemeinsames Skelett, so kann eine vereinfachte Mischung, das sog. Skelett-Merging,
durchgeführt werden. Die beiden Folgen werden anhand des gemeinsamen Skelettes in Teilfolgen zerlegt,
die in konstanter Zeit O(1) gemischt werden können.
Lemma 5.4: Sei X, Y, Z sortierte endliche Folgen mit X ∝
Y
Z
Sei
Y (i) := (y ∈ Y : xi−1 < y ≤ xi )
Z(i) := (z ∈ Z : xi−1 < z ≤ xi )
für
1 ≤ i ≤ |x| + 1
½
x0
:= −∞
x|x|+1 :=
∞
Dann gilt:
Y &Z = Y (1) &Z (1) , Y (2) &Z (2) , . . . , Y (|X| + 1) &Z (|X| + 1)
Beispiel:
−∞
Y (1) = 1, 4
Z(1) = 2, 3
¾
1, 2, 3, 4
5
Y (2) =
6, 9
Z(2) = 7, 8, 10
10
Y (3) = 11, 12
Z(3) =
¾
¾
11, 12
12
Y (4) =
13, 16
Z(4) = 14, 15, 17
17
Y (5) = 19, 20
Z(5) = 18, 21
¾
6, 7, 8, 9, 10
¾
13, 14, 15, 16, 17
18, 19, 20, 21
∞
X heißt Skelett von Y , in Zeichen X ∝ Y , falls für alle k ≥ 2 gilt:
Zwischen je k Elementen von X liegen höchstens 2k − 1 Elemente von Y .
Grundidee des Algorithmus von Cole
• Verschmelzung von Folgen mit gemeinsamen Skelett mit konstantem Aufwand.
• Zu sortierende Liste ist zu Beginn auf Blattknoten eines vollst. Binärbaums verteilt.
• die Verschmelzung von Teillisten erfolgt in mehreren Baumebenen fließbandartig gleichzeitig.
Bezeichnungen: Gegeben sei der vollständige Binärbaum mit n = 2k Blättern
63
KAPITEL 5. PARALLELE ALGORITHMEN
5.3. PARALLELES SORTIEREN
T (v)
sei der Unterbaum mit Wurzel v.
val(v)
sei die momentane Folge des Knotens v.
list(v)
sei die sortierte Folge, die aus den Werten der Blätter in T (v) entsteht.
Es gilt: val(v) ist stets geordnete Teilfolge von list(v).
Ein Knoten v heißt vollständig, falls val(v) = list(v); sonst unvollständig (|val (v)| < |list (v)|).
Algorithmus von Cole:
Sei n = 2k die Anzahl der zu sortierenden Werte, die 1 : 1 den Blättern des vollständigen
Binärbaums zugeordnet werden.
Arbeitsweise eines beliebigen inneren Knotens v:
Zu Beginn ist val(v) leer. Der Knoten v wird aktiv, wenn vom linken Kind eine Folge X1 der
Länge 1 und vom rechten Kind eine Folge Y1 der Länge 1 erhält, die er zu einer Folge val(v)
der Länge 2 verschmilzt. In jedem weiteren Schritt j erhält der Knoten von seinen beiden KindX
Yj[1]
knoten Folgen Xj und Yj , so dass Xj−1 = j[1]
2 , Yj−1 = 2 , Xj und Yj werden zu val(v)
verschmolzen. In jedem Schritt wird die Länge von val(v) verdoppelt, bis list(v) erreicht wird
−→ Knoten v wird vollständig.
Ausgabevorschriften
1. Ist v unvollständig und val(v) ≥ 4, so sendet v die Folge
val(v)[1]
4
= z an den Elternknoten.
2. Ist v vollständig, so bleibt v noch zwei Schritte aktiv.
list(v)[1]
und im letzten Schritt list(v).
Im vorletzten Schritt sendet v
2
Danach wird der Knoten inaktiv.
Abbildung 5.2: Beispiel: 16 Zahlen
Zahlenfolge: 34, 81, 74, 92, 14, 31, 13, 97, 28, 36, 30, 80
34
81
\ /
34,81
\
74
92
\ /
74,92
/
34,74
34,74,81,92
14
31
\ /
14,31
\
13
97
\ /
13,97
/
13,14
13,14,31,97
28
36
\ /
28,36
\
30
80
\ /
30,80
/
28,30
28,30,36,80
\
/
13,34
13,31,34,81
13,14,31,34,74,81,92,97
25
\ /
25,45
\
/
1,28
1,28,36,45
1,25,28,30,36,45,71,80
/
1,13
1,13,36,74
1,13,28,31,36,71,74,92
/
\
1, 13, 28, 31, 36, 71, 74, 92, 97
1
71
\ /
1,71
/
1,25
1,25,45,71
\
\
64
45
KAPITEL 5. PARALLELE ALGORITHMEN
5.3. PARALLELES SORTIEREN
Betrachte nun einen typischen Knoten, d. h. v mit |list(v)| > 4.
Xi , Yi seien die Eingaben des Knotens im i-ten Schritt und Zi sei die Ausgabe im (i + 1)-ten Schritt.
X1 = (28) Y1 = (1)
\ /
val1 (v) = (1, 28)
Schritt 1
|
∅
X2 = (28, 36) Y2 = (1, 45)
\
/
val2 (v) = (1, 28, 36, 45)
Schritt 2
|
Z = (1)
X3 = (28, 30, 36, 80) Y3 = (1, 25, 45, 71)
\
/
val3 (v) = (1, 25, 28, 30, 36, 45, 71, 80)
Schritt 3
|
Z2 = (1, 36)
Schritt 4 vorletzter Schritt Z3 = (1, 28, 36, 71)
Schritt 5 Z4 = (1, 25, 28, 30, 36, 45, 71, 80) y v wird inaktiv.
Invariante des Algorithmus von Cole
Satz 5.5.: Sei v ein Knoten mit |list(v)| ≥ 4. Seien Xi+1 , Yi+1 die Eingaben und Zi die Ausgabefolge von v in
seinem (i + 1)-ten Schritt Dann gilt für alle i ∈ N:
Xi+1 ∝ Xi+2 ∧ Yi+1 ∝ Yi+2 y Zi ∝ Zi+1
Lemma 5.6.: X ∝ X ′ ∧ Y ∝ Y ′ y
X&Y
4
∝
X ′ &Y ′
4
Beweisgang. Gelte X ∝ X ′ , Y ∝ Y ′
Zeige
(a)
(b)
X&Y ∝ X ′ , X&Y ∝ Y ′
Im allgemeinen gilt nicht: X&Y ∝ X ′ &Y ′
Jedoch liegen zwischen je k aufeinander folgenden Elementen von X&Y höchstens 2k + 2
Elementen. von X ′ &Y ′
Beweis von Satz 5.5. Sei |list(v)| = 2j−1 j = 3, 4, . . ., d. h. Knoten v ist nach seinem (j − 1)-ten Schritt vollständig.
Mit der Ausgabevorschrift 1 erhält man mit Lemma 5.6 für alle i mit 1 ≤ i < j − 2:
Zi =
val(v)[1]
Xi+1 &Yi+1
Xi+2 &Yi+2
=
∝
= Zi+1
4
4
4
65
KAPITEL 5. PARALLELE ALGORITHMEN
5.3. PARALLELES SORTIEREN
Sobald v vollständig, tritt die Ausgabevorschrift (2) in Kraft und es gilt:
Zj−1
=
Zj
=
list(v)
list(v)
∝
= Zj
4
2
list(v)
∝ list(v) = Zj+1
2
Für die Eingabefolge Xi+1 und Yi+1 steht stets ein gemeinsames Skelett Xi &Yi bereit.
zeitlicher Ablauf:
K
Xi+1
ZiK
¡
K
Yi+1
¢ ↓werden immer parallelgeschickt
seien Eingabefolgen 
eines Knotens des Levels K im

sei Ausgabefolge
Baum in seinem (i + 1)-ten aktiven
Schritt
Abbildung 5.3: Zeitlicher Ablaufplan
Phase
gesendete Folgen
1
Z1Blatt → X1A /1
——————————————————————————————————————–
2
Z1A → X1B /1
3
Z2A → X2B /2
——————————————————————————————————————–
4
Z1B → X1C /1
5
Z2B → X2C /2
6
Z3B → X3C /4 Z1C → X1D /1
——————————————————————————————————————–
7
Z2C → X2D /2
8
Z3C → X3D /4 Z1D → X1E /1
——————————————————————————————————————–
9
Z4C → X4D /8 Z2D → X2E /2
Beobachtung:
• Wird Knoten v im Schritt i inaktiv, so wird der Elternknoten im Schritt i + 3 inaktiv y Laufzeit:
t(n)
=
3 log n
= O(log n)
• Prozessoren: O(n)
⇒ Kostenoptimalität: O(n log n)
66
KAPITEL 5. PARALLELE ALGORITHMEN
5.4. GRAPHEN ALGORITHMEN
5.4 Graphen Algorithmen
Definition 5.7.: Ein endlicher Graph G = (V, E) besteht aus einer endlichen Menge von Knoten V (vertex) und einer
endlichen Menge von Kanten E (edges), E ⊆ V × V
Definition 5.8.: Sei G = (V, E) mit V = {v0 , . . . , vn−1 }. Die Einträge aij , 0 ≤ i, j ≤ n−1 der n×n Adjazenzmatrix
zu G sind definiert durch
½
1, f alls (vi , vj ) ∈ E
aij =
0, sonst
Definition 5.9.:
a)
Ein Graph G = (V, E) heißt ungerichtet, falls zu jedem (v, v ′ ) ∈ E auch (v ′ , v) ∈ E, ansonsten gerichtet.
b)
G heißt gewichtet, falls jeder Kante mittels einer Gewichtsfunktion w : E → R+ eine nicht negative
reelle Zahl zugeordnet ist. w kann zu w̃ : V × V → R+
0 ∪ {∞} ergänzt werden.
½
w(vi , vj ), f alls (vi , vj ) ∈ E
w̃(vi , vj ) :=
∞,
sonst
Definition 5.10.:
a)
Eine Folge von Kanten (vi1 , vi2 )(vi2 , vi3 ), . . . , (vik , vik+1 ) heißt Pfad, falls alle Knoten vi1 , . . . , vik+1 der
Folge voneinander verschieden sind.
b)
Eine Kantenfolge (vi1 , vi2 )(vi2 , vi3 ), . . . , (vik−1 , vik ), (vik , vi1 ) heißt Zykel, falls alle Knoten vi1 , . . . , vik
paarweise verschieden sind.
c)
Eine Kantenfolge (vi1 , vi2 ), . . . , (vik , vik+1 ) heißt Weg, falls alle Kanten voneinander verschieden sind.
Ein Graph ohne Zykel heißt azyklisch.
Definition 5.11.: Ein Graph (V ′ , E ′ ) heißt Subgraph von G = (V, E), falls V ′ ⊆ V und E ′ ⊆ E
Definition 5.12.: Ein ungerichteter Graph heißt zusammenhängend, falls zu jedem Paar vi und vj in G ein Pfad von
vi nach vj existiert.
5.4.1 Bestimmung der Zusammenhangskomponenten eines Graphen
Zusammenhangskomponenten: minimale Menge von zusammenhängenden Subgraphen
Definition 5.13.: Sei G = (V, E) mit V = {v0 , . . . , vn−1 } die n × n Zusammenhangsmatrix: C = (cij )0≤i,j≤n−1
wird definiert durch:

1 , falls vi und vj durch



einen Weg der
cij =
Länge ≥ 0 verbunden sind



0 , sonst
67
KAPITEL 5. PARALLELE ALGORITHMEN
5.4. GRAPHEN ALGORITHMEN
Abbildung 5.4: Beispiel – Zusammenhangskomponenten
0
1
0
0
0
0
0
0
1
1
0
1
2
3
4
5
6
7
8
1
0
1
1
0
1
1
1
0
0
2
0
1
1
0
1
1
1
0
0
3
0
0
0
1
0
0
0
0
0
4
0
1
1
0
1
1
1
0
0
5
0
1
1
0
1
1
1
0
0
6
0
1
1
0
1
1
1
0
0
7
1
0
0
0
0
0
0
1
1
8
1
0
0
0
0
0
0
1
1
C ergibt sich aus reflexivem, transitivem Abschluss der Adjazenzmatrix unter der boolschen Matrixmultiplikation, bei
der als Multiplikation „∧“ und als Addition „∨“ verwendet wird.
Statt dij =
n−1
X
aik bkj wird demnach dij =
n−1
_
(aik ∧ bkj ) berechnet.
k=0
k=0
Anstelle der Adjazenzmatrix wird die auf der Diagonalen modifizierte Matrix B verwendet.
B
=
mit
bij
=
(bij )0≤i,j≤n−1
½
aij ,
1,
f alls
f alls
i 6= j
i=j

1,



falls es einen Weg von
vi nach vj der
Länge ≤ k gibt
sonst
←− reflexiver Abschluss
Für die Einträge von B k gilt
bij
=



0,
Satz 5.14.: Für die Zusammenhangsmatrix C gilt: C = B n−1 wobei n die Anzahl der Knoten bezeichnet.
68
KAPITEL 5. PARALLELE ALGORITHMEN
5.4. GRAPHEN ALGORITHMEN
Beweis Satz 5.14.: Falls zwei Knoten vi und vj überhaupt durch einen Weg verbunden sind, so existiert auch ein Weg
der Länge ≤ n−1. Würde es nur Wege der Länge > n−1 geben, so würde mindestens 1 Knoten mehrfach vorkommen
und der Weg enthielte einen Zyklus, der entfernt werden könnte.
Sei O.B.d.A (n − 1) Zweierpotenz
=⇒ log(n − 1) Boolsche Matrixmultiplikationen (sukzessives Quadrieren). Wird die Matrixmultiplikation auf einem
Hypercube mit n3 Prozessen durchgeführt, läge der Gesamtaufwand bei O(log n) parallelen Schritten.
5.4.1.1 Algorithmus von Hirschberg (1976)
Grundidee: Zusammenfassen von verbundenen Knoten zu Superknoten, bis jeder Superknoten einer Zusammenhangskomponente entspricht.
¡
¢
¡ ¢
Komplexität: O log2 (n) mit O n2 Prozessoren mit n = #Graphknoten
Eingabe: Adjazenzmatrix eines ungerichteten Graphen G = (V, E) mit V = {1, . . . , n}
Ausgabe: Vektor C der Länge n, so dass C (i) = C (j) = k, falls i und j in der selben Zusammenhangskomponente
liegen und k der „kleinste“ Knoten in dieser Zusammenhangskomponente ist.
Abbildung 5.5: Beispiel
Ziel:
i
C(i)
1
1
2
1
3
3
4
1
5
1
6
1
7
1
8
1
Berechnung:
i
Initial C(i)
T (i)
1
1
8
2
2
6
3
3
3
4
4
6
5
5
7
6
6
2
7
7
2
8
8
1
nach Phase 3:
1 2 3 4
1 2 3 2
5
2
6
2
7
2
8
1
i
T (i)
Der Algorithmus arbeitet in 3 Phasen, die ⌈log n⌉ mal iteriert werden.
1. Finde zu jedem Knoten den benachbarten Superknoten mit kleinstem Index.
2. Verbinde die Wurzel jedes Superknotens mit der Wurzel des benachbarten Superknotens mit kleinstem Index.
Die Wurzel eines Superknotens ist der Knoten mit der kleinsten Nummer.
3. Alle neu verbundenen Superknoten werden zu einem neuen Superknoten zusammengefasst.
Pseudocode: Initialisierung des C-Vektors: C(i) := i (1 ≤ i ≤ n) =⇒ Superknoten der Größe 1.
zu Phase 1:
69
KAPITEL 5. PARALLELE ALGORITHMEN
5.4. GRAPHEN ALGORITHMEN
1
2
3
4
for all vertices i in parallel do
T(i):= minj {C(j)|A(i,j)=1, C(j)6=C(i)}
(falls diese Menge leer ist
wird C(i) in T(i) gespeichert)
zu Phase 2:
1
2
3
4
5
6
for all vertices i in parallel do
T(i):= minj {T(j)|C(j)=i, T(j)6=T(i)}
(wie oben)
# "Finde aus allen benachbarten
# Superknoten denjenigen mit
# kleinstem Index"
Abbildung 5.6: T-Graph
zu Phase 3:
1
2
3
4
5
6
7
for all vertices i in parallel do
B(i)←T(i) (1 ≤ i ≤ n) # "Umspeichern in Hilfsvektor B"
repeat log(n) times
for all vertices i in parallel do
T(i)←T(T(i))
# "Setze T (i) ← T n (i)"
for all vertices i in parallel do
C(i)←min{(B(T(i)),T(i)}
Bestimmung von Zusammenhangskomponenten
Adjazenzmatrix A Hirschberg Vektor C mit C(i) = Index der Zusammenhangskomponenten mit i V = {1, . . . , n}
−−−−−−−−→
Index einer Zusammenhangskomponente = Nummer des „kleinsten“ enthaltenen Knotens
Algorithmus: ⌈log n⌉ Iterationen der folgenden 3 Phasen
Phase 1:
1
2
for all vertices i in parallel do

minj {C(j)|A(i, j) = 1, C(j) 6= C(i)}
T (i) :=
C(i)
f alls existent
sonst
Detaillierung: Sei ∞ eine Zahl > n.
1
2
3
4
5
6
7
8
9
10
70
(a) for all i,j, 1 ≤ i, j ≤ n in parallel do
if A(i, j) = 1 and C(i) 6= C(j)
then T emp(i, j) :=C(j)
else T emp(i, j) := ∞
(b) for all i, 1 ≤ i ≤ n in parallel do
T emp(i, 1) := minj T emp(i, j)
(c) for all i, 1 ≤ i ≤ n in parallel do
if T emp(i, j) 6= ∞
then T (i) :=Temp(i,1)
else T (i) :=C(i)
KAPITEL 5. PARALLELE ALGORITHMEN
5.4. GRAPHEN ALGORITHMEN
Analyse:
(a)
(b)
(c)
O(1) mit O(n2 )Proz.
O(log n)mit O(n2 )Proz.
O(1) mit O(n)Proz.
Phase 2:
for all vertices i in parallel do

minj {T (j)|C(j) = i, T (j) 6= i}
T (i) :=
C(i)
1
2
f alls existent
sonst
„Verbinde Wurzel aller Superknoten mit Wurzel des Nachbar-Superknotens mit minimalem Index“
Detaillierung: analog zu Phase1 =⇒ Aufwand wie in Phase1
Beispiel:
i
1 2 3 4 5 6 7 8
C(i)
1 2 3 4 5 6 7 8
T(i)
8 6 3 6 7 2 2 1
nach Phasen 1 u. 2 der 1ten Iteration
Abbildung 5.7: T-Graph
Der T-Graph, der in Phase 2 gebildet wird, besitzt in jedem neu zu bildenden Superknoten genau eine Schleife aus 2
Kanten, wobei der kleinste Knoten des neuen Superknotens einer der beiden Schleifenknoten ist. Da jeder Superknoten
aus höchstens n Knoten besteht, kommt man beim Durchlaufen des T-Graphen nach n Schritten in die Schleife und
ist somit höchstens 1 Schritt vom Minimum entfernt.
Phase 3:
1
2
3
4
5
6
7
8
for all vertices i in parallel do
B (i) := T (i)
repeat} log n times
for all vertices i in parallel do
T (i) := T (T (i))
--setze T (i) := T n (i)
for all vertices i in parallel do
C (i) := min {T (i) , B (T (i))}
71
KAPITEL 5. PARALLELE ALGORITHMEN
5.4. GRAPHEN ALGORITHMEN
1
2
3
C(i)
1
1
1
1
1
2
2
2
2
2
3
3
3
3
3
4
2
2
2
2
5
2
2
2
2
6
6
6
6
2
7
6
6
6
2
8
8
8
8
1
Abbildung 5.8: C-Graph
Analyse der 3.Phase:
1. Anweisung O (1) mit O (n) Proz.
2. Anweisung O (log n) mit O (n) Proz.
3. Anweisung O (1) mit O (n) Proz.
y O (log n) mit O (n) Proz.
¡ ¢
Aufwand pro Iteration (3 Phasen) O (log n)mit O n2 Proz.
¡
¢
¡ ¢
⌈log n⌉-Iterationen y O log2 n mit O n2 Proz.
l 2 m
¡ 2 ¢
n
Mit Brents Theorem kann man zeigen, dass log
n Proz. ausreichen, um mit O log n - Schritten Zshgskomp zu
³ 2 ´
bestimmen. Es ist auch möglich mit O logn2 n Prozessoren. [C HIN ET AL 81/82]
5.4.2 Kürzeste Wege
Zu G = (V, E) mit |V | = n sei die Kostenmatrix W gegeben mit
wij
wii
:= w̃ (vi , vj ) ∈ R0+ ∪ {∞}
:= 0
Gesucht ist die minimale Kostenmatrix D, deren Einträge dij , 0 ≤ i, j ≤ n − 1 die minimalen Kosten (d. h. die
Summe der Gewichte) eines Weges von vi zu vj sind.
Die Einträge der Matrix Dk seien definiert durch dkij := minimale Kosten des Weges von vi nach vj höchstens der
Länge k
y D1 = W , Dn−1 = D Wege der Länge ≥ n können nicht kürzeste Wege sein, da Kosten immer ≥ 0.
O.B.d.A: n − 1 sei Zweierpotenz.
Es gilt für k > 1
n
o
min dkil + dklj
2k
dij =
l
72
KAPITEL 5. PARALLELE ALGORITHMEN
5.4. GRAPHEN ALGORITHMEN
=⇒ modifizierte Matrix-Multiplikation
Multiplikation −→ Addition
Addition −→ Minimumbestimmung
=⇒ Dn−1 kann nach log (n − 1) modifizierten Matrix-Multiplikation (sukzessive Quadrierung) bestimmt werden
¡
¢
Beispiel: auf n3 Proz. O log2 n (H YPERCUBE -M ATRIX -M ULTIPLIKATION)
5.4.3 Minimal spannende Bäume
Definition 5.15.: Ein Baum ist ein zusammenhängender, ungerichteter, azyklischer Graph.
Ein spannender Baum eines Graphen G ist ein Subgraph, der alle Knoten von G umfasst und ein Baum ist.
In einem gewichteten Graphen ist ein minimal spannender Baum (MST) ein spannender Baum mit der minimalen
Summe von Kantengewichten.
Abbildung 5.9: minimal spannender Baum
Falls |v| = n, so hat ein MST nach Def. n − 1 Kanten. Da jede der potentiellen n(n−1)
Kanten mindestens einmal
2
betrachtet
werden
muss,
ist
die
untere
Grenze
der
Laufzeit
eines
sequentiellen
Algorithmus
zur Bestimmung eines
¡ ¢
MST Ω n2
Tabelle 5.1: 3 Klassische sequentielle Verfahren
¡ ¢
Kruskal
1956
O ¡n2 ¢
Prim-Dijkstra 1957/59 O ¡n2
¢
Sollen
1977
O n2 log n
5.4.3.1 Algorithmus von Prim
Invariante: Alle Knoten vi außerhalb des momentanen Baumes Ti kennen den Knoten in Ti mit minimalem Abstand
zu ihnen. C (vi ) :=„nächster Nachbar von vi in Ti “
Bestimmung von MSTs
Initialisierung: Ein Anfangsknoten v0 wird festgelegt. T0 besteht nur aus v0 .
c (vi ) := v0 für alle vi 6= v0
for i := 1 to n − 1 do
73
KAPITEL 5. PARALLELE ALGORITHMEN
5.4. GRAPHEN ALGORITHMEN
Suche unter den Knoten außerhalb von Ti einen Knoten ṽ mit w (ṽ, c (ṽ)) minimal und füge
ṽ mit Kante (ṽ, c (ṽ)) zu Ti hinzu.
Die Knoten vj , die außerhalb von Ti bleiben berechne c (vj ) neu:
(i)
(ii)
1
2
c (vj ) := if w (vj , ṽ) < w (vj , c (vj ))
then ṽ else c(vj )
sequentielle Laufzeit:
T (n)
=
1
|{z}
+
v0 auswaehlen
¡
2
= O n
¢
O (n)
| {z }
Initalisierung
+ (n − 1) O (n)
{z
}
|
Schleif e
Implementierung des Verfahrens auf einer CREW-PRAM mit n Prozessoren mit 1-1-Zuordnung von Prozessoren zu
Graphenknoten.
Initialisierungsaufwand: O (1)
Schleife:
Phase 1:
(Minimumsbildung) O (log n)
Phase 2:
O (1)
y par. Laufzeit¡ O (n log¢n) mit n Proz.
y par. Kosten n2 log n
y nicht optimal.
Beobachtung: Prozessoren werden untätig, sobald ihre Knoten im MST sind.
y Rescheduling zur Kostenoptimierung
Annahme: Es stehen N Prozessoren mit 1 ≤ N ≤ n bereit. Sei N = n1−x mit 0 < x < 1.
Jeder Prozessor verwaltet jetzt
n
N
= nx Knoten.
Laufzeitanalyse:
Initialisierungsaufwand: O (nx )
Schleife:
74
KAPITEL 5. PARALLELE ALGORITHMEN
5.4. GRAPHEN ALGORITHMEN
Phase 1:
Phase 2:
O (nx ) für lokale Minimumbestimmung pro Prozessor
+ O (log N ) für globale Minimumbestimmung durch Reduktion
+ O (1) für Baumerweiterung
O (nx ) lokale Updates von c (vj )
CREW-Aufwand:
O (nx ) + O (n) (O (nx ) + O (log N ))
=
O (n)
O ¢(nx )
¡ x+1
=
O n
auf nx−1¡Prozessoren
¢
=⇒ parallele Kosten O n2
=⇒ kostenoptimal
5.4.3.2 Algorithmus von Sollin (1977)
Arbeitsweise ähnlich zu Hirschberg-Algorithmus (Bestimmung von Zusammenhangskomponenten)
anstelle des Knotens mit minimalem Index innerhalb der Superknoten wird jetzt die Kante mit minimalem Gewicht zu
anderem Superknoten bestimmt.
Initialisierung:
Wald von n isolierten Knoten, die als Bäume betrachtet werden.
Iteration:
Für jeden Baum: bestimme die Kante mit dem kleinsten Gewicht, die diesen Baum mit einem anderen
Baum verbindet. Alle diese minimalen Kanten werden hinzugefügt – dabei werden eventuell entstehende
Zykel beliebig durchbrochen.
Die Anzahl der Bäume wird pro Iteration mindestens halbiert. y ⌈log (n)⌉ Iterationen genügen.
75
KAPITEL 5. PARALLELE ALGORITHMEN
5.4. GRAPHEN ALGORITHMEN
Abbildung 5.10: Beispiel
(a) 1.Iteration
(b) 2.Iteration
Pseudo-Code(sequentiell)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Parameter: n #Knoten
Variablen: closest[ ] Abstand zu nächstem Baum
edge[ ]
Kante zu nächstem Baum
T
MST (als Kantenmenge)
v,w
Endpunkte der aktuellen Kante
weight[ ] Kantengewichte
Baum[ ]
Wald als Knotenmenge
begin
for i:=1 to n do Baum[i]:={vi } od
T := ∅
while |T | < n − 1 do
für jeden Baum i setze closest[i]:=∞
für jede Kante (v,w) tue
if FIND(v) 6= FIND(w) then
if weight(v,w) < closest[FIND(v)]
then closest[FIND(v)]:= weight(v,w)
edge [FIND(v)]:= (v,w)
fi
fi
für jeden Baum i true
(v,w):= edge[i]
/ if FIND(v)6= FIND(w) then T:=T ∪ {(v, w)}
(*)
UNION(v,w)
\ fi
od
end
FIND
76
liefert zu einem Knoten, den Baum, in dem er enthalten ist.
KAPITEL 5. PARALLELE ALGORITHMEN
5.4. GRAPHEN ALGORITHMEN
UNION
vereinigt die Bäume, in denen zwei Knoten v und w enthalten sind.
FIND und UNION effizient realisierbar.
Parallelisierung:
• Die äußere while-Schleife ist nicht parallelisierbar.
• 1te innere Schleife kann voll parallelisiert werden.
• 2te innere Schleife: Jeder Prozessor kann für Anteil von inneren Knoten jeweils die von diesem
Knoten ausgehenden Kanten untersuchen.
• 3te innere Schleife: kritischer Bereich (*) erfordert Synchronisation.
77
6 Algorithmische Skelette
Beobachtung: Viele parallele Algorithmen arbeiten mit festen Grundmustern für parallele Berechnung und Kommunikation. Durch algorithmische Skelette wird versucht, diese Grundmuster zu erfassen, effizient zu implementieren und
zu analysieren.
Ein algorithmisches Skelett besteht aus:
1. einer funktionalen Spezifikation „abstrakte Funktionsbeschreibung“
in fkt. Sprache: polymorphe Funktion höherer Ordnung (HOF)
2. parallele Implementierungen für verschiedene Zielarchitekturen
3. einem Kostenmodell zur Abschätzung der parallelen Ausführungszeit (für jede parallele Implementierung)
typische Skelette
• Divide & Conquer (Abb. 6.1)
Listing 17 Divide & Conquer
dc :: (a−→Bool)−→(a−→b)−→(a−→[a])−→([b]−→b)−→a−→b
dc isAtom solve divide combine x
= if isAtom x then solve x
else combine(map dc’ (divide x))
where dc’ = dc isAtom solve divide combine
Abbildung 6.1: Divide & Conquer
• Master-Worker-Schema (Abb. 6.2)
78
KAPITEL 6. ALGORITHMISCHE SKELETTE
Abbildung 6.2: Master-Worker-Schema
• Pipeline (Abb. 6.3)
Abbildung 6.3: Pipeline
−→ ¤ −→ ¤ −→ . . . −→ ¤ −→ ¤
1. funktionale Spezifikation
pipe :: [[a]−→[a]]−→[a]−→[a]
pipe [] xs = xs
pipe(f:fs) xs = pipe fs (f xs)
Beispiel: pipe (map map[*3,+5,*2])(1:2:...)
2. parallele Implementierung ...4 3 2 1["*3"]...6 3["+5"]...11 8["*2"]...22 16
−−−−−→
−−→
−−−→
−−−−→
3. Kostenmodell:
allgemein: Ausdruck mit Parametern, der parallele Ausführungszeit des Skelettes abschätzt.
typische Parameter:
• architekturabhängig
– #Prozessoren
– Kommunikationskosten
tsend
„Zeit für das Senden einer Nachricht“
δ
„Übertragungsdauer einer Nachricht“
treceive
Empfangszeit
• Laufzeit systemabhängig
– Prozesserzeugungskosten
– sequentielle Ausführungszeiten
• problemabhängig
– Problemgröße
Methode: Analyse eines kritischen Pfades (Abb. 6.4)
— kritischer Pfad: Folge notwendiger Aktionen, die aufeinander aufbauen und damit die Gesamtausführungszeit bestimmen.
Sehr oft: ’3’ Grundphasen
1. Hochfahren des Systems bis alle Prozessoren aktiv sind
79
KAPITEL 6. ALGORITHMISCHE SKELETTE
Abbildung 6.4: kritischer Pfad
2. parallele Phase
„längster“ Teil der Parallelausw.
3. Schlussarbeiten und Runterfahren des Systems
tpipe
=
tinit + tpar + tf inal
tinit
=
tpar
=
tf inal
=
#F ct ∗ (tcreateP rozess + tsend (size (Daten)) + δ)
„
«
#F ct
max
∗ (tstartP rocess + #Daten ∗ treceive (size (Daten)) +
{tcomp } + tsend (size (Daten))
F ct
p
δ + treceive (size (Daten))
< < < Folien Skeletal Programming > > >
map f (xs + +ys)
red ⊕ (xs + +ys)
=
=
(map f xs) + + (map f ys)
(red ⊕ xs) ⊕ (map ⊕ ys)
falls
scan ⊕ (xs + +ys)
⊕
=
=
assoziativ
(scan ⊕ xs) + +map ((red ⊕ xs) ⊕) (scan ⊕ ys)
(scan ⊕ xs) op (scan ⊕ ys)
a op b
where
=
a + + map ((last a) ⊕) b
scanred (⊗, ⊕) (xs + +ys)
= red (⊕) ◦ scan (⊗) (xs + +ys)
= red (⊕) (scan ⊗ xs + +map ((red ⊗ xs) ⊗) (scan ⊗ ys))
80
KAPITEL 6. ALGORITHMISCHE SKELETTE
= (scanred (⊗, ⊕) xs) ⊕ (red ⊕ (map ((red ⊗ xs) ⊗) (scan ⊕ ys)))
scanred′ (⊗, ⊕) (xs + +ys)
= ((scanred (⊗, ⊕) xs) ⊕ (red ⊕ (map ((red ⊗ xs) ⊗) (scan ⊕ ys))) , (red ⊗ xs) ⊗ (red ⊕ ys))
Distributivität:
a ⊗ (b ⊕ c)
=
(a ⊗ b) ⊕ (a ⊗ c)
map (a⊗) ◦ red⊕ =
red ⊕ ◦map (a⊗)
= ((scanred (⊗, ⊕) xs) ⊕ (red ⊗ xs) ⊗ (scanred (⊗, ⊕) ys) , (red ⊗ xs) ⊗ (red ⊕ ys))
= scanred′ (⊗, ⊕) xs < ⊕, ⊗ > scanred′ (⊗, ⊕) ys
< < < Folien Alternative Concepts: Parallel Functional Programming > > >
81
Literaturverzeichnis
[1] A NDREWS , G REGORY R.: Foundations of Multithreaded, Parallel, and Distributed. Addison Wesley, 1999.
[2] F OSTER , I AN: Designing and Building Parallel Programs: Concepts and Tools for Parallel Software Engineering.
Addison Wesley, 1995.
I
Abbildungsverzeichnis
II
2.1
Matrix-Multiplikation n=3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
2.2
Hypercube . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
2.3
Butterfly-Vernetzung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
2.4
Hypercube der Dimension k . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
4.1
Zusammenhängender Puffer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
5.1
Aufbau einer PRAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
5.2
Beispiel: 16 Zahlen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
64
5.3
Zeitlicher Ablaufplan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
66
5.4
Beispiel – Zusammenhangskomponenten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
68
5.5
Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
69
5.6
T-Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
70
5.7
T-Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
71
5.8
C-Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
72
5.9
minimal spannender Baum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
73
5.10 Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
76
6.1
Divide & Conquer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
6.2
Master-Worker-Schema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
6.3
Pipeline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
6.4
kritischer Pfad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
80
Herunterladen