一个获取 Android 某个 package 的 CPU 占用率,内存占用率,系统 IOPS .. 程序
本文是作者结合自己的开发经验,参考 Linux 官方文档,和其他的一些 Android 文档编辑而成,但因开发此 脚本的时候并没有记录参考资料,如果在此文没有指出出去的地方,在此深表歉意。
我认为,代码是最能说明功用的手段,除非代码写得太复杂,或者太乱。因此我不会再额外说明脚本中处理流程。 但此脚本中几个注意的点,我会事先说明。
首先该脚本依赖 adb, 因为作者本意是通过此脚本去获取 Android APK 的各项参数。 而 Android 系统一般会自带 adb, 而且更具系统的不同您可能要处理权限方面的问题。 但是该脚本可以轻松的换成 ssh 去采集也是可以的。而为什么采用 Shell 而不是用 Python, Node.js, Go 编写采集程序,主要是因为这样开发效率更高,但是在某些 Windows 机器上 shell 的执行效率比较底下(比如说跑在 4 代或者 5 代 i3 win10),此时最好换成 ssh 和更高效的语言去实现。,但基本采集数据的思想都是相同的。
因为效率原因后面将该脚本换成了从系统内部执行,adb 部分删除了。
脚本采集的参数有 CPU 占用率,内存消耗,整体 IO 的消耗,线程数。 下面我会具体的说明各个参数是如何采集的。
另外一般 Linux 里面表示 CPU 占用率表示的是单颗 CPU 的占用率,如果硬件有超过一颗 CPU (虚拟的也算)那么总的 CPU 占用率会超过 100%, 比如说 4 核的 CPU 占用率是 400%。 而此脚本中计算的 CPU 为每秒占总 CPU 的占比,因此恒定为 100%。但如果想要换成通用的计算标准,在最后不去平均核数即可。
为了美化打印,这里采用了 3/4 bit 的颜色模式,但是可能在某些终端不支持,从而会打印出一些多余的乱码, 此时直接在前面的函数中去掉颜色控制方面的代码即可(换成其他的前导码或者 256 色模式也可以试一试)。
脚本最后会在目标路径生成一个 csv 文件。该脚本还有一个配套的数据统计脚本,脚本时间轴还有些问题先不上传了(后续更新)。
如果想了解更多关于 Proc 相关的信息,请在 Linux 系统下执行 man 5 proc
。
如果想了解 /proc/diskstate 相关的信息,请访问 Linux 内核工程中 Documentation/iostats.txt
文档。
#!/system/bin/sh # set -e # ------------------------------------------------------------------------------ # Author: mojies # 使用说明: # 1. 先将该脚本上传到测试设备 # 2. 给改脚本家可执行权限 chmod +x ./SamplingSysData-xxxxxxxx.sh # 3. 该脚本采集五个数据 # 1. date 采集时的系统时间 # 2. flash /data/data/${package} 消耗 Flash 大小 # 3. mem 应用启动之后消耗的系统内存 # 4. cpu 应用启动之后在监测点监测到的数学平均 CPU 占用率,单位 1/1000 # 5. iow 系统造成的 iops # 4. 使用时请运行以下命令采集指定包的运行时数据 # ./SamplingSysData-xxxxxxxx.sh ${package} # 如: # ./SamplingSysData-xxxxxxxx.sh com.xxx.xxx # 5. 生成的数据在 /data/SamplingSysDaya/${package} 目录下用如下命令将采集数据 # 打印到终端 # ls /data/SamplingSysDaya/${package} | while read line; do echo "$line"; cat /data/SamplingSysDaya/${package}/${line}; echo ""; done # # # ------------------------------------------------------------------------------ # ----------------------------------------------------------------------------- echo_red(){ echo -e "\e[1;31m$1\e[0m" } echo_yellow(){ echo -e "\e[1;33m$1\e[0m" } echo_green(){ echo -e "\e[1;32m$1\e[0m" } echo_blue(){ echo -e "\e[1;34m$1\e[0m" } echo_purple(){ echo -e "\e[1;35m$1\e[0m" } echo_cyan(){ echo -e "\e[1;36m$1\e[0m" } function show_help_info(){ echo_green "------------------------------------------------------------" echo_green "Option:" echo_green " --pkg | -p 包名" echo_green " --duration | -d 采样频率" echo_green " --verbose 是否打印详细信息( 不需要指定参数 )" echo_green " --result_dir 指定保存采样数据目录" echo_green "ex:" echo_green " ./deploy.sh -p com.xxx.xxxx -d 1" echo_green "------------------------------------------------------------" exit -1 } # ----------------------------------------------------------------------------- export PARAM_PACKAGE_NAME="" export PARAM_DURATION="" export PARAM_VERBOSE=false export PARAM_RESULT_DIR=false if [ $# -eq 0 ]; then show_help_info exit else PARAM=("$@") I=0 while true; do case ${PARAM[$I]} in --pkg|-p) I=`expr $I + 1` PARAM_PACKAGE_NAME=${PARAM[$I]} ;; --duration|-d) I=`expr $I + 1` PARAM_DURATION=${PARAM[$I]} ;; --verbose) PARAM_VERBOSE=true ;; --result_dir) I=`expr $I + 1` PARAM_RESULT_DIR=${PARAM[$I]} ;; *) show_help_info exit 1 ;; esac I=`expr $I + 1` if [ $I -eq $# ]; then break; fi done fi #设置包名 if [ "$PARAM_PACKAGE_NAME" = "" ]; then echo_red "Please specify the package name" echo_red "ex: ./SamplingSysData-* com.xxx.xxx" exit 1 fi if [ "$PARAM_DURATION" = "" ]; then PARAM_DURATION=5 echo_red "The default duration: ${PARAM_DURATION}" fi echo_v(){ if [ ${PARAM_VERBOSE} = true ]; then echo_blue "$@" fi } #设置U盘路径 export RESULT_PATH="" if [ "${PARAM_RESULT_DIR}" = "" ]; then RESULT_PATH="/data/SamplingSysDaya/$PARAM_PACKAGE_NAME"; else RESULT_PATH="${PARAM_RESULT_DIR}/$PARAM_PACKAGE_NAME" fi res="result.$(date +%Y%m%d-%H%M%S).csv" #设置 CPU 采样周期(s) sampling_CPU_interval=5 a=0 #设置总次数 total=100000 if [ ! -d "$RESULT_PATH" ]; then mkdir -p $RESULT_PATH if [ $? -ne 0 ]; then echo_red "You specifyc error path or you didn't have permission" exit 1 fi fi ; # ----------------------------------------------------------------------------- #获取CPU个数 processor=$(cat /proc/cpuinfo| grep "processor"|wc -l) # ----------------------------------------------------------------------------- # 获取 PID export PROGRESS_PID="" get_package_pid(){ PID=$(ps | grep "${1}" | sed 's/ [ ]*/ /g' - | cut -d' ' -f2 | xargs echo) if [ "${PID}" = "" ]; then PID=$(ps -A | grep "${1}" | sed 's/ [ ]*/ /g' - | cut -d' ' -f2 | xargs echo) if [ "${PID}" = "" ]; then exit 1 else echo ${PID} fi else echo ${PID} fi } is_process_exist(){ safty_param="$@ end" I=0 while true; do let "I += 1" PID=$(echo ${safty_param}|cut -d' ' -f${I}) if [ ${PID} == end ]; then break; fi if [ -f /proc/${PID}/stat ]; then continue; else return 1 fi done return 0 } get_pids_threadNumbers(){ safty_param="$@ end" sum=0; I=0 while true; do let "I += 1" PID=$(echo ${safty_param}|cut -d' ' -f${I}) if [ ${PID} == end ]; then break; fi nums=$(ls /proc/${PID}/task | wc -l) let "sum+=${nums}" done echo ${sum} } PROGRESS_PID=$(get_package_pid ${PARAM_PACKAGE_NAME}) # ----------------------------------------------------------------------------- function get_disk_iow(){ export DISK_NAME; if [ "$1" = "" ];then DISK_NAME=mmcblk0 else DISK_NAME=${1} fi export diskstate=$(cat /proc/diskstats | grep " ${DISK_NAME} " | sed 's/[ ][ ]*/ /g' -) rt=$(echo ${diskstate}|cut -d' ' -f8) wt=$(echo ${diskstate}|cut -d' ' -f12) iot=$(echo ${diskstate}|cut -d' ' -f14) let "sum=${rt}+${wt}+${iot}" echo ${sum} } DISK_SUM_COST_TIME=$(get_disk_iow) # ----------------------------------------------------------------------------- function get_pid_ticket(){ safty_param="$@ end" sum=0; I=0 while true; do let "I += 1" PID=$(echo ${safty_param}|cut -d' ' -f${I}) if [ "$PID" == "end" ]; then echo ${sum} return fi stats=$(cat /proc/${PID}/stat) utime=$(echo ${stats}|cut -d' ' -f14) stime=$(echo ${stats}|cut -d' ' -f15) let "sum+=${stime}+${utime}" done } CPU_SUM_TIKI=$(get_pid_ticket ${PROGRESS_PID}) echo $CPU_SUM_TIKI # ----------------------------------------------------------------------------- export t1=0 export t2=0 export t3=0 export t4=0 export t5=0 export DATE=0 export FLASH_USAGE=0 export MEM_USAGE=0 export CPU_USAGE=0 export IO_USAGE=0 # ----------------------------------------------------------------------------- rm -rf $RESULT_PATH/$res echo "date,flash(KB),mem(KB),cpu(‰),iorw(ms),thread" >> $RESULT_PATH/$res echo "date,flash(KB),mem(KB),cpu(‰),iorw(ms),thread" #生成应用占用flash数据 while (($a < $total));do if [ "${PROGRESS_PID}" = "" ]; then is_process_exist ${PROGRESS_PID} if [ $? -eq 1 ]; then sleep 1 FLASH_USAGE=0 MEM_USAGE=0 CPU_USAGE=0 IO_USAGE=0 PROGRESS_PID=$(get_package_pid ${PARAM_PACKAGE_NAME}) continue; fi fi # ------------------------------------------------------------ DATE=$(date "+%H:%M:%S") # ------------------------------------------------------------ let "t4 += 1"; if [ $t4 -ge ${PARAM_DURATION} ]; then t4=0; # ------------------------------------------------------------ # Flash Usage # du -sh /data/data/$PARAM_PACKAGE_NAME | sed 's/ [ ]*/ /g' - | cut -d" " -f1 >> $RESULT_PATH/flash.csv; FLASH_USAGE=$(du -sh /data/data/${PARAM_PACKAGE_NAME} | sed 's/[ \t][ \t]*/ /g' - | cut -d" " -f1) echo_v "FLASH_USAGE: ${FLASH_USAGE}" # ------------------------------------------------------------ # mem usage # 输出Meminfo大小 单位:M # echo `dumpsys meminfo ${PARAM_PACKAGE_NAME} | grep "TOTAL SWAP" | sed 's/ [ ]*/ /g' - | cut -d' ' -f3` >>$RESULT_PATH/ddr.csv; MEM_USAGE=$(dumpsys meminfo ${PARAM_PACKAGE_NAME} | grep "TOTAL SWAP" | sed 's/ [ ]*/ /g' - | cut -d' ' -f3) echo_v "MEM_USAGE: ${MEM_USAGE}" # ------------------------------------------------------------ # io usage NOW_DISK_SUM=$(get_disk_iow) let "diff=${NOW_DISK_SUM}-${DISK_SUM_COST_TIME}" let "diff=${diff}/${PARAM_DURATION}" IO_USAGE=${diff} DISK_SUM_COST_TIME=${NOW_DISK_SUM} echo_v "IO_USAGE: ${IO_USAGE}" # ------------------------------------------------------------ # Thread numbs # THREAD_NUM=`ls /proc/${PROGRESS_PID}/task | wc -l` THREAD_NUM=$(get_pids_threadNumbers ${PROGRESS_PID}) echo_v "THREAD_NUM: ${THREAD_NUM}" # echo "Thread Num: ${THREAD_NUM}" fi # ------------------------------------------------------------ let "t3 += 1"; if [ $t3 -ge ${sampling_CPU_interval} ]; then t3=0; tmpsum=$(get_pid_ticket ${PROGRESS_PID}) if [ $tmpsum -eq 0 ]; then PROGRESS_PID=$(ps | grep "${PARAM_PACKAGE_NAME}" | sed 's/ [ ]*/ /g' - | cut -d' ' -f2 | xargs echo) CPU_SUM_TIKI=$(get_pid_ticket ${PROGRESS_PID}) else let "diff=${tmpsum}-${CPU_SUM_TIKI}" let "diff=${diff}" let "diff=${diff}/${processor}" CPU_SUM_TIKI=${tmpsum} CPU_USAGE=${diff} echo_v "CPU_USAGE: ${CPU_USAGE}" fi fi # ------------------------------------------------------------ let "t5 += 1"; if [ $t5 -ge ${PARAM_DURATION} ]; then t5=0 echo "${DATE},${FLASH_USAGE},${MEM_USAGE},${CPU_USAGE},${IO_USAGE},${THREAD_NUM}" # echo "DATE: ${DATE}" # echo "FLASH_USAGE: ${FLASH_USAGE}" # echo "MEM_USAGE: ${MEM_USAGE}" # echo "CPU_USAGE: ${CPU_USAGE}" # echo "IO_USAGE: ${IO_USAGE}" # echo "THREAD_NUM: ${THREAD_NUM}" echo "${DATE},${FLASH_USAGE},${MEM_USAGE},${CPU_USAGE},${IO_USAGE},${THREAD_NUM}" >> ${RESULT_PATH}/${res} fi sleep 1 done
![]() |
![]() |