長い文字列を tr に転送すると、中断と CPU スパイクが発生します。

長い文字列を tr に転送すると、中断と CPU スパイクが発生します。

MacOSヨセミテ(10.10.5)。私はこれがUnix / Linuxの一部であることを知っていますが...この質問はMacOS領域よりも関連性があると思いました。

私の端末は起動時に中断され始め、プロンプトを表示し、同時にCPU使用率が急増します。 CTRL-Cを押すとメッセージが表示されます(おそらく保留中/実行中の一部の.bashrc/.profile/etcを終了するように求められます)。

私は.bashrcの特定の行が中断を引き起こすことをすぐに見つけました。これは新しいものです(つまり、.bashrcで何も変更しておらず、すべてがうまく機能します)。だから、システムで何かが変更されました。

特定の長い文字列をパイピングすると、停止/ CPUスパイクが発生するようです。

紐をパイピングしてtr -d '\n'紐があることを確認して、これを再現できます。

macattack:~ $ openssl rand -base64 93  | tr -d '\n'
eDsz4JqFX/HAVjplNI6WDWwPRp9l9snp6UKp/pLn+GbBvJx0+ZMvSJFS/SuCwjMRRXVXfUvBdkaH1R0UgCr2UOf283MvHVTRusLFEVPcGCIz1t3sFMU/3foRzNWVmattp@macattack:~ $ openssl rand -base64 94 | tr -d '\n'
^C
mattp@macattack:~ $ openssl rand -base64 94 | tr -du '\n'
^C

trがぶら下がり始める魔法の数は93文字のようです。 opensslは中断されません(つまり、すべての送信パイプを削除した場合tr)。しかし、元の問題の行の長さは異なりました。

mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log;' | tr -d '\n'
^C-bash: echo: write error: Interrupted system call

mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log' | tr -d '\n'

mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log' | wc -c
     128
mattp@macattack:~ $

trこれは問題ではなく配管の問題かもしれません。同じ問題を再現できますsed(コマンドは意味がありません...中断のみが表示されます)。

mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log;'  | sed 's/\n/ /g'
^C-bash: echo: write error: Interrupted system call

mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log'  | sed 's/\n/ /g'
echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log
mattp@macattack:~

この問題に対する解決策が不足しています。
停止コマンドは、任意のCentos Linuxサーバーで正しく実行されます。最近まで、これらのコマンドはmacOSで正常に動作していました。私は以前にパイプがぶら下がっていた状況を経験したことがありません。入力の奇妙な文字が問題の原因だと思いましたが、opensslランダム文字列はそうでないとマークされています。 ulimitは同じ問題がない他のMacと同じです。

mattp@macattack:~ $ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 7168
pipe size            (512 bytes, -p) 1
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 709
virtual memory          (kbytes, -v) unlimited

dtrussこれを使用すると、trread_nocancel呼び出しが中断されるようです。

修正する

一緒に過ごす。ハンギングとパイプのバッファサイズに関するコメントが見つかりました。ここから盗んだテストスクリプト: パイプバッファはどれくらい大きいですか?

問題が発生すると、実行時にパイプバッファは128バイトであるとマークされます。再起動し(問題が一時的に消えた)、パイプバッファは65536バイトです。下記のテスト出力をご覧ください。

今問題は、「何か」がシステムのパイプバッファサイズを減らす理由/方法です。

問題がある

$ /bin/bash -c 'for p in {0..18}; do pipe-buffer-test.sh $((2 ** $p)) 0.5; done'
write size:          1; bytes successfully before error: 128
write size:          2; bytes successfully before error: 128
write size:          4; bytes successfully before error: 128
write size:          8; bytes successfully before error: 128
write size:         16; bytes successfully before error: 128
write size:         32; bytes successfully before error: 128
write size:         64; bytes successfully before error: 128
write size:        128; bytes successfully before error: 128
write size:        256; bytes successfully before error: 0
write size:        512; bytes successfully before error: 0
write size:       1024; bytes successfully before error: 0
write size:       2048; bytes successfully before error: 0
write size:       4096; bytes successfully before error: 0
write size:       8192; bytes successfully before error: 0
write size:      16384; bytes successfully before error: 0
write size:      32768; bytes successfully before error: 0
write size:      65536; bytes successfully before error: 0
write size:     131072; bytes successfully before error: 0
write size:     262144; bytes successfully before error: 0

再起動後(問題が一時的に消える)

$ /bin/bash -c 'for p in {0..18}; do pipe-buffer-test.sh $((2 ** $p)) 0.5; done'
write size:          1; bytes successfully before error: 65536
write size:          2; bytes successfully before error: 65536
write size:          4; bytes successfully before error: 65536
write size:          8; bytes successfully before error: 65536
write size:         16; bytes successfully before error: 65536
write size:         32; bytes successfully before error: 65536
write size:         64; bytes successfully before error: 65536
write size:        128; bytes successfully before error: 65536
write size:        256; bytes successfully before error: 65536
write size:        512; bytes successfully before error: 65536
write size:       1024; bytes successfully before error: 65536
write size:       2048; bytes successfully before error: 65536
write size:       4096; bytes successfully before error: 65536
write size:       8192; bytes successfully before error: 65536
write size:      16384; bytes successfully before error: 65536
write size:      32768; bytes successfully before error: 65536
write size:      65536; bytes successfully before error: 65536
write size:     131072; bytes successfully before error: 0
write size:     262144; bytes successfully before error: 0

答え1

カーネルバッファリークに関する@Barmarのコメントに基づいて、現在非OS kextを調べました。最近インストールされたBlockBlockが比較的新しいものがあることに気づきました。https://objective-see.com/products/blockblock.html)。

BlockBlockを削除して再起動しましたが、問題は再び表示されませんでした。したがって、この場合、BlockBlockは犯人であり、作成者にこの問題を報告しました。

しかし、これは原因を特定するためにほとんど推測と確認アプローチをとっているため、特に満足できません。正直なところ、根本的な原因をよく理解していません(OSに関する限り)。 )、これは将来、これらの問題をより賢明に解決しないことを意味します。

誰もがこの問題を経験し、何が起こっているのかをさらに説明し、トラブルシューティングを提供できる場合は、「BlockBlockの削除」よりも良い答えになります。

関連情報