美文网首页
Gfxinfo 衡量安卓UI的性能

Gfxinfo 衡量安卓UI的性能

作者: 爱睡觉的小章鱼 | 来源:发表于2020-06-02 14:10 被阅读0次

用户界面(UI)性能测试不仅可以确保app满足其功能要求,而且能够保证用户与app之间的交互是相当平滑的——以每秒60帧的速度运行(为什么是60fps?),没有任何丢弃或延迟的帧(或者我们喜欢称之为jank)。本文档介绍了可用于衡量UI性能的工具,并提供了将UI性能测量集成到测试实践中的方法。

为了提高性能,我们首先需要能够衡量系统的性能,然后诊断并识别可能从管道的各个部分到达的问题。

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

1.输入命令

示例:adb shell dumpsys gfxinfo < PACKAGE_NAME >

比如:adb shell dumpsys gfxinfo com.hashkey.hub

会出现如下结果

2.聚合帧统计信息

Graphics info for pid 2040 [com.hashkey.hub]  -表明当前dump的为hashkey hub应用界面的帧信息,pid为2040

Total frames rendered: 2240817  -本次dump搜集了2240817帧的信息

Janky frames: 2163335 (96.54%)  -2240817帧中有2163335 帧的耗时超过了16ms,卡顿概率为96.54%

50th percentile: 32ms

90th percentile: 44ms

95th percentile: 48ms

99th percentile: 61ms

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

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

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

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

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

HISTOGRAM: 5ms=8610 6ms=1886 7ms......直方图数据,表面耗时为0-5ms的帧数为8610,耗时为5-6ms的帧数为1886,同理类推。这些高级统计数据在很高的层次上向我们传达了app的渲染性能,以及它在许多帧中的稳定性。

3.精确帧耗时信息

Android 6.0版本为gfxinfo提供了一个新的命令——framestats,其作用是可以从最近的帧中获取非常详细的帧耗时信息,因此我们可以更准确地跟踪和调试问题。

adb shell dumpsys gfxinfo com.hashkey.hub framestats >D:\zy.csv

此命令会打印出来app最后生成的120帧的帧耗时信息(使用纳秒时间戳)。运行该命令后,可将结果写进D盘的zy.csv文件里面

csv中各个字段的解释如下:

Framestats数据格式

由于数据块以CSV格式输出,因此将其粘贴到我们选择的电子表格工具,或者使用脚本进行收集和解析非常简单。下面说明了输出数据列的格式。所有时间戳都以纳秒为单位(1纳秒=1e-6毫秒)。

1.FLAGS

如果flags为0,则此帧的总耗时时间 = FRAME_COMPLETED(第14列,帧的结束时间) - INTENDED_VSYNC(第2列,帧的预期开始时间)。

如果flags不为0,则忽略该行,因为该帧的布局和绘制时间超过16ms,为异常帧。以下是可能发生的一些原因:

(1)窗口布局发生变化(例如app的第一帧或旋转后);

(2)帧被跳过也是有可能的,在这种情况下,某些值将具有垃圾时间戳。例如,如果帧超出60fps,或者屏幕上没有任何内容变脏,则可能跳过一个帧,这不一定是app中出现问题的迹象。

2.INTENDED_VSYNC

帧的预期开始时间。如果此值与VSYNC不同,则UI线程上发生了阻止其及时响应vsync信号的工作。

3.VSYNC

花费在vsync监听器和帧绘制的时间(Choreographer frame回调,动画,View.getDrawingTime()等)。

要了解VSYNC的更多信息及其对app的影响,请查看Understanding VSYNC视频。

4.OLDEST_INPUT_EVENT

输入队列中最早输入事件的时间戳。如果此帧没有输入事件,则为Long.MAX_VALUE。

此值主要用于平台工作,对app开发人员的用处不大。

5.NEWEST_INPUT_EVENT

输入队列中最后输入事件的时间戳,如果此帧没有输入事件,则为0。

此值主要用于平台工作,对app开发人员的用处不大。

但是,通过计算FRAME_COMPLETED - NEWEST_INPUT_EVENT的值,可以大致了解app添加的延迟时间。

6.HANDLE_INPUT_START

将输入事件分派给app的时间戳。

通过计算ANIMATION_START - HANDLE_INPUT_START的值,可以测量app处理输入事件所花费的时间。

如果它们的时间差很高(> 2ms),则表示app花费了非常长的时间处理输入事件,例如View.onTouchEvent(),这可能表示此工作需要优化,或者分发到其他线程。但是请注意,在某些情况下,例如发起新活动或类似活动的点击事件时,预计可接受的时间差是很大的。

7.ANIMATION_START

运行Choreographer注册动画的时间戳。

通过计算PERFORM_TRANVERSALS_START - ANIMATION_START的值,可以得到评估正在运行的所有动画器(ObjectAnimator,ViewPropertyAnimator和常用转换器)所花费的时间。

如果它们的时间差很高(> 2ms),请检查您的app是否已编写了自定义动画或者设置了ObjectAnimators动画的字段,并确保它们适用于动画。

要了解Choreographer的更多信息,请查看For Butter or Worse视频。

8.PERFORM_TRAVERSALS_START

计算DRAW_START - PERFORM_TRAVERSALS_START的值,可以得到完成布局和度量阶段所需的时间。(注意,在滚动或动画期间,你会希望它应该接近于零)

要了解有关渲染管道的度量和布局阶段的更多信息,请查看Invalidations, Layouts and Performance视频。

9.DRAW_START

performTraversals的绘制阶段开始的时间戳。这是录制任何无效视图的显示列表的起点。

此时间与SYNC_START之间的时间是在树中所有无效视图上调用View.draw()所需的时间。

有关绘图模型的更多信息,请查看Hardware Acceleration或者Invalidations, Layouts and Performance视频。

10.SYNC_QUEUED

将同步请求发送到RenderThread的时间。

这标志着开始同步阶段的消息被发送到RenderThread的时刻。如果此时间与SYNC_START之间的时间差很长(> 0.1ms左右),则表示RenderThread正忙于处理不同的帧。在内部,这用于区分执行太多工作以至于超过16ms预算的帧和由于前一帧超过16ms预算而导致被停止的帧。

11.SYNC_START

绘图同步阶段开始的时间。

如果此时间与ISSUE_DRAW_COMMANDS_START之间的时间很长(> 0.4ms左右),则通常表示已绘制了许多必须上传到GPU的新位图。

要了解有关同步阶段的更多信息,请查看Profile GPU Rendering视频。

12.ISSUE_DRAW_COMMANDS_START

硬件渲染器开始向GPU发出绘图命令的时间。

计算FRAME_COMPLETED - ISSUE_DRAW_COMMANDS_START的值,可以大致了解app生成多少GPU工作。这里会出现很多过度绘制或低效的渲染效果等问题。

13.SWAP_BUFFERS

调用eglSwapBuffers的时间,在平台工作之外相对无用。

14.FRAME_COMPLETED

帧的结束时间戳。可以通过执行FRAME_COMPLETED - INTENDED_VSYNC来计算在此帧上工作的总时间。

15.DequeueBufferDuration和QueueBufferDuration

我测试的是Android 8.0版本,除了以上14列数据外,还有2列数据——DequeueBufferDuration和QueueBufferDuration,这2列数据在官方文档中没有提及,估计是后来新加的。

相关文章

网友评论

      本文标题:Gfxinfo 衡量安卓UI的性能

      本文链接:https://www.haomeiwen.com/subject/gslrzhtx.html