4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

MPIプログラムのデバッグ方法 〜MPIプロファイリングインタフェース編〜

Last updated at Posted at 2017-12-17

はじめに

これはMPI Advent Calendar 2017の18日目の記事です。

MPI Advent Calendar 2017 はMPIプログラムのデバッグ技法の記事が多い気がしますが、MPIプロファイリングインタフェースを使う方法を書いたものがないので、この「MPIプログラムのデバッグ方法〜MPIプロファイリングインタフェース編〜」を書きます。

MPIプロファイリングインタフェースというものがある

MPIにはMPIプロファイリングインタフェースというものが1.0のときから規格として存在します。

どういうものかをざっくり書くと、

  • 各MPI関数はMPI_を接頭詞とせず、PMPI_を接頭詞としても呼び出し可能。機能や引数は接頭詞MPI_のものと全く同じ...と言うか 単なる別名
    • 例えば、MPI_SendPMPI_Sendで呼べる。
  • 接頭詞MPI_のMPI関数は ユーザプログラムで再定義できる

というもの。
パチェコの本が手元にあるなら、とりあえず12章6.1節を読むと良いでしょう。

具体的使い方としてはこんな感じで

#include <mpi.h>

int MPI_Send(void* buffer, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
{
   int ret;

   /* ここで何か固有処理(1) */

   ret = PMPI_Send(buffer, cont, datatype, dest, tag, comm);

   /* ここで何か固有処理(2) */

   return ret;
}

とすることで、ユーザプログラム定義のMPI_Send関数が作れます。
呼び出し側は特に何もする必要はありません。

MPI_Send(...);

などと通常のMPI関数と同様にコールすればOKです。

固有処理を通信ごとに分けたいような場合は、tagで制御するといいです。

なお、各MPIライブラリはこれをどう実現しているのかはよくわかりません。調べてもいませんが。特にFortranではどうやってるんでしょうね。

MPIプロファイリングインタフェースを使ったデバッグ

さて、MPIプロファイリングインタフェース(以下、"PMPI関数"と呼ぶ)はその名前のとおり、タイマ関数を使うなどして通信性能(正確にはMPI関数の経過時間)を測定することを目的としています。たぶん。

そしてこれはデバッグにも使うことができます。

たとえば、MPIプログラムをデバッグするときは、通信内容をダンプしたいことがよくあります。少なくとも私はある。
プログラム中のMPI関数の呼び出しの前後にダンプするコードを挿れいていくのは大変手間です。そんなとき、ダンプの対象としたいMPI関数を、PMPI関数のラッパとしてユーザプログラムで再定義してラッパ内でダンプ処理することで容易に実現できます。

え?そんなことしたら、全部の通信がダンプされて大変なことになるって?tagで処理を分けましょう。異なる通信は異なるtagを着けるのが作法ですよ。(自戒)

デバッグ事例

こういう記事を書くということは、わたしの経験としてPMPI関数がデバッグに強烈に役立った経験があるからなわけで、その例を簡単に紹介。(実際のコードは手元に残ってないので擬似コードで)

バグの事象としては、プログラムを実行すると毎回ほぼ同じタイミングでMPIの内部エラーでプログラムが終了を起こすというもの。そういうわけで、まずはそのプログラムで使っている全てのMPI関数をPMPI関数を使って再定義して、呼び出し回数をカウントするようにしました。

こんな感じ

static unsigned int mpi_send_count = 0;
int MPI_Send(void* buffer, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
{
   int ret;
   mpi_send_count++;
   printf("MPI_Send: %d\n", mpi_send_count);
   ret = PMPI_Send(buffer, cont, datatype, dest, tag, comm);
   return ret;
}

この結果、毎回同じ呼び出しカウントでコケることが判明。続いて、

static unsigned int mpi_send_count = 0;
int MPI_Send(void* buffer, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
{
   int ret;
   mpi_send_count++;
   if (mpi_send_count == コケるカウント) {
      /* 引数とスタックトレースをダンプする処理 */
   }
   ret = PMPI_Send(buffer, cont, datatype, dest, tag, comm);
   return ret;
}

として、問題が発生するMPI関数の呼び出し位置とタイミングを特定して、デバッグの材料とした・・・ということがありました。まあ、結果としてMPIライブラリの実装のバグだったのですけども。(おこ)

まとめ

  • MPIプロファイリングインタフェースというのがあります。
  • 使い方しだいでデバッグにも使えます。
4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?