int scatter_is_short(int count, MPI_Datatype dtype, MPI_Comm comm)
{
int size;
MPI_Pack_size(count, dtype, comm, &size);
if (size < 2048) {
return(1);
} else {
return(0);
}
}
int MPI_Scatter(void *sbuf, int scount, MPI_Datatype sdtype,
void *rbuf, int rcount, MPI_Datatype rdtype,
int root, MPI_Comm comm)
{
if (scatter_is_short(rcount, rdtype, comm)) {
scatter_short(sbuf, scount, sdtype, rbuf, rcount, rdtype, root, comm);
} else {
scatter_long(sbuf, scount, sdtype, rbuf, rcount, rdtype, root, comm);
}
return(MPI_SUCCESS);
}
int scatter_long(void *sbuf, int scount, MPI_Datatype sdtype,
void *rbuf, int rcount, MPI_Datatype rdtype,
int root, MPI_Comm comm)
{
MPI_Status status;
MPI_Aint extent;
int i, myrank, nprocs, incr;
MPI_Comm_rank(comm, &myrank);
MPI_Comm_size(comm, &nprocs);
if (myrank != root) {
MPI_Recv(rbuf, rcount, rdtype, root, IMPI_SCATTER_TAG, comm, &status);
} else {
MPI_Type_extent(sdtype, &extent);
incr = extent * scount;
for (i = 0, p = (char *) sbuf; i < nprocs; i++, p += incr) {
if (i == myrank) {
MPI_Sendrecv(p, scount, sdtype, i, IMPI_SCATTER_TAG,
rbuf, rcount, rdtype, i, IMPI_SCATTER_TAG,
comm, &status);
} else {
MPI_Send(p, scount, sdtype, i, IMPI_SCATTER_TAG, comm);
}
}
}
return(MPI_SUCCESS);
}
int scatter_short(void *sbuf, int scount, MPI_Datatype sdtype,
void *rbuf, int rcount, MPI_Datatype rdtype,
int root, MPI_Comm comm)
{
MPI_Status status;
int i, myrank, packsize, size, nmasters;
void *tmpbuf;
MPI_Comm_rank(comm, &myrank);
MPI_Pack_size(rcount, rdtype, comm, &packsize);
/* global phase */
if (myrank == root) {
nmasters = num_masters(comm);
for (i = 0; i < nmasters; i++) {
if (i == local_master_num(root, comm)) {
continue; /* skip root's node */
}
size = num_local_to_master(i, comm) * packsize;
allocate a temporary buffer tmpbuf of size bytes and
put into it concatenated in rank order packed copies of the data
destined for each process local to master i;
MPI_Send(tmpbuf, size, MPI_BYTE,
master_rank(i, comm), IMPI_SCATTER_TAG, comm);
free tmpbuf;
}
} else if (is_master(myrank, comm) && !are_local(myrank, root, comm))) {
size = num_local_to_rank(myrank, comm) * packsize;
allocate a temporary buffer tmpbuf of size bytes;
MPI_Recv(tmpbuf, size, MPI_BYTE, root,
IMPI_SCATTER_TAG, comm, &status);
}
/* local phase */
if (are_local(myrank, root, comm)) {
scatter data from root sbuf to local processes;
} else {
scatter packed data from master tmpbuf to local processes;
}
free all temporary buffers which are still allocated;
return(MPI_SUCCESS);
}