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

Mac で Boost.MPI を動かしてみた

Boost.MPI をインストールする

Boost.MPI はデフォルトでインストールされないので Boost をインストールする際に追加でいれる必要があります.Linux 等の環境で Boost.MPI をインストールする方法は他の方々にまかせるとして,Mac で port を使ってインストールするには以下のようになります.

$ sudo port install boost +openmpi

ただし,上記の方法でインストールした場合,MPI のコンパイラ等の名前が変化します.

  • mpiCC → openmpiCC
  • mpic++ → openmpic++
  • mpicxx → openmpicxx
  • mpirun → openmpirun
  • etc.

Boost.MPI のコンパイル方法と実行方法

Boost.MPI は OpenMPI のコンパイラ等でコンパイルや実行が可能となっています.ただし,Boost.MPI を使用する場合はコンパイルオプションに -lboost_mpi が必要となります.

普通にコンパイルする場合
$ openmpicxx hoge.cpp -lboost_mpi
  • 1台のマシン内で2つのランクを生成する実行例
$ openmpirun -np 2 ./a.out
任意のコンパイラを使用する場合

特に設定を変更していない場合,Apple clang2.1 が openmpicxx のベースコンパイラとなってしまいます.gcc4.7 などを使用してコンパイルする場合は以下のようにします.

$ g++-mp-4.7 main.cpp -lboost_mpi $(openmpicxx -showme:link) $(openmpicxx -showme:compile)

ベクトル同士の加算の例

/*--------------------
  boost_vec_add.cpp
  --------------------*/

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

template<class T>
void mpi_vec_add(boost::mpi::communicator const& world, 
                 std::size_t const n, T* z, T const* x, T const* y){
  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){
    len = n / world.size();
    end = n;
  }

  for(std::size_t i=beg; i<end; ++i) 
    z[i] = x[i] + y[i];

  gather(world, z+beg, len, z+beg, 0);
  //MPI_Gather(z+beg, len, MPI_DOUBLE,
  //           z+beg, len, MPI_DOUBLE, 0, MPI_COMM_WORLD);
}

int main(int argc, char** argv){
  std::size_t const n = 11;
  auto x = reinterpret_cast<double*>( malloc(sizeof(double) * n) );
  auto y = reinterpret_cast<double*>( malloc(sizeof(double) * n) );
  auto z = reinterpret_cast<double*>( malloc(sizeof(double) * n) );

  boost::mpi::environment env(argc, argv);//MPI_Init(&argc, &argv)
  boost::mpi::communicator world;//MPI_Comm_rank(MPI_COMM_WORLD, &my_rank) と MPI_Comm_size(MPI_COMM_WORLD, &all_rank);

  for(std::size_t i=0; i<n; ++i) x[i] = i;
  for(std::size_t i=0; i<n; ++i) y[i] = i;

  mpi_vec_add(world, n, z, x, y);

  if(world.rank() == 0){
    for(std::size_t i=0; i<n; ++i)
      std::cout << z[i] << std::endl;
  }

  free(x);
  free(y);
  free(z);

  //MPI_Finalize(); 不要

  return 0;
}

MPI_Gather の場合では MPI_Float や MPI_Double で通信する精度を指定する必要があったため,Traits などを自分で行う必要がありましたが,Boost.MPI では通信する精度を気にすること無くプログラムを書くことができます.また,std::vector の通信もサポートしているらしいです.

ちなみに,Boost.MPI の詳細はこちらとか → Chapter 17. Boost.MPI - 1.49.0