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)
Definicje dolnej i górnej granicy oraz rozpietości i rozmiaru typu danych lb(Typemap) = minj (dispj) ub(Typemap) = maxj (dispj+sizeof(typej))+pad extend(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 extend=5+pad=8 rozmiar=5
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
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
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_ADRESS_KIND) iadd double precision a(10000) call MPI_Adress( a, iadd, ierror)
Tworzenie typów danych użytkownika Contiguous - najprostszy typ pochodny, pozycje kolejnych takich samych elementów wyznaczone przez ich rozpietość Vector i Hvector - pozwala na określenie regularnych odstepów pomiędzy jednakowymi elementami jako wielokrotności rozpietości typu lub w bajtach Indexed i Hindexed - odstępy pomiędzy jednakowymi elementami są określone dowolnie przez tablice przesunięć Struct - najbardzięj ogólny typ, elementy nie musza być jednakowe, odstepy mogą być nieregularne
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)}
MPI_TYPE_VECTOR(count, blocklength, stride, oldtype, newtype) MPI_TYPE_HVECTOR(count, blocklength, stride_bytes,
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)
MPI_TYPE_STRUCT(count, array_of_blocklengths, array_of_displacements_bytes, array_of_types, newtype)
MPI_Type_indexed(100, blocklen, disp, MPI_DOUBLE, &upper); 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);
struct Partstruct particle[1000]; int i,dest,rank; MPI_Comm comm; 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);
struct Partstruct particle[1000]; int i,dest,rank; MPI_Comm comm; 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 independeny */ 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);
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(1) = 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)
Przesylanie wybranych elementow tablicy struktur
typedef struct{ double x,y,z; double mass; } Particle; Particle myparticles[MAX_PARTICLES], newparticles[MAX_PARTICLES]; MPI_Type_contiguous (4, MPI_DOUBLE,&particletype) MPI_Tupe 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);
Dynamiczna obsluga pamieci 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);
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)
void myProd( Complex *in, Complex *inout, int *len, 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++; }
Complex a[100], answer[100]; MPI_Op myOp; MPI_Datatype ctype; MPI_Type_contigous( 2, MPI_DOUBLE, &ctype ); MPI_Type_commit( &ctype ); MPI_Op_create( myProd, True, &myOp ); MPI_Reduce( a, answer, 100, ctype, myOp, root,comm );