移动测试基础 [穿山甲系列] 找出后台偷偷耗电的元凶

匿名 · 2017年12月29日 · 1060 次阅读

作者:万宇

团队:腾讯移动品质中心 TMQ

背景故事

先来看一个浏览器用户反馈。

如图所示,在浏览器用户反馈中,耗电一直是头部问题之一,用户对于电量是非常敏感的,特别是那种类似 “我明明就没用,怎么还在耗电?” 的后台耗电问题,更容易引起用户的抱怨。

遇到这些情况,项目组和测试组都比较无奈。我们明明一直都有做耗电测试,本地的耗电监控也一直跑的很溜。但是线上仍然有这些问题,应该怎么办呢?

所以,我们需要一种新的耗电监控的方案,来解决线上用户反馈的耗电问题。

方案分析

对于线上用户耗电的监控,我们需要解决两个问题。

1、线上用户不同于本地测试,不可能随时把手机拿到进行调试,我们如何在 app 端获取足够的信息,以方便后期的调试分析?

2、线上用户数量庞大,不像本地测试才个位数的机器,这么多用户,手工分析太耗时,我们如何进行自动化分析?

先考察一下现有的耗电监控的方案:

测试方法一:BatteryHistorian(https://github.com/google/battery-historian

Battery Historian 是 Google 推出的专用来分析 Android App 耗电的工具,通过简单的操作便可在网页中生成比较详细的图表,展示手机上各模块电量消耗情况。我们主要用 Battery Historian 来做定期的例行测试,并以邮件的形式同步测试结果。

BatteryHistorian 报表

测试方法二:Method Profiling

针对常见的用户场景,在浏览器切后台时通过 DDMS Method Profiling 抓取后台执行的所有任务。Method Profiling 一般是用来分析性能问题的,它会记录每一个线程、每一个方法的耗时,也正是利用了这一点,我们可以清楚地看到浏览器在切后台后都做了哪些事情。

对比两种方案, 最终我们选择了基于后台 Method Profiling 方案,因为这个方案有两个优点。

1、MethodProfiling 在用户手机上容易执行, 调用一个函数抓 trace 即可, 而 Battery Historian 需要执行 shell 命令。

2、MethodProfiling 有更加丰富的函数执行信息, 而 Battery Historian 只能够获取一些系统事件。

技术实现

线上监控别于本地测试,本地测试可以简单粗暴,但在用户的手机上,必须考虑方案对用户的影响。Method Profiling 生成的 Trace 文件相对来说是比较大的,最大可能有几十兆,我们不可以把所有用户的 Trace 文件都上报上来。

另外,监控本身可能导致耗电,例如我们首先排除的方案——用一个例行线程不断记录当前所有线程,所以在设计方案时需要将监控本身的影响降到最低。

几轮讨论后,我们最终采用了这样的思路——首先监控是否存在后台耗电现象,当判断为后台耗电现象后开始 Method Profiling 并通过穿山甲上报。

这样我们上报的都是经过筛选的有问题的场景,一方面减轻了后台数据存储的压力,另一方面也相当于做了过滤,减轻后台分析的工作量。

最终线上耗电监控的具体方案如下:

1、切后台时,记录当前进程对 CPU 占用的时间片;

2、切后台一段时间后,再获取进程对 CPU 占用的时间片,如果发现耗电异常,开始 Method Profiling;

3、MethodProfiling 进行一段时间后停止,上报 trace 文件到穿山甲后台;

4、穿山甲后台对上报的 trace 文件进行分析和处理,并自动提 BUG 单。

关键技术点一:判断耗电异常

APP 耗电的产生主要是对 CPU 产生了占用,我们通过获取浏览器占用 CPU 时间片的数据来判断是否异常耗电。在 Linux 系统中,可以通过/proc//stat 查看进程对 CPU 的占用数据。

打印的第 14~17 个参数依次表示(单位:jiffies):

114242 utime,任务在用户态运行的时间

20692 stime,任务在核心态运行的时间

6 cutime,累计的任务的所有的 waited-for 进程曾经在用户态运行的时间

2 cstime,累计的任务的所有的 waited-for 进程曾经在核心态运行的时间

Jiffies 是 Linux 内核中代表时间的变量。系统中定义了一个常数 HZ,代表每秒种最小时间间隔的数目,jiffies 的单位就是 1/HZ。每个 CPU 时间片,jiffies 都要加 1。进程的 CPU 时间片占用就是用户态 + 系统态的 jiffies,进程占用的 jiffies 越大,对 CPU 的占用越多。

114242 + 20692+ 6 + 2 = 134942 (jiffies)

在浏览器切后台时,记录当前进程占用的 jiffies,当切后台达到设定时间后(10 分钟),再次获取当前占用的 jiffies,当两次差值超过设定阀值时(400jiffies),判定为发生了后台耗电事件。阈值设定参考了手机厂商后台耗电的评判标准。

关键技术点二:上报分析

当判定后台耗电后,开始抓取 Trace,时长 1 分钟,Trace 结束上报数据到后台。

正式版用户数庞大,我们上报的 trace 文件相对来说比较大,如果正式版做监控上报数据量会相当庞大, 目前资源无法支持。当存在耗电场景时,抽取一部分用户应该也是可以监控到的,所以我们选取一部分内测版的用户做监控和上报耗电异常。另外为了避免消耗用户流量,我们只会在 WiFi 环境下上报数据。

当存在耗电问题时,上报上来的 trace 文件会比较多,我们不可能每一个上报都做人工分析处理,所以需要一个程序来进行自动化的分析。

对 trace 数据文件的分析参考了 TraceView 源代码,主要是对 Metho Profiling 文件格式的解析。从 Method Profiling 数据中我们可以得出当次上报有多少个线程在运行,每个线程里都调用了哪些方法,以及每个方法的调用栈、耗时等。

有了方法的耗时, 调用栈等信息, 是不是就可以确定问题了?

一个耗时长的调用栈, 是不是就是耗电的元凶呢?

答案:并不是!

根据历史经验, 一个孤立的调用栈, 就算它比较耗时,但很多时候并不是耗电问题的元凶. 真正的耗电原因, 常常是一些定时任务, 浏览器切后台以后本应该停止, 但这些任务还一直在执行, 导致耗电量大, 而这些调用栈, 具有下面一些特征:

(1)多次被调用;

(2)调用具有规律性;

(3)调用比较耗时。

所以,我们从 trace 文件中,对每个调用栈,分别计算下面 3 个指标。

1)调用次数,记为 count;

2)调用时间间隔的方差, 记为 diviation;

3)运行耗时, 记为 cost。

针对每一个调用栈, 我们给出一个评分:

Score = cost * count / diviation

分数越大的调用栈,越可能是耗电问题。同时,我们把类似的栈进行合并,上报次数越多的调用栈,影响面越广。最终,我们根据排序,将 Top50 的调用栈标记为疑似耗电问题,自动提交 Bug。

Trace 源文件


最终 Bug 信息:

分析结果:

实施效果

以下是从引入线上电量监控以来的相关数据统计。

关注微信公众号:腾讯移动品质中心 TMQ,获取更多测试干货!

版权所属,禁止转载

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