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/skeleton_and_content.hpp>
11 #include <boost/mpi/detail/point_to_point.hpp>
12 
13 namespace boost { namespace mpi {
14 
15 /***************************************************************************
16  * status                                                                  *
17  ***************************************************************************/
cancelled() const18 bool status::cancelled() const
19 {
20   int flag = 0;
21   BOOST_MPI_CHECK_RESULT(MPI_Test_cancelled, (&m_status, &flag));
22   return flag != 0;
23 }
24 
25 /***************************************************************************
26  * communicator                                                            *
27  ***************************************************************************/
28 
communicator()29 communicator::communicator()
30 {
31   comm_ptr.reset(new MPI_Comm(MPI_COMM_WORLD));
32 }
33 
communicator(const MPI_Comm & comm,comm_create_kind kind)34 communicator::communicator(const MPI_Comm& comm, comm_create_kind kind)
35 {
36   if (comm == MPI_COMM_NULL)
37     /* MPI_COMM_NULL indicates that the communicator is not usable. */
38     return;
39 
40   switch (kind) {
41   case comm_duplicate:
42     {
43       MPI_Comm newcomm;
44       BOOST_MPI_CHECK_RESULT(MPI_Comm_dup, (comm, &newcomm));
45       comm_ptr.reset(new MPI_Comm(newcomm), comm_free());
46       MPI_Comm_set_errhandler(newcomm, MPI_ERRORS_RETURN);
47       break;
48     }
49 
50   case comm_take_ownership:
51     comm_ptr.reset(new MPI_Comm(comm), comm_free());
52     break;
53 
54   case comm_attach:
55     comm_ptr.reset(new MPI_Comm(comm));
56     break;
57   }
58 }
59 
communicator(const communicator & comm,const boost::mpi::group & subgroup)60 communicator::communicator(const communicator& comm,
61                            const boost::mpi::group& subgroup)
62 {
63   MPI_Comm newcomm;
64   BOOST_MPI_CHECK_RESULT(MPI_Comm_create,
65                          ((MPI_Comm)comm, (MPI_Group)subgroup, &newcomm));
66   if(newcomm != MPI_COMM_NULL)
67     comm_ptr.reset(new MPI_Comm(newcomm), comm_free());
68 }
69 
size() const70 int communicator::size() const
71 {
72   int size_;
73   BOOST_MPI_CHECK_RESULT(MPI_Comm_size, (MPI_Comm(*this), &size_));
74   return size_;
75 }
76 
rank() const77 int communicator::rank() const
78 {
79   int rank_;
80   BOOST_MPI_CHECK_RESULT(MPI_Comm_rank, (MPI_Comm(*this), &rank_));
81   return rank_;
82 }
83 
group() const84 boost::mpi::group communicator::group() const
85 {
86   MPI_Group gr;
87   BOOST_MPI_CHECK_RESULT(MPI_Comm_group, ((MPI_Comm)*this, &gr));
88   return boost::mpi::group(gr, /*adopt=*/true);
89 }
90 
send(int dest,int tag) const91 void communicator::send(int dest, int tag) const
92 {
93   BOOST_MPI_CHECK_RESULT(MPI_Send,
94                          (MPI_BOTTOM, 0, MPI_PACKED,
95                           dest, tag, MPI_Comm(*this)));
96 }
97 
recv(int source,int tag) const98 status communicator::recv(int source, int tag) const
99 {
100   status stat;
101   BOOST_MPI_CHECK_RESULT(MPI_Recv,
102                          (MPI_BOTTOM, 0, MPI_PACKED,
103                           source, tag, MPI_Comm(*this), &stat.m_status));
104   return stat;
105 }
106 
iprobe(int source,int tag) const107 optional<status> communicator::iprobe(int source, int tag) const
108 {
109   typedef optional<status> result_type;
110 
111   status stat;
112   int flag;
113   BOOST_MPI_CHECK_RESULT(MPI_Iprobe,
114                          (source, tag, MPI_Comm(*this), &flag,
115                           &stat.m_status));
116   if (flag) return stat;
117   else return result_type();
118 }
119 
probe(int source,int tag) const120 status communicator::probe(int source, int tag) const
121 {
122   status stat;
123   BOOST_MPI_CHECK_RESULT(MPI_Probe,
124                          (source, tag, MPI_Comm(*this), &stat.m_status));
125   return stat;
126 }
127 
128 void (communicator::barrier)() const
129 {
130   BOOST_MPI_CHECK_RESULT(MPI_Barrier, (MPI_Comm(*this)));
131 }
132 
133 
operator MPI_Comm() const134 communicator::operator MPI_Comm() const
135 {
136   if (comm_ptr) return *comm_ptr;
137   else return MPI_COMM_NULL;
138 }
139 
split(int color) const140 communicator communicator::split(int color) const
141 {
142   return split(color, rank());
143 }
144 
split(int color,int key) const145 communicator communicator::split(int color, int key) const
146 {
147   MPI_Comm newcomm;
148   BOOST_MPI_CHECK_RESULT(MPI_Comm_split,
149                          (MPI_Comm(*this), color, key, &newcomm));
150   return communicator(newcomm, comm_take_ownership);
151 }
152 
as_intercommunicator() const153 optional<intercommunicator> communicator::as_intercommunicator() const
154 {
155   int flag;
156   BOOST_MPI_CHECK_RESULT(MPI_Comm_test_inter, ((MPI_Comm)*this, &flag));
157   if (flag)
158     return intercommunicator(comm_ptr);
159   else
160     return optional<intercommunicator>();
161 }
162 
as_graph_communicator() const163 optional<graph_communicator> communicator::as_graph_communicator() const
164 {
165   optional<graph_communicator> graph;
166   // topology test not allowed on MPI_NULL_COMM
167   if (bool(*this)) {
168     int status;
169     BOOST_MPI_CHECK_RESULT(MPI_Topo_test, ((MPI_Comm)*this, &status));
170     if (status == MPI_GRAPH)
171       graph = graph_communicator(comm_ptr);
172   }
173   return graph;
174 }
175 
has_cartesian_topology() const176 bool communicator::has_cartesian_topology() const
177 {
178   // topology test not allowed on MPI_NULL_COM
179   if (!bool(*this)) {
180     return false;
181   } else {
182     int status;
183     BOOST_MPI_CHECK_RESULT(MPI_Topo_test, ((MPI_Comm)*this, &status));
184     return status == MPI_CART;
185   }
186 }
187 
abort(int errcode) const188 void communicator::abort(int errcode) const
189 {
190   BOOST_MPI_CHECK_RESULT(MPI_Abort, (MPI_Comm(*this), errcode));
191 }
192 
193 /*************************************************************
194  * archived send/recv                                     *
195  *************************************************************/
196 template<>
197 void
send(int dest,int tag,const packed_oarchive & ar) const198 communicator::send<packed_oarchive>(int dest, int tag,
199                                     const packed_oarchive& ar) const
200 {
201   detail::packed_archive_send(MPI_Comm(*this), dest, tag, ar);
202 }
203 
204 template<>
205 void
send(int dest,int tag,const packed_skeleton_oarchive & ar) const206 communicator::send<packed_skeleton_oarchive>
207   (int dest, int tag, const packed_skeleton_oarchive& ar) const
208 {
209   this->send(dest, tag, ar.get_skeleton());
210 }
211 
212 template<>
send(int dest,int tag,const content & c) const213 void communicator::send<content>(int dest, int tag, const content& c) const
214 {
215   BOOST_MPI_CHECK_RESULT(MPI_Send,
216                          (MPI_BOTTOM, 1, c.get_mpi_datatype(),
217                           dest, tag, MPI_Comm(*this)));
218 }
219 
220 template<>
221 status
recv(int source,int tag,packed_iarchive & ar) const222 communicator::recv<packed_iarchive>(int source, int tag,
223                                     packed_iarchive& ar) const
224 {
225   status stat;
226   detail::packed_archive_recv(MPI_Comm(*this), source, tag, ar,
227                               stat.m_status);
228   return stat;
229 }
230 
231 template<>
232 status
recv(int source,int tag,packed_skeleton_iarchive & ar) const233 communicator::recv<packed_skeleton_iarchive>
234   (int source, int tag, packed_skeleton_iarchive& ar) const
235 {
236   return this->recv(source, tag, ar.get_skeleton());
237 }
238 
239 template<>
240 status
recv(int source,int tag,const content & c) const241 communicator::recv<const content>(int source, int tag, const content& c) const
242 {
243   status stat;
244   BOOST_MPI_CHECK_RESULT(MPI_Recv,
245                          (MPI_BOTTOM, 1, c.get_mpi_datatype(),
246                           source, tag, MPI_Comm(*this), &stat.m_status));
247   return stat;
248 }
249 
250 /*************************************************************
251  * non-blocking send/recv                                    *
252  *************************************************************/
253 template<>
254 request
isend(int dest,int tag,const packed_oarchive & ar) const255 communicator::isend<packed_oarchive>(int dest, int tag,
256                                      const packed_oarchive& ar) const
257 {
258   request req;
259   detail::packed_archive_isend(MPI_Comm(*this), dest, tag, ar,
260                                &req.m_requests[0] ,2);
261   return req;
262 }
263 
264 template<>
265 request
isend(int dest,int tag,const packed_skeleton_oarchive & ar) const266 communicator::isend<packed_skeleton_oarchive>
267   (int dest, int tag, const packed_skeleton_oarchive& ar) const
268 {
269   return this->isend(dest, tag, ar.get_skeleton());
270 }
271 
272 template<>
isend(int dest,int tag,const content & c) const273 request communicator::isend<content>(int dest, int tag, const content& c) const
274 {
275   request req;
276   BOOST_MPI_CHECK_RESULT(MPI_Isend,
277                          (MPI_BOTTOM, 1, c.get_mpi_datatype(),
278                           dest, tag, MPI_Comm(*this), &req.m_requests[0]));
279   return req;
280 }
281 
isend(int dest,int tag) const282 request communicator::isend(int dest, int tag) const
283 {
284   request req;
285   BOOST_MPI_CHECK_RESULT(MPI_Isend,
286                          (MPI_BOTTOM, 0, MPI_PACKED,
287                           dest, tag, MPI_Comm(*this), &req.m_requests[0]));
288   return req;
289 }
290 
291 template<>
292 request
irecv(int source,int tag,packed_skeleton_iarchive & ar) const293 communicator::irecv<packed_skeleton_iarchive>
294   (int source, int tag, packed_skeleton_iarchive& ar) const
295 {
296   return this->irecv(source, tag, ar.get_skeleton());
297 }
298 
299 template<>
300 request
irecv(int source,int tag,const content & c) const301 communicator::irecv<const content>(int source, int tag,
302                                    const content& c) const
303 {
304   request req;
305   BOOST_MPI_CHECK_RESULT(MPI_Irecv,
306                          (MPI_BOTTOM, 1, c.get_mpi_datatype(),
307                           source, tag, MPI_Comm(*this), &req.m_requests[0]));
308   return req;
309 }
310 
irecv(int source,int tag) const311 request communicator::irecv(int source, int tag) const
312 {
313   request req;
314   BOOST_MPI_CHECK_RESULT(MPI_Irecv,
315                          (MPI_BOTTOM, 0, MPI_PACKED,
316                           source, tag, MPI_Comm(*this), &req.m_requests[0]));
317   return req;
318 }
319 
operator ==(const communicator & comm1,const communicator & comm2)320 bool operator==(const communicator& comm1, const communicator& comm2)
321 {
322   int result;
323   BOOST_MPI_CHECK_RESULT(MPI_Comm_compare,
324                          ((MPI_Comm)comm1, (MPI_Comm)comm2, &result));
325   return result == MPI_IDENT;
326 }
327 
328 } } // end namespace boost::mpi
329