123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- // 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/vector.hpp>
- #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;
- }
|