1 / 30

Definiowanie typów danych użytkownika

Definiowanie typów danych użytkownika. Każdy typ danych w MPI jest określony przez tablice typemap podającą dla każdego elementu parami typ podstawowy i przesunięcie w bajtach Typemap={(type 0 ,disp 0 ),...,(type n-1 ,disp n-1 )} przykład MPI_INT (int,0).

damian
Download Presentation

Definiowanie typów danych użytkownika

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Definiowanie typów danych użytkownika Każdy typ danych w MPI jest określony przez tablice typemap podającą dla każdego elementu parami typ podstawowy i przesunięcie w bajtach Typemap={(type0,disp0),...,(typen-1,dispn-1)} przykład MPI_INT (int,0)

  2. Podstawowe typy danych w MPI: przypomnienie

  3. Definicje dolnej i górnej granicy oraz rozpietości i rozmiaru typu danych • lb(Typemap) = minj (dispj) • ub(Typemap) = maxj (dispj+sizeof(typej))+pad • extent(Typemap) = ub(Typemap)- lb(Typemap) „pad” określa poprawkę ze wzgędu na rozmieszczenie danych w pamięci komputera, w większosci przypadków wymagane jest aby dane określonego typu były umieszczone pod adresami będącymi wielokrotnością rozmiaru danego typu, np. int zajmuje 4 bajty więc adres powinien byc podzielny przez 4, więc dla {(int,0),(char,4)} lb=min(0,4)=0 ub=max(0+4,4+1)+pad=5+pad=8 extent=5+pad=8 rozmiar=5

  4. MPI_TYPE_EXTENT(datatype, extent) [ IN datatype] typ danych [ OUT extent] rozpiętość typu danych int MPI_Type_extent(MPI_Datatype datatype, MPI_Aint *extent) MPI_TYPE_EXTENT(DATATYPE, EXTENT, IERROR)INTEGER DATATYPE, EXTENT, IERROR MPI_TYPE_SIZE(datatype, size) [ IN datatype] typ danych [ OUT size] rozmiar typu danych w bajtach – ilość bajtow buforowanych/przesyłanych int MPI_Type_size(MPI_Datatype datatype, int *size) MPI_TYPE_SIZE(DATATYPE, SIZE, IERROR)INTEGER DATATYPE, SIZE, IERROR

  5. MPI_TYPE_LB( datatype, displacement) [ IN datatype] typ danych [ OUT displacement] pozycja dolnej granicy w bajtach względem początku obszaru danych int MPI_Type_lb(MPI_Datatype datatype, MPI_Aint* displacement) MPI_TYPE_LB( DATATYPE, DISPLACEMENT, IERROR)INTEGER DATATYPE, DISPLACEMENT, IERROR MPI_TYPE_UB( datatype, displacement) [ IN datatype] typ danych [ OUT displacement] pozycja górnej granicy w bajtach względem początku obszaru danych int MPI_Type_ub(MPI_Datatype datatype, MPI_Aint* displacement) MPI_TYPE_UB( DATATYPE, DISPLACEMENT, IERROR)INTEGER DATATYPE, DISPLACEMENT, IERROR

  6. MPI_ADDRESS(location, address) [ IN location] zmienna[ OUT address] adres zmiennej w bajtach int MPI_Address(void* location, MPI_Aint *address) MPI_ADDRESS(LOCATION, ADDRESS, IERROR)<type> LOCATION(*) INTEGER ADDRESS, IERROR Uwaga: integer w f77 jest 32bitowy i nie może reprezentować adresu dla maszyn 64bitowych integer ierror integer (kind=MPI_ADDRESS_KIND) iadd double precision a(10000) call MPI_Address( a, iadd, ierror)

  7. Tworzenie typów danych użytkownika • Contiguous - najprostszy typ pochodny; kolejne elementy są kopiami danego typu wejściowego a ich pozycje są wielokrotnościami jego rozpiętości. • Vector – elementy są kopiami danego typu wejściowego ale pomiędzy nimi występują odstępy będące wielokrotnościami rozpiętości tego typu. • Hvector – jak Vector ale odstępy między elementami są określone w bajtach. • Indexed– jak Vector ale odstępy między elementami są określone dowolnie przez tablicę przesunięć. • Hindexed – jak Indexed ale elementy tablicy przesunięć są podane w bajtach. • Struct - najbardzięj ogólny typ, elementy nie muszą być jednakowego typu a odstępy między nimi są określone przez tablicę przesunięć, której elementy są podane w bajtach.

  8. MPI_TYPE_CONTIGUOUS(count, oldtype, newtype) oldtype {(int,0),(double,8)} MPI_Type_contiguous (2, oldtype, &newtype) newtype {(int,0),(double,8),(int,16),(double,24)}

  9. MPI_TYPE_VECTOR(count, blocklength, stride, oldtype, newtype) MPI_TYPE_HVECTOR(count, blocklength, stride_bytes, oldtype, newtype)

  10. MPI_TYPE_INDEXED(count,array_of_blocklengths ,array_of_displacements, oldtype, newtype) MPI_TYPE_HINDEXED(count,array_of_blocklengths ,array_of_displacements_bytes, oldtype ,newtype)

  11. MPI_TYPE_STRUCT(count, array_of_blocklengths, array_of_displacements_bytes, array_of_types, newtype)

  12. Uaktywnienie nowozdefiniowanego typu MPI i zwalnianie typu: MPI_TYPE_COMMIT(type) MPI_TYPE_FREE(type) type – nowozdefiniowany lub zwalniany typ C: MPI_Type_commit(&type); MPI_Type_free(&type); MPI_TYPE type Fortran 77: CALL MPI_TYPE_COMMIT(TYPE,IERROR) CALL MPI_TYPE_FREE(TYPE,IERROR) INTEGER TYPE,IERROR

  13. Wprowadzania “przerw” między elementami typów od Vector włącznie: uwagi • Przerwy wskazują co jest pomijane podczas pakowania tablicy lub struktury do bufora. • W związku z powyższym, zdefiniowanie typu Vector umożliwia w Fortranie 77 przesłanie całej interesującej części tablicy w jednej instruktji (pamiętamy, że wymiary trzeba tam definiować zawsze “na wyrost”), natomiast HVector i Struct umożliwiają przesłanie wybranych elementów tablic, obszarów wspólnych i struktur bez pisania oddzielnego SEND i RECEIVE dla każdego z nich.

  14. przesyłanie górnego trójkąta macierzy NxN • double a[100][100] • disp[100], blocklenp[100],i; • MPI_Datatype upper; • for (i=0; i<100; ++i) { • disp[i] = 100 * i + i; • blocklen[i] = 100 - i; • } • MPI_Type_indexed(100, blocklen, disp, MPI_DOUBLE, &upper); • MPI_Type_commit(&upper); • .... • MPI_Send(a, 1, upper, dest, tag, MPI_COMM_WORLD);

  15. przesyłanie struktury • struct Partstruct • { char class; • double d[6]; • char b[7]; } • struct Partstruct particle[1000]; • int i,dest,rank; • MPI_Comm comm; • MPI_Datatype Particletype; • MPI_Datatype type[3] = {MPI_CHAR, MPI_DOUBLE, MPI_CHAR}; • int blocklen[3] = {1, 6, 7}; • /* double-word aligned */ • MPI_Aint disp[3] = {0, sizeof(double), 7*sizeof(double)}; • /* single-word aligned */ • MPI_Aint disp[3] = {0, sizeof(int), sizeof(int)+6*sizeof(double)}; • MPI_Type_struct(3, blocklen, disp, type, &Particletype); • MPI_Type_commit(&Particletype); • ... • MPI_Send(particle, 1000, Particletype, dest, tag, comm);

  16. przesyłanie struktury • struct Partstruct • { char class; • double d[6]; • char b[7]; } • struct Partstruct particle[1000]; • int i,dest,rank; • MPI_Comm comm; • MPI_Datatype Particletype; • MPI_Datatype type[3] = {MPI_CHAR, MPI_DOUBLE, MPI_CHAR}; • int blocklen[3] = {1, 6, 7}; • /* machine independency */ • MPI_Aint disp[3]; • MPI_Address(particle, &disp[0]); • MPI_Address(particle[0].d, &disp[1]); • MPI_Address(particle[0].b, &disp[2]); • for (i=2; i >=0; i--) • disp[i] -= disp[0]; • MPI_Type_struct(3, blocklen, disp, type, &Particletype); • MPI_Type_commit(&Particletype); • ... • MPI_Send(particle, 1000, Particletype, dest, tag, comm);

  17. przesyłanie zawartości COMMON • PARAMETER(NBLOCKS = 2) • INTEGER array_of_displacements(NBLOCKS) • INTEGER array_of_addresses(NBLOCKS) • INTEGER array_of_types(NBLOCKS) • INTEGER array_of_blocklenghts(NBLOCKS) • DOUBLE PRECISION results(RMAX) • PARAMETER (RMAX=3) • COMMON /resultPacket/ nResults, results • array_of_blocklenghts(1) = 1 • array_of_blocklenghts(2) = RMAX • CALL MPI_ADDRESS(nResults, array_of_addresses(1), ierr) • CALL MPI_ADDRESS(results, array_of_addresses(2), ierr) • array_of_displacements(1)=0 • array_of_displacements(2)=array_of_addresses(2)-array_of_addresses(1) • array_of_types(1) = MPI_INTEGER • array_of_types(2) = MPI_DOUBLE_PRECISION • CALL MPI_TYPE_STRUCT (NBLOCKS, • & array_of_blocklenghts, • & array_of_displacements, • & array_of_types, • & resultPacketType, ierr) • CALL MPI_TYPE_COMMIT (resultPacketType, ierr) • ... • count = 1 • CALL MPI_SSEND (nResults, count, resultPacketType, • & dest, tag, comm, ierr)

  18. Przykład przesyłania wybranych elementów tablicy struktur: przesyłanie informacji o cząsteczkach, które opuściły daną komórkę

  19. typedef struct{ double x,y,z; double mass; } Particle; Particle myparticles[MAX_PARTICLES], newparticles[MAX_PARTICLES]; MPI_Type_contiguous (4, MPI_DOUBLE,&particletype)MPI_Type commit(&particletype) n_to_move = 0; for (i=0;i<count;i++) { if (...particle exited cell...) { elmoffset[n_to_move] = i; elmsize[n_to_move] =1; n_to_move++; } } MPI_Type_indexed( n_to_move, elmsize, elmoffset, particletype, &sendtype); MPI_Type_commit (&sendtype); MPI_Send( myparticles,1,sendtype,dest,tag,comm); MPI_Type_free( &sendtype); .... MPI_Recv( newparticles,MAX_PARTICLES, particletype,source,tag,comm, &status); MPI_Get_count( &status, particletype, &number);

  20. Dynamiczna obsługa pamięci MPI_Probe( source, tag, comm, &status); MPI_Get_count( &status, particletype, &number); MPI_Type_extent( particletype, &extent); Newparticles = (Particle *)malloc( number * extend); MPI_Recv( newparticles, number, particletype, source, tag, comm, &status); Kompletny zestaw procedur w C do tworzenia, uaktualniania i przesyłania list cząstek

  21. Równoległy algorytm mnożenia macierzy (więcej w rozdziale 6.8 MPI: The Complete Reference)

  22. SUBROUTINE PMATMULT( A, B, C, n, p, comm) INTEGER n(3) REAL A(n(1),n(2)), B(n(2),n(3)), C(n(1),n(3)) INTEGER p(2) INTEGER comm INTEGER nn(2) REAL, ALLOCATABLE AA(:), BB(:), CC(:,:) INTEGER comm_2D, comm_1D(2), pcomm INTEGER coords(2) INTEGER rank INTEGER, ALLOCATABLE dispc(:), countc(:) INTEGER typea, typec, types(2), blen(2), disp(2) INTEGER ierr, i, j, k, sizeofreal LOGICAL periods(2), remains(2) CALL MPI_COMM_DUP( comm, pcomm, ierr) CALL MPI_BCAST( n, 3, MPI_INTEGER, 0, pcomm, ierr) CALL MPI_BCAST( p, 2, MPI_INTEGER, 0, pcomm, ierr) periods = (/ .FALSE., .FALSE./) CALL MPI_CART_CREATE( pcomm, 2, p, periods, .FALSE., comm_2D, ierr) CALL MPI_COMM_RANK( comm_2D, rank, ierr) CALL MPI_CART_COORDS( comm_2D, rank, 2, coords, ierr)

  23. ! compute communicators for subspaces DO i = 1, 2 DO j = 1, 2 remains(j) = (i.EQ.j) END DO CALL MPI_CART_SUB( comm_2D, remains, comm_1D(i), ierr) END DO nn(1) = n(1)/p(1) nn(2) = n(3)/p(2) ALLOCATE (AA(nn(1),n(2)), BB(n(2),nn(2)), CC(nn(1),nn(2)))

  24. IF (rank.EQ.0) THEN ! compute datatype for slice of A CALL MPI_TYPE_VECTOR( n(2), nn(1), n(1), MPI_REAL,types(1), ierr) ! and correct extent to size of subcolumn so that ! consecutive slices be "contiguous" CALL MPI_TYPE_EXTENT( MPI_REAL, sizeofreal, ierr) blen = (/ 1, 1 /) disp = (/ 0, sizeofreal*n(1) /) types(2) = MPI_UB CALL MPI_TYPE_STRUCT( 2, blen, disp, types, typea, ierr) CALL MPI_TYPE_COMMIT( typea, ierr) ! compute datatype for submatrix of C CALL MPI_TYPE_VECTOR( nn(2), nn(1), n(1), MPI_REAL,types(1), ierr) ! and correct extent to size of subcolumn CALL MPI_TYPE_STRUCT(2, blen, disp, types, typec, ierr) CALL MPI_TYPE_COMMIT(typec, ierr) ! compute number of subcolumns preceeding each successive ! submatrix of C. Submatrices are ordered in row-major ! order, to fit the order of processes in the grid. ALLOCATE (dispc(p(1)*p(2)), countc(p(1)*p(2))) DO i = 1, p(1) DO j = 1, p(2) dispc((i-1)*p(2)+j) = ((j-1)*p(1) + (i-1))*nn(2) countc((i-1)*p(2)+j) = 1 END DO END DO END IF

  25. ! 1. scatter row slices of matrix A on x axis IF (coords(2).EQ.0) THEN CALL MPI_SCATTER(A, 1, typea, AA, nn(1)*n(2), MPI_REAL, 0, comm_1D(1), ierr) END IF ! 2. scatter column slices of matrix B on y axis IF (coords(1).EQ.0) THEN CALL MPI_SCATTER(B, n(2)*nn(2), MPI_REAL, BB, n(2)*nn(2), MPI_REAL, 0, comm_1D(2), ierr) END IF ! 3. broadcast matrix AA in y dimension CALL MPI_BCAST(AA, nn(1)*n(2), MPI_REAL, 0, comm_1D(2)) ! 4. broadcast matrix BB in x dimension CALL MPI_BCAST(BB, n(2)*nn(2), MPI_REAL, 0, comm_1D(1)) ! 5. compute submatrix products DO j = 1, nn(2) DO i = 1, nn(1) CC(i,j) = 0 DO k = 1, n(2) CC(i,j) = CC(i,j) + AA(i,k)*BB(k,j) END DO END DO END DO

  26. ! 6. gather results from plane to node 0 CALL MPI_GATHERV( CC, nn(1)*nn(2),MPI_REAL, C, countc, dispc, typec, 0, comm_2D, ierr) DEALLOCATE(AA, BB, CC) MPI_COMM_FREE( pcomm, ierr) MPI_COMM_FREE( comm_2D, ierr) DO i = 1, 2 MPI_COMM_FREE( comm_1D(i), ierr) END DO IF (rank.EQ.0) THEN DEALLOCATE(countc, dispc) MPI_TYPE_FREE( typea, ierr) MPI_TYPE_FREE( typec, ierr) MPI_TYPE_FREE( types(1), ierr) END IF RETURN END

  27. Definiowanie, inicjalizacja i zwalnianie własnych operatorów dla MPI_REDUCE • MPI_Op_create (MPI_User_function *function, int commute, MPI_Op *op) • MPI_OP_CREATE (USER_FUNCTION, COMMUTE, OP, IERROR) • EXTERNAL USER_FUNCTION • LOGICAL COMMUTE • INTEGER OP, IERROR • typedef void MPI_User_function (void *invec, void *inoutvec, int *len, • MPI_Datatype *datatype); • FUNCTION USER_FUNCTION( INVEC(*), INOUTVEC(*), LEN, TYPE) • <type> INVEC(LEN), INOUTVEC(LEN) • INTEGER LEN, TYPE • MPI_op_free (MPI_Op *op) • MPI_OP_FREE (OP, IERROR)

  28. mnożenie liczb zespolonych • typedef struct { • double real,imag; • } Complex; • void myProd( Complex *in, Complex *inout, int *len, • MPI_Datatype *dtpr) • { • int i; • Complex c; • for (i=0; i< *len; i++) { • c.real = inout->real * in->real - • inout->imag * in->imag; • c.imag = inout->real * in->imag + • inout->imag * in->real; • *inout = c; • in++; inout++; • } • }

  29. Complex a[100], answer[100]; MPI_Op myOp; MPI_Datatype ctype; MPI_Type_contiguous( 2, MPI_DOUBLE, &ctype ); MPI_Type_commit( &ctype ); MPI_Op_create( myProd, True, &myOp ); MPI_Reduce( a, answer, 100, ctype, myOp, root,comm );

More Related