Terminal

跟踪程序的 CPU 負載

  • July 21, 2021

我有一個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

如果您無法控制退出的主程序(在執行某件事並退出的或類似程序的情況下)ddrm以下是對上述腳本的修改,可以處理這種情況。

#!/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

引用自:https://unix.stackexchange.com/questions/659196