30
Komunikacja zbiorowa – część I Komunikacja zbiorowa: przesyłanie danych pomiędzy wszystkimi procesorami grupy zdefiniowanymi przez dany komunikator. Typy komunikacji zbiorowej: 1. Bariera (synchronizacja). 2. Globalna wymiana danych. 3. Globalne operacje redukcji. Szczegółowy opis procedur komunikacji zbiorowej można znaleźć w książce „MPI - the complete reference” pod adresem http://www.netlib.org/utk/papers/mpi-book/node 91.html

Komunikacja zbiorowa – część I

  • Upload
    fell

  • View
    32

  • Download
    0

Embed Size (px)

DESCRIPTION

Komunikacja zbiorowa – część I Komunikacja zbiorowa: przesyłanie danych pomiędzy wszystkimi procesorami grupy zdefiniowanymi przez dany komunikator. Typy komunikacji zbiorowej : Bariera (synchronizacja). Globalna wymiana danych. Globalne operacje redukcji . - PowerPoint PPT Presentation

Citation preview

Page 1: Komunikacja zbiorowa  – część I

Komunikacja zbiorowa – część I

Komunikacja zbiorowa: przesyłanie danych pomiędzy wszystkimi procesorami grupy zdefiniowanymi przez dany komunikator.

Typy komunikacji zbiorowej:

1. Bariera (synchronizacja).

2. Globalna wymiana danych.

3. Globalne operacje redukcji.

Szczegółowy opis procedur komunikacji zbiorowej można znaleźć w książce „MPI - the complete reference” pod adresem http://www.netlib.org/utk/papers/mpi-book/node91.html

Page 2: Komunikacja zbiorowa  – część I

Bariera

Bariera: synchronizacja wszystkich procesorów grupy (MPI_BARRIER).

Składnia procedury MPI_BARRIER w C i Fortranie 77:

MPI_Barrier(MPI_Comm comm)

MPI_BARRIER(COMM, IERROR)

INTEGER COMM, IERROR

comm - komunikator

Page 3: Komunikacja zbiorowa  – część I

Globalna wymiana danych:

Broadcast: rozesłanie wiadomości przez jeden procesor (root) do pozostałych procesorów grupy (MPI_BCAST).

Gather: zebranie wiadomości przez jeden procesor (root) od wszystkich procesorów grupy (MPI_GATHER, MPI_GATHERV).

Scatter: rozproszenie danych od jednego procesora (roota) do wszystkich elementów grupy (MPI_SCATTER, MPI_SCATTERV).

Allgather: każdy procesor zbiera wiadomości od pozostałych procesorów grupy (MPI_ALLGATHER, MPI_ALLGATHERV).

All-to-all (all-scatter-all-gather): każdy procesor rozprasza swoje dane do wszystkich procesorów grupy i zbiera wiadomości od wszystkich procesorów grupy (MPI_ALLTOALL, MPI_ALLTOALLV).

Page 4: Komunikacja zbiorowa  – część I
Page 5: Komunikacja zbiorowa  – część I

Składnia procedury MPI_BCAST w C i Fortranie 77:

MPI_Bcast(void* buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm )

MPI_BCAST(BUFFER, COUNT, DATATYPE, ROOT, COMM, IERROR) <type> BUFFER(*) INTEGER COUNT, DATATYPE, ROOT, COMM, IERROR

buffer - początkowy adres bufora transmitowanych danychcount - liczba transmitowanych elementów danychdatatype - identyfikator typu transmitowanych danych (w sensie MPI)root - rząd (numer) procesora, który rozsyła danecomm - komunikator.

Page 6: Komunikacja zbiorowa  – część I

Przykład (C): rozesłanie przez procesor 0 tablicy 100 liczb całkowitych:

MPI_Comm comm; int array[100]; int root=0; ...MPI_Bcast( array, 100, MPI_INT, root, comm);

Przykład (Fortran): rozsyłanie rozkazu oraz danych do „robotników” przez „nadzorcę”:

subroutine func1(n,What,x,zz,obf,obg)...integer Whatdouble precision x(n)...call MPI_Bcast( What, 1, MPI_INTEGER, Master, Comm1, IERROR)call MPI_Bcast(x(1),n,MPI_DOUBLE_PRECISION, Master, Comm1, IERROR)if (What.le.0) return

Page 7: Komunikacja zbiorowa  – część I

Składnia procedur MPI_GATHER w C i Fortranie 77:

MPI_Gather(void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm)

MPI_GATHER(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR) <type> SENDBUF(*), RECVBUF(*) INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR

sendbuf - początkowy adres bufora transmitowanych danych

recvbuf - początkowy adres bufora przyjmowanych danych

sendcount, sendcounts - liczba wysyłanych elementów danych (w przypadku MPI_Gatherv jest to tablica)

recvcount, recvcounts - liczba przyjmowanych elementów danych (w przypadku MPI_Gatherv jest to tablica)

sendtype - identyfikator typu wysyłanych danych (w sensie MPI)

recvtype - identyfikator typu przyjmowanych danych (w sensie MPI)

root - rząd (numer) procesora, który przyjmuje dane

comm - komunikator.

Page 8: Komunikacja zbiorowa  – część I

Efekt działania MPI_Gather dla układu n procesorów można przedstawić jako wykonanie instrukcji MPI_Send przez każdy procesor (łącznie z rootem) a następnie przyjęcie przez root danych od kolejnych procesorów (łącznie z sobą samym) w ten sposób, że dane zawarte w buforze procesora pierwszego są lokowane na początku bufora przyjmującego, dane pochodzące od procesora drugiego są w buforze przyjmującym przesunięte o RECVCOUNT, itd.:

Page 9: Komunikacja zbiorowa  – część I

Oddzielna specyfikacja dla SENDCOUNT i SENDTYPE oraz RECVCOUNT i RECVTYPE umożliwia inną specyfikację danych dla roota a inną dla pozostałych procesorów; należy jednak pamiętać, że całkowita długość SENDBUF musi się zgadzać z długością części RECVBUF, do której root przyjmuje te dane.

Przykład: zebranie przez procesor 0 (root) tablicy 100 liczb całkowitych od każdego procesora:

integer comm, gsize, sendarray(100)integer root, rbuf(100*MaxProcs) ... call MPI_Comm_size(comm, gsize)call MPI_Gather( sendarray, 100, MPI_INT, rbuf, 100, MPI_INT, root, comm)

Page 10: Komunikacja zbiorowa  – część I

Składnia procedur MPI_GATHER w C i Fortranie 77:

MPI_Gatherv(void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int *recvcounts, int *displs, MPI_Datatype recvtype, int root, MPI_Comm comm)

MPI_GATHERV(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNTS, DISPLS, RECVTYPE, ROOT, COMM, IERROR) <type> SENDBUF(*), RECVBUF(*) INTEGER SENDCOUNT, SENDTYPE, RECVCOUNTS(*), DISPLS(*), RECVTYPE, ROOT, COMM, IERROR

recvcounts - tablica zawierająca liczbę elementów danych przyjmowanych od poszczególnych procesorów

displs - tablica zawierająca przesunięcia porcji danych przyjmowanych od poszczególnych procesorów w buforze przyjmującym.

Page 11: Komunikacja zbiorowa  – część I

Przykład: Zbieranie przez „nadzorcę” od „robotników” wyliczonych przez nich części energii struktur:

ii=0do i=indstart(me),indend(me)

ii=ii+1call restore_coords(iprot,ii)call chainbuildcall etotal(energia(0))enetb(i,0)=energia(0)

enddo...if (What.eq.2) then

call MPI_Gatherv(enetb(indstart(me),0), scount(me),MPI_DOUBLE_PRECISION,

enetb(1,0),scount(0),idispl(0),MPI_DOUBLE_PRECISION,Master,Comm1, IERROR)

endif

Page 12: Komunikacja zbiorowa  – część I

Składnia procedur MPI_SCATTER, MPI_ALLGATHER i MPI_ALLTOALL w C i Fortranie 77

MPI_Scatter(void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm)

MPI_SCATTER(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR) <type> SENDBUF(*), RECVBUF(*) INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR

MPI_Allgather(void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm)

MPI_ALLGATHER(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT, RECVTYPE, COMM, IERROR) <type> SENDBUF(*), RECVBUF(*) INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE, COMM, IERROR

MPI_Alltoall(void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm)

MPI_ALLTOALL(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT, RECVTYPE, COMM, IERROR) <type> SENDBUF(*), RECVBUF(*) INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE, COMM, IERROR

Page 13: Komunikacja zbiorowa  – część I

Globalne operacje redukcji

Redukcja: Wykonywanie danej operacji (np. dodawania) na grupie danych zebranych od wszystkich procesorów. Wynik jest zwracany albo do jednego procesora (roota; zwykła redukcja) albo do wszystkich (allreduce) (MPI_REDUCE, MPI_ALLREDUCE).

Redukcja z rozproszeniem wyników (MPI_REDUCE_SCATTER).

Redukcja „od procesorów wstecz” (MPI_SCAN).

Page 14: Komunikacja zbiorowa  – część I
Page 15: Komunikacja zbiorowa  – część I

Globalne operatory redukcji

MPI_MAX maksimum

MPI_MIN minimum

MPI_SUM suma

MPI_PROD iloczyn

MPI_LAND logiczne „and”

MPI_BAND bitowe „and”

MPI_LOR logiczne „or”

MPI_BOR bitowe „or”

MPI_LXOR logiczne „xor”

MPI_BXOR bitowe „xor”

MPI_MAXLOC maksimum oraz jego położenie

MPI_MINLOC minimum oraz jego położenie

Użytkownik może również definiować własne operatory redukcji, za pomocą funkcji MPI_OP_CREATE.

Page 16: Komunikacja zbiorowa  – część I

Składnia procedury MPI_REDUCE w C i Fortranie 77

MPI_Reduce(void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm)

MPI_REDUCE(SENDBUF, RECVBUF, COUNT, DATATYPE, OP, ROOT, COMM, IERROR) <type> SENDBUF(*), RECVBUF(*) INTEGER COUNT, DATATYPE, OP, ROOT, COMM, IERROR

sendbuf - adres buforu wysyłanych danych

recvbuf - adres bufora przechowującego wynik operacji redukcji

count - liczba wysyłanych przez każdy procesor elementów danych

datatype - identyfikator typu wysyłanych/przyjmowanych danych

op - identyfikator operacji redukcji

root - rząd (numer) roota

comm - komunikator

Page 17: Komunikacja zbiorowa  – część I

Przykład: obliczanie iloczynu skalarnego dwóch wektorów. Poszczególne m-elementowe części wektorów zostały już wcześniej rozprowadzone pomiędzy procesory:

SUBROUTINE PAR_BLAS1(m, a, b, c, comm)REAL a(m), b(m) ! zawieraja czesci wektorow a i b ! przypisane danemu procesorowi REAL c ! wynik (otrzymany przez procesor 0 - root) REAL sum ! suma czastkowa dla kazdego procesora INTEGER m, comm, i, ierr

! suma czastkowa dla danego procesora sum = 0.0 DO i = 1, m

sum = sum + a(i)*b(i) ENDDO

! obliczanie sumy calkowitej przez procesor 0 CALL MPI_REDUCE(sum, c, 1, MPI_REAL, MPI_SUM, 0, comm, ierr) RETURN END

Page 18: Komunikacja zbiorowa  – część I

Składnia procedur MPI_ALLREDUCE, MPI_REDUCE_SCATTER i MPI_SCAN w C i Fortranie 77

MPI_Allreduce(void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)

MPI_ALLREDUCE(SENDBUF, RECVBUF, COUNT, DATATYPE, OP, COMM, IERROR)<type> SENDBUF(*), RECVBUF(*) INTEGER COUNT, DATATYPE, OP, COMM, IERROR

MPI_Reduce_scatter(void* sendbuf, void* recvbuf, int *recvcounts, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)

MPI_REDUCE_SCATTER(SENDBUF, RECVBUF, RECVCOUNTS, DATATYPE, OP, COMM, IERROR)<type> SENDBUF(*), RECVBUF(*) INTEGER RECVCOUNTS(*), DATATYPE, OP, COMM, IERROR

MPI_Scan(void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm )

MPI_SCAN(SENDBUF, RECVBUF, COUNT, DATATYPE, OP, COMM, IERROR) <type> SENDBUF(*), RECVBUF(*) INTEGER COUNT, DATATYPE, OP, COMM, IERROR

Page 19: Komunikacja zbiorowa  – część I

Przykład użycia procedury MPI_REDUCESCATTER

Rozproszone obliczanie iloczynu wektora a przez macierz b z dystrybucją wynikowego wektora c pomiędzy procesory:

b a = c

Page 20: Komunikacja zbiorowa  – część I

Macierz b oraz wektor a są podzielone pomiędzy procesory na odpowiadające sobie ,,plasterki''. Każdy procesor oblicza wkład do elementów wektora wynikowego odpowiadający swoim danym. Następnie przy pomocy procedury MPI_REDUCESCATTER wkłady te są sumowane a wynikowy wektor c jest dystrybuowany pomiędzy procesory.

Page 21: Komunikacja zbiorowa  – część I

subroutine matvec( n, m, lmatrix, lx, ly, counts, comm )use mpiinteger n, m, comm, counts(*)real lmatrix(n,m), lx(m), ly(m)integer i, jreal sumreal, allocatable :: tmp(:)allocate (tmp(n))! Perform the local matrix-vector multiply! Should use the level-2 BLAS routine SGEMVdo i=1,n sum = 0 do j=1,m sum = sum + lmatrix(i,j)*lx(j) enddo tmp(i) = sumenddo! Perform the local matrix-vector productcall MPI_REDUCE_SCATTER( tmp, ly, counts, MPI_REAL, MPI_SUM, comm, ierr)deallocate (tmp)! We're done!end

Kod źródłowy (Fortran90)

Page 22: Komunikacja zbiorowa  – część I

Kompletny przykladowy program (FORTRAN 77)

Wyniki (2 procesory)

Page 23: Komunikacja zbiorowa  – część I

Przykład programu wykorzystującego procesury komunikacji zbiorowej: obliczanie liczby przez całkowanie numeryczne

dxx

1

021

14)1arctan(4

n

ii

n

i

fn

nin 11

2

4

5.01

14

Ilustracja przybliżonego obliczania liczby p przez całkowanie numeryczne dla liczby przedziałów n=10.

Page 24: Komunikacja zbiorowa  – część I

Zrównoleglenie algorytmu

1. Przedział całkowania dzieli się na n części: 1, 2,..., n

2. W układzie m procesorów, procesor 1 sumuje wkłady dla części 1, m+1, procesor 2 dla 2, m+2itd.

3. Procesory przesyłają swoje obliczone cząstkowe sumy do mastera, który oblicza sumę całkowitą.

Źródło programu w CŹrodło programu w Fortranie77

Page 25: Komunikacja zbiorowa  – część I

Wyniki (4 procesory)

adaml@galera ~/MPI/scali > mpirun -np 4 pif/opt/scali/bin/mpimon -stdin all pif -- gal72 1 gal71 1 gal65 1 gal64 1Enter the number of intervals: (0 quits)100 Processor 1 mypi 0.7879260283629753 Processor 0 mypi 0.7928763409009609 Processor 3 mypi 0.7778741525634217 Processor 2 mypi 0.7829244650957667 pi is approximately: 3.1416009869231250 Error is: 0.0000083333333314Enter the number of intervals: (0 quits)0FORTRAN STOPFORTRAN STOPFORTRAN STOPFORTRAN STOP

Page 26: Komunikacja zbiorowa  – część I

OPERATORY MIN_LOCK i MAX_LOCK

Te operatory redukcji służą do wyszukania minimalnych (maksymalnych) wartości rozproszonych danych oraz odpowiadających im indeksów (np. indeks może być rzędem procesora). Bufor danych musi być wtedy strukturą zawierającą zarówno porównywane wartości, jak i stowarzyszone z nimi indeksy, np.

proc1 x1 ind1 x2 ind2 x3 ind3proc2 x1 ind1 x2 ind2 x3 ind3proc3 x1 ind1 x2 ind2 x3 ind3proc4 x1 ind1 x2 ind2 x3 ind3

x1min ind1min x2min ind2min x3min ind3min

Page 27: Komunikacja zbiorowa  – część I

W celu stworzenia bufora danych o strukturze jak podanej tabeli w MPI zdefiniowano następujące złożone typy danych:

MPI_FLOAT_INT float+int

MPI_DOUBLE_INT double+int

MPI_LONG_INT long+int

MPI_2INT int+int

MPI_SHORT_INT short+int

MPI_LONG_DOUBLE long+double

C:

FORTRAN:

MPI_2REAL 2*REAL

MPI_2DOUBLEPRECISION 2*DOUBLE PRECISION

MPI_2INTEGER 2*INTEGER

Page 28: Komunikacja zbiorowa  – część I

W przypadku FORTRANu indeks ma typ zgodny z typem danych, w zbiorze których jest wyszukiwane minimum/maksimum. Jest to spowodowane brakiem typów złożonych w standarcie FORTRANu 77. Aby w tym przypadku posługiwać się parami dana-indeks jak w C należy zdefiniować własne operatory i typy danych.

Definicja typu MPI_2REAL oraz MPI_FLOAT_INT:

FORTRANcall MPI_TYPE_CONTIGUOUS(2, MPI_REAL, MPI_2REAL)

Ctype[0] = MPI_FLOATtype[1] = MPI_INTdisp[0] = 0disp[1] = sizeof(float)block[0] = 1block[1] = 1MPI_TYPE_STRUCT(2, block, disp, type, MPI_FLOAT_INT)

Page 29: Komunikacja zbiorowa  – część I

Przykład programu wykorzystującego operator MAX_LOC

Każdy procesor wypełnia tablicę 10 liczb podwójnej precyzji, zgodnie z następującą formułą:

A[i] = sin(rank*i), i=1,2,...10

gdzie rank jest rzędem procesora. Następnie jest wyszukiwana największa wartość danego elementu tablicy po wszystkich procesorach oraz rząd odpowiadającego jej procesora. Wielkości te są zbierane przez procesor o rzędzie 0.

Źródło programu w CŹródło programu w FORTRANie 77

Page 30: Komunikacja zbiorowa  – część I

/opt/scali/bin/mpimon -stdin all maxloc -- gal72 1 gal71 1 gal65 1 gal64 1

1 0 0.00000 1 1 0.84147 1 2 0.90930 1 3 0.1411 2 0 0.00000 2 1 0.90930 2 2 -0.75680 2 3 -0.2794 3 0 0.00000 3 1 0.14112 3 2 -0.27942 3 3 0.4121 4 0 0.00000 4 1 -0.75680 4 2 0.98936 4 3 -0.5365 5 0 0.00000 5 1 -0.95892 5 2 -0.54402 5 3 0.6502 6 0 0.00000 6 1 -0.27942 6 2 -0.53657 6 3 -0.7509 7 0 0.00000 7 1 0.65699 7 2 0.99061 7 3 0.8366 8 0 0.00000 8 1 0.98936 8 2 -0.28790 8 3 -0.9055 9 0 0.00000 9 1 0.41212 9 2 -0.75099 9 3 0.9563 10 0 0.00000 10 1 -0.54402 10 2 0.91295 10 3 -0.9880

i 1 ind 2 value 0.90930i 2 ind 1 value 0.90930i 3 ind 3 value 0.41212i 4 ind 2 value 0.98936i 5 ind 3 value 0.65029i 6 ind 0 value 0.00000i 7 ind 2 value 0.99061i 8 ind 1 value 0.98936i 9 ind 3 value 0.95638i 10 ind 2 value 0.91295

Wyniki (4 procesory)