Update of /cvsroot/boost/boost/libs/parallel/test
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv657/libs/parallel/test
Added Files:
all_gather_test.cpp all_reduce_test.cpp all_to_all_test.cpp
broadcast_test.cpp gather_test.cpp is_mpi_op_test.cpp
nonblocking_test.cpp reduce_test.cpp ring_test.cpp
scan_test.cpp scatter_test.cpp skeleton_content_test.cpp
Log Message:
Import Boost.MPI with the beginnings of a BBv2-based build system
--- NEW FILE: all_gather_test.cpp ---
// Copyright (C) 2005-2006 Douglas Gregor <[EMAIL PROTECTED]>
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// A test of the all_gather() collective.
#include <boost/parallel/mpi/collectives/all_gather.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/test/minimal.hpp>
#include <algorithm>
#include "gps_position.hpp"
#include <boost/serialization/string.hpp>
#include <boost/serialization/list.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/lexical_cast.hpp>
using boost::parallel::mpi::communicator;
using boost::parallel::mpi::packed_skeleton_iarchive;
using boost::parallel::mpi::packed_skeleton_oarchive;
template<typename Generator>
void
all_gather_test(const communicator& comm, Generator generator,
const char* kind)
{
typedef typename Generator::result_type value_type;
value_type value = generator(comm.rank());
using boost::parallel::mpi::all_gather;
std::vector<value_type> values;
if (comm.rank() == 0) {
std::cout << "Gathering " << kind << "...";
std::cout.flush();
}
all_gather(comm, value, values);
std::vector<value_type> expected_values;
for (int p = 0; p < comm.size(); ++p)
expected_values.push_back(generator(p));
BOOST_CHECK(values == expected_values);
if (comm.rank() == 0 && values == expected_values)
std::cout << "OK." << std::endl;
(comm.barrier)();
}
// Generates integers to test with gather()
struct int_generator
{
typedef int result_type;
int operator()(int p) const { return 17 + p; }
};
// Generates GPS positions to test with gather()
struct gps_generator
{
typedef gps_position result_type;
gps_position operator()(int p) const
{
return gps_position(39 + p, 16, 20.2799);
}
};
struct string_generator
{
typedef std::string result_type;
std::string operator()(int p) const
{
std::string result = boost::lexical_cast<std::string>(p);
result += " rosebud";
if (p != 1) result += 's';
return result;
}
};
struct string_list_generator
{
typedef std::list<std::string> result_type;
std::list<std::string> operator()(int p) const
{
std::list<std::string> result;
for (int i = 0; i <= p; ++i) {
std::string value = boost::lexical_cast<std::string>(i);
result.push_back(value);
}
return result;
}
};
int test_main(int argc, char* argv[])
{
boost::parallel::mpi::environment env(argc, argv);
communicator comm;
all_gather_test(comm, int_generator(), "integers");
all_gather_test(comm, gps_generator(), "GPS positions");
all_gather_test(comm, string_generator(), "string");
all_gather_test(comm, string_list_generator(), "list of strings");
return 0;
}
--- NEW FILE: all_reduce_test.cpp ---
// Copyright (C) 2005, 2006 Douglas Gregor.
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// A test of the all_reduce() collective.
#include <boost/parallel/mpi/collectives/all_reduce.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include <algorithm>
#include <boost/serialization/string.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/lexical_cast.hpp>
#include <numeric>
using boost::parallel::mpi::communicator;
// A simple point class that we can build, add, compare, and
// serialize.
struct point
{
point() : x(0), y(0), z(0) { }
point(int x, int y, int z) : x(x), y(y), z(z) { }
int x;
int y;
int z;
private:
template<typename Archiver>
void serialize(Archiver& ar, unsigned int /*version*/)
{
ar & x & y & z;
}
friend class boost::serialization::access;
};
std::ostream& operator<<(std::ostream& out, const point& p)
{
return out << p.x << ' ' << p.y << ' ' << p.z;
}
bool operator==(const point& p1, const point& p2)
{
return p1.x == p2.x && p1.y == p2.y && p1.z == p2.z;
}
bool operator!=(const point& p1, const point& p2)
{
return !(p1 == p2);
}
point operator+(const point& p1, const point& p2)
{
return point(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z);
}
namespace boost { namespace parallel { namespace mpi {
template <>
struct is_mpi_datatype<point> : public mpl::true_ { };
} } } // end namespace boost::parallel::mpi
template<typename Generator, typename Op>
void
all_reduce_test(const communicator& comm, Generator generator,
const char* type_kind, Op op, const char* op_kind,
typename Generator::result_type init)
{
typedef typename Generator::result_type value_type;
value_type value = generator(comm.rank());
using boost::parallel::mpi::all_reduce;
if (comm.rank() == 0) {
std::cout << "Reducing to " << op_kind << " of " << type_kind << "...";
std::cout.flush();
}
value_type result_value = all_reduce(comm, value, op);
// Compute expected result
std::vector<value_type> generated_values;
for (int p = 0; p < comm.size(); ++p)
generated_values.push_back(generator(p));
value_type expected_result = std::accumulate(generated_values.begin(),
generated_values.end(),
init, op);
BOOST_CHECK(result_value == expected_result);
if (result_value == expected_result && comm.rank() == 0)
std::cout << "OK." << std::endl;
(comm.barrier)();
}
// Generates integers to test with all_reduce()
struct int_generator
{
typedef int result_type;
int_generator(int base = 1) : base(base) { }
int operator()(int p) const { return base + p; }
private:
int base;
};
// Generate points to test with all_reduce()
struct point_generator
{
typedef point result_type;
point_generator(point origin) : origin(origin) { }
point operator()(int p) const
{
return point(origin.x + 1, origin.y + 1, origin.z + 1);
}
private:
point origin;
};
struct string_generator
{
typedef std::string result_type;
std::string operator()(int p) const
{
std::string result = boost::lexical_cast<std::string>(p);
result += " rosebud";
if (p != 1) result += 's';
return result;
}
};
struct secret_int_bit_and
{
int operator()(int x, int y) const { return x & y; }
};
struct wrapped_int
{
wrapped_int() : value(0) { }
explicit wrapped_int(int value) : value(value) { }
template<typename Archive>
void serialize(Archive& ar, unsigned int /* version */)
{
ar & value;
}
int value;
};
wrapped_int operator+(const wrapped_int& x, const wrapped_int& y)
{
return wrapped_int(x.value + y.value);
}
bool operator==(const wrapped_int& x, const wrapped_int& y)
{
return x.value == y.value;
}
// Generates wrapped_its to test with all_reduce()
struct wrapped_int_generator
{
typedef wrapped_int result_type;
wrapped_int_generator(int base = 1) : base(base) { }
wrapped_int operator()(int p) const { return wrapped_int(base + p); }
private:
int base;
};
namespace boost { namespace parallel { namespace mpi {
// Make std::plus<wrapped_int> commutative.
template<>
struct is_commutative<std::plus<wrapped_int>, wrapped_int>
: mpl::true_ { };
} } } // end namespace boost::parallel::mpi
int test_main(int argc, char* argv[])
{
using namespace boost::parallel::mpi;
environment env(argc, argv);
communicator comm;
// Built-in MPI datatypes with built-in MPI operations
all_reduce_test(comm, int_generator(), "integers", std::plus<int>(), "sum",
0);
all_reduce_test(comm, int_generator(), "integers", std::multiplies<int>(),
"product", 1);
all_reduce_test(comm, int_generator(), "integers", maximum<int>(),
"maximum", 0);
all_reduce_test(comm, int_generator(), "integers", minimum<int>(),
"minimum", 2);
// User-defined MPI datatypes with operations that have the
// same name as built-in operations.
all_reduce_test(comm, point_generator(point(0,0,0)), "points",
std::plus<point>(), "sum", point());
// Built-in MPI datatypes with user-defined operations
all_reduce_test(comm, int_generator(17), "integers", secret_int_bit_and(),
"bitwise and", -1);
// Arbitrary types with user-defined, commutative operations.
all_reduce_test(comm, wrapped_int_generator(17), "wrapped integers",
std::plus<wrapped_int>(), "sum", wrapped_int(0));
// Arbitrary types with (non-commutative) user-defined operations
all_reduce_test(comm, string_generator(), "strings",
std::plus<std::string>(), "concatenation", std::string());
return 0;
}
--- NEW FILE: all_to_all_test.cpp ---
// Copyright (C) 2005, 2006 Douglas Gregor.
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// A test of the all_to_all() collective.
#include <boost/parallel/mpi/collectives/all_to_all.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include <algorithm>
#include "gps_position.hpp"
#include <boost/serialization/string.hpp>
#include <boost/serialization/list.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/lexical_cast.hpp>
using boost::parallel::mpi::communicator;
using boost::parallel::mpi::packed_skeleton_iarchive;
using boost::parallel::mpi::packed_skeleton_oarchive;
template<typename Generator>
void
all_to_all_test(const communicator& comm, Generator generator,
const char* kind)
{
typedef typename Generator::result_type value_type;
using boost::parallel::mpi::all_to_all;
std::vector<value_type> in_values;
for (int p = 0; p < comm.size(); ++p)
in_values.push_back(generator((p + 1) * (comm.rank() + 1)));
std::vector<value_type> out_values;
all_to_all(comm, in_values, out_values);
for (int p = 0; p < comm.size(); ++p) {
BOOST_CHECK(out_values[p] == generator((p + 1) * (comm.rank() + 1)));
}
(comm.barrier)();
}
// Generates integers to test with all_to_all()
struct int_generator
{
typedef int result_type;
int operator()(int p) const { return 17 + p; }
};
// Generates GPS positions to test with all_to_all()
struct gps_generator
{
typedef gps_position result_type;
gps_position operator()(int p) const
{
return gps_position(39 + p, 16, 20.2799);
}
};
struct string_generator
{
typedef std::string result_type;
std::string operator()(int p) const
{
std::string result = boost::lexical_cast<std::string>(p);
result += " rosebud";
if (p != 1) result += 's';
return result;
}
};
struct string_list_generator
{
typedef std::list<std::string> result_type;
std::list<std::string> operator()(int p) const
{
std::list<std::string> result;
for (int i = 0; i <= p; ++i) {
std::string value = boost::lexical_cast<std::string>(i);
result.push_back(value);
}
return result;
}
};
int test_main(int argc, char* argv[])
{
boost::parallel::mpi::environment env(argc, argv);
communicator comm;
all_to_all_test(comm, int_generator(), "integers");
all_to_all_test(comm, gps_generator(), "GPS positions");
all_to_all_test(comm, string_generator(), "string");
all_to_all_test(comm, string_list_generator(), "list of strings");
return 0;
}
--- NEW FILE: broadcast_test.cpp ---
// Copyright (C) 2005, 2006 Douglas Gregor.
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// A test of the broadcast() collective.
#include <boost/parallel/mpi/collectives/broadcast.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include <algorithm>
#include "gps_position.hpp"
#include <boost/serialization/string.hpp>
#include <boost/serialization/list.hpp>
#include <boost/parallel/mpi/skeleton_and_content.hpp>
#include <boost/iterator/counting_iterator.hpp>
using boost::parallel::mpi::communicator;
using boost::parallel::mpi::packed_skeleton_iarchive;
using boost::parallel::mpi::packed_skeleton_oarchive;
template<typename T>
void
broadcast_test(const communicator& comm, const T& bc_value,
const char* kind, int root = -1)
{
if (root == -1) {
for (root = 0; root < comm.size(); ++root)
broadcast_test(comm, bc_value, kind, root);
} else {
using boost::parallel::mpi::broadcast;
T value;
if (comm.rank() == root) {
value = bc_value;
std::cout << "Broadcasting " << kind << " from root " << root << "...";
std::cout.flush();
}
broadcast(comm, value, root);
BOOST_CHECK(value == bc_value);
if (comm.rank() == root && value == bc_value)
std::cout << "OK." << std::endl;
}
(comm.barrier)();
}
void
test_skeleton_and_content(const communicator& comm, int root = 0)
{
using boost::parallel::mpi::content;
using boost::parallel::mpi::get_content;
using boost::make_counting_iterator;
using boost::parallel::mpi::broadcast;
using boost::parallel::mpi::content;
using boost::parallel::mpi::get_content;
typedef std::list<int>::iterator iterator;
int list_size = comm.size() + 7;
if (comm.rank() == root) {
// Fill in the seed data
std::list<int> original_list;
for (int i = 0; i < list_size; ++i)
original_list.push_back(i);
// Build up the skeleton
packed_skeleton_oarchive oa(comm);
oa << original_list;
// Broadcast the skeleton
std::cout << "Broadcasting integer list skeleton from root " << root
<< "...";
broadcast(comm, oa, root);
std::cout << "OK." << std::endl;
// Broadcast the content
std::cout << "Broadcasting integer list content from root " << root
<< "...";
{
content c = get_content(original_list);
broadcast(comm, c, root);
}
std::cout << "OK." << std::endl;
// Reverse the list, broadcast the content again
std::reverse(original_list.begin(), original_list.end());
std::cout << "Broadcasting reversed integer list content from root "
<< root << "...";
{
content c = get_content(original_list);
broadcast(comm, c, root);
}
std::cout << "OK." << std::endl;
} else {
// Allocate some useless data, to try to get the addresses of the
// list<int>'s used later to be different across processes.
std::list<int> junk_list(comm.rank() * 3 + 1, 17);
// Receive the skeleton
packed_skeleton_iarchive ia(comm);
broadcast(comm, ia, root);
// Build up a list to match the skeleton, and make sure it has the
// right structure (we have no idea what the data will be).
std::list<int> transferred_list;
ia >> transferred_list;
BOOST_CHECK((int)transferred_list.size() == list_size);
// Receive the content and check it
broadcast(comm, get_content(transferred_list), root);
BOOST_CHECK(std::equal(make_counting_iterator(0),
make_counting_iterator(list_size),
transferred_list.begin()));
// Receive the reversed content and check it
broadcast(comm, get_content(transferred_list), root);
BOOST_CHECK(std::equal(make_counting_iterator(0),
make_counting_iterator(list_size),
transferred_list.rbegin()));
}
(comm.barrier)();
}
int test_main(int argc, char* argv[])
{
boost::parallel::mpi::environment env(argc, argv);
communicator comm;
if (comm.size() == 1) {
std::cerr << "ERROR: Must run the broadcast test with more than one "
<< "process." << std::endl;
MPI_Abort(comm, -1);
}
// Check transfer of individual objects
broadcast_test(comm, 17, "integers");
broadcast_test(comm, gps_position(39,16,20.2799), "GPS positions");
broadcast_test(comm, gps_position(26,25,30.0), "GPS positions");
broadcast_test(comm, std::string("Rosie"), "string");
std::list<std::string> strings;
strings.push_back("Hello");
strings.push_back("MPI");
strings.push_back("World");
broadcast_test(comm, strings, "list of strings");
test_skeleton_and_content(comm, 0);
test_skeleton_and_content(comm, 1);
return 0;
}
--- NEW FILE: gather_test.cpp ---
// Copyright (C) 2005, 2006 Douglas Gregor.
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// A test of the gather() collective.
#include <boost/parallel/mpi/collectives/gather.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include <algorithm>
#include "gps_position.hpp"
#include <boost/serialization/string.hpp>
#include <boost/serialization/list.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/lexical_cast.hpp>
using boost::parallel::mpi::communicator;
using boost::parallel::mpi::packed_skeleton_iarchive;
using boost::parallel::mpi::packed_skeleton_oarchive;
template<typename Generator>
void
gather_test(const communicator& comm, Generator generator,
const char* kind, int root = -1)
{
typedef typename Generator::result_type value_type;
value_type value = generator(comm.rank());
if (root == -1) {
for (root = 0; root < comm.size(); ++root)
gather_test(comm, generator, kind, root);
} else {
using boost::parallel::mpi::gather;
std::vector<value_type> values;
if (comm.rank() == root) {
std::cout << "Gathering " << kind << " from root " << root << "...";
std::cout.flush();
}
gather(comm, value, values, root);
if (comm.rank() == root) {
std::vector<value_type> expected_values;
for (int p = 0; p < comm.size(); ++p)
expected_values.push_back(generator(p));
BOOST_CHECK(values == expected_values);
if (values == expected_values)
std::cout << "OK." << std::endl;
} else {
BOOST_CHECK(values.empty());
}
}
(comm.barrier)();
}
// Generates integers to test with gather()
struct int_generator
{
typedef int result_type;
int operator()(int p) const { return 17 + p; }
};
// Generates GPS positions to test with gather()
struct gps_generator
{
typedef gps_position result_type;
gps_position operator()(int p) const
{
return gps_position(39 + p, 16, 20.2799);
}
};
struct string_generator
{
typedef std::string result_type;
std::string operator()(int p) const
{
std::string result = boost::lexical_cast<std::string>(p);
result += " rosebud";
if (p != 1) result += 's';
return result;
}
};
struct string_list_generator
{
typedef std::list<std::string> result_type;
std::list<std::string> operator()(int p) const
{
std::list<std::string> result;
for (int i = 0; i <= p; ++i) {
std::string value = boost::lexical_cast<std::string>(i);
result.push_back(value);
}
return result;
}
};
int test_main(int argc, char* argv[])
{
boost::parallel::mpi::environment env(argc, argv);
communicator comm;
gather_test(comm, int_generator(), "integers");
gather_test(comm, gps_generator(), "GPS positions");
gather_test(comm, string_generator(), "string");
gather_test(comm, string_list_generator(), "list of strings");
return 0;
}
--- NEW FILE: is_mpi_op_test.cpp ---
// Copyright (C) 2005-2006 Douglas Gregor <[EMAIL PROTECTED]>
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// A test of the is_mpi_op functionality.
#include <boost/parallel/mpi/operations.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/type_traits/is_base_and_derived.hpp>
#include <boost/test/minimal.hpp>
using namespace boost::parallel::mpi;
using namespace std;
using boost::is_base_and_derived;
int test_main(int argc, char* argv[])
{
boost::parallel::mpi::environment env(argc, argv);
// Check each predefined MPI_Op type that we support directly.
BOOST_CHECK((is_mpi_op<maximum<int>, int>::op() == MPI_MAX));
BOOST_CHECK((is_mpi_op<minimum<float>, float>::op() == MPI_MIN));
BOOST_CHECK((is_mpi_op<plus<double>, double>::op() == MPI_SUM));
BOOST_CHECK((is_mpi_op<multiplies<long>, long>::op() == MPI_PROD));
BOOST_CHECK((is_mpi_op<logical_and<int>, int>::op() == MPI_LAND));
BOOST_CHECK((is_mpi_op<bitwise_and<int>, int>::op() == MPI_BAND));
BOOST_CHECK((is_mpi_op<logical_or<int>, int>::op() == MPI_LOR));
BOOST_CHECK((is_mpi_op<bitwise_or<int>, int>::op() == MPI_BOR));
BOOST_CHECK((is_mpi_op<logical_xor<int>, int>::op() == MPI_LXOR));
BOOST_CHECK((is_mpi_op<bitwise_xor<int>, int>::op() == MPI_BXOR));
return 0;
}
--- NEW FILE: nonblocking_test.cpp ---
// Copyright (C) 2006 Douglas Gregor.
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// A test of the nonblocking point-to-point operations.
#include <boost/parallel/mpi/nonblocking.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include "gps_position.hpp"
#include <boost/lexical_cast.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/list.hpp>
#include <iterator>
#include <algorithm>
using boost::parallel::mpi::communicator;
using boost::parallel::mpi::request;
using boost::parallel::mpi::status;
enum method_kind {
mk_wait_any, mk_test_any, mk_wait_all, mk_wait_all_keep,
mk_test_all, mk_test_all_keep, mk_wait_some, mk_wait_some_keep,
mk_test_some, mk_test_some_keep,
mk_all, // use to run all of the different methods
mk_all_except_test_all // use for serialized types
};
static char* method_kind_names[mk_all] = {
"wait_any",
"test_any",
"wait_all",
"wait_all (keep results)",
"test_all",
"test_all (keep results)",
"wait_some",
"wait_some (keep results)",
"test_some",
"test_some (keep results)"
};
template<typename T>
void
nonblocking_test(const communicator& comm, const T* values, int num_values,
const char* kind, method_kind method = mk_all)
{
using boost::parallel::mpi::wait_any;
using boost::parallel::mpi::test_any;
using boost::parallel::mpi::wait_all;
using boost::parallel::mpi::test_all;
using boost::parallel::mpi::wait_some;
using boost::parallel::mpi::test_some;
if (method == mk_all || method == mk_all_except_test_all) {
nonblocking_test(comm, values, num_values, kind, mk_wait_any);
nonblocking_test(comm, values, num_values, kind, mk_test_any);
nonblocking_test(comm, values, num_values, kind, mk_wait_all);
nonblocking_test(comm, values, num_values, kind, mk_wait_all_keep);
if (method == mk_all) {
nonblocking_test(comm, values, num_values, kind, mk_test_all);
nonblocking_test(comm, values, num_values, kind, mk_test_all_keep);
}
nonblocking_test(comm, values, num_values, kind, mk_wait_some);
nonblocking_test(comm, values, num_values, kind, mk_wait_some_keep);
nonblocking_test(comm, values, num_values, kind, mk_test_some);
nonblocking_test(comm, values, num_values, kind, mk_test_some_keep);
} else {
if (comm.rank() == 0) {
std::cout << "Testing " << method_kind_names[method]
<< " with " << kind << "...";
std::cout.flush();
}
typedef std::pair<status, std::vector<request>::iterator>
status_iterator_pair;
T incoming_value;
std::vector<T> incoming_values(num_values);
std::vector<request> reqs;
// Send/receive the first value
reqs.push_back(comm.isend((comm.rank() + 1) % comm.size(), 0, values[0]));
reqs.push_back(comm.irecv((comm.rank() + comm.size() - 1) % comm.size(),
0, incoming_value));
if (method != mk_wait_any && method != mk_test_any) {
#ifndef LAM_MPI
// We've run into problems here (with 0-length messages) with
// LAM/MPI on Mac OS X and x86-86 Linux. Will investigate
// further at a later time, but the problem only seems to occur
// when using shared memory, not TCP.
// Send/receive an empty message
reqs.push_back(comm.isend((comm.rank() + 1) % comm.size(), 1));
reqs.push_back(comm.irecv((comm.rank() + comm.size() - 1) % comm.size(),
1));
#endif
// Send/receive an array
reqs.push_back(comm.isend((comm.rank() + 1) % comm.size(), 2, values,
num_values));
reqs.push_back(comm.irecv((comm.rank() + comm.size() - 1) % comm.size(),
2, &incoming_values.front(), num_values));
}
switch (method) {
case mk_wait_any:
if (wait_any(reqs.begin(), reqs.end()).second == reqs.begin())
reqs[1].wait();
else
reqs[0].wait();
break;
case mk_test_any:
{
boost::optional<status_iterator_pair> result;
do {
result = test_any(reqs.begin(), reqs.end());
} while (!result);
if (result->second == reqs.begin())
reqs[1].wait();
else
reqs[0].wait();
break;
}
case mk_wait_all:
wait_all(reqs.begin(), reqs.end());
break;
case mk_wait_all_keep:
{
std::vector<status> stats;
wait_all(reqs.begin(), reqs.end(), std::back_inserter(stats));
}
break;
case mk_test_all:
while (!test_all(reqs.begin(), reqs.end())) { /* Busy wait */ }
break;
case mk_test_all_keep:
{
std::vector<status> stats;
while (!test_all(reqs.begin(), reqs.end(), std::back_inserter(stats)))
/* Busy wait */;
}
break;
case mk_wait_some:
{
std::vector<request>::iterator pos = reqs.end();
do {
pos = wait_some(reqs.begin(), pos);
} while (pos != reqs.begin());
}
break;
case mk_wait_some_keep:
{
std::vector<status> stats;
std::vector<request>::iterator pos = reqs.end();
do {
pos = wait_some(reqs.begin(), pos, std::back_inserter(stats)).second;
} while (pos != reqs.begin());
}
break;
case mk_test_some:
{
std::vector<request>::iterator pos = reqs.end();
do {
pos = test_some(reqs.begin(), pos);
} while (pos != reqs.begin());
}
break;
case mk_test_some_keep:
{
std::vector<status> stats;
std::vector<request>::iterator pos = reqs.end();
do {
pos = test_some(reqs.begin(), pos, std::back_inserter(stats)).second;
} while (pos != reqs.begin());
}
break;
default:
BOOST_CHECK(false);
}
if (comm.rank() == 0) {
bool okay = true;
if (!((incoming_value == values[0])))
okay = false;
if (method != mk_wait_any && method != mk_test_any
&& !std::equal(incoming_values.begin(), incoming_values.end(),
values))
okay = false;
if (okay)
std::cout << "OK." << std::endl;
else
std::cerr << "ERROR!" << std::endl;
}
BOOST_CHECK(incoming_value == values[0]);
if (method != mk_wait_any && method != mk_test_any)
BOOST_CHECK(std::equal(incoming_values.begin(), incoming_values.end(),
values));
}
}
int test_main(int argc, char* argv[])
{
boost::parallel::mpi::environment env(argc, argv);
communicator comm;
int int_array[3] = {17, 42, 256};
nonblocking_test(comm, int_array, 3, "integers");
gps_position gps_array[2] = {
gps_position(17, 42, .06),
gps_position(42, 17, .06)
};
nonblocking_test(comm, gps_array, 2, "gps positions");
std::string string_array[2] = { "Hello", "World" };
nonblocking_test(comm, string_array, 2, "strings",
mk_all_except_test_all);
std::list<std::string> lst_of_strings;
for (int i = 0; i < comm.size(); ++i)
lst_of_strings.push_back(boost::lexical_cast<std::string>(i));
nonblocking_test(comm, &lst_of_strings, 1, "list of strings",
mk_all_except_test_all);
return 0;
}
--- NEW FILE: reduce_test.cpp ---
// Copyright (C) 2005, 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// A test of the reduce() collective.
#include <boost/parallel/mpi/collectives/reduce.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include <algorithm>
#include <boost/serialization/string.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/lexical_cast.hpp>
#include <numeric>
using boost::parallel::mpi::communicator;
// A simple point class that we can build, add, compare, and
// serialize.
struct point
{
point() : x(0), y(0), z(0) { }
point(int x, int y, int z) : x(x), y(y), z(z) { }
int x;
int y;
int z;
private:
template<typename Archiver>
void serialize(Archiver& ar, unsigned int /*version*/)
{
ar & x & y & z;
}
friend class boost::serialization::access;
};
std::ostream& operator<<(std::ostream& out, const point& p)
{
return out << p.x << ' ' << p.y << ' ' << p.z;
}
bool operator==(const point& p1, const point& p2)
{
return p1.x == p2.x && p1.y == p2.y && p1.z == p2.z;
}
bool operator!=(const point& p1, const point& p2)
{
return !(p1 == p2);
}
point operator+(const point& p1, const point& p2)
{
return point(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z);
}
namespace boost { namespace parallel { namespace mpi {
template <>
struct is_mpi_datatype<point> : public mpl::true_ { };
} } } // end namespace boost::parallel::mpi
template<typename Generator, typename Op>
void
reduce_test(const communicator& comm, Generator generator,
const char* type_kind, Op op, const char* op_kind,
typename Generator::result_type init,
int root = -1)
{
typedef typename Generator::result_type value_type;
value_type value = generator(comm.rank());
if (root == -1) {
for (root = 0; root < comm.size(); ++root)
reduce_test(comm, generator, type_kind, op, op_kind, init, root);
} else {
using boost::parallel::mpi::reduce;
if (comm.rank() == root) {
std::cout << "Reducing to " << op_kind << " of " << type_kind
<< " at root " << root << "...";
std::cout.flush();
value_type result_value;
reduce(comm, value, result_value, op, root);
// Compute expected result
std::vector<value_type> generated_values;
for (int p = 0; p < comm.size(); ++p)
generated_values.push_back(generator(p));
value_type expected_result = std::accumulate(generated_values.begin(),
generated_values.end(),
init, op);
BOOST_CHECK(result_value == expected_result);
if (result_value == expected_result)
std::cout << "OK." << std::endl;
} else {
reduce(comm, value, op, root);
}
}
(comm.barrier)();
}
// Generates integers to test with reduce()
struct int_generator
{
typedef int result_type;
int_generator(int base = 1) : base(base) { }
int operator()(int p) const { return base + p; }
private:
int base;
};
// Generate points to test with reduce()
struct point_generator
{
typedef point result_type;
point_generator(point origin) : origin(origin) { }
point operator()(int p) const
{
return point(origin.x + 1, origin.y + 1, origin.z + 1);
}
private:
point origin;
};
struct string_generator
{
typedef std::string result_type;
std::string operator()(int p) const
{
std::string result = boost::lexical_cast<std::string>(p);
result += " rosebud";
if (p != 1) result += 's';
return result;
}
};
struct secret_int_bit_and
{
int operator()(int x, int y) const { return x & y; }
};
struct wrapped_int
{
wrapped_int() : value(0) { }
explicit wrapped_int(int value) : value(value) { }
template<typename Archive>
void serialize(Archive& ar, unsigned int /* version */)
{
ar & value;
}
int value;
};
wrapped_int operator+(const wrapped_int& x, const wrapped_int& y)
{
return wrapped_int(x.value + y.value);
}
bool operator==(const wrapped_int& x, const wrapped_int& y)
{
return x.value == y.value;
}
// Generates wrapped_its to test with reduce()
struct wrapped_int_generator
{
typedef wrapped_int result_type;
wrapped_int_generator(int base = 1) : base(base) { }
wrapped_int operator()(int p) const { return wrapped_int(base + p); }
private:
int base;
};
namespace boost { namespace parallel { namespace mpi {
// Make std::plus<wrapped_int> commutative.
template<>
struct is_commutative<std::plus<wrapped_int>, wrapped_int>
: mpl::true_ { };
} } } // end namespace boost::parallel::mpi
int test_main(int argc, char* argv[])
{
using namespace boost::parallel::mpi;
environment env(argc, argv);
communicator comm;
// Built-in MPI datatypes with built-in MPI operations
reduce_test(comm, int_generator(), "integers", std::plus<int>(), "sum", 0);
reduce_test(comm, int_generator(), "integers", std::multiplies<int>(),
"product", 1);
reduce_test(comm, int_generator(), "integers", maximum<int>(),
"maximum", 0);
reduce_test(comm, int_generator(), "integers", minimum<int>(),
"minimum", 2);
// User-defined MPI datatypes with operations that have the
// same name as built-in operations.
reduce_test(comm, point_generator(point(0,0,0)), "points",
std::plus<point>(), "sum", point());
// Built-in MPI datatypes with user-defined operations
reduce_test(comm, int_generator(17), "integers", secret_int_bit_and(),
"bitwise and", -1);
// Arbitrary types with user-defined, commutative operations.
reduce_test(comm, wrapped_int_generator(17), "wrapped integers",
std::plus<wrapped_int>(), "sum", wrapped_int(0));
// Arbitrary types with (non-commutative) user-defined operations
reduce_test(comm, string_generator(), "strings",
std::plus<std::string>(), "concatenation", std::string());
return 0;
}
--- NEW FILE: ring_test.cpp ---
// Copyright (C) 2005, 2006 Douglas Gregor.
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// A test of the communicator that passes data around a ring and
// verifies that the same data makes it all the way. Should test all
// of the various kinds of data that can be sent (primitive types, POD
// types, serializable objects, etc.)
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include <algorithm>
#include "gps_position.hpp"
#include <boost/serialization/string.hpp>
#include <boost/serialization/list.hpp>
using boost::parallel::mpi::communicator;
using boost::parallel::mpi::status;
template<typename T>
void
ring_test(const communicator& comm, const T& pass_value, const char* kind,
int root = 0)
{
T transferred_value;
int rank = comm.rank();
int size = comm.size();
if (rank == root) {
std::cout << "Passing " << kind << " around a ring from root " << root
<< "...";
comm.send((rank + 1) % size, 0, pass_value);
comm.recv((rank + size - 1) % size, 0, transferred_value);
BOOST_CHECK(transferred_value == pass_value);
if (transferred_value == pass_value) std::cout << " OK." << std::endl;
} else {
comm.recv((rank + size - 1) % size, 0, transferred_value);
BOOST_CHECK(transferred_value == pass_value);
comm.send((rank + 1) % size, 0, transferred_value);
}
(comm.barrier)();
}
template<typename T>
void
ring_array_test(const communicator& comm, const T* pass_values,
int n, const char* kind, int root = 0)
{
T* transferred_values = new T[n];
int rank = comm.rank();
int size = comm.size();
if (rank == root) {
std::cout << "Passing " << kind << " array around a ring from root "
<< root << "...";
comm.send((rank + 1) % size, 0, pass_values, n);
comm.recv((rank + size - 1) % size, 0, transferred_values, n);
bool okay = std::equal(pass_values, pass_values + n,
transferred_values);
BOOST_CHECK(okay);
if (okay) std::cout << " OK." << std::endl;
} else {
status stat = comm.probe(boost::parallel::mpi::any_source, 0);
boost::optional<int> num_values = stat.template count<T>();
if (boost::parallel::mpi::is_mpi_datatype<T>())
BOOST_CHECK(num_values && *num_values == n);
else
BOOST_CHECK(!num_values || *num_values == n);
comm.recv(stat.source(), 0, transferred_values, n);
BOOST_CHECK(std::equal(pass_values, pass_values + n,
transferred_values));
comm.send((rank + 1) % size, 0, transferred_values, n);
}
(comm.barrier)();
delete [] transferred_values;
}
int test_main(int argc, char* argv[])
{
boost::parallel::mpi::environment env(argc, argv);
communicator comm;
if (comm.size() == 1) {
std::cerr << "ERROR: Must run the ring test with more than one process."
<< std::endl;
MPI_Abort(comm, -1);
}
// Check transfer of individual objects
ring_test(comm, 17, "integers", 0);
ring_test(comm, 17, "integers", 1);
ring_test(comm, gps_position(39,16,20.2799), "GPS positions", 0);
ring_test(comm, gps_position(26,25,30.0), "GPS positions", 1);
ring_test(comm, std::string("Rosie"), "string", 0);
std::list<std::string> strings;
strings.push_back("Hello");
strings.push_back("MPI");
strings.push_back("World");
ring_test(comm, strings, "list of strings", 1);
// Check transfer of arrays
int int_array[2] = { 17, 42 };
ring_array_test(comm, int_array, 2, "integer", 1);
gps_position gps_position_array[2] = {
gps_position(39,16,20.2799),
gps_position(26,25,30.0)
};
ring_array_test(comm, gps_position_array, 2, "GPS position", 1);
std::string string_array[3] = { "Hello", "MPI", "World" };
ring_array_test(comm, string_array, 3, "string", 0);
ring_array_test(comm, string_array, 3, "string", 1);
return 0;
}
--- NEW FILE: scan_test.cpp ---
// Copyright (C) 2005, 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// A test of the scan() collective.
#include <boost/parallel/mpi/collectives/scan.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include <algorithm>
#include <boost/serialization/string.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/lexical_cast.hpp>
#include <numeric>
using boost::parallel::mpi::communicator;
// A simple point class that we can build, add, compare, and
// serialize.
struct point
{
point() : x(0), y(0), z(0) { }
point(int x, int y, int z) : x(x), y(y), z(z) { }
int x;
int y;
int z;
private:
template<typename Archiver>
void serialize(Archiver& ar, unsigned int /*version*/)
{
ar & x & y & z;
}
friend class boost::serialization::access;
};
std::ostream& operator<<(std::ostream& out, const point& p)
{
return out << p.x << ' ' << p.y << ' ' << p.z;
}
bool operator==(const point& p1, const point& p2)
{
return p1.x == p2.x && p1.y == p2.y && p1.z == p2.z;
}
bool operator!=(const point& p1, const point& p2)
{
return !(p1 == p2);
}
point operator+(const point& p1, const point& p2)
{
return point(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z);
}
namespace boost { namespace parallel { namespace mpi {
template <>
struct is_mpi_datatype<point> : public mpl::true_ { };
} } } // end namespace boost::parallel::mpi
template<typename Generator, typename Op>
void
scan_test(const communicator& comm, Generator generator,
const char* type_kind, Op op, const char* op_kind)
{
typedef typename Generator::result_type value_type;
value_type value = generator(comm.rank());
using boost::parallel::mpi::scan;
if (comm.rank() == 0) {
std::cout << "Prefix reducing to " << op_kind << " of " << type_kind
<< "...";
std::cout.flush();
}
value_type result_value;
scan(comm, value, result_value, op);
BOOST_CHECK(scan(comm, value, op) == result_value);
// Compute expected result
std::vector<value_type> generated_values;
for (int p = 0; p < comm.size(); ++p)
generated_values.push_back(generator(p));
std::vector<value_type> expected_results(comm.size());
std::partial_sum(generated_values.begin(), generated_values.end(),
expected_results.begin(), op);
BOOST_CHECK(result_value == expected_results[comm.rank()]);
if (comm.rank() == 0) std::cout << "Done." << std::endl;
(comm.barrier)();
}
// Generates integers to test with scan()
struct int_generator
{
typedef int result_type;
int_generator(int base = 1) : base(base) { }
int operator()(int p) const { return base + p; }
private:
int base;
};
// Generate points to test with scan()
struct point_generator
{
typedef point result_type;
point_generator(point origin) : origin(origin) { }
point operator()(int p) const
{
return point(origin.x + 1, origin.y + 1, origin.z + 1);
}
private:
point origin;
};
struct string_generator
{
typedef std::string result_type;
std::string operator()(int p) const
{
std::string result = boost::lexical_cast<std::string>(p);
result += " rosebud";
if (p != 1) result += 's';
return result;
}
};
struct secret_int_bit_and
{
int operator()(int x, int y) const { return x & y; }
};
struct wrapped_int
{
wrapped_int() : value(0) { }
explicit wrapped_int(int value) : value(value) { }
template<typename Archive>
void serialize(Archive& ar, unsigned int /* version */)
{
ar & value;
}
int value;
};
wrapped_int operator+(const wrapped_int& x, const wrapped_int& y)
{
return wrapped_int(x.value + y.value);
}
bool operator==(const wrapped_int& x, const wrapped_int& y)
{
return x.value == y.value;
}
// Generates wrapped_its to test with scan()
struct wrapped_int_generator
{
typedef wrapped_int result_type;
wrapped_int_generator(int base = 1) : base(base) { }
wrapped_int operator()(int p) const { return wrapped_int(base + p); }
private:
int base;
};
namespace boost { namespace parallel { namespace mpi {
// Make std::plus<wrapped_int> commutative.
template<>
struct is_commutative<std::plus<wrapped_int>, wrapped_int>
: mpl::true_ { };
} } } // end namespace boost::parallel::mpi
int test_main(int argc, char* argv[])
{
using namespace boost::parallel::mpi;
environment env(argc, argv);
communicator comm;
// Built-in MPI datatypes with built-in MPI operations
scan_test(comm, int_generator(), "integers", std::plus<int>(), "sum");
scan_test(comm, int_generator(), "integers", std::multiplies<int>(),
"product");
scan_test(comm, int_generator(), "integers", maximum<int>(),
"maximum");
scan_test(comm, int_generator(), "integers", minimum<int>(),
"minimum");
// User-defined MPI datatypes with operations that have the
// same name as built-in operations.
scan_test(comm, point_generator(point(0,0,0)), "points",
std::plus<point>(), "sum");
// Built-in MPI datatypes with user-defined operations
scan_test(comm, int_generator(17), "integers", secret_int_bit_and(),
"bitwise and");
// Arbitrary types with user-defined, commutative operations.
scan_test(comm, wrapped_int_generator(17), "wrapped integers",
std::plus<wrapped_int>(), "sum");
// Arbitrary types with (non-commutative) user-defined operations
scan_test(comm, string_generator(), "strings",
std::plus<std::string>(), "concatenation");
return 0;
}
--- NEW FILE: scatter_test.cpp ---
// Copyright (C) 2005, 2006 Douglas Gregor.
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// A test of the scatter() collective.
#include <boost/parallel/mpi/collectives/scatter.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include <algorithm>
#include "gps_position.hpp"
#include <boost/serialization/string.hpp>
#include <boost/serialization/list.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/lexical_cast.hpp>
using boost::parallel::mpi::communicator;
using boost::parallel::mpi::packed_skeleton_iarchive;
using boost::parallel::mpi::packed_skeleton_oarchive;
template<typename Generator>
void
scatter_test(const communicator& comm, Generator generator,
const char* kind, int root = -1)
{
typedef typename Generator::result_type value_type;
if (root == -1) {
for (root = 0; root < comm.size(); ++root)
scatter_test(comm, generator, kind, root);
} else {
using boost::parallel::mpi::scatter;
value_type value;
if (comm.rank() == root) {
std::vector<value_type> values;
for (int p = 0; p < comm.size(); ++p)
values.push_back(generator(p));
if (comm.rank() == root) {
std::cout << "Scattering " << kind << " from root " << root << "...";
std::cout.flush();
}
scatter(comm, values, value, root);
} else {
scatter(comm, value, root);
}
BOOST_CHECK(value == generator(comm.rank()));
}
(comm.barrier)();
}
// Generates integers to test with scatter()
struct int_generator
{
typedef int result_type;
int operator()(int p) const { return 17 + p; }
};
// Generates GPS positions to test with scatter()
struct gps_generator
{
typedef gps_position result_type;
gps_position operator()(int p) const
{
return gps_position(39 + p, 16, 20.2799);
}
};
struct string_generator
{
typedef std::string result_type;
std::string operator()(int p) const
{
std::string result = boost::lexical_cast<std::string>(p);
result += " rosebud";
if (p != 1) result += 's';
return result;
}
};
struct string_list_generator
{
typedef std::list<std::string> result_type;
std::list<std::string> operator()(int p) const
{
std::list<std::string> result;
for (int i = 0; i <= p; ++i) {
std::string value = boost::lexical_cast<std::string>(i);
result.push_back(value);
}
return result;
}
};
int test_main(int argc, char* argv[])
{
boost::parallel::mpi::environment env(argc, argv);
communicator comm;
scatter_test(comm, int_generator(), "integers");
scatter_test(comm, gps_generator(), "GPS positions");
scatter_test(comm, string_generator(), "string");
scatter_test(comm, string_list_generator(), "list of strings");
return 0;
}
--- NEW FILE: skeleton_content_test.cpp ---
// Copyright 2005 Douglas Gregor.
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// A test of the communicator that transmits skeletons and
// content for data types.
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include <boost/serialization/list.hpp>
#include <boost/parallel/mpi/skeleton_and_content.hpp>
#include <boost/parallel/mpi/nonblocking.hpp>
#include <algorithm>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/parallel/mpi/collectives/broadcast.hpp>
using boost::parallel::mpi::communicator;
using boost::parallel::mpi::packed_skeleton_iarchive;
using boost::parallel::mpi::packed_skeleton_oarchive;
void
test_skeleton_and_content(const communicator& comm, int root,
bool manual_broadcast)
{
using boost::parallel::mpi::skeleton;
using boost::parallel::mpi::content;
using boost::parallel::mpi::get_content;
using boost::make_counting_iterator;
using boost::parallel::mpi::broadcast;
typedef std::list<int>::iterator iterator;
int list_size = comm.size() + 7;
if (comm.rank() == root) {
// Fill in the seed data
std::list<int> original_list;
for (int i = 0; i < list_size; ++i)
original_list.push_back(i);
std::cout << "Broadcasting integer list skeleton from root " << root
<< "...";
if (manual_broadcast) {
// Broadcast the skeleton (manually)
for (int p = 0; p < comm.size(); ++p)
if (p != root) comm.send(p, 0, skeleton(original_list));
} else {
broadcast(comm, skeleton(original_list), root);
}
std::cout << "OK." << std::endl;
// Broadcast the content (manually)
std::cout << "Broadcasting integer list content from root " << root
<< "...";
{
content c = get_content(original_list);
for (int p = 0; p < comm.size(); ++p)
if (p != root) comm.send(p, 1, c);
}
std::cout << "OK." << std::endl;
// Reverse the list, broadcast the content again
std::reverse(original_list.begin(), original_list.end());
std::cout << "Broadcasting reversed integer list content from root "
<< root << "...";
{
content c = get_content(original_list);
for (int p = 0; p < comm.size(); ++p)
if (p != root) comm.send(p, 2, c);
}
std::cout << "OK." << std::endl;
} else {
// Allocate some useless data, to try to get the addresses of the
// list<int>'s used later to be different across processes.
std::list<int> junk_list(comm.rank() * 3 + 1, 17);
// Receive the skeleton to build up the transferred list
std::list<int> transferred_list;
if (manual_broadcast) {
comm.recv(root, 0, skeleton(transferred_list));
} else {
broadcast(comm, skeleton(transferred_list), root);
}
BOOST_CHECK((int)transferred_list.size() == list_size);
// Receive the content and check it
comm.recv(root, 1, get_content(transferred_list));
BOOST_CHECK(std::equal(make_counting_iterator(0),
make_counting_iterator(list_size),
transferred_list.begin()));
// Receive the reversed content and check it
comm.recv(root, 2, get_content(transferred_list));
BOOST_CHECK(std::equal(make_counting_iterator(0),
make_counting_iterator(list_size),
transferred_list.rbegin()));
}
(comm.barrier)();
}
void
test_skeleton_and_content_nonblocking(const communicator& comm, int root)
{
using boost::parallel::mpi::skeleton;
using boost::parallel::mpi::content;
using boost::parallel::mpi::get_content;
using boost::make_counting_iterator;
using boost::parallel::mpi::broadcast;
using boost::parallel::mpi::request;
using boost::parallel::mpi::wait_all;
typedef std::list<int>::iterator iterator;
int list_size = comm.size() + 7;
if (comm.rank() == root) {
// Fill in the seed data
std::list<int> original_list;
for (int i = 0; i < list_size; ++i)
original_list.push_back(i);
std::cout << "Non-blocking broadcast of integer list skeleton from root "
<< root
<< "...";
// Broadcast the skeleton (manually)
{
std::vector<request> reqs;
for (int p = 0; p < comm.size(); ++p)
if (p != root)
reqs.push_back(comm.isend(p, 0, skeleton(original_list)));
wait_all(reqs.begin(), reqs.end());
}
std::cout << "OK." << std::endl;
// Broadcast the content (manually)
std::cout << "Non-blocking broadcast of integer list content from root " <<
root
<< "...";
{
content c = get_content(original_list);
std::vector<request> reqs;
for (int p = 0; p < comm.size(); ++p)
if (p != root) reqs.push_back(comm.isend(p, 1, c));
wait_all(reqs.begin(), reqs.end());
}
std::cout << "OK." << std::endl;
// Reverse the list, broadcast the content again
std::reverse(original_list.begin(), original_list.end());
std::cout << "Non-blocking broadcast of reversed integer list content from
root "
<< root << "...";
{
std::vector<request> reqs;
content c = get_content(original_list);
for (int p = 0; p < comm.size(); ++p)
if (p != root) reqs.push_back(comm.isend(p, 2, c));
wait_all(reqs.begin(), reqs.end());
}
std::cout << "OK." << std::endl;
} else {
// Allocate some useless data, to try to get the addresses of the
// list<int>'s used later to be different across processes.
std::list<int> junk_list(comm.rank() * 3 + 1, 17);
// Receive the skeleton to build up the transferred list
std::list<int> transferred_list;
request req = comm.irecv(root, 0, skeleton(transferred_list));
req.wait();
BOOST_CHECK((int)transferred_list.size() == list_size);
// Receive the content and check it
req = comm.irecv(root, 1, get_content(transferred_list));
req.wait();
BOOST_CHECK(std::equal(make_counting_iterator(0),
make_counting_iterator(list_size),
transferred_list.begin()));
// Receive the reversed content and check it
req = comm.irecv(root, 2, get_content(transferred_list));
req.wait();
BOOST_CHECK(std::equal(make_counting_iterator(0),
make_counting_iterator(list_size),
transferred_list.rbegin()));
}
(comm.barrier)();
}
int test_main(int argc, char* argv[])
{
boost::parallel::mpi::environment env(argc, argv);
communicator comm;
if (comm.size() == 1) {
std::cerr << "ERROR: Must run the skeleton and content test with more "
"than one process."
<< std::endl;
MPI_Abort(comm, -1);
}
test_skeleton_and_content(comm, 0, true);
test_skeleton_and_content(comm, 0, false);
test_skeleton_and_content(comm, 1, true);
test_skeleton_and_content(comm, 1, false);
test_skeleton_and_content_nonblocking(comm, 0);
test_skeleton_and_content_nonblocking(comm, 1);
return 0;
}
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Boost-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/boost-cvs