データロギングアプリケーションを作成していますが、すべてが次のように始まります。
./program > out.bin
データコレクタは定期的にstdout出力ファイルを集計し、データを読み込みます。
問題は、IOストリームがバッファリングされ、一部のプログラムが毎秒1バイトでデータを出力する場合、実際にデータをフラッシュするのに長い時間(デフォルトの4kBバッファサイズ、最大4k秒)がかかることです。
私の質問は、stdout / pipe / printfバッファを外部から強制的にフラッシュする方法です。つまり、fflush(stdout)
。
私は次のような様々なウェブサイトを読みました。パイプラインでバッファリングをオフにするただし、IOパフォーマンス(測定)に大きな影響を与えるため、バッファを無効にすることはできません。
私は高性能生産ソリューションを探しており、常に次の基準を満たしています。
- プログラム(データプロデューサー)PIDは常に知られています。
- 出力は常に既知のパスを持つファイルです。
- データロギングプロセスには完全なルートアクセス権があります。
答え1
gdb -p PID -batch -ex 'p fflush(stdout)'
すべてのデバッグとハッキングと同様に、YMMV。
答え2
実行中のプログラムのソースコードにアクセスできますか?
理論的には不可能ではありませんが、ランダムな実行可能ファイルを強制的に更新することは非常に困難です。fflush
コードで関数とパラメータを見つけて、プログラムの実行を中止し、stdout
呼び出しをスケジュールしてからfflush
実行を続行する必要があります。プログラムが共有ライブラリを使用している場合、少なくとも最初の部分は合計を見つけるfflush
のが簡単になりますが、stdout
まだ呼び出しをシミュレートする必要があります。また、不明なバイナリの場合、stdioを使用するのか、それとも独自のバッファリングメカニズムを実装しているのかはわかりません。出力ファイルのパスを知ることは役に立ちません。
gdb
コマンドを使用してattach
プロセスに接続してみることができます。たぶんgdb
関数がfflush
呼び出されるかもしれません。
プログラムのソースコードがある場合は、バッファをフラッシュし、バッファをフラッシュする必要があるときにシグナルを送信するシグナルハンドラを実装します。
パイプを試してみてください。出力がパイプの場合、プログラムはバッファリングできない可能性があります。それに変える
./program | your_program > out.bin
プログラムは入力を受け取り、バッファリングし、信号が受信されるとバッファをフラッシュすることができます。それでもCPUオーバーヘッドは追加されますが、ディスクオーバーヘッドは追加されません。
答え3
user313992の答えはほぼ最善のアプローチであり、少なくとも他のバイナリでも機能する可能性があります。説明:gdb開始、出力なし、pidに追加、フラッシュ実行、暗黙的:終了。
少し改善してください。
gdb -batch -p $PID -ex 'call (int)fflush(stdout)' -ex 'call (int)fflush(stderr)'
これの利点は、正しい戻り型を保証し、何も印刷されないことです。この点を念頭に置いて、stderrフラッシュも追加しました。
この方法は、他のファイルハンドルが内部的に使用されている場合、またはこれらのハンドルがGDBが解析できないマクロの場合は機能しません。
独自のアプリケーションを作成する最良の方法は次のとおりです。
extern
フラッシュを実行するためのすべての機能を提供します(call
上記の例に示すように、マクロまたは他のファイルハンドルに関連するすべての問題を削除し、すでにGDBで編集可能です)- プログラムの有用な状態でこの関数を呼び出してください。
- 信号ハンドラを登録します
SIGUSR1
。たとえば、関数を呼び出すと、そのシグナルを送信して強制的に更新できます。 - ファイルが存在するかポーリング(存在する場合は削除後に更新)
- メッセージ/セマフォ/ソケット/...のポーリング
- 信号ハンドラを登録します