230 likes | 396 Views
GWDG – Kurs Parallelrechner-Programmierung mit MPI MPI Punkt-zu-Punkt-Kommunikation. Oswald Haan ohaan@gwdg.de. Nachrichtenaustausch. Lokaler Speicher:. Daten : In lokale Speicherzellen. Daten : Aus lokalen Speicherzellen. Nachrichten- Inhalt :. Netz. Absender Empfänger
E N D
GWDG – KursParallelrechner-Programmierung mit MPIMPIPunkt-zu-Punkt-Kommunikation Oswald Haan ohaan@gwdg.de
Nachrichtenaustausch Lokaler Speicher: Daten : In lokale Speicherzellen Daten : Aus lokalen Speicherzellen Nachrichten-Inhalt : Netz Absender Empfänger Identifikation Größe : 3 kB Absender Empfänger Identifikation Größe : 3 kB Umschlag : Proz. 1 Proz. 2 Parallelrechner-Programmierung mit MPI
Blockierendes Senden: MPI_SEND MPI_SEND(buf, count, datatype, dest, tag, comm) IN bufinitialaddressof send buffer(choice) IN countnumberofelements in send buffer(non-negative integer) IN datatypedatatypeofeach send bufferelement (handle) IN dest rank ofdestination (integer) IN tag messagetag (integer) IN commcommunicator(handle) Parallelrechner-Programmierung mit MPI
Blockierendes Sendenmit mpi4py comm.Send(buf, dest = 0, tag = 0) IN commcommunicator(MPI comm) IN bufobjecttobesent (numpyarray) IN dest rank ofdestination (integer) IN tag messagetag (integer) comm.send(buf, dest = 0, tag = 0) IN commcommunicator (MPI comm) IN bufobjecttobesent (pythonobject) IN dest rank ofdestination (integer) IN tag message tag (integer) Parallelrechner-Programmierung mit MPI
MPI_SEND: Nachricht Die gesendete Nachricht besteht aus countaufeinanderfolgenden Speicherzellen, die jeweils ein Element vom Typ datatypeenthalten, beginnend bei der durch buf gegebenen Speicheradresse. Die Länge der Nachricht in Byte ist deshalb: count * Länge in Byte eines Elementes vom Typ datatype MPI Datentypen entsprechen den Standard-Datentypen von Fortran und C Zusätzliche Datentypen: MPI_BYTE ein Byte (uninterprätiert) MPI_PACKED mit MPI_PACK generiertes Datenpaket Implementationsabhängig können weitere Datentypen definiert sein Parallelrechner-Programmierung mit MPI
MPI-eigene Datentypen: Fortran MPI datatype Fortran datatype MPI_INTEGER INTEGER MPI_REAL REAL MPI_DOUBLE_PRECISION DOUBLE PRECISION MPI_LOGICAL LOGICAL MPI_CHARACTER CHARACTER MPI_COMPLEX COMPLEX Parallelrechner-Programmierung mit MPI
MPI-eigene Datentypen: C (Auswahl) MPI datatype C datatype MPI_INT signedint MPI_LONG signedlongint MPI_FLOAT float MPI_DOUBLE double MPI_LONG_DOUBLE longdouble MPI_CHAR char MPI_UNSIGNED unsignedint MPI_UNSIGNED_LONG unsignedlongint MPI_UNSIGNED_SHORT unsignedshortint MPI_UNSIGNED_CHAR unsignedchar Parallelrechner-Programmierung mit MPI
MPI-eigene Datentypen: mpi4py (Auswahl) MPI datatype mpi4py datatype MPI.INT signedint MPI.LONG signedlongint MPI.FLOAT float MPI.DOUBLE double MPI.LONG_DOUBLE longdouble MPI.CHAR char Parallelrechner-Programmierung mit MPI
MPI_SEND: Nachrichten-Umschlag Der Umschlag enthält die folgenden Informationen: Task-id (rank) des Senders, Task-id (rank) des Empfängers, Identifikationsnummer, Communicator Die Task-ID des Senders ist implizit durch den MPI_SEND aufrufenden Prozess gegeben, die anderen drei durch die Argumente dest, tag und comm des Aufrufs von MPI_SEND . Den Task-ids von Sender und Empfänger sind innerhalb des Communicators eindeutig zwei Prozesse zugeordnet, zwischen denen das System den Nachrichtenaustausch abwickelt Die vom Sender vergebene Identifikationsnummer kann vom Empfänger zur Unterscheidung verschiedener Nachrichten verwendet werden. 0tagMPI_TAG_UB Die in der MPI-Konstanten MPI_TAG_UB festgelegte obere Grenz für tag ist implementationsabhängig, auf jeden Fall aber mindestens 32767. Parallelrechner-Programmierung mit MPI
Blockierendes Empfangen: MPI_RECV MPI_RECV (buf, count, datatype, source, tag, comm, status) OUT buf initial address of receive buffer (choice) IN count number of elements in receive buffer (non-negative integer) IN datatypedatatypeof each receive buffer element (handle) IN source rank of source or MPI_ANY_SOURCE (integer) IN tag message tag or MPI_ANY_TAG (integer) IN comm communicator (handle) OUT status status object (Status) Parallelrechner-Programmierung mit MPI
Blockierendes Empfangenmit mpi4py comm.Recv(buf, source = 0, tag = 0, status = None) IN comm communicator (MPI comm) OUT buf object to be received (numpy array) IN source rank of source (integer) or MPI.ANY_SOURCE IN tag message tag (integer) or MPI.ANY_TAG OUT status status information (Status) buf = comm.recv(source = 0, tag = 0, status = None) IN comm communicator (MPI comm) OUT buf object to be received (python object) IN source rank of source (integer) or MPI.ANY_SOURCE IN tag message tag (integer) or MPI.ANY_TAG OUT status status information (Status) Parallelrechner-Programmierung mit MPI
MPI_RECV: Nachricht Die empfangene Nachricht wird abgespeichert auf count aufeinanderfolgenden Speicherzellen, die jeweils ein Element vom Typ datatypeerhalten, beginnend bei der durch buf gegebenen Speicheradresse. Die Länge der empfangenen Nachricht in Byte ist deshalb: count * Länge in Byte eines Elementes vom Typ datatype Die Länge der mit MPI_SEND gesendeten Nachricht darf die in MPI_RECV spezifizierte Länge der empfangenen Nachricht nicht überschreiten, sie kann aber kürzer sein. MPI_PROBE(source, tag, comm, status) mit identischen Argumenten wie MPI_RCV liefert über status Information über die zu empfangende Nachricht. Diese Information kann dann im eigentlichen MPI_RECV Aufruf verwendet werden, z.B. um einen genügend großen Empfangsbereich bereitzustellen Parallelrechner-Programmierung mit MPI
Das Argument status in MPI_RECV Eigenschaften der empfangenen Nachricht können unbekannt sein , wenn MPI_ANY_SOURCE als Wert für source MPI_ANY_TAG als Wert für tag gewählt wird und wenn die Länge der gesendeten Nachricht beim Empfänger nicht bekannt ist. Das Argument status stellt eine Struktur zur Verfügung, in der diese Eigenschaften hinterlegt sind. Die Abfrage des Status und der damit verbundene Aufwand wird vermieden, wenn als Argument für statusMPI_STATUS_IGNORE verwendet wird. In mpi4py ist dieses Verhalten voreingestellt, wenn die Variable statusnicht gesetzt wird. Parallelrechner-Programmierung mit MPI
Das Argument status in MPI_RECV C: Struktur FORTRAN: Feld MPI_Statusstatus integer status(MPI_STATUS_SIZE) status.MPI_SOURCEstatus(MPI_SOURCE) status.MPI_TAGstatus(MPI_TAG) status.MPI_ERRORstatus(MPI_ERROR) MPI_GET_COUNT(status, datatype, count) Berechnet aus den Anzahl der empfangenen Bytes die Zahl countder empfangenen Elemente vom Typ datatype Parallelrechner-Programmierung mit MPI
Das Argument status in mpi4py mpi4py: status ist Struktur vom Typ Status status = MPI.Status() source= status.Get_source() tag = status.Get_tag() error= status.Get_error() count= status.Get_elements(mpi_datentyp) size= status.Get_count() count: Anzahl empfangener Elemente vom Typ mpi_datentyp size: Größe des empfangenen Objekts in Byte Parallelrechner-Programmierung mit MPI
Nachricht vor Empfangen prüfen MPI_PROBE(MPI_ANY_SOURCE, MPI_ANY_TAG, comm, status) mpi4py: comm.Probe(source=MPI.ANY_SOURCE, tag=MPI.ANY_TAG, status=status) Parallelrechner-Programmierung mit MPI
Verschiedene Modi für blockierendes Senden Gepuffertes Senden: MPI_BSEND(sbuf,...Puffer-Initialisierung: MPI_BUFFER_ATTACH(temp,size)endet, wenn sbuf nach temp kopiert ist: lokale Operation Synchrones Senden: MPI_SSEND(sbuf,...Endet, wenn sbuf nach rbuf kopiert ist: nichlokaleOperation Sofortiges Senden: MPI_RSEND(sbuf,...Nur erlaubt, wenn MPI_RECV bereits gestartet ist Standard Implementierung: MPI_SEND(sbuf,...Kurze Nachrichten : in Puffer auf Empfängerseite Lange Nachrichten: synchrones Senden Aufruf von MPI_xSENDendet, wenn sbuf wieder verwendet werden kann Aufruf von MPI_RECV endet, wenn die Nachricht in rbuf abgespeichert ist. Parallelrechner-Programmierung mit MPI
Reihenfolge von Senden und Empfangen Mehrere Nachrichten werden in der Reihenfolge des Sendens empfangen: CALL MPI_COMM_RANK(comm, rank, ierr) IF (rank.EQ.0) THEN CALL MPI_SEND(buf1, count, MPI_INTEGER, 1, tag, comm, ierr) CALL MPI_SEND(buf2, count, MPI_REAL, 1, tag, comm, ierr) ELSE IF (rank.EQ.1) THEN CALL MPI_RECV(buf1, count, MPI_INTEGER, 0, tag, comm, status, ierr) CALL MPI_RECV(buf2, count, MPI_REAL, 0, tag, comm, status, ierr) END IF Parallelrechner-Programmierung mit MPI
Reihenfolge: garantierter Deadlock CALL MPI_COMM_RANK(comm, rank, ierr) IF (rank.EQ.0) THEN CALL MPI_RECV(recvbuf, count, MPI_REAL, 1, tag, comm, status, ierr) CALL MPI_SEND(sendbuf, count, MPI_REAL, 1, tag, comm, ierr) ELSE IF (rank.EQ.1) THEN CALL MPI_RECV(recvbuf, count, MPI_REAL, 0, tag, comm, status, ierr) CALL MPI_SEND(sendbuf, count, MPI_REAL, 0, tag, comm, ierr) END IF Parallelrechner-Programmierung mit MPI
Reihenfolge: möglicher Deadlock CALL MPI_COMM_RANK(comm, rank, ierr) IF (rank.EQ.0) THEN CALL MPI_SEND(sendbuf, count, MPI_REAL, 1, tag, comm, ierr) CALL MPI_RECV(recvbuf, count, MPI_REAL, 1, tag, comm, status, ierr) ELSE IF (rank.EQ.1) THEN CALL MPI_SEND(sendbuf, count, MPI_REAL, 0, tag, comm, ierr) CALL MPI_RECV(recvbuf, count, MPI_REAL, 0, tag, comm, status, ierr) END IF Deadlock, wenn die Nachricht auf Senderseite nicht gepuffert wird Parallelrechner-Programmierung mit MPI
Reihenfolge: garantiert kein Deadlock CALL MPI_COMM_RANK(comm, rank, ierr) IF (rank.EQ.0) THEN CALL MPI_SEND(sendbuf, count, MPI_REAL, 1, tag, comm, ierr) CALL MPI_RECV(recvbuf, count, MPI_REAL, 1, tag, comm, status, ierr) ELSE IF (rank.EQ.1) THEN CALL MPI_RECV(recvbuf, count, MPI_REAL, 0, tag, comm, status, ierr) CALL MPI_SEND(sendbuf, count, MPI_REAL, 0, tag, comm, ierr) END IF Zuerst: Nachricht Task 0 Task 1 Dann: Nachricht Task 1 Task 0 Parallelrechner-Programmierung mit MPI
MPI_SENDRECV : kein Deadlock MPI_SENDRECV(sendbuf, sendcount, sendtype, dest, sendtag, recvbuf, recvcount, recvtype,source, recvtag, comm, status) IN sendbufinitialaddressof send buffer(choice) IN sendcountnumberofelements in send buffer(non-negative integer) IN sendtype type ofelements in send buffer(handle) IN dest rank ofdestination (integer) IN sendtag send tag (integer) OUT recvbufinitialaddressofreceivebuffer(choice) IN recvcountnumberofelements in receivebuffer(non-negative integer) IN recvtype type ofelements in receivebuffer(handle) IN source rank ofsourceor MPI_ANY_SOURCE (integer) IN recvtagreceivetag or MPI_ANY_TAG (integer) IN commcommunicator(handle) OUT statusstatusobject (Status) Parallelrechner-Programmierung mit MPI
Sendrecv mit mpi4py comm.Sendrecv(sendbuf, dest=0, sendtag=0, recvbuf=None, source=0, recvtag=0, status=None) IN commcommunicator(MPI comm) IN sendbufobjecttobesent (numpyarray) IN dest rank ofdestination (integer) IN sendtag send tag (integer) OUT recvbufobjecttobereceived(numpyarray) IN source rank ofsource(integer) orMPI.ANY_SOURCE IN recvtagreceivetag (integer) orMPI.ANY_TAG OUT statusstatusinformation (Status) Parallelrechner-Programmierung mit MPI