blob: cf87a8c15ae76def1e3dc1db4ace9ad211f25982 [file] [log] [blame]
// 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;
}
enum color_t {red, green, blue};
BOOST_IS_MPI_DATATYPE(color_t)
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, red, "enums", 1);
ring_test(comm, red, "enums", 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;
}