回答:
他の誰かが言ったように、TotalViewはこれの標準です。しかし、それはあなたに腕と脚を要します。
OpenMPIサイトには、MPIデバッグに関するすばらしいFAQがあります。FAQの項目#6は、GDBをMPIプロセスにアタッチする方法を説明しています。すべてを読んでください。いくつかの素晴らしいヒントがあります。
ただし、追跡するプロセスが多すぎる場合は、スタックトレース分析ツール(STAT)を確認してください。Livermoreでこれを使用して、実行可能な数十万の実行中のプロセスからスタックトレースを収集し、ユーザーにインテリジェントに表現します。これは完全な機能を備えたデバッガーではありません(完全な機能を備えたデバッガーは、208kコアまで拡張されません)が、どのプロセスのグループが同じことを実行しているかがわかります。次に、標準デバッガーで各グループの代表をステップ実行できます。
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] [...]
<file>
渡し-x <file>
ます。
ここの投稿の多くはGDBに関するものですが、起動からプロセスにアタッチする方法については触れません。もちろん、すべてのプロセスにアタッチできます。
mpiexec -n X gdb ./a.out
しかし、すべてのプロセスを起動するためにバウンスする必要があるため、これは非常に効果がありません。1つ(または少数)のMPIプロセスをデバッグするだけの場合は、:
演算子を使用して、コマンドラインで別の実行可能ファイルとしてそれを追加できます。
mpiexec -n 1 gdb ./a.out : -n X-1 ./a.out
これで、プロセスの1つだけがGDBを取得します。
他の人が述べたように、ごく少数のMPIプロセスでのみ作業している場合は、複数のgdbセッション、redoubtable valgrind、または独自のprintf /ロギングソリューションを使用してみることができます。
それよりも多くのプロセスを使用している場合は、適切なデバッガーが必要になります。OpenMPIのよくある質問は、両方をお勧めしますAllinea DDTやTotalViewのを。
私はAllinea DDTに取り組んでいます。これはフル機能のグラフィカルなソースコードデバッガなので、次のことができます。
...等々。EclipseまたはVisual Studioを使用したことがあれば、ご自宅にいるようになります。
特にMPI、マルチスレッド、CUDAなどの並列コードをデバッグするための興味深い機能をいくつか追加しました。
スカラー変数はすべてのプロセスにわたって自動的に比較されます:(
ソース:allinea.com)
変数と式の値をプロセスと時間にわたって追跡およびフィルタリングすることもできます。
ORNL、NCSA、LLNL、Jülichなど、上位500の HPCサイトで広く使用されています。al。
インターフェースはかなり素早いです。オークリッジのジャガークラスターでの受け入れテストの一環として、220,000プロセスのスタックと変数を0.1秒でステップおよびマージする時間を計測しました。
@tgamblinは、他のいくつかの一般的なオープンソースプロジェクトと同様に、Allinea DDTと統合する優れたSTATについて言及しました。
あなたがtmux
ユーザーであれば、ベネディクト・モルバッハのスクリプトを使用して非常に快適に感じるでしょう:tmpi
元のソース: https://github.com/moben/scripts/blob/master/tmpi
フォーク:https : //github.com/Azrael3000/tmpi
これを使用すると、複数のパネル(プロセス数)がすべて同期されます(すべてのコマンドがすべてのパネルまたはプロセスに同時にコピーされるため、xterm -e
アプローチと比較して多くの時間を節約できます)。さらにprint
、別のパネルに移動することなく、実行したいプロセスの変数の値を知ることができます。これにより、各パネルに各プロセスの変数の値が出力されます。
あなたがtmux
ユーザーでないなら、私はそれを試して見てみることを強く勧めます。
http://github.com/jimktrains/pgdb/tree/masterは、これを行うために私が書いたユーティリティです。いくつかのドキュメントがあり、質問があれば遠慮なく私に連絡してください。
基本的には、GDBをラップし、そのIOを中央サーバーに集めるperlプログラムを呼び出します。これにより、GDBが各ホストで実行され、ターミナルの各ホストでGDBにアクセスできるようになります。
をscreen
一緒に使用してgdb
MPIアプリケーションをデバッグすることxterm
は、特にが利用できない場合、またはいくつかのプロセッサを処理している場合にうまく機能します。途中でスタックオーバーフロー検索を行うと、多くの落とし穴があったので、私のソリューションを完全に再現します。
まず、MPI_Initの後にコードを追加してPIDを出力し、プログラムが接続を待機するのを停止します。標準的な解決策は無限ループのようです。最終的にに落ち着きました。gdb内でエスケープraise(SIGSTOP);
するには、の追加の呼び出しが必要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"
後で簡単にアクセスできるように画面に名前を付けることができます-l
。bash のオプションはインタラクティブモードで画面を起動し、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が起動したら、screenの-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セッションに送信できます。
また、並列プログラミングの支援を目的とした私のオープンソースツールpadbもあります。デバッガとしてだけでなく、たとえば並列トップのようなプログラムとしても機能するため、これを「ジョブ検査ツール」と呼びます。「完全レポート」モードで実行すると、アプリケーション内のすべてのプロセスのスタックトレースと、すべてのランクのすべての関数のローカル変数が表示されます(-gでコンパイルした場合)。また、ジョブ内の各ランクの未処理の送受信のリストである「MPIメッセージキュー」も表示されます。
完全なレポートを表示するだけでなく、ジョブ内の個々の情報を拡大するようにpadbに指示することもできます。表示する情報を制御する無数のオプションと構成項目があります。詳細については、Webページを参照してください。
この小さな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);
}
もちろん、この関数はデバッグビルド専用にコンパイルする必要があります。
gethostname(hostname, sizeof(hostname)); printf("PID %d on host %s ready for attach\n", getpid(), hostname);
。次に、と入力してプロセスにアタッチし、rsh <hostname_from_print_statement>
最後にをアタッチしますgdb --pid=<PID_from_print_statement>
。
ログトレースを使用してMPI関連のデバッグを行いますが、mpich2を使用している場合はgdbを実行することもできます:MPICH2およびgdb。この手法は、デバッガーから起動するのが難しいプロセスを処理している場合、一般的には良い方法です。
もう1つのソリューションは、シミュレートされたMPIであるSMPIでコードを実行することです。それは私が関わっているオープンソースプロジェクトです。すべてのMPIランクは、同じUNIXプロセスのスレッドに変換されます。その後、gdbを使用してMPIランクを段階的に変更できます。
SMPIはMPIアプリケーションの研究に他の利点を提案します:クレアボイアンス(システムのすべての部分を観察できます)、再現性(特に指定しない限り、数回実行するとまったく同じ動作になります)、ハイゼンバグの不在(シミュレーションプラットフォームが異なるため)ホストから)など
詳細については、このプレゼンテーションまたは関連する回答を参照してください。