分享免费的编程资源和教程

网站首页 > 技术教程 正文

[性能优化]使用FrameTimeline进行Android卡顿检测

goqiw 2024-10-17 12:10:46 技术教程 51 ℃ 0 评论

注意:FrameTimeline需要Android 12(S)或更高版本

如果一个帧在屏幕上显示的时间与调度器给出的预测显示时间不匹配,那么就说这个帧是卡顿的。卡顿可能会导致:

  • 不稳定的帧率
  • 增加的延迟

FrameTimeline是SurfaceFlinger内的一个模块,用于检测卡顿并报告卡顿的源头。目前不支持SurfaceViews,但未来会支持。

UI

对于每个至少有一个帧在屏幕上的应用程序,都会添加两个新的跟踪轨道。

  • 预期时间线:每个切片代表应用程序渲染帧所需的时间。为避免系统出现卡顿,应用程序应在此时间框架内完成渲染。开始时间是Choreographer回调函数被调度运行的时间。
  • 实际时间线:这些切片代表应用程序完成帧(包括GPU工作)并将其发送到SurfaceFlinger进行合成所需的实际时间。开始时间是Choreographer#doFrame或AChoreographer_vsyncCallback开始运行的时间。这里切片的结束时间代表max(gpu时间, 提交时间)。提交时间是应用程序的帧被提交到SurfaceFlinger的时间。

类似地,SurfaceFlinger也获得了这两个新的跟踪轨道,分别代表它应该完成的预期时间和实际完成帧合成并在屏幕上显示所需的时间。在这里,SurfaceFlinger的工作代表了显示堆栈(Display Stack)中它下面的所有内容,包括Composer和DisplayHAL。因此,这些切片代表了SurfaceFlinger主线程从开始到屏幕更新的过程。

切片的名称表示从Choreographer那里接收到的令牌。您可以将实际时间线轨道中的一个切片与其在预期时间线轨道中对应的切片进行比较,以查看应用程序的表现是否符合预期。此外,为了调试目的,该令牌被添加到应用程序的doFrame和RenderThread切片中。对于SurfaceFlinger,相同的令牌在onMessageReceived中显示。

Selecting an actual timeline slice

“选择详情”提供了更多关于帧发生了什么的信息,包括:

  • 呈现类型:帧是提前、准时还是延迟呈现的。
  • 准时完成:应用程序是否按时完成了该帧的工作?
  • 卡顿类型:在此帧中是否观察到了卡顿?如果是,这表示观察到了哪种类型的卡顿。如果没有,则类型为“无”。
  • 预测类型:当FrameTimeline接收到此帧时,预测是否已过期?如果是,则为“过期预测”。如果不是,则为“有效预测”。
  • GPU合成:布尔值,表示帧是否由GPU合成。
  • 图层名称:帧被呈现到的图层/表面的名称。有些进程会更新多个表面的帧。在这里,实际时间线中将显示具有相同令牌的多个切片。图层名称可以很好地在这些切片之间进行区分。
  • 是缓冲区吗?:布尔值,表示帧是否对应于缓冲区或动画。

流程事件

在应用中选择一个实际时间线切片也会绘制一条线回到对应的SurfaceFlinger时间线切片。

由于SurfaceFlinger可以将来自多个图层的帧组合成屏幕上的单个帧(称为DisplayFrame),因此选择DisplayFrame会向所有组合在一起的帧绘制箭头。这可以跨多个进程进行。

Color codes

Janks explained

JankInfo.h 中定义了卡顿类型。由于每个应用程序的编写方式各不相同,因此没有通用的方法可以进入应用程序的内部并指定卡顿的原因。我们的目标不是这样做,而是提供一种快速判断是应用程序卡顿还是SurfaceFlinger卡顿的方法。

无卡顿
一切正常。帧没有出现卡顿。这是应该追求的理想状态。

应用程序卡顿

  • AppDeadlineMissed:应用程序运行时间超过预期,导致卡顿。应用程序帧的总时间是通过使用Choreographer唤醒作为开始时间,以及max(gpu, post time)作为结束时间来计算的。Post time是帧发送到SurfaceFlinger的时间。由于GPU通常并行运行,因此GPU可能在Post time之后完成。
  • BufferStuffing:这更多是一种状态而非卡顿。如果应用程序在上一帧呈现之前不断向SurfaceFlinger发送新帧,就会发生这种情况。内部缓冲区队列中充满了尚未呈现的缓冲区,因此得名“Buffer Stuffing”。队列中的这些额外缓冲区将逐一呈现,从而导致额外的延迟。这也可能导致应用程序没有更多缓冲区可供使用,从而进入出队阻塞等待状态。尽管应用程序执行的实际工作时间可能仍在截止时间之内,但由于缓冲区已满,无论应用程序完成工作有多快,所有帧都将至少延迟一个vsync时间呈现。在这种状态下,帧仍然是平滑的,但与延迟呈现相关的输入延迟会增加。

SurfaceFlinger Janks

SurfaceFlinger 合成(composite)帧有两种方式:

  1. 设备组合(Device Composition) - 使用专门的硬件
  2. GPU/客户端组合(GPU/Client Composition) - 使用GPU进行合成

需要注意的一个重要事项是,执行设备合成是在主线程上作为阻塞调用进行的。然而,GPU组合是并行进行的。SurfaceFlinger执行必要的绘制调用,然后将GPU栅栏(fence)传递给显示设备。显示设备随后等待栅栏被触发(be signaled),然后呈现帧。

SurfaceFlingerCpuDeadlineMissed
SurfaceFlinger应在给定的截止时间内完成。如果主线程运行时间超过该时间,则卡顿类型为SurfaceFlingerCpuDeadlineMissed。SurfaceFlinger的CPU时间是主线程上花费的时间,如果使用设备合成,则包括整个合成时间。如果使用GPU合成,则包括写入绘制调用和将帧传递给GPU的时间。

SurfaceFlingerGpuDeadlineMissed
SurfaceFlinger在主线程上的CPU时间加上GPU合成时间总共比预期长。在这种情况下,CPU时间可能仍在截止时间内,但由于GPU上的工作没有按时准备好,帧被推送到下一个vsync。

DisplayHAL
DisplayHAL卡顿指的是SurfaceFlinger已完成其工作并按时将帧发送到HAL,但帧未在vsync时呈现,而是在下一个vsync时呈现。这可能是SurfaceFlinger没有为HAL的工作提供足够的时间,或者HAL的工作确实存在延迟。

PredictionError
SurfaceFlinger的调度器会提前规划呈现帧的时间。然而,这种预测有时会偏离实际的硬件vsync时间。例如,一个帧可能预测的呈现时间为20ms。由于估计的偏差,帧的实际呈现时间可能是23ms。这在SurfaceFlinger的调度器中被称为预测错误。调度器会定期自我纠正,因此这种偏差不是永久性的。但是,为了跟踪目的,预测出现偏差的帧仍将被归类为卡顿。

孤立的预测错误通常不会被用户感知到,因为调度器会迅速适应并修正偏差。

Unknown jank

顾名思义,在这种情况下,造成卡顿(jank)的原因未知。一个例子是,SurfaceFlinger或应用程序花费的时间比预期长,错过了截止时间,但帧仍然被提前呈现。发生这种卡顿的概率非常低,但并非不可能。

TraceConfig

Trace Protos: FrameTimelineEvent

Datasource:

data_sources {
config {
name: "android.surfaceflinger.frametimeline"
}
}

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表