Update of /cvsroot/boost/boost/libs/parallel/example
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv657/libs/parallel/example
Added Files:
generate_collect.cpp generate_collect_optional.cpp
hello_world.cpp hello_world_broadcast.cpp
hello_world_nonblocking.cpp parallel_example.cpp
random_content.cpp random_gather.cpp random_min.cpp
reduce_performance_test.cpp string_cat.cpp
Log Message:
Import Boost.MPI with the beginnings of a BBv2-based build system
--- NEW FILE: generate_collect.cpp ---
// Copyright (C) 2006 Douglas Gregor <[EMAIL PROTECTED]>
// 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)
// An example using Boost.MPI's split() operation on communicators to
// create separate data-generating processes and data-collecting
// processes.
#include <boost/parallel/mpi.hpp>
#include <iostream>
#include <cstdlib>
#include <boost/serialization/vector.hpp>
namespace mpi = boost::parallel::mpi;
enum message_tags { msg_data_packet, msg_broadcast_data, msg_finished };
void generate_data(mpi::communicator local, mpi::communicator world)
{
using std::srand;
using std::rand;
// The rank of the collector within the world communicator
int master_collector = local.size();
srand(time(0) + world.rank());
// Send out several blocks of random data to the collectors.
int num_data_blocks = rand() % 3 + 1;
for (int block = 0; block < num_data_blocks; ++block) {
// Generate some random data
int num_samples = rand() % 1000;
std::vector<int> data;
for (int i = 0; i < num_samples; ++i) {
data.push_back(rand());
}
// Send our data to the master collector process.
std::cout << "Generator #" << local.rank() << " sends some data..."
<< std::endl;
world.send(master_collector, msg_data_packet, data);
}
// Wait for all of the generators to complete
(local.barrier)();
// The first generator will send the message to the master collector
// indicating that we're done.
if (local.rank() == 0)
world.send(master_collector, msg_finished);
}
void collect_data(mpi::communicator local, mpi::communicator world)
{
// The rank of the collector within the world communicator
int master_collector = world.size() - local.size();
if (world.rank() == master_collector) {
while (true) {
// Wait for a message
mpi::status msg = world.probe();
if (msg.tag() == msg_data_packet) {
// Receive the packet of data
std::vector<int> data;
world.recv(msg.source(), msg.tag(), data);
// Tell each of the collectors that we'll be broadcasting some data
for (int dest = 1; dest < local.size(); ++dest)
local.send(dest, msg_broadcast_data, msg.source());
// Broadcast the actual data.
broadcast(local, data, 0);
} else if (msg.tag() == msg_finished) {
// Receive the message
world.recv(msg.source(), msg.tag());
// Tell each of the collectors that we're finished
for (int dest = 1; dest < local.size(); ++dest)
local.send(dest, msg_finished);
break;
}
}
} else {
while (true) {
// Wait for a message from the master collector
mpi::status msg = local.probe();
if (msg.tag() == msg_broadcast_data) {
// Receive the broadcast message
int originator;
local.recv(msg.source(), msg.tag(), originator);
// Receive the data broadcasted from the master collector
std::vector<int> data;
broadcast(local, data, 0);
std::cout << "Collector #" << local.rank()
<< " is processing data from generator #" << originator
<< "." << std::endl;
} else if (msg.tag() == msg_finished) {
// Receive the message
local.recv(msg.source(), msg.tag());
break;
}
}
}
}
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
if (world.size() < 3) {
if (world.rank() == 0) {
std::cerr << "Error: this example requires at least 3 processes."
<< std::endl;
}
env.abort(-1);
}
bool is_generator = world.rank() < 2 * world.size() / 3;
mpi::communicator local = world.split(is_generator? 0 : 1);
if (is_generator) generate_data(local, world);
else collect_data(local, world);
return 0;
}
--- NEW FILE: generate_collect_optional.cpp ---
// Copyright (C) 2006 Douglas Gregor <[EMAIL PROTECTED]>
// 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)
// An example using Boost.MPI's split() operation on communicators to
// create separate data-generating processes and data-collecting
// processes using boost::optional for broadcasting.
#include <boost/parallel/mpi.hpp>
#include <iostream>
#include <cstdlib>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/optional.hpp>
namespace mpi = boost::parallel::mpi;
enum message_tags { msg_data_packet, msg_finished };
void generate_data(mpi::communicator local, mpi::communicator world)
{
using std::srand;
using std::rand;
// The rank of the collector within the world communicator
int master_collector = local.size();
srand(time(0) + world.rank());
// Send out several blocks of random data to the collectors.
int num_data_blocks = rand() % 3 + 1;
for (int block = 0; block < num_data_blocks; ++block) {
// Generate some random dataa
int num_samples = rand() % 1000;
std::vector<int> data;
for (int i = 0; i < num_samples; ++i) {
data.push_back(rand());
}
// Send our data to the master collector process.
std::cout << "Generator #" << local.rank() << " sends some data..."
<< std::endl;
world.send(master_collector, msg_data_packet, data);
}
// Wait for all of the generators to complete
(local.barrier)();
// The first generator will send the message to the master collector
// indicating that we're done.
if (local.rank() == 0)
world.send(master_collector, msg_finished);
}
void collect_data(mpi::communicator local, mpi::communicator world)
{
// The rank of the collector within the world communicator
int master_collector = world.size() - local.size();
if (world.rank() == master_collector) {
while (true) {
// Wait for a message
mpi::status msg = world.probe();
if (msg.tag() == msg_data_packet) {
// Receive the packet of data into a boost::optional
boost::optional<std::vector<int> > data;
data = std::vector<int>();
world.recv(msg.source(), msg.source(), *data);
// Broadcast the actual data.
broadcast(local, data, 0);
} else if (msg.tag() == msg_finished) {
// Receive the message
world.recv(msg.source(), msg.tag());
// Broadcast to each collector to tell them we've finished.
boost::optional<std::vector<int> > data;
broadcast(local, data, 0);
break;
}
}
} else {
boost::optional<std::vector<int> > data;
do {
// Wait for a broadcast from the master collector
broadcast(local, data, 0);
if (data) {
std::cout << "Collector #" << local.rank()
<< " is processing data." << std::endl;
}
} while (data);
}
}
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
if (world.size() < 4) {
if (world.rank() == 0) {
std::cerr << "Error: this example requires at least 4 processes."
<< std::endl;
}
env.abort(-1);
}
bool is_generator = world.rank() < 2 * world.size() / 3;
mpi::communicator local = world.split(is_generator? 0 : 1);
if (is_generator) generate_data(local, world);
else collect_data(local, world);
return 0;
}
--- NEW FILE: hello_world.cpp ---
// Copyright (C) 2006 Douglas Gregor <[EMAIL PROTECTED]>
// 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 simple Hello, world! example using Boost.MPI message passing.
#include <boost/parallel/mpi.hpp>
#include <iostream>
#include <boost/serialization/string.hpp> // Needed to send/receive strings!
namespace mpi = boost::parallel::mpi;
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
if (world.rank() == 0) {
world.send(1, 0, std::string("Hello"));
std::string msg;
world.recv(1, 1, msg);
std::cout << msg << "!" << std::endl;
} else {
std::string msg;
world.recv(0, 0, msg);
std::cout << msg << ", ";
std::cout.flush();
world.send(0, 1, std::string("world"));
}
return 0;
}
--- NEW FILE: hello_world_broadcast.cpp ---
// Copyright (C) 2006 Douglas Gregor <[EMAIL PROTECTED]>
// 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 simple Hello, world! example using Boost.MPI broadcast()
#include <boost/parallel/mpi.hpp>
#include <iostream>
#include <boost/serialization/string.hpp> // Needed to send/receive strings!
namespace mpi = boost::parallel::mpi;
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
std::string value;
if (world.rank() == 0) {
value = "Hello, World!";
}
broadcast(world, value, 0);
std::cout << "Process #" << world.rank() << " says " << value << std::endl;
return 0;
}
--- NEW FILE: hello_world_nonblocking.cpp ---
// Copyright (C) 2006 Douglas Gregor <[EMAIL PROTECTED]>
// 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 simple Hello, world! example using Boost.MPI message passing.
#include <boost/parallel/mpi.hpp>
#include <iostream>
#include <boost/serialization/string.hpp> // Needed to send/receive strings!
namespace mpi = boost::parallel::mpi;
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
if (world.rank() == 0) {
mpi::request reqs[2];
std::string msg, out_msg = "Hello";
reqs[0] = world.isend(1, 0, out_msg);
reqs[1] = world.irecv(1, 1, msg);
mpi::wait_all(reqs, reqs + 2);
std::cout << msg << "!" << std::endl;
} else {
mpi::request reqs[2];
std::string msg, out_msg = "world";
reqs[0] = world.isend(0, 1, out_msg);
reqs[1] = world.irecv(0, 0, msg);
mpi::wait_all(reqs, reqs + 2);
std::cout << msg << ", ";
}
return 0;
}
--- NEW FILE: parallel_example.cpp ---
// Copyright (C) 2005-2006 Matthias Troyer
// 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)
// An example of a parallel Monte Carlo simulation using some nodes to produce
// data and others to aggregate the data
#include <iostream>
#include <boost/parallel/mpi.hpp>
#include <boost/random/parallel.hpp>
#include <boost/random.hpp>
#include <boost/foreach.hpp>
#include <iostream>
#include <cstdlib>
namespace mpi = boost::parallel::mpi;
enum {sample_tag, sample_skeleton_tag, sample_broadcast_tag, quit_tag};
void calculate_samples(int sample_length)
{
int num_samples = 100;
std::vector<double> sample(sample_length);
// setup communicator by splitting
mpi::communicator world;
mpi::communicator calculate_communicator = world.split(0);
unsigned int num_calculate_ranks = calculate_communicator.size();
// the master of the accumulaion ranks is the first of them, hence
// with a rank just one after the last calculation rank
int master_accumulate_rank = num_calculate_ranks;
// the master of the calculation ranks sends the skeleton of the sample
// to the master of the accumulation ranks
if (world.rank()==0)
world.send(master_accumulate_rank,sample_skeleton_tag,mpi::skeleton(sample));
// next we extract the content of the sample vector, to be used in sending
// the content later on
mpi::content sample_content = mpi::get_content(sample);
// now intialize the parallel random number generator
boost::lcg64 engine(
boost::random::stream_number = calculate_communicator.rank(),
boost::random::total_streams = calculate_communicator.size()
);
boost::variate_generator<boost::lcg64&,boost::uniform_real<> >
rng(engine,boost::uniform_real<>());
for (unsigned int i=0; i<num_samples/num_calculate_ranks+1;++i) {
// calculate sample by filling the vector with random numbers
// note that std::generate will not work since it takes the generator
// by value, and boost::ref cannot be used as a generator.
// boost::ref should be fixed so that it can be used as generator
BOOST_FOREACH(double& x, sample)
x = rng();
// send sample to accumulation ranks
// Ideally we want to do this as a broadcast with an inter-communicator
// between the calculation and accumulation ranks. MPI2 should support
// this, but here we present an MPI1 compatible solution.
// send content of sample to first (master) accumulation process
world.send(master_accumulate_rank,sample_tag,sample_content);
// gather some results from all calculation ranks
double local_result = sample[0];
std::vector<double> gathered_results(calculate_communicator.size());
mpi::all_gather(calculate_communicator,local_result,gathered_results);
}
// we are done: the master tells the accumulation ranks to quit
if (world.rank()==0)
world.send(master_accumulate_rank,quit_tag);
}
void accumulate_samples()
{
std::vector<double> sample;
// setup the communicator for all accumulation ranks by splitting
mpi::communicator world;
mpi::communicator accumulate_communicator = world.split(1);
bool is_master_accumulate_rank = accumulate_communicator.rank()==0;
// the master receives the sample skeleton
if (is_master_accumulate_rank)
world.recv(0,sample_skeleton_tag,mpi::skeleton(sample));
// and broadcasts it to all accumulation ranks
mpi::broadcast(accumulate_communicator,mpi::skeleton(sample),0);
// next we extract the content of the sample vector, to be used in receiving
// the content later on
mpi::content sample_content = mpi::get_content(sample);
// accumulate until quit is called
double sum=0.;
while (true) {
// the accumulation master checks whether we should quit
if (world.iprobe(0,quit_tag)) {
world.recv(0,quit_tag);
for (int i=1; i<accumulate_communicator.size();++i)
accumulate_communicator.send(i,quit_tag);
std::cout << sum << "\n";
break; // We're done
}
// the otehr accumulation ranks check whether we should quit
if (accumulate_communicator.iprobe(0,quit_tag)) {
accumulate_communicator.recv(0,quit_tag);
std::cout << sum << "\n";
break; // We're done
}
// check whether the master accumulation rank has received a sample
if (world.iprobe(mpi::any_source,sample_tag)) {
BOOST_ASSERT(is_master_accumulate_rank);
// receive the content
world.recv(mpi::any_source,sample_tag,sample_content);
// now we need to braodcast
// the problam is we do not have a non-blocking broadcast that we could
// abort if we receive a quit message from the master. We thus need to
// first tell all accumulation ranks to start a broadcast. If the sample
// is small, we could just send the sample in this message, but here we
// optimize the code for large samples, so that the overhead of these
// sends can be ignored, and we count on an optimized broadcast
// implementation with O(log N) complexity
for (int i=1; i<accumulate_communicator.size();++i)
accumulate_communicator.send(i,sample_broadcast_tag);
// now broadcast the contents of the sample to all accumulate ranks
mpi::broadcast(accumulate_communicator,sample_content,0);
// and handle the sample by summing the appropriate value
sum += sample[0];
}
// the other accumulation ranks wait for a mesage to start the broadcast
if (accumulate_communicator.iprobe(0,sample_broadcast_tag)) {
BOOST_ASSERT(!is_master_accumulate_rank);
accumulate_communicator.recv(0,sample_broadcast_tag);
// receive broadcast of the sample contents
mpi::broadcast(accumulate_communicator,sample_content,0);
// and handle the sample
// and handle the sample by summing the appropriate value
sum += sample[accumulate_communicator.rank()];
}
}
}
int main(int argc, char** argv)
{
mpi::environment env(argc, argv);
mpi::communicator world;
// half of the processes generate, the others accumulate
// the sample size is just the number of accumulation ranks
if (world.rank() < world.size()/2)
calculate_samples(world.size()-world.size()/2);
else
accumulate_samples();
return 0;
}
--- NEW FILE: random_content.cpp ---
// Copyright (C) 2006 Douglas Gregor <[EMAIL PROTECTED]>
// 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)
// An example using Boost.MPI's skeletons and content to optimize
// communication.
#include <boost/parallel/mpi.hpp>
#include <boost/serialization/list.hpp>
#include <algorithm>
#include <functional>
#include <numeric>
#include <iostream>
#include <stdlib.h>
namespace mpi = boost::parallel::mpi;
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
if (world.size() < 2 || world.size() > 4) {
if (world.rank() == 0)
std::cerr << "error: please execute this program with 2-4 processes.\n";
world.abort(-1);
}
if (world.rank() == 0) {
int list_len = 50;
int iterations = 10;
if (argc > 1) list_len = atoi(argv[1]);
if (argc > 2) iterations = atoi(argv[2]);
if (list_len <= 0) {
std::cerr << "error: please specific a list length greater than zero.\n";
world.abort(-1);
}
// Generate the list and broadcast its structure
std::list<int> l(list_len);
broadcast(world, mpi::skeleton(l), 0);
// Generate content several times and broadcast out that content
mpi::content c = mpi::get_content(l);
for (int i = 0; i < iterations; ++i) {
do {
std::generate(l.begin(), l.end(), &random);
} while (std::find_if(l.begin(), l.end(),
std::bind1st(std::not_equal_to<int>(), 0))
== l.end());
std::cout << "Iteration #" << i << ": sending content"
<< " (min = " << *std::min_element(l.begin(), l.end())
<< ", max = " << *std::max_element(l.begin(), l.end())
<< ", avg = "
<< std::accumulate(l.begin(), l.end(), 0)/l.size()
<< ").\n";
broadcast(world, c, 0);
}
// Notify the slaves that we're done by sending all zeroes
std::fill(l.begin(), l.end(), 0);
broadcast(world, c, 0);
} else {
// Receive the content and build up our own list
std::list<int> l;
broadcast(world, mpi::skeleton(l), 0);
mpi::content c = mpi::get_content(l);
int i = 0;
do {
broadcast(world, c, 0);
if (std::find_if(l.begin(), l.end(),
std::bind1st(std::not_equal_to<int>(), 0)) == l.end())
break;
if (world.rank() == 1)
std::cout << "Iteration #" << i << ": max value = "
<< *std::max_element(l.begin(), l.end()) << ".\n";
else if (world.rank() == 2)
std::cout << "Iteration #" << i << ": min value = "
<< *std::min_element(l.begin(), l.end()) << ".\n";
else if (world.rank() == 3)
std::cout << "Iteration #" << i << ": avg value = "
<< std::accumulate(l.begin(), l.end(), 0)/l.size()
<< ".\n";
++i;
} while (true);
}
return 0;
}
--- NEW FILE: random_gather.cpp ---
// Copyright (C) 2006 Douglas Gregor <[EMAIL PROTECTED]>
// 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)
// An example using Boost.MPI's gather()
#include <boost/parallel/mpi.hpp>
#include <iostream>
#include <cstdlib>
namespace mpi = boost::parallel::mpi;
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
std::srand(time(0) + world.rank());
int my_number = std::rand();
if (world.rank() == 0) {
std::vector<int> all_numbers;
gather(world, my_number, all_numbers, 0);
for (int proc = 0; proc < world.size(); ++proc)
std::cout << "Process #" << proc << " thought of " << all_numbers[proc]
<< std::endl;
} else {
gather(world, my_number, 0);
}
return 0;
}
--- NEW FILE: random_min.cpp ---
// Copyright (C) 2006 Douglas Gregor <[EMAIL PROTECTED]>
// 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)
// An example using Boost.MPI's reduce() to compute a minimum value.
#include <boost/parallel/mpi.hpp>
#include <iostream>
#include <cstdlib>
namespace mpi = boost::parallel::mpi;
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
std::srand(time(0) + world.rank());
int my_number = std::rand();
if (world.rank() == 0) {
int minimum;
reduce(world, my_number, minimum, mpi::minimum<int>(), 0);
std::cout << "The minimum value is " << minimum << std::endl;
} else {
reduce(world, my_number, mpi::minimum<int>(), 0);
}
return 0;
}
--- NEW FILE: reduce_performance_test.cpp ---
// Copyright (C) 2006 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)
// Performance test of the reduce() collective
#include <boost/parallel/mpi.hpp>
#include <boost/lexical_cast.hpp>
namespace mpi = boost::parallel::mpi;
struct add_int {
int operator()(int x, int y) const { return x + y; }
};
struct wrapped_int
{
wrapped_int() : value(0) { }
wrapped_int(int value) : value(value) { }
template<typename Archiver>
void serialize(Archiver& ar, const unsigned int /*version*/) {
ar & value;
}
int value;
};
inline wrapped_int operator+(wrapped_int x, wrapped_int y)
{
return wrapped_int(x.value + y.value);
}
namespace boost { namespace parallel { namespace mpi {
template<> struct is_mpi_datatype<wrapped_int> : mpl::true_ { };
} } }
struct serialized_int
{
serialized_int() : value(0) { }
serialized_int(int value) : value(value) { }
template<typename Archiver>
void serialize(Archiver& ar, const unsigned int /*version*/) {
ar & value;
}
int value;
};
inline serialized_int operator+(serialized_int x, serialized_int y)
{
return serialized_int(x.value + y.value);
}
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
int repeat_count = 100;
int outer_repeat_count = 2;
if (argc > 1) repeat_count = boost::lexical_cast<int>(argv[1]);
if (argc > 2) outer_repeat_count = boost::lexical_cast<int>(argv[2]);
if (world.rank() == 0)
std::cout << "# of processors: " << world.size() << std::endl
<< "# of iterations: " << repeat_count << std::endl;
int value = world.rank();
int result;
wrapped_int wi_value = world.rank();
wrapped_int wi_result;
serialized_int si_value = world.rank();
serialized_int si_result;
// Spin for a while...
for (int i = 0; i < repeat_count/10; ++i) {
reduce(world, value, result, std::plus<int>(), 0);
reduce(world, value, result, add_int(), 0);
reduce(world, wi_value, wi_result, std::plus<wrapped_int>(), 0);
reduce(world, si_value, si_result, std::plus<serialized_int>(), 0);
}
for (int outer = 0; outer < outer_repeat_count; ++outer) {
// Raw MPI
mpi::timer time;
for (int i = 0; i < repeat_count; ++i) {
MPI_Reduce(&value, &result, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
}
double reduce_raw_mpi_total_time = time.elapsed();
// MPI_INT/MPI_SUM case
time.restart();
for (int i = 0; i < repeat_count; ++i) {
reduce(world, value, result, std::plus<int>(), 0);
}
double reduce_int_sum_total_time = time.elapsed();
// MPI_INT/MPI_Op case
time.restart();
for (int i = 0; i < repeat_count; ++i) {
reduce(world, value, result, add_int(), 0);
}
double reduce_int_op_total_time = time.elapsed();
// MPI_Datatype/MPI_Op case
time.restart();
for (int i = 0; i < repeat_count; ++i) {
reduce(world, wi_value, wi_result, std::plus<wrapped_int>(), 0);
}
double reduce_type_op_total_time = time.elapsed();
// Serialized/MPI_Op case
time.restart();
for (int i = 0; i < repeat_count; ++i) {
reduce(world, si_value, si_result, std::plus<serialized_int>(), 0);
}
double reduce_ser_op_total_time = time.elapsed();
if (world.rank() == 0)
std::cout << "\nInvocation\tElapsed Time (seconds)"
<< "\nRaw MPI\t\t\t" << reduce_raw_mpi_total_time
<< "\nMPI_INT/MPI_SUM\t\t" << reduce_int_sum_total_time
<< "\nMPI_INT/MPI_Op\t\t" << reduce_int_op_total_time
<< "\nMPI_Datatype/MPI_Op\t" << reduce_type_op_total_time
<< "\nSerialized/MPI_Op\t" << reduce_ser_op_total_time
<< std::endl;
}
return 0;
}
--- NEW FILE: string_cat.cpp ---
// Copyright (C) 2006 Douglas Gregor <[EMAIL PROTECTED]>
// 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)
// An example using Boost.MPI's reduce() to concatenate strings.
#include <boost/parallel/mpi.hpp>
#include <iostream>
#include <string>
#include <boost/serialization/string.hpp> // Important for sending strings!
namespace mpi = boost::parallel::mpi;
/* Defining STRING_CONCAT_COMMUTATIVE lies to Boost.MPI by forcing it
* to assume that string concatenation is commutative, which it is
* not. However, doing so illustrates how the results of a reduction
* can change when a non-commutative operator is assumed to be
* commutative.
*/
#ifdef STRING_CONCAT_COMMUTATIVE
namespace boost { namespace parallel { namespace mpi {
template<>
struct is_commutative<std::plus<std::string>, std::string> : mpl::true_ { };
} } } // end namespace boost::parallel::mpi
#endif
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
std::string names[10] = { "zero ", "one ", "two ", "three ", "four ",
"five ", "six ", "seven ", "eight ", "nine " };
std::string result;
reduce(world,
world.rank() < 10? names[world.rank()] : std::string("many "),
result, std::plus<std::string>(), 0);
if (world.rank() == 0)
std::cout << "The result is " << result << std::endl;
return 0;
}
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Boost-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/boost-cvs