移动性能测试android性能监控⼯具介绍(Python+PyQt实
现)
前阵⼦公司发布⼀款新应⽤,第⼀次发布应⽤市场,过程⽐较坎坷,查看百度反馈的监测报告于是想着⾃⼰做⼀款android性能监控⼯具,由于之前写了  ⼯具,所以继续⽤python+PyQt 做了⼀款GUI⼯具,V1.1.0版本主界⾯如下:
其中数据采集部分主要参考了:
以及其他⼀些同学的⽂章,具体的可能我也忘记了,sry
借鉴社区⼀些同学的idea,最终做成了这个⼯具,⾮常感谢
数据采集
⼯具⽬前版本主要监控三个指标:mem、cpu、流量(上传和下载),后⾯有需求会加上其他指标
具体的数据采集,上⾯的链接的⼏篇⽂章已经说得很清楚了,我就不再狗尾续貂
具体做法是,将这些⽅法放在adb_commonn.py⽂件中,在需要的时候引⽤即可
def mem():
xxxxx
def cpu():
xxxx
def flow():
xxxx
⼯具介绍
框架介绍
⼯具主要有⼏部分构成:
其中:
AATT.py 主要逻辑实现
aatt_pyqt.py 主要是页⾯,由下⾯.ui⽂件转换⽽来
aatt_pyqt.ui QT Designer⽣成的⽂件
adb_common.py 即上⾯说的封装的数据采集的⽅法
MatplotlibWidget.py 绘图⽂件,⽤来定义绘图的逻辑
使⽤⽅法介绍
连接⼿机---点击检查设备,检查成功则显⽰设备SN号,失败则显⽰‘No device found’
打开待测应⽤,点击获取,获取应⽤包名和activity
下拉选择更新时间
点击‘开始’按钮---开始测试,点击’结束’按钮---结束测试
点击图表,显⽰图表(这边暂时未做到实时显⽰图表,后续再优化)
主要代码分析
其中点击pushbutton获取信息、下拉框选择信息,这些简单的逻辑在上篇  中已经讲过了,这篇⽂章也不再赘述了
主要讲过程中主要遇到了两个问题:
1.实时向textedit中添加最新获取到的数据
2.图表的显⽰
QTimer的使⽤
加⼊QTimer主要是为了解决,在写数据的过程中,不断往原有数据上append新采集到数据的问题,同时不⾄于是应⽤⽆响应。初始化⼀个定时器,把定时器的timeout信号和slotadd()槽函数连接。
self.timer = QTimer(self)
self.t(self.slotadd)
slotadd()往五个textedit中写数据
由于返回的数据是⼀个列表,所以每次只需要取最新的即最后⼀个数据即可。
def slotadd(self):
'''
往mem、cpu、flow写数据
:return:
'''
memlist = ()
mem = 'mem占⽤:'+ str(memlist[-1])
cpulist = adb.cpu()
cpu = 'cpu占⽤:'+ str(cpulist[-1])
append(mem)
self.ui.cpu.append(cpu)
(recevice,send,allflow)=flow()
android最新版receflow = '下载流量:' + str(int(recevice[-1]))
sendflow = '上传流量:' + str(int(send[-1]))
alladd = '总流量:' + str(int(allflow[-1]))
v.append(receflow)
self.ui.send.append(sendflow)
self.ui.all.append(alladd)
点击开始按钮,启动定时器,并使开始按钮失效
def startTimer(self):
'''
设置时间间隔并启动定时器
:
return:
'''
self.timer.start(self.wait_time())
self.ui.start.setEnabled(False)
d.setEnabled(True)
点击结束按钮,停⽌定时器,并使开始按钮⽣效。
def endTimer(self):
self.timer.stop()
self.ui.start.setEnabled(True)
特别说明:
流量采集部分,需要将两个采集到的结果相减,才会得到这段时间内的流量,所以相对其他指标直接获取的稍有区别:
#获取流量
receive = []
sendflow = []
all = []
def flow():
cmd = 'adb -s '+ get_devices() +' shell cat /proc/net/xt_qtaguid/stats | findstr '+ uid()
print (cmd)
flow_info = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).adlines()
down = 0
up = 0
if len(flow_info)>= 1:
for flow in flow_info:
down =down + int(flow.split()[5])
up = up+ int(flow.split()[7])
receive.append(down)
sendflow.append(up)
print (receive,sendflow)
return (receive,sendflow)
def getflow():
(receive,sendflow) = flow()
recev = []
send = []
allflow = []
print(len(receive))
for i in range(len(receive)-1):
recev.append((int(receive[i+1]) - int(receive[i]))//1024)
send.append((int(sendflow[i+1]) - int(sendflow[i]))//1024)
allflow.append(recev[i]+send[i])
print(recev,send,allflow)
return recev,send,allflow
Matplotlib的应⽤
Matplotlib是python常⽤的绘图模块,提供了⼀套与MATLAB 相似的命令API,⽤来交互式的绘图,⾮常⽅便。设置绘图类
新增⼀个MatplotlibWidget.py⽂件,创建FigureCanvas类,在初始化过程中建⽴⼀个空⽩图像。
class MyMplCanvas(FigureCanvas):
"""FigureCanvas的最终的⽗类其实是QWidget。"""
def __init__(self, parent=None, width=5, height=4, dpi=100):
# 配置中⽂显⽰
self.fig = plt.figure(figsize=(width, height), dpi=dpi)  # 新建⼀个figure
self.axes = self.fig.add_subplot(111)  # 建⽴⼀个⼦图,如果要建⽴复合图,可以在这⾥修改
self.axes.hold(False)  # 每次绘图的时候不保留上⼀次绘图的结果
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
'''定义FigureCanvas的尺⼨策略,这部分的意思是设置FigureCanvas,使之尽可能的向外填充空间。'''
FigureCanvas.setSizePolicy(self,
QSizePolicy.Expanding,
QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
定义绘图函数,调⽤这个函数可以在上⾯所创建的空⽩图像中绘图。
备注:这边由于演⽰需要,所以稍微更改了下图⽚显⽰的逻辑
实际中将a换成adb_common ⽂件返回的 各指标即可
def start_static_plot(self):
self.fig.suptitle('图表')
a=[1,2,4,2,3,1,2,3,4,2]
self.axes.plot(a)
self.axes.set_ylabel('number')
id(True)
封装绘图类
这部分主要把上⾯的绘图类和⼯具栏封装到MatplotlibWidget中,只需要调⽤MatplotlibWidget这个类就可以实现绘图功能
class MatplotlibWidget(QWidget):
def __init__(self, parent=None):
super(MatplotlibWidget, self).__init__(parent)
self.initUi()
def initUi(self):
self.layout = QVBoxLayout(self)
self.mpl = MyMplCanvas(self, width=5, height=4, dpi=100)
self.mpl.start_static_plot()
self.mpl_ntb = NavigationToolbar(self.mpl, self)  # 添加完整的 toolbar
self.layout.addWidget(self.mpl)
self.layout.addWidget(self.mpl_ntb)
if __name__ == '__main__':
app = QApplication(sys.argv)
ui = MatplotlibWidget()
ui.mpl.start_static_plot()  # 测试静态图效果
ui.show()
<_())
运⾏结果,如下:
设置提升窗⼝控件
在QT Designer中右击提升窗⼝部件,新建⼀个QWidget类,名称和头⽂件均为 MatplotlibWidget
在.ui⽂件中加⼊widget并升级
这个转换⽣成的ui⽂件,后最下⽅会有⼀⾏
from MatplotlibWidget import MatplotlibWidget
MatplotlibWidget的使⽤
下⾯即AATT.py部分代码展⽰
初始化模型
class Main(QMainWindow,Ui_Form):
def __init__(self,parent=None):
super(Main,self).__init__(parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
self.setWindowTitle('Waiqin365-AATT-V1.1.0')
_plot.setVisible(False)
self.ui.t(self.setdevices)
t(self.setpackage)
self.ui.t(self.clearall)
self.t(self.wait_time)
#初始化⼀个定时器
self.timer = QTimer(self)
self.t(self.slotadd)
self.ui.t(self.startTimer)
dTimer)
_plot.setVisible(False)
初始化中隐藏图像,设置按钮的触发操作,同时使得图像可见并出发绘图函数
@pyqtSlot()
def on_pushButton_clicked(self):
_plot.setVisible(True)
_plot.mpl.start_static_plot()
运⾏测试程序:
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
ui = Main()
ui.show()
<_())
结果如下:
备注:这边的图⽚,是上⾯直接写的a,实际显⽰的adb_common返回的各列表的值
思考
⽬前⼯具优化到V1.1.0版本,但是仍存在很多不⾜的情况,⽬前遇到的问题:
1.打包成exe⽂件后,⽆法使⽤----这也是导致⼯具不能share的原因
2.缺少对⼿机状态的监控,断开连接后,没有⾃动停⽌