26
Kolejność odbieranych wiadomości Zgodność typów przysyłanych danych MPI_BYTE też musi być zgodny u nadawcy i odbiorcy wyjątek MPI_PACKED automatyczna konwersja w środowisku heterogenicznym, ale nie zdefiniowana pomiędzy językami np. C-Fortran Zgodność identyfikatorów tag= 0...MPI_TAG_UB>=32767 Wielkość odbieranej wiadomości nie musi być zgodna z rozmiarem bufora odbiorcy (błąd w przypadku przepełnienia); MPI_PROBE pozwala sprawdzić wielkośćwiadomości bez jej odbierania

Kolejność odbieranych wiadomości

  • Upload
    fern

  • View
    38

  • Download
    2

Embed Size (px)

DESCRIPTION

Kolejność odbieranych wiadomości. Zgodność typów przysyłanych danych MPI_BYTE też musi być zgodny u nadawcy i odbiorcy wyjątek MPI_PACKED automatyczna konwersja w środowisku heterogenicznym, ale nie zdefiniowana pomiędzy językami np. C-Fortran Zgodność identyfikatorów - PowerPoint PPT Presentation

Citation preview

Page 1: Kolejność odbieranych wiadomości

Kolejność odbieranych wiadomości● Zgodność typów przysyłanych danych

– MPI_BYTE też musi być zgodny u nadawcy i odbiorcy – wyjątek MPI_PACKED– automatyczna konwersja w środowisku heterogenicznym, ale

nie zdefiniowana pomiędzy językami np. C-Fortran● Zgodność identyfikatorów

– tag= 0...MPI_TAG_UB>=32767● Wielkość odbieranej wiadomości nie musi być zgodna

z rozmiarem bufora odbiorcy (błąd w przypadku przepełnienia); MPI_PROBE pozwala sprawdzić wielkośćwiadomości bez jej odbierania

Page 2: Kolejność odbieranych wiadomości

Poprawny kod

CALL MPI_COMM_RANK(comm, rank, ierr) IF(rank.EQ.0) THEN

CALL MPI_SEND(a(1), 10, MPI_REAL, 1, tag, comm, ierr) ELSE

CALL MPI_RECV(b(1), 15, MPI_REAL, 0, tag, comm, status, ierr) END IF

Błędny kod

CALL MPI_COMM_RANK(comm, rank, ierr) IF(rank.EQ.0) THEN

CALL MPI_SEND(a(1), 10, MPI_REAL, 1, tag, comm, ierr) ELSE

CALL MPI_RECV(b(1), 40, MPI_BYTE, 0, tag, comm, status, ierr) END IF

Page 3: Kolejność odbieranych wiadomości

MPI_PACK i MPI_UNPACK

● Funkcja MPI_PACK umieszcza dane różnych typów w buforze zdefiniowanym przez użytkownika który pózniej można przesłać korzystając z typu MPI_PACKED

● Wiadomość o dowolnym typie można wysłać/odebrać korzystając z typu MPI_PACKED

● Funkcja MPI_UNPACK umieszcza odebrane dane typu MPI_PACKED w zmiennej określonego typu

Page 4: Kolejność odbieranych wiadomości

MPI_PACK(inbuf, incount, datatype, outbuf, outsize, position, comm)

[ IN inbuf] zmienna zawierając dane wejściowe [ IN incount] ilość danych wejsciowych[ IN datatype] typ danych wejściowych[ OUT outbuf] bufor danych [ IN outsize] rozmiar bufora danych w bajtach[ INOUT position] bierząca pozycja w buforze w bajtach [ IN comm] komunikator

int MPI_Pack(void* inbuf, int incount, MPI_Datatype datatype, void *outbuf, int outsize, int *position, MPI_Comm comm)

MPI_PACK(INBUF, INCOUNT, DATATYPE, OUTBUF, OUTSIZE, POSITION, COMM, IERROR)

<type> INBUF(*), OUTBUF(*)INTEGER INCOUNT, DATATYPE, OUTSIZE, POSITION, COMM, IERROR

Page 5: Kolejność odbieranych wiadomości

MPI_UNPACK(inbuf, insize, position, outbuf, outcount, datatype, comm)

[ IN inbuf] bufor zawierając dane wejściowe [ IN insize] rozmiar bufora w bajtach[ INOUT position] bierząca pozycja w buforze w bajtach [ OUT outbuf] zmienna dla danych wyjściowych[ IN outcount] ilość danych wyjściowych[ IN datatype] typ danych wyjściowych[ IN comm] komunikator

int MPI_Unpack(void* inbuf, int insize, int *position, void *outbuf, int outcount, MPI_Datatype datatype, MPI_Comm comm)

MPI_UNPACK(INBUF, INSIZE, POSITION, OUTBUF, OUTCOUNT, DATATYPE, COMM, IERROR)

<type> INBUF(*), OUTBUF(*) INTEGER INSIZE, POSITION, OUTCOUNT, DATATYPE, COMM, IERROR

Page 6: Kolejność odbieranych wiadomości

MPI_PACK_SIZE(incount, datatype, comm, size)

[ IN incount] ilość danych wejściowych dla MPI_PACK [ IN datatype] typ danych wejściowych [ IN comm] komunikator [ OUT size] potrzebny rozmiar bufora w MPI_PACK w bajtach

int MPI_Pack_size(int incount, MPI_Datatype datatype, MPI_Comm comm, int *size)

MPI_PACK_SIZE(INCOUNT, DATATYPE, COMM, SIZE, IERROR)INTEGER INCOUNT, DATATYPE, COMM, SIZE, IERROR

Page 7: Kolejność odbieranych wiadomości

int position, i, j, a[2]; char buff[1000]; .... MPI_Comm_rank(MPI_COMM_WORLD, &myrank); if (myrank == 0) {

/ * SENDER CODE */ position = 0; MPI_Pack(&i,1,MPI_INT,buff,1000,&position,MPI_COMM_WORLD); MPI_Pack(&j,1,MPI_INT,buff,1000,&position,MPI_COMM_WORLD); MPI_Send(buff, position, MPI_PACKED, 1, 0, MPI_COMM_WORLD); }

else /* RECEIVER CODE */

MPI_Recv( a, 2, MPI_INT, 0, 0, MPI_COMM_WORLD) }

Page 8: Kolejność odbieranych wiadomości

MPI_CHARACTER●W Fortranie ciąg znaków jest zmienna o stałej dlugości bez specjałnego znaku zakończenia

●MPI_CHARACTER odpowiada pojedynczemy znakowi a nie ciągowi znaków CHARACTER*n

CHARACTER*10 a CHARACTER*10 b CALL MPI_COMM_RANK(comm, rank, ierr) IF(rank.EQ.0) THEN

CALL MPI_SEND(a, 5, MPI_CHARACTER, 1, tag, comm, ierr)ELSE

CALL MPI_RECV(b(6:10), 5, MPI_CHARACTER, 0, tag, comm, status, ierr)

END IF

Page 9: Kolejność odbieranych wiadomości

Tryby i rodzaje komunikacji punktowej

– Standardowy (Standard) MPI_Send MPI_Isend

MPI_RecvMPI_Irecv

– Synchroniczny(Synchronous) MPI_Ssend MPI_Issend

– Buforowany (Buffered) MPI_Bsend MPI_Ibsend

– Gotowości (Ready) MPI_Rsend MPI_Irsend

Wstrzymująca(blocking)

Niewstrzymująca(nonblocking)

Rodzaje komunikacji

Tryby :

Page 10: Kolejność odbieranych wiadomości

● Działanie funkcji biblioteki MPI jest zdefiniowane przez specyfikację MPI Standard 1.1 i 2.0 a nie przez konkretną implementację

● Implementacje mogą się różnić w szczegółach nie zdefiniowanych przez MPI Standard, co pozwala na dostosowanie implementacji do sprzętu (np. MPICHG2 jest dostosowany do pracy w rozproszonym środowisku GRID)

● Nie należy korzystać z cech obecnych jedynie w konkretnej implementacji przy tworzeniu przenośnych kodów równoległych

Page 11: Kolejność odbieranych wiadomości

Tryb standardowy

● Specyfikacja nie definiuje czy komunikacja bedzie buforowana czy nie

● Charakter nielokalny - zakończenie może zależeć od odbiorcy

● Większość implementacji zapewnia buforowanie w zależności od rozmiaru wiadomości

● Przenośne programy nie powinny bazować na buforowaniu w trybie standardowym

Page 12: Kolejność odbieranych wiadomości

Tryb buforowany

● Bufor u nadawacy jest definiowany przez programistę MPI_BUFFER_ATTACH

● Charakter lokalny - zakończenie zależy jedynie od odbiorcy

● Może doprowadzić do podwójnego buforowania i związanych z tym dodatkowych operacji dostępu do pamięci

● MPI_PACK_SIZE + MPI_BSEND_OVERHEAD

Page 13: Kolejność odbieranych wiadomości

MPI_BUFFER_ATTACH( buffer, size) [ IN buffer] początkowy adres bufora[ IN size] rozmiar bufora w bajtach

int MPI_Buffer_attach( void* buffer, int size)

MPI_BUFFER_ATTACH( BUFFER, SIZE, IERROR)<type> BUFFER(*) INTEGER SIZE, IERROR

MPI_BUFFER_DETACH( buffer_addr, size) [ OUT buffer_addr] początkowy adres bufora[ OUT size] rozmiar bufora w bajtach

int MPI_Buffer_detach( void* buffer_addr, int* size)

MPI_BUFFER_DETACH( BUFFER_ADDR, SIZE, IERROR)<type> BUFFER_ADDR(*) INTEGER SIZE, IERROR

Page 14: Kolejność odbieranych wiadomości

Tryb synchroniczny

● Brak buforowania u nadawacy ● Charakter nielokalny - zakończenie zależy

zawsze od odbiorcy● Zakończenie działania u nadawcy gwarantuje że

odbiorca rozpoczął przyjmowanie wiadomości● W przypadku komunikacji blokującej u nadawcy

i odbiorcy zapewnia pełną synchronizację komunikacji

Page 15: Kolejność odbieranych wiadomości

Tryb gotowości

● Może się rozpocząć tylko jeśli odbiorca już czeka na wiadomość, w innym przypadku zachowanie jest nie zdefiniowane przez specyfikację

● Charakter lokalny - zakończenie operacji nie gwarantuje ze wiadomość jest odebrana

● Pozwala zaoszczędzić część operacji synchronizacji (handshaking)

● W poprawnym programie zastapienie MPI_Rsend przez MPI_Send nie powinno wpłynąć na efekt działania poza szybkością komunikacji

Page 16: Kolejność odbieranych wiadomości

Przykładowa implementacja

● Tryb gotowości - wysyłanie natychmiastowe● Tryb synchroniczny - nadawca wysyła najpierw

prośbę o potwierdzenie gotowości odbiorcy● Tryb standardowy - dla małych wiadomości

wysyłanie natychmiastowe z buforowaniem na poziomie sprzętu a dla większych jak w trybie synchronicznym

● Tryb buforowany - skopiowanie wiadomości do bufora i wykonanie wysyłania nieblokującego

Page 17: Kolejność odbieranych wiadomości

CALL MPI_COMM_RANK(comm, rank, ierr) IF (rank.EQ.0) THEN

CALL MPI_BSEND(buf1, count, MPI_REAL, 1, tag, comm, ierr) CALL MPI_BSEND(buf2, count, MPI_REAL, 1, tag, comm, ierr)

ELSE ! rank.EQ.1 CALL MPI_RECV(buf1, count, MPI_REAL, 0, MPI_ANY_TAG, comm,

status, ierr) CALL MPI_RECV(buf2, count, MPI_REAL, 0, tag, comm, status, ierr)

END IF

CALL MPI_COMM_RANK(comm, rank, ierr) IF (rank.EQ.0) THEN

CALL MPI_BSEND(buf1, count, MPI_REAL, 1, tag1, comm, ierr) CALL MPI_SSEND(buf2, count, MPI_REAL, 1, tag2, comm, ierr)

ELSE ! rank.EQ.1 CALL MPI_RECV(buf1, count, MPI_REAL, 0, tag2, comm, status, ierr) CALL MPI_RECV(buf2, count, MPI_REAL, 0, tag1, comm, status, ierr)

END

Page 18: Kolejność odbieranych wiadomości

include 'mpif.h' integer ierr,rank,size,req(4),stat(MPI_STATUS_SIZE) integer i,n double precision pi parameter(pi=3.1415, n=10) double precision x(n),dx,y(n),right,left

call MPI_INIT( ierr ) call MPI_COMM_RANK( MPI_COMM_WORLD, rank, ierr ) call MPI_COMM_SIZE( MPI_COMM_WORLD, size, ierr )

dx=2*pi/(n*size) do i=1,n x(i)=cos(n*dx*rank+i*dx) enddo

iright=mod(size+rank+1,size) ileft=mod(size+rank-1,size)

call MPI_SEND(x(1),1,MPI_DOUBLE_PRECISION, ileft, & 1, MPI_COMM_WORLD, ierr) call MPI_SEND(x(n),1,MPI_DOUBLE_PRECISION, iright, & 1, MPI_COMM_WORLD, ierr) call MPI_RECV(left,1,MPI_DOUBLE_PRECISION, ileft, & 1, MPI_COMM_WORLD, stat, ierr) call MPI_RECV(right,1,MPI_DOUBLE_PRECISION, iright, & 1, MPI_COMM_WORLD, stat, ierr)

do i=2,n-1 y(i)=(x(i-1)-2*x(i)+x(i+1))/(dx*dx) enddo

y(1)=(left-2*x(1)+x(2))/(dx*dx) y(n)=(x(n-1)-2*x(n)+right)/(dx*dx)

do i=1,n print *,rank,n*dx*rank+i*dx,x(i),y(i) enddo

call MPI_FINALIZE(ierr) stop end

Pierwsza wersja kodu równoległego – prosta ale nie spełnia wymogów bezpieczeństwa- opiera się na buforowaniu dwu instrukcji MPI_SEND

Page 19: Kolejność odbieranych wiadomości

double precision x(n),dx,y(n),right,left,bufor(100).....

call MPI_BUFFER_ATTACH(bufor,100,ierr)..... call MPI_BSEND(x(n),1,MPI_DOUBLE_PRECISION, iright, & 1, MPI_COMM_WORLD, ierr)

call MPI_BSEND(x(1),1,MPI_DOUBLE_PRECISION, ileft, & 1, MPI_COMM_WORLD, ierr)

call MPI_RECV(left,1,MPI_DOUBLE_PRECISION, ileft, & 1, MPI_COMM_WORLD, stat, ierr)

call MPI_RECV(right,1,MPI_DOUBLE_PRECISION, iright, & 1, MPI_COMM_WORLD, stat, ierr)

Wersja bezpieczna – buforowanie danych w MPI_BSEND

Page 20: Kolejność odbieranych wiadomości

call MPI_SSEND(x(n),1,MPI_DOUBLE_PRECISION, iright, & 1, MPI_COMM_WORLD, ierr) call MPI_RECV(left,1,MPI_DOUBLE_PRECISION, ileft, & 1, MPI_COMM_WORLD, stat, ierr) call MPI_SSEND(x(1),1,MPI_DOUBLE_PRECISION, ileft, & 1, MPI_COMM_WORLD, ierr) call MPI_RECV(right,1,MPI_DOUBLE_PRECISION, iright, & 1, MPI_COMM_WORLD, stat, ierr)

Wersja bardziej bezpieczna – odpowiednia kolejność wysyłania i odbioru lecz nie zadziała w trybie synchronicznym (deadlock)

Page 21: Kolejność odbieranych wiadomości

if (mod(rank,2).eq.0) then call MPI_SSEND(x(n),1,MPI_DOUBLE_PRECISION, iright, & 1, MPI_COMM_WORLD, ierr) call MPI_RECV(left,1,MPI_DOUBLE_PRECISION, ileft, & 1, MPI_COMM_WORLD, stat, ierr) call MPI_SSEND(x(1),1,MPI_DOUBLE_PRECISION, ileft, & 1, MPI_COMM_WORLD, ierr) call MPI_RECV(right,1,MPI_DOUBLE_PRECISION, iright, & 1, MPI_COMM_WORLD, stat, ierr)else call MPI_RECV(left,1,MPI_DOUBLE_PRECISION, ileft, & 1, MPI_COMM_WORLD, stat, ierr) call MPI_SSEND(x(n),1,MPI_DOUBLE_PRECISION, iright, & 1, MPI_COMM_WORLD, ierr) call MPI_RECV(right,1,MPI_DOUBLE_PRECISION, iright, & 1, MPI_COMM_WORLD, stat, ierr) call MPI_SSEND(x(1),1,MPI_DOUBLE_PRECISION, ileft, & 1, MPI_COMM_WORLD, ierr)endif

Page 22: Kolejność odbieranych wiadomości

Tryb gotowości

Page 23: Kolejność odbieranych wiadomości

Gorąca linia (persistent communication)

● Pozwala na dodatkową optymalizację przesyłania danych jeśli lista argumentów jest taka sama

● Rozdzielenie inicjalizacji gorącej linii (funkcja MPI_SEND_INIT i MPI_RECV_INIT) od samego przesyłania danych MPI_START

● Wyłączenie gorącej linii (MPI_REQUEST_FREE) jest możliwe po zakończeniu komunikacji

● Możliwe jest użycie różnych trybów komunikacji ● Gorąca może współpracować ze zwyczajnymi

instrukcjami komunikacji punktowej

Page 24: Kolejność odbieranych wiadomości

MPI_SEND_INIT(buf, count, datatype, dest, tag, comm, request) [ IN buf] zmienna do wysłania [ IN count] ilość elementów do wysłania [ IN datatype] typ elementów [ IN dest] odbiorca [ IN tag] identyfikator wiadomości [ IN comm] komunikator [ OUT request] wskaźnik pozwalający na dowołanie się do tej instrukcji

int MPI_Send_init(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request)

MPI_SEND_INIT(BUF, COUNT, DATATYPE, DEST, TAG, COMM, REQUEST, IERROR)<type> BUF(*) INTEGER REQUEST, COUNT, DATATYPE, DEST, TAG, COMM, REQUEST, IERROR

Page 25: Kolejność odbieranych wiadomości

MPI_RECV_INIT( buf, count, datatype, source, tag, comm, request) [ OUT buf] zmienna dla odbieranych danych [ IN count] ilość elementów [ IN datatype] typ danych [ IN source] nadawca[ IN tag] identyfikator wiadomości [ IN comm] komunikator [ OUT request] wskaźnik pozwalający na dowołanie się do tej instrukcji

int MPI_Recv_init(void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request)

MPI_RECV_INIT(BUF, COUNT, DATATYPE, SOURCE, TAG, COMM, REQUEST, IERROR)<type> BUF(*) INTEGER COUNT, DATATYPE, SOURCE, TAG, COMM, REQUEST, IERROR

Page 26: Kolejność odbieranych wiadomości

MPI_START(request) [ INOUT request] wskaźnik do instrukji inicjalizującej gorąca linię

int MPI_Start(MPI_Request *request)

MPI_START(REQUEST, IERROR)INTEGER REQUEST, IERROR

MPI_STARTALL( count, array_of_requests) [ IN count] wielkość tablicy ze wskaźnikami [ INOUT array_of_requests] tablica ze wskaźnik do instrukji

inicjalizującej gorąca linię

int MPI_Startall(int count, MPI_Request *array_of_requests)

MPI_STARTALL(COUNT, ARRAY_OF_REQUESTS, IERROR)INTEGER COUNT, ARRAY_OF_REQUESTS(*), IERROR