私の用途としては大量のデータの処理、という方がメインなのでクラスタと言ってもノードをまたぐ並列処理よりもバッチシステムのほうがよく使う。しかしノードをまたぐような大規模解析も時々行うことがあって、これまではスパコンを使ってやっていた。せっかくなので新サーバではMPIも入れてみることにする。
大規模解析としてベイジアンネットワーク解析をするための環境を整える。
まずMPI環境としてopenMPI4.1.0を要求するようなので、それをインストールする。
dnfでも一応インストールできるっぽいが、ここはマニュアルでインストールすることにする。
まずはgccライブラリをインストール
これは全ノードでやる
$ sudo dnf groupinstall "Development Tools" $ sudo dnf install gcc-gfortran
実はhomebrewでgccがインストールされていて、それがここでインストールするライブラリと競合してエラーを出すので一旦homebrewはアンインストールした。(実際今回のシステムではhomebrewでインストールしたプログラムは使っていない)
ヘッドノードにて
$ wget https://download.open-mpi.org/release/open-mpi/v4.1/openmpi-4.1.0.tar.bz2 $ tar xvf openmpi-4.1.0.tar.gz $ cd openmpi-4.1.0 $ ./configure --prefix=/usr/local |& tee config.out ・・・・ $ make -j 8 |& tee make.out ・・・・ $ sudo make install |& tee install.out ・・・・ $ cd $ nano .bashrc ##以下を追記する ##openmpi MPIROOT=/usr/local/package/openmpi/4.1.0 export PATH=$PATH:$MPIROOT/bin export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MPIROOT/lib $ source .bashrc ## インストールの確認 $ which mpic++ /usr/local/package/openmpi/4.1.0/bin/mpic++ $ which mpirun /usr/local/package/openmpi/4.1.0/bin/mpirun
テストプログラムhello.cpp
#include <iostream> #include <mpi.h> #include <stdio.h> int main(int argc, char **argv) { int rank, size; MPI_Init(&argc, &argv); // MPI::Init(argc, argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); // rank = MPI::COMM_WORLD.Get_rank(); // size = MPI::COMM_WORLD.Get_size(); std::cout << "rank = " << rank << std::endl; std::cout << "size = " << size << std::endl; MPI_Finalize(); // MPI::Finalize(); }
ビルドして動かしてみる
$ mpic++ hello.cpp -o hello $ mpirun -np 2 ./hello rank = 0 size = 2 rank = 1 size = 2
- ヘッドノードで公開鍵の設定
ノード間並列処理をするには公開鍵を登録してパスワード無しで計算ノードにアクセスできるようにして置かなければならない。
$ cd .ssh/ $ ssh-keygen #パスワードは空欄のままにする。ここでパスワードを入れると結局パスワードを入力しないとログインできない。 $ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys $ echo "StrictHostKeyChecking no" >> ~/.ssh/config $ chmod 600 ~/.ssh/id_rsa $ chmod 600 ~/.ssh/authorized_keys $ chmod 700 ~/.ssh/ $ chmod 600 ~/.ssh/config ## sshできるかテスト $ ssh k2-inspur-a6
ノード間並列計算テストプログラムhello2.cpp
#include <stdio.h> #include "mpi.h" int main( int argc, char *argv[] ) { int rank, size, len; char name[MPI_MAX_PROCESSOR_NAME]; MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Comm_size( MPI_COMM_WORLD, &size ); MPI_Get_processor_name( name, &len ); name[len] = '\0'; printf( "Hello world: rank %d of %d running on %s\n", rank, size, name ); MPI_Finalize(); return 0; }
$ nano hostfile ## HyperthreadingはMPIでは効率が逆に低下するのでslotsには物理コア数以下を記載する。 k1-inspur-a6 slots=1 k2-inspur-a6 slots=1 k3-inspur-a6 slots=1 $ mpic++ hello2.cpp -o hello2 $ sudo systemctl stop firewalld #ファイアウォールは止めなければならない $ mpirun --hostfile hostfile -n 3 ./hello2 Hello world: rank 0 of 3 running on k1-inspur-a6.klab.kuro.jp Hello world: rank 2 of 3 running on k3-inspur-a6.klab.kuro.jp Hello world: rank 1 of 3 running on k2-inspur-a6.klab.kuro.jp