01 | App启动性能分析
基本的测试checklist和手段
专项测试(用户维度)
- 崩溃(Crash,弱网)
- 卡顿(掉帧,gc,cpu)
- 响应慢(启动时间,交互响应,H5加载)
- 发热(cpu,mem,io,network,gps等硬件使用)
- 掉电快(硬件占用)
- 兼容性问题(机型覆盖,回归)
专项测试(技术维度)
- 崩溃(自动遍历,monkey测试,横竖屏切换,快速进退)
- 卡顿(卡顿测试,内存泄漏测试,method profile)
- 响应慢(冷仍启动,界面切换,h5性能测试)
- 发热(method profile,gc统计,io统计,流量统计,硬件使用统计,耗电量分析)
- 兼容性问题(兼容性测试,自动化测试,自动遍历,monkey测试)
app性能
- android应有由很多的activity组成,这些activity的耦合度比较低
-
activity的启动流程
- 主要流程
1.Application OnCreate(加载第三方的sdk等)
2.Activity OnCreate(加载自身逻辑,发送远程数据请求,渲染界面List)
app启动性能指标
- 冷启动(进程已被kill,或新安装的应用)建议小于5s
- 暖启动(app在后台久了,会被内存管理kill,此时用户重启应用),建议小于2s
- 热启动(app在后台运行),建议小于1.5s
- 首屏启动(加上了stuff时间)
测试工具和方法
- adb logcat
- 录屏+视频拆帧:把1s拆成10帧,人工数帧,可以计算首屏启动时间
- uiautomator等自动化工具,每隔200ms打印page_source的变化
- traceview:android的分析工具
- 硬埋点:最准确,app启动前后植入埋点,再把数据回传到服务器,需开发配合,不常用
adb logcat 使用
package=com.xueqiu.android
-
adb shell pm clear $package
清除缓存 -
adb shell am force-stop $package
停止进程 -
adb shell am start -S -W $package/.view.WelcomeActivityAlias
启动app -
adb logcat | grep -i displayed
获取数据
adb logcat结果
- startTime:记录刚准备调用startActivityAndWait()的时间点
- endTime:记录startActivityAndWait()函数调用返回的时间点
- WaitTime:startActivityAndWait()调用耗时(endTime - startTime)
- TotalTime:创建进程+创建object+创建activity的时间
使用ffmpeg拆帧
adb shell am force-stop $package
adb shell screenrecord --bugreport --time-limit 30 /data/local/tmp/xueqiu.mp4 &
adb shell am start -S -W $package/.view.WelcomeActivityAlias # 或手动点击
adb pull /data/local/tmp/xueqiu.mp4 .
ffmpeg -i xueqiu.mp4 xueqiu.gif
ffmpeg -i xueqiu.mp4 -r 10 frames_%03d.jpg
02 | 接口性能
工具
- 代理工具:charles,burpsuite
1.电脑的流量都会经过charles,再到服务器
2.抓到请回和返回数据的内容 - 抓包工具:tcpdump,wireshark
1.主动请求服务器,抓取服务器返回的数据包
2.监听端口,抓取发送和返回的数据包
03 | webview性能分析
简介
- WebView是android中一个非常重要的控件,它的作用是用来展示一个web页面。它使用的内核是webkit引擎,4.4版本之后,直接使用Chrome作为内置网页浏览器。
chrome检查中的关键选项
- Disable cache:不加载缓存,从零载入
- 蓝色线:dom出现
-
红色线:图片等资源已加载完
- timing各字段:
1.waiting:服务器响应时间
https://cloud.tencent.com/developer/article/1083690
手机浏览器性能分析
04 | H5性能分析
参考资料
资源加载指标
- prompt for unload:访问新页面时,旧页面卸载完成时间
- redirect:重定向,用户注销登录返回主页面或跳转到其他网站
- app cache:检查缓存是否打开
- DNS:DNS查询时间,若是长连接或请求文件来自缓存等本地存储则返回fetchStart时间点
- TCP:与服务器建立连接的时间
- request:浏览器发起请求的时间
- response:拿到第一个响应字节到最后一个响应字节的时间
- processing:各种状态的时间点
- load:触发load事件执行时间
获取单个资源的性能
浏览器 -> console -> PerformanceTiming
自动化获取性能指标
- chrome -> console :
1.window.performance.timing
2.window.performance.timing.responseEnd - window.performance.timing.responseStart
- python代码
from selenium import webdriver
class TestPerformance():
def test_performance(self):
driver = webdriver.Chrome()
driver.get("http://www.baidu.com")
print(driver.execute_script("return JSON.stringify(window.performance.timing)"))
05 | CPU统计
CPU与GPU的关系
- 图形api不允许CPU直接与GPU通信
- 通过中间层链接CPU和GPU
- 中间层维护一个队列
- CPU把display list放入队列
-
GPU从队列取数据进行绘制
GPU渲染工具
- android开发者模式提供性能调优工具:开发者选项 - GPU呈现模式分析 - 在屏幕上显示为条形图
GPR显示内容
- 绘制每一帧所消耗的时间
- 不同颜色代表UI绘制的不同阶段
1.官方资料:https://developer.android.com/topic/performance/rendering/inspect-gpu-rendering - 柱状图的中间有一根绿色的横线,代表16ms绘制时间基准
- GRP会统计并显示app最近运行的128帧
06 | mem统计
名词解释
名词术语 | 全拼 | 解释 |
---|---|---|
VSS | virtual set size | 虚拟内存(包含共享库占用的内存) |
RSS | resident set size | 实际使用的物理内存(包含共享库占用的内存) |
PSS | proportional set size | 实际使用的物理内存(比例分配共享占用内存) |
USS | unique set size | 进程独自占用的物理内存(不包含共享库占用的内存) |
各指标解析
VSS:衡量虚拟内存大小无太大用处,无法知道分配物理内存大小
RSS:各进程的RSS相加,会超过系统内存使用量
PSS:各进程的RSS相加,就是系统内存使用量
USS:是PSS中自己的部分,不包含任何共享部分
procstats
adb shell dumpsys procstats --hours 3
adb shell dumpsys meminfo com.xueqiu.android
输出详解
- 进程详情
1.进程名称/user/versionCode
2.状态:minPSS-avgPSS-maxPSS/minUSS-avgUSS-maxUSS - 100%:表示在总的时间内,进程在各种状态下的消耗(100%即在这段时间,进程一直处于运行当中)
- total:表示进程的综合占用情况
- Imp Fg:加载到前台
- Service:标识是否是服务
- Persisitent:标识是否一直驻留在内存,与service一样表示内存进驻的级别
- Top:标识是否是顶层进程
- Receiver:标识是否是广播进程
补充
同一时间有多个应用占用内存,测内存要对比不同版本的内存大小
07 | 网络流量分析
显示网路流量
adb shell dumpsys netstats
找到应用UID
adb shell dumpsys package com.xueqiu.android | grep userId
-
adb shell dumpsys netstats | grep 10051
1.rb:receive byte
2.rp:receiver package
3.tb:transport byte
4.tp:transport package
08 | 卡顿分析
cpu、网络、内存都有可能引起卡顿
systrace
- sdk/platform-tools/systrace
- 须python2.7
运行中遇到的问题
- 提示"No module win32com"
解决:pip2 install pypiwin32
- 提示"No module six"
解决:pip2 install six
使用
cd D:\Programs\android-sdk-windows\platform-tools\systrace
-
python systrace.py -e 设备 -l
进入录制模式,在设备上操作,命令行按下enter结束录制,并在systrace目录下生成result
查看报告
- 蓝点:警告
- cpu
- 指定app
- 绿色圆点:代表每一帧,点击绿色圆点,按M键显示加载时间
- 函数调用
- 任务状态:灰-休眠,蓝-可运行,绿-运行,橙-不响应
- 常用命令:w-放大,s-缩小,m-找到下一帧,显示时间
卡顿影响因素
- 内存问题(内存抖动,垃圾回收)
- cpu(计算耗时)
- render(布局复杂,overdraw)
帧分析
- 冰冻帧:一个帧超过0.7s
09 | 耗电量测试
应用耗电过大,导致手机过热,cpu降频。耗电量测试就是通过不同的测试场景,找出app高耗电的场景并解决
安装
- golang
- python 2.7
git clone https://github.com/google/battery-historian.git
go get -d -u github.com/google/battery-historian/...
- 修改setup.go中的closureCompilerVersion="20190513"
go run setup.go
go run cmd/battery-historian/battery-historian.go
batterystats收集数据
- 清理耗电量数据
adb shell dumpsys batterystats --reset
adb shell dumpsys batterystats --enable full-wake-history
- 运行测试用例或手动操作
- 收集数据
1.android 7.0及以上:adb bugreport bugreport.zip
2.android 6.0:adb bugreport > bugreport.txt - 上传数据
1.打开localhost:9999
2.把zip或txt上传
查看报告
- 指标含义
1.battery_level:电量
2.plugged:充电状态及充电时长
3.screen:屏幕是否点亮
4.top:显示当前手机运行的app
5.status:电池状态信息,充电、放点、未充电、已充满、未知等
10 | 健壮性测试
测试系统在出现故障时,能否自动恢复或忽略故障继续运行
操作过程
- 对应用进行盲点
- 网络不佳
- 数据不通
使用工具
- Monkey,Maxim,Charles,Appcrawler
11 | 弱网测试
弱网问题
- 封闭环境,网速降低
1.掉包
2.数据无法加载
3.消息更新不及时
弱网速度
- 低于2G速率
- 3G
模拟弱网
-
charles代理设置
-
设置本地代理
- 开启节流(Proxy-Throttle Setting -Enable Throttling)
名词解释
- Bandwidth(带宽:理论网速上限)
1.上行:数据流出,如上传
2.下行:数据流入,如下载
3.带宽的单位是Mbps,真实的网速要除以8,如带宽是10M,真实网速最高可达到1.25M - Round-trip Latency(请求往返延迟)
1.客户端与服务器第一次往返通信的延迟,单位毫秒 - MTU(最大传输单元)
1.传输的TCP数据包的最大尺寸 - Reliability(可靠性)
1.衡量连接完全失败的可能性,如为50%,则只有50%的成功率
12 | 实战1
非功能测试(针对专项质量问题的测试)
- 移动端性能问题(硬件相关,如cpu、mem、disk、network、gpu)
- 移动端场景问题(场景相关,如弱网测试、兼容性测试、国际化)
常用的测试方案
- android
1.ddms
2.android studio最新版本的集成工具
3.hook
4.代码插桩 - IOS
1.instruments
2.hook
3.代码插桩
app启动性能指标
- 首次安装启动:会耗费较多时间初始化,如下载补丁、缓存数据
- 冷启动:进程不存在(主要关注,不超过5秒)
- 暖启动:进程存在,界面不存在
- 热启动:界面对象依然存在,只是从后台切到前台
- 首屏启动:第一屏加载完成
测试启app动性能的方法
- logcat观察启动时间
- 录屏拆帧
- 注:通常杀掉进程,不清理数据
web性能
https://developers.google.com/web/tools/chrome-devtools/network/reference#timing-explanation
13 | 实战2
chrome中network的使用
- 蓝线:dom 加载完成
- 红线:所有资源加载完成
- 捕获:查看加载图片
- 根据 waterfall 排序 ,进行资源筛选
- shift 查看资源依赖关系
chrome模拟手机
- setting-devices,勾选手机
chromer中performance的使用
- record button
- screenshorts
- Diable JavaScript samples 禁用js样例,禁用后调用关系简单很多
-
Enable advanced paint instrumentation
appium性能获取
from appium import webdriver
from selenium.webdriver.common.by import By
class TestWebview:
_package = "com.xueqiu.android"
_activity = ".view.WelcomeActivityAlias"
def test_webview(self):
caps = dict()
caps["platformName"] = "android"
caps["deviceName"] = "hogwarts"
caps["appPackage"] = self._package
caps["appActivity"] = self._activity
caps["noReset"] = True
# 需要对应版本的 chromedirver ,才能在 webview 中执行 js 代码
caps["chromedriverExecutable"] = "C:/develop/chromedriver/chromedriver2.20.exe"
# 初始化driver
self._driver = webdriver.Remote(
"http://localhost:4723/wd/hub",
caps)
self._driver.implicitly_wait(15)
# 进入到 webview
self._driver.find_element(By.XPATH, "//*[@text='交易']").click()
# 切换上下文到 webview
webview = self._driver.contexts[-1]
self._driver.switch_to.context(webview)
# 执行 js 代码,获取性能数据
all_time = self._driver.execute_script("return window.performance.timing")
# 对数据进行二次操作
response_time = all_time['responseEnd'] - all_time['responseStart']
print(response_time)
使用adb shell 获取cpu的使用率
while true;do adb shell top -n 1 | grep xueqiu | awk '{print $3}';done
14 | 实战3
https://www.w3.org/TR/navigation-timing/#performancenavigation
navigation
TYPE_NAVIGATE = 0
TYPE_RELOAD = 1
TYPE_BACK_FORWARD = 2
-
window.performance.navigation.type
新打开页面,type的初始值是0,随着页面操作,type的值随之变化;如刷新页面,type的值变为1
使用js模拟浏览器动作
window.history.back()
window.history.forward()
window.location.reload()
window.location.href=“https://www.baidu.com/"
window.location.href # 获取当前网址
将手机内容下载到本地
adb pull ///data/user/0/com.xueqiu.android/files/h5/modules_new/xueqiu.com ~/Desktop/xueqiu.com
查看webview网址
adb logcat | grep http
adb logcat -c
清除logcat
唤醒锁
https://developer.android.google.cn/topic/performance/vitals?hl=en
- 唤醒锁阻止设备进入睡眠模式,若唤醒锁不释放,耗电量会很高
-
adb shell dumpsys power
查看唤醒锁
- 避免使用唤醒锁
https://developer.android.google.cn/guide/background - 唤醒锁改进:使用前台服务
https://developer.android.google.cn/guide/components/services#Foreground
Amdahl定律
- S:加速比
- a:系统某部分所需时间与总时间的比例
-
k:性能提升比例
Amdahl特殊情况
-
考虑k->无穷