// 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 #include #include #include #include #include #include #include #include #include #include #include #include #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 void serialize(Archiver& ar, const unsigned int /*version*/) { ar & processor & local_key; } }; namespace boost { namespace mpi { template<> struct is_mpi_datatype : 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 { 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 value_type; typedef value_type reference; }; inline std::pair get(remote_key_to_global, const remote_key& key) { return std::make_pair(key.processor, key.local_key); } template struct my_reduce : boost::parallel::basic_reduce { 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_vec(n, my_start_color); typedef iterator_property_map::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 ColorMap; ColorMap colors(pg, remote_key_to_global(), local_colors); colors.set_reduce(my_reduce()); 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_vec(n, my_start_value); typedef iterator_property_map::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 ValueMap; ValueMap values(pg, remote_key_to_global(), local_values); values.set_reduce(my_reduce()); 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(process_id(pg)); int next_processor = (process_id(pg) + 1) % num_processes(pg); std::string next_start_string = lexical_cast(next_processor); // Initial color map: even-numbered processes are false, // odd-numbered processes are true std::vector string_vec(n, my_start_string); typedef iterator_property_map::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 StringMap; StringMap strings(pg, remote_key_to_global(), local_strings); strings.set_reduce(my_reduce()); 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; }