• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
7 // A test of the scatter() and scatterv() collectives.
8 #include <iterator>
9 #include <boost/mpi/collectives/scatter.hpp>
10 #include <boost/mpi/collectives/scatterv.hpp>
11 #include <boost/mpi/communicator.hpp>
12 #include <boost/mpi/environment.hpp>
13 #include "gps_position.hpp"
14 #include <boost/serialization/string.hpp>
15 #include <boost/serialization/list.hpp>
16 #include <boost/iterator/counting_iterator.hpp>
17 #include <boost/lexical_cast.hpp>
18 
19 #define BOOST_TEST_MODULE mpi_scatter
20 #include <boost/test/included/unit_test.hpp>
21 
22 using namespace boost::mpi;
23 
24 template<typename Generator>
25 void
scatter_test(const communicator & comm,Generator generator,const char * kind,int root=-1)26 scatter_test(const communicator& comm, Generator generator,
27              const char* kind, int root = -1)
28 {
29   typedef typename Generator::result_type value_type;
30 
31   if (root == -1) {
32     for (root = 0; root < comm.size(); ++root)
33       scatter_test(comm, generator, kind, root);
34   } else {
35     using boost::mpi::scatter;
36 
37     value_type value;
38 
39     if (comm.rank() == root) {
40       std::vector<value_type> values;
41 
42       for (int p = 0; p < comm.size(); ++p)
43         values.push_back(generator(p));
44 
45       std::cout << "Scattering " << kind << " from root "
46                 << root << "..." << std::endl;
47 
48       scatter(comm, values, value, root);
49     } else {
50       scatter(comm, value, root);
51     }
52 
53     BOOST_CHECK(value == generator(comm.rank()));
54   }
55 
56   comm.barrier();
57 }
58 
59 
60 //
61 // Generators to test with scatter/scatterv
62 //
63 struct int_generator
64 {
65   typedef int result_type;
66 
operator ()int_generator67   int operator()(int p) const { return 17 + p; }
68 };
69 
70 struct gps_generator
71 {
72   typedef gps_position result_type;
73 
operator ()gps_generator74   gps_position operator()(int p) const
75   {
76     return gps_position(39 + p, 16, 20.2799);
77   }
78 };
79 
80 struct string_generator
81 {
82   typedef std::string result_type;
83 
operator ()string_generator84   std::string operator()(int p) const
85   {
86     std::string result = boost::lexical_cast<std::string>(p);
87     result += " rosebud";
88     if (p != 1) result += 's';
89     return result;
90   }
91 };
92 
93 struct string_list_generator
94 {
95   typedef std::list<std::string> result_type;
96 
operator ()string_list_generator97   std::list<std::string> operator()(int p) const
98   {
99     std::list<std::string> result;
100     for (int i = 0; i <= p; ++i) {
101       std::string value = boost::lexical_cast<std::string>(i);
102       result.push_back(value);
103     }
104     return result;
105   }
106 };
107 
108 std::ostream&
operator <<(std::ostream & out,std::list<std::string> const & l)109 operator<<(std::ostream& out, std::list<std::string> const& l) {
110   out << '[';
111   std::copy(l.begin(), l.end(), std::ostream_iterator<std::string>(out, " "));
112   out << ']';
113   return out;
114 }
115 
116 template<typename Generator>
117 void
scatterv_test(const communicator & comm,Generator generator,const char * kind,int root=-1)118 scatterv_test(const communicator& comm, Generator generator,
119               const char* kind, int root = -1)
120 {
121   typedef typename Generator::result_type value_type;
122 
123   if (root == -1) {
124     for (root = 0; root < comm.size(); ++root)
125       scatterv_test(comm, generator, kind, root);
126   } else {
127     using boost::mpi::scatterv;
128 
129     int mysize = comm.rank() + 1;
130     std::vector<value_type> myvalues(mysize);
131 
132     if (comm.rank() == root) {
133       std::vector<value_type> values;
134       std::vector<int> sizes(comm.size());
135 
136       // process p will receive p+1 identical generator(p) elements
137       for (int p = 0; p < comm.size(); ++p) {
138         for (int i = 0; i < p+1; ++i)
139           values.push_back(generator(p));
140         sizes[p] = p + 1;
141       }
142 
143       std::cout << "Scatteringv " << kind << " from root "
144                 << root << "..." << std::endl;
145       assert(mysize == sizes[comm.rank()]);
146       scatterv(comm, values, sizes, &(myvalues[0]), root);
147     } else {
148       scatterv(comm, &(myvalues[0]), mysize, root);
149     }
150 
151     for (int i = 0; i < mysize; ++i)
152       BOOST_CHECK(myvalues[i] == generator(comm.rank()));
153   }
154 
155   comm.barrier();
156 }
157 
158 template<typename Generator>
159 void
scatterd_test(const communicator & comm,Generator generator,const char * kind,int root=-1)160 scatterd_test(const communicator& comm, Generator generator,
161               const char* kind, int root = -1)
162 {
163   typedef typename Generator::result_type value_type;
164 
165   if (root == -1) {
166     for (root = 0; root < comm.size(); ++root)
167       scatterv_test(comm, generator, kind, root);
168   } else {
169     using boost::mpi::scatterv;
170 
171     int mysize = comm.rank() + 1;
172     std::vector<value_type> myvalues(mysize);
173 
174     if (comm.rank() == root) {
175       std::vector<value_type> values;
176       std::vector<int> sizes(comm.size());
177       std::vector<int> displs(comm.size());
178       value_type noise = generator(comm.size()+1);
179       // process p will receive a payload of p+1 identical generator(p) elements
180       // root will insert pseudo random pading between each payload.
181       int shift = 0; // the current position of next payload in source array
182       for (int p = 0; p < comm.size(); ++p) {
183         int size = p+1;
184         int pad  = p % 3;
185         // padding
186         for (int i = 0; i < pad; ++i) {
187           values.push_back(noise);
188         }
189         // payload
190         for (int i = 0; i < size; ++i)
191           values.push_back(generator(p));
192         shift += pad;
193         displs[p] = shift;
194         sizes[p]  = size;
195         shift += size;
196       }
197 
198       std::cout << "Scatteringv " << kind << " from root "
199                 << root << "..." << std::endl;
200       assert(mysize == sizes[comm.rank()]);
201       scatterv(comm, values, sizes, displs, &(myvalues[0]), mysize, root);
202     } else {
203       scatterv(comm, &(myvalues[0]), mysize, root);
204     }
205 
206     for (int i = 0; i < mysize; ++i)
207       BOOST_CHECK(myvalues[i] == generator(comm.rank()));
208   }
209 
210   comm.barrier();
211 }
212 
213 
BOOST_AUTO_TEST_CASE(simple_scatter)214 BOOST_AUTO_TEST_CASE(simple_scatter)
215 {
216   environment env;
217   communicator comm;
218 
219   scatter_test(comm, int_generator(), "integers");
220   scatter_test(comm, gps_generator(), "GPS positions");
221   scatter_test(comm, string_generator(), "string");
222   scatter_test(comm, string_list_generator(), "list of strings");
223 
224   scatterv_test(comm, int_generator(), "integers");
225   scatterv_test(comm, gps_generator(), "GPS positions");
226   scatterv_test(comm, string_generator(), "string");
227   scatterv_test(comm, string_list_generator(), "list of strings");
228 
229   scatterd_test(comm, int_generator(), "integers");
230   scatterd_test(comm, gps_generator(), "GPS positions");
231   scatterd_test(comm, string_generator(), "string");
232   scatterd_test(comm, string_list_generator(), "list of strings");
233 }
234