APP性能测试——卡顿、流畅度测试

一、先了解几个缩写的含义:

    • fps:一秒内绘制到屏幕的帧数(通常60hz的手机1s是60帧,目前高端机基本120hz)

    • jank:卡顿次数

    • bigJank:严重卡顿次数

    • stutter:卡顿率=卡顿时长/总时长

    • lostFrame:丢帧率=实际帧数/预期帧数

    • frameInfo:帧耗时,即每一帧渲染耗

二、以 Google Vitals 的卡顿描述为准,即呈现速度缓慢和帧冻结两个维度判断:

    • 呈现速度缓慢:在呈现速度缓慢的帧数较多的页面,当超过 50% 的帧呈现时间超过 16ms 毫秒时,用户感官明显卡顿。

    • 帧冻结:帧冻结的绘制耗时超过 700ms,为严重卡顿问题。

    • 卡顿忽略 FPS<=2 的页面:因为人的视觉暂留 100~400ms,即 FPS 在 2.5~10 之间时,所以当 FPS 低于 3 时,人眼看到的并不是连续动作,即使有丢帧现象,也不会察觉。

    • FPS和卡顿无任何关系:假如1s内,前800ms刷新了50帧,但是由于卡顿最后200ms刷新了1帧。这1s的帧率为51帧,从fps上来看51帧已经非常好了,但是用户在这1s内会感觉到一次明显的卡顿。

三、Jank 计算方法:

    • 普通卡顿 Jank(由于硬件的发展,现在中高端手机基本都是120hz,肉眼对于流畅度越来越敏感,实际测试中满足以下一条即可判断为卡顿)

      • 当前帧耗时>前三帧平均耗时 2 倍(人眼一般可容忍2帧延迟)。

      • 当前帧耗时>两帧电影帧耗时 (1000ms/24*2=84ms,低于24帧画面,人眼就能感知到画面不连续性)。

    • 严重卡顿 BigJank(同上):

      • 当前帧耗时>前三帧平均耗时 2 倍。

      • 当前帧耗时>三帧电影帧耗时 (1000ms/24*3=125ms)。

四、卡顿标准:

    目前了解到某游戏大厂的卡顿率是5%以下,我们主要是app页面,所以我建议:

  •  卡顿不要高于10%,对于高级别项目要求不能超过5%

    • 当页面切换时,系统会产生一些超大帧,导致卡顿率上升,可以忽略

    • 中端机FPS不低于56

五、实际测试中需要关注的场景:

    • 静态页面窗口

      • 只需关注FPS,理论PFS应该为0,否则,说明页面有冗余刷新,可能是bug,容易引起手机发热及耗电。

    • 有滚动动画页面窗口

      • 只需关注FPS,FPS处于合适值即可,无需高频刷新,一般fps20以上。

    • 快速滑动页面窗口(同"四"中的标准)

      • 需要关注FPS、卡顿率,手机交互灵敏度就是来源于此。

    • 播放视频、游戏页面窗口

      • 需要关注FPS、Jank及卡顿率,一般帧率20-24帧,卡顿率5%以下,目前高端机可以做到60-90帧。

六、测试方法:

  • 工具类:perfdog、totorobox、Snapdragon Profiler 等

  • 脚本类:adb官方命令行,通过adb命令获取并计算卡顿率、丢帧率、FPS等指标,测试前需要在手机的开发者选项中,找到“GPU呈现模式分析”,选择“在adb shell dumpsys gfxinfo中”

    • 静止页面、banner滚动等通过工具做测试,不再赘述

    • 常规测试中我们更关注可快滑的长列表页面,以下主要针对快滑场景的流畅度测试

1、计算每次滑动时系统记录的数据:

# 使用系统命令获取帧率数据# 以下为示例代码:def get_fps(pkg_name, devices):  #fps 测试    _adb = "adb -s " + devices +" shell dumpsys gfxinfo %s" % pkg_name    os.system("adb -s " + devices +" shell dumpsys SurfaceFlinger --latency-clear")        # 初始化数据,如fps、卡顿时间、丢帧率、卡顿率等    all_result={        "jankFrames": 0,  # jank次数,跳帧数        "totalFrames" :  0,  # 统计的总帧数        ...    }    results = os.popen(_adb)    flag=False    every_frame_Time= []  # 每帧耗时
    for line in results.readlines():        line=line.strip()        if flag and line :            times = line.split("\t")            # 计算一帧所花费的时间            if len(times)>3:                onceTime = float(times[0])+float(times[1])+float(times[2])+float(times[3])                every_frame_Time.append(onceTime)                all_result['alltime']+=onceTime                all_result['totalFrames'] += 1 # 统计总帧数                if onceTime > 16.67: # 以Android定义的60FPS为标准                    all_result['test_alltime']+=onceTime                    all_result['jankFrames'] += 1# 统计跳帧jank数                    all_result['vsyncOverTimes'] +=int(onceTime / 16.67) # 向下取整即可                else:                    all_result['test_alltime']+=16.67                    # 普通卡顿 Jank条件:                if len(every_frame_Time)>=3:                    if onceTime>(every_frame_Time[-1]+every_frame_Time[-3]+every_frame_Time[-2])/3*2:                        all_result['jankTime']+=onceTime    if  all_result['totalFrames'] >0:        all_result['fps'] = all_result['totalFrames'] / (all_result['totalFrames'] + all_result['vsyncOverTimes']) * 60        all_result['lostFrameRate'] = all_result['jankFrames'] / all_result['totalFrames']        ...        # print("fps(1秒内平均画面刷新次数)值为:",fps)        # print("总帧数:",totalFrames)    else:        print("【ERROR】无FPS信息,请确认手机正常连接或APP正常运行")    return all_result

2、计算滑动周期内的所有数据平均值:

# 以下为示例代码:def record_fps(sencens,t):    global stop    avg_all_reuslt= {        "jankFrames": 0,  # jank次数,跳帧数        "totalFrames" :  0,  # 统计的总帧数        ...    }    while True:        if stop==0:            all_result=get_fps(package, serialno)            avg_all_reuslt['jankFrames']+=all_result['jankFrames']            avg_all_reuslt['totalFrames']+=all_result['totalFrames']            ...        else:            break    if  avg_all_reuslt['totalFrames'] >0:        avg_all_reuslt['fps'] = round( avg_all_reuslt['totalFrames'] / (avg_all_reuslt['totalFrames'] + avg_all_reuslt['vsyncOverTimes']) * 60,4)        avg_all_reuslt['lostFrameRate']=round( avg_all_reuslt['jankFrames'] / avg_all_reuslt['totalFrames'],4)        avg_all_reuslt['jankRate'] =round( avg_all_reuslt['jankTime'] / avg_all_reuslt['test_alltime'],4)
        ...        ##记录每个场景的自动化值        if t==0:            allJson_result[sencens]=[avg_all_reuslt,]        else:            allJson_result[sencens].append(avg_all_reuslt)        # 数据入库示例代码        insert_mysql(devices,sencens.allJson_result)    stop = 0

示例:不同维度的聚合,能否反映出不同版、不同时间段的性能的数据,可进行版本数据监控,历史版本数据对比,示例:

七、总结:

    在实际测试当中,我们主要关注三个指标:FPS、卡顿率、丢帧率即可,通过这三个指标能够清晰地反映出当前app的体感现状,对于后期制定标准、促进优化效果、提高产品质量都会有一定的帮助;当然我们也可以根据可视化工具来辅助测试,来提升测试准确度,通过脚本能够弥补可视化工具的不足,脚本能够做成自动化,以节约测试时间和人力成本,提升效率。

*完整代码,关注公众号后,赞赏留言获取!

长按关注QuTest,定期分享技术干货,欢迎投稿!

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值