page.title=测试显示性能 page.image=images/cards/card-test-performance_2x.png page.keywords=性能, fps, 工具 @jd:body
用户界面 (UI) 性能测试可确保您的应用不仅满足其功能要求,同时确保用户与应用之间的交互顺畅无比,能够以每秒连续 60 帧(为什么选择 60fps?)的帧速运行,而不会出现任何帧丢失或延迟的现象,也就是我们通常所说的“卡顿”。 本文档介绍可用于测量 UI 性能的工具并提出一种将 UI 性能测量集成到测试实践中的方法。
为了改善性能,您首先必须能够测量系统性能,然后诊断并识别可能来自管道各个部分的问题。
dumpsys 是一种在设备上运行并转储感兴趣的系统服务状态信息的 Android 工具。 通过向 dumpsys 传递“gfxinfo”命令,可以提供 logcat 格式的输出,其中包含有关与录制阶段期间发生的动画帧相关的性能信息。
> adb shell dumpsys gfxinfo <PACKAGE_NAME>
此命令可以生成多个不同表达形式的帧时间数据。
借助 M 预览版,该命令可将在整个进程生命周期中收集的帧数据的聚合分析打印输出到 logcat。 例如:
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
这些高级统计信息可以较高水平地传达应用的呈现性能及其在多个帧之间的稳定性。
M 预览版附带提供了一个适用于 gfxinfo 的新命令,即:framestats,该命令根据最近的帧提供非常详细的帧时间信息,让您能够更准确地查出并调试问题。
>adb shell dumpsys gfxinfo <PACKAGE_NAME> framestats
此命令根据应用生成的最后 120 帧,打印输出带有纳秒时间戳的帧时间信息。以下是来自 adb dumpsys gfxinfo <软件包名称> framestats 的原始输出示例:
0,49762224585003,49762241251670,9223372036854775807,0,49762257627204,49762257646058,49762257969704,49762258002100,49762265541631,49762273951162,49762300914808,49762303675954, 0,49762445152142,49762445152142,9223372036854775807,0,49762446678818,49762446705589,49762447268818,49762447388037,49762453551527,49762457134131,49762474889027,49762476150120, 0,49762462118845,49762462118845,9223372036854775807,0,49762462595381,49762462619287,49762462919964,49762462968454,49762476194547,49762476483454,49762480214964,49762480911527, 0,49762479085548,49762479085548,9223372036854775807,0,49762480066370,49762480099339,49762481013089,49762481085850,49762482232152,49762482478350,49762485657620,49762486116683,
每行输出均代表应用生成的一帧。每行都有固定的列数,用于描述帧生成管道的每个阶段所花的时间。 下文将详细描述此格式,包括每列代表的具体内容。
由于数据块是 CSV 格式的输出,因此将其粘贴到所选的电子表格工具或使用脚本进行收集和解析非常简单。 下表解释了输出数据列的格式。 所有时间戳均以纳秒计。
您可以通过不同的方法使用此数据。一种简单却有用的可视化方式就是在不同的延迟时段中显示帧时间 (FRAME_COMPLETED - INTENDED_VSYNC) 分布的直方图(参见下图)。 此图直观地表明,大部分帧非常有效,截止时间远低于 16 毫秒(显示为红色),但是少数帧明显超出了截止时间。 我们可以观察此直方图中的变化趋势,了解所产生的整体变化或新异常值。 此外,您还可以根据数据中的多个时间戳绘制表示输入延迟、布局所用时间或其他类似关注指标的图形。
如果在“开发者选项”中将 GPU 呈现模式分析设置为在 adb shell dumpsys gfxinfo 中,则 adb shell dumpsys gfxinfo
命令会打印输出最近 120 帧的时间信息,这些信息分为几个不同的类别,其相应的值以制表符分隔。
这些数据可以用于大致表明绘图管道的哪些部分可能速度较慢。
与上述 framestats 类似,将其粘贴到所选的电子表格工具或使用脚本进行收集和解析同样非常简单。 下图详细显示了应用生成的许多帧的具体时间分布。
运行 gfxinfo、复制输出、将其粘贴到电子表格应用并将数据绘制成堆积条形图的结果。
每个垂直条均代表一个动画帧;其高度代表计算该动画帧所需的毫秒数。 垂直条的每个彩色分段均代表呈现管道的一个不同阶段,因此您可以看到应用的哪些部分可能会出现瓶颈。 如需了解有关呈现管道的详细信息,请参阅失效、布局和性能视频。
Framestats 和简单的帧计时均可在极短的时间内(相当于约呈现 2 秒)收集数据。 要精确控制此时间范围(例如,将数据限制于特定动画),您可以重置所有计数器并汇总收集的统计信息。
>adb shell dumpsys gfxinfo <PACKAGE_NAME> reset
这也可以与转储命令结合使用来定期进行收集和重置,从而持续捕获时间范围不到 2 秒的帧。
要查出问题并保持应用运行状况良好,第一步最好是识别回归。 但是,dumpsys 仅确定是否存在问题及其相对严重性。 您仍需诊断性能问题的具体原因并找到适当的解决方法。 为此,我们强烈建议您使用 systrace 工具。
如需了解有关 Android 呈现管道的工作原理、可能存在的常见问题以及如何解决这些问题的详细信息,以下其他资源可能对您有所帮助:
UI 性能测试方法之一是让测试人员对目标应用执行一系列用户操作,并目视检查是否存在卡顿现象,或花费大量时间使用工具驱动型方法来查明是否存在卡顿现象。 但是,这种人工方法充满风险:人为感知帧率变化的能力参差不齐,并且此过程又费时、繁琐且易于出错。
更为有效的方法是记录并分析自动化 UI 测试中的关键性能指标。 Android M 开发者预览版包括新的日志记录功能。利用这些功能,您可以轻松确定应用动画中的卡顿数量和严重性,您还可以使用这些功能构建严格的流程,用于确定当前性能并跟踪未来的性能目标。
本文将向您介绍一种使用这些数据自动化性能测试的推荐方法。
此方法主要分为两个关键操作。首先,确定测试对象和测试方法;其次,设置和维护自动化测试环境。
在开始进行自动化测试之前,您必须做出一些较高层次的决策,以便准确了解测试空间和可能存在的需求。
请记住,流畅的动画中断时,用户对低劣性能的感触最深。 因此,在识别要测试的 UI 操作类型时,集中精力处理用户最常见或对用户体验最为重要的关键动画非常有用。 例如,以下是对识别有所帮助的一些常见场景:
与团队中的工程师、设计师和产品经理开展合作,优先处理测试覆盖范围内的这些关键产品动画。
从较高层面来看,确定具体的性能目标、专注于编写测试并收集相关数据至关重要。 例如:
在所有这些情况下,您都将需要进行历史跟踪,以显示多个应用版本中的性能。
应用性能因其所在设备而异。某些设备的内存可能更少,GPU 功能略弱或 CPU 芯片速度较慢。 这意味着动画在一套硬件上表现良好,但在其他硬件上可能并非如此,而且可能因为其他管道部分中出现的瓶颈表现更为糟糕。 因此,考虑到用户可能会看到的这种变化,请选取各种设备(包括当前的高端设备、低端设备、平板电脑等)来执行测试。 找出 CPU 性能、RAM、屏幕密度、尺寸等方面的变化。 在高端设备上顺利通过的测试在低端设备上可能会失败。
UI Automator 和 Espresso 等测试套件是为了帮助自动化用户使用应用过程中的操作而构建。 这些套件是模拟用户与您的设备进行交互的简单框架。 要使用这些框架,您需要有效创建通过一组用户操作运行的独特脚本,并在设备中演示这些脚本。
通过结合这些自动化测试以及 dumpsys gfxinfo
,您可以快速创建可再生成的系统,然后您可使用此系统执行测试并测量特定条件的性能信息。
您能够执行 UI 测试并拥有从单一测试收集数据的管道后,下一个重要步骤就是采用可以在多种设备上多次执行该测试的框架,并汇总生成的性能数据,以供开发团队做进一步分析。
有一点值得注意,UI 测试框架(例如,UI Automator)直接在目标设备/模拟器上运行, 而性能信息收集则是由主机通过 ADB 发送命令来驱动 dumpsys gfxinfo 完成的。 为帮助桥接这些单独实体的自动化,我们开发了 MonkeyRunner 框架;这是一款在主机上运行的脚本编写系统,可以向一组连接设备发出命令并从中接收数据。
为正确自动化 UI 性能测试而构建一套脚本时,至少应当能够利用 monkeyRunner 完成以下任务:
一旦确定问题模式或回归,下一步就是识别和应用修复。 如果自动化测试框架保持帧的精确时间分解,则可帮助您审查最近的可疑代码/布局更改(出现回归时),或在切换到人工调查时缩小分析的系统范围。 对于人工调查,systrace 是一个很好的着手点,它可显示有关呈现管道的每个阶段、系统中的每个线程和核心以及您定义的任何自定义事件标记的精确时间信息。
需要注意的是,获取和测量呈现性能所需的时间并非易事。 就其本质而言,这些数字不具有确定性,往往会随系统状态、可用内存量、热节流以及太阳耀斑到达地面的最后时间而波动。 问题在于,尽管同一测试可以运行两次,但获得的结果可能略有不同,它们彼此接近,却并不完全相同。
以这种方式准确收集和分析数据意味着多次运行同一测试,且以平均值或中值的形式累积结果(为了简单起见,我们将其称为“批处理”)。这可为您提供测试性能的粗略近似值,而无需确切的时间。
您可对代码更改前和更改后的应用均使用批处理,了解这些更改对性能产生的相对影响。 如果更改前批处理的平均帧率大于更改后批处理的平均帧率,则此特定更改通常可为您带来全面的性能优势。
这意味着您执行的任何自动化 UI 测试均应考虑这一概念以及测试期间可能出现的任何异常。 例如,如果应用性能因某些设备问题(不是由应用引起)骤降,则您可能需要重新运行批处理以便获得更精确的时间。
那么,在获得更有意义的测量结果之前,您应运行多少次测试?至少应运行 10 次,次数越多(例如 50 或 100 次)获得的结果更精确(当然,您现在是牺牲时间换取精确度)