+ All Categories
Home > Documents > Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

Date post: 06-Apr-2016
Category:
Upload: elissa-bolls
View: 221 times
Download: 4 times
Share this document with a friend
63
Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03
Transcript
Page 1: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

Algorithmische Skelette

Michael BrulandMichael Hüllbrock

Münster, den 12.06.03

Page 2: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

2

Gliederung(1) Motivation(2) Grundlegende Technologien(3) Algorithmische Skelette(4) Alternativen zur Implementierung mittels

Bibliothek(5) Fazit

Page 3: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

3

1 Motivation (1) „Low-Level-Programmierung“ auf Parallelrechnern

häufig erforderlich Kommunikationsprobleme wie Deadlocks oder

Starvation schnell möglich Einsatz von Programmiersprachen speziell für

Parallelrechner erfordert neue Einarbeitung häufig Scheu vor Nutzung neuer

Programmiersprachen Lernkurveneffekte

Page 4: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

4

1 Motivation (2) Portierbarkeit von Programmen erwünscht Einsatz von Bibliotheken zur Erweiterung

bestehender Programmiersprachen Programmiermuster für Parallelrechner

Page 5: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

5

Gliederung(1) Motivation(2) Grundlegende Technologien(3) Algorithmische Skelette(4) Alternativen zur Implementierung mittels

Bibliothek(5) Fazit

Page 6: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

6

2 Grundlegende Technologien Funktionen höherer Ordnung (Higher-Order-

Functions) Parametrisierte Datentypen Partielle Applikationen Verteilte Datenstrukturen

Page 7: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

7

2.1 Funktionen höherer Ordnung Gleichstellung von Funktionen und Werten in

funktionalen Sprachen Funktion mit Funktionen und/oder Ergebnissen als

Argumenten Neustrukturierung von Problemen aufgrund

allgemeingültiger Berechnungsschemata möglich, durch Funktionsparameter an Kontext anpassbar

Bsp.: wendet eine Funktion auf alle Werte

einer Kollektion an

babamap )(:

Page 8: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

8

2.2 Parametrisierte Datentypen Schablonen von Berechnungsvorschriften Typen erst durch Übergabe von Parametern in

Klassendefinition festgelegt Überprüfung zur Laufzeit auf Typsicherheit Implementierung in C++ durch Templates

Page 9: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

9

Funktionen, die mit weniger Argumenten angewendet werden können als eigentlich benötigt

Anwendung auf restliche Argumente führt zum selben Ergebnis wie Auflösen der Ursprungsfunktion

Ermittlung der letzten einstelligen Funktion und Rückgabe an weitere Funktionen

Currying als Identifikation mehrstelliger Funktionen mit einstelligen Funktionen höherer Ordnung

Ausgangsfunktion: Mit Currying:

2.3 Partielle Applikationen

)...)...(( 21 tttt n tttt n ),...,,( 21

Page 10: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

10

2.4 Verteilte Datenstrukturen (1) Kollektionen wie Listen, Arrays oder Matrizen Verteilung auf die partizipierenden Prozessoren Aufteilung durch verschiedene Verfahren möglich

Blockpartitionierung Zyklische Partitionierung …

Page 11: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

11

2.4 Verteilte Datenstrukturen (2) Bsp.: Aufteilung einer Matrix auf 4 Prozessoren

Prozessor1

Prozessor2

Prozessor3

Prozessor4

44434241

34333231

24232221

14131211

xxxxxxxxxxxxxxxx

2221

1211

xxxx

2423

1413

xxxx

4241

3231

xxxx

4443

3433

xxxx

Page 12: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

12

2.5 Eigenschaften von C++ für die Nutzung von Skeletten

Polymorphismus Partielle Applikationen durch Currying ermöglicht Parametrisierte Datentypen durch Templates

template <class E> class DistributedArray{…}

Page 13: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

13

Gliederung(1) Motivation(2) Grundlegende Technologien(3) Algorithmische Skelette(4) Alternativen zur Implementierung mittels

Bibliothek(5) Fazit

Page 14: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

14

3 Algorithmische Skelette (1) Programmiermuster für Interaktion und

Rechenoperationen zwischen Prozessen Vorimplementierte, parametrisierte Komponenten Globale Sichtweise bei Implementierung Entweder Sprachkonstrukte oder Inhalte in

Bibliotheken Realisierung basiert auf MPI Abstraktion von „Low-Level-Programmierung“ Hardwareabhängige Implementierung

Portierbarkeit der Programme

Page 15: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

15

3 Algorithmische Skelette (2) Aufbau der Bibliothek in C++

Verteilte Datenstruktur ist Klasse Nutzung der algorithmischen Skelette durch

Methodenaufrufe der Klassen

Page 16: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

16

3.1 Klassifikation algorithmischer Skelette Datenparallele Skelette

Rechenskelette Kommunikationsskelette

Taskparallele Skelette

Page 17: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

17

3.2 Datenparallele Skelette (1) Ermöglichen Ortstransparenz Beherrschung von Datenparallelität Aufteilung der Daten auf die Prozessoren Steuerung der Prozessoren, wo welche Daten

bearbeitet werden sollen Bsp.: map oder fold

Page 18: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

18

3.2 Datenparallele Skelette (2) Bsp.: Geometrisch Daten werden partitioniert und auf die Prozessoren

verteilt Kommunikation zwischen benachbarten Prozessoren

möglich Ergebnisse werden von einem Prozess geordnet Anwendung: Vektorberechnung

Page 19: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

19

3.2 Datenparallele Skelette (3)

Nach Campbell 1996

Page 20: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

20

3.2.1 Rechenskelette (1) Arbeiten Elemente einer verteilten Datenstruktur

parallel ab Map: wendet eine Funktion auf Teile einer verteilten

Datenstruktur an Fold: kombiniert alle Elemente einer verteilten

Datenstruktur sukzessive mit einer Verknüpfungsfunktion h

Page 21: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

21

3.2.1 Rechenskelette (2) Bsp.: Fold Verknüpfungsfunktion h ist E plus(E,E) A ist eine verteilte (4x4)-Matrix A.fold(plus)

bildet die Summe über alle Elemente

2221

1211

xxxx

4241

3231

xxxx

4443

3433

xxxx

2423

1413

xxxx

),...,( 4411 xx

Page 22: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

22

3.2.2 Kommunikationsskelette (1) Tauschen Partitionen einer verteilten Datenstruktur

aus Realisierung basiert auf MPI Kein Austausch individueller Nachrichten erlaubt

→ Probleme wie Deadlock, Starvation etc. werden verhindert

Page 23: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

23

3.2.2 Kommunikationsskelette (2) Bsp.: A.permutePartition(f)

Partition (an Prozessor i) wird an Prozessor f(i) gesendet

Weiteres Kommunikationsskelett: rotate

2221

1211

xxxx

iA

Page 24: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

24

3.3 Taskparallele Skelette (1) Verarbeiten Strom von Eingabewerten in Menge von

Ausgabewerten Teilen den Prozessoren Tätigkeiten zu Tätigkeit kann Funktion oder wiederum Skelett sein

Verschachtelung von Skeletten möglich Kann mit Funktion oder partieller Applikation

aufgerufen werden

Page 25: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

25

3.3 Taskparallele Skelette (2) Bsp.: Farm Anzahl der Prozessoren ist gleich Anzahl der Worker Auswahl vom Farmer nicht-deterministisch

Initial Farmer Final

AtomicWorker

AtomicWorker

Quelle: Kuchen 2002

Page 26: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

26

3.3 Taskparallele Skelette (3) Initial-Prozess

template <class O>class Initial: public Process{public:

Initial(O* (*f)(Empty))void start()

}

Page 27: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

27

3.3 Taskparallele Skelette (4) Farm-Prozess

template<class I, class O>class Farm: public Process{public:

Farm(Process& worker, int n)void start()

}

Page 28: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

28

3.3 Taskparallele Skelette (5) Final-Prozess

template <class I>class Final: public Process{public:

Final(void(*f)(I))void start()

}

Page 29: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

29

3.3 Taskparallele Skelette (6) Bsp.: Divide and Conquer Probleme werden rekursiv in Subprobleme unterteilt Lösung der Subprobleme erfolgt unabhängig von

einander und parallel Je nach Implementierung

unterschiedliche Anforderungen an Struktur Unterstützung von konservativer und spekulativer

Parallelität Anwendung: Quicksort, Branch and Bound

Page 30: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

30

3.3 Taskparallele Skelette (7)

Nach Campbell 1996

Page 31: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

31

3.3 Taskparallele Skelette (8) Bsp.: Branch and Bound Anwendung: Optimierungsprobleme Vorgehensweise:

n Worker-Kopien durch Konstruktoraufruf Verknüpfung mit internem Controller Teillösungen werden vom Controller im Heap

gesammelt, falls besser als bestehende Suboptimale Lösungen werden verworfen

Page 32: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

32

3.3 Taskparallele Skelette (9) Bsp.: Branch and Bound

template <class I>class BranchAndBound:public Process{public:

BranchAndBound(Process& worker, int n, bool (* lth)(I,I), bool (* isSolution)(I))

void start()}

Page 33: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

33

3.4 Das 2-Ebenen-Modell (1) Modell zur Kombination von task- und datenparallelen

Skeletten

äußere Ebene: miteinander verzahnte taskparallele Skelette

innere Ebene: sequentielle Programme und datenparallele Skelette

Page 34: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

34

3.4 Das 2-Ebenen-Modell (2) Aufgabe: Ein Musikstück soll

von Hintergrundrauschen befreit werden, Hall hinzugefügt werden, in ein best. Dateiformat (z.B. wav) konvertiert

werden

Lösung mit 2-Ebenen-Modell: Äußere Ebene : Pipeline Innere Ebene : sequentielle Bearbeitung oder

datenparalleles Skelett

Page 35: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

35

3.5 Zusätzliche Funktionen Keine Skelette Flexible Optimierung des Quellcodes Lokale und globale Sichtweise möglich

Beispiele: getLocalRows() gibt die Anzahl der lokal

verfügbaren Zeilen zurück getRows() gibt die Anzahl der Zeilen der gesamten

verteilten Matrix zurück isLocal (int i, int j) ist wahr, wenn das Element mit

dem Index i,j lokal verfügbar ist …

Page 36: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

36

3.6 Laufzeitverhalten (1) Skelette sind ein abstraktes Konstrukt

Wie hoch sind die Performanzeinbußen von Skeletten gegenüber einer „reinen“ MPI Implementierung?

Vergleich von 5 Beispielprogrammen auf einer Siemens hpcLine mit 4 bzw. 16 Prozessoren

Page 37: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

37

3.6 Laufzeitverhalten (2)Beispiel n Skelette MPI Quotient

Matrix Multiplikation 1024 35.203 29.772 1.18Kürzester Pfad 1024 393.769 197.979 1.99

Gauss’sches Eliminationsverfahren

1024 13.816 9.574 1.44

FFT 218 2.127 1.295 1.64

Samplesort 218 1.599 † -

Quelle: Kuchen 2002

Page 38: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

38

3.6 Laufzeitverhalten (3)Beispiel n Skelette MPI Quotient

Matrix Multiplikation 1024 8.624 6.962 1.24

Kürzester Pfad 1024 93.825 44.761 2.10

Gauss’sches Eliminationsverfahren

1024 7.401 4.045 1.83

FFT 218 0.636 0.403 1.58

Samplesort 218 0.774 † -

Quelle: Kuchen 2002

Page 39: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

39

3.6 Laufzeitverhalten (4)Fazit Laufzeitverhalten:

Skelette sind um den Faktor 1,2 bis 2,1 langsamer als „reines“ MPI

Grund: Overhead bei der Parameterübergabe Fehlende Optimierungsroutinen

Page 40: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

40

3.7 Beispiele mit algorithmischen Skeletten

3.7.1 Gauß‘sches Eliminationsverfahren 3.7.2 Matrixmultiplikation

Page 41: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

41

3.7.1 Gauß (1)Eliminationsverfahren nach Gauß Lösungsmenge und Rang einer n x (n+1) Matrix Hier: zusätzliche Voraussetzung a1,1 ≠ 0

Idee: Reduzierung der Variabeln durch Addition/Subtraktion der einzelnen Zeilen mit der Pivotzeile

Page 42: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

42

3.7.1 Gauß (2)#include „Skeleton.h“

inline double init(const int a, const int b){return (a==b) ? 1.0 : 2.0;}

inline double copyPivot(const DistributedMatrix<double>&A,int k, int i, int j, double Pij){

return A.isLocal(k,k) ? A.get(k,k) : 0;}

Page 43: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

43

3.7.1 Gauß (3)inline void pivotOp(const DistributedMatrix<double>& Pivot, int

rows,int firstrow, int k, double** A){double Alk;for (int l=0; l<rows; l++){

Alk = A[l][k];for (int j=k; j<=Problemsize; j++) if (firstrow+1 == k)

A[l][j] = Pivot.getLocalGlobal(0,j); else A[l][j] -= Alk *

Pivot.getLocalGlobal(0,j);}}

Page 44: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

44

3.7.1 Gauß (4)void gauss(DistributedMartix<double>& A){

DistributedMatrix<double> Pivot(sk_numprocs,Problemsize+1,0.0,sk_numprocs,1);

for (int K=0; k<Problemsize; k++){Pivot.mapIndexInPlace(curry(copyPivot)(A)(k));Pivot.broadcastPartition(k/A.getLocalRows(),0);A.mapPartitionInPlace(curry(pivotOp)(Pivot,A.getLocalRows();

A.getFirstRow(),k));}}

Page 45: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

45

3.7.1 Gauß (5)int main(int argc, char **argv){

try{InitSkeletons(argc, argv);DistributedMatrix<double>

A(Problemsize,Problemsize+1,&init,sk_numprocs, 1);gauss(A);A.show();

TerminateSkeletons();}catch(Exception&){cout << “Exception” << endl <<flush;}

}

Page 46: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

46

3.7.1 Gauß (6)

Ausführung auf 3-Prozessor-Maschine Pivot.mapIndexInPlace(curry(copyPivot)(A)(k))

kopiert die Pivotzeile (I) in eine p x (n+1), also eine 3x4 Matrix

broadcastPartition übermittelt diese Zeile weiter Mit mapPartitionInPlace wird auf jeder Partition der

Matrix parallel pivotOP ausgeführt

Page 47: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

47

3.7.1 Gauß (7)

die Zeile II wird mit -(9/6 * I) addiert und die Zeile III mit –(3/6 * I)

Weitere Schritte analog

Page 48: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

48

3.7.2 Matrixmultiplikation (1)Matrixmultiplikation Idee: Multiplikation zweier verteilter Matrizen

A und B durch Blockpartitionierung und Aufteilung auf n Prozessoren

Page 49: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

49

3.7.2 Matrixmultiplikation (2)#include „Skeleton.h“#include „math.h“inline int negate(const int a) {return –a;}inline int add(const int a, const int b) {return a+b;}

template <class C>C sprod (const DistributedMatrix<C>& A,

const DistributedMatrix<C>& B, int i, int j, C Cij){C sum=Cij;for(int k=0;k<A.getLocalRows();k++)

sum+=A.getGlobalLocal(i,k))*B.getLocalGlobal(k,j);return sum;}

Page 50: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

50

3.7.2 Matrixmultiplikation (3)template <class C>DistributedMatrix<C> matmult(DistributedMatrix<C>

A,DistributedMatrix<C> B){

//assumption: A, B have same square shapeA.rotateRows(& negate);B.rotateCols(& negate);DistributedMatrix<C> R(A.getRows(),A.getCols(),0,

A.getBlocksInCol(),A.getBlocksInRow());for(int i=0;i<A.getBlocksInRow();i++){

R.mapIndexInPlace(curry(sprod<C>)(A)(B));A.rotateRows(-1);B.rotateCols(-1);}

return R;}

Page 51: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

51

3.7.2 Matrixmultiplikation (4)int main(int argc, char **argv){

try{InitSkeletons(argc,argv));int sqrtp=(int) (sqrt(sk_numprocs)+0.1);DistributedMatrix<int> A(Problemsize,Problemsize,

& add, sqrtp, sqrtp);DistributedMatrix<int> B(Problemsize,Problemsize,

& add, sqrtp,sqrtp);DistributedMatrix<int> C=matmult(A,B);C.show();TerminateSkeletons();}

catch(Exception&){cout << “Exception” << endl << flush;};}

Page 52: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

52

Gliederung(1) Motivation(2) Grundlegende Technologien(3) Algorithmische Skelette(4) Alternativen zur Implementierung mittels

Bibliothek(5) Fazit

Page 53: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

53

4 Alternativen zur Bibliothek P3L SkIE

Page 54: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

54

4.1 P3L (1) Pisa Parallel Programming Language Basiert auf C++ Skelette farm, map, pipe und loop sind vordefiniert

<skelettname> <bezeichner> in(<par>) out(<par>) <prozedur> in(<p>) out(<p>)end <skelettname>

Page 55: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

55

4.1 P3L (2)farm myfarm in(int inputA, int inputB) out(int

output) p in(inputA,inputB) out(output)end farm

Anzahl der Worker wird vom Compiler selbstständig ermittelt

Compiler versucht den Speedup zu maximieren „Mapping Problem“ wird durch implementation

templates gelöst

Page 56: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

56

4.1 P3L (3)Ausführung in 3 Stufen:

1. Emitter empfängt Datenstrom und verteilt ihn an die Worker

2. Worker führen Prozesse aus und geben das Ergebnis an den Collector

3. Collector empfängt Ergebnisse und schreibt sie in den Ausgabekanal

Page 57: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

57

4.2 SkIE (1) Skeleton-based Integrated Enviroment

Vorteile gegenüber P3L Breitere Sprachunterstützung (C, C++, F90, Java,

…) Einbindung von MPI und HPF Grafische Benutzeroberfläche (VisualSkIE) Analysetools

Page 58: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

58

4.2 SkIE (2)

Page 59: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

59

4.2 SkIE (3)Anwendungsentwicklung mit SkIE in 3 Phasen:

Phase 1: Generieren des Codes und globale Optimierungen

Phase 2: Debugging

Phase 3: Performanzanalyse

Page 60: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

60

Gliederung(1) Motivation(2) Grundlegende Technologien(3) Algorithmische Skelette(4) Alternativen zur Implementierung mittels

Bibliothek(5) Fazit

Page 61: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

61

5 Fazit (1) Skelette befreien den Programmierer von

Problemen der parallelen Hardware Portierbarkeit von Programmen Globale Sichtweise bei Konzeption und

Programmierung Kommunikationsprobleme wie Deadlock oder

Starvation können nicht vorkommen Integration einer Bibliothek in eine bekannte

Sprache überbrückt „Berührungsängste“

Page 62: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

62

5 Fazit (2) Vermeidung von Lernkurveneffekten durch Nutzung

bekannter Programmiersprachen Kostenabschätzungen möglich Performanzeinbußen sind im akzeptablem Rahmen

Page 63: Algorithmische Skelette Michael Bruland Michael Hüllbrock Münster, den 12.06.03.

63

Fragen / Diskussion


Recommended