ディレクトリ内のすべてのファイルの変更を監視したいと思いますinotifywait
。inotifywait
FIFOバッファに書き込む必要があり、その後正常に読み取ることができます。比較的多数のイベントを試みている間、理解したいボトルネックがいくつか発生しました。
変化は常にによって発生しますtouch {0000..9999}testfile
。ボトルネックは、すべてのファイルイベントをキャプチャできないことです。
出力をファイルにリダイレクトすると、すべてがinotifywait
期待どおりに記録されます。
inotifywait -q -m ./
書き込み端末は、約5000〜8000個のファイルに対してCREATE、OPEN、ATTRIB、CLOSEをキャプチャします。 「画面に書く」が非遮断になるほど速くないと思いますか?
cat
( ) にパイプすると、inotifywait... | cat | ... | cat
ある時点でそのすべての項目が終了します。だから私はパイプがバッファであるように見えますが、それがどのように機能するのか、何を見つけるべきかさえ理解できません。誰かがこれを説明できますか?
私もここで見つけた「ソリューション」を使用しました。pv -q -B 1g
バッファ(または)として使用されますbuffer
。
inotifywait -q -m ./ | BUFFER | \
while read line; do
# Do something with $line or ...
sleep 1
done
すべてのファイルイベントが処理されたことを確認する方法は?私はbash桟橋についての私の小さなゲームがより深い限界を発見したという感じを受け、それについてより多くの洞察力を持っていたいと思います。
答え1
出力がinotifywait -q -m ./
リダイレクトされず、端末エミュレータで実行されると、出力は pty デバイスに移動されます。デバイスはpty
パイプにやや似ていますが、端末などの相互作用を促進する機能を追加したプロセス間通信の一形態です。
そのptyの反対側に「管路」、端末エミュレータはinotifywait
作成した内容を読み、画面にレンダリングします。レンダリングは複雑でCPU時間を占めます。
端末エミュレータがパイプを埋めるよりも遅くパイプを空にする場合inotifywait
、pty管路あなたはいっぱいになります。パイプのようにいっぱいになると、write()
メモリに再利用可能なスペースがあるまで書き込みプロセスがブロックされます(システムコールは返されません)。「管路」。
私のLinuxバージョンでは、一度に1バイトずつ書き込むと、もう一方の端がブロックされる前に何も読み取らずにptyデバイスに19457バイトを書き込むことができることがわかりました。
$ socat -u 'exec:dd bs=1 if=/dev/zero,pty' 'exec:sleep inf,nofork' &
[1] 1247815
$ pkill -USR1 -x dd
19458+0 records in
19457+0 records out
19457 bytes (19 kB, 19 KiB) copied, 14.7165 s, 1.3 kB/s
一度に2バイトを書くと19458バイト、一度に256バイトを書くと19712バイトです。端末をネイティブモードに設定するか、送信されたデータに改行文字を含めると(CRLFに変換されるため)、それは別の値になります。
とにかくバッファサイズをカスタマイズすることはできないと思います。
inotifywait
使用inotifyイベントリストを取得するためのAPI。inotify(7)
マニュアルページには次のものがあります。
次のインターフェイスを使用して、inotifyが消費するカーネルメモリの量を制限できます。
/proc/sys/fs/inotify/max_queued_events
このファイルの値は、アプリケーションがinotify_init(2)を呼び出してそのInotifyインスタンスに待機できるイベント数の上限を設定するために使用されます。この制限を超えるイベントは削除されますが、IN_Q_OVERFLOW イベントは常に生成されます。
標準出力がinotifywait
ブロックされると、write()
カーネルはこのキューに入れるイベントを処理できません。キュー自体がいっぱいになると、イベントは削除されます。
私のシステムでは
$ sysctl fs.inotify.max_queued_events
fs.inotify.max_queued_events = 16384
今これを行う:
inotifywait -q -m ./ | cat
今回はとの間にパイプがあり、inotifywait
端末エミュレータcat
の間にはptyがあります。cat
パイプは各パイプでptysより大きく(Linuxではデフォルトでは64KiBですが使用可能です)、これをfs.pipe-max-size
sysctl値(デフォルトでは1MiB)に上げますfcntl(fd, F_SETPIPE_SZ, newsize)
。
したがって、私たちはinotifywait
ブロックwrite()
の前にこれらの2つのバッファを埋める必要があります。また、cat
一部のデータは、独自の読み取りバッファから読み取られ、書き込まれるのを待ちます。
コンテンツを追加するたびに、追加の| cat
バッファスペース(最小64KiB以上)を追加します。
使用すると、pv -q -B 1g
データpv
は内部的にバッファリングされます。
これは、入力を処理するためにはるかに少ない作業を行う必要があるため、端末エミュレータよりも速く入力を読み込みますが、十分に速く読み込み、復号化、またはフォーマットcat
できない場合は、一部のイベントを削除できます。pv
inotifywait
イベントが削除される可能性を最小限に抑えるには、次のようにします。
- 増加する
fs.inotify.max_queued_events
- 遅い消費者に出力を送信しない場合、
inotifywait
またはこの場合は十分なバッファリングを追加してください。 - フィルタを調整して興味のある
inotifywait
イベントのみを選択してください。 inotifywait
出力消費者に低い優先順位が与えられていないことをnice
確認してください。