Definiowanie typów danych użytkownika

30
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 )}

description

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). - PowerPoint PPT Presentation

Transcript of Definiowanie typów danych użytkownika

Page 1: 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={(type0,disp0),...,(typen-1,dispn-1)}

przykład MPI_INT (int,0)

Page 2: Definiowanie typów danych użytkownika

Podstawowe typy danych w MPI: przypomnienie

Page 3: Definiowanie typów danych użytkownika
Page 4: Definiowanie typów danych użytkownika

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

Page 5: Definiowanie typów danych użytkownika

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

Page 6: Definiowanie typów danych użytkownika

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

Page 7: Definiowanie typów danych użytkownika

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 ierrorinteger (kind=MPI_ADDRESS_KIND) iadddouble precision a(10000)call MPI_Address( a, iadd, ierror)

Page 8: Definiowanie typów danych użytkownika

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.

Page 9: Definiowanie typów danych użytkownika

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)}

Page 10: Definiowanie typów danych użytkownika

MPI_TYPE_VECTOR(count, blocklength, stride, oldtype, newtype)

MPI_TYPE_HVECTOR(count, blocklength, stride_bytes, oldtype, newtype)

                                                                           

Page 11: Definiowanie typów danych użytkownika

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)

                                                                          

Page 12: Definiowanie typów danych użytkownika

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

                                                                 

Page 13: Definiowanie typów danych użytkownika

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

Page 14: Definiowanie typów danych użytkownika

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.

Page 15: Definiowanie typów danych użytkownika

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);

Page 16: Definiowanie typów danych użytkownika

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);

Page 17: Definiowanie typów danych użytkownika

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);

Page 18: Definiowanie typów danych użytkownika

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)

Page 19: Definiowanie typów danych użytkownika

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

Page 20: Definiowanie typów danych użytkownika

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);

Page 23: Definiowanie typów danych użytkownika

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 commINTEGER nn(2)REAL, ALLOCATABLE AA(:), BB(:), CC(:,:)INTEGER comm_2D, comm_1D(2), pcommINTEGER coords(2)INTEGER rankINTEGER, 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)

Page 24: Definiowanie typów danych użytkownika

! 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)))

Page 25: Definiowanie typów danych użytkownika

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

Page 26: Definiowanie typów danych użytkownika

! 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 dimensionCALL 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

Page 27: Definiowanie typów danych użytkownika

! 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 IFRETURN END

Page 28: Definiowanie typów danych użytkownika

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)

Page 29: Definiowanie typów danych użytkownika

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++; }}

Page 30: Definiowanie typów danych użytkownika

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 );