mirror of
https://github.com/boostorg/mpi.git
synced 2026-02-27 17:12:24 +00:00
Full merge from trunk at revision 41356 of entire boost-root tree.
[SVN r41369]
This commit is contained in:
@@ -1,36 +0,0 @@
|
||||
# Support for the Message Passing Interface (MPI)
|
||||
#
|
||||
# (C) Copyright 2005, 2006 Trustees of Indiana University
|
||||
# (C) Copyright 2005 Douglas Gregor
|
||||
#
|
||||
# Distributed under 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.)
|
||||
#
|
||||
# Authors: Douglas Gregor
|
||||
# Andrew Lumsdaine
|
||||
|
||||
use-project /boost/mpi : ../build ;
|
||||
project /boost/mpi/test ;
|
||||
import mpi : mpi-test ;
|
||||
|
||||
if [ mpi.configured ]
|
||||
{
|
||||
test-suite mpi
|
||||
:
|
||||
[ mpi-test all_gather_test ]
|
||||
[ mpi-test all_reduce_test ]
|
||||
[ mpi-test all_to_all_test ]
|
||||
[ mpi-test broadcast_test : : : 2 17 ]
|
||||
[ mpi-test gather_test ]
|
||||
[ mpi-test is_mpi_op_test : : : 1 ]
|
||||
# Note: Microsoft MPI fails nonblocking_test on 1 processor
|
||||
[ mpi-test nonblocking_test ]
|
||||
[ mpi-test reduce_test ]
|
||||
[ mpi-test ring_test : : : 2 3 4 7 8 13 17 ]
|
||||
[ mpi-test scan_test ]
|
||||
[ mpi-test scatter_test ]
|
||||
# Note: Microsoft MPI fails all skeleton-content tests
|
||||
[ mpi-test skeleton_content_test : : : 2 3 4 7 8 13 17 ]
|
||||
[ mpi-test graph_topology_test : : : 2 7 13 ]
|
||||
;
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
// Copyright (C) 2005-2006 Douglas Gregor <doug.gregor@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 all_gather() collective.
|
||||
#include <boost/mpi/collectives/all_gather.hpp>
|
||||
#include <boost/mpi/environment.hpp>
|
||||
#include <boost/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::mpi::communicator;
|
||||
|
||||
using boost::mpi::packed_skeleton_iarchive;
|
||||
using boost::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::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::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;
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
// 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/mpi/collectives/all_reduce.hpp>
|
||||
#include <boost/mpi/communicator.hpp>
|
||||
#include <boost/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::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 mpi {
|
||||
|
||||
template <>
|
||||
struct is_mpi_datatype<point> : public mpl::true_ { };
|
||||
|
||||
} } // end namespace boost::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::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 mpi {
|
||||
|
||||
// Make std::plus<wrapped_int> commutative.
|
||||
template<>
|
||||
struct is_commutative<std::plus<wrapped_int>, wrapped_int>
|
||||
: mpl::true_ { };
|
||||
|
||||
} } // end namespace boost::mpi
|
||||
|
||||
int test_main(int argc, char* argv[])
|
||||
{
|
||||
using namespace boost::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;
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
// 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/mpi/collectives/all_to_all.hpp>
|
||||
#include <boost/mpi/communicator.hpp>
|
||||
#include <boost/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::mpi::communicator;
|
||||
|
||||
using boost::mpi::packed_skeleton_iarchive;
|
||||
using boost::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::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)));
|
||||
|
||||
if (comm.rank() == 0) {
|
||||
std::cout << "Performing all-to-all operation on " << kind << "...";
|
||||
std::cout.flush();
|
||||
}
|
||||
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)));
|
||||
}
|
||||
|
||||
if (comm.rank() == 0) {
|
||||
std::cout << " done." << std::endl;
|
||||
}
|
||||
|
||||
(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::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;
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
// 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/mpi/collectives/broadcast.hpp>
|
||||
#include <boost/mpi/communicator.hpp>
|
||||
#include <boost/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/mpi/skeleton_and_content.hpp>
|
||||
#include <boost/iterator/counting_iterator.hpp>
|
||||
|
||||
using boost::mpi::communicator;
|
||||
|
||||
using boost::mpi::packed_skeleton_iarchive;
|
||||
using boost::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::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::mpi::content;
|
||||
using boost::mpi::get_content;
|
||||
using boost::make_counting_iterator;
|
||||
using boost::mpi::broadcast;
|
||||
using boost::mpi::content;
|
||||
using boost::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::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;
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
// 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/mpi/collectives/gather.hpp>
|
||||
#include <boost/mpi/communicator.hpp>
|
||||
#include <boost/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::mpi::communicator;
|
||||
|
||||
using boost::mpi::packed_skeleton_iarchive;
|
||||
using boost::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::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::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;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#ifndef GPS_POSITION_HPP
|
||||
#define GPS_POSITION_HPP
|
||||
|
||||
// Copyright Matthias Troyer
|
||||
// 2005. Distributed under 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)
|
||||
|
||||
#include <boost/mpi/datatype_fwd.hpp>
|
||||
#include <boost/mpl/and.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
class gps_position
|
||||
{
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
// When the class Archive corresponds to an output archive, the
|
||||
// & operator is defined similar to <<. Likewise, when the class Archive
|
||||
// is a type of input archive the & operator is defined similar to >>.
|
||||
template<class Archive>
|
||||
void serialize(Archive & ar, const unsigned int version)
|
||||
{
|
||||
ar & degrees & minutes & seconds;
|
||||
}
|
||||
int degrees;
|
||||
int minutes;
|
||||
float seconds;
|
||||
public:
|
||||
gps_position(){};
|
||||
gps_position(int d, int m, float s) :
|
||||
degrees(d), minutes(m), seconds(s)
|
||||
{}
|
||||
|
||||
friend bool operator==(const gps_position& x, const gps_position& y)
|
||||
{
|
||||
return (x.degrees == y.degrees
|
||||
&& x.minutes == y.minutes
|
||||
&& x.seconds == y.seconds);
|
||||
}
|
||||
|
||||
inline friend bool operator!=(const gps_position& x, const gps_position& y)
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
namespace boost { namespace mpi {
|
||||
|
||||
template <>
|
||||
struct is_mpi_datatype<gps_position>
|
||||
: public mpl::and_
|
||||
<
|
||||
is_mpi_datatype<int>,
|
||||
is_mpi_datatype<float>
|
||||
>
|
||||
{};
|
||||
|
||||
} }
|
||||
#endif
|
||||
@@ -1,123 +0,0 @@
|
||||
// Copyright (C) 2007 Trustees of Indiana University
|
||||
|
||||
// Authors: Douglas Gregor
|
||||
// Andrew Lumsdaine
|
||||
|
||||
// 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/mpi/graph_communicator.hpp>
|
||||
#include <boost/mpi/communicator.hpp>
|
||||
#include <boost/mpi/environment.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/graph/erdos_renyi_generator.hpp>
|
||||
#include <boost/test/minimal.hpp>
|
||||
#include <boost/random/linear_congruential.hpp>
|
||||
#include <boost/graph/iteration_macros.hpp>
|
||||
#include <boost/graph/isomorphism.hpp>
|
||||
#include <algorithm> // for random_shuffle
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include <boost/mpi/collectives/broadcast.hpp>
|
||||
|
||||
using boost::mpi::communicator;
|
||||
using boost::mpi::graph_communicator;
|
||||
using namespace boost;
|
||||
|
||||
int test_main(int argc, char* argv[])
|
||||
{
|
||||
boost::function_requires< IncidenceGraphConcept<graph_communicator> >();
|
||||
boost::function_requires< AdjacencyGraphConcept<graph_communicator> >();
|
||||
boost::function_requires< VertexListGraphConcept<graph_communicator> >();
|
||||
boost::function_requires< EdgeListGraphConcept<graph_communicator> >();
|
||||
|
||||
double prob = 0.1;
|
||||
|
||||
boost::mpi::environment env(argc, argv);
|
||||
|
||||
communicator world;
|
||||
|
||||
// Random number generator
|
||||
minstd_rand gen;
|
||||
|
||||
// Build a random graph with as many vertices as there are processes
|
||||
typedef adjacency_list<listS, vecS, bidirectionalS> Graph;
|
||||
sorted_erdos_renyi_iterator<minstd_rand, Graph>
|
||||
first(gen, world.size(), prob), last;
|
||||
Graph graph(first, last, world.size());
|
||||
|
||||
// Display the original graph
|
||||
if (world.rank() == 0) {
|
||||
std::cout << "Original, random graph:\n";
|
||||
BGL_FORALL_VERTICES(v, graph, Graph) {
|
||||
BGL_FORALL_OUTEDGES(v, e, graph, Graph) {
|
||||
std::cout << source(e, graph) << " -> " << target(e, graph)
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create an arbitrary mapping from vertices to integers
|
||||
typedef property_map<Graph, vertex_index_t>::type GraphVertexIndexMap;
|
||||
std::vector<int> graph_alt_index_vec(num_vertices(graph));
|
||||
iterator_property_map<int*, GraphVertexIndexMap>
|
||||
graph_alt_index(&graph_alt_index_vec[0], get(vertex_index, graph));
|
||||
|
||||
// Rank 0 will populate the alternative index vector
|
||||
if (world.rank() == 0) {
|
||||
int index = 0;
|
||||
BGL_FORALL_VERTICES(v, graph, Graph)
|
||||
put(graph_alt_index, v, index++);
|
||||
|
||||
std::random_shuffle(graph_alt_index_vec.begin(), graph_alt_index_vec.end());
|
||||
}
|
||||
broadcast(world, graph_alt_index_vec, 0);
|
||||
|
||||
// Display the original graph with the remapping
|
||||
if (world.rank() == 0) {
|
||||
std::cout << "Original, random graph with remapped vertex numbers:\n";
|
||||
BGL_FORALL_VERTICES(v, graph, Graph) {
|
||||
BGL_FORALL_OUTEDGES(v, e, graph, Graph) {
|
||||
std::cout << get(graph_alt_index, source(e, graph)) << " -> "
|
||||
<< get(graph_alt_index, target(e, graph)) << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a communicator with a topology equivalent to the graph
|
||||
graph_communicator graph_comm(world, graph, graph_alt_index, false);
|
||||
|
||||
// The communicator's topology should have the same number of
|
||||
// vertices and edges and the original graph
|
||||
BOOST_CHECK((int)num_vertices(graph) == num_vertices(graph_comm));
|
||||
BOOST_CHECK((int)num_edges(graph) == num_edges(graph_comm));
|
||||
|
||||
// Display the communicator graph
|
||||
if (graph_comm.rank() == 0) {
|
||||
std::cout << "Communicator graph:\n";
|
||||
BGL_FORALL_VERTICES(v, graph_comm, graph_communicator) {
|
||||
BGL_FORALL_OUTEDGES(v, e, graph_comm, graph_communicator) {
|
||||
std::cout << source(e, graph_comm) << " -> " << target(e, graph_comm)
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Communicator graph via edges():\n";
|
||||
BGL_FORALL_EDGES(e, graph_comm, graph_communicator)
|
||||
std::cout << source(e, graph_comm) << " -> " << target(e, graph_comm)
|
||||
<< std::endl;
|
||||
}
|
||||
(graph_comm.barrier)();
|
||||
|
||||
// Verify the isomorphism
|
||||
if (graph_comm.rank() == 0)
|
||||
std::cout << "Verifying isomorphism..." << std::endl;
|
||||
BOOST_CHECK(verify_isomorphism(graph, graph_comm, graph_alt_index));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright (C) 2005-2006 Douglas Gregor <doug.gregor@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 is_mpi_op functionality.
|
||||
#include <boost/mpi/operations.hpp>
|
||||
#include <boost/mpi/environment.hpp>
|
||||
#include <boost/type_traits/is_base_and_derived.hpp>
|
||||
#include <boost/test/minimal.hpp>
|
||||
|
||||
using namespace boost::mpi;
|
||||
using namespace std;
|
||||
using boost::is_base_and_derived;
|
||||
|
||||
int test_main(int argc, char* argv[])
|
||||
{
|
||||
boost::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;
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
// 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/mpi/nonblocking.hpp>
|
||||
#include <boost/mpi/communicator.hpp>
|
||||
#include <boost/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::mpi::communicator;
|
||||
using boost::mpi::request;
|
||||
using boost::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::mpi::wait_any;
|
||||
using boost::mpi::test_any;
|
||||
using boost::mpi::wait_all;
|
||||
using boost::mpi::test_all;
|
||||
using boost::mpi::wait_some;
|
||||
using boost::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::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;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
# Copyright (C) 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)
|
||||
|
||||
# Test all_gather() collective.
|
||||
|
||||
import boost.parallel.mpi as mpi
|
||||
from generators import *
|
||||
|
||||
def all_gather_test(comm, generator, kind):
|
||||
if comm.rank == 0: print ("Gathering %s..." % (kind,)),
|
||||
my_value = generator(comm.rank)
|
||||
result = mpi.all_gather(comm, my_value)
|
||||
for p in range(0, comm.size):
|
||||
assert result[p] == generator(p)
|
||||
if comm.rank == 0: print "OK."
|
||||
|
||||
return
|
||||
|
||||
all_gather_test(mpi.world, int_generator, "integers")
|
||||
all_gather_test(mpi.world, gps_generator, "GPS positions")
|
||||
all_gather_test(mpi.world, string_generator, "strings")
|
||||
all_gather_test(mpi.world, string_list_generator, "list of strings")
|
||||
@@ -1,29 +0,0 @@
|
||||
# Copyright (C) 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)
|
||||
|
||||
# Test all_reduce() collective.
|
||||
|
||||
import boost.parallel.mpi as mpi
|
||||
from generators import *
|
||||
|
||||
def all_reduce_test(comm, generator, kind, op, op_kind):
|
||||
if comm.rank == 0:
|
||||
print ("Reducing to %s of %s..." % (op_kind, kind)),
|
||||
my_value = generator(comm.rank)
|
||||
result = mpi.all_reduce(comm, my_value, op)
|
||||
expected_result = generator(0);
|
||||
for p in range(1, comm.size):
|
||||
expected_result = op(expected_result, generator(p))
|
||||
|
||||
assert result == expected_result
|
||||
if comm.rank == 0:
|
||||
print "OK."
|
||||
return
|
||||
|
||||
all_reduce_test(mpi.world, int_generator, "integers", lambda x,y:x + y, "sum")
|
||||
all_reduce_test(mpi.world, int_generator, "integers", lambda x,y:x * y, "product")
|
||||
all_reduce_test(mpi.world, string_generator, "strings", lambda x,y:x + y, "concatenation")
|
||||
all_reduce_test(mpi.world, string_list_generator, "list of strings", lambda x,y:x + y, "concatenation")
|
||||
@@ -1,30 +0,0 @@
|
||||
# Copyright (C) 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)
|
||||
|
||||
# Test all_to_all() collective.
|
||||
|
||||
import boost.parallel.mpi as mpi
|
||||
from generators import *
|
||||
|
||||
def all_to_all_test(comm, generator, kind):
|
||||
if comm.rank == 0:
|
||||
print ("All-to-all transmission of %s..." % (kind,)),
|
||||
|
||||
values = list()
|
||||
for p in range(0, comm.size):
|
||||
values.append(generator(p))
|
||||
result = mpi.all_to_all(comm, values)
|
||||
|
||||
for p in range(0, comm.size):
|
||||
assert result[p] == generator(comm.rank)
|
||||
|
||||
if comm.rank == 0: print "OK."
|
||||
return
|
||||
|
||||
all_to_all_test(mpi.world, int_generator, "integers")
|
||||
all_to_all_test(mpi.world, gps_generator, "GPS positions")
|
||||
all_to_all_test(mpi.world, string_generator, "strings")
|
||||
all_to_all_test(mpi.world, string_list_generator, "list of strings")
|
||||
@@ -1,29 +0,0 @@
|
||||
# Copyright (C) 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)
|
||||
|
||||
# Test broadcast() collective.
|
||||
|
||||
import boost.parallel.mpi as mpi
|
||||
|
||||
def broadcast_test(comm, value, kind, root):
|
||||
if comm.rank == root:
|
||||
print ("Broadcasting %s from root %d..." % (kind, root)),
|
||||
|
||||
got_value = mpi.broadcast(comm, value, root)
|
||||
assert got_value == value
|
||||
if comm.rank == root:
|
||||
print "OK."
|
||||
return
|
||||
|
||||
broadcast_test(mpi.world, 17, 'integer', 0)
|
||||
broadcast_test(mpi.world, 17, 'integer', 1)
|
||||
broadcast_test(mpi.world, 'Hello, World!', 'string', 0)
|
||||
broadcast_test(mpi.world, 'Hello, World!', 'string', 1)
|
||||
broadcast_test(mpi.world, ['Hello', 'MPI', 'Python', 'World'],
|
||||
'list of strings', 0)
|
||||
broadcast_test(mpi.world, ['Hello', 'MPI', 'Python', 'World'],
|
||||
'list of strings', 1)
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
# Copyright (C) 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)
|
||||
|
||||
# Test gather() collective.
|
||||
|
||||
import boost.parallel.mpi as mpi
|
||||
from generators import *
|
||||
|
||||
def gather_test(comm, generator, kind, root):
|
||||
if comm.rank == root:
|
||||
print ("Gathering %s to root %d..." % (kind, root)),
|
||||
my_value = generator(comm.rank)
|
||||
result = mpi.gather(comm, my_value, root)
|
||||
if comm.rank == root:
|
||||
for p in range(0, comm.size):
|
||||
assert result[p] == generator(p)
|
||||
print "OK."
|
||||
else:
|
||||
assert result == None
|
||||
return
|
||||
|
||||
gather_test(mpi.world, int_generator, "integers", 0)
|
||||
gather_test(mpi.world, int_generator, "integers", 1)
|
||||
gather_test(mpi.world, gps_generator, "GPS positions", 0)
|
||||
gather_test(mpi.world, gps_generator, "GPS positions", 1)
|
||||
gather_test(mpi.world, string_generator, "strings", 0)
|
||||
gather_test(mpi.world, string_generator, "strings", 1)
|
||||
gather_test(mpi.world, string_list_generator, "list of strings", 0)
|
||||
gather_test(mpi.world, string_list_generator, "list of strings", 1)
|
||||
@@ -1,23 +0,0 @@
|
||||
# Copyright (C) 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)
|
||||
|
||||
# Value generators used in the Boost.MPI Python regression tests
|
||||
def int_generator(p):
|
||||
return 17 + p
|
||||
|
||||
def gps_generator(p):
|
||||
return (39 + p, 16, 20.2799)
|
||||
|
||||
def string_generator(p):
|
||||
result = "%d rosebud" % p;
|
||||
if p != 1: result = result + 's'
|
||||
return result
|
||||
|
||||
def string_list_generator(p):
|
||||
result = list()
|
||||
for i in range(0,p):
|
||||
result.append(str(i))
|
||||
return result
|
||||
@@ -1,31 +0,0 @@
|
||||
# Copyright (C) 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)
|
||||
|
||||
# Test reduce() collective.
|
||||
|
||||
import boost.parallel.mpi as mpi
|
||||
from generators import *
|
||||
|
||||
def reduce_test(comm, generator, kind, op, op_kind, root):
|
||||
if comm.rank == root:
|
||||
print ("Reducing to %s of %s at root %d..." % (op_kind, kind, root)),
|
||||
my_value = generator(comm.rank)
|
||||
result = mpi.reduce(comm, my_value, op, root)
|
||||
if comm.rank == root:
|
||||
expected_result = generator(0);
|
||||
for p in range(1, comm.size):
|
||||
expected_result = op(expected_result, generator(p))
|
||||
assert result == expected_result
|
||||
print "OK."
|
||||
else:
|
||||
assert result == None
|
||||
return
|
||||
|
||||
reduce_test(mpi.world, int_generator, "integers", lambda x,y:x + y, "sum", 0)
|
||||
reduce_test(mpi.world, int_generator, "integers", lambda x,y:x * y, "product", 1)
|
||||
reduce_test(mpi.world, int_generator, "integers", min, "minimum", 0)
|
||||
reduce_test(mpi.world, string_generator, "strings", lambda x,y:x + y, "concatenation", 0)
|
||||
reduce_test(mpi.world, string_list_generator, "list of strings", lambda x,y:x + y, "concatenation", 0)
|
||||
@@ -1,42 +0,0 @@
|
||||
# Copyright (C) 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)
|
||||
|
||||
# Test basic communication.
|
||||
|
||||
import boost.parallel.mpi as mpi
|
||||
|
||||
def ring_test(comm, value, kind, root):
|
||||
next_peer = (comm.rank + 1) % comm.size;
|
||||
prior_peer = (comm.rank + comm.size - 1) % comm.size;
|
||||
|
||||
if comm.rank == root:
|
||||
print ("Passing %s around a ring from root %d..." % (kind, root)),
|
||||
comm.send(next_peer, 0, value)
|
||||
(other_value, stat) = comm.recv(return_status = True)
|
||||
assert value == other_value
|
||||
assert stat.source == prior_peer
|
||||
assert stat.tag == 0
|
||||
else:
|
||||
msg = comm.probe()
|
||||
other_value = comm.recv(msg.source, msg.tag)
|
||||
assert value == other_value
|
||||
comm.send(next_peer, 0, other_value)
|
||||
|
||||
comm.barrier()
|
||||
if comm.rank == root:
|
||||
print "OK"
|
||||
pass
|
||||
|
||||
if mpi.world.size < 2:
|
||||
print "ERROR: ring_test.py must be executed with more than one process"
|
||||
mpi.world.abort(-1);
|
||||
|
||||
ring_test(mpi.world, 17, 'integers', 0)
|
||||
ring_test(mpi.world, 17, 'integers', 1)
|
||||
ring_test(mpi.world, 'Hello, World!', 'string', 0)
|
||||
ring_test(mpi.world, 'Hello, World!', 'string', 1)
|
||||
ring_test(mpi.world, ['Hello', 'MPI', 'Python', 'World'], 'list of strings', 0)
|
||||
ring_test(mpi.world, ['Hello', 'MPI', 'Python', 'World'], 'list of strings', 1)
|
||||
@@ -1,29 +0,0 @@
|
||||
# Copyright (C) 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)
|
||||
|
||||
# Test scan() collective.
|
||||
|
||||
import boost.parallel.mpi as mpi
|
||||
from generators import *
|
||||
|
||||
def scan_test(comm, generator, kind, op, op_kind):
|
||||
if comm.rank == 0:
|
||||
print ("Prefix reduction to %s of %s..." % (op_kind, kind)),
|
||||
my_value = generator(comm.rank)
|
||||
result = mpi.scan(comm, my_value, op)
|
||||
expected_result = generator(0);
|
||||
for p in range(1, comm.rank+1):
|
||||
expected_result = op(expected_result, generator(p))
|
||||
|
||||
assert result == expected_result
|
||||
if comm.rank == 0:
|
||||
print "OK."
|
||||
return
|
||||
|
||||
scan_test(mpi.world, int_generator, "integers", lambda x,y:x + y, "sum")
|
||||
scan_test(mpi.world, int_generator, "integers", lambda x,y:x * y, "product")
|
||||
scan_test(mpi.world, string_generator, "strings", lambda x,y:x + y, "concatenation")
|
||||
scan_test(mpi.world, string_list_generator, "list of strings", lambda x,y:x + y, "concatenation")
|
||||
@@ -1,36 +0,0 @@
|
||||
# Copyright (C) 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)
|
||||
|
||||
# Test scatter() collective.
|
||||
|
||||
import boost.parallel.mpi as mpi
|
||||
from generators import *
|
||||
|
||||
def scatter_test(comm, generator, kind, root):
|
||||
if comm.rank == root:
|
||||
print ("Scattering %s from root %d..." % (kind, root)),
|
||||
|
||||
if comm.rank == root:
|
||||
values = list()
|
||||
for p in range(0, comm.size):
|
||||
values.append(generator(p))
|
||||
result = mpi.scatter(comm, values, root = root)
|
||||
else:
|
||||
result = mpi.scatter(comm, root = root);
|
||||
|
||||
assert result == generator(comm.rank)
|
||||
|
||||
if comm.rank == root: print "OK."
|
||||
return
|
||||
|
||||
scatter_test(mpi.world, int_generator, "integers", 0)
|
||||
scatter_test(mpi.world, int_generator, "integers", 1)
|
||||
scatter_test(mpi.world, gps_generator, "GPS positions", 0)
|
||||
scatter_test(mpi.world, gps_generator, "GPS positions", 1)
|
||||
scatter_test(mpi.world, string_generator, "strings", 0)
|
||||
scatter_test(mpi.world, string_generator, "strings", 1)
|
||||
scatter_test(mpi.world, string_list_generator, "list of strings", 0)
|
||||
scatter_test(mpi.world, string_list_generator, "list of strings", 1)
|
||||
@@ -1,37 +0,0 @@
|
||||
// (C) Copyright 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)
|
||||
|
||||
// Authors: Douglas Gregor
|
||||
|
||||
#include <boost/parallel/mpi/python.hpp>
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/serialization/list.hpp>
|
||||
using namespace boost::python;
|
||||
|
||||
template<typename T>
|
||||
boost::python::list list_to_python(const std::list<T>& value) {
|
||||
boost::python::list result;
|
||||
for (typename std::list<T>::const_iterator i = value.begin();
|
||||
i != value.end(); ++i)
|
||||
result.append(*i);
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOST_PYTHON_MODULE(skeleton_content)
|
||||
{
|
||||
using boost::python::arg;
|
||||
|
||||
class_<std::list<int> >("list_int")
|
||||
.def("push_back", &std::list<int>::push_back, arg("value"))
|
||||
.def("pop_back", &std::list<int>::pop_back)
|
||||
.def("reverse", &std::list<int>::reverse)
|
||||
.def(boost::python::self == boost::python::self)
|
||||
.def(boost::python::self != boost::python::self)
|
||||
.add_property("size", &std::list<int>::size)
|
||||
.def("to_python", &list_to_python<int>);
|
||||
|
||||
boost::parallel::mpi::python::register_skeleton_and_content<std::list<int> >();
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
# Copyright (C) 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)
|
||||
|
||||
# Test skeleton/content
|
||||
|
||||
import boost.parallel.mpi as mpi
|
||||
import skeleton_content
|
||||
|
||||
def test_skeleton_and_content(comm, root, manual_broadcast = True):
|
||||
assert manual_broadcast
|
||||
|
||||
# Setup data
|
||||
list_size = comm.size + 7
|
||||
original_list = skeleton_content.list_int()
|
||||
for i in range(0,list_size):
|
||||
original_list.push_back(i)
|
||||
|
||||
if comm.rank == root:
|
||||
# Broadcast skeleton
|
||||
print ("Broadcasting integer list skeleton from root %d..." % (root)),
|
||||
if manual_broadcast:
|
||||
for p in range(0,comm.size):
|
||||
if p != comm.rank:
|
||||
comm.send(p, 0, value = mpi.skeleton(original_list))
|
||||
print "OK."
|
||||
|
||||
# Broadcast content
|
||||
print ("Broadcasting integer list content from root %d..." % (root)),
|
||||
if manual_broadcast:
|
||||
for p in range(0,comm.size):
|
||||
if p != comm.rank:
|
||||
comm.send(p, 0, value = mpi.get_content(original_list))
|
||||
|
||||
print "OK."
|
||||
|
||||
# Broadcast reversed content
|
||||
original_list.reverse()
|
||||
print ("Broadcasting reversed integer list content from root %d..." % (root)),
|
||||
if manual_broadcast:
|
||||
for p in range(0,comm.size):
|
||||
if p != comm.rank:
|
||||
comm.send(p, 0, value = mpi.get_content(original_list))
|
||||
|
||||
print "OK."
|
||||
else:
|
||||
# Allocate some useless data, to try to get the addresses of
|
||||
# the underlying lists used later to be different across
|
||||
# processors.
|
||||
junk_list = skeleton_content.list_int()
|
||||
for i in range(0,comm.rank * 3 + 1):
|
||||
junk_list.push_back(i)
|
||||
|
||||
# Receive the skeleton of the list
|
||||
if manual_broadcast:
|
||||
transferred_list_skeleton = comm.recv(root, 0)
|
||||
assert transferred_list_skeleton.object.size == list_size
|
||||
|
||||
# Receive the content and check it
|
||||
transferred_list = transferred_list_skeleton.object
|
||||
if manual_broadcast:
|
||||
comm.recv(root, 0, mpi.get_content(transferred_list))
|
||||
assert transferred_list == original_list
|
||||
|
||||
# Receive the content (again) and check it
|
||||
original_list.reverse()
|
||||
if manual_broadcast:
|
||||
comm.recv(root, 0, mpi.get_content(transferred_list))
|
||||
assert transferred_list == original_list
|
||||
|
||||
|
||||
test_skeleton_and_content(mpi.world, 0)
|
||||
test_skeleton_and_content(mpi.world, 1)
|
||||
@@ -1,237 +0,0 @@
|
||||
// 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/mpi/collectives/reduce.hpp>
|
||||
#include <boost/mpi/communicator.hpp>
|
||||
#include <boost/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::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 mpi {
|
||||
|
||||
template <>
|
||||
struct is_mpi_datatype<point> : public mpl::true_ { };
|
||||
|
||||
} } // end namespace boost::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::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 mpi {
|
||||
|
||||
// Make std::plus<wrapped_int> commutative.
|
||||
template<>
|
||||
struct is_commutative<std::plus<wrapped_int>, wrapped_int>
|
||||
: mpl::true_ { };
|
||||
|
||||
} } // end namespace boost::mpi
|
||||
|
||||
int test_main(int argc, char* argv[])
|
||||
{
|
||||
using namespace boost::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;
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
// 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/mpi/communicator.hpp>
|
||||
#include <boost/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::mpi::communicator;
|
||||
using boost::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::mpi::any_source, 0);
|
||||
boost::optional<int> num_values = stat.template count<T>();
|
||||
if (boost::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::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;
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
// 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/mpi/collectives/scan.hpp>
|
||||
#include <boost/mpi/communicator.hpp>
|
||||
#include <boost/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::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 mpi {
|
||||
|
||||
template <>
|
||||
struct is_mpi_datatype<point> : public mpl::true_ { };
|
||||
|
||||
} } // end namespace boost::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::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 mpi {
|
||||
|
||||
// Make std::plus<wrapped_int> commutative.
|
||||
template<>
|
||||
struct is_commutative<std::plus<wrapped_int>, wrapped_int>
|
||||
: mpl::true_ { };
|
||||
|
||||
} } // end namespace boost::mpi
|
||||
|
||||
int test_main(int argc, char* argv[])
|
||||
{
|
||||
using namespace boost::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;
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
// 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/mpi/collectives/scatter.hpp>
|
||||
#include <boost/mpi/communicator.hpp>
|
||||
#include <boost/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::mpi::communicator;
|
||||
|
||||
using boost::mpi::packed_skeleton_iarchive;
|
||||
using boost::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::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::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;
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
// 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/mpi/communicator.hpp>
|
||||
#include <boost/mpi/environment.hpp>
|
||||
#include <boost/test/minimal.hpp>
|
||||
#include <boost/serialization/list.hpp>
|
||||
#include <boost/mpi/skeleton_and_content.hpp>
|
||||
#include <boost/mpi/nonblocking.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/iterator/counting_iterator.hpp>
|
||||
#include <boost/mpi/collectives/broadcast.hpp>
|
||||
|
||||
using boost::mpi::communicator;
|
||||
|
||||
using boost::mpi::packed_skeleton_iarchive;
|
||||
using boost::mpi::packed_skeleton_oarchive;
|
||||
|
||||
void
|
||||
test_skeleton_and_content(const communicator& comm, int root,
|
||||
bool manual_broadcast)
|
||||
{
|
||||
using boost::mpi::skeleton;
|
||||
using boost::mpi::content;
|
||||
using boost::mpi::get_content;
|
||||
using boost::make_counting_iterator;
|
||||
using boost::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::mpi::skeleton;
|
||||
using boost::mpi::content;
|
||||
using boost::mpi::get_content;
|
||||
using boost::make_counting_iterator;
|
||||
using boost::mpi::broadcast;
|
||||
using boost::mpi::request;
|
||||
using boost::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::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;
|
||||
}
|
||||
Reference in New Issue
Block a user