For reference, here's the suggested function:
MPI_TYPE_COMPACT ( type, compact_type )
IN type datatype to be compacted
OUT compact_type datatype with identical type signature
as "type", but with possibly smaller real
extent
-- Nathan Doss doss@ERC.MsState.Edu
/* * Simple gather function using MPI_Type_compact. * It makes the following simplifications: * a) root is always 0 * b) temporary buffer on intermediate nodes * is bigger than it need be * c) leaf nodes unecessarily allocate temporary * buffer & make an extra copy */
int MPI_Gather(sbuf, scnt, stype, rbuf, rcnt, rtype, comm) void *sbuf; int scnt; MPI_Datatype stype; void *rbuf; int rcnt; MPI_Datatype rtype; MPI_Comm comm; { int rank, size, source, dest, total_count, root = 0; MPI_Aint extent; int mask = 0x1; MPI_Status status; MPI_Comm_rank ( comm, &rank ); MPI_Comm_size ( comm, &size );
/* rbuf,rcnt,rtype only valid on root */ if (rank != root) { MPI_Type_compact ( stype, &rtype ); MPI_Type_extent ( rtype, &extent ); rbuf = (void *) malloc ( extent ); rcnt = scnt; } comm = /* collective communiator */;
/* Copy send buffer to recvbuf */ MPI_Sendrecv(sbuf,scnt,stype,rank,GATHER_TAG, rbuf,rcnt,rtype,rank,GATHER_TAG,comm,&status);
/* Do the gather using a spanning tree */ total_count = rcnt; while (mask < size) {
/* Receiver */ if ((mask & rank) == 0) { source = (rank | mask); if (source < size) { mpi_errno = MPI_Recv (rbuf + (offset * source), size*rcnt, /* a "large" number */ rtype, source, GATHER_TAG, comm, &status); MPI_Get_count( &status, rtype, &len ); total_count += len; } } /* Sender */ else { dest = (rank & (~ mask)); MPI_Send( rbuf + (offset * rank), total_count, rtype, dest, GATHER_TAG, comm ); break; } mask <<= 1; }
/* Clean up */ if (rank != root) { free (rbuf); MPI_Type_free ( &rtype ); }
return (MPI_SUCCESS); }