web-dev-qa-db-ja.com

MPIプログラムをデバッグするにはどうすればよいですか?

コンパイルして実行するMPIプログラムがありますが、奇妙なことは何も起こらないようにステップスルーしたいと思います。理想的には、GDBを特定のプロセスにアタッチする簡単な方法が欲しいです代わりに、各プロセスがデバッグ出力を個別のログファイルに書き込むようにすることもできますが、これは実際にはデバッガと同じ自由度を与えません。

より良いアプローチはありますか? MPIプログラムをどのようにデバッグしますか?

117
Jay Conrod

他の誰かが言ったように、 TotalView はこれの標準です。しかし、それはあなたに腕と脚がかかります。

OpenMPIサイトには素晴らしい MPIデバッグに関するFAQ があります。 FAQの項目#6は、GDBをMPIプロセスにアタッチする方法を説明しています。すべてを読んで、いくつかの素晴らしいヒントがあります。

ただし、追跡するプロセスが多すぎる場合は、 Stack Trace Analysis Tool(STAT) を確認してください。 Livermoreでこれを使用して、潜在的に数十万の実行中のプロセスからスタックトレースを収集し、それらをユーザーにインテリジェントに表現します。これはフル機能のデバッガーではありません(フル機能のデバッガーが208kコアに拡張することはありません)が、どのプロセスグループが同じことを行っているかがわかります。その後、標準デバッガーで各グループの代表者をステップスルーできます。

59
Todd Gamblin

Gdbは非常に便利です。私はそれを

mpirun -np <NP> xterm -e gdb ./program 

これは私ができるxtermウィンドウを起動します

run <arg1> <arg2> ... <argN>

通常は正常に動作します

以下を使用して、これらのコマンドを一緒にパッケージ化することもできます。

mpirun -n <NP> xterm -hold -e gdb -ex run --args ./program [arg1] [arg2] [...]
75
messenjah

ここの投稿の多くはGDBに関するものですが、スタートアップからプロセスにアタッチする方法については言及していません。明らかに、すべてのプロセスにアタッチできます:

mpiexec -n X gdb ./a.out

しかし、すべてのプロセスを起動するために跳ね返る必要があるため、それは非常に効果的ではありません。 1つ(または少数)のMPIプロセス)をデバッグするだけの場合は、:演算子を使用して、コマンドラインで別の実行可能ファイルとして追加できます。

mpiexec -n 1 gdb ./a.out : -n X-1 ./a.out

これで、プロセスの1つだけがGDBを取得します。

23
Wesley Bland

他の人が述べたように、handfulMPIプロセスを使用してみてください- 複数のgdbセッション 、再編集可能な valgrind または独自のprintf /ロギングソリューションを展開します。

それよりも多くのプロセスを使用している場合は、適切なデバッガーが本当に必要になります。 OpenMPI FAQAllinea DDTTotalView の両方を推奨しています。

私は Allinea DDT に取り組んでいます。フル機能のグラフィカルソースコードデバッガーなので、次のことができます。

  • デバッグまたはアタッチ(200k以上)MPIプロセス
  • グループで、または個別にステップして一時停止する
  • ブレークポイント、ウォッチ、トレースポイントを追加する
  • メモリエラーとリークをキャッチする

...等々。 EclipseまたはVisual Studioを使用したことがあれば、すぐに自宅にいられるでしょう。

デバッグparallelコード(MPI、マルチスレッド、またはCUDA)のために、いくつかの興味深い機能を追加しました。

  • スカラー変数はすべてのプロセスで自動的に比較されます: Sparklines showing values across processes
    (ソース: allinea.com

  • また、プロセスと時間にわたって変数と式の値をトレースおよびフィルターできます。 Tracepoints log values over time

top5[〜#〜] ornl [〜#〜][〜#〜] ncsa [〜#〜などのHPCサイトで広く使用されています][〜#〜] llnl [〜#〜]Jülich et。等.

インターフェイスは非常にきびきびしています。オークリッジのジャガークラスターでの受け入れテストの一環として、220,000プロセスのスタックと変数を0.1秒でステップ実行し、マージしました。

@tgamblinは、優れた [〜#〜] stat [〜#〜] に言及しました。これは Allinea DDT と統合され、他のいくつかの一般的なオープンソースプロジェクトと同様です。

17
Mark
8
Chad Brewbaker

http://github.com/jimktrains/pgdb/tree/master は、まさにこれを行うために書いたユーティリティです。いくつかのドキュメントがありますので、気軽に質問してください。

基本的に、GDBをラップし、IOの中央サーバーにファンネルするPerlプログラムを呼び出します。これにより、各ホストでGDBを実行でき、端末の各ホストでアクセスできます。

6
Jim Keener

tmuxユーザーの場合、Benedikt Morbachtmpiのスクリプトを使用すると非常に快適です。

元のソース: https://github.com/moben/scripts/blob/master/tmpi

フォーク: https://github.com/Azrael3000/tmpi

これにより、複数のパネル(プロセス数)がすべて同期されます(すべてのコマンドがすべてのパネルまたはプロセスに同時にコピーされるため、xterm -eアプローチと比較して多くの時間を節約できます)。さらに、別のパネルに移動することなく、printを実行したいプロセスの変数の値を知ることができます。これにより、各プロセスに変数の値が各パネルに出力されます。

tmuxユーザーでない場合は、試してみることを強くお勧めします。

5
GG1991

screengdbと一緒に使用してMPIアプリケーションをデバッグします。特にxtermが利用できない場合、または数個を超えるプロセッサを扱っている場合は、うまく機能します。付随するstackoverflow検索には多くの落とし穴がありましたので、ソリューションを完全に再現します。

最初に、MPI_Initの後にコードを追加してPIDを出力し、プログラムが停止して接続を待機します。標準的な解決策は無限ループのようです。最終的にraise(SIGSTOP);に落ち着きました。gdb内でエスケープするには、continueの追加の呼び出しが必要です。

}
    int i, id, nid;
    MPI_Comm_rank(MPI_COMM_WORLD,&id);
    MPI_Comm_size(MPI_COMM_WORLD,&nid);
    for (i=0; i<nid; i++) {
        MPI_Barrier(MPI_COMM_WORLD);
        if (i==id) {
            fprintf(stderr,"PID %d rank %d\n",getpid(),id);
        }
        MPI_Barrier(MPI_COMM_WORLD);
    }
    raise(SIGSTOP);
}

コンパイル後、バックグラウンドで実行可能ファイルを実行し、stderrをキャッチします。次に、grepキーワード(ここではリテラルPID)のstderrファイルを使用して、各プロセスのPIDとランクを取得できます。

MDRUN_EXE=../../Your/Path/To/bin/executable
MDRUN_ARG="-a arg1 -f file1 -e etc"

mpiexec -n 1 $MDRUN_EXE $MDRUN_ARG >> output 2>> error &

sleep 2

PIDFILE=pid.dat
grep PID error > $PIDFILE
PIDs=(`awk '{print $2}' $PIDFILE`)
RANKs=(`awk '{print $4}' $PIDFILE`)

Gdbセッションは、gdb $MDRUN_EXE $PIDを使用して各プロセスにアタッチできます。画面セッション内でこれを行うと、任意のgdbセッションに簡単にアクセスできます。 -d -mは分離モードで画面を開始し、-S "P$RANK"は後で簡単にアクセスできるように画面に名前を付けることができ、bashの-lオプションは対話モードで開始し、gdbがすぐに終了しないようにします。

for i in `awk 'BEGIN {for (i=0;i<'${#PIDs[@]}';i++) {print i}}'`
do
    PID=${PIDs[$i]}
    RANK=${RANKs[$i]}
    screen -d -m -S "P$RANK" bash -l -c "gdb $MDRUN_EXE $PID"
done

画面でgdbが起動したら、画面の-X stuffコマンドを使用して、画面への入力をスクリプト化できます(すべての画面を入力して同じものを入力する必要はありません)。コマンドの最後に改行が必要です。ここでは、以前に指定した名前を使用して、-S "P$i"によって画面にアクセスします。 -p 0オプションは重要です。それ以外の場合、コマンドは断続的に失敗します(以前に画面に接続したことがあるかどうかに基づいて)。

for i in `awk 'BEGIN {for (i=0;i<'${#PIDs[@]}';i++) {print i}}'`
do
    screen -S "P$i" -p 0 -X stuff "set logging file debug.$i.log
"
    screen -S "P$i" -p 0 -X stuff "set logging overwrite on
"
    screen -S "P$i" -p 0 -X stuff "set logging on
"
    screen -S "P$i" -p 0 -X stuff "source debug.init
"
done

この時点で、screen -rS "P$i"を使用して任意の画面にアタッチし、Ctrl+A+Dを使用してデタッチできます。前のセクションのコードと同様に、コマンドはすべてのgdbセッションに送信できます。

5
user3788566

MPIプログラムをデバッグする「標準的な」方法は、その実行モデルをサポートするデバッガーを使用することです。

UNIXでは、 TotalView はMPIを適切にサポートすると言われています。

3

この小さなhomebrewnメソッドを使用して、デバッガーをMPIプロセスに接続します-コード内のMPI_Init()の直後に、次の関数DebugWait()を呼び出します。プロセスがキーボード入力を待っている間、デバッガーをアタッチしてブレークポイントを追加する時間は常にあります。

static void DebugWait(int rank) {
    char    a;

    if(rank == 0) {
        scanf("%c", &a);
        printf("%d: Starting now\n", rank);
    } 

    MPI_Bcast(&a, 1, MPI_BYTE, 0, MPI_COMM_WORLD);
    printf("%d: Starting now\n", rank);
}

もちろん、デバッグビルド専用にこの関数をコンパイルする必要があります。

2
Harshdeep

私のオープンソースツールであるpadbもあります。これは、並列プログラミングを支援することを目的としています。 「ジョブ検査ツール」と呼びます。デバッガーとしてだけでなく、たとえばプログラムのような並列トップとしても機能するためです。 「フルレポート」モードで実行すると、アプリケーション内のすべてのプロセスのスタックトレースと、すべてのランクのすべての関数のローカル変数が表示されます(-gでコンパイルした場合)。また、「MPIメッセージキュー」、つまりジョブ内の各ランクの未処理の送受信のリストも表示されます。

完全なレポートを表示するだけでなく、ジョブ内の個々の情報にズームインするようpadbに指示することもできます。表示する情報を制御するための無数のオプションと構成アイテムがあります。詳細については、Webページを参照してください。

Padb

2
user224253

Gpiをmpiプロセスにアタッチするコマンドは不完全です。

mpirun -np <NP> xterm -e gdb ./program 

Mpiとgdbの簡単な説明を見つけることができます here

1
akintayo

ログトレースを使用してMPI関連のデバッグをいくつか行いますが、mpich2を使用している場合は、gdbを実行することもできます: MPICH2 and gdb 。この手法は、デバッガーから起動するのが難しいプロセスを処理する場合、一般的には良い習慣です。

1
Jim Hunziker
1
RSFalcon7

MPIプログラムをデバッグする非常に簡単な方法。

Main()関数でスリープを追加(some_seconds)

通常どおりプログラムを実行します

$ mpirun -np <num_of_proc> <prog> <prog_args>

プログラムが起動し、スリープ状態に入ります。

そのため、psでプロセスを見つけてgdbを実行し、それらに接続するまでに数秒かかります。

QtCreatorのようなエディターを使用する場合、使用できます

デバッグ->デバッグの開始->実行中のアプリケーションへの接続

そこにあなたのプロセスを見つけます。

1
stranger

別の解決策は、シミュレートされたMPIであるSMPI内でコードを実行することです。それは私が関わっているオープンソースプロジェクトです。すべてのMPIランクは、同じUNIXプロセスのスレッドに変換されます。その後、gdbを使用してMPIランクをステップ実行できます。

SMPIは、MPIアプリケーション:千里眼(システムのすべての部分を観察できます)、再現性(特に指定しない限り、いくつかの実行がまったく同じ動作につながる)の研究に他の利点を提案します。 heisenbugs(シミュレートされたプラットフォームはホストのものとは異なるため)など.

詳細については、「 このプレゼンテーション 」または「 関連する回答 」を参照してください。

0
Martin Quinson