Fullmoon System

Open MPI構築ガイド:コンパイル・SSH・Slurmと性能検証

EdwardMoon

Open MPIの構築は、全ノードへ同じ実行ファイルをコピーするだけの作業ではありません。コンパイラーとOpen MPIのバージョン、ランタイムライブラリ、ネットワーク転送層、スケジューラーとの連携をそろえ、小さなプログラムから通信性能まで段階的に検証します。

このガイドでは、ディストリビューションのパッケージと公式tarballの選択、ラッパーコンパイラー、スケジューラーを使わないSSH実行、Slurm割り当て内のmpirun、PMIx・PRRTE、CPUバインディング、UCXの確認を運用の観点から説明します。

Open MPI構築の流れ:ラッパーコンパイラー、Slurm割り当て、mpirunとPMIx・PRRTE、計算ノードのMPIランク
ラッパーコンパイラーでビルドし、Slurmの割り当て内でmpirunとPMIx・PRRTEを使って実行します

実行モデルを選ぶ

環境推奨する実行方法必要条件
単一ホストでの開発mpirun -nローカルのライブラリとスロット
スケジューラーのない小規模クラスターmpirun + hostfileSSH、同じパス、host keyの検証
Slurmを使う本番クラスター割り当て内でmpirunSlurm・PMIx連携のビルドとリソース方針

本番のSlurmクラスターでは、独自のhostfileやSSHでスケジューラーを迂回して計算ノードへ接続しないでください。割り当て外で実行すると、CPU・メモリー・GPUの分離やジョブ履歴・リソース使用量の記録が正しく機能しません。

配布パッケージかソースビルドかを選ぶ

ディストリビューションのパッケージは更新と依存関係の管理が容易ですが、バージョンやUCX・PMIxの機能が要件に合わない場合があります。まずパッケージ情報を調べ、不足する場合にのみ公式リリースのtarballを別のprefixへビルドします。GitHubが自動生成したソースアーカイブは、公式リリースtarballの代わりにはなりません。

dnf info openmpi openmpi-devel
rpm -q openmpi openmpi-devel
module avail 2>&1 | grep -i mpi

公式tarballを検証し、別のprefixへビルドする

sha256sum -c openmpi-X.Y.Z.tar.bz2.sha256
tar -xjf openmpi-X.Y.Z.tar.bz2
cd openmpi-X.Y.Z

./configure   --prefix=/opt/openmpi/X.Y.Z   --with-slurm   --with-pmix   --with-ucx
make -j"$(nproc)"
make check
sudo make install

configureの要約で、要求した機能が実際に検出されたか確認します。UCXやPMIxのパスが異なるのに自動検出へ任せると、ノードごとに違うライブラリへリンクする場合があります。本番では同じRPMとしてパッケージ化して配布すると、再現性を高められます。

/opt/openmpi/X.Y.Z/bin/ompi_info --version
/opt/openmpi/X.Y.Z/bin/ompi_info --all   | grep -Ei 'slurm|pmix|prrte|ucx'
ldd /opt/openmpi/X.Y.Z/bin/mpirun

環境モジュールとノード間の統一

PATHをそろえるだけでは不十分です。ラッパーコンパイラーが参照するヘッダーとライブラリ、実行時のlibmpi、プラグインのパスを全ノードで統一します。

export PATH=/opt/openmpi/X.Y.Z/bin:$PATH
export LD_LIBRARY_PATH=/opt/openmpi/X.Y.Z/lib:$LD_LIBRARY_PATH

which mpicc
which mpirun
mpicc --showme:command
mpicc --showme:compile
mpicc --showme:link
ompi_info --version
for host in node01 node02 node03 node04; do
  ssh "$host" '/opt/openmpi/X.Y.Z/bin/ompi_info --version'
done

環境モジュールを使うと、バージョン切り替えと再現が容易になります。モジュールファイルではPATHとライブラリパスを1つのバージョンのprefixにそろえ、ジョブスクリプトでバージョンを明示してロードしてください。

ラッパーコンパイラーで最小のMPIプログラムをビルドする

mpiccとmpicxxは独立したコンパイラーではなく、選択したC/C++コンパイラーに必要なMPIオプションを追加するラッパーです。通常のgccでヘッダーやライブラリのパスを手作業で組み立てないでください。

#include <mpi.h>
#include <stdio.h>

int main(int argc, char **argv) {
    int rank, size, name_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, &name_len);
    printf("rank=%d size=%d host=%s\n", rank, size, name);
    MPI_Finalize();
    return 0;
}
mpicc -O2 -Wall -Wextra hello_mpi.c -o hello_mpi
ldd ./hello_mpi | grep -E 'libmpi|open-rte|pmix'
mpirun -n 4 ./hello_mpi

Open MPIをrootで実行しないでください。コンテナ内でも専用の非特権ユーザーとスケジューラーのリソース制限を使い、root実行を強制する回避オプションを運用標準にしないでください。

スケジューラーのないクラスターでSSH実行する

hostfileはスケジューラーのない実験用クラスターでのみ使用します。実行ファイルと動的ライブラリは全ノードの同じ絶対パスに配置し、SSH鍵認証とhost keyの確認を先に済ませます。

node01 slots=8
node02 slots=8
mpirun --hostfile hosts.txt   --map-by ppr:4:node   --bind-to core   ./hello_mpi

slotsを超えるランクを暗黙に起動しないでください。オーバーサブスクリプションは開発試験で意図的に使うことはできますが、本番の性能測定を歪め、メモリーを圧迫する場合があります。

Slurmの割り当て内でmpirunを使う

Open MPI 5系は、Slurm環境でもmpirunの使用を推奨しています。割り当て内のmpirunはSlurmのノードとタスク情報を読み取るため、hostfile、–host、-nを改めて指定する必要はありません。

#!/usr/bin/env bash
#SBATCH --job-name=mpi-smoke
#SBATCH --partition=compute
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=4
#SBATCH --cpus-per-task=1
#SBATCH --time=00:05:00
#SBATCH --output=mpi-%j.out

set -euo pipefail
module purge
module load openmpi/X.Y.Z

echo "nodes=${SLURM_JOB_NODELIST} tasks=${SLURM_NTASKS}"
mpirun --bind-to core --map-by slot ./hello_mpi
JOB_ID=$(sbatch --parsable mpi-smoke.sbatch)
squeue --job "$JOB_ID"
sacct --jobs "$JOB_ID"   --format=JobID,State,Elapsed,AllocCPUS,ExitCode
cat "mpi-${JOB_ID}.out"

srunによる直接実行はPMIx対応を確認してから選ぶ

srunから直接実行することもできますが、SlurmとOpen MPIを互換性のあるPMIxでビルドする必要があります。対応プラグインを先に確認し、運用標準をmpirunまたはsrunのどちらかに統一して文書化します。

srun --mpi=list
ompi_info --all | grep -Ei 'pmix|slurm'
srun --mpi=pmix ./hello_mpi

TCP・UCXとCPUバインディングを検証する

EthernetではTCP、InfiniBandやRoCEではUCXが選ばれる場合があります。転送層を無条件に固定する前に、Open MPIが検出した構成、NICの状態、MTU、RDMAデバイスの権限を確認してください。

ompi_info --param pml all
ompi_info --param btl all
ompi_info --param osc all
ucx_info -d
ibv_devinfo
ip -br link
mpirun --report-bindings   --display-map   --bind-to core   --map-by slot   ./hello_mpi

ハイパースレッディング、NUMA、GPUのあるノードでは、実際のアプリケーションに合わせてmap-byとbind-toをベンチマークします。ランクを増やせば速くなると考えて、物理コア数を超えないでください。

機能試験と性能試験を分ける

  1. 単一ノードの2~4ランクで初期化と終了を確認する。
  2. 2ノードのhelloプログラムで名前解決とプロセス起動を確認する。
  3. 小さなping-pongベンチマークで遅延と帯域幅を記録する。
  4. 実際のアプリケーション入力でCPU、メモリー、ネットワーク、スケーラビリティを測定する。
  5. ノードやNICの障害、ジョブ取消時にプロセスが残らないか確認する。
mpirun -n 2 osu_latency
mpirun -n 2 osu_bw
sstat --jobs "${SLURM_JOB_ID}.batch"   --format=JobID,AveCPU,MaxRSS,AveRSS

トラブルシューティング

mpirun --version
mpicc --showme
ompi_info --version
ldd ./hello_mpi
env | grep -E '^(PATH|LD_LIBRARY_PATH|OPAL|OMPI|PMIX|PRTE|SLURM)'
scontrol show job "$SLURM_JOB_ID"
hostnamectl --static
getent hosts node01
  • libmpiのバージョンが違う場合は、moduleとLD_LIBRARY_PATHを整理し、同じビルドを再配布する。
  • 遠隔起動に失敗する場合は、host key、非対話SSH、同一パス、ファイアウォールを確認する。
  • Slurmジョブが割り当て外のノードへ向かう場合は、hostfile・–hostを削除する。
  • UCXエラーでは、デバイス、ドライバー、MTU、メモリーロック、コンテナのデバイス権限を確認する。
  • 性能低下では、CPUバインディング、NUMA、オーバーサブスクリプション、アプリケーションの通信パターンを併せて測定する。

公式資料と関連記事

Open MPI構築の完了基準は、helloが一度動くことではありません。同じビルド、スケジューラーのリソース制約、バインディング、転送層、ジョブ履歴・リソース使用量の記録、実際の性能を再現できる状態です。バージョン、モジュール、コンパイルオプション、ベンチマーク結果を記録し、更新前後を比較してください。