经过一段时间的优化,PerfDog4.0全新来袭,先来看看都更新了神马
一,新版功能初探
- 【新增】新增图表常见操作提示功能
- 【新增】新增高阶功能,子进程帧率精准测试
- 【优化】彻底解决部分Android手机无法获取电量和内存等问题
- 【优化】解决iOS低版本无法获取FPS等问题
- 【修复】修复一些已知问题
我们发现新版增加了一些常用tip
优化了一些安卓以及ios部分机型或者系统版本无法获取部分数据的问题,如果还有一些获取不到数据或者连接的问题,请查看
PerfDog使用连接相关说明
二,子进程帧率精准测试说明
这个子进程帧率获取对于目前来说使用多进程的应用来说非常有用哦,可能有些同学对于这个概念不是很清晰,我们来一步步探索;
这是啥?干啥用?怎么用?
多进程简介:Android平台,一般大型APP,比如游戏有时候是多进程协作运行(微信小游戏,微视等APP及王者荣耀等游戏多子进程),可选择目标子进程进行针对性测试。默认是主进程。如图王者荣耀
弄清出子进程帧率之前先需要搞清楚Android窗口是是啥。下面简要的概述下,具体还不理解的请度娘 SurfaceFliger,或者查看这篇文章 扒一扒安卓渲染原理
简单来说surfaceflinger是安卓系统的一个服务,作用是接受多个来源的图形显示数据,将他们合成,然后发送到显示设备;
我们来看看官方的描述
大类去看,一般Android主窗口Activity和与之对应的View,有一种特殊的View,如SurfaceView,他会独享一个Surface,不与主窗口共享Surface,独立渲染非常高效,支持OpenglES渲染。也就是说可能会出现两类窗口FPS。一个是Activety窗口帧率和SurfaceView窗口帧率。
在什么情况下会出现两种类型窗口都有的情况呢?一般是游戏类型、直播类、视屏流、小游戏等类型应用会出现有两种窗口。特殊情况下,可能会出现多个Activity和多个SurfaceView,对统计帧率造成很大困难,需要一定策略获取帧率。
游戏、直播、视频、小游戏等类型应用,PerfDog默认获取的是SurfaceView的FPS。其他传统应或Web用获取的是Activity帧率。
同时PerfDog高阶功能,支持用户自己选择窗口类型帧率,特别针对小程序,小游戏等,能更精准测试目标窗口帧率,如下图(微信小游戏-欢乐斗地主)
小游戏、直播、视频、游戏等类型应用,请选择SurfaceView
我们来总结一下:
如果我们子进程的View是SurfaceView,那么子进程会独享一个Surface,不与主窗口共享Surface;
这里拿一个视频页举例,主线程和子线程实际上可以理解为叠加的状态,二者互不干扰;也就是说我们获取主线程的帧率是下面主进程的数据,而子进程帧率是中间的一小块轮播图的帧率数据,二者是独立的
三,用户自建Web云获取性能数据
在更新4.0后,我们在setting界面可以发现可以自定义上传的云平台了
这里要怎么使用呢,如果我们有自己的云平台,那我们自定义一个链接请求就可以了;
下面我用Tornado框架做个简单的例子
首先定义路由:
(r"/", GetPerfDogData), (r"/icon", GetPerfDogIcon), (r"/screenshots", GetPerfDogScreenShots), (r"/done", GetPerfDogDone),
接下来处理方法
class GetPerfDogData(tornado.web.RequestHandler): """ :fuc:获取PerfDog性能数据 """ def post(self): data = self.request.body.decode('utf8') data = parse.unquote(data) print("性能数据:",data) self.finish( { "errCode": 0, "errStr": "", "reportId": "" })
完整代码:
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.web, tornado.ioloop from urllib import parse def Set_Ima(data): with open("img.jpg", "wb") as f: f.write(data["body"]) # 生成一张img.jpg的图片 class GetPerfDogData(tornado.web.RequestHandler): """ :fuc:获取PerfDog性能数据 """ def post(self): data = self.request.body.decode('utf8') data = parse.unquote(data) print("性能数据:",data) self.finish( { "errCode": 0, "errStr": "", "reportId": "" }) class GetPerfDogIcon(tornado.web.RequestHandler): """ :fuc:获取PerfDog应用图标 """ def put(self): data = self.request.files['icon'] print("Icon图标:", data) for imadata in data: Set_Ima(imadata) self.finish( { "errCode": 0, "errStr": "", "reportId": "" }) class GetPerfDogScreenShots(tornado.web.RequestHandler): """ :fuc:获取PerfDog测试过程中生成的应用截图 """ def post(self): pass class GetPerfDogDone(tornado.web.RequestHandler): """ :fuc:完成上传测试数据 """ def put(self): pass if __name__ == '__main__': CONTENTS_LIST = [] settings = { 'template_path': 'template', 'static_path': 'static', } application = tornado.web.Application([ (r"/", GetPerfDogData), (r"/icon", GetPerfDogIcon), (r"/screenshots", GetPerfDogScreenShots), (r"/done", GetPerfDogDone), ], **settings) application.listen(8868) tornado.ioloop.IOLoop.instance().start()
运行脚本,把ip地址+端口号填进server里,如果有域名就填写域名,
点击上传数据,就可以看到数据信息啦
这里贴出一下目前的接口文档:
接口说明 baseURL 需要配置,例如:http://abc.com/report 开始上传测试数据 • path: • method: post • header: – Content-Type: 'multipart/form-data' • req – file_format: json/pb – data: file • resp { errCode: 0, errStr: "", reportId: "" } 上传测试过程中生成性能数据,如fps、卡顿等等 设置测试应用图标 • path: /icon • method: put • header: – Content-Type: 'multipart/form-data' • req – reportId – icon: file • resp { errCode: 0, errStr: "" } 上传测试过程中生成的应用截图 • path: /screenshots • method: post • header: – Content-Type: 'multipart/form-data' • req – reportId – file1: file – file2: file – file3: file – file4: file – file5: file – ... • resp { errCode: 0, errStr: "" } 一次可以上传多张 或者使用zip压缩多张图片上传 完成上传测试数据 • path: /done • method: put • header: – Content-Type: 'multipart/form-data' • req – reportId • resp { errCode: 0, errStr: "" }
注意这是4.0版本的接口文档哦。以后没准会变得哟 !
再贴一份flask框架完整的demo吧
report文件
# coding: utf-8 import os import uuid from werkzeug.utils import secure_filename class Report(object): def __init__(self, base_dir): self.base_dir = base_dir def set_data_by_pb(self, file): filename = self.get_filename('data.pb') file.save(filename) def set_data_by_json(self, file): filename = self.get_filename('data.json') file.save(filename) def set_icon(self, file): filename = self.get_filename('icon.png') file.save(filename) def add_screenshots(self, files): for file in files: filename = self.get_filename(secure_filename(file.filename)) file.save(filename) def done(self): filename = self.get_filename('done') with open(filename, 'wb'): pass def get_filename(self, filename): return '%s%s%s' % (self.base_dir, os.sep, filename) class ReportManager(object): def __init__(self): self.base_dir = os.path.split(os.path.realpath(__file__))[0] + os.sep + 'data' if not os.path.exists(self.base_dir): os.mkdir(self.base_dir) def create_report(self): report_id = str(uuid.uuid4()) report_dir = self.get_report_dir(report_id) os.mkdir(report_dir) return report_id, Report(report_dir) def get_report(self, report_id): report_dir = self.get_report_dir(report_id) return Report(report_dir) def get_report_dir(self, report_id): return '%s%s%s' % (self.base_dir, os.sep, report_id) reportManager = ReportManager() def create_by_pb(file): (report_id, report) = reportManager.create_report() report.set_data_by_pb(file) return report_id def create_by_json(file): (report_id, report) = reportManager.create_report() report.set_data_by_json(file) return report_id def set_icon(report_id, value): report = reportManager.get_report(report_id) report.set_icon(value) def add_screenshots(report_id, screenshots): report = reportManager.get_report(report_id) report.add_screenshots(screenshots) def done(report_id): report = reportManager.get_report(report_id) report.done()
demo文件
#! /usr/bin/python # coding: utf-8 from flask import Flask, request, jsonify import report app = Flask(__name__) @app.route('/report', methods=['POST']) def create_report(): file_format = request.form['file_format'] if file_format == 'pb': report_id = report.create_by_pb(request.files['data']) elif file_format == 'json': report_id = report.create_by_json(request.files['data']) if report_id is None: res = {'errCode': -1, 'errStr': 'invalid arguments'} else: res = {'errCode': 0, 'errStr': 'success', 'reportId': report_id} return jsonify(res) @app.route('/report/icon', methods=['PUT']) def set_icon(): report_id = request.form['reportId'] report.set_icon(report_id, request.files['icon']) return jsonify({'errCode': 0, 'errStr': 'success'}) @app.route('/report/screenshots', methods=['POST']) def add_screenshots(): report_id = request.form['reportId'] files = [] for name in request.files: files.append(request.files[name]) report.add_screenshots(report_id, files) return jsonify({'errCode': 0, 'errStr': 'success'}) @app.route('/report/done', methods=['PUT']) def done(): report_id = request.form['reportId'] report.done(report_id) return jsonify({'errCode': 0, 'errStr': 'success'})
好啦,可以开始愉快的玩耍啦!
延伸阅读:
如何自定义数据文件服务器地址,构建自己web云
https://bbs.perfdog.qq.com/detail-217.html