ToB企服应用市场:ToB评测及商务社交产业平台

标题: iOS 高刷屏监控 + 优化:从理论到实践全面剖析 [打印本页]

作者: 雁过留声    时间: 2024-8-4 01:26
标题: iOS 高刷屏监控 + 优化:从理论到实践全面剖析
减少移动装备的屏幕功耗

在搭载了固定刷新率屏幕的装备上,当体现静态内容或者帧率较低(比方视频)的内容时,GPU 的渲染频率比实际频率刷新率会更低。但是固定刷新率的屏幕依然会已最高速率举行刷新,重复展示之前的内容,造成了额外的电量消耗。
ProMotion 屏幕在这种情况下可以自动降低刷新率,减少屏幕功耗,这对于移动装备来说尤其重要。
动态刷新率的体现情势

   The iPhone 13 Pro, the iPhone 13 Pro Max, and the iPad Pro ProMotion displays are capable of dynamically switching between:
     
     
   已知,ProMotion 屏幕的刷新帧率并不固定,体系会实时地根据当前体现内容的类型和状态来动态切换屏幕的刷新帧率。为了更好地理解这种动态帧率的体现情势,笔者分别在

上对一些典范渲染场景举行了测试,发现搭载了 ProMotion 屏幕的装备上运行 App 时,差异的场景下的各种统计口径的帧率指标确实展示出了有趣的变化。
详细而言,笔者分别在以下几种场景:
测试场景

静态的 UIView,无动画/视频等元素
包含静态 Cell 的 UITableView,仅观察滑动中的体现
体现基于 CABasicAnimation 实现的简单位移动画
仅在 ProMotion 装备上测试,基于 CABasicAnimation 实现的简单位移动画,同时解锁了 CADisableMinimumFrameDurationOnPhone 和 preferredFrameRateRange 帧率限制。(关于此限制下文会有详细先容)
使用基于 MTKView 举行渲染的播放器,播放源帧率分别为 30Hz/60Hz 的视频文件
并使用以下几种统计口径的帧率指标举行测试:
测试指标

iOS 中主要的帧率统计本领。
根据 CADisplayLink.h 头文件中描述,CADisplayLink 是一个 ”Class representing a timer bound to the display vsync “。在回调中比较当前帧/前一帧的时间戳,可以盘算出上一帧的渲染耗时(ts),其倒数(1/ts)即为当前的实时帧率。
Xcode -> Show Debug Navigator -> FPS 中体现的帧率。这个只能统计当前应用直接通过 OpenGL ES 或者 Metal 举行绘制的帧率,比方游戏渲染/视频播放,无法统计 Core Animation 的帧率(众所周知,后者通过 backboardd 举行绘制)。
Instruments 中 Core Animation FPS 工具所体现的帧率。这个统计的是 Core Animation 的帧率,即 Render Server backboardd 绘制的频率。目前该工具有 BUG 无法体现高于 60 FPS 的帧率。
Instruments 中 Display 工具所体现的 Surface/VSync 信号时间戳。如下图所示:


在 60Hz 屏幕上,iOS 装备默认接纳双缓冲刷新机制,也就是前帧缓存和后帧缓存。GPU 总是在后帧缓存上举行当前帧的绘制。当 VSync 信号到来时,交换前后帧缓存的指针(Swap FrameBuffer),屏幕刷新体现新的内容。
而当屏幕以 120Hz 体现内容时,iOS 会切换成三缓冲刷新机制(见上图中三种颜色的 Surface),这减少渲染管线的压力,但同时会增加肯定的渲染上屏延迟。
   Metal 应用可以通过设置 -[CAMetalLayer setMaximumDrawableCount:] 为 2 来在 120Hz 屏幕上强制启用双缓冲机制,避免这种延迟。
  如果屏幕体现内容未发生变化,Surface 则不会发生交换,一个 Surface 的 Display 大概持续数个 VSync 间隔,但多余的 VSync 信号依然代表着硬件层额外的屏幕刷新,造成额外的电量消耗。
非 ProMotion 装备

起首让我们看看传统的固定刷新率的装备的情况。
VSync 信号间隔固定为 16.67ms

XR 的屏幕刷新率为固定的 60Hz,这一点对应的详细指标是 VSync 信号的间隔,而在任何场景下,XR 的 VSync 信号的间隔均为固定的 16.67ms。
此外,在体现静态内容时,由于视图 Layer Tree 无变化,Core Animation 不会有提交新的事务提交,backboardd 不会举行刷新,以是对应这一帧的 Surface 也长时间(数十秒)未被交换下去,Core Animation FPS 的值体现为 0。
但由于 VSync 信号仍然以 60Hz 的频率持续触发,屏幕此时正在不绝重复展示同样的 Frame Buffer,消耗了额外的电量。
CADisplayLink 根本完全跟随 VSync 信号

根据过去对 iOS 体系的认知,我们知道 CADisplayLink 是由 VSync 信号驱动的:

默认设置的 CADisplayLink 的回调应该与 VSync 信号根本同时。
这一点在 XR 上得到了验证,用 Instruments 记录一次主线程发生的卡顿,得到:

此中:

可以观察到下述现象,符合我们之前的对 DisplayLink 的认识:

ProMotion 装备

下面看看 ProMotion 装备的测试效果。
VSync 信号间隔可变

在 ProMotion 屏幕上 VSync 信号间隔是可变的,详细而言:

可以看到 VSync 信号间隔能自动跟随体现内容的渲染帧率的改变而改变。
减少卡顿造成的体现延迟

在主线程发生卡顿导致滑动中某一帧渲染耗时过长时,体系会改变这一帧所对应的 VSync 信号间隔(下图 Surface 5),减小从渲染到展示的延时,从而减缓用户感知到的卡顿时长。

DisplayLink 不完全跟随 VSync 信号

如图是一张滑动中场景的 CADisplayLink 回调 和 Display/VSync 事件对照记录。和之前差异的是,再 ProMotion 装备上 DisplayLink 和 VSync 信号之间没有体现出显着的跟随关系:

详细而言:
解除 DisplayLink 的帧数限制

我们知道,在 iOS 15 上 Apple 对第三方应用的体现帧率默认做了限制。第三方应用必要在 Info.plist 中添加<key>CADisableMinimumFrameDurationOnPhone</key><true/> 字段才可以解锁 120Hz 的刷新率。
于此同时,在 iOS 15 中,CADisplayLink 等动画相关 API 也新增了一个用于设置偏好帧率的属性:
/* Defines the range of desired callback rate in frames-per-second for this
display link. If the range contains the same minimum and maximum frame rate,
this property is identical as preferredFramesPerSecond. Otherwise, the actual
callback rate will be dynamically adjusted to better align with other
animation sources. */
@property(nonatomic) CAFrameRateRange preferredFrameRateRange
API_AVAILABLE(ios(15.0), watchos(8.0), tvos(15.0));
为了进一步探究新装备上 DisplayLink 和 VSync 信号之间的关系,笔者将测试 App 的 Core Animation 的帧率限制解除,并设置对应的 API,分别在差异的场景重新举行测试:
体现动态内容的场景

动画场景

展示一个速度中等的位移动画,得到下图:

可以很直观地发现,DisplayLink 解锁帧率后的屏幕刷新率根本稳固在 120Hz。并且 VSync 和 DisplayLink 的关系似乎又重新一一对应了起来。
但是,将动画速度减慢,笔者发现这种对应关系发生了变化:

可以观察到在播放慢速动画时,DisplayLink 的频率依然是设置的 120Hz,但是实际的屏幕刷新率却只有 30Hz。
滑动场景

让我们换一种场景再次举行测试,快速滑动视图,在 Instruments 中得到下图:

可以发现,DisplayLink 解锁帧率后,屏幕刷新率同样根本稳固在 120Hz,仅在丢帧时有降频。
然后降低滑动屏幕的速度,得到了和慢速动画相似的效果,只管 DisplayLink 回调速度不减,但是 VSync 信号频率一直保持在较低的程度:

卡顿场景

上面两次测试都靠近抱负情况,即整个 Render Loop 执行几乎没有延迟与卡顿。但是现实中应用的运行总是有着各种各样的或大或小的卡顿标题。
为了验证更靠近现实情况下,DisplayLink 和 VSync 信号之间的关系,在一连滑动的情况下笔者人为参加了一个 20ms 的微小卡顿举行测试:

上图中可以看到,ProMotion 屏幕很好的处理了这次卡顿,由于三缓冲机制的存在,再 Render Loop 渲染 Surface 4 卡顿期间,通过改变 VSync 间隔,体系实验将缓冲区中的 Surface 283 与 Surface 250 延迟上屏,尽量缩短了用户看到静止画面的时长。
随后,主线程规复执行,可以看到 DisplayLink 的回调频率很快规复至卡顿前的高程度。而此时 VSync 信号由于前述卡顿减缓机制的存在频率其实有所降低。此时二者频率并不吻合。
这和之前播放慢速动画/慢速滑动的情况很相似,由于卡顿加上缓冲机制的存在导致短时间内体系将屏幕的刷新频率降低,但在 CPU 侧依然维持了 DisplayLink 的高速回调,满足了使用方对 preferredFrameRateRange 这一 API 的设置。
为了进一步分析了这种机制的本质,笔者接下来会实验逆向分析 iOS 15 中的体系库相关实现的改动。
逆向分析

DisplayLink 驱动方式的变化

在 CADisplayLink 回调方法上设置断点,分别在 iOS 14 和 15 ProMotion 装备上运行,可以得到:


在 15 中,CADisplayLink 第一次创建并添加至 RunLoop 的时间,会注册一个 Source 1 信号,这和 14 中举动划一。

其 callout 回调地址对应符号为同样为 display_timer_callback,同样和 14 中的划一。

这也可以解释为什么 15 上 VSync 信号确实会叫醒一次 RunLoop,只是这次叫醒并不肯定触发 DisplayLink 的回调,这就阐明 display_timer_callback 举动和 14 相比肯定发生了某种变化。
display_timer_callback 逻辑的变化

使用 Hopper 分析 display_timer_callback 的实现,发现 15 和 14 的实现并无区别。使用 LLDB 举行 debug,逐步分析,观察到后续调用函数为 CA:isplay:isplayLink::callback,其关键反汇编代码如下图所示:

观察反汇编代码可以发现,如果 CA::display_link_will_fire_handler 这个 block 返回了 NO,则这次 VSync 信号回调不会触发后续的 CA:isplayLink::dispatch_items 调用。
实际上在 LLDB 中也验证了这点:

注意上图中的 _CFRunLoopCurrentIsMain 和上图红框代码靠近,后续的 blraa 指令看起来很显着是调用了一个 block(上面的 ldr x9 [x8, #0x10] 就是把 invoke 指针从 block 布局体中取出的意思)。tbz 指令中 w0 寄存器为 block 执行的返回值,为 0(即 NO)时跳转至 0x1848dbc08,而 0x1848dbc08 刚幸亏 dispatch_items 的调用之后,跳过了该调用。
通过对上图中 blraa 指令 step in,我们发现这个 block 实际上是由 UIKitCore 注册的:

找到引用了该符号的 UIKit 的私有方法 __UIUpdateCycleSchedulerStart ,反汇编效果也验证了这点。

同时发现这个 block 的返回值固定为 0x0。

而同样的 symbol 在之前的 iOS 版本上并不存在,也就是说这个应该是 iOS 15 的变动。换安装了 iOS 15 的非 ProMotion 装备,重走上面的逆向流程发现,该装备的 CA::display_link_will_fire_handler 为 nil,未注册:

这里 cbz 执行了跳转,阐明 x0 为 nil,而 x0 是由 ldr x0, [x8, #0x1c8] 得到。

可以看到 x0 就是 CA::display_link_will_fire_handler。继续分析之前找到的私有符号 __UIUpdateCycleSchedulerStart 的相关实现,可以知道这是由于在非 ProMotion 装备上 _UIUpdateCycleEnabled 返回了 NO 导致的。

在返回 NO 的情况下 __UIUpdateCycleSchedulerStart 方法不会执行,CA::display_link_will_fire_handler 也就不会被注册。
_UIUpdateCycleEnabled 所带来的变化

继续研究 _UIUpdateCycleEnabled 相关的代码,笔者发现这个的改动并不是仅仅影响 DisplayLink 驱动方式那么简单。
当 _UIUpdateCycleEnabled 返回 YES 时,UIKit 会在 UIApplicationMain 中执行 _UIUpdateCycleSchedulerStart。分析该函数,发现 _UIUpdateCycleEnabled 启用时会调用 [CATransaction setDisableRunLoopObserverCommits:YES]。

Core Animation 是绝大部分 iOS 应用的渲染引擎,熟悉 iOS 渲染流程的同砚想必都知道它的执行也是由 MainRunLoop 驱动,大致为:

随后 MainRunLoop 进入休眠
Render Server 将打包好的 Layer Tree 解码,天生并提交对应的 draw calls
GPU 执行渲问鼎令,渲染出 FrameBuffer,待后续 VSync 信号来临时上屏展示
上图中 +[CATransaction setDisableRunLoopObserverCommits:YES] 这个调用给了笔者提示,让我们验证一下 CA::Transaction::commit() 在 iOS 15 ProMotion 装备上的执行时机,会发现确实不再由 BeforeWaiting 事件驱动了:

实际上同样的 Source 0 信号同时也驱动了 CADisplayLink 的回调:

关注这个 Source 0 的回调符号 runloopSourceCallback,会发现这个 Source0 是由 signalChanges 函数驱动:

而 signalChanges 又是由多个回调所驱动:

此中:


通过上面的分析,笔者有理由认为在 iOS 15 上应用的渲染驱动机制出现了比较大的变化。此中之一便是 DisplayLink 的驱动源的改变。
结论


   关于如何界定低速/中高速,笔者在下文中 CAAnimation 设置动态帧率 部分做了一些试验,可作为参考。
  同时,默认设置的 CADisplayLink 回调频率最高为 60Hz,无法监控更高频率的刷新事件。
动态帧率的应用场景

监控动态帧率下的流畅度体现

业界中一样寻常接纳 CADisplayLink 对应用的流畅度举行监控。由于 CADisplayLink 的举动在 iOS 15 上的变化,原先的监控方案无法评估 ProMotion 屏幕在超过 60Hz 时的体现。
根据上面的探索结论,目前笔者假想了三种针对 ProMotion 装备的兼容性修改方案:
方案一 [Pass]

对于任何装备都以 60Hz 为优化目标,只思量刷新间隔长于 16.67ms 的情况。换句话说,在屏幕以 120Hz 刷新时,对于丢 1 帧的情况也认为不丢帧,由于此时两帧之间的间隔仍然小于 16.67ms,理论上用户感知不大。
优点

缺点

方案二 [Pass]

通过一些本领,可以更换驱动 display_timer_callback 的 Source 1 信号的回调,使用它来正确监听 VSync 信号,实现对动态帧率的正确监控。
优点

缺点

方案三 [Pick]

通过在 CADisplayLink 回调中确认 duration 参数,盘算得到当前屏幕的实时刷新率,并修改 preferredFrameRateRange 来举行跟踪。
优点
方案相对简单,只需在每次回调中更新 DisplayLink 对象的 preferredFrameRateRange 属性即可
缺点

必要注意的是,CADisplayLink 的 preferredFrameRateRange 必要以类似一下格式举行设置:
NSInteger currentFPS = (NSInteger)ceil(1.0 / displayLink.duration);
displayLink.preferredFrameRateRange = CAFrameRateRangeMake(10.0, currentFPS, 0.0);
   CAFrameRateRange.minimum 传最小值 10.0,preferred 传 0.0,可以让该 CADisplayLink 只用于监控当前的体系帧率,而不影响帧率的动态选择。
  相比前两个方案,方案三改动小,不使用私有 API,监控正确性也较高,缺点相对来说可以担当。
FPS 的替换指标

思量到在 ProMotion 屏幕上 FPS 指标不再与应用运行是否流畅直接相关,它的聚合值参考价值不大,有必要探求一个新指标作为更换。
Apple 官方在 WWDC20 - 10077 Eliminate animation hitches with XCTest 中先容了 Hitch Time Ratio 这一概念,并着重阐明确它比单纯的 FPS 更能适配差异刷新率的场景。
在 XCTest 框架中,苹果提供了 API XCTOSSignpostMetric 帮助开发者在单测中即时地获取该指标,但相关 API 尽在单测中提供,线上无法使用。而 MetricKit 中的 MXAnimationMetric 只管可以在线上获取,但却不是实时的,无法满足大型 App 对差异场景的监控需求。
因此,遵循下面 Apple 对 Hitch Ratio 的定义:
   Hitch time:
     
      Hitch time ratio:
     
   笔者实验实现了基于 CADisplayLink 的 (Scroll) Hitch Time Ratio 的盘算方案:

关键场景提升帧率

在测试过程中笔者发现,体系 App 滑动时是稳固以最高刷新率 120Hz 运行的:

而第三方 App 即便设置了 CADisableMinimumFrameDurationOnPhone 为 true 也无法稳固以满帧率滑动(颠末验证,这一点在 iOS 15.4 beta 体系上依然建立)。
自我先容一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己探索发展或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技能停滞不前!
因此网络整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。







既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,根本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你以为这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)

末端

好了,今天的分享就到这里,如果你对在面试中遇到的标题,或者刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不敷了解不知道给如何规划,可以来看看偕行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试筹划及职业规划。
   这里放上一部分我工作以来以及加入过的大巨微小的面试网络总结出来的一套进阶学习的视频及面试专题资料包,主要还是希望大家在现在大环境不好的情况下面试能够顺利一点,希望可以帮助到大家~
  


一个人可以走的很快,但一群人才能走的更远。岂论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码参加我们的的圈子(技能交换、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习发展!

img-wwfxbOQm-1712847789125)]
[外链图片转存中…(img-Vafigpls-1712847789126)]
[外链图片转存中…(img-Tmu844ZK-1712847789126)]
[外链图片转存中…(img-SoDSURQt-1712847789127)]
[外链图片转存中…(img-9ww7TtyF-1712847789127)]
[外链图片转存中…(img-W4CRIuGY-1712847789127)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,根本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你以为这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-4QR20Rhf-1712847789127)]
末端

好了,今天的分享就到这里,如果你对在面试中遇到的标题,或者刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不敷了解不知道给如何规划,可以来看看偕行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试筹划及职业规划。
   这里放上一部分我工作以来以及加入过的大巨微小的面试网络总结出来的一套进阶学习的视频及面试专题资料包,主要还是希望大家在现在大环境不好的情况下面试能够顺利一点,希望可以帮助到大家~
  [外链图片转存中…(img-TMGKIbSB-1712847789128)]
[外链图片转存中…(img-yNVcmEJn-1712847789128)]
一个人可以走的很快,但一群人才能走的更远。岂论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码参加我们的的圈子(技能交换、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习发展!
[外链图片转存中…(img-OE914FY0-1712847789128)]

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4