はじめに
MPIプログラムをgdbでデバッグするためのまともな方法が見つからず、あまりにしんどかったのでmpitxというツールを作った、というお話です。
デモ動画を見てもらえると分かりやすいかもしれないですが、各MPIプロセス毎に端末が割り当てられてtmuxで制御できます。
tmuxの機能としてキーボード入力を全ての端末に複製して送ることができるので、gdbによるデバッグ等に便利です。
さらに、複数ノードにも対応させたので、スパコンやクラスタ等の環境でも動作します。
これは某スパコンで実際に実行したときのキャプチャですが、
hostnameの結果から別のノードでの実行をインタラクティブに制御できているのが分かると思います。
必要になった背景
MPIプログラムをgdbでデバッグするには、下の記事でも言及されているようにあんなことやこんなことをしてやる必要がありました。
いちいちデバッグのためにコンパイルし直すのもなんだかなあという気がして、もっと簡単にgdbを起動できる何かが欲しいなあと思っていたところ、tmpiなるスクリプトを見つけました。
これがmpitxの原型で、大体の機能は既にあってありがたく使わせていただいていました。
しかし、しばらく使っているうちにいくつか不満が出てきたので作り直したという次第です。
mpitx と tmpi の比較:
-
mpitxはマルチノード対応、tmpiはマルチノード不可 -
mpitxはMPI実装固有のオプションをそのままmpiexecに渡せる、tmpiではそれが面倒 -
mpitxはpython3スクリプト、tmpiはbashスクリプト- 細かい話:
tmpiではreptyrコマンドがなければMPIの子プロセスに環境変数を引き継ぐことができないが、mpitxではpython3のいい感じに上手いことやっているのでreptyrへの依存なしで環境を引き継げる
- 細かい話:
色々あるんですが、大きかったのはtmpiがマルチノードに対応していなかったことでした。
複数ノードでしか再現しないバグがたまーに出現するので、この機能はぜひとも欲しいところ。
使い方
だいたいはGitHubの方に書いたので、そちらを参照してもらえればと思います。
単なるpython3スクリプトなので、python3とtmuxがあればうごくはず、です。
簡単に試したければこれでインストール:
pip3 install git+https://github.com/s417-lama/mpitx.git
使い方は
mpitx [OPTIONS]... -- [COMMANDS]...
こんな感じで、[OPTIONS]...の部分がmpiexecのオプションとしてそのまま渡されます。
コマンドとの区切りの--は必須になっていて、--のあとの[COMMANDS]...がtmuxの各端末上で実行され(ているように見え)ます。
--が必須なのはオプション解析をサボるためで、MPI実装固有のオプションが渡されてもそれをそのままmpiexecに投げられるようにするためです。
一方tmpiでは独自のオプション体系を持っていたので、mpiexecにそのまま渡したいパラメタがあると大変です(--hostfileとか諸々)。
例えば4プロセスでbashを起動したければ
mpitx -n 4 -- bash
gdbでデバッグしたければ
mpitx -- gdb --args ./a.out arg1 arg2 ...
こんな感じで簡単にできます。
実装について
細かい話ですが簡単にメモしておきます。
単に使う上では知らなくても困らないと思うので適宜読み飛ばしてください。
mpitxコマンドで立ち上げられた大元のプロセスをPとしましょう。
まず渡されたオプションはmpiexecにそのまま渡し、コマンドはmpitxのラッパを挟んでmpiexecに渡しておきます。
そしてmpiexecによって立ち上げられたMPIの子プロセスをC_i(iはMPIランク)とします。
次に、tmuxの各端末に標準入出力をプロキシするプロセスを立ち上げておきます。
MPIプロセスの数だけ端末を用意するので、これらのプロセスを同様にT_iと表記します。
ここで、PとT_iは同一のノードで実行されていますが、これらとC_iが同一のノードで実行されている保証はありません。
これらのプロセス間での情報のやり取りにはTCPソケットを用いています。
まず最初にP <---> C_i間の接続を確立し、次にP <---> T_i間の接続を確立します。
T_iではリバースシェルと同様の原理で、標準入出力をC_iへフォワードするためにC_iからの接続を待ち受けます。
T_iのホスト名およびポート番号はPを介してC_iに伝えられ、C_iからT_iへの接続が完了します。
この時点でC_iがmpitxに渡されたコマンドを実行し、T_iの端末からC_iのセッションをインタラクティブに操作することが可能になります。
TCPソケットを用いた実装である以上、マルチノードでmpitxを使うにはノード間がイーサネットで接続されていてソケット通信が通ることが条件になります。
接続できるポートが制限されていたりすると動かないかもしれないです。
最後に
gdbやtmuxなど、使い慣れたツールを気軽に使えた方がデバッグへの心理的障壁が下がるのでおすすめです。
MPI向けにはTotalViewのようなリッチなデバッガもあるようですが、オープンソースではないし使えるシステムも限られてくるので...。
主にデバッグ用途で紹介していましたが、マルチノードで各計算機の状態を確認する用途でもこれは結構便利です。

