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