Linux shell编程:监控进程CPU使用率并使用 perf 抓取高CPU进程信息
0. 概要
本文将介绍一个用于监控一组进程CPU使用率的Shell脚本,,当检测到某进程的CPU使用率超出阈值时,使用 perf 工具抓取该进程的详细信息。
本shell脚本为了能在普通嵌入式系统上运行做了妥协和优化。
1. shell脚本流程的简要图示:

2. perf介绍
perf 是 Linux 内核提供的一个强大性能分析工具,能够用于分析和调优系统性能。它支持多种事件类型,如CPU时钟、缓存命中/未命中、中断等。
在本脚本中,当某个进程的CPU使用率超过设定阈值(例如80%)时,会使用以下命令抓取该进程的详细性能数据:
perf record -F 99 -e cpu-clock -p $pid -g -o "perf-$process_name.data" -- sleep $perf_sleep_time
-F 99:以每秒99次的频率进行采样。-e cpu-clock:采样的事件类型为CPU时钟周期。-p $pid:指定要采样的进程ID。-g:记录调用栈信息,帮助分析性能瓶颈。-o "perf-$process_name.data":将采样数据输出到指定文件中。-- sleep $perf_sleep_time:持续采样时间为10秒。
通过抓取高CPU使用率进程的详细性能数据,我们可以深入分析性能瓶颈,找出导致高CPU使用的原因,从而进行针对性的优化。
更多介绍请查看:
使用perf(火焰图)查看热点函数和系统调用最大延迟函数
如何使用perf 统计cpu和内存?
3. shell脚本详解
-
日志文件配置:
# Log file location LOGFILE="process_monitor.log" # Redirect standard input, output, and error to log file exec 1>>"$LOGFILE" exec 2>>"$LOGFILE"这部分代码配置日志文件,并将标准输入、输出和错误重定向到日志文件中。
-
后台运行检测:
# Check if the script is already running if [ "$1" != "background" ]; then"$0" background &exit 0 fi这段代码用于检测脚本是否已经在后台运行,如果没有,则重新以后台模式启动自己。
-
初始化上次报告时间文件:
# Initialize last report time file last_report_time_file="last_report_time" touch "$last_report_time_file"初始化用于存储上次报告时间的文件。
-
获取CPU总时间的函数:
# Function to get the total CPU usage from /proc/stat get_total_cpu_time() {awk '/^cpu / {print $2 + $3 + $4 + $5 + $6 + $7 + $8}' /proc/stat }从
/proc/stat文件中获取CPU总时间。 -
获取进程CPU时间的函数:
# Function to get the process CPU usage from /proc/[pid]/stat get_process_cpu_time() {pid=$1awk '{print $14 + $15 + $16 + $17}' /proc/$pid/stat }从
/proc/[pid]/stat文件中获取指定进程的CPU时间。 -
计算进程CPU使用率的函数:
# Function to calculate CPU usage of a process calculate_cpu_usage() {pid=$1prev_process_time=$(get_process_cpu_time "$pid")prev_total_time=$(get_total_cpu_time)sleep 1process_time=$(get_process_cpu_time "$pid")total_time=$(get_total_cpu_time)process_delta=$((process_time - prev_process_time))total_delta=$((total_time - prev_total_time))cpu_usage=$((100 * process_delta / total_delta))echo $cpu_usage }计算指定进程的CPU使用率。
-
加载上次报告时间的函数:
# Function to load the last report time for a PID load_last_report_time() {pid=$1grep "^$pid=" "$last_report_time_file" | cut -d'=' -f2 }从文件中加载上次报告时间。
-
保存上次报告时间的函数:
# Function to save the last report time for a PID save_last_report_time() {pid=$1time=$2sed -i "/^$pid=/d" "$last_report_time_file"echo "$pid=$time" >> "$last_report_time_file" }将上次报告时间保存到文件中。
-
进程监控列表:
# List of process names to monitor process_names="top systemd"定义需要监控的进程名称列表。
-
监控循环:
while true; docurrent_time=$(date +%s)for process_name in $process_names; doif [ -n "$DEBUG_ON" ]; thenecho "Checking process: $process_name"fi# Find all matching process PIDspids=$(ps aux | grep "$process_name" | grep -v grep | awk '{print $2}')for pid in $pids; do# Calculate CPU usagecpu_usage=$(calculate_cpu_usage "$pid")# Check if CPU usage exceeds $max_cpu_usage%if [ "$cpu_usage" -gt $max_cpu_usage ]; thenecho "High CPU usage detected for process '$process_name' (PID: $pid): $cpu_usage%"# Load the last report time for this PIDlast_time=$(load_last_report_time "$pid")last_time=${last_time:-0}time_diff=$((current_time - last_time))# Check if the last report time is more than 60 seconds agoif [ "$time_diff" -ge 60 ]; thenecho "time_diff: $time_diff, perf record -F 99 -e cpu-clock -p $pid -g -o perf-$process_name.data -- sleep $perf_sleep_time"ps -p "$pid" -o pid,ppid,cmd,%mem,%cpu >> "$LOGFILE"perf record -F 99 -e cpu-clock -p $pid -g -o "perf-$process_name.data" -- sleep $perf_sleep_time# Save the last report time for this PIDsave_last_report_time "$pid" "$current_time"# sleep for 1 secondsleep 1fielseif [ -n "$DEBUG_ON" ]; thenecho "CPU usage for process '$process_name' (PID: $pid): $cpu_usage%"fifidonedonedone
这是主要的监控循环,定期检查指定进程的CPU使用率,并在超过阈值时使用 perf 抓取详细信息。
4. 完整脚本实现
以下是优化后的Shell脚本,适用于普通嵌入式系统:
#!/bin/sh# This script monitors the CPU usage of a list of processesDEBUG_ON=1
# Log file location
LOGFILE="process_monitor.log"# Redirect standard input, output, and error to log file
exec 1>>"$LOGFILE"
exec 2>>"$LOGFILE"# Check if the script is already running
if [ "$1" != "background" ]; then"$0" background &exit 0
fi# Initialize last report time file
last_report_time_file="last_report_time"
touch "$last_report_time_file"# Function to get the total CPU usage from /proc/stat
get_total_cpu_time() {awk '/^cpu / {print $2 + $3 + $4 + $5 + $6 + $7 + $8}' /proc/stat
}# Function to get the process CPU usage from /proc/[pid]/stat
get_process_cpu_time() {pid=$1awk '{print $14 + $15 + $16 + $17}' /proc/$pid/stat
}# Function to calculate CPU usage of a process
calculate_cpu_usage() {pid=$1prev_process_time=$(get_process_cpu_time "$pid")prev_total_time=$(get_total_cpu_time)sleep 1process_time=$(get_process_cpu_time "$pid")total_time=$(get_total_cpu_time)process_delta=$((process_time - prev_process_time))total_delta=$((total_time - prev_total_time))cpu_usage=$((100 * process_delta / total_delta))echo $cpu_usage
}# Function to load the last report time for a PID
load_last_report_time() {pid=$1grep "^$pid=" "$last_report_time_file" | cut -d'=' -f2
}# Function to save the last report time for a PID
save_last_report_time() {pid=$1time=$2sed -i "/^$pid=/d" "$last_report_time_file"echo "$pid=$time" >> "$last_report_time_file"
}# List of process names to monitor
process_names="top systemd"echo "Monitoring CPU usage for processes: $process_names"# Perf sleep time
perf_sleep_time=10
max_cpu_usage=80# Monitoring loop
while true; docurrent_time=$(date +%s)for process_name in $process_names; doif [ -n "$DEBUG_ON" ]; thenecho "Checking process: $process_name"fi# Find all matching process PIDs# pids=$(ps | grep "$process_name" | grep -v grep | awk '{print $1}')pids=$(ps aux | grep "$process_name" | grep -v grep | awk '{print $2}')for pid in $pids; do# Calculate CPU usagecpu_usage=$(calculate_cpu_usage "$pid")# Check if CPU usage exceeds $max_cpu_usage%if [ "$cpu_usage" -gt $max_cpu_usage ]; thenecho "High CPU usage detected for process '$process_name' (PID: $pid): $cpu_usage%"# Load the last report time for this PIDlast_time=$(load_last_report_time "$pid")last_time=${last_time:-0}time_diff=$((current_time - last_time))# Check if the last report time is more than 60 seconds agoif [ "$time_diff" -ge 60 ]; thenecho "time_diff: $time_diff, perf record -F 99 -e cpu-clock -p $pid -g -o perf-$process_name.data -- sleep $perf_sleep_time"ps -p "$pid" -o pid,ppid,cmd,%mem,%cpu >> "$LOGFILE"perf record -F 99 -e cpu-clock -p $pid -g -o "perf-$process_name.data" -- sleep $perf_sleep_time# Save the last report time for this PIDsave_last_report_time "$pid" "$current_time"# sleep for 1 secondsleep 1fielseif [ -n "$DEBUG_ON" ]; thenecho "CPU usage for process '$process_name' (PID: $pid): $cpu_usage%"fifidonedonedone
通过这种方式,我们可以有效地监控嵌入式系统中高CPU使用率的进程,并通过 perf 工具获取详细的性能数据,帮助我们进行性能调优和问题排查。
相关文章:
Linux shell编程:监控进程CPU使用率并使用 perf 抓取高CPU进程信息
0. 概要 本文将介绍一个用于监控一组进程CPU使用率的Shell脚本,,当检测到某进程的CPU使用率超出阈值时,使用 perf 工具抓取该进程的详细信息。 本shell脚本为了能在普通嵌入式系统上运行做了妥协和优化。 1. shell脚本流程的简要图示&#…...
Linux网络编程的套接字分析(其一,基本知识)
文章目录 套接字的类型流套接字数据报套接字原始套接字 套接字地址获取套接字地址 协议族和地址族 套接字的类型 Linux系统的套接字有三类:流套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAM)。 流套接字 用于面向连接…...
后端Web开发之Maven
1.java项目构建工具maven介绍 Maven是apache旗下的一个开源项目。Apache软件基金会,成立于1999年7月,是目前世界上最大的最受欢迎的开源(源代码开放)软件基金会也是一一个专门为支持开源项目而生的非盈利性组织。 apache开源项目…...
前端创新实践:用JavaScript打造网页扫码新体验
引言 简述扫码技术在现代网页应用中的普及和重要性。引入JavaScript实现网页扫码功能的创新性和实用性。 扫码技术概述 介绍扫码技术的原理和在不同平台(如微信、支付宝)的应用。讨论扫码技术对用户体验和业务流程的影响。 JavaScript实现网页扫码的…...
AWS CLI命令行
参考文档:在 macOS 上安裝,更新和卸載 AWS CLI 版本 1 - AWS Command Line Interface...
领导力培养的底层逻辑
领导力就是从人们从他们现在的地方,到他们从未去过的地方的能力--基辛格 ## 1. 领导力的一些观点 ## 2. 五种习惯十大承诺 ## 3. 需要领导的场景 ## 4.0 组织中谁需要领导力 ## 5.0 领导力培养 领导力培养的底层逻辑可以简单描述为以下几个方面: 管理…...
【MATLAB第107期】基于MATLAB的Morris局部敏感性分析模型(无目标函数)
【MATLAB第107期】基于MATLAB的Morris局部敏感性分析模型(无目标函数) 更正: 局部敏感性分析方法 一、原理介绍 1.基本原理: Morris方法采用概率均匀抽样的方式估计每个模型输入因子在输出结果中的重要性,通过比较系…...
Tomcat搭建JSPServlet
一、Tomcat环境搭建 1. 将项目变为Web项目 选中项目,点击Help中的Find Action 搜索Add Framework Support 勾选Web Application 出现这些文件就是成功了 2. 配置Tomcat 点击Edit Configurations 点击加号,选择Tomcat Server Local Deployment栏下点击…...
32位定点数和32/64位浮点数的二进制生成方法
问题由来 定点数和浮点数在嵌入式软件处理和FPGA算法方面使用比较普遍,但是遇到FPGA实现32位定点数的处理,想要仿真时,突然发现全网都在讲浮点数和定点数的格式和理论,几乎没有生成的快捷方法,好在一片文章出现了一点…...
STM32利用arm-dsp库进行FIR低通滤波【详细】
arm-dsp库官方已经封装好了,使用的时候需要把dsp库移植到工程里面,具体怎么移植网上可以找到教程 这里直接说怎么用FIR的流程: 一、Matlab里面生成所配置的阶数和系数 1、在Matlab命令窗口输入fdatool,回车,会弹出一个新窗口 2…...
Efficient-KAN 源码详解
Efficient-KAN源码链接 Efficient-KAN (GitHub) 改进细节 1.内存效率提升 KAN网络的原始实现的性能问题主要在于它需要扩展所有中间变量以执行不同的激活函数。对于具有in_features个输入和out_features个输出的层,原始实现需要将输入扩展为shape为(batch_size, out_featur…...
Jlink commander使用方法(附指令大全)
Jlinkcmd它可以方便用户在非仿真的情况下,hold内核、单步、全速、设置断点、查看内核和外设寄存器、读取flash代码等等,方便大家拥有最高的权限查看在运行中的MCU情况,查找非IDE仿真情况下,MCU运行异常的原因。 目录 驱动安装 …...
Java SpringBoot实现PDF转图片
不是单页图片,是多页PDF转成一张图片的逻辑。 我这里的场景是PDF转成图片之后返回给前端,前端再在图片上实现签字,并且可拖拽的逻辑,就是签订合同的场景。 但是这里只写后端多页PDF转图片的逻辑。 先说逻辑,后面直接…...
elasticsearch SQL:在Elasticsearch中启用和使用SQL功能
❃博主首页 : 「码到三十五」 ,同名公众号 :「码到三十五」,wx号 : 「liwu0213」 ☠博主专栏 : <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 :…...
Java 并发编程:线程变量 ThreadLocal
大家好,我是栗筝i,这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 029 篇文章,在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验,并希望进…...
【OpenHarmony4.1 之 U-Boot 2024.07源码深度解析】018 - init_sequence_f 各函数源码分析(二)
【OpenHarmony4.1 之 U-Boot 2024.07源码深度解析】018 - init_sequence_f 各函数源码分析(二) 一、arch_cpu_init二、arch_cpu_init系列文章汇总:《【OpenHarmony4.1 之 U-Boot 源码深度解析】000 - 文章链接汇总》 本文链接:《【OpenHarmony4.1 之 U-Boot 2024.07源码深度…...
LVS原理——详细介绍
目录 介绍 lvs简介 LVS作用 LVS 的优势与不足 LVS概念与相关术语 LVS的3种工作模式 LVS调度算法 LVS-dr模式 LVS-tun模式 ipvsadm工具使用 实验 nat模式集群部署 实验环境 webserver1配置 webserver2配置 lvs配置 dr模式集群部署 实验环境 router 效果呈现…...
MYSQL 5.7.36 等保 建设记录
文章目录 前言一、开启审计日志1.1 查看当前状态1.2 开启方式1.3 查看开启后状态 二、密码有效期2.1 查看当前状态2.2 开启方式2.3 查看开启后状态 三、密码复杂度3.1 查看当前状态3.2 开启方式3.3 查看开启后状态 四、连接控制4.1 查看当前状态4.2 开启方式4.3 查看开启后状态…...
fatal: unable to access ‘https://github.com/xxxxx
ubuntu中git克隆项目异常 git clone https://github.com/xxx Cloning into ‘xxx’… fatal: unable to access ‘https://github.com/xxx/xx.git/’: Could not resolve host: github.com 解决办法使用命令: git config --global http.proxy git config --global…...
从零开始的CPP(38)——递归与动态规划
leetcode46 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1: 输入:nums [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]示例 2: 输入&#…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态
前言 在人工智能技术飞速发展的今天,深度学习与大模型技术已成为推动行业变革的核心驱动力,而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心,系统性地呈现了两部深度技术著作的精华:…...
【iOS】 Block再学习
iOS Block再学习 文章目录 iOS Block再学习前言Block的三种类型__ NSGlobalBlock____ NSMallocBlock____ NSStackBlock__小结 Block底层分析Block的结构捕获自由变量捕获全局(静态)变量捕获静态变量__block修饰符forwarding指针 Block的copy时机block作为函数返回值将block赋给…...
MeshGPT 笔记
[2311.15475] MeshGPT: Generating Triangle Meshes with Decoder-Only Transformers https://library.scholarcy.com/try 真正意义上的AI生成三维模型MESHGPT来袭!_哔哩哔哩_bilibili GitHub - lucidrains/meshgpt-pytorch: Implementation of MeshGPT, SOTA Me…...
