本文为霍格沃茨测试学院的学生学习笔记,并在高级学习结束时添加了一个群组。
而FPS和丢帧率在一定程度上可以作为APP流畅度的衡量标准。介绍了使用adb shell dumpsys gfxinfo命令获取软件渲染和加载过程的数据,并进行计算得出测试结果。
有业务知识在先,需要了解屏幕显示的绘制流程和Android的VSync机制。
VSync的全称是垂直同步,在Android 4.1中引入了Android系统(同时引入的一个概念是三重缓冲)。
计算机专业的学生经常听到Buffer这个概念(他们在生活中遇到过很多),起着类似的作用。用来协调两个速度不同的东西的工作。
例如,假设存储器用于显示内容和绘图,则可能出现以下问题。存在截断的例外(图中的撕裂点#1和撕裂点#2)。
为什么会这样?因为CPU/GPU处理和屏幕显示速度不一样,但是使用的内存是一样的。
在此插入图片描述。
怎么解决?可以将CPU/GPU处理从屏幕显示中分离出来。CPU/GPU在后台处理,处理完一帧数据,就会呈现到屏幕上。(这可能会导致另一个问题:如果CPU/GPU处理缓慢,屏幕可能会一直显示某一帧数据。下面主要分析这个问题的处理)。
绘画过程中的两个概念。手机屏幕刷新率:手机硬件每秒刷新屏幕的次数,单位为HZ。一般是固定值,比如60HZ。FPS:每秒传输的帧数。一般来说是指动画或者视频的帧数。单位赫兹。手机的屏幕刷新率是固定的,而FPS是不断变化的。怎么才能保证它能顺利运行?我们从几个例子来看。
先解释一下图片的意思:最下面的黑线代表时间,黄色代表屏幕显示,绿色代表GPU处理,蓝色代表CPU处理。邱建代表重复前一帧的异常。下面会从屏幕展示的每一帧开始分析:
没有引入VSync机制。
上图是没有引入VSync机制的处理流程。
显示第0帧的数据,然后CPU/GPU会处理第1帧的数据。
显示第一帧数据(此时屏幕显示正常),之后CPU/GPU可能会处理其他任务,导致画图后期处理。
因为CPU/GPU没有对第二帧的数据进行处理,所以显示器仍然显示第一帧的数据(此时屏幕显示异常)。CPU/GPU处理第二帧未完成的数据,然后继续处理第三帧的数据。
…
上图一个明显的问题是,只要一个CPU/GPU处理异常,后续一系列处理都可能异常。
引入VSync机制VSync可以简单的看作是一个定时中断。系统每次需要画图时都会发送VSync脉冲信号,CPU/GPU收到信号后会立即处理画图。
一般情况下,4.1之后会引入VSync机制。
垂直同步机构图
在FPS手机屏幕刷新率的情况下,一切运行完美。
双缓冲例外:VSync机制下双缓冲时FPS手机的屏幕刷新率。
双缓冲出现在垂直同步机制中
显示A帧的数据,CPU/GPU收到VSync脉冲信号后立即处理B帧的数据,但由于计算量太大,在一个VSync间隔内没有处理。
由于B帧的数据没有处理好,显示器继续显示A帧的数据(此时屏幕显示异常)。因为系统中只有一个内存供cpu/GPU处理画图,所以在这个VSync间隔中cpu不做任何处理。
显示B帧的数据,CPU/GPU收到VSync脉冲信号后会立即处理要显示的A帧的数据。因为计算量太大,不在一个VSync的房间里。
隔内处理完。需要展示的A 帧数据没有处理好,Display 继续展示第 B 帧数据(此时屏幕显示是异常的)。由于系统中只存在一块内存给 CPU/GPU 处理绘制,所以在这个 VSync 间隔内 CPU 不处理任何事。
…
上图中一个很明显的问题是,只要出现一次Jank 就会影响下一次的VSync(cpu 不能工作)。
Triple Buffering 异常情况Triple Buffering 的引入。
VSync机制出现triple buffering
Display 展示第A 帧数据,CPU/GPU 收到VSync Pulse 信号马上处理B 帧的数据,但是由于计算太多,导致没有在一个VSync 间隔内处理完。
由于第B 帧数据没有准备好,Display 继续展示第A 帧数据(此时屏幕显示是异常的)。此时虽然B 被gpu 在使用,但是cpu 可以处理Buffer C(因为有3个缓冲)。
Display 展示第B 帧数据,gpu 继续处理上一步骤的C,cpu 则处理A。
后续过程出错的情况被降低了…
获取数据并计算结果1.运行命令"adb -s " + deviceName + " shell dumpsys gfxinfo " + packageName 获取基础数据,我们会获得很多数据,这里截取需要进行分析的部分:
注:如果运行完命令发现无上图中的4个参数,则很可能是手机的“GPU呈现模式分析”未打开;
在手机的开发者选项中,找到“GPU呈现模式分析”,选择“在adb shell dumpsys gfxinfo中”,如果是华为或荣耀的手机,则选择“在屏幕上显示为线型图”:
2.如上图信息表示了每一帧在安卓系统中的四个阶段:
Draw: 表示在Java中创建显示列表部分中,OnDraw()方法占用的时间
Prepare: 准备时间
Process:表示渲染引擎执行显示列表所花的时间,view越多,时间就越长
Execute:表示把一帧数据发送到屏幕上排版显示实际花费的时间,其实是实际显示帧数据的后台缓存区与前台缓冲区交换后并将前台缓冲区的内容显示到屏幕上的时间
将上面的四个时间加起来就是绘制一帧所需要的时间,如果超过了16.67就表示掉帧了
说明Android 定义了流畅度的数据标准,以 60FPS 为标准(FPS 为每秒绘制的帧数),帧数过小就会出现卡顿感。
每一帧在安卓系统中分4个阶段,4个阶段的总和超过16.67(1秒60帧,算下来平均1帧的间隔就约是16.67ms)就认为丢帧。
这个定义在 Android6.0 以前是一定的,但是现在已经没有固定的标准了,因为目前安卓系统有3层缓存机制,加上硬件上的进步,即使超过16.67,也不一定会出现卡顿感。所以这个数据在测试时作为一种对比和相对衡量标准,也可根据需求自定义标准。
计算结果通过以上数据,就可以获取到每一帧的时间、总帧数;从而就可以计算出 jank 数、vsync 数,进而就可以得到最终的 FPS 和丢帧率数据。
当然,手工计算无疑效率低,出错率大,所以这里的计算过程最好还是以脚本形式,让代码帮我们去计算,具体代码计算原理与专项自动化过程后续探讨。
获取更多相关资料:请添加vx,ceshiren001
https://qrcode.ceba.ceshiren.com/link?name=article&project_id=qrcode&from=toutiao×tamp=1653268551&author=MM