1 // Copyright (C) 2004-2006 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/queue.hpp>
13 #include <boost/test/minimal.hpp>
14 #include <boost/graph/distributed/mpi_process_group.hpp>
15 #include <boost/pending/queue.hpp>
16 #include <boost/property_map/property_map.hpp>
17 #include <utility>
18 #include <iostream>
19 
20 #ifdef BOOST_NO_EXCEPTIONS
21 void
throw_exception(std::exception const & ex)22 boost::throw_exception(std::exception const& ex)
23 {
24     std::cout << ex.what() << std::endl;
25     abort();
26 }
27 #endif
28 
29 using boost::graph::distributed::mpi_process_group;
30 
31 struct global_value
32 {
global_valueglobal_value33   global_value(int p = -1, std::size_t l = 0) : processor(p), value(l) {}
34 
35   int processor;
36   std::size_t value;
37 
38   template<typename Archiver>
serializeglobal_value39   void serialize(Archiver& ar, const unsigned int /*version*/)
40   {
41     ar & processor & value;
42   }
43 };
44 
45 namespace boost { namespace mpi {
46     template<> struct is_mpi_datatype<global_value> : mpl::true_ { };
47 } } // end namespace boost::mpi
48 
49 BOOST_IS_BITWISE_SERIALIZABLE(global_value)
50 BOOST_CLASS_IMPLEMENTATION(global_value,object_serializable)
51 BOOST_CLASS_TRACKING(global_value,track_never)
52 
53 inline bool operator==(const global_value& x, const global_value& y)
54 { return x.processor == y.processor && x.value == y.value; }
55 
56 struct global_value_owner_map
57 {
58   typedef int value_type;
59   typedef value_type reference;
60   typedef global_value key_type;
61   typedef boost::readable_property_map_tag category;
62 };
63 
get(global_value_owner_map,global_value k)64 int get(global_value_owner_map, global_value k)
65 {
66   return k.processor;
67 }
68 
test_distributed_queue()69 void test_distributed_queue()
70 {
71   mpi_process_group process_group;
72 
73   typedef boost::queue<global_value> local_queue_type;
74 
75   typedef boost::graph::distributed::distributed_queue<mpi_process_group,
76                                              global_value_owner_map,
77                                              local_queue_type> dist_queue_type;
78 
79   dist_queue_type Q(process_group, global_value_owner_map());
80 
81   mpi_process_group::process_id_type id = process_id(process_group),
82     n = num_processes(process_group);
83   global_value v(0, 0);
84 
85   if (id == 0) {
86     std::cerr << "Should print level of each processor in a binary tree:\n";
87   }
88   synchronize(process_group);
89 
90   if (id == n-1) Q.push(v);
91   while (!Q.empty()) {
92     v = Q.top(); Q.pop();
93 
94     std::cerr << "#" << id << ": level = " << v.value << std::endl;
95 
96     int level_begin = 1;
97     for (std::size_t i = 0; i < v.value; ++i) level_begin *= 2;
98     int level_end = level_begin * 2;
99     BOOST_CHECK(level_begin <= (id + 1));
100     BOOST_CHECK((id + 1) <= level_end);
101 
102     ++v.value;
103     v.processor = v.processor * 2 + 1;
104     if (v.processor < n) Q.push(v);
105     ++v.processor;
106     if (v.processor < n) Q.push(v);
107   }
108 }
109 
test_main(int argc,char ** argv)110 int test_main(int argc, char** argv)
111 {
112   boost::mpi::environment env(argc, argv);
113   test_distributed_queue();
114   return 0;
115 }
116