初投稿です.
前回,前々回と,Raspberry PiにOpenFOAMを導入する方法について書きました.
今回はいよいよ,Raspberry PIで4ノード並列計算を実現していこうと思います.
環境は前回と変わりません.
マシン:Raspberry Pi 4B 8GB × 4機
OS:Raspberry Pi OS (64bit) 2023-02-21
クライアント:MobaXterm Portable v23.0
クラスタリングの設定を行う流れ的には,こちらに書かれている方法が分かりやすかったです.一方で,本サイトで紹介されている方法を辿るだけだとOpenFOAMでの並列計算は上手くいかないため,そのあたりの方法も交えながら記載していきます.
MPI環境構築
既にマシンの構築は終わっているものとして話を進めます.
以下の手順を,クラスタを組むラズパイ各機に対して行っていってください.
ライブラリの導入
まず最初に,MPI関係に必要なライブラリ群を導入します.
sudo apt-get update
sudo apt upgrade
sudo apt install build-essential manpages-dev gfortran nfs-common nfs-kernel-server vim openmpi-bin libopenmpi-dev openmpi-doc keychain nmap
同時に,OpenFOAMの環境構築も,前回の記事を基に行います.
ネットワークの設定
クラスタを組むにあたって必要なネットワーク設定をラズパイ上で行います.基本的には分かりやすいようにホスト名を設定し,IPを固定する作業です.これらの方法はググればめちゃくちゃ出てきますので端折りますが,次のように設定していけばいい感じです.
interface wlan0
static ip_address=[固定したいIPアドレス]/24
static routers=[デフォルトゲートウェイのIPアドレス]
static domain_name_servers=[DNSサーバのIPアドレス]
interface eth0
static ip_address=[固定したいIPアドレス]/24
static routers=[デフォルトゲートウェイのIPアドレス]
static domain_name_servers=[DNSサーバのIPアドレス]
#127.0.1.1 rpi01
192.168.1.101 rpi01
192.168.1.102 rpi02
192.168.1.103 rpi03
192.168.1.104 rpi04
認証鍵の設定
マスターノード(ここではrpi01)上で,次のコマンドからSSH認証鍵を作成します.この時に,認証鍵を保存するディレクトリはデフォルトで良いか,認証鍵のパスフレーズを何にするか聞いてきますので,それぞれ設定してください.
ssh-keygen -t rsa
認証鍵を作成したら,その鍵をスレーブノードに送信します.今回はrpi02に送ります.途中で送信を続けていいか,スレーブノードのパスワード(鍵のパスフレーズではない)を聞いてきますので,入力していきます.
ssh-copy-id ユーザ名@rpi02
転送が出来たら,ssh rpi02
でマスターノード(rpi01)から接続・操作が出来るようになります.ここで認証鍵のパスフレーズを聞かれますので入力します.
ssh rpi02
基本的にはこのSSH認証鍵を使って,ノード間通信を行い,並列計算を実現することになります.一方で,この状態でMPIによる計算を始めてしまうと,全ノード分のパスフレーズをいちいち入力する必要が生じてしまい,非常に煩雑です.そこで,~/.bashrc
に以下の通り追記してください.
# Logic for Keychain
/usr/bin/keychain $HOME/.ssh/id_rsa
source $HOME/.keychain/$HOSTNAME-sh
追記したら,,source .bashrc
を実行してください.その時に,またパスフレーズを聞かれますので入力します.これを行う事で,以降は逐一パスフレーズを入力しなくて済むようになります.
共有ディレクトリの作成
ノード間での並列計算を行うにあたって,同一ディレクトリ上で作業できる仕組みが必要です.そこで,/working_MPI
というフォルダを各ノードに作り,各スレーブノードからマスターノードにマウントできるようにします.
まずマスターノードから以下の操作を行います.
sudo mkdir /working_MPI
sudo chown ユーザ名:ユーザ名 /working_MPI
スレーブノードから/working_MPI
フォルダを操作するためには,対象のIPアドレスに対して,読み込み・書き込みの権限(rw)を与える必要があります.sudo nano /etc/exports
から,以下の一文を追記してください.
/working_MPI 192.168.1.0/24(rw,sync)
書き換え次第,NFSサーバの再起動を行い,以上の設定を適用します.
sudo service nfs-kernel-server restart
OS起動時に自動実行する内容を記述する/etc/rc.local
のexit 0
の前に,以上の一文を入れておくと,次回起動時から自動で適用されるようになります.
続けて,スレーブノード側で以下の操作を行うと,マスターノードの/working_MPI
がマウントされ,中身が共有できるようになります.
sudo mkdir /working_MPI
sudo chown ユーザ名:ユーザ名 /working_MPI
sudo mount rpi01:/working_MPI /working_MPI
実際に共有できているかは,'touch'コマンド等使って確認すると良いでしょう.
また,スレーブノード側では,次回起動時にも自動でマウントされるように設定を行っておきましょう.まず,ファイルのマウントに関する記述を行う/etc/fstab
に次の一文を追加します.
ユーザ名:/working_MPI /working_MPI nfs noauto,x-systemd.automount,rw,exec 0 0
続いて,マスターノード起動後にマウントを確実に実行できるよう,マウントするタイミングを5秒遅らせる設定を/etc/rc.local
のexit 0
の前に記述します.
sleep 5
mount -a
これでMPIを実行する環境は出来ました.ここまででの導入結果のチェックをされたい場合は,先ほど紹介したページや,或いはラズパイスパコンの参考書付属のコードでチェックしてみてください.
OpenFOAMにおけるMPI環境の構築
いよいよここから,OpenFOAM実行時に必要な環境構築について紹介します.この辺りは明確に方法を示してくださっていたサイトが無く,かなり手探りだったので,同様に試みている方々の参考になればと思います.
実は以上までの段階で,さぁ早速OpenFOAMでノード間計算だ~とtime mpirun --hostfile machines -np 16 pimpleFoam -parallel
とか実行すると以下のエラーが出ます.
--------------------------------------------------------------------------
mpirun was unable to find the specified executable file, and therefore
did not launch the job. This error was first reported for process
rank 4; it may have occurred for other processes as well.
NOTE: A common cause for this error is misspelling a mpirun command
line parameter option (remember that mpirun interprets the first
unrecognized command line token as the executable).
Node: rpi02
Executable: /home/user_name/OpenFOAM/OpenFOAM-v2006/platforms/linuxARM64GccDPInt32Opt/bin/pimpleFoam
--------------------------------------------------------------------------
pimpleFoamが見つかんね-よ!ってことなんですが,rpi02を覗くと普通にあるんですよね.rpi02上のみでpimpleFoam
を実行する分には普通に計算が進みますので,インストールに問題があったとも思えません.
その原因は,SSH接続時の環境変数にありました.
まずマスターノード側(rpi01)で,環境変数の一覧をenv
から取得すると,普通にOpenFOAM関係の環境変数が確認できます.
CGAL_ARCH_PATH=/home/user_name/OpenFOAM/ThirdParty-v2006/platforms/linuxARM64Gcc/CGAL-4.12.2
FOAM_MPI=openmpi-system
WM_PROJECT_USER_DIR=/home/user_name/OpenFOAM/user_name-v2006
FOAM_RUN=/home/user_name/OpenFOAM/user_name-v2006/run
FOAM_EXT_LIBBIN=/home/user_name/OpenFOAM/ThirdParty-v2006/platforms/linuxARM64GccDPInt32/lib
FFTW_ARCH_PATH=/home/user_name/OpenFOAM/ThirdParty-v2006/platforms/linuxARM64Gcc/fftw-3.3.7
FOAM_TUTORIALS=/home/user_name/OpenFOAM/OpenFOAM-v2006/tutorials
WM_PROJECT=……(以下略)
これは,スレーブノード側(rpi02)でもenv
を打っても全く同じです.
一方で,マスターノード(rpi01)からスレーブノードにSSH接続し,環境変数を確認(ssh rpi02 env
)してみると,これらの環境変数が確認出来ないのです.すなわち,スレーブノードで環境変数が設定済みでも,SSH接続でマスターノード側から除くと,その環境変数は存在しないことになってしまうのです.
この対策として,マスターノードからSSHでつなぐとき,環境変数も同時に渡してやるように設定してやります.
環境変数の引き継ぎ設定
まずスレーブノード側では,環境変数の受け入れ許可を行います.
/etc/ssh/sshd_config
を開き,PermitUserEnvironment
を許可するように書き換えてください.
#PermitUserEnvironment no
PermitUserEnvironment yes
また,同一ファイル上の末尾に以下の文を追加します.これで,スレーブノード側でOpenFOAM関連の環境変数受け入れが可能になります.
AcceptEnv FOAM_APP FOAM_EXT_LIBBIN FOAM_SRC FOAM_LIBBIN FOAM_MPI FOAM_SOLVERS FOAM_USER_APPBIN FOAM_APPBIN FOAM_INST_DIR FOAM_USER_LIBBIN FOAM_ETC FOAM_LIBBIN FOAM_TUTORIALS FOAM_UTILITIES FOAM_*
以上の設定が終わったら,sudo service sshd restart
で設定を適用します.
続けて,マスターノード側の設定です.$HOME/.ssh/config
を作成し,以下のように記述してください.
Host *
SendEnv FOAM_APP FOAM_EXT_LIBBIN FOAM_SRC FOAM_LIBBIN FOAM_MPI FOAM_SOLVERS FOAM_USER_APPBIN FOAM_APPBIN FOAM_INST_DIR FOAM_USER_LIBBIN FOAM_ETC FOAM_LIBBIN FOAM_TUTORIALS FOAM_UTILITIES
これでマスターノード側から送信する環境変数を設定できました.
最後に,マスターノード・スレーブノード全てで,$HOME/.bashrc
の編集を行います.まず最初,.bashrcの冒頭付近のcase文をコメントアウトします.環境変数を読まない原因として,SSH接続時にこのcase文を抜けてしまい,それ以降のコードを読まないことが理由にあるそうです.
# If not running interactively, don't do anything
#case $- in
# *i*) ;;
# *) return;;
#esac
同じ.bashrc上,末尾に以下の一文を足します.
#OpenFOAM
. ~/OpenFOAM/OpenFOAM-v2006/etc/bashrc
最後にsource .bashrc
を行えば,環境変数の問題はクリアできるかと思います.
実際にMPI実行するときは
MPI実行の前準備として,decomposeParDictを設定してやり,decomposePar
を実行して計算領域を分割します.このへんの話はこちらをご参照ください.
decomposePar
を実行したら以下のコマンドで計算を開始できます.見れば分かる通りなのですが,計算ノードの名前を使うコア数分だけ並べていき,合計のコア数を-np
で記述,最後に並列計算であることを示す-parallel
を書きます.
mpirun -H rpi01,rpi01,rpi01,rpi01,rpi02,rpi02,rpi02,rpi02,rpi03,rpi03,rpi03,rpi03,rpi03,rpi04,rpi04,rpi04,rpi04 -np 16 pimpleFoam -parallel
いちいちホスト名を列挙するのは煩雑なので,ケースディレクトリ内にそこに使用ノードと使用コア数を記載したmachines
を作ってから呼び出す方法もあります.
rpi01 cpu=4
rpi02 cpu=4
rpi03 cpu=4
rpi04 cpu=4
mpirun --hostfile machines -np 16 pimpleFoam -parallel
緒言
本記事では,Raspberry Pi 4Bによるクラスタ設定から,OpenFOAMによるMPI実行までの操作について説明しました.ちなみにLESによる壁乱流チュートリアルであるchannel395での計算時間を以下に示します.
real | user | sys | |
---|---|---|---|
1node 4core | 81m0.468s | 299m7.207s | 11m18.900s |
2node 8core | 66m47.498s | 156m13.197s | 101m37.000s |
4node 8core | 34m59.999s | 43m57.109s | 25m43.479s |
4node 16core | 56m26.276s | 102m42.795s | 116m28.655s |
(参考) Ryzen7 3700X 8core | 4m33.570s | 20m35.703s | 0m45.188s |
意外にも4node 16coreよりも4node 8coreの方が計算時間が早かったです.思いつく原因としては,ラズパイに用いているUSBの転送速度があまり早いものではない(50MB/s前後)ので,そこがボトルネックになってしまっているかなぁと思ったりしています.一方で,2node 8coreと比較すると計算時間がかなり短縮されているので,その点ではノード間計算による効果は出ている形です.
「MPIで数値計算」っていうと富岳やら不老やらAWSやら出てくるイメージもあり,なんとなくハードルも高い気がしますが,Raspberry PIであれば低コスト・コンパクトであり,スーパーコンピュータの仕組みや実装を自宅の机上で体験できるのは非常にいい点です.幸い,日本国内で稼働するスパコンは殆どLinuxで稼働していますし,ここで勉強した知識が,いつか本当にスパコンを触る時に生きるかもしれませんから,興味のあるうちにこうしたモノで慣れておくというのも良いのかもしれません.
引用一覧
https://note.com/rasen/n/n57dd963a7a40/ (RaspberryPiですぱこん!その②(いよいよクラスター化!))
https://note.com/rasen/n/n793feb3d6424 (RaspberryPiですぱこん!その① (1台でもスーパー!))
https://nissy-lab.com/blogs/inherit-env-variables-over-ssh/ (SSH接続で環境変数を引き継ぎたい | にっしーラボ)
https://www.cfd-online.com/Forums/openfoam-solving/62627-parallel-runs-across-network-broken-openmpi-ssh-issue-no-bashrc.html (Parallel runs across a network broken with OpenMPI)
https://ss1.xrea.com/penguinitis.g1.xrea.com/study/OpenFOAM/partition/partition.html (領域分割 - PENGUINITIS)