]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright (C) 2004-2008 The Trustees of Indiana University. |
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 | // Authors: Douglas Gregor | |
8 | // Andrew Lumsdaine | |
9 | #include <boost/graph/use_mpi.hpp> | |
10 | #include <boost/config.hpp> | |
11 | #include <boost/throw_exception.hpp> | |
12 | #include <boost/graph/distributed/mpi_process_group.hpp> | |
13 | #include <boost/property_map/property_map.hpp> | |
1e59de90 | 14 | #include <boost/core/lightweight_test.hpp> |
7c673cae FG |
15 | #include <vector> |
16 | #include <string> | |
17 | #include <boost/serialization/vector.hpp> | |
18 | #include <boost/serialization/string.hpp> | |
19 | #include <boost/serialization/utility.hpp> | |
20 | #include <boost/lexical_cast.hpp> | |
21 | #include <boost/graph/parallel/basic_reduce.hpp> | |
22 | ||
23 | #ifdef BOOST_NO_EXCEPTIONS | |
24 | void | |
25 | boost::throw_exception(std::exception const& ex) | |
26 | { | |
27 | std::cout << ex.what() << std::endl; | |
28 | abort(); | |
29 | } | |
30 | #endif | |
31 | ||
32 | using namespace boost; | |
33 | using boost::graph::distributed::mpi_process_group; | |
34 | ||
35 | enum color_t { red, blue }; | |
36 | ||
37 | struct remote_key | |
38 | { | |
39 | remote_key(int p = -1, std::size_t l = 0) : processor(p), local_key(l) {} | |
40 | ||
41 | int processor; | |
42 | std::size_t local_key; | |
43 | ||
44 | template<typename Archiver> | |
45 | void serialize(Archiver& ar, const unsigned int /*version*/) | |
46 | { | |
47 | ar & processor & local_key; | |
48 | } | |
49 | }; | |
50 | ||
51 | namespace boost { namespace mpi { | |
52 | template<> struct is_mpi_datatype<remote_key> : mpl::true_ { }; | |
53 | } } | |
54 | BOOST_IS_BITWISE_SERIALIZABLE(remote_key) | |
55 | BOOST_CLASS_IMPLEMENTATION(remote_key,object_serializable) | |
56 | BOOST_CLASS_TRACKING(remote_key,track_never) | |
57 | ||
58 | namespace boost { | |
59 | ||
60 | template<> | |
61 | struct hash<remote_key> | |
62 | { | |
63 | std::size_t operator()(const remote_key& key) const | |
64 | { | |
65 | std::size_t hash = hash_value(key.processor); | |
66 | hash_combine(hash, key.local_key); | |
67 | return hash; | |
68 | } | |
69 | }; | |
70 | } | |
71 | ||
72 | inline bool operator==(const remote_key& x, const remote_key& y) | |
73 | { return x.processor == y.processor && x.local_key == y.local_key; } | |
74 | ||
75 | struct remote_key_to_global | |
76 | { | |
77 | typedef readable_property_map_tag category; | |
78 | typedef remote_key key_type; | |
79 | typedef std::pair<int, std::size_t> value_type; | |
80 | typedef value_type reference; | |
81 | }; | |
82 | ||
83 | inline std::pair<int, std::size_t> | |
84 | get(remote_key_to_global, const remote_key& key) | |
85 | { | |
86 | return std::make_pair(key.processor, key.local_key); | |
87 | } | |
88 | ||
89 | template<typename T> | |
90 | struct my_reduce : boost::parallel::basic_reduce<T> { | |
91 | BOOST_STATIC_CONSTANT(bool, non_default_resolver = true); | |
92 | }; | |
93 | ||
94 | void colored_test() | |
95 | { | |
96 | mpi_process_group pg; | |
97 | const int n = 500; | |
98 | ||
99 | color_t my_start_color = process_id(pg) % 2 == 0? ::red : ::blue; | |
100 | int next_processor = (process_id(pg) + 1) % num_processes(pg); | |
101 | color_t next_start_color = next_processor % 2 == 0? ::red : ::blue; | |
102 | ||
103 | // Initial color map: even-numbered processes are all red, | |
104 | // odd-numbered processes are all blue. | |
105 | std::vector<color_t> color_vec(n, my_start_color); | |
106 | ||
107 | typedef iterator_property_map<std::vector<color_t>::iterator, | |
108 | identity_property_map> LocalPropertyMap; | |
109 | LocalPropertyMap local_colors(color_vec.begin(), identity_property_map()); | |
110 | ||
111 | synchronize(pg); | |
112 | ||
113 | // Create the distributed property map | |
114 | typedef boost::parallel::distributed_property_map<mpi_process_group, | |
115 | remote_key_to_global, | |
116 | LocalPropertyMap> ColorMap; | |
117 | ColorMap colors(pg, remote_key_to_global(), local_colors); | |
118 | colors.set_reduce(my_reduce<color_t>()); | |
119 | ||
120 | if (process_id(pg) == 0) std::cerr << "Checking local colors..."; | |
121 | // check local processor colors | |
122 | for (int i = 0; i < n; ++i) { | |
123 | remote_key k(process_id(pg), i); | |
1e59de90 | 124 | BOOST_TEST(get(colors, k) == my_start_color); |
7c673cae FG |
125 | } |
126 | ||
127 | colors.set_consistency_model(boost::parallel::cm_bidirectional); | |
128 | if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's default colors..."; | |
129 | // check next processor's colors | |
130 | for (int i = 0; i < n; ++i) { | |
131 | remote_key k(next_processor, i); | |
1e59de90 | 132 | BOOST_TEST(get(colors, k) == color_t()); |
7c673cae FG |
133 | } |
134 | ||
135 | if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing..."; | |
136 | synchronize(pg); | |
137 | ||
138 | if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's colors..."; | |
139 | // check next processor's colors | |
140 | for (int i = 0; i < n; ++i) { | |
141 | remote_key k(next_processor, i); | |
1e59de90 | 142 | BOOST_TEST(get(colors, k) == next_start_color); |
7c673cae FG |
143 | } |
144 | ||
145 | if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing..."; | |
146 | synchronize(pg); | |
147 | ||
148 | if (process_id(pg) == 0) std::cerr << "OK.\nChanging next processor's colors..."; | |
149 | // change the next processor's colors | |
150 | color_t next_finish_color = next_processor % 2 == 0? ::blue : ::red; | |
151 | for (int i = 0; i < n; ++i) { | |
152 | remote_key k(next_processor, i); | |
153 | put(colors, k, next_finish_color); | |
154 | } | |
155 | ||
156 | if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing..."; | |
157 | synchronize(pg); | |
158 | ||
159 | if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed colors..."; | |
160 | // check our own colors | |
161 | color_t my_finish_color = process_id(pg) % 2 == 0? ::blue : ::red; | |
162 | for (int i = 0; i < n; ++i) { | |
163 | remote_key k(process_id(pg), i); | |
1e59de90 | 164 | BOOST_TEST(get(colors, k) == my_finish_color); |
7c673cae FG |
165 | } |
166 | ||
167 | // check our neighbor's colors | |
168 | if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed colors on neighbor..."; | |
169 | for (int i = 0; i < n; ++i) { | |
170 | remote_key k(next_processor, i); | |
1e59de90 | 171 | BOOST_TEST(get(colors, k) == next_finish_color); |
7c673cae FG |
172 | } |
173 | ||
174 | synchronize(pg); | |
175 | ||
176 | if (process_id(pg) == 0) std::cerr << "OK.\n"; | |
177 | } | |
178 | ||
179 | void bool_test() | |
180 | { | |
181 | mpi_process_group pg; | |
182 | const int n = 500; | |
183 | ||
184 | bool my_start_value = process_id(pg) % 2; | |
185 | int next_processor = (process_id(pg) + 1) % num_processes(pg); | |
186 | bool next_start_value = ((process_id(pg) + 1) % num_processes(pg)) % 2; | |
187 | ||
188 | // Initial color map: even-numbered processes are false, | |
189 | // odd-numbered processes are true | |
190 | std::vector<bool> bool_vec(n, my_start_value); | |
191 | ||
192 | typedef iterator_property_map<std::vector<bool>::iterator, | |
193 | identity_property_map> LocalPropertyMap; | |
194 | LocalPropertyMap local_values(bool_vec.begin(), identity_property_map()); | |
195 | ||
196 | synchronize(pg); | |
197 | ||
198 | // Create the distributed property map | |
199 | typedef boost::parallel::distributed_property_map<mpi_process_group, | |
200 | remote_key_to_global, | |
201 | LocalPropertyMap> ValueMap; | |
202 | ValueMap values(pg, remote_key_to_global(), local_values); | |
203 | values.set_reduce(my_reduce<bool>()); | |
204 | ||
205 | if (process_id(pg) == 0) std::cerr << "Checking local values..."; | |
206 | // check local processor values | |
207 | for (int i = 0; i < n; ++i) { | |
208 | remote_key k(process_id(pg), i); | |
1e59de90 | 209 | BOOST_TEST(get(values, k) == my_start_value); |
7c673cae FG |
210 | } |
211 | ||
212 | values.set_consistency_model(boost::parallel::cm_bidirectional); | |
213 | if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's default values..."; | |
214 | // check next processor's values | |
215 | for (int i = 0; i < n; ++i) { | |
216 | remote_key k(next_processor, i); | |
1e59de90 | 217 | BOOST_TEST(get(values, k) == false); |
7c673cae FG |
218 | } |
219 | ||
220 | if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing..."; | |
221 | synchronize(pg); | |
222 | ||
223 | if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's values..."; | |
224 | // check next processor's values | |
225 | for (int i = 0; i < n; ++i) { | |
226 | remote_key k(next_processor, i); | |
1e59de90 | 227 | BOOST_TEST(get(values, k) == next_start_value); |
7c673cae FG |
228 | } |
229 | ||
230 | if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing..."; | |
231 | synchronize(pg); | |
232 | ||
233 | if (process_id(pg) == 0) std::cerr << "OK.\nChanging next processor's values..."; | |
234 | // change the next processor's values | |
235 | bool next_finish_value = next_processor % 2 == 0; | |
236 | for (int i = 0; i < n; ++i) { | |
237 | remote_key k(next_processor, i); | |
238 | put(values, k, next_finish_value); | |
239 | } | |
240 | ||
241 | if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing..."; | |
242 | synchronize(pg); | |
243 | ||
244 | if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed values..."; | |
245 | // check our own values | |
246 | bool my_finish_value = process_id(pg) % 2 == 0; | |
247 | for (int i = 0; i < n; ++i) { | |
248 | remote_key k(process_id(pg), i); | |
1e59de90 | 249 | BOOST_TEST(get(values, k) == my_finish_value); |
7c673cae FG |
250 | } |
251 | ||
252 | // check our neighbor's values | |
253 | if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed values on neighbor..."; | |
254 | for (int i = 0; i < n; ++i) { | |
255 | remote_key k(next_processor, i); | |
1e59de90 | 256 | BOOST_TEST(get(values, k) == next_finish_value); |
7c673cae FG |
257 | } |
258 | ||
259 | synchronize(pg); | |
260 | ||
261 | if (process_id(pg) == 0) std::cerr << "OK.\n"; | |
262 | } | |
263 | ||
264 | void string_test() | |
265 | { | |
266 | mpi_process_group pg; | |
267 | const int n = 500; | |
268 | ||
269 | std::string my_start_string = lexical_cast<std::string>(process_id(pg)); | |
270 | int next_processor = (process_id(pg) + 1) % num_processes(pg); | |
271 | std::string next_start_string = lexical_cast<std::string>(next_processor); | |
272 | ||
273 | // Initial color map: even-numbered processes are false, | |
274 | // odd-numbered processes are true | |
275 | std::vector<std::string> string_vec(n, my_start_string); | |
276 | ||
277 | typedef iterator_property_map<std::vector<std::string>::iterator, | |
278 | identity_property_map> LocalPropertyMap; | |
279 | LocalPropertyMap local_strings(string_vec.begin(), identity_property_map()); | |
280 | ||
281 | synchronize(pg); | |
282 | ||
283 | // Create the distributed property map | |
284 | typedef boost::parallel::distributed_property_map<mpi_process_group, | |
285 | remote_key_to_global, | |
286 | LocalPropertyMap> StringMap; | |
287 | StringMap strings(pg, remote_key_to_global(), local_strings); | |
288 | strings.set_reduce(my_reduce<std::string>()); | |
289 | ||
290 | if (process_id(pg) == 0) std::cerr << "Checking local strings..."; | |
291 | // check local processor strings | |
292 | for (int i = 0; i < n; ++i) { | |
293 | remote_key k(process_id(pg), i); | |
1e59de90 | 294 | BOOST_TEST(get(strings, k) == my_start_string); |
7c673cae FG |
295 | } |
296 | ||
297 | strings.set_consistency_model(boost::parallel::cm_bidirectional); | |
298 | if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's default strings..."; | |
299 | // check next processor's strings | |
300 | for (int i = 0; i < n; ++i) { | |
301 | remote_key k(next_processor, i); | |
1e59de90 | 302 | BOOST_TEST(get(strings, k) == (num_processes(pg) == 1 ? my_start_string : std::string())); |
7c673cae FG |
303 | } |
304 | ||
305 | if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing..."; | |
306 | synchronize(pg); | |
307 | ||
308 | if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's strings..."; | |
309 | // check next processor's strings | |
310 | for (int i = 0; i < n; ++i) { | |
311 | remote_key k(next_processor, i); | |
1e59de90 | 312 | BOOST_TEST(get(strings, k) == next_start_string); |
7c673cae FG |
313 | } |
314 | ||
315 | if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing..."; | |
316 | synchronize(pg); | |
317 | ||
318 | if (process_id(pg) == 0) std::cerr << "OK.\nChanging next processor's strings..."; | |
319 | // change the next processor's strings | |
320 | std::string next_finish_string = next_start_string + next_start_string; | |
321 | for (int i = 0; i < n; ++i) { | |
322 | remote_key k(next_processor, i); | |
323 | put(strings, k, next_finish_string); | |
324 | } | |
325 | ||
326 | if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing..."; | |
327 | synchronize(pg); | |
328 | ||
329 | if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed strings..."; | |
330 | // check our own strings | |
331 | std::string my_finish_string = my_start_string + my_start_string; | |
332 | for (int i = 0; i < n; ++i) { | |
333 | remote_key k(process_id(pg), i); | |
1e59de90 | 334 | BOOST_TEST(get(strings, k) == my_finish_string); |
7c673cae FG |
335 | } |
336 | ||
337 | // check our neighbor's strings | |
338 | if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed strings on neighbor..."; | |
339 | for (int i = 0; i < n; ++i) { | |
340 | remote_key k(next_processor, i); | |
1e59de90 | 341 | BOOST_TEST(get(strings, k) == next_finish_string); |
7c673cae FG |
342 | } |
343 | ||
344 | synchronize(pg); | |
345 | ||
346 | if (process_id(pg) == 0) std::cerr << "OK.\n"; | |
347 | } | |
348 | ||
1e59de90 | 349 | int main(int argc, char** argv) |
7c673cae FG |
350 | { |
351 | boost::mpi::environment env(argc, argv); | |
352 | colored_test(); | |
353 | bool_test(); | |
354 | string_test(); | |
1e59de90 | 355 | return boost::report_errors(); |
7c673cae | 356 | } |