前言:虽然有翻译软件,虽然有chatgpt,毕竟语言隔阂,对这个工具还是一知半解,因此想通过翻译的方式和大家来一起学习下Perfetto这个强大的工具
#####################以下分割线#####################
英文原文在这里
注意:FrameTimeline需要 Android 12(S) 或更高版本
如果帧在屏幕上显示的实际时间与调度程序给出的预期时间不匹配,则称帧是卡顿的。
卡顿可能导致:
帧率不稳定
延迟增加
FrameTimeline是SurfaceFlinger中的一个模块,用于检测卡顿并报告卡顿的来源。 SurfaceViews目前不受支持,但将来会支持。
UI
对于屏幕上至少有一个帧的每个应用程序,将添加两个新轨道。
- Expected Timeline :每个切片表示为应用呈现帧而提供的时间。为避免系统中出现卡顿,该应用程序应在此时间范围内完成。开始时间是Choreographer回调计划运行的时间。
- Actual Timeline:这些切片表示应用完成帧(包括 GPU 工作)并将其发送到 SurfaceFlinger 进行合成所花费的实际时间。开始时间是
Choreographer#doFrame
或AChoreographer_vsyncCallback
开始运行的时间。切片的结束时间表示max(gpu time, post time)
. Post time 是应用程序将帧数据交给 SurfaceFlinger 的时间。
app-timelines.png
同样,SurfaceFlinger也新增了这两个新轨道,代表了它应该完成的预期时间,以及完成合成帧和在屏幕上呈现所需的实际时间。在这里,SurfaceFlinger's work represents everything underneath it in the display stack(SurfaceFlinger的工作代表了显示堆栈中它下面的所有内容)。这包括Composer和 DisplayHAL。因此,切片代表 SurfaceFlinger 主线程开始在屏幕上更新。
切片的名称表示从 choreographer收到的token,可以将实际时间线轨道中的切片与预期时间线轨道中的相应切片进行比较,以查看应用与预期相比的表现。此外,出于调试目的,token将添加到应用的 doFrame 和RenderThread切片中。对于 SurfaceFlinger,相同的token显示在 onMessageReceived 中。
选择实际的时间轴切片
选择详细信息提供了有关帧发生的情况的更多信息。其中包括:
- Present Type
Was the frame early, on time or late.
帧是早,准时还是晚。
- **On time finish **
应用程序是否按时完成了帧的工作?
- **Jank Type **
这一帧有没有观察到卡顿?如果是,则显示观察到的卡顿类型。否则,类型将为None。
- **Prediction type **
在FrameTimeline收到此帧时,预测是否已过期? 如果是,这将显示 Expired Prediction。如果不是,则为Valid Prediction。
-
**GPU Composition **
布尔值,用于判断帧是否由 GPU 合成。
**Layer Name **
显示的帧对应的Layer/Surface的名称。某些进程将帧更新到多个surfaces。在这里,具有相同token的多个切片将显示在实际时间轴中。图层名称是消除这些切片之间歧义的好方法。
- Is Buffer?
布尔值,用于区分帧是对应于缓冲区还是动画。
Flow events(流事件)
在应用程序中选择实际的时间线切片还会出现一条线,和相应的 SurfaceFlinger 时间线切片联系起来。
由于 SurfaceFlinger 可以将多个图层中的帧合成为屏幕上的单个帧(称为 DisplayFrame),因此选择 DisplayFrame 会将箭头指向到合成当前DisplayFrame帧的的所有帧。这可以跨越多个进程。
颜色含义
卡顿类型解析
卡顿类型在JankInfo.h中定义。由于每个应用程序的编写方式不同,因此没有通用的方法可以深入到应用程序的内部,并指出卡顿的原因。我们的目标也不是这样,而是提供一种快速的方法来判断应用程序是否卡顿或SurfaceFlinger是否卡顿。
NONE
每一帧都很好,没有卡顿发生,这个是理想的目标状态
应用卡顿
AppDeadlineMissed 应用程序运行比预期慢,导致卡顿。 app frame所用的总时间,用choreographer唤醒作为开始时间,max(gpu,post time)作为结束时间计算的。Post time是帧发送到SurfaceFlinger的时间。由于 GPU 通常并行运行,因此 GPU 的完成时间可能晚于Post time。
BufferStuffing 这更像是一种状态,而不是一种卡顿。如果应用在显示前一帧之前不断向 SurfaceFlinger 发送新帧,就会发生这种情况。内部缓冲区队列中塞满了尚未显示的缓冲区,因此得名缓冲区填充。队列中的这些额外缓冲区仅一个接一个地显示,从而导致额外的延迟。这也可能导致应用没有更多的缓冲区,并且进入取消排队阻塞等待的状态。应用执行的实际工作仍可能持续到截止点,但由于填充性质,无论应用完成工作的速度有多快,所有帧都将至少延迟显示一个vsync。在此状态下,帧仍将是平滑的,但与延迟相关的输入延迟会增加。
SurfaceFlinger卡顿
SurfaceFlinger有两种方法可以合成一帧。
设备合成 - 使用专用硬件
GPU/客户端合成 - 使用 GPU 进行合成
需要注意的重要一点是,执行设备合成是作为主线程上的阻塞调用发生的。但是,GPU合成是并行进行的。SurfaceFlinger 执行必要的绘制调用,然后将 GPU fence传递给显示设备。然后,显示设备等待fence发出信号,然后显示帧。
SurfaceFlingerGpuDeadlineMissed
SurfaceFlinger的主线程在CPU上花费的时间+GPU合成时间加在一起的时间比预期的要长。在这里,CPU按时完成,但由于 GPU 上的工作没有按时准备好,帧被推送到下一个 vsync。
DisplayHAL
DisplayHAL 卡顿是指 SurfaceFlinger 完成其工作并按时将帧发送到 HAL 的情况,但帧未显示在 vsync 上。它在下一个 vsync 上呈现。可能是SurfaceFlinger没有为HAL的工作预留足够的时间,也可能是HAL的工作确实存在延迟。
PredictionError SurfaceFlinger的调度程序提前计划了呈现帧的时间。但是,此预测有时会偏离实际的硬件vsync时间。例如,帧可能预测当前时间为 20 毫秒。由于估计的偏差,帧的实际呈现时间可能是 23 毫秒。这在 SurfaceFlinger 的调度程序中称为 Prediction Error。调度程序会定期自行更正,因此这种偏移不是永久性的。但是,出于trace目的,预测中存在偏差的帧仍将归类为卡顿。
孤立的prediction errors通常不会被用户感知到,因为调度程序可以快速调整和修复偏差。
Unknown jank
顾名思义,在这种情况下,卡顿的原因尚不清楚。比如说,SurfaceFlinger或应用程序花费的时间比预期的要长,并且错过了截止日期,但帧仍然提前呈现。这种卡顿发生的可能性非常低,但并非不可能。
SQL
在 SQL 级别,frametimeline数据在两个表中可用
select ts, dur, surface_frame_token as app_token, display_frame_token as sf_token, process.name
from expected_frame_timeline_slice left join process using(upid)
select ts, dur, surface_frame_token as app_token, display_frame_token, jank_type, on_time_finish, present_type, layer_name, process.name
from actual_frame_timeline_slice left join process using(upid)
TraceConfig
Trace 原型:FrameTimelineEvent
数据源:
data_sources {
config {
name: "android.surfaceflinger.frametimeline"
}
}
#####################以上分割线#####################
后记:
1 本次主要使用百度翻译,虽然被骂,但至少翻译这个工具降低了门槛。
2 英文文档中的长难句真的是又长又难,基于百度的翻译,然后自己再调整下,水平实在有限。
3 技术背景知识不够,有些专有名词不知道怎么翻译,也不知道百度翻译的是否准确,功夫在诗外。
4 万事开头难,中间难不难,还不知道。中间的事后面再说,正确一天翻译一篇。
5 虽然可能会有人不屑,但总要有人去做不起眼的小事。
6 google 厉害,这个perfetto 工具也很厉害。君子善假于物也。
7 工具的使用是最简单的入门,背后还有更多的东西值得学习。
8 水平实在有限,闻过则喜,希望有更多的人反馈,期待更好的建议