观察者模式
观察者模式主要用来在一对多依赖关系中,通知被观察者同步状态或数据,android执行monkey期间收集性能数据,当数据返回时,我们可以采用观察者模式来通知数据收集器,更新数据,经典观察者模式结构图引用观察者模式。
基本性能指标
获取android端的性能数据,可以通过以下命令,其中主要依赖于top和dumpsys命令,具体如下:
CPU
cpu使用情况可以通过top/dumpsys命令来获取,如
adb shell top -m 100 -n 1 -s cpu | grep 包名;
adb shell dumpsys cpuinfo |grep 包名。
内存
查看内存使用情况使用命令
adb shell dumpsys meminfo 包名
流量
查看流量使用情况使用命令
adb shell cat /proc/net/xt_qtaguid/stats | grep uid
其中uid 可以通过
dumpsys package 包名| grep userId=
掉帧率
页面流畅度,我们不能通过fps来判断页面是否卡顿,但是我们可以通过每一帧的加载时间,来判断该帧是否加载超时,按照标准识动画的频率大约是每秒连续加载60帧,人眼才不会感觉到卡顿,那么平均每一帧的加载时间不得超过1s/60帧,即16.6ms,那么每一帧加载的四个阶段(draw,prepare,process,executor)时间之和不能超过16.6ms,超时现象被称为掉帧,掉帧数越大,表明页面卡顿越严重。我们先通过“dumpsys gfxinfo 包名” 获取帧加载情况,再计算每一帧的加载总时间,统计掉帧数,计算出掉帧率。
执行monkey测试期间收集性能数据
在启动monkey测试前,初始化androidPerformanceData参数并传递给执行器。
@Override
public void coreTesting(BaseTestData baseTestData) throws Exception {
MonkeyTestRunner runner = new MonkeyTestRunner();
//执行monkey测试时,收集性能数据
runner.startMonkeyTest(androidPerformanceData, sn, app, monkeyTime, 0, 0, 0, 0, 0, 0);
baseTestData.setPerformanceData(androidPerformanceData);
}
在执行monkey线程中起性能收集任务androidPerformanceRunner,示例如下
try {
if (androidPerformanceData != null){
//开始收集性能数据
androidPerformanceRunner = new AndroidPerformanceRunner(device, pkgName, androidPerformanceData);
androidPerformanceRunner.start();
}
device.executeShellCommand(command, receiver, 60000);
result = true;
} catch (ShellCommandUnresponsiveException mttor) {
result = true;
} catch (Exception ex) {
result = false;
} finally {
if (androidPerformanceData != null ){
//结束收集性能数据
if (androidPerformanceRunner != null){
androidPerformanceRunner.stop();
}
}
}
采用观察者模式同步性能数据
在AndroidPerformanceRunner提供方法getMemoryInfo、getxxinfo获取不同的性能数据,以获取内存为例,如下:
JSONObject memInfo = getMemoryInfo(pkgName, device);
if (memInfo == null) {
memInfo = new JSONObject();
memInfo.put("total_mem", 0);
memInfo.put("app_mem", 0);
}
memInfo.put("time", time);
performanceData.getJSONArray("mem_info").add(memInfo);
其中getMemoryInfo方法中使用MemInfoService类实例,MemInfoService类继承Observable类,并提供方法executeCmd4GetMemInfo执行cmd命令收集数据,数据收集完毕后,通过Observable的notifyObservers方法通知观察者更新数据。
public void executeCmd4GetMemInfo() {
String cmd = "cat /proc/meminfo | grep MemTotal:";
try {
device.executeShellCommand(cmd, totalMemInfoReceiver);
} catch (TimeoutException e) {
e.printStackTrace();
} catch (AdbCommandRejectedException e) {
e.printStackTrace();
} catch (ShellCommandUnresponsiveException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Integer memInfo = getTotalMemInfo();
if (memInfo > 0) {
setChanged();
notifyObservers(memInfo);
}
在notifyObservers方法中,采用同步锁更新数据
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
数据处理
收集完数据后,采用json格式拼装性能数据,并上报至报告中心。
private JSONObject handlePerformanceData(BaseTestData baseTestData){
JSONObject data = new JSONObject();
JSONObject performanceInfo = baseTestData.getPerformanceData();
if (performanceInfo != null){
data.put("mem_info", getMemInfo(performanceInfo.getJSONArray("mem_info")));
data.put("cpu_info", getCPUInfo(performanceInfo.getJSONArray("cpu_info")));
data.put("fps_info", getFPSInfo(performanceInfo.getJSONArray("fps_info")));
data.put("traffic_info", getTrafficInfo(performanceInfo.getJSONArray("traffic_info")));
}
return data;
}
至此,性能数据收集完毕。