]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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.6. Scatter | |
8 | #ifndef BOOST_MPI_SCATTER_HPP | |
9 | #define BOOST_MPI_SCATTER_HPP | |
10 | ||
11 | #include <boost/mpi/exception.hpp> | |
12 | #include <boost/mpi/datatype.hpp> | |
13 | #include <vector> | |
14 | #include <boost/mpi/packed_oarchive.hpp> | |
15 | #include <boost/mpi/packed_iarchive.hpp> | |
16 | #include <boost/mpi/detail/point_to_point.hpp> | |
17 | #include <boost/mpi/communicator.hpp> | |
18 | #include <boost/mpi/environment.hpp> | |
11fdf7f2 TL |
19 | #include <boost/mpi/detail/offsets.hpp> |
20 | #include <boost/mpi/detail/antiques.hpp> | |
7c673cae FG |
21 | #include <boost/assert.hpp> |
22 | ||
23 | namespace boost { namespace mpi { | |
24 | ||
25 | namespace detail { | |
11fdf7f2 TL |
26 | // We're scattering from the root for a type that has an associated MPI |
27 | // datatype, so we'll use MPI_Scatter to do all of the work. | |
28 | template<typename T> | |
29 | void | |
30 | scatter_impl(const communicator& comm, const T* in_values, T* out_values, | |
31 | int n, int root, mpl::true_) | |
32 | { | |
33 | MPI_Datatype type = get_mpi_datatype<T>(*in_values); | |
34 | BOOST_MPI_CHECK_RESULT(MPI_Scatter, | |
35 | (const_cast<T*>(in_values), n, type, | |
36 | out_values, n, type, root, comm)); | |
37 | } | |
7c673cae | 38 | |
11fdf7f2 TL |
39 | // We're scattering from a non-root for a type that has an associated MPI |
40 | // datatype, so we'll use MPI_Scatter to do all of the work. | |
41 | template<typename T> | |
42 | void | |
43 | scatter_impl(const communicator& comm, T* out_values, int n, int root, | |
44 | mpl::true_) | |
45 | { | |
46 | MPI_Datatype type = get_mpi_datatype<T>(*out_values); | |
47 | BOOST_MPI_CHECK_RESULT(MPI_Scatter, | |
48 | (0, n, type, | |
49 | out_values, n, type, | |
50 | root, comm)); | |
51 | } | |
52 | ||
53 | // Fill the sendbuf while keeping trac of the slot's footprints | |
54 | // Used in the first steps of both scatter and scatterv | |
55 | // Nslots contains the number of slots being sent | |
56 | // to each process (identical values for scatter). | |
57 | // skiped_slots, if present, is deduced from the | |
58 | // displacement array authorised be the MPI API, | |
59 | // for some yet to be determined reason. | |
60 | template<typename T> | |
61 | void | |
62 | fill_scatter_sendbuf(const communicator& comm, T const* values, | |
63 | int const* nslots, int const* skipped_slots, | |
64 | packed_oarchive::buffer_type& sendbuf, std::vector<int>& archsizes) { | |
65 | int nproc = comm.size(); | |
66 | archsizes.resize(nproc); | |
67 | ||
68 | for (int dest = 0; dest < nproc; ++dest) { | |
69 | if (skipped_slots) { // wee need to keep this for backward compatibility | |
70 | for(int k= 0; k < skipped_slots[dest]; ++k) ++values; | |
71 | } | |
72 | packed_oarchive procarchive(comm); | |
73 | for (int i = 0; i < nslots[dest]; ++i) { | |
74 | procarchive << *values++; | |
75 | } | |
76 | int archsize = procarchive.size(); | |
77 | sendbuf.resize(sendbuf.size() + archsize); | |
78 | archsizes[dest] = archsize; | |
79 | char const* aptr = static_cast<char const*>(procarchive.address()); | |
80 | std::copy(aptr, aptr+archsize, sendbuf.end()-archsize); | |
7c673cae | 81 | } |
11fdf7f2 | 82 | } |
7c673cae | 83 | |
11fdf7f2 TL |
84 | template<typename T, class A> |
85 | T* | |
86 | non_const_data(std::vector<T,A> const& v) { | |
87 | using detail::c_data; | |
88 | return const_cast<T*>(c_data(v)); | |
89 | } | |
90 | ||
91 | // Dispatch the sendbuf among proc. | |
92 | // Used in the second steps of both scatter and scatterv | |
93 | // in_value is only provide in the non variadic case. | |
94 | template<typename T> | |
95 | void | |
96 | dispatch_scatter_sendbuf(const communicator& comm, | |
97 | packed_oarchive::buffer_type const& sendbuf, std::vector<int> const& archsizes, | |
98 | T const* in_values, | |
99 | T* out_values, int n, int root) { | |
100 | // Distribute the sizes | |
101 | int myarchsize; | |
102 | BOOST_MPI_CHECK_RESULT(MPI_Scatter, | |
92f5a8d4 TL |
103 | (non_const_data(archsizes), 1, MPI_INT, |
104 | &myarchsize, 1, MPI_INT, root, comm)); | |
11fdf7f2 TL |
105 | std::vector<int> offsets; |
106 | if (root == comm.rank()) { | |
107 | sizes2offsets(archsizes, offsets); | |
108 | } | |
109 | // Get my proc archive | |
110 | packed_iarchive::buffer_type recvbuf; | |
111 | recvbuf.resize(myarchsize); | |
112 | BOOST_MPI_CHECK_RESULT(MPI_Scatterv, | |
113 | (non_const_data(sendbuf), non_const_data(archsizes), c_data(offsets), MPI_BYTE, | |
114 | c_data(recvbuf), recvbuf.size(), MPI_BYTE, | |
115 | root, MPI_Comm(comm))); | |
116 | // Unserialize | |
117 | if ( in_values != 0 && root == comm.rank()) { | |
118 | // Our own local values are already here: just copy them. | |
119 | std::copy(in_values + root * n, in_values + (root + 1) * n, out_values); | |
120 | } else { | |
121 | // Otherwise deserialize: | |
122 | packed_iarchive iarchv(comm, recvbuf); | |
123 | for (int i = 0; i < n; ++i) { | |
124 | iarchv >> out_values[i]; | |
7c673cae FG |
125 | } |
126 | } | |
11fdf7f2 | 127 | } |
7c673cae | 128 | |
11fdf7f2 TL |
129 | // We're scattering from the root for a type that does not have an |
130 | // associated MPI datatype, so we'll need to serialize it. | |
131 | template<typename T> | |
132 | void | |
133 | scatter_impl(const communicator& comm, const T* in_values, T* out_values, | |
134 | int n, int root, mpl::false_) | |
135 | { | |
136 | packed_oarchive::buffer_type sendbuf; | |
137 | std::vector<int> archsizes; | |
138 | ||
139 | if (root == comm.rank()) { | |
140 | std::vector<int> nslots(comm.size(), n); | |
141 | fill_scatter_sendbuf(comm, in_values, c_data(nslots), (int const*)0, sendbuf, archsizes); | |
7c673cae | 142 | } |
11fdf7f2 TL |
143 | dispatch_scatter_sendbuf(comm, sendbuf, archsizes, in_values, out_values, n, root); |
144 | } | |
145 | ||
146 | template<typename T> | |
147 | void | |
148 | scatter_impl(const communicator& comm, T* out_values, int n, int root, | |
149 | mpl::false_ is_mpi_type) | |
150 | { | |
151 | scatter_impl(comm, (T const*)0, out_values, n, root, is_mpi_type); | |
152 | } | |
7c673cae FG |
153 | } // end namespace detail |
154 | ||
155 | template<typename T> | |
156 | void | |
157 | scatter(const communicator& comm, const T* in_values, T& out_value, int root) | |
158 | { | |
11fdf7f2 | 159 | detail::scatter_impl(comm, in_values, &out_value, 1, root, is_mpi_datatype<T>()); |
7c673cae FG |
160 | } |
161 | ||
162 | template<typename T> | |
163 | void | |
164 | scatter(const communicator& comm, const std::vector<T>& in_values, T& out_value, | |
165 | int root) | |
166 | { | |
11fdf7f2 TL |
167 | using detail::c_data; |
168 | ::boost::mpi::scatter<T>(comm, c_data(in_values), out_value, root); | |
7c673cae FG |
169 | } |
170 | ||
171 | template<typename T> | |
172 | void scatter(const communicator& comm, T& out_value, int root) | |
173 | { | |
174 | BOOST_ASSERT(comm.rank() != root); | |
175 | detail::scatter_impl(comm, &out_value, 1, root, is_mpi_datatype<T>()); | |
176 | } | |
177 | ||
178 | template<typename T> | |
179 | void | |
180 | scatter(const communicator& comm, const T* in_values, T* out_values, int n, | |
181 | int root) | |
182 | { | |
11fdf7f2 | 183 | detail::scatter_impl(comm, in_values, out_values, n, root, is_mpi_datatype<T>()); |
7c673cae FG |
184 | } |
185 | ||
186 | template<typename T> | |
187 | void | |
188 | scatter(const communicator& comm, const std::vector<T>& in_values, | |
189 | T* out_values, int n, int root) | |
190 | { | |
20effc67 | 191 | ::boost::mpi::scatter(comm, detail::c_data(in_values), out_values, n, root); |
7c673cae FG |
192 | } |
193 | ||
194 | template<typename T> | |
195 | void scatter(const communicator& comm, T* out_values, int n, int root) | |
196 | { | |
197 | BOOST_ASSERT(comm.rank() != root); | |
198 | detail::scatter_impl(comm, out_values, n, root, is_mpi_datatype<T>()); | |
199 | } | |
200 | ||
201 | } } // end namespace boost::mpi | |
202 | ||
203 | #endif // BOOST_MPI_SCATTER_HPP |