跟踪程序的 CPU 負載
我有一個
foo
想從終端執行的程序。同時,我有興趣確定這個程序消耗了多少 CPU,所以我想,例如,進入top
,找到程序foo
(只有一個程序會有這個名稱),從%CPU
列,並將該值附加到具有日期時間時間戳和提取值在一行上的文件中。使用這些值,我可以生成一個繪圖和一些描述性統計數據,以更好地了解工作量foo
。此外,我希望這種 CPU 負載提取每秒
n
(例如每秒n=1
)繼續進行,並且我希望它在開始時foo
開始並在foo
完成處理時結束。據我了解,這需要兩個程序同時進行。
關於如何實現這一目標的任何想法?最好作為向終端提供的直接命令——必要時使用 shell 腳本作為最後的手段。
編輯:下面評論中的連結回答瞭如何從中檢索值
top
。但是,我仍然需要確定如何模擬執行兩個程序——一個“主”程序和一個跟踪程序,跟踪程序分別在主程序開始和結束時開始和結束。
由於此問題的主要部分已通過指向此問題的連結在評論中得到回答
我將嘗試回答您問題的其餘部分。
由於我不知道您是如何執行“主”程序的,因此我將在包裝腳本上下文和 systemd 上下文中對此進行介紹
但是在此之前,我想解決一個誤解;
您不能真正同時執行這些程序,您應該等待主程序啟動(如果您之前啟動了觀察者)或之後啟動觀察者,這將允許觀察者假設主程序已經在執行。
系統:
如果您的程序由 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/cat "$wPid" > /var/run/foo-watcher.pid /usr/bin/cat "$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