Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

MPI 特別講義まとめ

これは何か

2026-07-11 の特別講義(MPI 入門)の記録です。当日の殴り書きメモを、後から読み返せる形に整理しました。

内容は MPI の仕様(specification)レベルの基礎知識が中心です。特記がない限り、ここに書いたことは MPI 標準として定まっている情報です。実装(Open MPI など)に依存する挙動は、その旨を明記します。

  • MPI(Message Passing Interface): 分散メモリ並列プログラミングの API を定めた国際標準仕様。

1. 並列計算と分散計算

用語意味
Parallel Computing1 つのタスクを小さいタスクに分割して同時に処理する
Distributed Computing複数の計算機を使って 1 つの問題を解く。多数のノードが互いに接続し、同じ問題を協調して解く

メモリモデルによる分類

モデル代表的な技術特徴
Shared Memory(共有メモリ)pthreadsOpenMPSHMEM同一メモリ空間を複数スレッドで共有
Distributed Memory(分散メモリ)MPIプロセスごとに独立したメモリ。通信でデータをやり取り
Data Parallel(データ並列)PGASデータを分散配置し、グローバルアドレス空間として扱う

補足:理論値を超える Speedup

理論上の上限を超える速度向上(super-linear speedup)が観測されることがあります。主な要因は次の通りです。

  • メモリとキャッシュの効果(データが分割されて各ノードのキャッシュに載りやすくなる)
  • 並列探索アルゴリズムで早く解が見つかる場合
  • 単なる測定上のばらつき(偶然)

2. MPI:仕様と実装の関係

「MPI は specification(仕様)」であり、実際に動くのはその実装です。ここは混同しやすいので分けて整理します。

MPI 仕様の実装(MPI 標準に準拠したライブラリ)

実装位置づけ
Open MPI代表的なオープンソース実装
MPICH歴史の古いオープンソースの代表実装
MVAPICHMPICH ベース。InfiniBand / HPC ネットワーク向けに最適化
Intel MPIIntel 提供。Intel CPU / Omni-Path 向けに最適化

いずれも mpirun / mpiexec を提供し、MPI プログラムを動かすランタイム兼ライブラリです。

GPU 向けコレクティブ通信ライブラリ(MPI 実装ではない)

NCCL / RCCL / HCCLMPI の実装ではありません。ベンダーごとの GPU/アクセラレータ向け高速コレクティブ通信ライブラリで、allreducebroadcastallgather などの集合通信に特化しています。

ライブラリベンダー / 対象
NCCLNVIDIA Collective Communications Library(NVIDIA GPU 向け)
RCCLRadeon Collective Communications Library(AMD GPU 向け、NCCL クローン的)
HCCLHuawei Collective Communication Library(Ascend など向け)

階層イメージ

  • MPI(汎用メッセージパッシングの標準仕様)
    • Open MPI / MPICH / MVAPICH / Intel MPI(仕様に沿った実装)
  • NCCL / RCCL / HCCL(各社が GPU 向けに出す高速集合通信エンジン。規格ではなくプロダクト)

3. MPI Hello World

MPI 入門で最初に出てくる最小プログラムです。mpirun -np N ./a.out で起動すると、同じ実行ファイルが N プロセス立ち上がり、それぞれが自分の rank・ノード名・全体プロセス数を表示します。

int main(int argc, char** argv) {
    int world_size, world_rank, name_len;
    char processor_name[MPI_MAX_PROCESSOR_NAME];

    MPI_Init(NULL, NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &world_size);
    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
    MPI_Get_processor_name(processor_name, &name_len);

    printf("Hello world from %s, rank %d/%d\n",
           processor_name, world_rank, world_size);

    MPI_Finalize();
}

各要素の意味

要素役割
MPI_InitMPI ランタイムを初期化。「このプロセスは MPI の一員」と登録する開始宣言
MPI_Comm_sizeコミュニケータ内の全プロセス数を取得(-np 4 なら 4)
MPI_Comm_rank自分のランク番号(0 〜 world_size-1)を取得。条件分岐(例: rank 0 だけがファイルを読む)に使う
MPI_Get_processor_name動作中の物理マシン名(ホスト名)を取得
MPI_COMM_WORLD全プロセスが所属する、MPI が用意済みのコミュニケータ
MPI_MAX_PROCESSOR_NAMEノード名の最大長を表す MPI 定義の定数
MPI_FinalizeMPI の終了処理。以降は原則 MPI 関数を呼べない

覚え方: MPI プログラムの本編は「MPI_InitMPI_Finalize の間」。

スライドの色分け: 赤 = MPI 関数、緑 = MPI 定義の定数・ハンドル、黒 = 通常の C 要素。

mpicc hello.c -o hello
mpirun -np 4 ./hello

出力例(どのノードにどの rank が割り当てられたか目視で確認できる):

Hello world from node01, rank 0/4
Hello world from node02, rank 1/4
Hello world from node02, rank 2/4
Hello world from node03, rank 3/4

4. 通信パターンと基本オブジェクト

MPI でできる通信の「地図」です。

通信パターン

パターン代表 API概要
Two-sided(両側通信)MPI_Send / MPI_Recv送信側と受信側の両方が MPI 関数を呼ぶ。相手が Recv しないと Send が完了しない。ブロッキング/ノンブロッキング(MPI_Isend / MPI_Irecv)を含む
One-sided(片側通信)MPI_Put / MPI_GetRMA(リモートメモリアクセス)。相手が公開したメモリ領域(MPI_Win_create で作る window)に直接読み書きする。相手は毎回 Recv を書かなくてよい
Collective(集合通信)MPI_BarrierMPI_Bcast ほかコミュニケータに属する全員(または一部)が同じ関数を呼んで同期・データ共有する
MPI I/O(並列 I/O)MPI_File_read / MPI_File_write / MPI_File_set_view複数プロセスで協調して巨大ファイルを読み書きする。大規模 HPC では I/O がネックになりやすく重要

基本オブジェクト

オブジェクト役割
Communicatorsプロセスの「グループ」とその中のランク対応をまとめる。MPI_COMM_WORLD が代表。MPI_Comm_split などで部分グループを作れる。「どのグループ内の会話か」を決める部屋番号
Data TypesMPI が理解するデータの並び。基本型(MPI_INTMPI_DOUBLE など)と派生型(構造体やストライド配列を 1 つの型として定義)。異なるアーキテクチャ間の変換(エンディアン差など)も吸収
Requestsノンブロッキング通信で使う「未完了操作」を表すハンドル。MPI_Wait / MPI_Test で完了確認。通信と計算のオーバーラップを可能にする

MPI プログラムは「どのコミュニケータ内で」「どのデータ型のバッファを」「どの通信パターンで」やり取りするか、の 3 つを組み合わせて設計します。


5. Tag-Matching(タグマッチング)

MPI_SendMPI_Recv同時に呼ぶ必要はありません。MPI ランタイムが送信キュー・受信キューを管理し、条件が合った瞬間にデータを受信バッファへ渡します。この対応付けが Tag-Matching です。

マッチングに使うパラメータ

パラメータ送信側受信側ワイルドカード
相手ランクdestsourceMPI_ANY_SOURCE
タグ(メッセージ種別のラベル、int 値)tagtagMPI_ANY_TAG
コミュニケータcommcomm

順序が入れ替わっても正しくつながる

  • Recv が先: 受信側が先に MPI_Recv を呼ぶと「未完了の受信」としてキューに登録され、データ到着時に即バッファへコピーされる。
  • Send(データ)が先: データが先に届くと内部バッファにストックされ、後から MPI_Recv が呼ばれた瞬間にコピーされる。

正しい source, tag, comm さえ指定すれば、送受信のタイミングをぴったり合わせる必要はありません。

マッチングのルール

  • マッチング条件(source, dest, comm, tag)は一意である必要はない。同じ条件のメッセージが複数流れてよい。
  • Matching in the order posted: 複数がマッチしうる場合、先にポストされた Recv から順に、先にポストされた Send とマッチする(FIFO)。これにより「送った順=受け取った順」が保たれ、追い越し(overtaking)が起きない。

アプリからのヒント(info オブジェクト)

コミュニケータに info を付けて「自分はこういうことをしない」と宣言すると、実装がマッチング処理を最適化しやすくなります(実際のキー名・サポート状況は実装依存)。

ヒント宣言する内容
mpi_assert_no_any_tagMPI_ANY_TAG を使わない
mpi_assert_no_any_sourceMPI_ANY_SOURCE を使わない
mpi_assert_exact_length受信 count を常にメッセージ長ぴったりにする
mpi_assert_no_allow_overtakingメッセージの追い越しを許さない

6. ブロッキング Send/Recv の完了条件と引数

ブロッキングな MPI_Send / MPI_Recv は、安全なタイミングまで戻ってこない設計です。

関数戻ってきたとき保証されること
MPI_Recv送られてきたデータが受信バッファ(buf)に安全にコピー済み。バッファを読んでよい
MPI_Send送信バッファ(buf)を上書きしても、送信中メッセージが壊れない状態。相手にすでに届いたか、MPI 内部にコピー済み

注意: 関数が戻る前に、Send は送信バッファを書き換えない、Recv は受信バッファを読まないこと。

引数の役割(3 分割)

int MPI_Send(void* buf, int count, MPI_Datatype datatype,
             int dest, int tag, MPI_Comm comm)

int MPI_Recv(void* buf, int count, MPI_Datatype datatype,
             int source, int tag, MPI_Comm comm,
             MPI_Status* status)
分類引数意味
データ内容(何を送る/受け取るか)buf, count, datatypeバッファ先頭、要素数、要素 1 個の型
相手とグループ(誰と通信するか)dest / source, comm相手ランク、そのランクが意味を持つコミュニケータ
タグ(メッセージ種別)tag同じ相手でもタグで別種のメッセージとして区別

7. 送信モード(communication modes)

同じ「送る」でも、何をもって送信完了とみなすかがモードで違います。各モードにブロッキング版とノンブロッキング版があります。

モード完了条件特徴・用途
Standard(標準)実装・メッセージサイズに依存。小さいメッセージは内部バッファにコピーして即完了(eager)、大きいメッセージは受信待ちでブロックすることも一番よく使うデフォルト。「本当に届いたか」は保証しない
Buffered(バッファ付き)データがローカルの登録済みバッファ(MPI_Buffer_attach)にコピーされた時点で完了。受信の有無に依存しないユーザーが送信用バッファを用意する必要がある
Synchronous(同期)マッチする Recv がポストされ、受信が始まって初めて完了相手の受信開始を確認できる。順序制御やデッドロック発見に有用。遅くなることがある
Ready(レディー)マッチする Recvすでにポスト済みのときだけ開始してよい。未ポストなら undefined behavior特殊・高度な最適化用。一般アプリではほぼ使わない

モード × ブロッキング / ノンブロッキング

StandardBufferedSynchronousReady
BlockingMPI_SendMPI_BsendMPI_SsendMPI_Rsend
NonblockingMPI_IsendMPI_IbsendMPI_IssendMPI_Irsend

8. Point-to-Point 通信の保証

MPI 標準がどこまで保証し、どこから実装依存かを整理します。キーワードは Order / Progress / Fairness / Resource limitations。

観点標準の保証実務上のポイント
Order(順序)同じ (source, dest, comm) かつ同種の通信では non-overtaking(送った順に届く)「送信順=意味的な順序」として設計してよい
Progress(進行性)MPI 関数を呼んでいるとき以外は通信進行を保証しないノンブロッキング通信を投げた後ずっと自前計算だけしていると、背景で転送が進むとは限らない。定期的に MPI_Test / MPI_Wait などで進行のきっかけを与える
Fairness(公平性)公平性は保証しない実装は best effort で公平に動くが、「絶対に公平」と仮定して設計しない
Resource limitations(リソース)厳密な規定なし(best effort)大量の未完了通信を一度に投げるとバッファ不足でエラーや性能劣化。リソースを意識した設計を

Quality implementation: MPI 標準の保証は最小限(Order 以外はかなり緩い)。実際の良い実装(Open MPI、MPICH、Intel MPI など)は、高速・公平・安定・良い進行性といった望ましい性質を最適化で提供している。「標準の最低ライン」と「実装が提供する挙動」にはギャップがある点に注意。

HPC コンペでチューニングまで踏み込むなら、実装ごとの Progress 性・背景進行の有無はかなり効いてくる。


9. ノンブロッキング通信の完了確認

MPI_Isend / MPI_Irecv は即戻り、MPI_Request を返します。実際の完了は以下のルーティンで確認します。

完了の意味

  • 送信(Isend)の完了 → 送信バッファを安全に上書きできる。
  • 受信(Irecv)の完了 → 受信バッファにメッセージが入っている。

単一操作の完了

関数挙動
MPI_Wait(request, status)その通信 1 個が完了するまでブロック
MPI_Test(request, flag, status)ノンブロッキング。flag != 0 なら完了、flag == 0 ならまだ。計算とオーバーラップさせるときに使う

複数のうちどれか 1 個の完了(ANY)

MPI_Request の配列を渡し、そのうち 1 つが完了したら教えてくれます。

関数挙動
MPI_Waitany(count, array_of_requests, index, status)配列内で最初に完了したものが出るまでブロック。完了した要素の位置が index に入る
MPI_Testany(count, array_of_requests, index, flag, status)MPI_Waitany のノンブロッキング版

典型パターン: 多数の Isend / Irecv を投げておき、Waitany / Testany で「終わった順」に処理して通信と計算を重ねる。

MPI_Request reqs[N];
/* Isend / Irecv をセットアップして reqs に入れる */
for (int finished = 0; finished < N; ++finished) {
    int index;
    MPI_Status status;
    MPI_Waitany(N, reqs, &index, &status);
    /* index 番目の通信の後処理 */
}

10. 集団通信(Collective)

集団通信はコミュニケータ単位で定義されます(defined in the context of a communicator)。そのコミュニケータに属するランクが、全員または特定パターンで同じ collective 関数を呼ぶのが前提です。

10-1. 3 つの分類軸

種類内容
Completion semantics(完了)Blocking1 コミュニケータにつき同時アクティブは 1 つだけ。完了までブロック(MPI_BcastMPI_AllreduceMPI_Barrier
Nonblocking同じコミュニケータ上でも複数を同時進行可(MPI_IbcastMPI_IallreduceMPI_Ibarrier)。計算と通信のオーバーラップに有用
Scope(スコープ)Non-persistent毎回一から呼ぶ従来型。各操作は一度きり
Persistentテンプレート(persistent object)を一度作り、start / wait を繰り返す。毎回の準備処理を再利用でき、オーバーヘッドを削減
Participating ranks(参加ランク)regular全ランクが参加(MPI_BcastMPI_Gather など)。誰か一人でも呼ばないとデッドロック
Neighborhoodトポロジ情報を持つコミュニケータ(MPI_Cart_create など)に紐づき、近傍とだけ通信(MPI_Neighbor_allgather など)。格子状・グラフ状パターンで効率的

「nonblocking + persistent + neighborhood」を組み合わせると強力な性能チューニングができる、という布石。

10-2. 入出力パターンによる 4 分類

「誰がデータを出し、誰が結果を受け取るか」で分類します。

クラスパターン代表 API
One-To-All1 プロセスが情報源 → 全員が受け取るMPI_BcastMPI_Scatter / MPI_Scatterv
All-To-One全員が出す → 1 プロセスが集約MPI_Gather / MPI_GathervMPI_Reduce
All-To-All全員が出し、全員が受け取る(双方向)MPI_Allgather / MPI_AllgathervMPI_Alltoall / MPI_Alltoallv / MPI_AlltoallwMPI_AllreduceMPI_Reduce_scatter
Other上記に当てはまらないものMPI_Scan(prefix 演算 = 部分和)、MPI_Barrier(同期のみ)

グラフでのイメージ

  • One-To-All: ルート 1 個 → 全ノードへ広がる木(Bcast, Scatter)
  • All-To-One: 全ノード → ルート 1 個へ集まる木(Gather, Reduce)
  • All-To-All: 全ノード間の多重エッジ(Allgather, Alltoall, Allreduce)
  • Other: 部分和や同期など、単純な送受図で表しづらいもの(Scan, Barrier)

この型を頭に入れておくと、「Allreduce を Allgather + Reduce に分解できるか」「Bcast の木構造はどうか」といった議論が整理しやすくなる。


大会との関係(メモ)

  • OpenFOAM 課題(テーマ①)は分散メモリ並列 = MPI が中核。領域分割・ランク配置・通信量・MPI I/O が性能に直結する。
  • 実装ごとの Progress 性・背景進行・コレクティブアルゴリズムの違いは、チューニング時の検討対象になりうる。
  • 関連ページ: MPI通信最適化領域分割(decomposePar)NCCL通信最適化

参考文献