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

Reduce

int MPI_Reduce(void *sbuf, void *rbuf, int count, MPI_Datatype dtype, 
               MPI_op op, int root, MPI_Comm comm)
{
  if (op is commutative) {
    return(reduce_commutative(sbuf, rbuf, count, dtype, op, root, comm));
  } else {
    return(reduce_noncommutative(sbuf, rbuf, count, dtype, op, root, comm));
  }
}

int reduce_commutative(void *sbuf, void *rbuf, int count, MPI_Datatype dtype, 
                       MPI_op op, int root, MPI_Comm comm)
{
  MPI_Status status;
  int myrank, mynum, rootnum, vnum, dim, hibit, mask;
  int peer, nmasters;
  void *tmpbuf, *redbuf;

  nmasters = num_masters(comm);
  MPI_Comm_rank(comm, &myrank);

  /* local phase */
  if (are_local(myrank, root, comm)) {
    perform a local reduction to root's rbuf;
  } else {
    perform a local reduction to a temporary buffer redbuf in
      the local master;
  }

  /* global phase */
  if ((myrank == root) || (is_master(myrank, comm) 
      && !are_local(myrank, root, comm))) {
  
    allocate a temporary buffer tmpbuf large enough for
      count copies of dtype;

    if (nmasters <= MAXLINEARREDUCE) {
      /* linear reduction to root */
      if (rank == root) {
        for (i = 0; i < nmasters; i++) {
          if (i == local_master_num(root, comm)) continue;
          MPI_Recv(tmpbuf, count, dtype, master_rank(i, comm), 
                   IMPI_REDUCE_TAG, comm, &status);
        }

        call reduction function op on tmpbuf (invec) 
          and rbuf (inoutvec);
      } else {
        MPI_Send(redbuf, count, dtype, root, IMPI_REDUCE_TAG, comm); 
      }
    } else {
      /* tree reduction to root */
      mynum = local_master_num(myrank, comm);
      rootnum = master_num(root, comm);
      vnum = (mynum - rootnum + nmasters) % nmasters;
      dim = cubedim(nmasters);
      hibit = hibit(vnum, dim);
      --dim;

      /* loop over cube dimensions */
      for (i = 0, mask = 1; i < dim; ++i, mask <<= 1) {
        /* a high-proc sends to low-proc and stops */
        if (vnum & mask) {
          peer = master_rank(((vnum & ~mask) + rootnum) % nmasters, comm);
          if (are_local(peer, root, comm)) {
            peer = root;
          }

          MPI_Send(redbuf, count, dtype, peer, IMPI_REDUCE_TAG, comm);
          break;
        }

        /* a low-proc receives, reduces, and moves 
         * to a higher dimension */
        else {
          peer = vnum | mask;
          if (peer >= nmasters) continue;
          peer = master_rank((peer + rootnum) % nmasters, comm);

          MPI_Recv(tmpbuf, count, dtype, peer, 
                   IMPI_REDUCE_TAG, comm, &status);

          if (myrank == root) {
            call reduction function op on tmpbuf (invec) 
              and redbuf (inoutvec);
          } else {
            call reduction function op on tmpbuf (invec) 
              and rbuf (inoutvec);
          }
        }
      }
    }
  }

  free all temporary buffers;
  return(MPI_SUCCESS);
}

int reduce_noncommutative(void *sbuf, void *rbuf, int count, 
                MPI_Datatype dtype, MPI_op op, int root, MPI_Comm comm)
{
  MPI_Status status;
  int i, myrank, nprocs;
  void *inbuf, *tmpbuf;

  MPI_Comm_size(comm, &nprocs);
  MPI_Comm_root(comm, &myrank);

  if (myrank != root) {
    return(MPI_Send(sbuf, count, dtype, root, IMPI_REDUCE_TAG, comm);
  }

  if (nprocs > 1) {
    create a temporary buffer tmpbuf large enough for count dtypes;
  }

  if (myrank == (nprocs - 1)) {
    MPI_Sendrecv(sbuf, count, dtype, myrank, IMPI_REDUCE_TAG,
                 rbuf, count, dtype, myrank, IMPI_REDUCE_TAG, comm, &status);
  } else {
    MPI_Recv(rbuf, count, dtype, nprocs - 1, IMPI_REDUCE_TAG, comm, &status);
  }

  for (i = nprocs - 2; i >= 0; --i) {
    if (myrank == i) {
       inbuf = sbuf;
    } else {
      MPI_Recv(tmpbuf, count, dtype, i, IMPI_REDUCE_TAG, comm, &status);
      inbuf = tmpbuf;
    }

    call reduction function op on inbuf (invec) and rbuf (inoutvec);
  }

  free all temporary buffers;
  return(MPI_SUCCESS);
}



IMPI Protocol ver 0.0
DRAFT March 22, 1999