1 // Copyright (C) 2005, 2006 Douglas Gregor.
2
3 // Use, modification and distribution is subject to the Boost Software
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6
7 // Message Passing Interface 1.1 -- Section 4.5. Gather
8 #ifndef BOOST_MPI_ALLGATHER_HPP
9 #define BOOST_MPI_ALLGATHER_HPP
10
11 #include <cassert>
12 #include <cstddef>
13 #include <numeric>
14 #include <boost/mpi/exception.hpp>
15 #include <boost/mpi/datatype.hpp>
16 #include <vector>
17 #include <boost/mpi/packed_oarchive.hpp>
18 #include <boost/mpi/packed_iarchive.hpp>
19 #include <boost/mpi/detail/point_to_point.hpp>
20 #include <boost/mpi/communicator.hpp>
21 #include <boost/mpi/environment.hpp>
22 #include <boost/mpi/detail/offsets.hpp>
23 #include <boost/mpi/detail/antiques.hpp>
24 #include <boost/assert.hpp>
25
26 namespace boost { namespace mpi {
27
28 namespace detail {
29 // We're all-gathering for a type that has an associated MPI
30 // datatype, so we'll use MPI_Gather to do all of the work.
31 template<typename T>
32 void
all_gather_impl(const communicator & comm,const T * in_values,int n,T * out_values,mpl::true_)33 all_gather_impl(const communicator& comm, const T* in_values, int n,
34 T* out_values, mpl::true_)
35 {
36 MPI_Datatype type = get_mpi_datatype<T>(*in_values);
37 BOOST_MPI_CHECK_RESULT(MPI_Allgather,
38 (const_cast<T*>(in_values), n, type,
39 out_values, n, type, comm));
40 }
41
42 // We're all-gathering for a type that does not have an
43 // associated MPI datatype, so we'll need to serialize
44 // it.
45 template<typename T>
46 void
all_gather_impl(const communicator & comm,const T * in_values,int n,T * out_values,int const * sizes,int const * skips,mpl::false_)47 all_gather_impl(const communicator& comm, const T* in_values, int n,
48 T* out_values, int const* sizes, int const* skips, mpl::false_)
49 {
50 int nproc = comm.size();
51 // first, gather all size, these size can be different for
52 // each process
53 packed_oarchive oa(comm);
54 for (int i = 0; i < n; ++i) {
55 oa << in_values[i];
56 }
57 std::vector<int> oasizes(nproc);
58 int oasize = oa.size();
59 BOOST_MPI_CHECK_RESULT(MPI_Allgather,
60 (&oasize, 1, MPI_INT,
61 c_data(oasizes), 1, MPI_INT,
62 MPI_Comm(comm)));
63 // Gather the archives, which can be of different sizes, so
64 // we need to use allgatherv.
65 // Every thing is contiguous, so the offsets can be
66 // deduced from the collected sizes.
67 std::vector<int> offsets(nproc);
68 sizes2offsets(oasizes, offsets);
69 packed_iarchive::buffer_type recv_buffer(std::accumulate(oasizes.begin(), oasizes.end(), 0));
70 BOOST_MPI_CHECK_RESULT(MPI_Allgatherv,
71 (const_cast<void*>(oa.address()), int(oa.size()), MPI_BYTE,
72 c_data(recv_buffer), c_data(oasizes), c_data(offsets), MPI_BYTE,
73 MPI_Comm(comm)));
74 for (int src = 0; src < nproc; ++src) {
75 int nb = sizes ? sizes[src] : n;
76 int skip = skips ? skips[src] : 0;
77 std::advance(out_values, skip);
78 if (src == comm.rank()) { // this is our local data
79 for (int i = 0; i < nb; ++i) {
80 *out_values++ = *in_values++;
81 }
82 } else {
83 packed_iarchive ia(comm, recv_buffer, boost::archive::no_header, offsets[src]);
84 for (int i = 0; i < nb; ++i) {
85 ia >> *out_values++;
86 }
87 }
88 }
89 }
90
91 // We're all-gathering for a type that does not have an
92 // associated MPI datatype, so we'll need to serialize
93 // it.
94 template<typename T>
95 void
all_gather_impl(const communicator & comm,const T * in_values,int n,T * out_values,mpl::false_ isnt_mpi_type)96 all_gather_impl(const communicator& comm, const T* in_values, int n,
97 T* out_values, mpl::false_ isnt_mpi_type)
98 {
99 all_gather_impl(comm, in_values, n, out_values, (int const*)0, (int const*)0, isnt_mpi_type);
100 }
101 } // end namespace detail
102
103 template<typename T>
104 void
all_gather(const communicator & comm,const T & in_value,T * out_values)105 all_gather(const communicator& comm, const T& in_value, T* out_values)
106 {
107 detail::all_gather_impl(comm, &in_value, 1, out_values, is_mpi_datatype<T>());
108 }
109
110 template<typename T>
111 void
all_gather(const communicator & comm,const T & in_value,std::vector<T> & out_values)112 all_gather(const communicator& comm, const T& in_value, std::vector<T>& out_values)
113 {
114 using detail::c_data;
115 out_values.resize(comm.size());
116 ::boost::mpi::all_gather(comm, in_value, c_data(out_values));
117 }
118
119 template<typename T>
120 void
all_gather(const communicator & comm,const T * in_values,int n,T * out_values)121 all_gather(const communicator& comm, const T* in_values, int n, T* out_values)
122 {
123 detail::all_gather_impl(comm, in_values, n, out_values, is_mpi_datatype<T>());
124 }
125
126 template<typename T>
127 void
all_gather(const communicator & comm,const T * in_values,int n,std::vector<T> & out_values)128 all_gather(const communicator& comm, const T* in_values, int n, std::vector<T>& out_values)
129 {
130 using detail::c_data;
131 out_values.resize(comm.size() * n);
132 ::boost::mpi::all_gather(comm, in_values, n, c_data(out_values));
133 }
134
135 } } // end namespace boost::mpi
136
137 #endif // BOOST_MPI_ALL_GATHER_HPP
138