乐趣区

Python-绘制Android-CPU和内存增长曲线

内容简介:在做性能监控的时候,如果能把监控的 CPU 和内存增长变化用图表展示出来会比较直观,花了点时间用 Python 实现了下,来看下怎么用 Python 绘制 Android CPU 和内存变化曲线,生成增长曲线图表的 PNG 图片。一开始想通过采集的 CPU 和内存数据,导出到 Excel 生成增长曲线图表。做了下调研,并没有比较好的实现方法。后面看了下用 Python 来绘制图表实现起来挺容易的,而且 Python 的学习成本低,语法之类的做过开发的稍微看下就知道怎么用,容易上手。具体实现的效果如下,CPU 和内存采集的数据是独立进程的,内存分

本文转载自:https://www.chenwenguan.com/python-draw-cpu-memory-chart/,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有。

在做性能监控的时候,如果能把监控的 CPU 和内存增长变化用图表展示出来会比较直观,花了点时间用 Python 实现了下,来看下怎么用 Python 绘制 Android CPU 和内存变化曲线,生成增长曲线图表的 PNG 图片。

一、实现效果

一开始想通过采集的 CPU 和内存数据,导出到 Excel 生成增长曲线图表。做了下调研,并没有比较好的实现方法。后面看了下用 Python 来绘制图表实现起来挺容易的,而且 Python 的学习成本低,语法之类的做过开发的稍微看下就知道怎么用,容易上手。

具体实现的效果如下,CPU 和内存采集的数据是独立进程的,内存分三块数据,应用总内存,Native 内存和 Dalvik 内存,如果存在内存泄漏,要么在 Native,要么在 Dalvik,从图表增长曲线上很容易看出来。

二、具体逻辑实现详解

1. CPU 图表的 Python 实现

import matplotlib
matplotlib.use(‘Agg’)
import matplotlib.pyplot as plt
import json
import sys
import time
import traceback

def startDump():
try:

cpuData = json.loads(sys.argv\[1\])
imagePath = sys.argv\[2\]
cpuRateArray = \[\]
timeArray = \[\]
for cpuItem in cpuData:
  cpuRateArray.append(float(cpuItem\["cpuRate"\]))
  timeArray.append((float(float(cpuItem\["time"\]) - float(cpuData\[0\]\["time"\]))/1000))

plt.title("Monitor Cpu Rate")
plt.figure(figsize=(10, 8))
plt.tight\_layout()
plt.plot(timeArray, cpuRateArray, c='red', label='Process CPU')
plt.ylabel("CPURate (%)", fontsize=12)
plt.xlabel("TimeRange:" + formatTime(float(cpuData\[0\]\["time"\])) + '-' + formatTime(float(cpuData\[len(cpuData) -1\]\["time"\])), fontsize=10)
plt.legend()
plt.savefig(imagePath)

except Exception:

print 'exeption occur:' + traceback.format\_exc()

def formatTime(timeMillis):
timeSeconds = float(timeMillis/1000)
timelocal = time.localtime(timeSeconds)
timeFormat = time.strftime(“%Y-%m-%d %H:%M:%S”, timelocal)
return timeFormat

if __name__ == ‘__main__’:
startDump()

2. 内存图表的 Python 实现

import matplotlib
matplotlib.use(‘Agg’)
import matplotlib.pyplot as plt
import json
import sys
import time
import traceback

def startDump():
try:

memoryData = json.loads(sys.argv\[1\])
imagePath = sys.argv\[2\]
totalPssArray = \[\]
nativePssArray = \[\]
dalvikPssArray = \[\]
timeArray = \[\]
for memoryItem in memoryData:
  totalPssArray.append(float(memoryItem\["totalPss"\])/1024)
  nativePssArray.append(float(memoryItem\["nativePss"\])/1024)
  dalvikPssArray.append(float(memoryItem\["dalvikPss"\])/1024)
  timeArray.append((float(float(memoryItem\["time"\]) - float(memoryData\[0\]\["time"\]))/1000))

plt.title("Monitor Memory")
plt.figure(figsize=(10, 8))
plt.tight\_layout()
plt.plot(timeArray, totalPssArray, c='red', label='Total Memory')
plt.plot(timeArray, nativePssArray, c='yellow', label='Native Memory')
plt.plot(timeArray, dalvikPssArray, c='blue', label='Dalvik Memory')
plt.ylabel("Memory (MB)", fontsize=12)
plt.xlabel("TimeRange:" + formatTime(float(memoryData\[0\]\["time"\])) + '-' + formatTime(float(memoryData\[len(memoryData) -1\]\["time"\])), fontsize=10)
plt.legend()
plt.savefig(imagePath)

except Exception:

print 'exeption occur:' + traceback.format\_exc()

def formatTime(timeMillis):
timeSeconds = float(timeMillis/1000)
timelocal = time.localtime(timeSeconds)
timeFormat = time.strftime(“%Y-%m-%d %H:%M:%S”, timelocal)
return timeFormat

if __name__ == ‘__main__’:
startDump()

3. 实现说明

脚本传入的参数有两个,一个是监控的 JSON 数据字符串值 sys.argv[1],一个是保存的图片文件完整路径 sys.argv[2]。关于传入的 JSON 参数字符串值需要加上单引号修饰,否则会导致解析异常,传入的 JSON 参数也 不能直接是 JSON 对象,必须转化成字符串,示例调用命令如下:

python dump_chart.py ‘<JSONString>’ cpu_chart.png

1)采样 CPU 示例数据,time 是设备的系统时间戳,CPU 的占用率的计算可以查看前面写的:Android 性能监控之 CPU 监控

[
{
“time”: “1589435564442.279053”,
“cpuRate”: “2.17”
},
{
“time”: “1589435565655.333008”,
“cpuRate”: “3.26”
},
{
“time”: “1589435566954.137939”,
“cpuRate”: “2.52”
},

]

2)采样内存示例数据,totalPss、nativePss 和 dalvikPss 值都是从 dumpsys meminfo 输出的应用内存信息中截取出来的原始数据,对应“TOTAL”、“Native Heap“、”Dalvik Heap“字段的 Pss Total 值。内存信息的监控获取参考:Android 性能监控之内存监控

[
{
“time”: “1589636256923.429932”,
“totalPss”: 177804,
“nativePss”: 27922,
“dalvikPss”: 10212
},
{
“time”: “1589636258236.298096”,
“totalPss”: 178021,
“nativePss”: 27850,
“dalvikPss”: 9990
},
{
“time”: “1589636259525.219971”,
“totalPss”: 177899,
“nativePss”: 27742,
“dalvikPss”: 9990
},

]

三、实现过程中遇到的问题

1. load 方法使用错误

json.load () 方法使用错误,应该替换成 json.loads ()。

exeption occur:Traceback (most recent call last):
File “*******”, line 11, in startDump

memoryData = json.load(sys.argv\[1\])

File “/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py”, line 287, in load

return loads(fp.read(),

AttributeError: ‘str’ object has no attribute ‘read’

2. JSON 字符串对象入参问题

File “******”, line 11, in startDump

memoryData = json.loads(sys.argv\[1\])

File “/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py”, line 339, in loads

return \_default\_decoder.decode(s)

File “/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py”, line 364, in decode

obj, end = self.raw\_decode(s, idx=\_w(s, 0).end())

File “/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py”, line 382, in raw_decode

raise ValueError("No JSON object could be decoded")

ValueError: No JSON object could be decoded

针对 Python 脚本调用,JSON 字符串对象作为入参,传入的 JSON 字符串对象 需要加单引号处理,比如在 JavaScript 中示例处理如下:

‘\” + JSON.stringify(cpuRateJSON) + ‘\”

3. Python 需要显示声明参数的类型

在 Python 中需要指明参数的类型,解析获取到 JSON 对象中的值之后,Python 并不会根据参数来判断是什么类型,需要指明要转化的对象参数类型,比如把系统时间戳转化成 float 值类型:float(memoryData[0][“time”])

Traceback (most recent call last):
File “*******”, line 21, in startDump

timeArray.append(timeStamp(memoryItem\["time"\]))

File “*******”, line 36, in timeStamp

timeStamp = float(timeNum/1000)

TypeError: unsupported operand type(s) for /: ‘unicode’ and ‘int’

4. 编码导致的异常

SyntaxError: Non-ASCII character ‘\xe5’ in file ******* on line 24, but no encoding declared; see http://python.org/dev/peps/pe… for details

如果运行之后报如下的异常,说明是编码出问题,在脚本开头加上编码类型声明:

!usr/bin/python

-*- coding: utf-8 -*-

5. 保存的文件格式限制

plt.savefig (image_path) 保存的文件格式只能是 eps , pdf , pgf , png , ps , raw , rgba , svg , svgz 这些,不支持 jpg 图片的保存。

退出移动版