[转帖]分享自己做的一个指定进程以及线程长时间cpu监控的工具

分享,自己,一个,指定,进程,以及,线程,长时间,cpu,监控,工具 · 浏览次数 : 0

小编点评

```shell # 10分钟平均cpu占用率统计 var=\"NR == $((${loop}+8)) {print \\$9}}\"   awk&\"$var\"  # 5分钟平均cpu占用率统计 ((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 #退出脚本 exit ```

正文

https://cdn.modb.pro/db/329601

 

前言:

前面给大家分享过一个工作中用到的编译拷贝脚本,其实工作中还有一些其他工具的使用,今天再来分享一个自己纯手工的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 篮球。关注我,与我一起同行。

与[转帖]分享自己做的一个指定进程以及线程长时间cpu监控的工具相似的内容:

[转帖]分享自己做的一个指定进程以及线程长时间cpu监控的工具

https://cdn.modb.pro/db/329601 前言: 前面给大家分享过一个工作中用到的编译拷贝脚本,其实工作中还有一些其他工具的使用,今天再来分享一个自己纯手工的CPU监控的脚本。大家可以结合上篇文章与本篇文章一起学习shell。 主要实现功能: 1.监控指定进程是否运行 2.读取该

[转帖]进程间通信方式

1)管道 管道分为有名管道和无名管道 无名管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系一般指的是父子关系。无明管道一般用于两个不同进程之间的通信。当一个进程创建了一个管道,并调用fork创建自己的一个子进程后,父进程关闭读管道端,子进程关闭写管道端

[转帖]CPU性能监控之一------CPU架构

CPU性能监控之一 CPU架构 https://blog.51cto.com/hl914/1557231 先说下CPU的缓存吧,都知道CPU的缓存是分为L1,L2和L3的,L1又分为数据缓存和指令缓存,每颗CPU核心都有自己的L1和L2,但L3是各核心共享的,一但涉及共享的东西,当然就有竞争咯。 S

【转帖】15.JVM栈帧的内部结构

目录 1.JVM栈帧的内部结构 1.JVM栈帧的内部结构 栈帧存储的数据可以分为下面的5个部分: 1.局部变量表(重点) 2.操作数栈(重点) 3.动态链接,也称为指向运行时常量池的方法引用 4.方法返回地址,也称为方法退出或者异常退出的定义 5.一些附加信息 每个栈帧都有自己的大小,各个栈帧的大小

【转帖】15.JVM栈帧的内部结构

目录 1.JVM栈帧的内部结构 1.JVM栈帧的内部结构 栈帧存储的数据可以分为下面的5个部分: 1.局部变量表(重点) 2.操作数栈(重点) 3.动态链接,也称为指向运行时常量池的方法引用 4.方法返回地址,也称为方法退出或者异常退出的定义 5.一些附加信息 每个栈帧都有自己的大小,各个栈帧的大小

[转帖]redis bigkey 删除问题

一、慢操作分析 redis 的慢操作已经有了,如果没有,我们可以自己去 redis 服务器查看历史的慢日志操作,或者有对应的慢操作监控系统也可以发现问题,这里不做展开。 接下来我们就要看一看为什么这么慢。 看了下项目中的实现代码,结合日志一分析,发现是一个 redis bigkey。 一个 redi

[转帖]perf学习-linux自带性能分析工具

目前在做性能分析的事情,之前没怎么接触perf,找了几篇文章梳理了一下,按照问题的形式记录在这里。 方便自己查看。 什么是perf? linux性能调优工具,32内核以上自带的工具,软件性能分析。在2.6.31及后续版本的Linux内核里,安装perf非常的容易。 几乎能够处理所有与性能相关的事件。

[转帖]perf学习-linux自带性能分析工具

目前在做性能分析的事情,之前没怎么接触perf,找了几篇文章梳理了一下,按照问题的形式记录在这里。 方便自己查看。 什么是perf? linux性能调优工具,32内核以上自带的工具,软件性能分析。在2.6.31及后续版本的Linux内核里,安装perf非常的容易。 几乎能够处理所有与性能相关的事件。

[转帖]perf学习-linux自带性能分析工具

存储技术为满足层出不穷应用的海量数据存储需求,从物理介质到技术架构也同样发生了天翻地覆的变革。无论技术如何更新换代,其目的都是为了更好的提供高性能,高容量,高可用的数据服务。本系列文章会对存储系统的测试和调试工具做一个介绍。 dd - Linux世界中的搬运工 FIO – IO压力测试工具 vdbe

[转帖]张磊:浅谈容器网络

https://zhuanlan.zhihu.com/p/595014129 你好,我是张磊。今天我和你分享的主题是:浅谈容器网络。 在前面讲解容器基础时,我曾经提到过一个Linux容器能看见的“网络栈”,实际上是被隔离在它自己的Network Namespace当中的。 而所谓“网络栈”,就包括了