乐趣区

关于android:Flutter帧率监控-由浅入深详解获取帧率的那些事

前言

做线上帧率监控上报时,少不了须要弄明确如何通过代码获取实时帧率的需要,这篇文章通过图解配合 Flutter 性能调试工具的形式一步步通俗易懂地让你明确获取帧率的基础知识,当前再也不愁看不懂调试工具上指标了。

说说 List<FrameTiming>

Flutter 中通过如下形式监听帧率,addTimingsCallback 波及到帧调度常识,感兴趣能够看看这篇 Flutter 帧调度过程。

这里重点说说 List<FrameTiming>。

List<FrameTiming> 从哪里来

addTimingsCallback 定义:

List<FrameTiming> 可简略了解成:引擎层到框架层的帧数据流。

<p align=center><img src=”https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a0124d1fed7640d094cfc4a473ba7d01~tplv-k3u1fbpfcp-zoom-1.image” alt=”” /></p>

List<FrameTiming> 何时有值

List<FrameTiming> 则示意一系列实时帧信息。

如点击屏幕按钮, 引擎将传递系列帧信息到框架层:“框架层,屏幕发送了变动,筹备回调数据更新了!”。如果用户未操作,addTimesCallback 则不会回调。

因而,addTimesCallback(List<FrameTiming>)只有用户操作界面时参数才有值

List<FrameTiming> 中帧存储程序


List<FrameTiming> 中 0 的地位是第一帧,last 是最新一帧。最新的帧永远在最初面

再说说 FrameTiming

通过这个单词不难猜测 Frame 示意帧,加上 Timing 能够了解成实时变动的帧。FrameTiming 是一个用来存储实时帧信息的 数据结构

FrameTiming 定义:

这里列了下我认为最重要的几个属性:

<p align=center><img src=”https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4a029f915b4041dca4a71892ae532dc4~tplv-k3u1fbpfcp-zoom-1.image” alt=”” width=”70%” /></p>

前置常识简略阐明

了解上述属性前需理解渲染相干常识,不分明的能够看看 Vsync 机制 和 卡顿产生起因。

核心思想
图像内容展现到屏幕的过程须要 CPU 和 GPU 独特参加。CPU 负责计算显示内容,比方视图的创立、布局计算、图片解码、文本绘制等。随后 CPU 会将计算好的内容提交到 GPU 去,由 GPU 进行变换、合成、渲染。之后 GPU 会把渲染后果提交到帧缓冲区去,期待下一次 VSync 信号到来时显示到屏幕上。因为垂直同步的机制,如果在一个 VSync 工夫内,CPU 或者 GPU 没有实现内容提交,则那一帧就会被抛弃,期待下一次机会再显示,而这时显示屏会保留之前的内容不变。

FrameTiming 在帧中的示意

当在利用中操作时候,就会产生间断的帧,如图:

每两个柱形一起示意一帧:ui 示意 cpu 耗时,raster 示意 gpu 耗时。

每帧细化后如下图,其中标注 ①②③④ 对应 FrameTiming 中的四个次要属性。而其中:

  • ui 在 FrameTiming 中有对应衍生变量叫 buildDuration。
  • Raster 在 FrameTiming 中用 RasterDuration 示意。

同时可推导出 FrameTiming 中相干衍生变量与上述重点关注属性关系:

④-① = totalSpan:同步信号开始到栅格化工夫

②-① = vsyncOverhead:同步信号承受后到 ui 构建之间提早。

③-② = buildDuration:ui 构建过程总工夫。

④-③ = rasterDuration:栅格化过程总工夫。

totalSpan 与 buildDuration+rasterDuration 关系

通过代码验证 Flutter 调试工具 PerformanceOverlay 中 Timing 每帧 ui 值和 ration 值与 vsyncstart、buildstart、buildFinish、rasterStart、rasterFinish 关系。

输入:

代码中,11 行是 ui 构建 + 栅格化工夫,17 行是 totalSpan 工夫,22 行中是 vsyncOverhead + ui 构建 + 栅格化工夫 这个值最终和才等于 totalSpan 值。

这里有个误区, 网上很少人关注 totalSpan 与 buildDuration+rasterDuration 关系,如同默认就是相等的。其实,totalSpan 不等于 Timing 中 ui + raster 值 而是 Vsync 信号承受后构建之前提早 vsyncOverhead+cpu 构建耗时 + gpu 耗时

通过上述案例和 totalSpan 定义很容易佐证这点:

如何获取帧率

外围思路

  1. 将原始帧数据 List<FrameTiming> 降噪保留最新关注帧数。
  2. 通过公式 FPS≈ REFRESH_RATE * 理论绘制帧数 / 实践绘制帧数。

如何降噪

  • 从原生数据中筛查最新关注帧数,其余都干掉。

    如下,通过栈形式调换了存储形式更容易操作,而后将栈中老的干掉只保留最新的关注 100 条。

  • 将位于不同帧的有效数据过滤掉。

    如下,以刷新率为 60 举例,如果一帧之间的工夫 > 16.6 *2,该帧就位于不同帧中,因为一帧最大工夫也就是 16.6ms。

如何计算

代码如下:

这里拆解下其中逻辑,不便了解。

有 5 帧,其中在理论绘制过程中 f① 和 f② 都是在失常工夫范畴内绘制,f③ 则会绘制耗时,逾越 2 帧。

假如 f①,f②,f③ 绘制总耗时为 P1, P2, P3 则:

  1. 实践绘制帧数 =(P1 / 16.6)+ 1 + (P2 / 16.6) + 1 + (P3 / 16.6) + 1 图中显著能够看到 P1 和 P2 < 16.6, 而 P3 > 16.6 *2,所有实践绘制帧数 = 0 +1 + 0 + 1 + 2 + 1 = 5。
  2. 理论绘制帧数 = 3。
  3. 原本失常应该绘制 5 帧,然而理论绘制 3 帧,取比值示意理论绘制能力,依据 FPS≈ REFRESHRATE 理论绘制帧数 / 实践绘制帧数。即 FPS = 3 \_ 60 / 5。

残缺代码

成果展现

这就完结了?

下面代码在刷新率为 60HZ 的手机上每秒绘制帧工夫为 16.6 是没有问题的,然而如果在其余帧率的手机上,比方 90HZ(OnePlus 7 Pro), 120HZ(Redmi K30)上就会存在问题。

  1. 代码中写死了 REFRESH_RATE = 60。
  2. maxframes = 100 也有问题,如果在 60HZ 手机上取 100 帧入不敷出,在 120HZ 手机上的话,每秒绘制 120 帧显然不够。

如何获取帧率(改进版)

思路:通过通道获取各零碎提供的刷新率获取形式,而后更新上述代码中的刷新率。

获取各零碎帧率

在 Android 和 ios 平台提供了获取帧率的办法。

  • 对于 Android 通过 WindowManager 获取刷新率:
  • 对于 iOS 从  CADisplayLink 获取刷新率:

定义对立获取接口并实现(以安卓为例)

定义接口

最终批改点

  1. 最大帧率数批改成 120。
  2. fpsHZ 这个值通过插件动静获取。
  3. 工夫距离也同步批改下,也就是 16.6(60hz 的时候)。
  4. 最初 fps 计算公式中的刷新率同步批改成 fpsHZ。

总结

本文重点解说了 FrameTiming 构造在帧显示过程中的对应关系,图解获取精确帧的算法,最初欠缺了获取帧的逻辑。

总体来说网上能搜到的我这里都有,在学习过程中遇到 FrameTiming 构造和帧率计算方法这两个点感觉不好了解,不够零碎,就重点介绍争取深入浅出表达出来。不足之处还望各位大佬指出,谢谢!

如果感觉文章对你有帮忙,点赞、珍藏、关注、评论,一键四连反对,你的反对就是我创作最大的能源。

❤️ 本文原创 听蝉 公众号: 码里特地有禅 欢送关注原创技术文章第一工夫推送 ❤️

PS: 文中所有源码获取形式:公众号后盾回复“fps”

参考链接

如何代码获取 Flutter APP 的 FPS – Yrom’s

Flutter 如何更加精确地获取 FPS | 区长

Flutter 性能计算之流畅性 fps 计算 – 简书

allenymt/flutter_fps: flutter Fps 的两种监听计划

退出移动版