foo
端末で実行したいプロセスがあります。同時にプロセスが消費するCPUの量を確認することに興味があるので、に行き、列でプロセスtop
(foo
この名前を持つプロセスは1つのみ)を%CPU
見つけ、その値を日付/時刻スタンプを含むファイルを抽出し、値を1行に配置します。これらの値を使用して、ワークロードをよりよく理解するためのグラフといくつかの説明統計を生成できますfoo
。
また、このCPU負荷の抽出が毎秒n
(例えば毎秒)続行されることを望み、開始時に開始され、処理が完了したら終了することをn=1
望みます。foo
foo
私が理解したのは、このためには両方のプロセスが同時に起こる必要があるということです。
これを達成する方法についてのアイデアはありますか?必要に応じて、最後の手段としてシェルスクリプトを端末に直接コマンドとして提供するのが最善です。
編集する:以下のコメントのリンクは、値を取得する方法への答えですtop
。ただし、「基本」プロセスとトレースプロセスという2つのプロセスの実行をシミュレートする方法を理解する必要があります。トレース・プロセスは、基本プロセスの開始および終了時にそれぞれ開始および終了します。
答え1
主な部分はリンク付きのコメントで答えてくれるので質問
私はあなたの質問の残りの部分に答えようとします。
「基本」プロセスをどのように実行するかわからないので、ラッパースクリプトコンテキストとシステムコンテキストでこれについて説明します。
しかし、その前に誤解を解決したいと思います。
実際、これらのプロセスを実行することはできません。同時に、基本プロセスが開始されるのを待つか(以前にウォッチャーを起動した場合)、後でウォッチャーを起動する必要があります。これにより、ウォッチャーは既定のプロセスがすでに実行されていると想定できます。
システム:
プロセスがsystemdによって管理されている場合、そのデバイスのサービスファイルがある可能性が高くなります。
これらのファイルは通常ディストリビューションに保存されるか、/etc/systemd/system/
ディストリビューション/usr/lib/systemd/system/
によって異なります。
これらのファイルを操作する最も簡単な方法は、次の構文を使用することです。
systemctl edit <service name> --full
指定すると、--full
直接編集(デフォルトではブラインド編集)を実行するのではなく、元のファイルのコピーを変更でき、この特定のサービスを初めて使用する場合に便利です。
実際に修正すべき事項は、ExecStartPre=
またはExecStartPost=
ExecStopPost=
ExecStartPre
指定された操作を実行します(観察者スクリプト/プログラムの実行)。今後サービスが開始されました
ExecStartPost
指定された操作を実行します(観察者スクリプト/プログラムの実行)。後ろにサービスが開始されました起動が成功した場合のみ
同様にExecStopPost
、指定された操作が実行されます。後ろにサービスが終了しました(で定義された操作が完了しましたExecStop
)。
以下は例です。
[Unit]
Description=Foo
[Service]
# Start the watcher
ExecStartPre=/usr/bin/foo-watcher
# Actual service start
ExecStart=/usr/sbin/foo-daemon start
# Actual service stop
ExecStop=/usr/sbin/foo-daemon stop
# Stop the watcher
ExecStopPost=/usr/bin/pkill foo-watcher
[Install]
WantedBy=multi-user.target
ExecStopPost
名前ではなくPIDでプロセスを終了する方が良いかもしれませんが、これを行わない製品の例が多いため、同じ名前のプロセスを誤って終了する危険があることに注意してください。
スクリプトメソッドの起動:
デフォルトでは、起動 bash スクリプトでプロセスをラップする必要があります。このスクリプトを使用して複数のプロセスを管理するには、ウォッチャーと基本プロセスをバックグラウンドに配置するのが便利です。
フル機能の管理スクリプトを作成する予定の場合は、これらのバックグラウンドプロセスのPIDも追跡する必要があります。
簡単な例は次のとおりです。
#!/bin/bash
# Do we have too many arguments(Or too few)? Exit if so.
if [ $# -ne 1 ]
then
exit 1
fi
if [ "$1" == "start" ]
then
# Start the watcher as a job and save the pid to a variable
/usr/bin/foo-watcher &
wPid="$!"
# Start the main process as a job and save the pid to a variable
/usr/bin/foo-daemon &
mPid="$!"
# Save the PIDs to a file, make sure than the main process
# (foo-daemon) doesn't already do this for us
/usr/bin/echo "$wPid" > /var/run/foo-watcher.pid
/usr/bin/echo "$mPid" > /var/run/foo-daemon.pid
elif [ "$1" == "stop" ]
then
# Grab PID from files and store in a variable, since kill
# doesn't read from stdin
wPid="$(/usr/bin/cat /var/run/foo-watcher.pid)"
mPid="$(/usr/bin/cat /var/run/foo-daemon.pid)"
# Kill the processes
/usr/bin/kill "$wPid"
/usr/bin/kill "$mPid"
# Delete pid files
/usr/bin/rm -f /var/run/foo-watcher.pid
/usr/bin/rm -f /var/run/foo-daemon.pid
else
# We didn't get a valid input, exit (maybe display help?)
exit 1
fi
基本プロセスの終了を制御できない場合(dd
そのプロセスまたはrm
同様のプロセスがタスクを実行して終了する場合)、以下はこの状況を処理するために上記のスクリプトを変更したものです。
#!/bin/bash
# Start the watcher as a job and save the pid to a variable
/usr/bin/foo-watcher &
wPid="$!"
# Start the main process as a job and save the pid to a variable
/usr/bin/foo-daemon &
mPid="$!"
while true
do
#Check ps for the process via PID
status="$(ps -q "$mPid" | wc -l)"
#Did ps return anything, if not, kill the watcher
if [ "$status" -eq 1 ]
then
kill "$wPid"
exit 0
fi
#Interval to check if process is running in seconds
sleep 1
done