next up previous contents
Next: Scatterv Up: Collectives Previous: Gatherv

Scatter

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



IMPI Protocol ver 0.0
DRAFT March 22, 1999