自动化工具 全自动化的抖音启动速度测试

williamfzc · 2020年02月12日 · 最后由 刘珂 回复于 2023年01月13日 · 13858 次阅读
本帖已被设为精华帖!

前言

背景

我来啦,感谢社区的朋友们对这个项目的支持,这次有机会到 MTSC2019 深圳站上分享。虽然讲得还不够好,但是对自己也是一次难得的历练机会。
开发维护至今,很开心能得知,已经有不少团队将该工具落地到实际项目中,其中不乏来自各大厂的业务团队们。这也是开源项目的意义之一。

当然,随着使用范围增大,功能更加复杂,我们也在不断改进与优化这个工具。目前,stagesepx 已经迭代了 35 个版本,稳定性与功能比起之前也不可同日而语。
在启动速度测试这一块上,应用已经趋向稳定。因此,本文将针对这一项,进行一个完整例子的讲解。

起因

其实,对于一般应用来说,可以参考前言中 如何手动或自动进行 app 的启动速度测试 的方式去做就可以。之所以会有这么一项,是因为:

  • 一些超级 app 的启动过程非常复杂且可变
  • 无法满足游戏的需求

简而言之,也就是部分同学最关心的动态化问题。举个例子,抖音的启动过程是这样的:

可以看到,它有五个阶段(你也可以按照你的理解划分):

  1. 初始阶段(app 没打开)
  2. 首屏(抖音字样)
  3. 插屏广告(可能有)
  4. 应用内首屏(视频未加载,但主体控件已加载完成)
  5. 应用完成(视频与控件均以加载完成)

看起来还好,但是:

  • 插屏广告每次打开都不一样,且不一定有
  • 抖音的主页是动态的,会大面积动,而且每次都不一样

由于模型的限制,之前的 stagesepx 没法满足这个问题,所以,这类问题也成为它应用的瓶颈。
本篇文章将以抖音为例(此条五毛),描述现在的版本如何处理复杂情况下的启动速度测试问题。

这里选抖音只是因为抖音的启动流程够复杂,方便讲解

流程

所有代码可以在 例子地址 找到。

场景设计

对于测试来说,场景与过程设计永远是最重要的。如果标准都没有定下来,操作没有任何意义。
这里我们的规划保持与上面相同,五个阶段。另外在本次测试中我们姑且认为:

应用完成的首点 - 初始阶段的结束点 = 启动耗时(这里自行根据实际需要去界定)

操作

这里请先阅读 如何手动或自动进行 app 的启动速度测试 中的自动测试部分,操作流程差不多。这里不会赘述

与上文一样,我们可以利用几个视频,得到一系列的截图。通过人工分拣,我们可以将截图按我们上面设计好的类别进行归类。训练集大概是这样:

然后一样的,我们在上面进行训练就可以得到我们想要的模型。
看起来与传统模式非常相似,不同之处在于,在这种模式下我们不再使用传统的 SVM 分类器,而改用 keras 支持的神经网络分类器。
当然,这一切对于用户来说几乎是无感知或不需要了解的,这也是我们在设计初期希望的,api 保持稳定,用户并不需要关心过多实现细节,能够更快实现功能。

from stagesepx.classifier.keras import KerasClassifier


data_home = "./dataset"
model_file = "./keras_model.h5"

cl = KerasClassifier(
    # 轮数
    epochs=10,
    # 保证数据集的分辨率统一性
    target_size=(600, 800),
)
cl.train(data_home)
cl.save_model(model_file, overwrite=True)

而代码上的修改也仅仅是从 SVMClassifier 替换为 KerasClassifier。那么我们就可以利用这个训练好的模型进行预测,并得到一个字典:

OrderedDict([('-3',
              [<ClassifierResult stage=-3 frame_id=63 timestamp=1.062857142857143>,
               <ClassifierResult stage=-3 frame_id=64 timestamp=1.0797278911564627>,
               ...
             ('0',
              [<ClassifierResult stage=0 frame_id=1 timestamp=0.01687074829931973>,
               ...

从这个字典中我们可以知道,每一帧分别对应的:

  • 被分类到哪一个类别
  • 时间戳
  • 帧编号
  • ...

那么理论上,我们可以由下一段脚本来处理这些结果,达到自动计算的目的。回到我们一开始的设计:

应用完成的首点 - 初始阶段的结束点 = 启动耗时

对应到我们分好的类别(0、1、2、3、4),就是:

阶段4[0] - 阶段0[-1] = 启动耗时

即可自动计算出耗时。在此基础上,你可以根据实际需要进行额外的扩展,例如部署到 jenkins 上使其定时执行。

一些问题

看起来好像跟普通版本没什么变化,为什么要用 keras 分类器?

神经网络的介入主要为了强化分类的普适性。例如,抖音的插屏广告可能形态各异,而他们在被分类时又应该被分到同一个类别。让 SVM 完成这项任务未免有些强人所难。

训练完的模型效果并不好

动态情景下最大的问题是,每个阶段的表现可能是不相同的。以插屏广告为例,每次打开时插屏广告都不一样,此时我们需要扩大训练集,尽量让模型找到广告之间的共性,能够正确地将他们划分到同一类别。

对于抖音的例子,我这边大概用了四个视频作为训练集,此后的预测基本可以满足要求。当然对于真实的业务来说,你完全可以继续增大你的训练集,使其稳定性更强。

切换到 keras,性能是否有影响?对硬件(GPU)是否有要求?

诚然,神经网络的计算量相比之前要大许多,但并没有想象中那么大。

  • 模型并不复杂
  • 场景要求不高(仅做单标签分类)
  • 训练集很小(百级别)

在这种情况下,用 cpu 训练已经足够。参考数据:

  • 200 张图片
  • epoch = 10
  • MacBook Pro 2019 16g
  • 耗时 3 分钟左右
  • 最终 accuracy: 0.9871

除此之外,在切换到神经网络之后,虽然在训练过程上我们需要花费更多的时间,但分类的效率被极大地提高了。总的来说,这个结果是非常积极的。

最后

任何建议与意见可以留言或到主库留 issue~

https://github.com/williamfzc/stagesepx

最佳回复

很多同学问到了落地细节相关的事项,实际上我们也做了一套将它与各类终端绑定到一起的方案,能够让他直接与诸如 uiautomator2 之类的框架一同运作,快速落地。

可以看看这个项目:https://github.com/williamfzc/sepmachine
与这个例子:https://github.com/williamfzc/sepmachine/blob/master/example/android/custom.py

对于文档的话实在是没时间细写,有空会单独发文介绍。这个例子在 100 行内,包含了对微信整个启动过程的全自动测试方法,可以试跑看看。几个前提先提醒免得直接跳坑:

  • 需要 ffmpeg 安装好并配置在 $PATH 下
  • 需要 scrcpy 安装好并配置在 $PATH 下
  • 需要 pip 装一下 uiautomator2,例子里的自动化由他驱动,论坛搜一下好多帖子

既然要跟终端绑定,势必会带来很多环境、稳定性之类的麻烦事情,这也是我一直比较懒得做这个事情的原因。
不过比起这个,我还是希望这个项目能有一种比较漂亮的方式着陆吧。这个仓库应该可以帮到在落地上比较迷茫的同学,毕竟基于这个,需要写的代码量真的非常少了。
有问题与建议欢迎继续留言,或者到 sepmachine 的 issue 区 :)

共收到 36 条回复 时间 点赞
仅楼主可见

可以,你留我加你吧,我没法仅你可见

仅楼主可见
恒温 将本帖设为了精华贴 02月13日 09:27

我有比这更熟悉,完全自动化.图像识别 + 自动化脚本

chenyouan 回复

欢迎出来遛遛

chenyouan 回复

嗯嗯,看起来是已经落地挺完全的哈。不过这种做法在最初的时候我们就试过了,在 MTSC 上也已经拿出来分析过,弊端也是比较多的。就拿这篇文章里的内容来说的话:

  • 对于抖音这类高度动态化的 app 基本是无从下手
  • 即时分析这条路会导致高度的延迟,如你文章说到的 200-300ms,对于现代 app 来说是完全不可接受的误差

看了楼主的各种仓库,点出我的 “Follow”&“start”~
厉害🙇

如果是我可能只是记录下启动后有可能的 Activity 名称,然后启动后触发一个线程做轮询,一旦找到时间相减,用纳秒的计算返回。你这个就精细很多了。

陈子昂 回复

谢谢,埋点也是必备思路,我们正式落地时是结合着来的。

work_with_stagesepx实践了一下 auto、manual、dynamic
其中,auto、manual 成功,尝试 dynamic 第三步执行 classify_with_model.py 分类时总是报错,产生的中间数据不对,KerasClassifier 分析原理的具体细节不了解,请楼主指点一下,谢谢

2020-03-10 15:38:40.925 | DEBUG    | stagesepx.hook:do:24 - execute hook: GreyHook, frame id: 1
Traceback (most recent call last):
  File "classify_with_model.py", line 25, in <module>
    classify_result = cl.classify(video, stable, keep_data=True)
  File "/usr/local/lib/python3.7/site-packages/stagesepx/classifier/base.py", line 359, in classify
    result = self._classify_frame(frame, *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/stagesepx/classifier/keras.py", line 198, in _classify_frame
    return self.predict_with_object(frame.data)
  File "/usr/local/lib/python3.7/site-packages/stagesepx/classifier/keras.py", line 193, in predict_with_object
    frame = np.expand_dims(frame, axis=[0, -1])
  File "<__array_function__ internals>", line 6, in expand_dims
  File "/Users/aa/Library/Python/3.7/lib/python/site-packages/numpy/lib/shape_base.py", line 577, in expand_dims
    if axis > a.ndim or axis < -a.ndim - 1:
TypeError: '>' not supported between instances of 'list' and 'int'
栋杰 回复

比较怀疑是 numpy 版本问题:

  • 你先pip list看看 numpy 版本多少,回复我一下,可能有些依赖没处理好;
  • pip install --upgrade numpy 单独升级一下,再试试;

谢谢
还真是 numpy 版本的问题😂😂
之前是 1.17.4,升级到最新版 (1.18.1),再执行 classify_with_model.py 就通过了。

2020-03-10 17:59:11.842 | INFO     | stagesepx.reporter:draw:261 - save report to 2020031017591156.html

我们当前的测试场景是智能硬件系统本身的性能响应时间,如开关机时间、亮灭屏时间等场景,目前我们的测试方法是手机拍摄视频 + 手工分帧计算时间。

之前关注实践过 LZ 的框架,最终没有完全落地楼主的框架,比较遗憾,主要原因还是当时发现外置手机拍摄视频误差较大,解析计算时间也相对较慢。(当然也因为个人菜😅

之前看过小米的性能测试方案,是外置机械手 + 高速相机视频拍摄 + 视频自动分析,但作为我们这个小团队来说,好像也不是很适用(成本过高😅 )。

请问楼主有什么好的建议吗?

Joo 回复

我记得早前跟你沟通那会儿,我还没有想到得用 ffmpeg 去处理软件录制之后的视频,所以那个时候我也误以为软件录制行不通。现在来说,软件录制 +ffmpeg 已经成为了推荐方式,准确度在实验室效果也很不错,可以试试;

不过对于一些特殊场景,例如开关机这种,似乎也没办法用软件录制,确实是比较麻烦。硬件方向我了解到比较多的还是会用外置相机,但是分析这一块还是可以用这套分析工具的;

小米的同学似乎最近也在调研这个方案,不过进展跟结论我就不太清楚了,有相关同学也可以出来冒个泡;

很多同学问到了落地细节相关的事项,实际上我们也做了一套将它与各类终端绑定到一起的方案,能够让他直接与诸如 uiautomator2 之类的框架一同运作,快速落地。

可以看看这个项目:https://github.com/williamfzc/sepmachine
与这个例子:https://github.com/williamfzc/sepmachine/blob/master/example/android/custom.py

对于文档的话实在是没时间细写,有空会单独发文介绍。这个例子在 100 行内,包含了对微信整个启动过程的全自动测试方法,可以试跑看看。几个前提先提醒免得直接跳坑:

  • 需要 ffmpeg 安装好并配置在 $PATH 下
  • 需要 scrcpy 安装好并配置在 $PATH 下
  • 需要 pip 装一下 uiautomator2,例子里的自动化由他驱动,论坛搜一下好多帖子

既然要跟终端绑定,势必会带来很多环境、稳定性之类的麻烦事情,这也是我一直比较懒得做这个事情的原因。
不过比起这个,我还是希望这个项目能有一种比较漂亮的方式着陆吧。这个仓库应该可以帮到在落地上比较迷茫的同学,毕竟基于这个,需要写的代码量真的非常少了。
有问题与建议欢迎继续留言,或者到 sepmachine 的 issue 区 :)

试试这个软件,我们公司用硬件高速摄像机 获取 app 从点击到应用首页加载完成,根据拍摄的帧率,计算应用首次启动速度,还有页面跳转 滑动流畅等等

williamfzc 回复

楼主,请教一下跟埋点结合落地的方案大概是什么样的啊,最近在学习这个项目,也想看是否能跟现有的埋点结合一下,目前还没想到比较好的方案

lt-juejiang 回复

埋点跟这个完全没冲突啊


Hi,在测试的时候发现第三帧的时间比第四帧晚,想问一下你们有遇到类似的情况吗? 结果是使用 work_withstagesepx 的 manual 脚本跑出来的,视频使用 adb 录制。

Ciara 回复

pip list package 看一下 stagesepx 与 opencv 分别是什么版本

williamfzc 回复

opencv-python 4.2.0.32
stagesepx 0.11.1

Ciara 回复

用 ffmpeg 处理过?
没有的话视频私发下我吧

williamfzc 回复

好的 QQ 已经发你了~

williamfzc [该话题已被删除] 中提及了此贴 04月08日 12:59
Joo 回复

外设拍摄的话可以先做归一化和滤波 + 透视变换将有效区域提取出来,规避拍摄设备导致的误差问题,接下来就和录屏是一样的了

有没有简单现成的工具啊 大佬们

风里2289191 回复

说下你的目的

我用了大佬提供后面这个实现了整个自动化 app 录屏到自动计算时间,想问下生成的报告可以自定义吗? 没找到啥资料 谢谢

大赞,已经落地~

35楼 已删除

请问为什么我这执行 train_model.py 的时候,会如下错误?我的 tensorflow 版本是 2.4.0,python3.8 环境

2020-12-18 17:54:06.073 | DEBUG    | stagesepx.classifier.base:__init__:297 - compress rate: None
2020-12-18 17:54:06.073 | DEBUG    | stagesepx.classifier.base:__init__:298 - target size: (600, 800)
2020-12-18 17:54:06.073 | DEBUG    | stagesepx.hook:__init__:13 - start initialing: CompressHook ...
2020-12-18 17:54:06.074 | DEBUG    | stagesepx.hook:__init__:80 - compress rate: None
2020-12-18 17:54:06.074 | DEBUG    | stagesepx.hook:__init__:81 - target size: (600, 800)
2020-12-18 17:54:06.074 | DEBUG    | stagesepx.hook:__init__:13 - start initialing: GreyHook ...
2020-12-18 17:54:06.074 | DEBUG    | stagesepx.classifier.base:add_hook:319 - add hook: CompressHook
2020-12-18 17:54:06.074 | DEBUG    | stagesepx.classifier.base:add_hook:319 - add hook: GreyHook
2020-12-18 17:54:06.074 | DEBUG    | stagesepx.classifier.keras:__init__:50 - score threshold: 0.0
2020-12-18 17:54:06.074 | DEBUG    | stagesepx.classifier.keras:__init__:51 - data size: (200, 200)
2020-12-18 17:54:06.074 | DEBUG    | stagesepx.classifier.keras:__init__:52 - nb train samples: 64
2020-12-18 17:54:06.074 | DEBUG    | stagesepx.classifier.keras:__init__:53 - nb validation samples: 64
2020-12-18 17:54:06.074 | DEBUG    | stagesepx.classifier.keras:__init__:54 - epochs: 10
2020-12-18 17:54:06.075 | DEBUG    | stagesepx.classifier.keras:__init__:55 - batch size: 4
2020-12-18 17:54:06.075 | DEBUG    | stagesepx.classifier.keras:train:151 - no model can be used. build a new one.
2020-12-18 17:54:06.075 | INFO     | stagesepx.classifier.keras:create_model:99 - creating keras sequential model
2020-12-18 17:54:06.080939: I tensorflow/compiler/jit/xla_cpu_device.cc:41] Not creating XLA devices, tf_xla_enable_xla_devices not set
2020-12-18 17:54:06.081188: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2020-12-18 17:54:06.186 | INFO     | stagesepx.classifier.keras:create_model:129 - model created
Found 56 images belonging to 10 classes.
Found 21 images belonging to 10 classes.
2020-12-18 17:54:06.386301: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:116] None of the MLIR optimization passes are enabled (registered 2)
Epoch 1/10
2020-12-18 17:54:07.361360: W tensorflow/core/framework/op_kernel.cc:1763] OP_REQUIRES failed at sparse_xent_op.cc:90 : Invalid argument: Received a label value of 9 which is outside the valid range of [0, 6).  Label values: 9 4 7 0
Traceback (most recent call last):
  File "/Users/aaa/Downloads/work_with_stagesepx-master/dynamic/train_model.py", line 13, in <module>
    cl.train(data_home)
  File "/usr/local/lib/python3.8/site-packages/stagesepx/classifier/keras.py", line 178, in train
    self._model.fit(
  File "/usr/local/lib/python3.8/site-packages/tensorflow/python/keras/engine/training.py", line 1100, in fit
    tmp_logs = self.train_function(iterator)
  File "/usr/local/lib/python3.8/site-packages/tensorflow/python/eager/def_function.py", line 828, in __call__
    result = self._call(*args, **kwds)
  File "/usr/local/lib/python3.8/site-packages/tensorflow/python/eager/def_function.py", line 888, in _call
    return self._stateless_fn(*args, **kwds)
  File "/usr/local/lib/python3.8/site-packages/tensorflow/python/eager/function.py", line 2942, in __call__
    return graph_function._call_flat(
  File "/usr/local/lib/python3.8/site-packages/tensorflow/python/eager/function.py", line 1918, in _call_flat
    return self._build_call_outputs(self._inference_function.call(
  File "/usr/local/lib/python3.8/site-packages/tensorflow/python/eager/function.py", line 555, in call
    outputs = execute.execute(
  File "/usr/local/lib/python3.8/site-packages/tensorflow/python/eager/execute.py", line 59, in quick_execute
    tensors = pywrap_tfe.TFE_Py_Execute(ctx._handle, device_name, op_name,
tensorflow.python.framework.errors_impl.InvalidArgumentError:  Received a label value of 9 which is outside the valid range of [0, 6).  Label values: 9 4 7 0
   [[node sparse_categorical_crossentropy/SparseSoftmaxCrossEntropyWithLogits/SparseSoftmaxCrossEntropyWithLogits (defined at usr/local/lib/python3.8/site-packages/stagesepx/classifier/keras.py:178) ]] [Op:__inference_train_function_984]

Function call stack:
train_function

@williamfzc 在执行视频分析时,15 秒的视频花了 20 分钟分析完毕,但是执行日志没有捕捉到异常,版本是 0.15.3,请问是什么原因呢?

Chen Jinyu 回复

https://github.com/williamfzc/stagesepx/issues
到 issue 这边沟通哈
最好贴下你的脚本跟视频啥的,这个耗时肯定不合理

williamfzc 图像分类在兼容性测试中的应用 中提及了此贴 06月25日 17:01

训练好的 model 能发我下吗,我为啥训练不出高准确率的 model

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册