Update of /cvsroot/boost/boost/libs/parallel/src/mpi
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv657/libs/parallel/src/mpi

Added Files:
        broadcast.cpp communicator.cpp computation_tree.cpp 
        content_oarchive.cpp environment.cpp mpi_datatype_cache.cpp 
        mpi_datatype_oarchive.cpp packed_iarchive.cpp 
        packed_oarchive.cpp packed_skeleton_iarchive.cpp 
        packed_skeleton_oarchive.cpp point_to_point.cpp request.cpp 
        text_skeleton_iarchive.cpp text_skeleton_oarchive.cpp 
        timer.cpp 
Log Message:
Import Boost.MPI with the beginnings of a BBv2-based build system

--- NEW FILE: broadcast.cpp ---
// Copyright 2005 Douglas Gregor.

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// Message Passing Interface 1.1 -- Section 4.4. Broadcast

#include <boost/parallel/mpi/collectives/broadcast.hpp>
#include <boost/parallel/mpi/skeleton_and_content.hpp>
#include <boost/parallel/mpi/detail/point_to_point.hpp>
#include <boost/parallel/mpi/environment.hpp>

namespace boost { namespace parallel { namespace mpi {

template<>
void
broadcast<const packed_oarchive>(const communicator& comm,
                                 const packed_oarchive& oa,
                                 int root)
{
  // Only the root can broadcast the packed_oarchive
  assert(comm.rank() == root);

  int size = comm.size();
  if (size < 2) return;

  // Determine maximum tag value
  int tag = environment::collectives_tag();

  // Broadcast data to all nodes
  std::vector<MPI_Request> requests(size * 2);
  int num_requests = 0;
  for (int dest = 0; dest < size; ++dest) {
    if (dest != root) {
      // Build up send requests for each child send.
      num_requests += detail::packed_archive_isend(comm, dest, tag, oa,
                                                   &requests[num_requests], 2);
    }
  }

  // Complete all of the sends
  BOOST_MPI_CHECK_RESULT(MPI_Waitall,
                         (num_requests, &requests[0], MPI_STATUSES_IGNORE));
}

template<>
void
broadcast<packed_oarchive>(const communicator& comm, packed_oarchive& oa,
                           int root)
{
  broadcast(comm, const_cast<const packed_oarchive&>(oa), root);
}

template<>
void
broadcast<packed_iarchive>(const communicator& comm, packed_iarchive& ia,
                           int root)
{
  int size = comm.size();
  if (size < 2) return;

  // Determine maximum tag value
  int tag = environment::collectives_tag();

  // Receive data from the root.
  if (comm.rank() != root) {
    MPI_Status status;
    detail::packed_archive_recv(comm, root, tag, ia, status);
  } else {
    // Broadcast data to all nodes
    std::vector<MPI_Request> requests(size * 2);
    int num_requests = 0;
    for (int dest = 0; dest < size; ++dest) {
      if (dest != root) {
        // Build up send requests for each child send.
        num_requests += detail::packed_archive_isend(comm, dest, tag, ia,
                                                     &requests[num_requests],
                                                     2);
      }
    }

    // Complete all of the sends
    BOOST_MPI_CHECK_RESULT(MPI_Waitall,
                           (num_requests, &requests[0], MPI_STATUSES_IGNORE));
  }
}

template<>
void
broadcast<const packed_skeleton_oarchive>(const communicator& comm,
                                          const packed_skeleton_oarchive& oa,
                                          int root)
{
  broadcast(comm, oa.get_skeleton(), root);
}

template<>
void
broadcast<packed_skeleton_oarchive>(const communicator& comm,
                                    packed_skeleton_oarchive& oa, int root)
{
  broadcast(comm, oa.get_skeleton(), root);
}

template<>
void
broadcast<packed_skeleton_iarchive>(const communicator& comm,
                                    packed_skeleton_iarchive& ia, int root)
{
  broadcast(comm, ia.get_skeleton(), root);
}

template<>
void broadcast<content>(const communicator& comm, content& c, int root)
{
  broadcast(comm, const_cast<const content&>(c), root);
}

template<>
void broadcast<const content>(const communicator& comm, const content& c,
                              int root)
{
#ifdef LAM_MPI
  if (comm.size() < 2)
    return;

  // Some versions of LAM/MPI behave badly when broadcasting using
  // MPI_BOTTOM, so we'll instead use manual send/recv operations.
  if (comm.rank() == root) {
    for (int p = 0; p < comm.size(); ++p) {
      if (p != root) {
        BOOST_MPI_CHECK_RESULT(MPI_Send,
                               (MPI_BOTTOM, 1, c.get_mpi_datatype(),
                                p, environment::collectives_tag(), comm));
      }
    }
  } else {
    BOOST_MPI_CHECK_RESULT(MPI_Recv,
                           (MPI_BOTTOM, 1, c.get_mpi_datatype(),
                            root, environment::collectives_tag(),
                            comm, MPI_STATUS_IGNORE));
  }
#else
  BOOST_MPI_CHECK_RESULT(MPI_Bcast,
                         (MPI_BOTTOM, 1, c.get_mpi_datatype(),
                          root, comm));
#endif
}

} } } // end namespace boost::parallel::mpi

--- NEW FILE: communicator.cpp ---
// Copyright (C) 2005, 2006 Douglas Gregor.

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/skeleton_and_content.hpp>
#include <boost/parallel/mpi/detail/point_to_point.hpp>

namespace boost { namespace parallel { namespace mpi {

/***************************************************************************
 * status                                                                  *
 ***************************************************************************/
bool status::cancelled()
{
  int flag = 0;
  BOOST_MPI_CHECK_RESULT(MPI_Test_cancelled, (&m_status, &flag));
  return flag != 0;
}

/***************************************************************************
 * communicator                                                            *
 ***************************************************************************/

communicator::communicator()
{
  comm_ptr.reset(new MPI_Comm(MPI_COMM_WORLD));
}

communicator::communicator(const MPI_Comm& comm, comm_create_kind kind)
{
  if (comm == MPI_COMM_NULL)
    /* MPI_COMM_NULL indicates that the communicator is not usable. */
    return;

  switch (kind) {
  case comm_duplicate:
    {
      MPI_Comm newcomm;
      BOOST_MPI_CHECK_RESULT(MPI_Comm_dup, (comm, &newcomm));
      comm_ptr.reset(new MPI_Comm(newcomm), comm_free());
      MPI_Errhandler_set(newcomm, MPI_ERRORS_RETURN);
      break;
    }

  case comm_take_ownership:
    comm_ptr.reset(new MPI_Comm(comm), comm_free());
    break;

  case comm_attach:
    comm_ptr.reset(new MPI_Comm(comm));
    break;
  }
 }

int communicator::size() const
{
  int size_;
  BOOST_MPI_CHECK_RESULT(MPI_Comm_size, (MPI_Comm(*this), &size_));
  return size_;
}

int communicator::rank() const
{
  int rank_;
  BOOST_MPI_CHECK_RESULT(MPI_Comm_rank, (MPI_Comm(*this), &rank_));
  return rank_;
}

void communicator::send(int dest, int tag) const
{
  BOOST_MPI_CHECK_RESULT(MPI_Send,
                         (MPI_BOTTOM, 0, MPI_PACKED,
                          dest, tag, MPI_Comm(*this)));
}

status communicator::recv(int source, int tag) const
{
  status stat;
  BOOST_MPI_CHECK_RESULT(MPI_Recv,
                         (MPI_BOTTOM, 0, MPI_PACKED,
                          source, tag, MPI_Comm(*this), &stat.m_status));
  return stat;
}

optional<status> communicator::iprobe(int source, int tag) const
{
  typedef optional<status> result_type;

  status stat;
  int flag;
  BOOST_MPI_CHECK_RESULT(MPI_Iprobe,
                         (source, tag, MPI_Comm(*this), &flag,
                          &stat.m_status));
  if (flag) return stat;
  else return result_type();
}

status communicator::probe(int source, int tag) const
{
  typedef optional<status> result_type;

  status stat;
  BOOST_MPI_CHECK_RESULT(MPI_Probe,
                         (source, tag, MPI_Comm(*this), &stat.m_status));
  return stat;
}

void (communicator::barrier)() const
{
  BOOST_MPI_CHECK_RESULT(MPI_Barrier, (MPI_Comm(*this)));
}


communicator::operator MPI_Comm() const
{
  if (comm_ptr) return *comm_ptr;
  else return MPI_COMM_NULL;
}

communicator communicator::split(int color) const
{
  return split(color, rank());
}

communicator communicator::split(int color, int key) const
{
  MPI_Comm newcomm;
  BOOST_MPI_CHECK_RESULT(MPI_Comm_split,
                         (MPI_Comm(*this), color, key, &newcomm));
  return communicator(newcomm, comm_take_ownership);
}

void communicator::abort(int errcode) const
{
  BOOST_MPI_CHECK_RESULT(MPI_Abort, (MPI_Comm(*this), errcode));
}

/*************************************************************
 * archived send/recv                                     *
 *************************************************************/
template<>
void
communicator::send<packed_oarchive>(int dest, int tag,
                                    const packed_oarchive& ar) const
{
  detail::packed_archive_send(MPI_Comm(*this), dest, tag, ar);
}

template<>
void
communicator::send<packed_skeleton_oarchive>
  (int dest, int tag, const packed_skeleton_oarchive& ar) const
{
  this->send(dest, tag, ar.get_skeleton());
}

template<>
void communicator::send<content>(int dest, int tag, const content& c) const
{
  BOOST_MPI_CHECK_RESULT(MPI_Send,
                         (MPI_BOTTOM, 1, c.get_mpi_datatype(),
                          dest, tag, MPI_Comm(*this)));
}

template<>
status
communicator::recv<packed_iarchive>(int source, int tag,
                                    packed_iarchive& ar) const
{
  status stat;
  detail::packed_archive_recv(MPI_Comm(*this), source, tag, ar,
                              stat.m_status);
  return stat;
}

template<>
status
communicator::recv<packed_skeleton_iarchive>
  (int source, int tag, packed_skeleton_iarchive& ar) const
{
  return this->recv(source, tag, ar.get_skeleton());
}

template<>
status
communicator::recv<const content>(int source, int tag, const content& c) const
{
  status stat;
  BOOST_MPI_CHECK_RESULT(MPI_Recv,
                         (MPI_BOTTOM, 1, c.get_mpi_datatype(),
                          source, tag, MPI_Comm(*this), &stat.m_status));
  return stat;
}

/*************************************************************
 * non-blocking send/recv                                    *
 *************************************************************/
template<>
request
communicator::isend<packed_oarchive>(int dest, int tag,
                                     const packed_oarchive& ar) const
{
  request req;
  detail::packed_archive_isend(MPI_Comm(*this), dest, tag, ar,
                               &req.m_requests[0] ,2);
  return req;
}

template<>
request
communicator::isend<packed_skeleton_oarchive>
  (int dest, int tag, const packed_skeleton_oarchive& ar) const
{
  return this->isend(dest, tag, ar.get_skeleton());
}

template<>
request communicator::isend<content>(int dest, int tag, const content& c) const
{
  request req;
  BOOST_MPI_CHECK_RESULT(MPI_Isend,
                         (MPI_BOTTOM, 1, c.get_mpi_datatype(),
                          dest, tag, MPI_Comm(*this), &req.m_requests[0]));
  return req;
}

request communicator::isend(int dest, int tag) const
{
  request req;
  BOOST_MPI_CHECK_RESULT(MPI_Isend,
                         (MPI_BOTTOM, 0, MPI_PACKED,
                          dest, tag, MPI_Comm(*this), &req.m_requests[0]));
  return req;
}

template<>
request
communicator::irecv<packed_skeleton_iarchive>
  (int source, int tag, packed_skeleton_iarchive& ar) const
{
  return this->irecv(source, tag, ar.get_skeleton());
}

template<>
request
communicator::irecv<const content>(int source, int tag,
                                   const content& c) const
{
  request req;
  BOOST_MPI_CHECK_RESULT(MPI_Irecv,
                         (MPI_BOTTOM, 1, c.get_mpi_datatype(),
                          source, tag, MPI_Comm(*this), &req.m_requests[0]));
  return req;
}

request communicator::irecv(int source, int tag) const
{
  request req;
  BOOST_MPI_CHECK_RESULT(MPI_Irecv,
                         (MPI_BOTTOM, 0, MPI_PACKED,
                          source, tag, MPI_Comm(*this), &req.m_requests[0]));
  return req;
}

} } } // end namespace boost::parallel::mpi

--- NEW FILE: computation_tree.cpp ---
// Copyright (C) 2005 Douglas Gregor.

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// Compute parents, children, levels, etc. to effect a parallel
// computation tree.

#include <boost/parallel/mpi/detail/computation_tree.hpp>

namespace boost { namespace parallel { namespace mpi { namespace detail {

int computation_tree::default_branching_factor = 3;

computation_tree
::computation_tree(int rank, int size, int root, int branching_factor)
  : rank(rank), size(size), root(root),
    branching_factor_(branching_factor > 1? branching_factor
                      /* default */: default_branching_factor),
    level_(0)
{
  // The position in the tree, once we've adjusted for non-zero
  // roots.
  int n = (rank + size - root) % size;
  int sum = 0;
  int term = 1;

  /* The level is the smallest value of k such that

  f^0 + f^1 + ... + f^k > n

  for branching factor f and index n in the tree. */
  while (sum <= n) {
    ++level_;
    term *= branching_factor_;
    sum += term;
  }
}

int computation_tree::level_index(int n) const
{
  int sum = 0;
  int term = 1;
  while (n--) {
    sum += term;
    term *= branching_factor_;
  }
  return sum;
}

int computation_tree::parent() const
{
  if (rank == root) return rank;
  int n = rank + size - 1 - root;
  return ((n % size / branching_factor_) + root) % size ;
}

int computation_tree::child_begin() const
{
  // Zero-based index of this node
  int n = (rank + size - root) % size;

  // Compute the index of the child (in a zero-based tree)
  int child_index = level_index(level_ + 1)
    + branching_factor_ * (n - level_index(level_));

  if (child_index >= size) return root;
  else return (child_index + root) % size;
}

} } } } // end namespace boost::parallel::mpi::detail

--- NEW FILE: content_oarchive.cpp ---
// (C) Copyright 2005 Matthias Troyer

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//  Authors: Matthias Troyer

#define BOOST_ARCHIVE_SOURCE
#include <boost/archive/impl/archive_pointer_oserializer.ipp>
#include <boost/parallel/mpi/skeleton_and_content.hpp>

namespace boost { namespace archive { namespace detail {
// explicitly instantiate all required template functions

template class 
archive_pointer_oserializer<parallel::mpi::detail::content_oarchive> ;

} } }

--- NEW FILE: environment.cpp ---
// Copyright (C) 2005-2006 Douglas Gregor <[EMAIL PROTECTED]>

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// Message Passing Interface 1.1 -- 7.1.1. Environmental Inquiries
#include <boost/parallel/mpi/environment.hpp>
#include <boost/parallel/mpi/exception.hpp>
#include <cassert>
#include <exception>
#include <stdexcept>

namespace boost { namespace parallel { namespace mpi {

environment::environment(int& argc, char** &argv, bool abort_on_exception)
  : i_initialized(false),
    abort_on_exception(abort_on_exception)
{
  if (!initialized()) {
    BOOST_MPI_CHECK_RESULT(MPI_Init, (&argc, &argv));
    i_initialized = true;
  }

  MPI_Errhandler_set(MPI_COMM_WORLD, MPI_ERRORS_RETURN);
}

environment::~environment()
{
  if (i_initialized) {
    if (std::uncaught_exception() && abort_on_exception) {
      abort(-1);
    } else if (!finalized()) {
      BOOST_MPI_CHECK_RESULT(MPI_Finalize, ());
    }
  }
}

void environment::abort(int errcode)
{
  BOOST_MPI_CHECK_RESULT(MPI_Abort, (MPI_COMM_WORLD, errcode));
}

bool environment::initialized()
{
  int flag;
  BOOST_MPI_CHECK_RESULT(MPI_Initialized, (&flag));
  return flag != 0;
}

bool environment::finalized()
{
  int flag;
  BOOST_MPI_CHECK_RESULT(MPI_Finalized, (&flag));
  return flag != 0;
}

int environment::max_tag()
{
  int* max_tag_value;
  int found = 0;

  BOOST_MPI_CHECK_RESULT(MPI_Attr_get,
                         (MPI_COMM_WORLD, MPI_TAG_UB, &max_tag_value, &found));
  assert(found != 0);
  return *max_tag_value - num_reserved_tags;
}

int environment::collectives_tag()
{
  return max_tag() + 1;
}

optional<int> environment::host_rank()
{
  int* host;
  int found = 0;

  BOOST_MPI_CHECK_RESULT(MPI_Attr_get,
                         (MPI_COMM_WORLD, MPI_HOST, &host, &found));
  if (!found || *host == MPI_PROC_NULL)
    return optional<int>();
  else
    return *host;
}

optional<int> environment::io_rank()
{
  int* io;
  int found = 0;

  BOOST_MPI_CHECK_RESULT(MPI_Attr_get,
                         (MPI_COMM_WORLD, MPI_IO, &io, &found));
  if (!found || *io == MPI_PROC_NULL)
    return optional<int>();
  else
    return *io;
}

std::string environment::processor_name()
{
  char name[MPI_MAX_PROCESSOR_NAME];
  int len;

  BOOST_MPI_CHECK_RESULT(MPI_Get_processor_name, (name, &len));
  return std::string(name, len);
}

} } } // end namespace boost::parallel::mpi

--- NEW FILE: mpi_datatype_cache.cpp ---
// (C) Copyright 2005 Matthias Troyer 

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//  Authors: Matthias Troyer

#include <boost/archive/impl/archive_pointer_oserializer.ipp>
#include <boost/parallel/mpi/detail/mpi_datatype_cache.hpp>

namespace boost { namespace parallel { namespace mpi { namespace detail {

mpi_datatype_map mpi_datatype_cache;
  
}}}}

--- NEW FILE: mpi_datatype_oarchive.cpp ---
// (C) Copyright 2005 Matthias Troyer 

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//  Authors: Matthias Troyer

#define BOOST_ARCHIVE_SOURCE
#include <boost/archive/impl/archive_pointer_oserializer.ipp>
#include <boost/parallel/mpi/detail/mpi_datatype_oarchive.hpp>

namespace boost { namespace archive { namespace detail {
// explicitly instantiate all required template functions

template class 
archive_pointer_oserializer<parallel::mpi::detail::mpi_datatype_oarchive> ;

} } } 

--- NEW FILE: packed_iarchive.cpp ---
// (C) Copyright 2005 Matthias Troyer 

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//  Authors: Matthias Troyer

#define BOOST_ARCHIVE_SOURCE
#include <boost/archive/impl/archive_pointer_iserializer.ipp>
#include <boost/archive/impl/archive_pointer_oserializer.ipp>
#include <boost/parallel/mpi/packed_iarchive.hpp>

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/impl/basic_binary_iprimitive.ipp>
#include <boost/archive/impl/basic_binary_iarchive.ipp>

namespace boost { namespace archive {

// explicitly instantiate all required templates

template class basic_binary_iarchive<parallel::mpi::packed_iarchive> ;
template class 
detail::archive_pointer_iserializer<parallel::mpi::packed_iarchive> ;
//template class binary_iarchive_impl<mpi_packed_iarchive> ;

} } // end namespace boost::archive

--- NEW FILE: packed_oarchive.cpp ---
// (C) Copyright 2005 Matthias Troyer 

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//  Authors: Matthias Troyer

#define BOOST_ARCHIVE_SOURCE
#include <boost/parallel/mpi/packed_oarchive.hpp>

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/impl/basic_binary_oprimitive.ipp>
#include <boost/archive/impl/basic_binary_oarchive.ipp>
#include <boost/archive/impl/archive_pointer_oserializer.ipp>

namespace boost { namespace archive {
// explicitly instantiate all required templates

template class 
detail::archive_pointer_oserializer<parallel::mpi::packed_oarchive> ;
template class basic_binary_oarchive<parallel::mpi::packed_oarchive> ;
//template class binary_oarchive_impl<mpi_packed_oarchive> ;

} } // end namespace boost::archive

--- NEW FILE: packed_skeleton_iarchive.cpp ---
// (C) Copyright 2005 Matthias Troyer

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//  Authors: Matthias Troyer

#define BOOST_ARCHIVE_SOURCE
#include <boost/archive/impl/archive_pointer_iserializer.ipp>
#include <boost/archive/impl/archive_pointer_oserializer.ipp>
#include <boost/parallel/mpi/skeleton_and_content.hpp>

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/impl/basic_binary_iprimitive.ipp>
#include <boost/archive/impl/basic_binary_iarchive.ipp>

namespace boost { namespace archive {

// explicitly instantiate all required templates

template class basic_binary_iarchive<parallel::mpi::packed_skeleton_iarchive> ;
template class 
detail::archive_pointer_iserializer<parallel::mpi::packed_skeleton_iarchive> ;
//template class binary_iarchive_impl<packed_skeleton_iarchive> ;

} } // end namespace boost::archive

--- NEW FILE: packed_skeleton_oarchive.cpp ---
// (C) Copyright 2005 Matthias Troyer

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//  Authors: Matthias Troyer

#define BOOST_ARCHIVE_SOURCE
#include <boost/parallel/mpi/skeleton_and_content.hpp>

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/impl/basic_binary_oprimitive.ipp>
#include <boost/archive/impl/basic_binary_oarchive.ipp>
#include <boost/archive/impl/archive_pointer_oserializer.ipp>

namespace boost { namespace archive {
// explicitly instantiate all required templates

template class 
detail::archive_pointer_oserializer<parallel::mpi::packed_skeleton_oarchive> ;
template class basic_binary_oarchive<parallel::mpi::packed_skeleton_oarchive> ;
//template class binary_oarchive_impl<mpi_packed_oarchive> ;

} } // end namespace boost::archive

--- NEW FILE: point_to_point.cpp ---
// Copyright 2005 Douglas Gregor.

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// Message Passing Interface 1.1 -- Section 3. MPI Point-to-point

/* There is the potential for optimization here. We could keep around
   a "small message" buffer of size N that we just receive into by
   default. If the message is N - sizeof(int) bytes or smaller, it can
   just be sent with that buffer. If it's larger, we send the first N
   - sizeof(int) bytes in the first packet followed by another
   packet. The size of the second packet will be stored in an integer
   at the end of the first packet.

   We will introduce this optimization later, when we have more
   performance test cases and have met our functionality goals. */

#include <boost/parallel/mpi/detail/point_to_point.hpp>
#include <boost/parallel/mpi/datatype.hpp>
#include <boost/parallel/mpi/exception.hpp>
#include <cassert>

namespace boost { namespace parallel { namespace mpi { namespace detail {

void
packed_archive_send(MPI_Comm comm, int dest, int tag,
                    const packed_oarchive& ar)
{
  const void* size = &ar.size();
  BOOST_MPI_CHECK_RESULT(MPI_Send,
                         (const_cast<void*>(size), 1, 
                          get_mpi_datatype<std::size_t>(), dest, tag, comm));
  BOOST_MPI_CHECK_RESULT(MPI_Send,
                         (const_cast<void*>(ar.address()), ar.size(),
                          MPI_PACKED,
                          dest, tag, comm));
}

int
packed_archive_isend(MPI_Comm comm, int dest, int tag,
                     const packed_oarchive& ar,
                     MPI_Request* out_requests, int num_out_requests)
{
  assert(num_out_requests >= 2);
  const void* size = &ar.size();
  BOOST_MPI_CHECK_RESULT(MPI_Isend,
                         (const_cast<void*>(size), 1, 
                          get_mpi_datatype<std::size_t>(), 
                          dest, tag, comm, out_requests));
  BOOST_MPI_CHECK_RESULT(MPI_Isend,
                         (const_cast<void*>(ar.address()), ar.size(),
                          MPI_PACKED,
                          dest, tag, comm, out_requests + 1));

  return 2;
}

int
packed_archive_isend(MPI_Comm comm, int dest, int tag,
                     const packed_iarchive& ar,
                     MPI_Request* out_requests, int num_out_requests)
{
  assert(num_out_requests >= 2);

  const void* size = &ar.size();
  BOOST_MPI_CHECK_RESULT(MPI_Isend,
                         (const_cast<void*>(size), 1, 
                          get_mpi_datatype<std::size_t>(), 
                          dest, tag, comm, out_requests));
  BOOST_MPI_CHECK_RESULT(MPI_Isend,
                         (const_cast<void*>(ar.address()), ar.size(),
                          MPI_PACKED,
                          dest, tag, comm, out_requests + 1));

  return 2;
}

void
packed_archive_recv(MPI_Comm comm, int source, int tag, packed_iarchive& ar,
                    MPI_Status& status)
{
  std::size_t count;
  BOOST_MPI_CHECK_RESULT(MPI_Recv,
                         (&count, 1, get_mpi_datatype<std::size_t>(),
                          source, tag, comm, &status));

  // Prepare input buffer and receive the message
  ar.resize(count);
  BOOST_MPI_CHECK_RESULT(MPI_Recv,
                         (ar.address(), ar.size(), MPI_PACKED,
                          status.MPI_SOURCE, status.MPI_TAG,
                          comm, &status));
}

} } } } // end namespace boost::parallel::mpi::detail

--- NEW FILE: request.cpp ---
// Copyright (C) 2006 Douglas Gregor.

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/parallel/mpi/request.hpp>
#include <boost/parallel/mpi/status.hpp>

namespace boost { namespace parallel { namespace mpi {

/***************************************************************************
 * request                                                                 *
 ***************************************************************************/
request::request()
  : m_handler(0), m_data()
{
  m_requests[0] = MPI_REQUEST_NULL;
  m_requests[1] = MPI_REQUEST_NULL;
}

status request::wait()
{
  if (m_handler) {
    // This request is a receive for a serialized type. Use the
    // handler to wait for completion.
    return *m_handler(this, ra_wait);
  } else if (m_requests[1] == MPI_REQUEST_NULL) {
    // This request is either a send or a receive for a type with an
    // associated MPI datatype, or a serialized datatype that has been
    // packed into a single message. Just wait on the one receive/send
    // and return the status to the user.
    status result;
    BOOST_MPI_CHECK_RESULT(MPI_Wait, (&m_requests[0], &result.m_status));
    return result;
  } else {
    // This request is a send of a serialized type, broken into two
    // separate messages. Complete both sends at once.
    MPI_Status stats[2];
    int error_code = MPI_Waitall(2, m_requests, stats);
    if (error_code == MPI_ERR_IN_STATUS) {
      // Dig out which status structure has the error, and use that
      // one when throwing the exception.
      if (stats[0].MPI_ERROR == MPI_SUCCESS 
          || stats[0].MPI_ERROR == MPI_ERR_PENDING)
        boost::throw_exception(exception("MPI_Waitall", stats[1].MPI_ERROR));
      else
        boost::throw_exception(exception("MPI_Waitall", stats[0].MPI_ERROR));
    } else if (error_code != MPI_SUCCESS) {
      // There was an error somewhere in the MPI_Waitall call; throw
      // an exception for it.
      boost::throw_exception(exception("MPI_Waitall", error_code));
    } 

    // No errors. Returns the first status structure.
    status result;
    result.m_status = stats[0];
    return result;
  }
}

optional<status> request::test()
{
  if (m_handler) {
    // This request is a receive for a serialized type. Use the
    // handler to test for completion.
    return m_handler(this, ra_test);
  } else if (m_requests[1] == MPI_REQUEST_NULL) {
    // This request is either a send or a receive for a type with an
    // associated MPI datatype, or a serialized datatype that has been
    // packed into a single message. Just test the one receive/send
    // and return the status to the user if it has completed.
    status result;
    int flag = 0;
    BOOST_MPI_CHECK_RESULT(MPI_Test, 
                           (&m_requests[0], &flag, &result.m_status));
    return flag != 0? optional<status>(result) : optional<status>();
  } else {
    // This request is a send of a serialized type, broken into two
    // separate messages. We only get a result if both complete.
    MPI_Status stats[2];
    int flag = 0;
    int error_code = MPI_Testall(2, m_requests, &flag, stats);
    if (error_code == MPI_ERR_IN_STATUS) {
      // Dig out which status structure has the error, and use that
      // one when throwing the exception.
      if (stats[0].MPI_ERROR == MPI_SUCCESS 
          || stats[0].MPI_ERROR == MPI_ERR_PENDING)
        boost::throw_exception(exception("MPI_Testall", stats[1].MPI_ERROR));
      else
        boost::throw_exception(exception("MPI_Testall", stats[0].MPI_ERROR));
    } else if (error_code != MPI_SUCCESS) {
      // There was an error somewhere in the MPI_Testall call; throw
      // an exception for it.
      boost::throw_exception(exception("MPI_Testall", error_code));
    }

    // No errors. Returns the second status structure if the send has
    // completed.
    if (flag != 0) {
      status result;
      result.m_status = stats[1];
      return result;
    } else {
      return optional<status>();
    }
  }
}

void request::cancel()
{
  if (m_handler) {
    m_handler(this, ra_cancel);
  } else {
    BOOST_MPI_CHECK_RESULT(MPI_Cancel, (&m_requests[0]));
    if (m_requests[1] != MPI_REQUEST_NULL)
      BOOST_MPI_CHECK_RESULT(MPI_Cancel, (&m_requests[1]));
  }
}

} } } // end namespace boost::parallel::mpi

--- NEW FILE: text_skeleton_iarchive.cpp ---
// (C) Copyright 2005 Matthias Troyer 

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//  Authors: Matthias Troyer

#define BOOST_ARCHIVE_SOURCE
#include <boost/archive/impl/archive_pointer_iserializer.ipp>
#include <boost/archive/impl/archive_pointer_oserializer.ipp>
#include <boost/parallel/mpi/text_skeleton_iarchive.hpp>

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/impl/basic_binary_iprimitive.ipp>
#include <boost/archive/impl/basic_binary_iarchive.ipp>

namespace boost { namespace archive {

// explicitly instantiate all required templates

template class 
detail::archive_pointer_iserializer<parallel::mpi::text_skeleton_iarchive> ;

} } // end namespace boost::archive

--- NEW FILE: text_skeleton_oarchive.cpp ---
// (C) Copyright 2005 Matthias Troyer

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//  Authors: Matthias Troyer

#define BOOST_ARCHIVE_SOURCE
#include <boost/parallel/mpi/detail/text_skeleton_oarchive.hpp>

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/impl/basic_binary_oprimitive.ipp>
#include <boost/archive/impl/basic_binary_oarchive.ipp>
#include <boost/archive/impl/archive_pointer_oserializer.ipp>

namespace boost { namespace archive {
// explicitly instantiate all required templates

template class 
detail::archive_pointer_oserializer<parallel::mpi::text_skeleton_oarchive> ;

} } // end namespace boost::archive

--- NEW FILE: timer.cpp ---
// Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/parallel/mpi/timer.hpp>
#include <boost/parallel/mpi/exception.hpp>

namespace boost { namespace parallel { namespace mpi {

bool timer::time_is_global()
{
  int* is_global;
  int found = 0;

  BOOST_MPI_CHECK_RESULT(MPI_Attr_get,
                         (MPI_COMM_WORLD, MPI_WTIME_IS_GLOBAL, &is_global,
                          &found));
  if (!found)
    return false;
  else
    return *is_global != 0;
}

} } } /// end namespace boost::parallel::mpi


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Boost-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/boost-cvs

Reply via email to