
昨日はコンパイルしようとしました。根ソースのパッケージ。 6コアモンスターマシンでコンパイルしていたので使い続けることにしましたmake -j 6
。最初はコンパイルがスムーズで非常に高速でしたが、ある時点でmake
1つのコアで100%CPUを使用すると中断されました。
Googleを少し探していました。これROOT掲示板に投稿してください。このコンピュータを自分で作ってみると、ヒートシンクを正しく取り付けずにCPUが過熱するなどの心配があります。残念ながら、私が働く場所に入れることができる冷蔵庫はありません。 ;-)
パッケージをインストールlm-sensors
してmake -j 6
再実行しましたが、今回はCPU温度を監視しました。温度は非常に高いですが(ほぼ60℃)、決して高い温度や臨界温度を超えません。
私はrunningを試しましたが、make -j 4
コンパイル中のある時点でmake
今回は別の場所で再び停止しました。
最後に、これをコンパイルして実行しましたが、make
うまくいきました。私の質問は:なぜ停止しますか? 2つの異なる場所で停止するため、競合状態の種類があると思いますが、make
提供されているオプションを考慮すると、すべてを正しい順序でインポートするのに十分スマートでなければならないと思いました-j
。
答え1
この正確な質問に対する答えはありませんが、何が起こるのかについてのヒントを提供できます。 Makefileに依存関係がありません。
例:
target: a.bytecode b.bytecode
link a.bytecode b.bytecode -o target
a.bytecode: a.source
compile a.source -o a.bytecode
b.bytecode: b.source
compile b.source a.bytecode -o a.bytecode
呼び出すと、make target
すべてが正しくコンパイルされます。a.source
コンパイルは最初に実行されます(任意ですが決定論的に)。その後、b.source
コンパイルします。
ただし、make -j2 target
両方のcompile
コマンドが同時に実行される場合。実際、Makefileの依存関係が破損していることがわかります。 2番目のコンパイルではコンパイルさa.bytecode
れたと仮定しますが、依存関係には表示されません。したがって、エラーが発生する可能性が高いです。正しい依存関係行は次b.bytecode
のようになります。
b.bytecode: b.source a.bytecode
質問に戻って、運が悪いと、依存関係がないため、命令が100%CPUループで中断される可能性があります。これがおそらくここで起こっていることでしょう。順次ビルドでは欠落している依存関係を明らかにすることはできませんでしたが、並列ビルドではすでにこれを明らかにしました。
答え2
これは非常に古い質問であることを知っていますが、まだ検索結果の上部に表示されるので、私の解決策は次のとおりです。
GNU make には、 make とその再帰サブプロセスが指定されたコア数を超えないようにするための Job Server メカニズムがあります。 http://make.mad-scientist.net/papers/jobserver-implementation/
すべてのプロセスが共有するパイプに依存します。追加の子プロセスをフォークしたい各プロセスは、まずパイプでトークンを使用し、完了したら廃棄する必要があります。子プロセスが消費したトークンを返さない場合、最上位のmakeは永久に停止し、返されるのを待ちます。
https://bugzilla.redhat.com/show_bug.cgi?id=654822
「sed」がGNU sedではなく、SolarisシステムでGNU makeを使用してbinutilsをビルドすると、このエラーが発生しました。この問題は、sed = = gsedがシステムsedよりも優先されるようにPATHを修正することによって解決されました。しかし、sedがパイプからトークンを消費する理由はわかりません。
答え3
make
デッドロックを作ったようです。を使用すると、ps -ef
次のプロセスが原因のようです。
ルート695 615 1 22:18? 00:00:00 prebuild-j32を作成 ルート2127 695 20 22:18 ? 00:00:04 make -f Makefile.prenobuild
各子プロセスが実行する操作を確認すると、子プロセスはファイル記述子4に書き込まれますが、親プロセスはすべての子プロセスが終了するのを待っていることがわかります。
root@ltzj2-6hl3t-b98zz:/# strace -p 2127 strace: 接続プロセス 2127 書き込み(4,"+",1
root@ltzj2-6hl3t-b98zz:/# strace -p 695 strace: プロセス 695 接続 {{しばらく 4(-1, }})
ファイル記述子4はパイプである。
root@ltzj2-6hl3t-b98zz:/# ls -la /proc/2127/fd/4 l-wx------ 1 root root 64 Sep 3 22:22 /proc/2127/fd/4 -> 'pipe:[1393418985]'
パイプは親プロセスと子プロセスの間にのみ存在します。
root@ltzj2-6hl3t-b98zz:/#lsof 1393418985 | 695 ルート 3r FIFO 0,12 0t0 1393418985 パイプを作る 695 ルート 4w FIFO 0,12 0t0 1393418985 パイプを作る 2127 ルート 3r FIFO 0,12 0t0 1393418985 パイプを作る 2127 ルート 4w FIFO 0,12 0t0 1393418985 パイプを作る
したがって、2127は695に再びパイプに出力を追加しようとするようですが、695は保留状態なwait4()
のでパイプを消去しません。
cat を使用してシェルからパイプをクリアすると、ビルドが期待どおりに再開され、完了します。
root@ltzj2-6hl3t-b98zz:/#猫/proc/695/fd/3 ++++++++++++++++++++++++++++++++++
ビルドがブロック解除され、引き続き実行されます...
私の初期の理解は間違っていましたが、さらに調査した後、最終的に次のLinuxカーネルの欠陥が見つかりました。
一時停止方法の正確な説明は次のとおりです。https://lore.kernel.org/lkml/1628086770.5rn8p04n6j.none@localhost/。
gnu make ソースコードに次の回避策を適用してカーネルパッチを待つこの問題を解決できます。
---a/src/posixos.c 2020-01-02 23:11:27.000000000-0800 +++ b/src/posixos.c 2021-09-18 09:12:02.786563319 -0700 @@-179,8+179,52 @@ jobserver_release(int is_fatal) { 整数r; - EINTRLOOP(r、write(job_fds [1]、&token、1)); - if(r != 1) +整数n; +文字b [32]; + +/* 複数の make サブプロセスによるデッドロックを回避するために、非ブロック書き込みを使用します。 + * また、ジョブを解放します。 */ + set_blocking(job_fds[1], 0); + memset(b,token,sizeof(b)); + n = 1; +同時に(n> 0) +{ + r =書き込み(job_fds [1]、b、n); +/* システムコールが中断されました。もう一度お試しください*/ + if ( r == -1 ) +{ + if (エラー番号 == EINTR) +継続; + + /* このプロセスと他のプロセスが両方ともパイプに書き込もうとしたのでここまで来ました。 + *まったく同じ時間で、パイプラインには1ページしか含まれていません。私たちは他人を失った + *プロセスが勝ちます(パイプに書き込む)。まず、この条件をリセットできます。 + *パイプから読みます。もちろん、これはさらに返す必要があることを意味します。 + *トークン。 */ + if ( errno == EWOULDBLOCK || errno == EAGAIN ) +{ + if ( jobserver_acquire(0) ) +{ +n++; + /*おそらく不可能に近いかもしれません... */ + if (n > 32) +割り込み; +継続; +} +} +} + if ( r == 0 ) /* 0バイトを書きましたが、エラーはありませんでしたので、もう一度お試しください */ +継続; + if(r> 0) +{ + n -= r; +継続; +} + break; /*他のすべてのエラーは中断されます。 */ +} + set_blocking(job_fds[1], 1); + + if(n != 0) { (致命的なら) pfatal_with_name(_("ジョブサーバーへの書き込み"));
答え4
make
システムは大丈夫かもしれませんが、これはビルドを並列に実行したときに発生する競合状態である可能性があります。
システムに問題が発生すると、並列ビルドを実行するときだけでなく、他の状況でもシステムがクラッシュしたりクラッシュしたりします。