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

Reply via email to