Message Passing Interface: MPI Geschichte: Erster MPI Standard Etwa 60 Personen, von 40 Institutionen (29-30 April 1992) MPI 1 im November 1993 MPI 1.1 im Juni 1995 MPI 1.2 Juli 1997 (Nur Ergänzung zu MPI 1.1) MPI 2.0 Standard, Juli 1997 (Compiler in Entwicklung) Ziele: Source Code portability Effiziente Umsetzung Unterstützung für heterogene Architekturen Sprachenunabhängig (C bzw. Fortran) Verschiedenes: Dokumentation: MPI Standard (http://www-unix.mcs.anl.gov/mpi/) Freie Implementation: MPICH (http://www-unix.mcs.anl.gov/mpi/mpich/) MPI 1
Message Passing Interface: MPI Voraussetzungen: Compiler muß MPI verstehen Linken mit: -lmpi Im Programm: #include <mpi.h> Das einfachste Programm: #include <mpi.h> main(int argc, char **argv) { MPI_Init(&argc, &argv); printf("hallo:\n"); MPI_Finalize(); } Ausführen: mpirun -np 4 a.out Single Program Multiple Data: SPMD Jeder Prozeß führt denselben Code aus Prozesse werden durch den sog. Rank unterschieden All Prozesse gehören dem Communicator MPI COMM WORLD an. MPI 2
Message Passing Interface: MPI Informationen über die Umgebung: MPI Comm rank(mpi Comm comm, int *rank): Wer bin ich? MPI Comm size(mpi Comm comm, int *size): Wie viele sind wir? Beispiel: Schreibe ein Programm, bei dem jeder Prozeß seine ID ausgibt, und wieviele Prozesse es gibt? Modifiziere das Programm so, daß nur der Prozeß mit dem höchsten Rank die Anzahl der Prozesse ausgibt. MPI 3
Datentypen und Nachrichten Einige (intrinsische) MPI Datentypen: MPI CHAR MPI INT MPI LONG MPI FLOAT MPI DOUBLE MPI LONG DOUBLE Nachrichten-Typen: signed char signed int signed long int float double long double Synchronous send: MPI Ssend Ist beendet wenn der Empfänger empfangen hat. Buffered Send: MPI Bsend Initiiert den Send, gibt dann die Kontrolle zurück, unabhänging vom Status des Empfängers Standard Send: MPI Send Abhängig von der Implementation Receive: MPI Recv Gibt die Kontrolle zurück, wenn die Nachricht empfangen wurde Aufruf: int MPI Send(void *buf, int cnt, MPI Typ typ, int dest, int tag, Comm comm) int MPI Recv(void *buf, int cnt, MPI Typ typ, int src, int tag, Comm comm, MPI Status *status): status.mpi TAG,.MPI SOURCE,.MPI ERROR MPI 4
Beispiel: Nachrichten #include <mpi.h> #include <stdio.h> main(int argc, char **argv) { int myrank,size; double number=0; MPI_Status status; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &myrank); MPI_Comm_size(MPI_COMM_WORLD, &size); } if (myrank == 0){number = 3.; MPI_Ssend(&number,1,MPI_DOUBLE,1,1,MPI_COMM_WORLD); } if (myrank == 1){ MPI_Recv(&number,1,MPI_DOUBLE,0,1,MPI_COMM_WORLD, &status); printf("wert: %f \n",number); } MPI_Finalize(); MPI 5
Nachrichten Aufgaben: Schreibe ein Programm Ping Pong, bei dem 2 Prozesse eine Nachricht hinund her schicken. Wie hängt die benötigte Zeit von der Größe der Nachricht ab? Benutze dazu double MPI Wtime() Schreibe ein Programm, das eine Nachricht (mehrmals) im Kreis herum schickt Schreibe ein Programm zur Matrizenmultiplikation: C = A B Dabei soll jeder Prozeß einen Streifen der Matrix C berechnen. Wie ist das Verhältins Kommunikation/Rechenzeit? MPI 6
Non-Blocking Communication Unterschied: Blocking: Gibt Kontrolle zurück wenn der Buffer wieder benutzt werden kann. Non-Blocking: Initiiert die Kommunikation, gibt Kontrolle sofort zurück. Aufruf: MPI Isend(void* buf, int cnt, MPI Datatype type, int dest, int tag, COMM com, MPI Request *request) MPI Issend( : : : ) MPI Ibsend( : : : ) MPI Irecv(void* buf, int cnt, MPI Datatype type, int src, int tag, COMM com, MPI Request *request) Fertig? Kann Buffer benutzt werden und nicht ist Nachricht empfangen? MPI Wait(MPI Request *request, MPI Status *status) MPI Test(MPI Request *request, int *flag, MPI Status *status) flag = true oder false? MPI Waitall(int cnt, MPI Request *array of requests, MPI Status *array of status) MPI 7
Beispiel Wie kann die Kommunikation im Beispiel der Matrizenmultiplikation optimiert werden? Implementiere folgendes Schema: Prozeß 0 schickt alle Nachrichten Non-Blocking weg Prozeß 0 geht in Empfangsbereitschaft Prozeß 0 startet seine Rechnung Prozeß 0 wartet bis alle Ergebnisse da sind Ist der Performance-Gewinn meßbar? Hat sich das Verhältins Kommunikation/Rechenzeit spürbar verbessert? MPI 8
Derived Datatypes Problem: Versand einer Var. die nicht kont. im Speicher liegt General Datatype: Sequenz von Basic datatypes + Sequence of integer displacements MPI Type contignuous(int count, MPI Datatype old, MPI Datatype new) MPI Type vector(int cnt, int blocklength, int stride, MPI Datatype old, MPI Datatype new) MPI Type struct(...), der allgemeinste Ansatz MPI Type vector: MPI Type struct: Freigabe eines Datentyps: MPI Type commit(mpi Datatype *new) MPI 9
Warum? Virtuelle Topologien Vereinfachen die Benennung der Prozesse ermöglicht (einfachere) Bindung der Prozesses an CPU s Bequem Verschiedene Topologien: MPI Graph create(...): allg Graph MPI Cart create(mpi Comm old, int ndims, int *dims, int * periods, int reorder, MPI Comm *new) old: der alte Communicator ndims: Wieviele Dimensionen soll der neue haben? *dims: Array mit der Länge in den ndims Dimensionen *periods: Periodisch? 0 oder 1 reorder: Sollen die ranks in der neuen Topologie umgeordnet werden? *new: Neuer Communicator MPI Dims create(int nnodes,int ndims, int *dims) nnodes: Wieviele Prozesse ndims: Kartesische Komponenten *dims: Wieviele Prozesse in welcher Richtung MPI Cart rank bzw. MPI Cart coords, vermittelt zw. Koordinaten MPI Cart Coords brechnet die eigenen Koordinaten, MPI Cart shift die von Nachbarn und rank MPI 10
Examples? Kollektive Kommunikation MPI Barrier(MPI Comm comm): Alle Prozesse warten aufeinander MPI Bcast(void* buffer, int cnt, MPI Datatype datatype, int root, MPI Comm comm) Scatter, Gather,... siehe MPI Standard Seite 92 MPI Reduce(void *sendbuf, void* recvbuf, int cnt, MPI Datatype type, MPI Op op, int root, MPI comm comm): Nimmt die Elemente in sendbuf, wendet MPI Op darauf an und kopiert Ergebnis in recvbuf des Prozesses mit rank=root MPI MAX, MPI MIN MPI SUM,MPI PROD..., können auch selbst definiert werden. MPI 11
Derived Datatypes Beispiel Schreibe ein Programm, das eine 10x10 Matrix in 4 Blöcke aufteilt und die Blöcke nacheinander an einen 2ten Prozess schickt, der die Blöcke ausgibt. Virtuelle Topologien Schreibe ein Programm, das eine Kartesische 2x3 Topologie definiert. Jeder Prozeß soll seinen rank und seine Koordinaten ausgeben. Modifiziere das Programm so, daß ein 2 dimensionales Koordinaten System angelegt wird, dessen Ausdehnung in den einzelnen Richtungen selbstständig abhängig von der Anzahl der Prozessoren bestimmt wird. Modifiziere das Programm so, daß ein 2 dim Koord.-System mit periodischen Randbedingungen angelegt wird, und jeder Prozeß den rank seiner 4 Nachbarn ausgibt. Collective Communication: Schreibe ein Programm, das MPI Reduce verwendet um eine Summe über Werte, die nur den einzelnen Prozessen bekannt sind berechnet. MPI 12
Das Ising Modell Case Study 2 dimensionales 2 Zustandsmodell P (z.bsp. Spin P System) mit Werten +/- 1 Hamilton Operator: H = J S hi;ji js j B S i i, mit: B: externel Magn. Feld, : magn. Dipolmoment J > 0: Ferromagnet J < 0: Antiferromagnet kanonische Zustandssumme: Z = Trfe H g Magnetisierung: hm i = 1 Z TrfMe H g Problem: Zuviele Zustände ( 2 N ) Der Metropolis Algorithmus Idee: Monte Carlo Integration, mit Zufallszahlen der Verteilung e H Vorgehen: Gehe das Gitter durch und wechsle den Zustand mit Wahrscheinlichkeit p p = 1, wenn H(flip) < H(jetzt) p = e (H(jetzt) H(flip)) sonst Konkret: B = 0, d.h. kein externes Feld, J > 0, d.h. Ferromagnet, J wird in Einheiten von = 1=(kT ) gemessen Tip: Benutze das Template ising.c :-) Ziel: Möglichst effiziente Implementation (Speedup Graph), Berechne die Magnetisierung in Abhängigkeit von J 2 [0; 1] MPI 13