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 #include <boost/mpi/communicator.hpp>
7 #include <boost/mpi/group.hpp>
8 #include <boost/mpi/intercommunicator.hpp>
9 #include <boost/mpi/graph_communicator.hpp>
10 #include <boost/mpi/cartesian_communicator.hpp>
11 #include <boost/mpi/skeleton_and_content.hpp>
12 #include <boost/mpi/detail/point_to_point.hpp>
13
14 namespace boost { namespace mpi {
15
communicator()16 communicator::communicator()
17 {
18 comm_ptr.reset(new MPI_Comm(MPI_COMM_WORLD));
19 }
20
communicator(const MPI_Comm & comm,comm_create_kind kind)21 communicator::communicator(const MPI_Comm& comm, comm_create_kind kind)
22 {
23 if (comm == MPI_COMM_NULL)
24 /* MPI_COMM_NULL indicates that the communicator is not usable. */
25 return;
26
27 switch (kind) {
28 case comm_duplicate:
29 {
30 MPI_Comm newcomm;
31 BOOST_MPI_CHECK_RESULT(MPI_Comm_dup, (comm, &newcomm));
32 comm_ptr.reset(new MPI_Comm(newcomm), comm_free());
33 MPI_Comm_set_errhandler(newcomm, MPI_ERRORS_RETURN);
34 break;
35 }
36
37 case comm_take_ownership:
38 comm_ptr.reset(new MPI_Comm(comm), comm_free());
39 break;
40
41 case comm_attach:
42 comm_ptr.reset(new MPI_Comm(comm));
43 break;
44 }
45 }
46
communicator(const communicator & comm,const boost::mpi::group & subgroup)47 communicator::communicator(const communicator& comm,
48 const boost::mpi::group& subgroup)
49 {
50 MPI_Comm newcomm;
51 BOOST_MPI_CHECK_RESULT(MPI_Comm_create,
52 ((MPI_Comm)comm, (MPI_Group)subgroup, &newcomm));
53 if(newcomm != MPI_COMM_NULL)
54 comm_ptr.reset(new MPI_Comm(newcomm), comm_free());
55 }
56
size() const57 int communicator::size() const
58 {
59 int size_;
60 BOOST_MPI_CHECK_RESULT(MPI_Comm_size, (MPI_Comm(*this), &size_));
61 return size_;
62 }
63
rank() const64 int communicator::rank() const
65 {
66 int rank_;
67 BOOST_MPI_CHECK_RESULT(MPI_Comm_rank, (MPI_Comm(*this), &rank_));
68 return rank_;
69 }
70
group() const71 boost::mpi::group communicator::group() const
72 {
73 MPI_Group gr;
74 BOOST_MPI_CHECK_RESULT(MPI_Comm_group, ((MPI_Comm)*this, &gr));
75 return boost::mpi::group(gr, /*adopt=*/true);
76 }
77
send(int dest,int tag) const78 void communicator::send(int dest, int tag) const
79 {
80 BOOST_MPI_CHECK_RESULT(MPI_Send,
81 (MPI_BOTTOM, 0, MPI_PACKED,
82 dest, tag, MPI_Comm(*this)));
83 }
84
recv(int source,int tag) const85 status communicator::recv(int source, int tag) const
86 {
87 status stat;
88 BOOST_MPI_CHECK_RESULT(MPI_Recv,
89 (MPI_BOTTOM, 0, MPI_PACKED,
90 source, tag, MPI_Comm(*this), &stat.m_status));
91 return stat;
92 }
93
iprobe(int source,int tag) const94 optional<status> communicator::iprobe(int source, int tag) const
95 {
96 typedef optional<status> result_type;
97
98 status stat;
99 int flag;
100 BOOST_MPI_CHECK_RESULT(MPI_Iprobe,
101 (source, tag, MPI_Comm(*this), &flag,
102 &stat.m_status));
103 if (flag) return stat;
104 else return result_type();
105 }
106
probe(int source,int tag) const107 status communicator::probe(int source, int tag) const
108 {
109 status stat;
110 BOOST_MPI_CHECK_RESULT(MPI_Probe,
111 (source, tag, MPI_Comm(*this), &stat.m_status));
112 return stat;
113 }
114
115 void (communicator::barrier)() const
116 {
117 BOOST_MPI_CHECK_RESULT(MPI_Barrier, (MPI_Comm(*this)));
118 }
119
120
operator MPI_Comm() const121 communicator::operator MPI_Comm() const
122 {
123 if (comm_ptr) return *comm_ptr;
124 else return MPI_COMM_NULL;
125 }
126
split(int color) const127 communicator communicator::split(int color) const
128 {
129 return split(color, rank());
130 }
131
split(int color,int key) const132 communicator communicator::split(int color, int key) const
133 {
134 MPI_Comm newcomm;
135 BOOST_MPI_CHECK_RESULT(MPI_Comm_split,
136 (MPI_Comm(*this), color, key, &newcomm));
137 return communicator(newcomm, comm_take_ownership);
138 }
139
as_intercommunicator() const140 optional<intercommunicator> communicator::as_intercommunicator() const
141 {
142 int flag;
143 BOOST_MPI_CHECK_RESULT(MPI_Comm_test_inter, ((MPI_Comm)*this, &flag));
144 if (flag)
145 return intercommunicator(comm_ptr);
146 else
147 return optional<intercommunicator>();
148 }
149
has_graph_topology() const150 bool communicator::has_graph_topology() const
151 {
152 bool is_graph = false;
153 // topology test not allowed on MPI_NULL_COMM
154 if (bool(*this)) {
155 int status;
156 BOOST_MPI_CHECK_RESULT(MPI_Topo_test, ((MPI_Comm)*this, &status));
157 is_graph = status == MPI_GRAPH;
158 }
159 return is_graph;
160 }
161
as_graph_communicator() const162 optional<graph_communicator> communicator::as_graph_communicator() const
163 {
164 if (has_graph_topology()) {
165 return graph_communicator(comm_ptr);
166 } else {
167 return optional<graph_communicator>();
168 }
169 }
170
has_cartesian_topology() const171 bool communicator::has_cartesian_topology() const
172 {
173 bool is_cart = false;
174 // topology test not allowed on MPI_NULL_COM
175 if (bool(*this)) {
176 int status;
177 BOOST_MPI_CHECK_RESULT(MPI_Topo_test, ((MPI_Comm)*this, &status));
178 is_cart = status == MPI_CART;
179 }
180 return is_cart;
181 }
182
as_cartesian_communicator() const183 optional<cartesian_communicator> communicator::as_cartesian_communicator() const
184 {
185 if (has_cartesian_topology()) {
186 return cartesian_communicator(comm_ptr);
187 } else {
188 return optional<cartesian_communicator>();
189 }
190 }
191
abort(int errcode) const192 void communicator::abort(int errcode) const
193 {
194 BOOST_MPI_CHECK_RESULT(MPI_Abort, (MPI_Comm(*this), errcode));
195 std::abort();
196 }
197
198 /*************************************************************
199 * archived send/recv *
200 *************************************************************/
201 template<>
202 void
send(int dest,int tag,const packed_oarchive & ar) const203 communicator::send<packed_oarchive>(int dest, int tag,
204 const packed_oarchive& ar) const
205 {
206 detail::packed_archive_send(*this, dest, tag, ar);
207 }
208
209 template<>
210 void
send(int dest,int tag,const packed_skeleton_oarchive & ar) const211 communicator::send<packed_skeleton_oarchive>
212 (int dest, int tag, const packed_skeleton_oarchive& ar) const
213 {
214 this->send(dest, tag, ar.get_skeleton());
215 }
216
217 template<>
send(int dest,int tag,const content & c) const218 void communicator::send<content>(int dest, int tag, const content& c) const
219 {
220 BOOST_MPI_CHECK_RESULT(MPI_Send,
221 (MPI_BOTTOM, 1, c.get_mpi_datatype(),
222 dest, tag, MPI_Comm(*this)));
223 }
224
225 template<>
226 status
recv(int source,int tag,packed_iarchive & ar) const227 communicator::recv<packed_iarchive>(int source, int tag,
228 packed_iarchive& ar) const
229 {
230 status stat;
231 detail::packed_archive_recv(*this, source, tag, ar,
232 stat.m_status);
233 return stat;
234 }
235
236 template<>
237 status
recv(int source,int tag,packed_skeleton_iarchive & ar) const238 communicator::recv<packed_skeleton_iarchive>
239 (int source, int tag, packed_skeleton_iarchive& ar) const
240 {
241 return this->recv(source, tag, ar.get_skeleton());
242 }
243
244 template<>
245 status
recv(int source,int tag,const content & c) const246 communicator::recv<const content>(int source, int tag, const content& c) const
247 {
248 status stat;
249 BOOST_MPI_CHECK_RESULT(MPI_Recv,
250 (MPI_BOTTOM, 1, c.get_mpi_datatype(),
251 source, tag, MPI_Comm(*this), &stat.m_status));
252 return stat;
253 }
254
255 /*************************************************************
256 * non-blocking send/recv *
257 *************************************************************/
258 template<>
259 request
isend(int dest,int tag,const packed_oarchive & ar) const260 communicator::isend<packed_oarchive>(int dest, int tag,
261 const packed_oarchive& ar) const
262 {
263 return detail::packed_archive_isend(*this, dest, tag, ar);
264 }
265
266 template<>
267 request
isend(int dest,int tag,const packed_skeleton_oarchive & ar) const268 communicator::isend<packed_skeleton_oarchive>
269 (int dest, int tag, const packed_skeleton_oarchive& ar) const
270 {
271 return this->isend(dest, tag, ar.get_skeleton());
272 }
273
274 template<>
isend(int dest,int tag,const content & c) const275 request communicator::isend<content>(int dest, int tag, const content& c) const
276 {
277 return request::make_bottom_send(*this, dest, tag, c.get_mpi_datatype());
278 }
279
isend(int dest,int tag) const280 request communicator::isend(int dest, int tag) const
281 {
282 return request::make_empty_send(*this, dest, tag);
283 }
284
285 template<>
286 request
irecv(int source,int tag,packed_skeleton_iarchive & ar) const287 communicator::irecv<packed_skeleton_iarchive>
288 (int source, int tag, packed_skeleton_iarchive& ar) const
289 {
290 return this->irecv(source, tag, ar.get_skeleton());
291 }
292
293 template<>
294 request
irecv(int source,int tag,const content & c) const295 communicator::irecv<const content>(int source, int tag,
296 const content& c) const
297 {
298 return request::make_bottom_recv(*this, source, tag, c.get_mpi_datatype());
299 }
300
irecv(int source,int tag) const301 request communicator::irecv(int source, int tag) const
302 {
303 return request::make_empty_recv(*this, source, tag);
304 }
305
operator ==(const communicator & comm1,const communicator & comm2)306 bool operator==(const communicator& comm1, const communicator& comm2)
307 {
308 int result;
309 BOOST_MPI_CHECK_RESULT(MPI_Comm_compare,
310 (MPI_Comm(comm1), MPI_Comm(comm2), &result));
311 return result == MPI_IDENT;
312 }
313
314 } } // end namespace boost::mpi
315