“ 最近有公司同事在处理UI卡顿及FPS自动化监测的问题,我也顺便看了一点相关的内容,其中在Perfetto的官方说明文档中有一篇关于利用FrameTimeLine进行Jank监测的解读,个人觉得蛮有意思的,借助工具翻译该篇文章并加上本人拙劣的解读供大家把玩!”
注意:Android 12(S)以及更高版本的安卓系统的SurfaceFlinger中才有实现FrameTimeLine的逻辑。
/frameworks/native/services/surfaceflinger/FrameTimeline/
英文好且对Graphics知识有一定了解的,无需阅读拙作,直接读英文原文即可,地址:
https://perfetto.dev/docs/data-sources/frametimeline
01 前言
Jank/Janky直译就是劣质的、不可靠的。如果一个Frame被认为出现了Jank,则说明该帧图像没有按照调度器给出的预计时间显示到屏幕上,通常就是显示晚了。
Jank会造成什么影响呢?
-
不稳定的帧率 -- 比如正常是60fps,但因为Jank帧率可能只有50fps,导致画面不流畅;
-
延迟增加 -- 在一些实时性要求高的场景,画面可能延时几个vsync显示,比如视频播放时AV不sync;
怎么监测Jank呢?
FrameTimeline是SurfaceFlinger中的一个模块,用于监测Jank并报告Jank的来源。
02 APP Timeline
对于至少有一帧画面显示到屏幕上的应用,在抓取的Perfetto信息中会看到两个Timeline轨迹:Expected Timeline 和 Actual Timeline
Expected Timeline:预期时间线,每个切片表示应用程序渲染帧的时间。为了避免系统中出现janks,该应用程序预计将在此时间范围内完成。切片开始时间是Choreographer callback计划运行的时间。
Actual Timeline:这些切片表示应用程序完成帧的绘制(包括GPU工作)并将其发送给SurfaceFlinger进行合成所花费的实际时间。起始时间是Choreographer#doFrame或AChoreographer_vsyncCallback开始运行的时间。切片的结束时间表示 (gpu time, post time) 两者的最大值。post time是应用的帧发送到SurfaceFlinger的时间。
看到这里大家会不会有什么疑问或发现?
对于Case 2,比较符合常规理解,CPU和GPU的工作都做完了,即APP的一帧图片绘制完成了,然后才送到SurfaceFlinger去显示;
对于Case 1,GPU的绘制还没完成就先送去SurfaceFlinger了,这不会有问题吧?当然不会,这就是acquire fence的意义了,不熟悉的可以参考前面文章
Android Graphics 显示系统 - GraphicBuffer同步机制-Fence(二十)
我们看Android 14代码中,主要是哪里在等待acquire fence:
CLIENT合成时,会调用到RenderEngine::drawLayers方法来呼叫GPU完成合成工作,要等到layer的buffer准备好后才能开始合成工作,此时就要等待acquire fence。
/frameworks/native/libs/renderengine/skia/SkiaRenderEngine.cpp
ftl::Future<FenceResult> RenderEngine::drawLayers(...) {
......
drawLayersInternal(std::move(resultPromise), display, layers, buffer, useFramebufferCache,
std::move(bufferFence));
return resultFuture;
}
/frameworks/native/libs/renderengine/skia/SkiaRenderEngine.cpp
void SkiaRenderEngine::drawLayersInternal(......) {
...
if (layer.source.buffer.buffer) {
ATRACE_NAME("DrawImage");
// if the layer's buffer has a fence, then we must must respect the fence prior to using
// the buffer.
if (layer.source.buffer.fence != nullptr) {
waitFence(grContext, layer.source.buffer.fence->get()); // 等待acquire fence
}
...
}
DEVICE合成时,layer的buffer连同其acquire fence会送到HWC,HWC合成前会等待acquire fence。以/external/drm_hwcomposer为例来看:
点击阅读全文:
Android Jank detection with FrameTimeline