読者です 読者をやめる 読者になる 読者になる

Boost.MPI を使って総和を計算

MPI を使って総和を計算

MPI を使って総和などを計算する場合,MPI_Reduce を使って各計算機の計算結果を足し合わせる作業が必要となります.MPI_Reduce の使い方は以下のような感じです.

MPI_Reduce(void* sendbuf, void* recvbuf, int count, 
            MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm )

MPI_Op には MPI_SUM や MPI_MAX が該当します.
MPI_Reduce の詳細な説明はコチラなどを参考にしてください → MPI_Reduce(3) man page (version 1.5.5)


MPI_Reduce を使って総和を求める場合のソースコードは以下のような感じになると思います.

double vec_sum(std::size_t const n, T const* x){
  T tmp = 0, sum;
  std::size_t len = (n + world.size() - 1) / world.size();
  std::size_t const beg = len * world.rank();
  std::size_t end = beg + len;
  if(world.rank() == world.size() - 1)
    end = n;
  
  for(std::size_t i=beg; i<end; ++i)
    tmp += x[i];
  MPI_Reduce(&tmp, &sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);

  return sum;
}

上記のソースコードの場合,sendbuf と recvbuf の先頭アドレスは別のメモリ空間にしなければならないことに注意してください.

Boost.MPI の Reduce

Boost.MPI を使用する場合は MPI_Reduce() の代わりに reduce() を使用することが可能です.
reduce() の使用方法はコチラ → Function reduce - 1.49.0

reduce を使用する場合は Op に MPI_SUM や MPI_MAX を使用することができません.MPI_SUM を使用したければ代わりに,std::plus() を渡すことで計算できるようです(便利ですね).Boost.MPI を使用する場合の総和計算のソースコードを以下に記載します.

/*--------------------
  reduce.cpp
  --------------------*/

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <numeric>
#include <boost/mpi/environment.hpp>
#include <boost/mpi/communicator.hpp>
#include <boost/mpi/collectives.hpp>
#include <boost/mpi.hpp>

template<class T>
T vec_sum(boost::mpi::communicator const& world, 
	  std::size_t const n, T const* x){
  T tmp = 0, sum;
  std::size_t len = (n + world.size() - 1) / world.size();
  std::size_t const beg = len * world.rank();
  std::size_t end = beg + len;
  if(world.rank() == world.size() - 1)
    end = n;
  
  for(std::size_t i=beg; i<end; ++i)
    tmp += x[i];
  //MPI_Reduce(&tmp, &sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);//for example
  reduce(world, tmp, sum, std::plus<T>(), 0);

  return sum;
}

int main(int argc, char** argv){
  std::size_t const n = 12;
  boost::mpi::environment env(argc, argv);
  boost::mpi::communicator world;

  auto x = static_cast<double*>( malloc(sizeof(double) * n) );

  for(std::size_t i=0; i<n; ++i) 
    x[i] = static_cast<double>( rand() ) / RAND_MAX;

  std::cout << "Accum = " << std::accumulate(x, x+n, 0.0) << std::endl;

  auto sum = vec_sum(world, n, x);
  if(world.rank() == 0)
    std::cout << "sum = " << sum << std::endl;

  free(x);

  return 0;
}