APM – iOS 卡顿监控 方案和指标

简介

iOS卡顿监控有多种不同的方案和指标,在实施成本和指标精确度上各有不同。本文例举一下常见的方案和代码,以及其指标的实现和拟合程度。

FPS

帧率

FPS数据,依据页面信息做聚合,或者APP版本之间比对,通常用于页面性能衡量。

单一的FPS数据难以用于卡顿的判定。

掉帧率

当前主流设备屏幕普遍在60帧,新iOS设备和部分Android设备有很多在90和120帧,计算掉帧率有更好的扩展性。

帧率波动

对于游戏等APP的卡顿监控,虽然任天堂Switch只有30帧的锁帧,但是玩家也不会感觉到卡顿,但是过快的帧率波动却会导致肉眼可见的卡顿。

帧率过低当然会导致卡顿,但是帧率波动过快也是导致卡顿的原因。我们可以从帧间耗时,与前几帧帧间耗时的对比计算,得到帧率波动水平。

同时满足两条件,则认为是一次卡顿Jank.

①Display FrameTime>前三帧平均耗时2倍。

②Display FrameTime>两帧电影帧耗时 (1000ms/24*2=84ms)。

同时满足两条件,则认为是一次严重卡顿BigJank.

①Display FrameTime >前三帧平均耗时2倍。

②Display FrameTime >三帧电影帧耗时(1000ms/24*3=125ms)。

场景化

低FPS在一些场景下,才能表示页面正在发生卡顿,在页面静止的情况下,低FPS值并不能代表卡顿。

主要场景

  • 页面转场

  • Scrollview等滑动

  • 其他

    • 容器内滑动
    • 视频播放

监听页面生命周期的状态,观察页面是否处于转场中。

监听Runloop状态,观察页面是否处于滑动中。

Runloop

基于Runloop的卡顿监控,主要是判断除Runloop Waiting外的activity执行是否超出阈值时间。

iOS-Matrix中阈值时间默认值为2秒,卡顿检测间隔为1秒。

实现方案

  • Observer
  • Ping-Pong

Hitch Time Ratio

Instruments中当前使用该指标衡量卡顿,是指卡顿的时间占总时间的占比

量化卡顿的两种方式:

  1. 卡顿时间:某一帧展示的时间比预期的时间晚了多少
  2. 卡顿率:总的卡顿时间/总时间

标准推荐:

Critical >= 10ms/s

Warning 5..10ms/s

Good < 5ms/s

渲染流程

把显示分为了提交和渲染2个阶段

辅助信息

页面信息

获取页面栈顶部的页面,部分特殊页面需要做处理

    @objc open class dynamic func topMost(of viewController: UIViewController?) -> UIViewController? {

        // presented view controller

        if let presentedViewController = viewController?.presentedViewController {

            return topMost(of: presentedViewController)

        }

        

        // UITabBarController

        if let tabBarController = viewController as? UITabBarController,

            let selectedViewController = tabBarController.selectedViewController {

            return topMost(of: selectedViewController)

        }

        

        // UINavigationController

        if let navigationController = viewController as? UINavigationController,

            let visibleViewController = navigationController.visibleViewController {

            return topMost(of: visibleViewController)

        }

        

        // UIPageController

        if let pageViewController = viewController as? UIPageViewController,

            pageViewController.viewControllers?.count == 1 {

            return topMost(of: pageViewController.viewControllers?.first)

        }

        return viewController

    }

堆栈信息

堆栈信息需要做符号化解析,才能从函数地址解析成函数符号。可以参考我的其他文章。

由于卡顿监控的滞后性,发现卡顿发生的时刻,堆栈可能已经变化。通常堆栈的获取并不能直接使用卡顿发生时刻的堆栈,需要使用循环队列等方式,从之前记录的一组堆栈中计算最近最耗时函数所在的堆栈。

最近最耗时函数

通过计算之前一组堆栈中重复次数最多的栈顶函数,找到其所在的堆栈,才能正确反应卡顿发生时的堆栈信息。

火焰图

获取之前发生的一组堆栈信息,把主线程堆栈组上报到对应平台,即可把完成火焰图显示出来。火焰图可以可视化的显示最近最耗时函数信息,而且并非一定需要是最近最耗时的栈顶函数。

问题

iOS常见卡顿问题总结

  1. NSUserDefaults:低内存的情况下,系统拷贝内存数据到磁盘
  2. I/O:文件读写、数据库操作
  3. 系统接口:获取mac地址、切换音频设备、读取桌面icon未知数
  4. 死锁以及锁的滥用
  5. 排版绘制:sizeWithFont、[EAGLContext setCurrentContext:]
  6. GCD并发队列短时间创建大量任务
  7. UIWebview初始化、销毁(使用性能更优的WKWebView)

引用

Matrix-iOS 卡顿监控

【PerfDog专家课堂】APP&游戏需要关注Jank卡顿吗?

Explore UI animation hitches and the render loop

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYkbpxRD' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片