移动性能测试 阿里巴巴 Android 性能测试工具 mobileperf 开源 (天猫精灵 Android 性能测试-线下篇)

露客look · May 06, 2020 · Last by 李鹏 replied at May 13, 2020 · 3392 hits

官方首发 阿里巴巴技术质量:Android 性能测试工具 mobileperf 开源 (天猫精灵 Android 性能测试-线下篇)

背景

Android 性能稳定性测试工具mobileperf github 如果您觉得有帮助,请给个star,有问题欢迎加入文底钉钉群交流

露客 2018年加入天猫精灵,之前有过一些性能 稳定性测试经验,但天猫精灵跟我之前的项目经验不太一样,之前大多服务于单独的APP,比如测手淘就只是测手淘,而天猫精灵业务更复杂一些,主要有如下挑战:

1、除了天猫精灵手机APP,还有带屏天猫精灵上很多APP都需要支持,比如天猫精灵CC上有13个app,每个app使用场景各有不同,涵盖了通讯录、视频、音乐、购物等各种场景

2、相比手机app,除了点击操作的触屏链路,天猫精灵还有语音链路

3、手机app monkey test一般可能也就云测平台上跑几个小时,语音压测需要连续测试72个小时以上,测试时长远超云测工具,对工具的稳定性提出了新的要求

4、相对现在定价动辄几千块,均价2千左右的手机,天猫精灵定价只有几百,硬件配置差些,所遇到的性能 稳定性挑战会更严峻

需求

本着前期先能发现问题,再深入定位问题,所以确定了线下、线上分步走的策略

1、线下方案,能方便采集性能数据,工具要支持Android手机、天猫精灵各种Android定制设备,支持Android全版本,轻量化,使用低门槛,尽可能少侵入甚至零侵入设备

2、线上性能指标 问题定位

本文是Android线下篇

线下方案选型

工具选型

  • Android App

​ 代表:开源工具腾讯GT网易Emmagee

​ 劣势:Android低版本有些功能需要root,Android高版本跨进程获取数据,权限限制,不兼容

  • PC adb工具

​ 优势:非侵入,权限高,能发现问题

​ 劣势:需要连接数据线,便携性差点

  • SDK

劣势:侵入式,需集成SDK,不利于做竞品测试

GT github上已表示Android GT后续不再支持GT APP版本,只支持GT SDK

由于Android权限控制越来越严格,通过APP跨进程获取性能数据在Android高版本已越来越困难,由于adb shell权限比较高,相信Android会一直开放开发者权限,故方案选型阶段,采用了依赖adb的方案,开发了一套Android性能数据采集工具mobileperf

还有一种思路,仍然是app形态,但用了adb wifi通道,露客之前也有过一些测试工具app的经验,相比采用adb usb方式mobileperf的担忧:

  • 测试工具app,应用进程优先级,还是会受Android限制,担心系统资源不足,测试进程优先级不高,被系统kill概率大,在IOT低端设备上被kill概率更大,进程保活是业界难题,黑科技手段层出不穷,并且存在随时被官方封杀的风险,路只会越走越窄,mobileperf是PC程序,除非adb usb方式不能用了,设备失联,关机等恶劣情况,都OK,与其花费很大精力探索各种黑科技上,还不如把精力放在Android允许范围内倒腾
  • 带屏天猫精灵都是定制Android系统,测试工具app可能要做单独的适配,兼容性成本高点,这点mobileperf不用担心,只要是Android系统、adb能用就可以,在各种Android定制设备,使用成本更低
  • 由于是APP,系统需要单独分配资源,比如工具发现的anr,开发童鞋一看cpu占用信息,如果发现测试工具app占用cpu较高,就很容易受到挑战,找工具的锅(不排除有些ANR确实是工具导致的),而mobileperf采集都依赖系统命令,这种影响小些

  • 长时间测试,比如72小时以上,adb wifi担心会有点不稳定,毕竟要依赖网络

工具对比

mobileperf跟GT APP对比如下:
工具对比

架构

mobileperf整体架构图:

架构图

工具自身影响

mobileperf对PC的影响

对PC的影响

测试PC:MacBook Pro (Retina,15-inch, Mid 2015) 2.2 GHz 四核Intel Core i7

工具稳定性:mobileperf能支持跑72个小时以上,adb断开重连都能继续采集

工具适用性:支持mac linux windows平台

工具Android兼容性验证

mobileperf Android版本兼容性验证结果如下

phone model Android version result
HUAWEI Mate20 HMA-AL00 10 pass
HUAWEI Mate10 ALP-TL00 10 pass
Xiaomi MI 8 10 pass
HUAWEI Mate20 HMA-AL00 9 pass
HUAWEI Mate10 ALP-TL00 9 pass
HUAWEI Mate9 MHA-AL00 9 pass
HUAWEI P10 Plus 9 pass
HUAWEI Honor AL10 9 pass
samsung Note9 SM-N9600 8.1.0 pass
Oppo R15 PACM00 8.1.0 pass
VIVO X23 8.1.0 pass
XiaoMi Note3 8.1.0 pass
RedMi note5 8.1.0 pass
Xiaomi MI 5 8.0.0 pass
smartisan OD103 7.1.1 pass
HUAWEI TRT-AL00 7.0 pass
vivo Y66 6.0.1 pass
XiaoMi Mi2 5.0.2 pass

#

效果

mobileperf在项目中使用1年半,天猫精灵总共发现了性能 稳定性类问题几百个,bug解决率都是100%

采集原理

cpu

方案调研

1、dumpsys cpuinfo

2、top命令

3、通过proc/stat计算cpu使用率

两者区别:Android CPU使用率:top和dump cpuinfo的不同,看网上一番讨论,top更准

通过实验发现采集频率非常快时,top有点耗cpu,对手机本身性能有影响,自测,采集频率1s,top在低端手机上(红米)会占到7%(100%统计方式)的cpu使用率,天猫精灵采集频率5s,会有20%占用(400%统计方式),发现top的底层实现是读取proc文件,top对每个进程都有计算

网上提供了一种计算方式,原理上跟top一样,如果计算指定进程的cpu使用率,只需读对应的proc文件,通过jiffies计算就可以了,这样比top方式占用cpu低,计算方式如下

整机cpu使用率

通过读取/proc/stat ,这个文件包含了所有cpu核的汇总情况,所以后面计算不用考虑核数,占用率不会超过100%

cpu使用时间 = user+nice+system+iowait+irq+softirq

CPU总时间=user+nice+system+idle+iowait+irq+softirq = cpu使用时间 +cpu idle时间

总cpu使用率=(cpu使用时间2-cpu使用时间1)/(cpu总时间2-cpu总时间1)*100%

进程cpu使用率

通过读取/proc/pid/stat

进程cpu使用时间 = utime+stime

进程cpu使用率=(进程cpu使用时间2-进程cpu使用时间1)/(cpu总时间2-cpu总时间1)*100%

选定方案

采集时间间隔 ,配置文件中默认5秒,由于对采集频率要求不高,top支持同时采集多进程,结果简单易处理,实时性 可信度高,决定采用top的方式

测试过程中会生成cpuinfo.csv,可以测试过程中查看,表中各列解释

cpu table

汇总xlsx文件会在测试结束后生成,xlsx数据跟csv数据完全一致,xlsx汇总是根据csv的数据画的曲线(csv没有画图功能)

cpu trend

内存

整机内存 可用内存通过dumpsys meminfo获取 Total RAM 、Free RAM

各进程pss通过dumpsys meminfo package获取TOTAL行 Pss Total所在列的值,各进程PSS也可以通过dumpsys meminfo获取,只是拿不到各进程更详细的内存占比情况,比如堆大小、native、system、so大小等

经在CC上测试发现dumpsys meminfo比dumpsy meminfo package耗时长,dumpsys meminfo耗时6s多,dumpsys meminfo package能在一秒内完成,采集频率5s,dumpsy meminfo会导致CC上system_server系统进程cpu由2%增高到80%,所以降低了dumpsys meminfo采集频率,采用10倍设置频率采集(比如 dumpsys meminfo package 5s,dumpsy meminfo则50s)

由于要支持多进程的情况,现在各进程pss通过解析dumpsys meminfo结果得到,dumpsys meminfo package来获取各个进程的详细内存情况

在测试过程中会生成一个meminfo.csv文件,可以查看,表中各列解释
mem table

这个csv表格是用dumpsys meminfo得出的,汇总xlsx文件会在测试结束后生成,对应meminfo这个表格
mem trend

每个进程会有pss_部分包名的csv表格,这个表格是用dumpsys meminfo package得出的

pss table

能把每个进程的详细内存展示出来

汇总xlsx中对应pss_部分包名这个表格

pss trend

如果进程发生了内存泄露,根据曲线,很方便一眼就看出是哪部分导致泄漏

为了帮助定位内存泄漏问题,工具每隔一个小时会执行am dumpheap package ,dump进程内存,但不能像LeakCanary直接翻译出GC引用链,仍需人工分析下

流畅度(fps/丢帧)

fps通过dumpsys SurfaceFlinger或dumpsys gfxinfo(android8.0之后)获得最近128帧数据计算得出,fps=帧数/耗费时间

如果以上两种方式都不OK,机器有root,用service call SurfaceFlinger 1013获取帧数

通过dumpsys SurfaceFlinger的方式还会计算丢帧janky值

丢帧:相邻两次绘制之间的丢帧数,丢帧数越多,说明问题越严重,mobileperf默认丢帧数超过10帧算是严重丢帧

流畅度数据在fps.csv中

表中各列解释

fps table

页面打开耗时

mobileperf从logcat日志中抓取am_activity_fully_drawn_time和am_activity_launch_time(大多数情况)日志,

会生成launch_logcat.csv

launcher table

不过这种方式有个弊端,日志的耗时不能完全反馈真实的体验耗时,我们内部已有其他方案测试启动耗时

monkey(可限制activity)

mobileperf调用了Android原生的monkey,如果您想限制在指定内activity内跑monkey ,可以通过配置项,开启monkey 后,会在测试目录下生成monkey.log

#如果需要在限定activity内做monkey testmain_activity是模块的几个主入口,用分号; 分隔
#main_activity=com.alibaba.ailabs.genie.contacts.MainActivity
#activity_list是准许的activitymain_activity开启前提下有效
activity_list=com.alibaba.ailabs.genie.contacts.MainActivity;
com.alibaba.ailabs.genie.contacts.cmd.CmdDispatchActivity;
com.alibaba.ailabs.genie.contacts.cmd.transform.VoipToPstnActivity;
com.alibaba.ailabs.genie.contacts.add.AddContactsActivity;
com.alibaba.ailabs.genie.contacts.avatar.TakePhotoActivity;
com.alibaba.ailabs.genie.contacts.details.DetailsActivity;
com.alibaba.ailabs.genie.contacts.add.RelationshipActivity;
com.alibaba.ailabs.genie.contacts.details.DownloadTipsActivity;
com.alibaba.ailabs.genie.contacts.details.DownloadTipsMiniActivity;
com.alibaba.ailabs.genie.contacts.cmd.selectlist.call.VCallListActivity;
com.alibaba.ailabs.genie.contacts.cmd.selectlist.contacts.VContactListActivity;
com.alibaba.ailabs.genie.contacts.message.VoiceDetailsActivity

logcat日志(支持异常日志检测)

工具会保留全量logcat日志,每隔60万行会新建文件,辅助定位问题

logcat file

如果配置文件中配置了异常日志

exception config

会将logcat中出现的异常日志都保存在exception.log中

exception log

根据异常汇总日志,再去logcat日志查看详细上下文信息,可以快速定位问题

流量

通过读取/proc/net/xt_qtaguid/stats文件获取,因为Android提供的流量统计API – TrafficStats中,对uid进行流量统计的方法,能区分应用,底层就是读取了该文件

Android性能测试之网络流量

流量数据在traffics_uid.csv中,表中各列解释

traffic table

<=android9 读取/proc/net/xt_qtaguid/stats获取流量

Android10,/proc/net/xt_qtaguid/stats not found,用/proc/net/dev /proc/pid/net/dev 获取流量

电量

先通过dumpsys batteryproperties获取,如果获取不到,再通过dumpsys battery获取(Android9)

问题:插着usb,这两种方式获取到的并不精准,并非专业级电流电量测试,只能作为参考

电量数据在powerinfo.csv中,表中各列解释

power table

由于功耗软件测试方式不太精准,我们内部已用硬件方案测试功耗,此项mobileperf中默认关闭

常驻进程pid监控

天猫精灵是整机,跟很多手机app不一样,是应用级别app,可能会被用户手动kill掉,天猫精灵上有些系统优先级进程,不能挂掉,一旦挂掉,会导致无法使用,所以mobileperf新增了常驻进程pid监控,一旦pid发生了变化,认为发生了异常

#常驻进程,需要关注pid变化,多个进程,英文分号分隔
pid_change_focus_package=com.alibaba.ailabs.genie.smartapp;com.alibaba.ailabs.genie.smartapp:core

磁盘剩余空间检查

天猫精灵跟很多手机app不一样,随便压测就是3天以上,如果有写文件不正常,占满磁盘空间,会导致机器彻底无法使用,影响用户体验,所以测试结束时,添加了对磁盘剩余空间检查,如果使用空间超过80%,则自动提单

进程线程数

通过进程名获取pid,ls -lt /proc/pid/task,统计多少行数即线程数

答疑

为了方便大家更容易的接入mobileperf或讨论相关技术,大家可加入钉钉交流群32266824。为了方便大家交流,入群请注明姓名与公司等信息。

dingding qr code

最佳回复

不过这种方式有个弊端,日志的耗时不能完全反馈真实的体验耗时,我们内部已有其他方案测试启动耗时

一直也比较困惑启动时间该如何测试,实际用户体验的启动时间与打点计算出来的有明显差异,可以透露下贵司内部的其它测试方案吗

露客look 回复

2.如下图1与2,二者的不同的就是第一个群与第二群位置变换,原因是第一张图上为启动过程中加载完所有群,但是需求还有一个逻辑,就是东方时尚那个群符合某个特殊条件,在排序中优先于第二个群,这个特殊条件是从接口获取的,等于是加载完首页群,又获取到一个接口数据,进行再排序,东方时尚就有第二位调整到第一位,整个过程给人的体感是,未重新排序之前页面已经很完整了,或许一些用户认为启动已经完成,但是之后确实又有了一个变动,二者位置调换,所以想请教下,像这种加载完之后的基于接口的逻辑再处理要不要计入启动过程


共收到 16 条回复 时间 点赞

关注中

源码在github上。有几个问题:

  1. 对游戏类app的FPS采集有问题,我测试的Unity游戏的FPS采集到的都是0;
  2. 得到的cpu info的百分比占用没有归一化
  3. 内存数据还是用dumpsys meminfo的方法采集,这个方法如同它源码所说的一样:有很大的性能问题。所以导致采集频率不能太高。

非常期待阿里爸爸能够给出更好的解决方案。

Mark一下Mark一下

不过这种方式有个弊端,日志的耗时不能完全反馈真实的体验耗时,我们内部已有其他方案测试启动耗时

一直也比较困惑启动时间该如何测试,实际用户体验的启动时间与打点计算出来的有明显差异,可以透露下贵司内部的其它测试方案吗

感谢LZ分享,学习下用到自己项目中😂 😂 😂

感谢分享!先试用一下

秦岭 回复

录屏分帧,结合图像识别,这样更贴近用户真实体验耗时,在项目受认可

chentianqin 回复

fps需要在滑动时才有值,静止时是0,前提需排除静止的情况
1、Unity没有测试过,如果不是用的Android那一套绘制,可能获取不到
2、cpu百分比占用没有归一化是指没有换成100%的统计方式?恩,现在是X个核,就是X*100%的统计方式,自己fork下,除以核数,处理下不难
3、dumpsys meminfo在低端手机上耗时5 6S,中高端手机1s左右,手机配置越来越好,如果官方觉得不是问题,估计不会优化了

10Floor has been deleted
露客look 回复

大佬再请教一下,目前录屏分帧这个方法,有些计时标准相关的疑问,以方便分离开,所以分开以几个回复,还请帮忙指导下,谢谢。

1.如下图淘宝,可见这个界面控件已经加载出来,部分内容也加载出来,但是部分图片尚未显示出来,因为淘宝这类产品首页图片非常之多,加载耗时在所难免,如果计时到所有图片都加载出来,得出的启动时间会比较难看,所以想参考下,阿里计时确实是等待所有图片都加载完才叫启动结束吗,还是计时到控件 框架加载完毕,部分图片加载完毕,大致显示ok即可?

露客look 回复

2.如下图1与2,二者的不同的就是第一个群与第二群位置变换,原因是第一张图上为启动过程中加载完所有群,但是需求还有一个逻辑,就是东方时尚那个群符合某个特殊条件,在排序中优先于第二个群,这个特殊条件是从接口获取的,等于是加载完首页群,又获取到一个接口数据,进行再排序,东方时尚就有第二位调整到第一位,整个过程给人的体感是,未重新排序之前页面已经很完整了,或许一些用户认为启动已经完成,但是之后确实又有了一个变动,二者位置调换,所以想请教下,像这种加载完之后的基于接口的逻辑再处理要不要计入启动过程


露客look 回复

3.如下图,控件与图片,业务内容基本全部加载出来了,但是仍然要刷新,理由是智能推荐每次启动都会更新一批,然而这个更新的数据内容是在第一页的最底部,用户能看到的部分都没变,这种计时到'加载完'三个字消失,还是看到大部分页面内容没有变化,不用等‘加载完’消失呢,谢谢!!

露客look #14 · May 10, 2020 作者
秦岭 回复

这个要看产品形态和你们团队怎么协商了,有的以第一张图片加载完为结束,有的以用户可操作为结束,有的以全部加载完成为结束点

秦岭 回复

哈哈哈,终于看到了一样的问题,团队内部之前坚持的就是肉眼看完全启动完,但是不同的人去测本身就有偏差。
再者说性能本身就是零点几秒的慢慢误差,要是看图说话这么猜太难了。
所以还是要测量,图片对比这个我们暂时没搞。
我试了下XCTestMetric的启动时间测试,虽然没有完整覆盖图片下载这部分(其实不算app启动过程吧)。图片的异步加载和app本身的初始化和启动从技术上看是不是可以分开看,不然网络环境的波动以及图片资源大小的变化本身就使得这个测量过程没说服力了

李鹏 回复

我的方法是尽量使用同一个环境,这样受网络波动影响会小些,测多组数据,舍弃最大最小,剩下的求平均,这样更符合统计学!!

但是现在最麻烦的就是如何确定结束界面在哪个,就像我上面的疑问一样,到底是页面全部加载完,还是可用(其实可用状态只是图片加载了一部分,部分接口请求数据还未完成刷新),因为之前是简单的命令取页面渲染前的值为启动时间,未曾用图片切割,所以一直困在该如何确定结束标准,如果定的过于靠后时间过长又不好说服开发与老板,如果定的太前则有很多主观性(比如说可用这个,看起来有主观的因素,不好度量),加上他们都是老思维,用的打点日志方法,如何让他们接收这种测试结果!!

秦岭 回复

完全体会到你的难处,我也是想办法说服同事和老板来着。
这么说吧。app的库编译连接啥的这个app首页UI框架的构造、渲染,以及框架出现后各个图片的加载。到底技术上和业务上如何定义app启动过程,真的是个坑。
1.比如你测试的启动时间长了,有没有想过开发如何优化
2.或者你首页UI从10张轮播图变成1张,那么app启动性能变化了么?(此处作为探讨)
3.如何对比不同UI甚至UI更新逻辑的app之间的启动性能?比如我们的app甚至首页模块都是智能推荐,每次启动由于投放内容和用户行为,出现不同结构的数据流,你拿哪一种UI结构当做本app的启动性能呢?

目前XCTestMetric测量app开始创建到firstFrameRender,想必有它的理由,但是说服领导有点难

恒温 《Android 性能测试初探》合集 中提及了此贴 14 May 15:34
需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up