关于dumpsys gfxinfo framestats 详细帧数据分析说明

精确的帧时间信息

Android 6.0 附带提供了一个适用于 gfxinfo 的新命令,即:framestats,该命令会根据最近的帧提供非常详细的帧时间信息,让您能够更准确地查出并调试问题。

    >adb shell dumpsys gfxinfo <PACKAGE_NAME> framestats

   

该命令会从应用生成的最近 120 个帧中输出带有纳秒时间戳的帧时间信息。以下是 adb dumpsys gfxinfo <PACKAGE_NAME> framestats 的原始输出示例:

    0,27965466202353,27965466202353,27965449758000,27965461202353,27965467153286,27965471442505,27965471925682,27965474025318,27965474588547,27965474860786,27965475078599,27965479796151,27965480589068,

    0,27965482993342,27965482993342,27965465835000,27965477993342,27965483807401,27965486875630,27965487288443,27965489520682,27965490184380,27965490568703,27965491408078,27965496119641,27965496619641,

    0,27965499784331,27965499784331,27965481404000,27965494784331,27965500785318,27965503736099,27965504201151,27965506776568,27965507298443,27965507515005,27965508405474,27965513495318,27965514061984,

    0,27965516575320,27965516575320,27965497155000,27965511575320,27965517697349,27965521276151,27965521734797,27965524350474,27965524884536,27965525160578,27965526020891,27965531371203,27965532114484,

   

每行输出均代表应用生成的一帧。每行都有固定的列数,描述帧生成管道的每个阶段所花的时间。下文将详细描述此格式,包括每列代表的具体内容。

Framestats 数据格式

由于数据块是 CSV 格式的输出,因此将其粘贴到所选的电子表格工具或使用脚本进行收集和解析非常简单。下表解释了输出数据列的格式。所有时间戳均以纳秒计。

  • FLAGS
    • FLAGS 列为“0”的行可以通过从 FRAME_COMPLETED 列中减去 INTENDED_VSYNC 列计算得出总帧时间。
    • 该列为非零值的行应该被忽略,因为其对应的帧已被确定为偏离正常性能,其布局和绘制时间预计超过 16 毫秒。出现这种情况可能有如下几个原因:
      • 窗口布局发生变化(例如,应用的第一帧或在旋转后)
      • 此外,如果帧的某些值包含无意义的时间戳,则也可能跳过该帧。例如,如果帧的运行速度超过 60fps,或者如果屏幕上的所有内容最终都准确无误,则可能跳过该帧,这不一定表示应用中存在问题。
  • INTENDED_VSYNC
    • 帧的预期起点。如果此值不同于 VSYNC,则表示界面线程中发生的工作使其无法及时响应 Vsync 信号。
  • VSYNC
    • 所有 Vsync 监听器中使用的时间值和帧绘图(Choreographer 帧回调、动画、View.getDrawingTime() 等等)
    • 如需进一步了解 VSYNC 及其对应用产生的影响,请观看了解 VSYNC 视频。
  • OLDEST_INPUT_EVENT
    • 输入队列中最早输入事件的时间戳或 Long.MAX_VALUE(如果帧没有输入事件)。
    • 此值主要用于平台工作,对应用开发者的作用有限。
  • NEWEST_INPUT_EVENT
    • 输入队列中最新输入事件的时间戳或 0(如果帧没有输入事件)。
    • 此值主要用于平台工作,对应用开发者的作用有限。
    • 但是,可以通过查看 (FRAME_COMPLETED - NEWEST_INPUT_EVENT) 大致了解应用增加的延迟时间。
  • HANDLE_INPUT_START
    • 将输入事件分派给应用的时间戳。
    • 通过观察此时间戳与 ANIMATION_START 之间的时间差,可以测量应用处理输入事件所花的时间。
    • 如果这个数字较高(> 2 毫秒),则表明应用处理 View.onTouchEvent() 等输入事件所花的时间太长,这意味着此工作需要进行优化或转交给其他线程。请注意,有些情况下(例如,启动新 Activity 或类似活动的点击事件),这个数字较大是预料之中并且可以接受的。
  • ANIMATION_START
    • 在 Choreographer 中注册的动画运行的时间戳。
    • 通过观察此时间戳与 PERFORM_TRANVERSALS_START 之间的时间差,可以确定评估正在运行的所有动画(常见动画有 ObjectAnimator、ViewPropertyAnimator 和 Transitions)所用的时间。
    • 如果这个数字较高(> 2 毫秒),请检查您的应用是否编写了任何自定义动画,或检查 ObjectAnimator 在对哪些字段设置动画并确保它们适用于动画。
    • 如需了解有关 Choreographer 的更多信息,请观看利弊视频。
  • PERFORM_TRAVERSALS_START
    • 如果您从此值中减去 DRAW_START,则可推断出完成布局和测量阶段所用的时间(请注意,在滚动或动画期间,您会希望此时间接近于零)。
    • 如需了解有关渲染管道的测量和布局阶段的更多信息,请观看失效、布局和性能视频。
  • DRAW_START
    • performTraversals 绘制阶段的开始时间。这是记录任何失效视图的显示列表的起点。
    • 此时间与 SYNC_START 之间的时间差就是对树中所有失效视图调用 View.draw() 所用的时间。
    • 如需了解有关绘图模型的详细信息,请参阅硬件加速失效、布局和性能视频。
  • SYNC_QUEUED
    • 将同步请求发送给 RenderThread 的时间。
    • 它标记的是将开始同步阶段的消息发送给 RenderThread 的时间点。如果该时间点与 SYNC_START 的时间差较大(约 > 0.1 毫秒),则意味着 RenderThread 正忙于处理另一帧。它在内部用于区分该帧是因作业负荷过大而超过了 16 毫秒的预算时间,还是该帧由于上一帧超过 16 毫秒的预算时间而停止。
  • SYNC_START
    • 绘制同步阶段的开始时间。
    • 如果此时间与 ISSUE_DRAW_COMMANDS_START 之间相差较大(约 > 0.4 毫秒),通常表示绘制了大量必须上传到 GPU 的新位图。
    • 如需进一步了解同步阶段,请观看 GPU 渲染分析视频。
  • ISSUE_DRAW_COMMANDS_START
    • 硬件渲染器开始向 GPU 发出绘图命令的时间。
    • 此时间与 FRAME_COMPLETED 之间的时间差让您可以大致了解应用生成的 GPU 工作量。绘制过度或渲染效果不佳等问题都会在此显示出来。
  • SWAP_BUFFERS
    • 调用 eglSwapBuffers 的时间,在平台工作范围之外,意义相对不大。
  • FRAME_COMPLETED
    • 大功告成!处理此帧所花的总时间可以通过执行 FRAME_COMPLETED - INTENDED_VSYNC 计算得出。

您可以通过不同的方法使用此数据。一种简单却有用的可视化方式就是在不同的延迟时段中显示帧时间 (FRAME_COMPLETED - INTENDED_VSYNC) 分布的直方图(参见下图)。此图直观地表明,大部分帧非常有效,截止时间远低于 16 毫秒(显示为红色),但是少数帧明显超出了截止时间。我们可以观察此直方图中的变化趋势,了解所产生的整体变化或新异常值。此外,您还可以根据数据中的多个时间戳绘制表示输入延迟、布局所用时间或其他类似关注指标的图表。

上一篇:api-java.util.concurrent.ThreadPoolExecutor


下一篇:2.工厂模式