背景
启动耗时是 App 的一项核心性能指标。知乎目前已有埋点数据可以作为参考,数据收集不需要人工干预,但这种测试方法的准确性一直被质疑,而且与用户的真实感受有一定差距。在性能优化初期与竞品横向的对比上,知乎采用录屏方式,即人工用视频录制软件对手机屏幕进行录制采集,然后用分帧工具进行分帧统计,这样测试的结果符合用户真实感受,但是测试成本极高。因此考虑在埋点数据作为纵向标准的基础上,实现录屏自动化测试方案作为辅助参考标准。
思路
既然是把手工测试的过程自动化,那我们先捋一下手工测试的思路:手动录屏 → 用分帧工具为视频分帧 → 人工挑选出关键节点的图片,记录这一帧在视频中的时间 → 计算启动时长:结束节点时间–开始节点时间。如果要自动化整个过程,把每一步的自动化的方案组装在一起即可。如何把人工识别关键节点图片调整成通过机器学习模型自动识别,是关乎结果准确性的重要步骤。
整体思路如图 1 启动时间自动化测试流程所示,可分为四个部分。
训练模型:收集图片素材,训练图片识别模型,验证模型准确率后,对识别不够准确的场景进行样本补充或调整,最终用准确率较高的模型进行识别。
屏幕录制:通过脚本自动启动 App ,并将手机的图片帧序列保存到 PC 端。
数据处理:对图片帧进行识别,准确识别出关键节点图片,计算启动时间。
闭环流程:数据持久化,建立 MR 准入机制。
图 1 启动时间自动化测试流程
训练模型
选择模型、训练模型最终目的是:让模型可以准确的识别出关键节点图片。我们通过不断调整、扩大训练样本,以便让训练后的模型能够更加准确的识别关键节点的图片。首先需要进行关键节点的样本收集,然后选择合适的模型并用样本进行训练,最后根据需要进行修正调整。
样本收集
我们将启动过程分为五个关键节点,分别为启动开始、出现 logo 界面、出现广告素材、首页框架加载完成、首页内容加载完成,对 App 启动过程进行录屏,并人工对图片帧分类,分别保存图片在五个关键节点文件夹中。如图 2 启动过程示意图所示。
文件夹命名为对应的节点的名称。
每个文件夹下存放 50 张截图,包含 2 个机型的截图,五个节点共计 250 张图片。
图 2 启动过程示意图
模型的选择与训练
机器学习模型选择了比较流行的 TensorFlow,主要原因是操作简单,不必提取特征,训练后识别准确度也很高。环境搭建流程可参考:https://www.tensorflow.org/hub/tutorials/image_retraining
搭好环境后开始训练样本,每个节点下的图片不能少于 20 张,不然会报错。
学习后的模型保存在 /tmp/output_graph.pb 中,五个关键节点的标识即五个文件夹的名称。
测试模型准确率并对样本进行调整
训练完的模型我们并不能拿来就用,还要看它识别的准不准,如果不准要对素材进行补充或调整,直到能满足需要。
当我们拿一张图进行测试时,模型会告诉我们他认为这张图为各个阶段的概率。如图 3 所示,模型识别出其为 loading 阶段的概率最高, 为 98.35%,那我们可以认定它将这张图识别为 loading 阶段。而事实上这张图片确实处于 loading 阶段。这个概率值越高,则说明模型越有把握,我们要尽量让训练后的模型可以胸有成竹的确认图片处于哪个节点。
图 3 测试模型准确率样例
接下来我们选取了 20 组新的截图(共计 100 张图),对训练之后的模型进行测试。这 20 组截图覆盖不同分辨率、不同机型。其中 MIN 为模型识别为这个节点的概率最小值。
图 4 不同阶段模型识别概率统计
由上图我们可以看到,大部分图片的识别的准确率还是蛮高的。只有「广告-ad」阶段部分图片的识别概率较低,甚至会错识别成「启动开始-start」,猜测可能是广告页与手机桌面相似度过高导致,在增加了不同广告的样式到素材中继续训练后,果然识别准确率有所增加。
我们在代码中设置了每个节点识别概率的阈值,只有识别概率超过阈值才会认为匹配成功。
屏幕录制
录屏工具选择了 stf 提供的 minicap,在中等手机上截图速率可达每秒 30、40 张。由于 minicap 传输速率极快,我们直接保存二进制流为图片,通过图片保存时的时间戳来计算启动时间。此时关键节点最后一张图片的传输耗时为这种计算方式的误差值,误差值不超过 200ms,可以接受。屏幕录制和启动是同时进行的,这里采用多线程的方式。
录制步骤如下:
拿到 minicap 源码后,我们需要对其手动编译得到可执行文件,但编译后的可执行文件会因 CPU 架构不同而不通用,好在官方文档比较详细,提供了 easy way 和 hard way,如果按照 easy way,把真机连在电脑上,运行官方脚本可直接编译出真机需要的版本。安装到客户端上后,可以通过 adb 命令启动 minicap,命令中 -P 参数可设置屏幕分辨率和图片压缩比,适当的图片压缩可以减少图片传输耗时和识别图片耗时。下面为启动 minicap 的命令,加上 -t 可以检查执行结果,出现 OK 即启动成功。
minicap 启动后,将设备的 TCP 服务器端口映射到本机的 1717 端口,在终端输入「nc localhost 1717」可以看到 minicap 传输到 PC 的二进制数据流,看起来是乱码,其实是图片流。
本地创建 tcp client,监听 1717 端口,把传输的二进制流保存成图片,得到启动过程截图。
数据处理
App 启动使用 adb 命令的方式,没有手指按压图标以后,图标颜色加深的效果,启动节点计算只能根据第一个页面在桌面不断放大、出现的过程来计算这个过程也忽略了真实用户手指按压硬件处理的时间,统一通过 adb 命令下发时的时间戳,来作为开始启动的时间。
整个启动时间的计算都是根据时间戳来计算的,即第一张首页出现图片被保存的时间戳 - 启动时间戳。
由于启动过程包含广告逻辑,出现广告是难免的。在图片识别过程,如果识别出现了广告,则本次启动时间不计入。
识别图片的过程比较耗时,每张图要 2s 左右,为了节省时间,每启动一次便新建一个线程在后台识别本次启动存下的图片,多个线程并发识别,启动十次的话,整个流程下来大概要 12 分钟。下图为多个线程并发识别图片的日志。
图 5 识别过程 log
即便是保持机型、系统等变量都不变,同一台手机启动同一个包的启动时间波动也是很大的,如何让测试结果更可靠,工具能够有效的反馈出问题,是我们在一直不断优化的,目前所做的优化主要有以下几点:
减少广告的出现。由于启动中出现广告的数据会被作废,我们在 app 安装后先做 10 次冷启动,这样后续测试数据中出现广告的概率会减少。
找到合适的启动次数。在一次测试任务中尽可能增加启动次数,样本数据越大准确性越高,但是由于图片识别是比较耗时的,启动次数也不宜过多。
在数据统计上降低误差值。拿到全部启动时间后,我们会去掉其中的最大值和最小值,然后计算平均值。
闭环流程
为了能尽早的发现代码对启动时间的影响,我们要在代码合入前对启动时间做到监控,因此将启动时间录屏自动化接入到 CI 中,每个 MR 打完包之后都会执行启动时间测试,如果启动时间高于历史数据的平均值,会在 MR 上 @启动时间负责人,对代码进行排查。为了方便 dev 对问题排查,我们将启动过程各个启动项的启动时间也记录下来,方便查找是哪个启动项影响了启动时间。接入 CI 自动化的整体流程图如下图所示。
图 6 闭环流程图
下图为测试数据数据存储平台的前端页面展示。从页面上可以查到每个 MR 打包之后的启动数据,方便排查问题。
图 7 数据展示图
展望
总体来说,启动时间录屏自动化测试,我们采用自动化录屏加图片模式识别进行自动化测试,并建全闭环流程让启动优化的结果得到持久保障。但是,我们注意到,目前测试中使用的模型还是最开始训练得到的,后续计划在每次测试结束后,都将关键帧图片保存在样本库中,定时训练,更新模型,这样可以让识别更加准确。
最后
我们期待有志于质量保证工作的知友们加入知乎质量保障团队,与知乎一起扬帆远航。详细职位可以点击 这里,期待你的加入,与我们一起做很酷的事情。
本文转载自知乎技术专栏。
原文链接:
https://zhuanlan.zhihu.com/p/70696324
评论