123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- // 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)
- // Message Passing Interface 1.1 -- Section 4.6. Scatter
- #ifndef BOOST_MPI_SCATTER_HPP
- #define BOOST_MPI_SCATTER_HPP
- #include <boost/mpi/exception.hpp>
- #include <boost/mpi/datatype.hpp>
- #include <vector>
- #include <boost/mpi/packed_oarchive.hpp>
- #include <boost/mpi/packed_iarchive.hpp>
- #include <boost/mpi/detail/point_to_point.hpp>
- #include <boost/mpi/communicator.hpp>
- #include <boost/mpi/environment.hpp>
- #include <boost/mpi/detail/offsets.hpp>
- #include <boost/mpi/detail/antiques.hpp>
- #include <boost/assert.hpp>
- namespace boost { namespace mpi {
- namespace detail {
- // We're scattering from the root for a type that has an associated MPI
- // datatype, so we'll use MPI_Scatter to do all of the work.
- template<typename T>
- void
- scatter_impl(const communicator& comm, const T* in_values, T* out_values,
- int n, int root, mpl::true_)
- {
- MPI_Datatype type = get_mpi_datatype<T>(*in_values);
- BOOST_MPI_CHECK_RESULT(MPI_Scatter,
- (const_cast<T*>(in_values), n, type,
- out_values, n, type, root, comm));
- }
- // We're scattering from a non-root for a type that has an associated MPI
- // datatype, so we'll use MPI_Scatter to do all of the work.
- template<typename T>
- void
- scatter_impl(const communicator& comm, T* out_values, int n, int root,
- mpl::true_)
- {
- MPI_Datatype type = get_mpi_datatype<T>(*out_values);
- BOOST_MPI_CHECK_RESULT(MPI_Scatter,
- (0, n, type,
- out_values, n, type,
- root, comm));
- }
- // Fill the sendbuf while keeping trac of the slot's footprints
- // Used in the first steps of both scatter and scatterv
- // Nslots contains the number of slots being sent
- // to each process (identical values for scatter).
- // skiped_slots, if present, is deduced from the
- // displacement array authorised be the MPI API,
- // for some yet to be determined reason.
- template<typename T>
- void
- fill_scatter_sendbuf(const communicator& comm, T const* values,
- int const* nslots, int const* skipped_slots,
- packed_oarchive::buffer_type& sendbuf, std::vector<int>& archsizes) {
- int nproc = comm.size();
- archsizes.resize(nproc);
-
- for (int dest = 0; dest < nproc; ++dest) {
- if (skipped_slots) { // wee need to keep this for backward compatibility
- for(int k= 0; k < skipped_slots[dest]; ++k) ++values;
- }
- packed_oarchive procarchive(comm);
- for (int i = 0; i < nslots[dest]; ++i) {
- procarchive << *values++;
- }
- int archsize = procarchive.size();
- sendbuf.resize(sendbuf.size() + archsize);
- archsizes[dest] = archsize;
- char const* aptr = static_cast<char const*>(procarchive.address());
- std::copy(aptr, aptr+archsize, sendbuf.end()-archsize);
- }
- }
- template<typename T, class A>
- T*
- non_const_data(std::vector<T,A> const& v) {
- using detail::c_data;
- return const_cast<T*>(c_data(v));
- }
- // Dispatch the sendbuf among proc.
- // Used in the second steps of both scatter and scatterv
- // in_value is only provide in the non variadic case.
- template<typename T>
- void
- dispatch_scatter_sendbuf(const communicator& comm,
- packed_oarchive::buffer_type const& sendbuf, std::vector<int> const& archsizes,
- T const* in_values,
- T* out_values, int n, int root) {
- // Distribute the sizes
- int myarchsize;
- BOOST_MPI_CHECK_RESULT(MPI_Scatter,
- (non_const_data(archsizes), 1, MPI_INT,
- &myarchsize, 1, MPI_INT, root, comm));
- std::vector<int> offsets;
- if (root == comm.rank()) {
- sizes2offsets(archsizes, offsets);
- }
- // Get my proc archive
- packed_iarchive::buffer_type recvbuf;
- recvbuf.resize(myarchsize);
- BOOST_MPI_CHECK_RESULT(MPI_Scatterv,
- (non_const_data(sendbuf), non_const_data(archsizes), c_data(offsets), MPI_BYTE,
- c_data(recvbuf), recvbuf.size(), MPI_BYTE,
- root, MPI_Comm(comm)));
- // Unserialize
- if ( in_values != 0 && root == comm.rank()) {
- // Our own local values are already here: just copy them.
- std::copy(in_values + root * n, in_values + (root + 1) * n, out_values);
- } else {
- // Otherwise deserialize:
- packed_iarchive iarchv(comm, recvbuf);
- for (int i = 0; i < n; ++i) {
- iarchv >> out_values[i];
- }
- }
- }
- // We're scattering from the root for a type that does not have an
- // associated MPI datatype, so we'll need to serialize it.
- template<typename T>
- void
- scatter_impl(const communicator& comm, const T* in_values, T* out_values,
- int n, int root, mpl::false_)
- {
- packed_oarchive::buffer_type sendbuf;
- std::vector<int> archsizes;
-
- if (root == comm.rank()) {
- std::vector<int> nslots(comm.size(), n);
- fill_scatter_sendbuf(comm, in_values, c_data(nslots), (int const*)0, sendbuf, archsizes);
- }
- dispatch_scatter_sendbuf(comm, sendbuf, archsizes, in_values, out_values, n, root);
- }
- template<typename T>
- void
- scatter_impl(const communicator& comm, T* out_values, int n, int root,
- mpl::false_ is_mpi_type)
- {
- scatter_impl(comm, (T const*)0, out_values, n, root, is_mpi_type);
- }
- } // end namespace detail
- template<typename T>
- void
- scatter(const communicator& comm, const T* in_values, T& out_value, int root)
- {
- detail::scatter_impl(comm, in_values, &out_value, 1, root, is_mpi_datatype<T>());
- }
- template<typename T>
- void
- scatter(const communicator& comm, const std::vector<T>& in_values, T& out_value,
- int root)
- {
- using detail::c_data;
- ::boost::mpi::scatter<T>(comm, c_data(in_values), out_value, root);
- }
- template<typename T>
- void scatter(const communicator& comm, T& out_value, int root)
- {
- BOOST_ASSERT(comm.rank() != root);
- detail::scatter_impl(comm, &out_value, 1, root, is_mpi_datatype<T>());
- }
- template<typename T>
- void
- scatter(const communicator& comm, const T* in_values, T* out_values, int n,
- int root)
- {
- detail::scatter_impl(comm, in_values, out_values, n, root, is_mpi_datatype<T>());
- }
- template<typename T>
- void
- scatter(const communicator& comm, const std::vector<T>& in_values,
- T* out_values, int n, int root)
- {
- ::boost::mpi::scatter(comm, detail::c_data(in_values), out_values, n, root);
- }
- template<typename T>
- void scatter(const communicator& comm, T* out_values, int n, int root)
- {
- BOOST_ASSERT(comm.rank() != root);
- detail::scatter_impl(comm, out_values, n, root, is_mpi_datatype<T>());
- }
- } } // end namespace boost::mpi
- #endif // BOOST_MPI_SCATTER_HPP
|