移动端测试 APP启动性能分析 WebView性能分析 H5性能分析 卡顿分析 帧分析 CPU统计 网络流量分析 耗电量指标 弱网测试 健壮性测试 兼容性测试 Amdahl

  • Post author:
  • Post category:其他


Android官网使用指南性能:

https://developer.android.com/topic/performance



一、APP启动性能分析


APP的启动过程


调用起APP、创建一个空白窗口、启动一个进程 ——> Application OnCreate 开始调用起App ——> Activity OnCreate 创建主线程MainThread(页面的渲染,数据的初始化)

在这里插入图片描述


启动性能指标


冷启动:第一次启动,无任何进程和数据

暖启动:之前启动过,存在缓存的数据

热启动:进程都还存在

首屏启动:页面完全加载完全的时间


对于以上的建议时间


Cold startup takes 5 seconds or longer 冷启动不超过5s

Warm startup takes 2 seconds or longer 暖启动不超过2s

Hot startup takes 1.5 seconds or longer 热启动不超过1.5s



主要流程

1、adb logcat 查看日志

2、录屏+视频拆祯

3、uiautomator等自动化工具200ms巡检界面变化

4、traceview

5、硬埋点 页面加载加了获取时间性能的埋点


logcat使用


package=com.xueqiu.android

清理缓存数据:adb shell pm clear $package

停止进程:adb shell am force-stop $package

执行上面的两个行为后,让启动的app变得冷启动

启动app:adb shell am start -S -W $package/.view.WelcomeActivityAlias

获取数据:adb logcat | grep -i displayed


查看结果


1、startTime: 记录刚准备调用startActivityAndWait()的时间

2、endTime: 记录startActivityAndWait()函数调用返回的时间点

3、WaitTime:startActivityAndWait()调用耗时 WaitTime = endTime – startTime

在这里插入图片描述


ffmpeg拆祯方法



作用

:计算每个阶段时间


原理

:先把APP停止 – 使用录屏录制启动的过程 – 获取到录制视频后(这时在模拟器),把获取到的视频拉取到本地电脑 – 然后拆祯为gif图 – 再拆成jpg图,通过1s的图拆成多少份后,计算多少张图片完成了这个加载的动作。然后用图的数量*1s拆成的分数,得出这个动作所消耗的时间。

使用说明:

package=com.xueqiu.android   测试的包名
adb shell am force-stop $package     停止测试软件
adb shell screenrecord --bugreport --time-limit 30 /data/local/tmp/Test.mp4 &   录屏30s
adb shell am start -S -W $package/.view.WelcomeActivityAlias wait
adb pull /data/local/tmp/Test.mp4   拉取录制的视频到本地
ffmpeg -i Test.mp4 Test.gif		视频拆成gif图片
ffmpeg -i Test.mp4 -r 10 frames_%03d.jpg  把gif图1s的图片拆成10份(也就是一张图片用例0.1s)



二、WebView性能分析


开发者工具


蓝色线:DOM出现

红色线:资源加载完成

Disable cache:加载缓存

在这里插入图片描述


fiter过滤表达式


domain.展示domain中的资源,*.com

has-response-header.包含指定HTTP响应header

is. 表达式

larger-than.展示大于某个尺寸的资源,1000等于1k

method.指定http请求方法,比如get或者post

mime-type.资源mime类型,比如application/json

scheme.HTTP(scheme.http)或者HTTPS(scheme:https).

status-code.状态码

在这里插入图片描述


performance使用


在这里插入图片描述

加载详情

在这里插入图片描述

对应字段说明:

https://developers.google.com/web/tools/chrome-devtools/network/reference?utm_source=devtools#timing-explanation


手机浏览器性能分析


原理:通过inspect把手机中的webview页面加载到PC端的浏览器中,然后通过浏览器的开发者工具查看


inspect使用注意点


1、模拟器使用6.0默认支持

2、物理机需要打开app内开关

在这里插入图片描述

3、PC端使用的chrome浏览器版本62.XXX (防止控制台样式异常)



三、H5性能分析

W3C性能说明:

https://www.w3.org/TR/navigation-timing/


在这里插入图片描述


资源加载指标说明


prompt for unload:访问一个新页面时,旧页面卸载完成的时间

redirect:重定向,用户注销登陆时返回主页面和跳转到其他的网站等

app cache:检查缓存,是否打开

DNS(域名系统):DNS查询时间,如果时长连接或者请求文件来自缓存等本地存储则返回fetchStart时间点

TCP:与服务器建立链接的时间

request:浏览器发起请求的时间

response:拿到第一个响应字节到最后一个响应字节的时间

processing:各种状态的时间点

load:触发load事件执行的时间


获取单个页面资源的性能

window.performance.timing

在这里插入图片描述


获取对应的操作码

window.performance.navigation.type

跳转 0

刷新 1

后退 2


JS模拟的基本操作

window.history.back()  //  返回
window.history.forward()   //  前进
window.location.reload()   //  刷新
window.location.href="https://www.baidu.com/"   //跳转到某个页面
window.location.href   // 查看本地的url
from appium import webdriver
from selenium.webdriver.common.by import By

def test_APP():
    desire_cap = {
        "platformName": "android",
        "deviceName": "emulator-5554",
        "appPackage": "com.xueqiu.android",
        "appActivity": ".view.WelcomeActivityAlias",
        "noReset": True,  # 保存缓存,  热启动
    }
    driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desire_cap)
    driver.implicitly_wait(16)
    driver.find_element(By.XPATH,"//*[@text='交易']").click()
    webview = driver.contexts[-1]
    driver.switch_to.context(webview)

    print(driver.execute_script("return window.performance.navigation.type"))
    driver.execute_script("window.location.href='https://www.baidu.com/'")
    driver.execute_script("window.location.reload()")
    print(driver.execute_script("return window.performance.navigation.type"))



四、卡顿分析


方式一、systrace SDK 自带分析工具


1、位置:sdk/platform-tools/systrace

2、需要使用python2.7

3、启动过程遇到少的文件,按需install


使用

1、启动设备:python systrace.py -e 192.168.181.102:5555 -l
不加参数启动开始录制:python2 systrace.py
2----运行模拟器上的对应要测的Activity----
3、停止录制手机报告:按下enter
4、在sdk/platform-tools/systrace获取报告trace.html

在这里插入图片描述

结果查看

在这里插入图片描述


详细信息


1、帧点

绿色:16.6ms内,黄色,红色超过16.6ms

2、任务状态

灰色:休眠 蓝色:可运行 橙色:不响应

3、函数调用


方式二、dumpsys gfxinfo

 adb shell dumpsys gfxinfo com.xueqiu.android

在这里插入图片描述


查看具体信息

 adb shell dumpsys gfxinfo com.xueqiu.android

在这里插入图片描述

在这里插入图片描述


使用matplotlib图形绘制

from matplotlib import pyplot

def test_draw():
    import subprocess
    cmd = "adb shell dumpsys gfxinfo com.xueqiu.android"
    res = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    # print(str(res.stdout.read(),encoding='utf-8'))
    lines = res.stdout.readlines()  # readlines()获取的是list
    # print(lines)
    i = 1
    # 判断下是否是对应的包
    for line in lines:
        i += 1
        if "com.xueqiu.android.common.MainActivity" in line.decode("utf-8"):
            break
    # 使用列表生成式,对获取的数据处理,并获取新的lines列表
    lines = [data.decode("utf-8").replace("\r\n","").replace("\t"," ").strip() for data in lines]
    lines = lines[i:i + 120]  # 获取i行到i+120行的数据
    print(lines)
    datas = [[] for row in range(4)]  # 生成一个空的二维数组 [[],[],[],[]]
    # lines = [14.84 0.2 6.17 11.58,14.00 0.4 6.66 11.11,.....]
    for x in lines:
        datas[0].append(float(x.split()[0]))  # 获取lines中每组数据的第1个值  14.8,并且添加到datas[[14.8,],[],[],[]]
        datas[1].append(float(x.split()[0]))  # 获取lines中每组数据的第1个值  14.8,并且添加到datas[[14.8,],[0.2],[],[]]
        datas[2].append(float(x.split()[0]))  # 获取lines中每组数据的第1个值  14.8,并且添加到datas[[14.8,],[0.2],[6.17],[]]
        datas[3].append(float(x.split()[0]))  # 获取lines中每组数据的第1个值  14.8,并且添加到datas[[14.8,],[0.2,],[6.17,],[11.58,]]
    # print(datas)

    # 绘制成图
    fig = pyplot.figure() # 生成一个画板
    # num = 1
    # for n in datas:
    #     ax = fig.add_subplot(2,2,num)  # 生成一个2*2图形
    #     ax.plot(n)  # 绘制第一个数组的图  plot折线
    #     num += 1
    # pyplot.show()

    # 分组绘制4个图  如果绘制到一个图中,fig.add_subplot(X,X,1),最后一个数字都改为1
    ax1 = fig.add_subplot(2,2,1)
    ax1.plot(datas[0])  # 折线图
    ax1.set_title("Draw")  # 标题
    ax1 = fig.add_subplot(2,2,2)
    ax1.scatter(range(120),datas[1])  # 散点图
    ax1.set_title("Prepare")
    ax1 = fig.add_subplot(2,2,3)
    ax1.hist(datas[2],range(5)) # 柱状图
    ax1.set_title("Process")
    ax1 = fig.add_subplot(2,2,4)
    ax1.plot(range(120),datas[3],'--k')  # 虚线图
    ax1.set_title("Execute")

    pyplot.show()

在这里插入图片描述


datas处理后数据形式


在这里插入图片描述



注意 ⚠️ : gfxinfo信息会有实效性,时间长了就获取不到了,注意刷新和模拟器中开发者选项中“GPU呈现模式分析”



卡顿影响因素

内存问题 (内存抖动、full gc)

cpu (计算耗时)

render(布局复杂、overdraw)



五、帧分析

冰冻帧:一个帧超过0.7s (橙色、红色)

帧分析:adb -s devicesname shell dumpsys gfxinfo | less



六、CPU统计


CPU与GPU关系


1、图形API不允许CPU直接与GPU通信,会通过Graphics Driver中间件进行连接

在这里插入图片描述

2、过程:CPU进行数据的处理 —> 处理后到Graphics Driver,Graphics Driver会维护一个队列,CPU把display list放入队列。—> GPU从队列去数据进行绘制

在这里插入图片描述


GPU渲染工具


Android开发者工具提供性能调优工具

GPU渲染分析:GPU-RENDERING-PROFILE

在这里插入图片描述

在这里插入图片描述


GPR显示内容


1、绘制每一帧所消耗的时间

2、不同的颜色代表UI绘制的不同阶段

3、并且子啊柱状图的中间还有一根绿色的横线代表16ms的绘制时间基准

4、GPR会统计并显示app最近运行的128帧

在这里插入图片描述

在这里插入图片描述


蓝色


View需要先转换为GPU能识别的格式(中间件处理的过程)

蓝色较高

  • view突然无效(invalidate) ->队列中的数据失效,view:绘制布局、样式、事件等的一个容器
  • onDraw函数中做了复杂的绘制逻辑 (onDraw函数:绘制图形的函数)

    在这里插入图片描述


    红线


    OpenGL处理DISPLAYIST,将处理结果传递给GPU (即中间件处理过程,红色代表中间件负载过高)

    红色较高:

    view过于复杂

    view重复提交


橙色


CPU在等待GPU完成工作 (GPU绘制的过程)

橙色较高

GPU任务负载过高,view绘制太复杂

不同颜色的意义(Android官网

https://developer.android.com/topic/performance/rendering/inspect-gpu-rendering



在这里插入图片描述

在这里插入图片描述



mem统计(手机内存统计)对于app的内存的优化,我们通常只是对不同版本对比,不看实际的占用多少


内存耗用名词


在这里插入图片描述


指标解析


VSS:衡量虚拟内存大小五太大用处。无法知道分配的物理内存大小

RSS:个进程的RSS相加,会超过系统内存使用量(不是按比例分配)

PSS:个进程的PSS之和,就是系统的内存使用量 (按比例分配的)

USS:是PSS中自己的部分,不包含任何共享的部分 (app之间交换使用共同的数据会产生共享的内存)


内存占用大小规律:


VSS>=RSS=>PSS>=USS


查看内存第一种方式:procstats


adb shell dumpsys procstats –hours 3 (查看3小时内的内存使用情况)


输出信息


在这里插入图片描述


输出格式


进程详情

进程名称/USER/VersionCode

状态:minPSS-avgPSS-maxPSS/minUSS-avgUSS-maxUSS


输入字段解释


百分比:表示在总的时间内,进程在各种状态下的消耗

例如:100%,就指在这段时间内,这个进程是一直处于运行当中的

TOTAL:表示进程的总和占用情况

Img Fg:加载到前台

Service:标示了是否是服务

Persistent:标识了是否一直驻留子在内存当中,与Service一样,标示内存进驻的级别

Top:标识了是否是顶层进程

Receiver:标识了是否是广播进程


查看内存第二种方式:meminfo


查看指定的进程mem:

adb shell dumpsys meminfo com.xueqiu.android(包名)

在这里插入图片描述


meminfo内容


在这里插入图片描述



网络流量分析


网络分析

adb shell dumpsys netstats


分块展示


Activity interfaces:活动接口

Activity UID interfaces:活动UID接口

Dev statistics:开发统计信息

Xt statistics:Xt统计信息

UID statistics:UID统计信息

UID tag statistics:UID代码统计信息


活动接口和活动UID接口


在这里插入图片描述


开发统计信息/Xt统计信息


在这里插入图片描述


UID统计信息


在这里插入图片描述


获取对应应用UID

adb shell dumpsys package com.xueqiu.android | grep userId
输出:userId=10000 gids=[2002,1023,3134]


查看相关应用的流量情况


set=DEFAULT 表示前台网络使用情况

set=BACKGROUND表示后台使用情况

set=ALL表示上述两类使用情况

tag=0x0表示与流量关联的套接字代码

rxBytes 和 rxPackets 表示在相应时间间隔内接收的字节数(rb)和数据包数(rp)

txBytes 和 txPackets 在相应时间间隔内发送的字节数(tb)和数据包数(tp)


查看对应网络的情况


如果使用模拟器会出现报错,可以换成真机

在这里插入图片描述

使用过程

adb shell dumpsys package com.xueqiu.android | grep userId  获取userId
adb shell dumpsys package netstats | grep 12321(UID信息)		获取网络信息,并且使用userId过滤

结果:

在这里插入图片描述



耗电量指标(在真机上测)


目的

:通过不同的测试场景,找出APP高耗电的场景解决


常见电量问题




唤醒锁(acquire)



关闭屏幕显示,让CPU后台运行

app长期获取唤醒锁,不释放

阻止设备进入低电量模式



耗电标准



电池会话:再次充满电之间

消耗整个电池会话的0.70%

在后台运行时,消耗整个电池会话的0.10%

调用唤醒锁存在的问题

void doSomethingAndRelease() throwsMyException{
	wakeLock.acquire();
	doSomethingThatThrows();  //当这里出现报错的时候,下面锁的释放将无法关闭。导致其他应用无法使用
	wakeLock.release();
	}

改进

void doSomethingAndRelease() throwsMyException{
	
	try{
		wakeLock.acquire();
		doSomethingThatThrows();  
	}finally{
		wakeLock.release();
		}
	}


测试方式

方式一、测试性能使用Google Play

https://play.google.com/store/apps


方式二、Battery Historian工具


GitHub地址:

https://github.com/google/battery-historian



安装


注意:要在python2.7环境下执行,安装好go语言

git clone https://github.com/google/battery-historian.git
cd battery-historian
go get -d -u github.com/google/battery-historian/...
go run setup.go
# cd $GOPATH/src/github.com/google/battery-historian
go run cmd/battery-historian/battery-historian.go [--port <default:9999>]


具体步骤:


1、git clone https://github.com/google/battery-historian.git 或者直接下载后解压

2、进入battery-historian文件,打开终端

3、执行

go get -d -u github.com/google/battery-historian/...


4、进入setup.go,更改版本为20190513,最稳定版本

在这里插入图片描述

5、开始编译,执行

go run setup.go


6、启动:

go run cmd/battery-historian/battery-historian.go [--port <default:9999>]


测试步骤


使用batterystats生成数据

使用Battery historian分析数据


batterystats收集数据


1、清理耗电量数据

adb shell dumpsys batterystats –reset

adb shell dumpsys batterystats –enable full-wake-history

2、运行测试用例/手工操作

3、收集数据

Android 7.0:adb bugreport bugreport.zip

Android 6.0: adb bugreport>bugreport.txt


上传数据


打开localhost:9999,把zip或者txt数据上传

在这里插入图片描述


报告生成


在这里插入图片描述


Historian


x轴代表时间周期,默认以60s为一个周期

在这里插入图片描述


指标含义:


battery_level:电量

plugged:充电状态及充电时长

screen:屏幕是否点亮

top:显示当前手机运行的app

status:电池状态信息,有充电、放电、未充电、已充满,未知等不同状态


方式三、dumpsys


在这里插入图片描述

建议:

https://developer.android.com/guide/background



弱网测试


弱网问题


封闭环境,网速降低

  • 丢包
  • 数据无法加载
  • 消息更新不及时等


    模拟弱网


    使用charles模拟弱网

    官网下载:

    https://www.charlesproxy.com/download/



    使用charles


    1、代理设置,设置端口

    Proxy -> Proxy Setting

    在这里插入图片描述

    2、设置本地代理 (如果代理模拟器,在手机网络中的代理设置本地的IP和端口)

    本地电脑网络设置 – > 代理 – 地址 (一般就是默认值)

    在这里插入图片描述

    在这里插入图片描述

    3、开启节流

    Proxy -> Throttle Settings -> Enable Throttling

    在这里插入图片描述


    名词解释


    Bandwidth (带宽) 理论网速上限 100MB大概下载速度是12Mb

    Utilisation (利用) 总带宽的百分比

    Round-trip Latency (请求往还延迟) 客户端和服务器第一次往返通信的延迟,单位毫秒

    MTU (最大传输单元) 传输的TCP数据包的最大尺寸

    Reliability (可靠性) 衡量连接完全失败的可靠性


健壮性测试

用于测试系统在出现故障时,是否能够自动恢复或者忽略故障继续运行。


操作过程


在正常情况和异常情况下(弱网,数据不同等)进行长时间操作 (通常使用monkey长时间操作)



兼容性测试

建议使用第三方网站测试,比如阿里云移动端测试:

https://www.aliyun.com/product/mqc?spm=5176.19720258.J_8058803260.444.1c852c4aIfPwku


不同硬件、软件或者硬件之间的配合度(手机设备,系统版本,浏览器版本,分辨率等)


APP兼容性测试


移动设备型号多样

测试APP在主流设备上能否正常运行

测试APP在主流设备奔溃卡顿现象



APP性能

移动端APP运行在shell和Linux是相同的,所以我们查看APP性能,可以使用所有Linux查看性能的方法。

在这里插入图片描述


字段解释

:r:排队数量b:阻塞数量swpd:虚拟内存free空闲内存buff缓冲cache缓存si虚拟内存换入so虚拟内存换出bi磁盘换入 bo磁盘换出 in中断次数 cs切换次数 us使用CPU时间 sy系统CPU时间 id空闲CPU时间 wa 等待IO CPU时间

打印对应应用实时信息

在这里插入图片描述


使用bash提取对应的指标



获取vmstat最后一行的第4个数

adb shell vmstat | tail -1 | awk '{print $4}'

在这里插入图片描述


循环提取

while true;do adb shell vmstat | tail -1 | awk '{print $4}'; done 


使用Python代码获取

def test_vmstat():
    cmd = 'adb shell vmstat'
    res = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    # print(res.stdout.readline())
    # 获取vmstat信息,获取的是b字节,使用str转码,转码后以"\r\n"切割,然后获取第3个数
    print(str(res.stdout.read(),encoding="utf-8").split("\r\n")[2].split()[3])


Amdahl定律

作用:1、改善任何过程的一般原则 2、加速计算机系统估值

参数:

S:加速比

a: 系统某部分所需时间与总时间的比例

k:性能提升比例

在这里插入图片描述



版权声明:本文为weixin_43665351原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。