blob: d1aae740eac4572f2947925ff7e6df26d303ddf2 [file] [log] [blame]
// Copyright (C) 2004-2008 The Trustees of Indiana University.
// 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
// Andrew Lumsdaine
#include <boost/graph/use_mpi.hpp>
#include <boost/config.hpp>
#include <boost/throw_exception.hpp>
#include <boost/graph/distributed/mpi_process_group.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/test/minimal.hpp>
#include <vector>
#include <string>
#include <boost/serialization/string.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/graph/parallel/basic_reduce.hpp>
#ifdef BOOST_NO_EXCEPTIONS
void
boost::throw_exception(std::exception const& ex)
{
std::cout << ex.what() << std::endl;
abort();
}
#endif
using namespace boost;
using boost::graph::distributed::mpi_process_group;
enum color_t { red, blue };
struct remote_key
{
remote_key(int p = -1, std::size_t l = 0) : processor(p), local_key(l) {}
int processor;
std::size_t local_key;
template<typename Archiver>
void serialize(Archiver& ar, const unsigned int /*version*/)
{
ar & processor & local_key;
}
};
namespace boost { namespace mpi {
template<> struct is_mpi_datatype<remote_key> : mpl::true_ { };
} }
BOOST_IS_BITWISE_SERIALIZABLE(remote_key)
BOOST_CLASS_IMPLEMENTATION(remote_key,object_serializable)
BOOST_CLASS_TRACKING(remote_key,track_never)
namespace boost {
template<>
struct hash<remote_key>
{
std::size_t operator()(const remote_key& key) const
{
std::size_t hash = hash_value(key.processor);
hash_combine(hash, key.local_key);
return hash;
}
};
}
inline bool operator==(const remote_key& x, const remote_key& y)
{ return x.processor == y.processor && x.local_key == y.local_key; }
struct remote_key_to_global
{
typedef readable_property_map_tag category;
typedef remote_key key_type;
typedef std::pair<int, std::size_t> value_type;
typedef value_type reference;
};
inline std::pair<int, std::size_t>
get(remote_key_to_global, const remote_key& key)
{
return std::make_pair(key.processor, key.local_key);
}
template<typename T>
struct my_reduce : boost::parallel::basic_reduce<T> {
BOOST_STATIC_CONSTANT(bool, non_default_resolver = true);
};
void colored_test()
{
mpi_process_group pg;
const int n = 500;
color_t my_start_color = process_id(pg) % 2 == 0? ::red : ::blue;
int next_processor = (process_id(pg) + 1) % num_processes(pg);
color_t next_start_color = next_processor % 2 == 0? ::red : ::blue;
// Initial color map: even-numbered processes are all red,
// odd-numbered processes are all blue.
std::vector<color_t> color_vec(n, my_start_color);
typedef iterator_property_map<std::vector<color_t>::iterator,
identity_property_map> LocalPropertyMap;
LocalPropertyMap local_colors(color_vec.begin(), identity_property_map());
synchronize(pg);
// Create the distributed property map
typedef boost::parallel::distributed_property_map<mpi_process_group,
remote_key_to_global,
LocalPropertyMap> ColorMap;
ColorMap colors(pg, remote_key_to_global(), local_colors);
colors.set_reduce(my_reduce<color_t>());
if (process_id(pg) == 0) std::cerr << "Checking local colors...";
// check local processor colors
for (int i = 0; i < n; ++i) {
remote_key k(process_id(pg), i);
BOOST_CHECK(get(colors, k) == my_start_color);
}
colors.set_consistency_model(boost::parallel::cm_bidirectional);
if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's default colors...";
// check next processor's colors
for (int i = 0; i < n; ++i) {
remote_key k(next_processor, i);
BOOST_CHECK(get(colors, k) == color_t());
}
if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
synchronize(pg);
if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's colors...";
// check next processor's colors
for (int i = 0; i < n; ++i) {
remote_key k(next_processor, i);
BOOST_CHECK(get(colors, k) == next_start_color);
}
if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
synchronize(pg);
if (process_id(pg) == 0) std::cerr << "OK.\nChanging next processor's colors...";
// change the next processor's colors
color_t next_finish_color = next_processor % 2 == 0? ::blue : ::red;
for (int i = 0; i < n; ++i) {
remote_key k(next_processor, i);
put(colors, k, next_finish_color);
}
if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
synchronize(pg);
if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed colors...";
// check our own colors
color_t my_finish_color = process_id(pg) % 2 == 0? ::blue : ::red;
for (int i = 0; i < n; ++i) {
remote_key k(process_id(pg), i);
BOOST_CHECK(get(colors, k) == my_finish_color);
}
// check our neighbor's colors
if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed colors on neighbor...";
for (int i = 0; i < n; ++i) {
remote_key k(next_processor, i);
BOOST_CHECK(get(colors, k) == next_finish_color);
}
synchronize(pg);
if (process_id(pg) == 0) std::cerr << "OK.\n";
}
void bool_test()
{
mpi_process_group pg;
const int n = 500;
bool my_start_value = process_id(pg) % 2;
int next_processor = (process_id(pg) + 1) % num_processes(pg);
bool next_start_value = ((process_id(pg) + 1) % num_processes(pg)) % 2;
// Initial color map: even-numbered processes are false,
// odd-numbered processes are true
std::vector<bool> bool_vec(n, my_start_value);
typedef iterator_property_map<std::vector<bool>::iterator,
identity_property_map> LocalPropertyMap;
LocalPropertyMap local_values(bool_vec.begin(), identity_property_map());
synchronize(pg);
// Create the distributed property map
typedef boost::parallel::distributed_property_map<mpi_process_group,
remote_key_to_global,
LocalPropertyMap> ValueMap;
ValueMap values(pg, remote_key_to_global(), local_values);
values.set_reduce(my_reduce<bool>());
if (process_id(pg) == 0) std::cerr << "Checking local values...";
// check local processor values
for (int i = 0; i < n; ++i) {
remote_key k(process_id(pg), i);
BOOST_CHECK(get(values, k) == my_start_value);
}
values.set_consistency_model(boost::parallel::cm_bidirectional);
if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's default values...";
// check next processor's values
for (int i = 0; i < n; ++i) {
remote_key k(next_processor, i);
BOOST_CHECK(get(values, k) == false);
}
if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
synchronize(pg);
if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's values...";
// check next processor's values
for (int i = 0; i < n; ++i) {
remote_key k(next_processor, i);
BOOST_CHECK(get(values, k) == next_start_value);
}
if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
synchronize(pg);
if (process_id(pg) == 0) std::cerr << "OK.\nChanging next processor's values...";
// change the next processor's values
bool next_finish_value = next_processor % 2 == 0;
for (int i = 0; i < n; ++i) {
remote_key k(next_processor, i);
put(values, k, next_finish_value);
}
if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
synchronize(pg);
if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed values...";
// check our own values
bool my_finish_value = process_id(pg) % 2 == 0;
for (int i = 0; i < n; ++i) {
remote_key k(process_id(pg), i);
BOOST_CHECK(get(values, k) == my_finish_value);
}
// check our neighbor's values
if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed values on neighbor...";
for (int i = 0; i < n; ++i) {
remote_key k(next_processor, i);
BOOST_CHECK(get(values, k) == next_finish_value);
}
synchronize(pg);
if (process_id(pg) == 0) std::cerr << "OK.\n";
}
void string_test()
{
mpi_process_group pg;
const int n = 500;
std::string my_start_string = lexical_cast<std::string>(process_id(pg));
int next_processor = (process_id(pg) + 1) % num_processes(pg);
std::string next_start_string = lexical_cast<std::string>(next_processor);
// Initial color map: even-numbered processes are false,
// odd-numbered processes are true
std::vector<std::string> string_vec(n, my_start_string);
typedef iterator_property_map<std::vector<std::string>::iterator,
identity_property_map> LocalPropertyMap;
LocalPropertyMap local_strings(string_vec.begin(), identity_property_map());
synchronize(pg);
// Create the distributed property map
typedef boost::parallel::distributed_property_map<mpi_process_group,
remote_key_to_global,
LocalPropertyMap> StringMap;
StringMap strings(pg, remote_key_to_global(), local_strings);
strings.set_reduce(my_reduce<std::string>());
if (process_id(pg) == 0) std::cerr << "Checking local strings...";
// check local processor strings
for (int i = 0; i < n; ++i) {
remote_key k(process_id(pg), i);
BOOST_CHECK(get(strings, k) == my_start_string);
}
strings.set_consistency_model(boost::parallel::cm_bidirectional);
if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's default strings...";
// check next processor's strings
for (int i = 0; i < n; ++i) {
remote_key k(next_processor, i);
BOOST_CHECK(get(strings, k) == (num_processes(pg) == 1 ? my_start_string : std::string()));
}
if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
synchronize(pg);
if (process_id(pg) == 0) std::cerr << "OK.\nChecking next processor's strings...";
// check next processor's strings
for (int i = 0; i < n; ++i) {
remote_key k(next_processor, i);
BOOST_CHECK(get(strings, k) == next_start_string);
}
if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
synchronize(pg);
if (process_id(pg) == 0) std::cerr << "OK.\nChanging next processor's strings...";
// change the next processor's strings
std::string next_finish_string = next_start_string + next_start_string;
for (int i = 0; i < n; ++i) {
remote_key k(next_processor, i);
put(strings, k, next_finish_string);
}
if (process_id(pg) == 0) std::cerr << "OK.\nSynchronizing...";
synchronize(pg);
if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed strings...";
// check our own strings
std::string my_finish_string = my_start_string + my_start_string;
for (int i = 0; i < n; ++i) {
remote_key k(process_id(pg), i);
BOOST_CHECK(get(strings, k) == my_finish_string);
}
// check our neighbor's strings
if (process_id(pg) == 0) std::cerr << "OK.\nChecking changed strings on neighbor...";
for (int i = 0; i < n; ++i) {
remote_key k(next_processor, i);
BOOST_CHECK(get(strings, k) == next_finish_string);
}
synchronize(pg);
if (process_id(pg) == 0) std::cerr << "OK.\n";
}
int test_main(int argc, char** argv)
{
boost::mpi::environment env(argc, argv);
colored_test();
bool_test();
string_test();
return 0;
}