浅谈Android流畅度

(转自360Qtest团队微信公众号:https://mp.weixin.qq.com/s/CTTWzg55g3BN0JsKIUoYcQ)

流畅度

关于流畅度谷歌官方给出的解释为:running at a consistent 60 frames per second, without any dropped or delayed frames, or as we like to call it, jank.即以每秒60帧(每帧16.6ms)的速度运行,也就是60fps,并且没有任何延迟或者掉帧。

因此,关于流畅度的问题,我们先确定了以下三个考量指标。

1、FPS:每秒的帧数。

2、丢帧(SF: Skipped Frame):在16.6ms完成工作却因各种原因没做完,占了后n个16.6ms的时间,相当于丢了n帧。

3、流畅度(SM: SMoothness):和丢帧相对,在VSync机制中1s内Loop运行的次数。

VSYNC机制

大家应该看到上面提到了16.6ms和VSync,现在来解释一下VSync机制。

VSync机制: Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,VSync是Vertical Synchronization(垂直同步)的缩写,是一种在PC上很早就广泛使用的技术,可以简单的把它认为是一种定时中断。而在Android 4.1(JB)中已经开始引入VSync机制

 


 

上图所示是VSync机制下的绘制过程。从上图可以看出,CPU和GPU的处理时间都少于一个VSync的间隔,即16.6ms。如果每个间隔都有绘制的情况下,当前的FPS即为60帧。

当CPU和GPU处理时间都很慢,或因为其他的原因,如在主线程中干活太多,那么就会出现如下图这样的状况。

 


 

从上图可以看到,CPU和GPU的处理时间因为各种原因都大于一个VSync的间隔(16.6ms),所以在第二个VSync还在处理1区域的绘制时,不可能实现理论上的FPS60,同时也出现了丢帧(SF: Skipped Frame)情况。试想用户盯着同一张图看了32ms而不是16ms,当然很容易察觉出卡顿感,哪怕仅仅出现一次掉帧,用户都会发现动画不是很顺畅。


测试方法

通过以上信息相信大家对VSync机制有一个简单的了解,也知道了为什么我们测试流畅度要定最开始提到的几个指标。下面我们来介绍一下测试方法。

gfxinfo

dumpsys是一个在设备上运行的Android工具,可以转储有关系统服务状态的信息。将gfxinfo命令传递给dumpsys在logcat中提供了一个输出,其中包含与记录阶段期间发生的动画帧相关的性能信息。 

> adb shell dumpsys gfxinfo <PACKAGE_NAME>

上面的命令可产出关于帧的多项信息,部分信息如下:

Stats since: 752958278148ns
Total frames rendered: 82189
Janky frames: 35335 (42.99%)
90th percentile: 34ms
95th percentile: 42ms
99th percentile: 69ms
Number Missed Vsync: 4706
Number High input latency: 142
Number Slow UI thread: 17270
Number Slow bitmap uploads: 1542
Number Slow draw: 23342

Total frames rendered:  本次dump搜集的总帧数

Janky frames:  卡帧数量和卡帧比

Number Missed Vsync:  垂直同步失败的帧

Number High input latency: 处理input时间超时的帧数

Number Slow UI thread:  因UI线程上的工作导致超时的帧数

Number Slow bitmap uploads:  因bitmap的加载耗时的帧数

Number Slow issue draw commands:  因绘制导致耗时的帧数

可以看到其实这个命令给出的结果就很详细了,我们可以运用此命令来测试我们的app,并计算我们需要的数据。

SurfaceFlinger

SurfaceFlinger 是Android系统的一个服务,用来生成Surface,管理帧缓冲区(按序排放窗口,将其合成一张图片,即一帧)

测试命令如下:adb shell dumpsys SurfaceFlinger --latency <window_activity>

运行结果部分如下:

这条命令的含义是获取当前layer(窗口、图层)的最近128帧的信息(仅保存128帧)共128行。

第一行是设备的刷新周期refresh-period,单位是纳秒

剩余的127行,分为3列

第一列: when the app started to draw (开始绘制图像的瞬时时间)

第二列: the vsync immediately preceding SF submitting the frame to the h/w (VSYNC信令将软件SF帧传递给硬件HW之前的垂直同步时间)

第三列:timestamp immediately after SF submitted that frame to the h/w (SF将帧传递给HW的瞬时时间,及完成绘制的瞬时时间)

fps计算:总帧数/刷新总耗时

一些问题

为什么有时候FPS很低,但是我们却不觉得App卡顿?

有时候FPS很低,我们却感觉不到卡顿,因为本来就用不到那么高的FPS,比如画一个动画只画了0.5秒就画完了,那么FPS最高也只有30帧/秒(标准是60帧/每秒),但这并不代表它是卡顿的,用0.5秒动画就画完了,不能为了凑够60帧/秒,在做个1s的动画吧。而如果屏幕根本没有绘制需求,即屏幕显示的画面是静止的,那FPS就为0。因此,是不是用fps来作为指标,我们需要认真想一想,这个跟你测试场景有很大关系。我们可以针对此问题设计合适的测试场景,这样才能更真实的反应出应用程序的性能。

 

 

posted on 2018-11-29 14:46  一生二  阅读(956)  评论(0编辑  收藏  举报