コンドルで実行中にミステリーセグフォールトを解くための方法/ツール
-
02-10-2019 - |
質問
コンピューティングクラスター(Condorを使用)を横切って実行されるCアプリケーションを書いています。問題のあるコードを明らかにするために多くの方法を試しましたが、役に立たない。
手がかり:
- 平均して、15マシンで2日間コードを実行すると、2つまたは3つのセグフォルトが得られます(信号11)。
- コードをローカルに実行すると、SegFaultが取得されません。ホームマシンで3週間近く走りました。
試み:
- メモリエラーなしでローカルで4日間Valgrindでコードを実行しました。
- プログラム状態の一部を出力できるように、自分の信号ハンドラーを定義することにより、SegFaultシグナルをキャプチャしました。
- SegFaultが発生したとき、BackTraceを使用して現在のスタックを印刷できます。
- 変数値を印刷できます。
- 現在の行番号に設定された変数を作成しました。
- また、問題がなくなるとセグフォーが発見されることを期待して、コードのチャンクをコメントしてコメントしようとしました。
悲しいことに、出力された行数はかなりランダムです。 Stacktraceで何ができるかは完全にはわかりません。 SegFaultが発生する関数のアドレスのみを記録すると仮定するのは正しいですか?
疑い:
- Condorがマシン全体でジョブを移動するために使用するチェックポインティングシステムは、メモリの腐敗により敏感であると思われます。これが、地元で見ない理由です。
- そのインデックスはバグによって破損しており、これらのインデックスがSEGFAULTを引き起こしていること。これは、SegFaultsがかなりランダムなライン数で発生しているという事実を説明します。
アップデート
これをさらに調査して、次のリンクを見つけました。
libsegfault -SegFaultsに関する状態データを自動的にキャッチおよび印刷するためのライブラリ。
GCCを使用したスタックバインディング(スタックトレース) セグフォルトをキャッチし、問題の指示の行番号を取得するためのチュートリアル。
更新2
グレッグは、コンドルのログを調べ、「セグフォールトをチェックポイントから実行可能ファイルを再起動するときとSegFaultsを相関させる」ことを提案しました。ログを見ると、再起動後すぐにSEGFAULTSが発生します。すべての障害は、ジョブがあるタイプのマシンから別のタイプに切り替えると発生するようです。
更新3
SEGFAULTは、コンドル提出ファイルの「要件」フィールドを問題に完全に消滅させることにより、ホスト間の違いによって引き起こされていました。
個々のマシンを設定できます。
requirements = machine == "hostname1" || machine == "hostname2"
または機械のクラス全体:
requirements = classOfMachinesName
要件の例を参照してください ここ
解決
可能であれば、デバッグでコンパイルし、GDBの下で実行します。または、コアダンプを取得してデバッガーにロードします。
MPICHには組み込みのデバッガーがあります。または、商用並列デバッガーを購入できます。
その後、コードを介してデバッガーで何が起こっているかを確認できます
他のヒント
セグフォルトが発生したときにコアダンプを作成できますか?その後、このダンプをデバッグして、コードがクラッシュしたときにコードの状態を把握しようとすることができます。
どの指示が障害を引き起こしたかを見てください。それは有効な指示でさえありましたか、それともデータを実行しようとしていますか?有効な場合、どのようなメモリにアクセスしようとしていますか?このポインターはどこから来ましたか。障害の位置を絞り込む必要があります(腐敗、腐敗を山積み、初期化ポインター、無効なメモリへのアクセス)。破損している場合は、破損した領域に巧妙なデータがあるかどうかを確認します(シンボルへのポインター、構造内の何かのように見えるデータなど)。メモリアロケーターには、いくつかの腐敗をデバッグするための機能が既に組み込まれている可能性があります(参照 MALLOC_CHECK_
Linuxまたは MallocGuardEdges
Mac OSで)。これらの一般的なケースは、free() 'dであるメモリを使用することです。したがって、malloc() / free()ペアを記録することが役立つ場合があります。
Condor_Compileツールを使用してコードをCondorチェックポイントコードで再リンクした場合、通常のリンクとは異なる方法でいくつかのことを行います。最も重要なことは、コードを静的にリンクし、独自のマロックを使用することです。もう1つの大きな違いは、コンドルが外国の機械でそれを実行することです。そこでは、環境が問題を引き起こすと予想されるものとは十分に異なる場合があります。
Condor_Compileによって生成された実行可能ファイルは、Condorシステムの外側のスタンドアロンバイナリとして実行可能です。 Condor_Compileから地元で、Condorの外で放出されたバイナリを実行している場合、SegFaultsはまだ表示されますか?
そうでない場合は、Condorがチェックポイントから実行可能ファイルを再起動したときにSegFaultsを相関させることができます(ユーザーログは、これがいつ発生するかを示します)。
あなたは私が考えていることのほとんどを試しました。私が提案する他の唯一のことは、多くのロギングコードの追加を開始し、エラーが発生している場所を絞り込むことができることを願っています。
あなたが言わないことの1つは、問題を解決する必要がある柔軟性の量です。たとえば、システムが停止してアプリケーションを実行してもらうことができますか?また、これらのクラッシュは解決するためにどれほど重要ですか?
私はあなたがそうすることの大部分を想定しています。これには多くのリソースが必要になる場合があります。
短期的なステップは、各変数の「アサート」(半手書き)を大量に配置して、望まないときに変更されていないことを確認することです。これは、長期的なプロセスを経るにつれて動作する可能性があります。
長期 - 2つのクラスターで実行してみてください(おそらく自宅のコンピューターとVM)。まだセグフォールトを見ていますか。 SEGFAULTSが表示されるまでクラスターサイズを増やさない場合。
最小構成で(セグフォールトを取得するため)に実行し、クラッシュするまですべての入力を記録します。記録した入力でシステムを自動化し、一貫性のある入力でクラッシュを取得できるまでそれらを調整します。
その時点で周りを見回します。それでもバグが見つからない場合は、それらの実行で収集したいくつかの追加のデータを再度尋ねる必要があります。