• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 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 // A test of the nonblocking point-to-point operations.
8 #include <boost/mpi/nonblocking.hpp>
9 #include <boost/mpi/communicator.hpp>
10 #include <boost/mpi/environment.hpp>
11 #include "gps_position.hpp"
12 #include <boost/lexical_cast.hpp>
13 #include <boost/serialization/string.hpp>
14 #include <boost/serialization/list.hpp>
15 #include <iterator>
16 #include <algorithm>
17 //#include "debugger.cpp"
18 
19 #define BOOST_TEST_MODULE mpi_non_blockin_test
20 #include <boost/test/included/unit_test.hpp>
21 
22 using boost::mpi::communicator;
23 using boost::mpi::request;
24 using boost::mpi::status;
25 
26 enum method_kind {
27   mk_wait_any, mk_test_any, mk_wait_all, mk_wait_all_keep,
28   mk_test_all, mk_test_all_keep, mk_wait_some, mk_wait_some_keep,
29   mk_test_some, mk_test_some_keep,
30   mk_test_size
31 };
32 
33 static const char* method_kind_names[mk_test_size] = {
34   "wait_any",
35   "test_any",
36   "wait_all",
37   "wait_all (keep results)",
38   "test_all",
39   "test_all (keep results)",
40   "wait_some",
41   "wait_some (keep results)",
42   "test_some",
43   "test_some (keep results)"
44 };
45 
46 
47 template<typename T>
48 void
nonblocking_tests(const communicator & comm,const T * values,int num_values,const char * kind,bool composite)49 nonblocking_tests( const communicator& comm, const T* values, int num_values,
50                    const char* kind, bool composite)
51 {
52   nonblocking_test(comm, values, num_values, kind, mk_wait_any);
53   nonblocking_test(comm, values, num_values, kind, mk_test_any);
54   //wait_for_debugger(comm);
55   nonblocking_test(comm, values, num_values, kind, mk_wait_all);
56   nonblocking_test(comm, values, num_values, kind, mk_wait_all_keep);
57   if (!composite) {
58     nonblocking_test(comm, values, num_values, kind, mk_test_all);
59     nonblocking_test(comm, values, num_values, kind, mk_test_all_keep);
60   }
61   nonblocking_test(comm, values, num_values, kind, mk_wait_some);
62   nonblocking_test(comm, values, num_values, kind, mk_wait_some_keep);
63   nonblocking_test(comm, values, num_values, kind, mk_test_some);
64   nonblocking_test(comm, values, num_values, kind, mk_test_some_keep);
65 }
66 
67 template<typename T>
68 void
nonblocking_test(const communicator & comm,const T * values,int num_values,const char * kind,method_kind method)69 nonblocking_test(const communicator& comm, const T* values, int num_values,
70                  const char* kind, method_kind method)
71 {
72   using boost::mpi::wait_any;
73   using boost::mpi::test_any;
74   using boost::mpi::wait_all;
75   using boost::mpi::test_all;
76   using boost::mpi::wait_some;
77   using boost::mpi::test_some;
78 
79   int next = (comm.rank() + 1) % comm.size();
80   int prev = (comm.rank() + comm.size() - 1) % comm.size();
81 
82   if (comm.rank() == 0) {
83     std::cout << "Testing " << method_kind_names[method]
84               << " with " << kind << "...";
85     std::cout.flush();
86   }
87 
88   typedef std::pair<status, std::vector<request>::iterator>
89     status_iterator_pair;
90 
91   T incoming_value;
92   std::vector<T> incoming_values(num_values);
93   std::vector<request> reqs;
94   // Send/receive the first value
95   reqs.push_back(comm.isend(next, 0, values[0]));
96   reqs.push_back(comm.irecv(prev, 0, incoming_value));
97 
98   if (method != mk_wait_any && method != mk_test_any) {
99 #ifndef LAM_MPI
100     // We've run into problems here (with 0-length messages) with
101     // LAM/MPI on Mac OS X and x86-86 Linux. Will investigate
102     // further at a later time, but the problem only seems to occur
103     // when using shared memory, not TCP.
104 
105     // Send/receive an empty message
106     reqs.push_back(comm.isend(next, 1));
107     reqs.push_back(comm.irecv(prev, 1));
108 #endif
109 
110     // Send/receive an array
111     reqs.push_back(comm.isend(next, 2, values, num_values));
112     reqs.push_back(comm.irecv(prev, 2, &incoming_values.front(), num_values));
113   }
114 
115   switch (method) {
116   case mk_wait_any:
117     if (wait_any(reqs.begin(), reqs.end()).second == reqs.begin())
118       reqs[1].wait();
119     else
120       reqs[0].wait();
121     break;
122 
123   case mk_test_any:
124     {
125       boost::optional<status_iterator_pair> result;
126       do {
127         result = test_any(reqs.begin(), reqs.end());
128       } while (!result);
129       if (result->second == reqs.begin())
130         reqs[1].wait();
131       else
132         reqs[0].wait();
133       break;
134     }
135 
136   case mk_wait_all:
137     wait_all(reqs.begin(), reqs.end());
138     break;
139 
140   case mk_wait_all_keep:
141     {
142       std::vector<status> stats;
143       wait_all(reqs.begin(), reqs.end(), std::back_inserter(stats));
144     }
145     break;
146 
147   case mk_test_all:
148     while (!test_all(reqs.begin(), reqs.end())) { /* Busy wait */ }
149     break;
150 
151   case mk_test_all_keep:
152     {
153       std::vector<status> stats;
154       while (!test_all(reqs.begin(), reqs.end(), std::back_inserter(stats)))
155         /* Busy wait */;
156     }
157     break;
158 
159   case mk_wait_some:
160     {
161       std::vector<request>::iterator pos = reqs.end();
162       do {
163         pos = wait_some(reqs.begin(), pos);
164       } while (pos != reqs.begin());
165     }
166     break;
167 
168   case mk_wait_some_keep:
169     {
170       std::vector<status> stats;
171       std::vector<request>::iterator pos = reqs.end();
172       do {
173         pos = wait_some(reqs.begin(), pos, std::back_inserter(stats)).second;
174       } while (pos != reqs.begin());
175     }
176     break;
177 
178   case mk_test_some:
179     {
180       std::vector<request>::iterator pos = reqs.end();
181       do {
182         pos = test_some(reqs.begin(), pos);
183       } while (pos != reqs.begin());
184     }
185     break;
186 
187   case mk_test_some_keep:
188     {
189       std::vector<status> stats;
190       std::vector<request>::iterator pos = reqs.end();
191       do {
192         pos = test_some(reqs.begin(), pos, std::back_inserter(stats)).second;
193       } while (pos != reqs.begin());
194     }
195     break;
196 
197   default:
198     BOOST_CHECK(false);
199   }
200 
201   if (comm.rank() == 0) {
202     bool okay = true;
203 
204     if (!((incoming_value == values[0])))
205       okay = false;
206 
207     if (method != mk_wait_any && method != mk_test_any
208         && !std::equal(incoming_values.begin(), incoming_values.end(),
209                        values))
210       okay = false;
211 
212     if (okay)
213       std::cout << "OK." << std::endl;
214     else
215       std::cerr << "ERROR!" << std::endl;
216   }
217 
218   BOOST_CHECK(incoming_value == values[0]);
219 
220   if (method != mk_wait_any && method != mk_test_any)
221     BOOST_CHECK(std::equal(incoming_values.begin(), incoming_values.end(),
222                            values));
223 }
224 
BOOST_AUTO_TEST_CASE(nonblocking)225 BOOST_AUTO_TEST_CASE(nonblocking)
226 {
227   boost::mpi::environment env;
228   communicator comm;
229 
230   int int_array[3] = {17, 42, 256};
231   nonblocking_tests(comm, int_array, 3, "integers", false);
232 
233   gps_position gps_array[2] = {
234     gps_position(17, 42, .06),
235     gps_position(42, 17, .06)
236   };
237   nonblocking_tests(comm, gps_array, 2, "gps positions", false);
238 
239   std::string string_array[2] = { "Hello", "World" };
240   nonblocking_tests(comm, string_array, 2, "strings", true);
241 
242   std::list<std::string> lst_of_strings;
243   for (int i = 0; i < comm.size(); ++i)
244     lst_of_strings.push_back(boost::lexical_cast<std::string>(i));
245 
246   nonblocking_tests(comm, &lst_of_strings, 1, "list of strings", true);
247 }
248