前言:

前面给大家分享过一个工作中用到的编译拷贝脚本,其实工作中还有一些其他工具的使用,今天再来分享一个自己纯手工的CPU监控的脚本。大家可以结合上篇文章与本篇文章一起学习shell。

主要实现功能:

  • 1.监控指定进程是否运行
  • 2.读取该进程所在当前CPU的占用率,5s一次的执行频率计算当前进程 5分钟 10分钟 15分钟的平均cpu占用率
  • 3.计算该进程下用PID排序的前十个线程的 5分钟 10分钟 15分钟的平均cpu占用率

作者:良知犹存

转载授权以及围观:欢迎关注微信公众号:羽林君

或者添加作者个人微信:become_me


情节介绍:

在工作中,我们会对调试的进程以及线程进行性能分析并进行调优,通常我们使用linux下很多的工具包例如,perf 性能分析工具,以及剖析工具 GNU profiler(gprof 可以为 Linux平台上的程序精确分析性能瓶颈。gprof精确地给出函数被调用的时间和次数,给出函数调用关系)。

当然现在运维以及自动驾驶里面工作对性能分析工具熟悉也要很多要求,举例展示一个自动驾驶相关的系统工程师需要掌握的一些性能分析工具,包含speccpu、fio、iperf、stream、mlc、lmbench、erf、emon/Vtune等工具及相关调优手段,以后有时间再给大家一一介绍这些使用的性能分析工具。

今天呢,没有过多描述这些工具,因为我遇到的情况是没有这些工具,所以为了实现一个进程监控,我自己写了一个脚本,今天主要给大家分享,如果你工作中,需要一个性能监控的要求,但是你使用的环境中没有这些工具,此外你的环境支持shell脚本,那么这篇文章应该对你有所帮助。

好了,言归正传,接下来我给大家分享我写这些脚本使用的技术,以及最终实现的情况。

下图是脚本执行的流程图:

脚本内容:

#!/bin/bash

#一共11个数据 第0个是总的cpu计算 第1-10是线程前十个的排序
# 0 1 2 3 4 5 6 7 8 9 a b
cpu_sum_info=(0 0 0 0 0 0 0 0 0 0 0 0)
cpu_5mi_info=(0 0 0 0 0 0 0 0 0 0 0 0)
cpu_10m_info=(0 0 0 0 0 0 0 0 0 0 0 0)
cpu_15m_info=(0 0 0 0 0 0 0 0 0 0 0 0)
cnt=0 function GetPID #User #Name
{ PsUser=$1 PsName=$2 PID=`ps -u $PsUser|grep $PsName|grep -v grep|grep -v vi|grep -v dbx\n|grep -v tail|grep -v start|grep -v stop |sed -n 1p |awk '{print $1}'` #echo $PID
return $PID }
function GetCpu
{
# CpuValue=`ps -p $1 -o pcpu |grep -v CPU | awk '{print $1}' | awk -F. '{print $1}'`
CpuValue=`top -p $1 -bn 1 | awk 'NR == 8 {print $9}'| awk -F. '{print $1}'`
# echo "cpu all use "$CpuValue "%" return $CpuValue
}
function SumCpuAverage
{
sum_value=$1
cnt=$2
# echo " "$sum_value $cnt
((aver=sum_value/cnt))
# echo "aver="${aver}
return $aver
}
function float() {
bc << EOF
num = $1;
base = num / 1;
if (((num - base) * 10) > 1 )
base += 1;
print base;
EOF
echo ""
return $base
} while true
do
date
GetPID root exe #修改对应的用户和进程名 echo $? if [ -n "$PID" -a -e /proc/$PID ]; then
echo "process exists"
else
exit 0
fi if ps -p $PID > /dev/null
then
echo "$PID is running"
# Do something knowing the pid exists, i.e. the process with $PID is running
else
exit 0
fi GetCpu $PID single_value=$?
echo -e "\033[0;42m cpu used process=" $single_value "% \033[0m" ((cpu_sum_info[0]=cpu_sum_info[0]+single_value))
echo "sum 0 = " ${cpu_sum_info[0]}
echo "all cpu used" # ps -Tp $PID -o pcpu,pid,lwp | awk 'NR>2{print line}{line=$0} END{print line}' | sort -rn -k1 | head -n 10
top -Hp $PID -bn 1 | awk 'NR>8{print line}{line=$0} END{print line}' | sort -rn -k1 # index=1
for loop in 1 2 3 4 5 6 7 8 9 10
do
var="NR == $((${loop}+8)) {print \$9}"
# echo "loop" $loop $var # single_value=$(ps -Tp $PID -o pcpu,pid,lwp| awk 'NR>2{print line}{line=$0} END{print line}' | sort -rn -k1 | head -n 10 | awk "$var" | awk -F. '{print $1}')
single_value=$(top -Hp $PID -bn 1 | awk 'NR>8{print line}{line=$0} END{print line}' | sort -rn -k1 | awk "$var" | awk -F. '{print $1}') # single_value=$(ps -Tp $PID -o pcpu,pid,lwp| awk 'NR>2{print line}{line=$0} END{print line}' | sort -rn -k1 | head -n 10 | awk "$var")
# float $single_value
# single_value=$?
# cpu_sum_info[$loop] = `expr ${cpu_sum_info[$loop]} + ${single_value}` # ((cpu_sum_info[$loop]+=single_value))
cpu_sum_info[$loop]=$((cpu_sum_info[$loop]+single_value)) echo "sum" $loop "=" ${cpu_sum_info[$loop]}
# let index+=1
done ((cnt+=1))
echo "cnt = "$cnt
if [ $((cnt%60)) -eq 0 ]
then
for loop in 0 1 2 3 4 5 6 7 8 9 10
do
SumCpuAverage ${cpu_sum_info[$loop]} ${cnt}
cpu_5mi_info[$loop]=$?
echo -e "\033[0;41m cpu_5mi_info" $loop "="${cpu_5mi_info[$loop]} "\033[0m"
done
echo -e " " fi
if [ $((cnt%120)) -eq 0 ]
then
for loop in 0 1 2 3 4 5 6 7 8 9 10
do
SumCpuAverage ${cpu_sum_info[$loop]} ${cnt}
cpu_10m_info[$loop]=$?
echo -e "\033[0;42m cpu_10m_info="${cpu_10m_info[$loop]} "\033[0m"
done echo -e " " fi
if [ $((cnt%180)) -eq 0 ]
then
for loop in 0 1 2 3 4 5 6 7 8 9 10
do
SumCpuAverage ${cpu_sum_info[$loop]} ${cnt}
cpu_15m_info[$loop]=$?
echo -e "\033[0;43m cpu_15m_info="${cpu_15m_info[$loop]} "\033[0m"
done
echo -e " "
fi
sleep 5
done

以上是monitor.sh 的内容,主要分为几块:

通过进程名称查询对应该进程的PID:

function GetPID #User #Name
{ PsUser=$1 PsName=$2 PID=`ps -u $PsUser|grep $PsName|grep -v grep|grep -v vi|grep -v dbx\n|grep -v tail|grep -v start|grep -v stop |sed -n 1p |awk '{print $1}'` #echo $PID
return $PID
} GetPID root exe #修改对应的用户和进程名

这个部分是的核心是一条组合命令,

  • ps -u $PsUser

进行指定用户的进程查询

  • grep $PsName

进行指定名称进程搜索

  • grep -v grep 等

去除掉grep等其他的搜索命令的影响

  • sed -n 1p

1p 打印第一行,p 功能为打印

-n 表示静默模式,一般sed都有把所有读到的行打印出来,如果不加这个参数,它将一行行打印读到的,并且由于 1p 会重复打印第一行;

  • awk '{print $1}'

把第一列的参数打印出来

查询指定进程是否存在:

if [ -n "$PID" -a -e /proc/$PID ]; then
echo "process exists"
else
exit 0
fi if ps -p $PID > /dev/null
then
echo "$PID is running"
# Do something knowing the pid exists, i.e. the process with $PID is running
else
exit 0
fi

这里面使用了proc里面查询以及ps命令进行查询 第一步得到的PID是否存在。

其中 > /dev/null 表示一个黑洞位置,代表linux的空设备文件,所有往这个文件里面写入的内容都会丢失,表示不打印输出数据。

获得存在的进程的总cpu占用率:

function GetCpu
{ CpuValue=`top -p $1 -bn 1 | awk 'NR == 8 {print $9}'| awk -F. '{print $1}'` return $CpuValue
} GetCpu $PID single_value=$?
echo -e "\033[0;42m cpu used process=" $single_value "% \033[0m"

重要命令介绍:

  • top -p $1 -bn 1

    使用top命令进行 查询指定的PID CPU 占用率信息,并且只执行一次之后退出(top命令默认是交互模式,无法进行退出,所以此处设置执行之后退出)。

  • awk 'NR == 8 {print $9}'



    这条命令是输出数据的第8行 第9列,至于为什么要这么输出。这个需要大家去手工去看你需要PID CPU数据的具体行列。这里我的第8行是指定PID下的CPU详细数据的一行,所以我输出了第8行,记住中间的空行也算一行。

这里我执行了,第9列的输出,同时也测试了10列的输出,大家配合输出数据的不同,也可以得出自己需要的对应那一列。

  • awk -F. '{print $1}'

这个也很熟悉,-F指定分割符号,这里我选择了.,去除这个符号的原因是shell脚本执行浮点计算比较麻烦,需要另写函数转换,上面大家应该看到我脚本里面写了这个转换函数,但是我的设备里面没有支持里面的一下操作特性,所以最终无法实现,只是在PC端实现,在我实际设备中,我计算的CPU占用率是去掉小数点的数据,损失了计算精度。

获得存在的进程的各个线程cpu占用率:



for loop in 1 2 3 4 5 6 7 8 9 10
do
var="NR == $((${loop}+8)) {print \$9}"
single_value=$(top -Hp $PID -bn 1 | awk 'NR>8{print line}{line=$0} END{print line}' | sort -rn -k1 | awk "$var" | awk -F. '{print $1}') cpu_sum_info[$loop]=$((cpu_sum_info[$loop]+single_value))
echo "sum" $loop "=" ${cpu_sum_info[$loop]}
done

重要命令介绍:

  • top -Hp $PID -bn 1

指定进程下面所有的线程打印输出一次并退出top命令。

  • awk 'NR>8{print line}{line=$0} END{print line}'

配合这张图大家应该会容易看一些,这个部分是使用 awk命令,把top命令头信息去除掉,从第8行开始打印剩余数据。

  • sort -rn -k1

这个部分是进行排序,其中-r 以相反的顺序来排序,-n 依照数值的大小排序,-k1是使用第一排数据进行排列。

var="NR == $((${loop}+8)) {print \$9}"
awk "$var"

这个部分因为有特殊字符,所以就用黑色代码进行引用。这个部分就是使用awk命令,打印输出排好序的前10行每一行的线程cpu数据。

  • awk -F. '{print $1}'

这个部分参考上一处介绍。

进行变量操作,并进行5分钟、10分钟、15分钟平均值计算

function SumCpuAverage
{
sum_value=$1
cnt=$2
((aver=sum_value/cnt))
return $aver
} ((cnt+=1))
echo "cnt = "$cnt
if [ $((cnt%60)) -eq 0 ]
then
for loop in 0 1 2 3 4 5 6 7 8 9 10
do
SumCpuAverage ${cpu_sum_info[$loop]} ${cnt}
cpu_5mi_info[$loop]=$?
echo -e "\033[0;41m cpu_5mi_info" $loop "="${cpu_5mi_info[$loop]} "\033[0m"
done
echo -e " " fi
if [ $((cnt%120)) -eq 0 ]
then
for loop in 0 1 2 3 4 5 6 7 8 9 10
do
SumCpuAverage ${cpu_sum_info[$loop]} ${cnt}
cpu_10m_info[$loop]=$?
echo -e "\033[0;42m cpu_10m_info="${cpu_10m_info[$loop]} "\033[0m"
done echo -e " " fi
if [ $((cnt%180)) -eq 0 ]
then
for loop in 0 1 2 3 4 5 6 7 8 9 10
do
SumCpuAverage ${cpu_sum_info[$loop]} ${cnt}
cpu_15m_info[$loop]=$?
echo -e "\033[0;43m cpu_15m_info="${cpu_15m_info[$loop]} "\033[0m"
done
echo -e " "
fi
sleep 5

这里主要就是进行存储变量以及变量进行时间上的平均计算,我选择了5分钟、10分钟、15分钟的计算。大家也可以选择自己合适的时间进行分配计算。其中有个sleep 5秒的操作,因为top命令本身也会占用cpu资源,如果过快查询,也会导致CPU占用率很高,所以这个部分休眠时间,大家可以按照自己CPU实际性能进行添加。

最终效果

这是在该进程存在的情况下执行:

这是最开始打印的信息

这是五分钟 十分钟 以及 十五分钟后计算打印的数据

如果输入的进程查询之后没有,则脚本直接退出:

结语

这就是我在工作中使用shell自己动手做的一个进程以及该进程包含的线程cpu占用率的监控,适合在大家使用的设备里面没有对应的性能分析工具的应用,大家也可以拿过去直接使用。如果大家有更好的想法和需求,也欢迎大家加我好友交流分享哈。


作者:良知犹存,白天努力工作,晚上原创公号号主。公众号内容除了技术还有些人生感悟,一个认真输出内容的职场老司机,也是一个技术之外丰富生活的人,摄影、音乐 and 篮球。关注我,与我一起同行。

                              ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

推荐阅读

【1】在球场上我向人民币玩家低了头

【2】Linux开发coredump文件分析实战分享

【3】CPU中的程序是怎么运行起来的 必读

【4】cartographer环境建立以及建图测试

【5】设计模式之简单工厂模式、工厂模式、抽象工厂模式的对比

本公众号全部原创干货已整理成一个目录,回复[ 资源 ]即可获得。

分享自己做的一个指定进程以及线程长时间cpu监控的工具的更多相关文章

  1. Linux进程或线程绑定到CPU

    Linux进程或线程绑定到CPU 为了让程序拥有更好的性能,有时候需要将进程或线程绑定到特定的CPU,这样可以减少调度的开销和保护关键进程或线程. 进程绑定到CPU Linux提供一个接口,可以将进程 ...

  2. 分享学做的一个jsp注册页面

    分享一个自己学习时,用bootstrap,多方搜索做的注册页面,包括页面的非空验证.导入相关的bootstrap的js和css文件就可以了.背景很丑,可以自己换一个.后面进一步完善<( ̄︶ ̄)↗ ...

  3. 【进程/作业管理】篇章一:Linux进程及管理(专用内存监控类工具)------【vmstat、pmap】

    主要讲解专用内存监控工具的使用:vmstat.pmap命令的使用. 命令概览: vmstat 显示虚拟内存状态 pmap 报告进程与内存映射关系 vmstat命令是最常见的Linux/Unix监控工具 ...

  4. logback 指定每隔一段时间创建一个日志文件

    我使用的logback版本是1.2.3 目前logback支持根据时间来配置产生日志文件,但是只支持每周,每天,每个小时,每分钟等创建一个文件,配置如下: <appender name=&quo ...

  5. python之进程与线程

    什么是操作系统       可能很多人都会说,我们平时装的windows7 windows10都是操作系统,没错,他们都是操作系统.还有没有其他的? 想想我们使用的手机,Google公司的Androi ...

  6. Windbg 进程与线程 《第三篇》

    Windbg既可以显示进程和线程列表,又可以显示指定进程或线程的详细信息.调试命令可以提供比taskmgr更详尽的进程资料,在调试过程中不可或缺. 一.进程命令 进程命令包括这些内容:显示进程列表.进 ...

  7. 线程概念( 线程的特点,进程与线程的关系, 线程和python理论知识,线程的创建)

    参考博客: https://www.cnblogs.com/xiao987334176/p/9041318.html 线程概念的引入背景 进程 之前我们已经了解了操作系统中进程的概念,程序并不能单独运 ...

  8. python 全栈开发,Day41(线程概念,线程的特点,进程和线程的关系,线程和python 理论知识,线程的创建)

    昨日内容回顾 队列 队列 : 先进先出.数据进程安全 队列实现方式: 管道 + 锁 生产者消费者模型 : 解决数据供需不平衡 管道 双向通信 数据进程不安全 EOFError: 管道是由操作系统进行引 ...

  9. c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程

    c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...

随机推荐

  1. 了解Threejs中的Clock对象以及简单应用

    什么是Clock对象 如果你对 JavaScript 有一定了解,那么 JavaScript 的时间对象 Date 你一定不陌生,Clock 本质上就是对 Date 进行封装,提供了一些方法和属性 当 ...

  2. Codeforces 1288F - Red-Blue Graph(上下界网络流)

    Codeforces 题面传送门 & 洛谷题面传送门 好久没有写过上下界网络流了,先来一题再说( 首先先假设所有边都是蓝边,那么这样首先就有 \(b\times m\) 的花费,但是这样不一定 ...

  3. python3安装,支持openssl,支持采集https

    python3安装,支持openssl,支持采集https 坑好多,特别是安装的时候,各种不匹配,服务器默认配置是python2,升级3后,采集的时候用到openssl,花了两天也没搞定各种错误,也许 ...

  4. Generic recipe for data analysis with general linear model

    Generic recipe for data analysis with general linear model Courtesy of David Schneider State populat ...

  5. bwa比对软件的使用以及其结果文件(sam)格式说明

    一.bwa比对软件的使用 1.对参考基因组构建索引 bwa index -a bwtsw hg19.fa   #  -a 参数:is[默认] or bwtsw,即bwa构建索引的两种算法,两种算法都是 ...

  6. Linux实现批量添加用户及随机密码小脚本

    通过chpasswd命令可实现迅速为用户批量设置密码     实例:写一个脚本,实现批量添加20个用户user1-20,密码为用户名和后面跟5个随机字符 #!/bin/sh # 思路:通过for循环, ...

  7. Docker环境中部署Prometheus及node-exporter监控主机资源

    前提条件 已部署docker 已部署grafana 需要开放 3000 9100 和 9090 端口 启动node-exporter docker run --name node-exporter - ...

  8. 学习java 7.10

    学习内容: List 集合:有序集合,用户可以精确控制列表中每个元素的插入位置 List 集合特点:有序:存储和取出的元素顺序一致 可重复:存储的元素可以重复 增强for循环:简化数组和 Collec ...

  9. 02-爬取http://www.allitebooks.org/网站,获取图片url,书名,简介,作者

    import requests from lxml import etree from bs4 import BeautifulSoup import json class BookSpider(ob ...

  10. 【Reverse】每日必逆0x00

    附件:https://files.buuoj.cn/files/aa4f6c7e8d5171d520b95420ee570e79/a9d22a0e-928d-4bb4-8525-e38c9481469 ...