跟踪进程的 CPU 负载

跟踪进程的 CPU 负载

我有一个foo想从终端运行的进程。同时,我有兴趣确定该进程消耗了多少CPU,因此我想进入top,找到该进程foo(只有一个进程具有此名称),从%CPU列,并将该值附加到文件中,并将日期时间时间戳和提取的值放在一行上。有了这些值,我可以生成一个图和一些描述性统计数据,以更好地了解工作量foo

此外,我希望这种 CPU 负载提取能够每秒继续一次n(例如每秒n=1),并且我希望它在foo开始时启动并在foo完成处理时结束。

据我了解,这需要两个过程同时进行。

关于如何实现这一目标有什么想法吗?最好作为直接命令向终端提供 shell 脚本,作为最后的手段(如有必要)。

编辑:下面评论中的链接回答了如何从 中检索值top。然而,我仍然需要确定如何模拟运行两个进程——一个“主”进程和一个跟踪进程,跟踪进程分别在主进程开始和结束时开始和结束。

答案1

因为主要部分是通过链接在评论中回答的问题

我将尝试回答你问题的其余部分。

由于我不知道您如何运行“主”进程,因此我将在包装器脚本上下文和 systemd 上下文中介绍这一点

但在此之前我想澄清一个误解:

您无法真正运行这些进程同时地,您应该等待主进程启动(如果您之前启动观察程序)或之后启动观察程序,这将允许观察程序假设主进程已经在运行。

系统:

如果您的进程由 systemd 管理,您很可能拥有该单元的服务文件。

这些文件通常存储在您的发行版中/etc/systemd/system//usr/lib/systemd/system/取决于您的发行版。

操作这些文件的最简单方法是使用以下语法

systemctl edit <service name> --full

指定--full将允许您修改原始文件的副本;而不是进行直接编辑(本质上是盲目编辑),如果您不熟悉此特定服务,这会很有用。

您需要进行的实际修改是添加一个ExecStartPre=orExecStartPost=和一个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

如果您无法控制主进程的退出(在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

相关内容