背景:
正常我们抓取perfetto或者systrace都是采用的手动抓取方式,但是手动抓取方式一般适用于一些必现的场景,但是经常一些性能问题都不是必现的。很可能是偶现的问题。所以针对这种偶现的性能问题我们应该如何做呢?
很多同学会想到是否可以考虑自动化监测的呢?本文就来带大家简单实现一个自动化监测系统性能,当性能低下时候可以实现对系统进行perfetto的抓取trace,方便分析问题。
方案简单设计:
上面背景中聊的性能低下,这里只是个文字描述,具体应该怎么来代表和判断当前系统就是性能低下呢?
这里其实可以有很多个指标维度:
1、cpu使用率过高,可以代表当前cpu负载太大,当前系统可能存在卡顿
2、当前帧率低,或者检测卡顿主线程卡顿等
…等其他指标
这里为了简单起见,我们就简单认为cpu使用率为性能低下的参考指标,也就是cpu使用率太高就代表当前系统性能低,要触发对应的perfetto来抓对应trace
设计如下图:
实战代码
#!/bin/bash
# 配置参数
THRESHOLD=40
CHECK_INTERVAL=5
TRACE_DURATION=10
TRACE_CONFIG="trace_config.pb"
TRACE_OUTPUT="trace.perfetto-trace"
ADB="adb"
LOG_FILE="cpu_monitor.log"
# 确保adb设备已连接
function check_adb() {
if ! $ADB get-state 1>/dev/null 2>&1; then
echo "错误:未找到已连接的Android设备" | tee -a "$LOG_FILE"
exit 1
fi
}
# 获取当前CPU使用率(整个系统)
function get_cpu_usage() {
# 使用临时变量存储adb输出
local cpu_data1=$(adb shell "cat /proc/stat | grep '^cpu '")
read -r cpu user nice system idle iowait irq softirq steal guest <<< "$cpu_data1"
# 计算首次总时间和空闲时间
total1=$((user + nice + system + idle + iowait + irq + softirq + steal))
idle1=$idle
sleep 1
# 第二次读取
local cpu_data2=$(adb shell "cat /proc/stat | grep '^cpu '")
read -r cpu user nice system idle iowait irq softirq steal guest <<< "$cpu_data2"
total2=$((user + nice + system + idle + iowait + irq + softirq + steal))
idle2=$idle
total_diff=$((total2 - total1))
idle_diff=$((idle2 - idle1))
if [[ $total_diff -ne 0 ]]; then
usage=$((100 - (idle_diff * 100) / total_diff))
echo $usage
else
echo 0
fi
}
# 执行perfetto跟踪
function start_tracing() {
local timestamp=$(date +%Y%m%d_%H%M%S)
local output_file="${TRACE_OUTPUT%.*}_${timestamp}.${TRACE_OUTPUT##*.}"
echo "$(date) - CPU使用率超过阈值,开始抓取跟踪数据..." | tee -a "$LOG_FILE"
# 将配置文件推送到设备
$ADB push "$TRACE_CONFIG" /data/local/tmp/trace_config.pb || {
echo "错误:推送配置文件失败" | tee -a "$LOG_FILE"
return 1
}
# 启动perfetto跟踪(后台执行)
$ADB shell "nohup perfetto -c /data/local/tmp/trace_config.pb -o /data/misc/perfetto-traces/$output_file --txt"
# 等待跟踪启动
sleep 2
# 检查是否启动成功
if $ADB shell "ps -A | grep -q perfetto"; then
echo "$(date) - 跟踪已启动,持续${TRACE_DURATION}秒..." | tee -a "$LOG_FILE"
sleep $TRACE_DURATION
# 停止跟踪(通过发送SIGINT)
$ADB shell "pkill -SIGINT perfetto"
# 等待文件写入
sleep 3
# 拉取跟踪文件
$ADB pull "/data/misc/perfetto-traces/$output_file" . && \
echo "$(date) - 跟踪文件已保存:$output_file" | tee -a "$LOG_FILE"
else
echo "错误:perfetto启动失败" | tee -a "$LOG_FILE"
return 1
fi
}
# 主监控循环
function main() {
check_adb
echo "$(date) - 启动CPU监控,阈值:${THRESHOLD}%,检测间隔:${CHECK_INTERVAL}秒" | tee -a "$LOG_FILE"
while true; do
cpu_usage=$(get_cpu_usage)
echo "$(date) - 当前CPU使用率:${cpu_usage}%" | tee -a "$LOG_FILE"
if [[ $cpu_usage -ge $THRESHOLD ]]; then
start_tracing
# 触发后暂停检测防止重复触发
echo "$(date) - 触发跟踪后暂停检测60秒..." | tee -a "$LOG_FILE"
sleep 60
else
sleep $CHECK_INTERVAL
fi
done
}
# 执行主函数
main
上面的代码保存到 cpu_monitor.sh中
验证方法:
-
授予执行权限
chmod +x cpu_monitor.sh -
使用bash明确执行(重要)
bash cpu_monitor.sh
当然要抓取perfetto可以准备好一个trace_config.pb在当前sh脚本目录,这个前面文章有说过
https://mp.weixin.qq.com/s/ruac6wUPvJSoXJ10ElfFJQ
执行结果如下:
我们设定了40%阈值,超过就会马上触发perfetto进行抓取trace,打开trace可以看看:
更多framework实战干货,请关注下面“千里马学框架”