Multiplicação Matriz-Vector Solução II Yi = Aij Xj N > A divida por colunas ( N/P multiplicações + (N/P-1) somas ) Soma Colectiva > X dividido por blocos N = k*P Y calculado em ~ 2N2 Tvf / P = 0 1 2 3 4 + comunicações Exercício Implemente a multiplicação de uma matriz por um vector usando a decomposição discutida no slide anterior. int MPI_Allreduce ( void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm ) Tipos Básicos pré-definidos Derived Data Types M P I_ B Y T E M P I_ C H A R.............................s ig n e dc h a r M P I_ D O U B L E........................d o u b le M P I_ F L O A T...........................flo a t M P I_ IN T................................. in t M P I_ L O N G.............................lo n g M P I_ L O N G _ L O N G _ IN T.......lo n glo n g M P I_ L O N G _ D O U B L E...........lo n gd o u b le M P I_ P A C K E D M P I_ S H O R T...........................s h o rt M P I_ U N S IG N E D _ C H A R.......u n s ig n e dc h a r M P I_ U N S IG N E D....................u n s ig n e din t M P I_ U N S IG N E D _ L O N G.......u n s ig n e dlo n g M P I_ U N S IG N E D _ S H O R T.....u n s ig n e ds h o rt Dados não estão em endereços de memória sucessivos Dados não são todos do mesmo tipo Recurso ao envio de várias mensagens e/ou buffers temporários maiores overheads Envio de uma Submatriz for (i=0; i<n; ++i) MPI_Send( &a[shift_linha + i][shift_coluna], m, MPI_DOUBLE, dest, tag, MPI_COMM_WORLD); PACKING utilização de um buffer contíguo definido pelo utilizador MPI_PACKED = tipo de dados a enviar MPI_Pack(void *inbuf, int incount, MPI_Datatype datatype, void *outbuf, int outcount, int *position, MPI_Comm comm) MPI_Pack_size(int incount, MPI_Datatype datatype, MPI_Comm comm, int *sizee) MPI_Pack_size( n*m, MPI_DOUBLE, MPI_COMM_WORLD, buffersize); buffer = malloc( (unsigned) buffersize ); conta = 0; for (i=1; i <= n; i++){ MPI_Pack(A[shift_linha+i][shift_coluna], m, MPI_DOUBLE, buffer, buffersize, count, MPI_COMM_WORLD); conta++; } MPI_Send(buffer, count, MPI_PACKED, dest, tag, MPI_COMM_WORLD); MPI_Recv(buffer, length, MPI_PACKED, source, tag, MPI_COMM_WORLD, &status); posicao = 0; for (i=1; i <= n; i++){ MPI_Unpack( buffer, length, &posicao, &A[shift_linha+i][shift_coluna], m, MPI_DOUBLE, MPI_COMM_WORLD); posicao++; } MPI_Unpack(void *inbuf, int insize, int *position, void *outbuf, int outcount, MPI_Datatype datatype, MPI_Comm comm) Packing on the fly elimina a operação de packing e a necessidade de utilização de um buffer intermédio i) Contrução do derived datatype: MPI_Type_contiguous, MPI_Type_vector, MPI_Type_hvector, MPI_Type_indexed, MPI_Type_hindexed, MPI_Type_struct ii) commit o datatype: MPI_Type_commit MPI_Type_free(datatype) datatype = MPI_DATATYPE_NULL MPI_Type_contiguous( int count, MPI_Datatype oldtype, MPI_Datatype *newtype) MPI_Type_commit( MPI_Datatype *datatype) MPI_Type_free(MPI_Datatype *datatype) double a[size][size], b[size]; MPI_Datatype linha; ... MPI_Type_contiguous( size, MPI_DOUBLE, &linha); MPI_Type_commit(&linha); ... MPI_Send(&a[i][0], 1, linha, ... ); ... MPI_Recv( b, size, MPI_DOUBLE, ... ); ... MPI_Type_free(&linha); MPI_Type_vector( int count, int blocklength, int stride, MPI_Datatype oldtype, MPI_Datatype *newtype ) stride Count = 3 blocklength double a[size][size], b[size]; Datatype coluna; ... MPI_Type_vector( size, 1, size, MPI_DOUBLE, &coluna); MPI_Type_commit(&coluna); ... MPI_Send( &a[0][i], 1, coluna, ... ); MPI_Recv( b, size, MPI_DOUBLE, ... ... MPI_Type_free(&coluna); MPI_Type_indexed( int count, int *array_of_blocklengths, int *array_of_displacements, MPI_DATAtyoe oldtype, MPI_Datatype *newtype int blocklengths[2], displacements[2]; double a[16], b[6]; MPI_Datatype indexado; blocklengths[0] = 4; blocklengths[1] = 2; displacements[0] = 5; displacements[1] = 12; ... MPI_Type_indexed(2, blocklengths, displacements, MPI_DOUBLE, &indexado); MPI_Type_commit(&indexado); ... MPI_Send(a, 1, indexado, ...); /* envia a[5]-a[8] + a[12]-a[13] */ ... MPI_Recv( b, 6, MPI_DOUBLE, ... ) MPI_Type_struct( int count, int *array_of_blocklengths, MPI_Aint *array_of_displacements, MPI_Datatype *array_of_types, MPI_Datatype *newtype); MPI_Type_get_extent( MPI_Datatype datatype, MPI_Aint *lb, MPI_Aint *extent ); lb = lower bound = mínimo dos displacements typedef long MPI_Aint; extent = onde está o endereço do próximo bloco de dados Typedef struct{ double x, y, z; double velocidade; int n, tipo; } particula; particula p[NElementos], particulas[NElementos]; MPI_Datatype tipoparticula, oldtypes[2]; int blockounts[2]; MPI_Aint offsets[2], extent, lb; /* coordenadas e velocidade */ offsets[0] = 0; oldtypes[0] = MPI_DOUBLE; blockcounts[0] = 4; MPI_Type_get_extent( MPI_DOUBLE, &lb, &extent); /* incluir o número e o tipo */ offsets[1] = 4*extent; oldtypes[1] = MPI_INT; blockcounts[1] = 2; MPI_Type_struct( 2, blockcounts, offsets, oldtypes, &tipoparticula ); MPI_Type_commit( &tipoparticula ); MPI_Send(particulas, Nelementos, tipoparticula, ... ) MPI_Recv(p, Nelementos, tipoparticula, ... )