0%

iOS-性能监控

最近在做性能监控,思路大致是 hook 一些 cpu 耗时比较严重(layoutSubviews,cellForRow 等)的方法,获取方法调用的时间写入日志。后期对日志进行分析,得到优化的方向。

此文简单介绍一下整套系统的设计思路和简述实现细节。

设计原则

1.不能影响原有业务代码逻辑

我们只是一个观察者,不应该影响其他业务方正常的功能。

2.监控对性能影响尽可能小

显而易见,因为观察者效应,监控必然是会对原有性能有影响。这一点需要非常注意

3.最好不需要业务方书写代码

如果需要业务方自己书写代码,这一点非常麻烦。最好能做到无痕接入,尽可能通用、可配置。

*4.面对不同用户提供不同程度的能力

使用这套性能监控的人可能很多。

  1. 产品
  2. QA
  3. RD

为这三种人提供分层次的能力。

5.最好有日志图表化的能力

日志数据分析是很重要的

6.数据一定要准确

一定要拿出可信度很高的数据,推动项目优化


项目实现

第一期:从用户肉眼感知到卡顿改善为可以通过数据去分析

第二期:页面级别统计流畅度,反馈给相关负责人

第三期:添加运行时的调试工具,帮助调试(自定义 time profiler)

统计方法调用时长

运行时懒加载 swizzle 我们关心的方法: layoutSubviews,drawRect,cellForRow

懒加载保证了我们调用时机永远在调用栈最底下,这样我们在方法被调用之前记录一个时间(start time),原始实现调用之后记录一个时间(end time),得到一个方法调用时长(duration)。

卡顿可视化

掉帧是一个主观性很强的感觉。我们需要把掉帧这种行为用数据、颜色表示出来。
特别是当一个列表页大部分情况下很流畅,但是只在一瞬间掉一两帧,这种情况直接用 Instruments 很难分析出需要优化的地方。
所以设计了如下的方案,完美解决瞬间掉帧的事情。

添加 FPS lable: 提供两个CPU、GPU 两种帧率显示

GPU 帧率根据每次 displayLink 到来的时候通过私有 API 获取的真实的 CAFrameID 计算得出

每个 Cell 添加耗时 Label

动态给每个 Cell 添加几个 Layer,放在左上角。显示 cellForRow 调用时长、所有子 View layoutSubviews 等方法调用的时长

UIView 染色

View 根据 layoutSubiew 和 drawRect 方法调用的时长进行染色(非常耗时的涂红,不太耗时涂白)

///  0 <= costLevel <= 1
layer.backgroundColor = [r: 1 g:1-costLevel b:1-costLevel]

布局、绘制行为记录
记录运行时所有的行为,方便分析

抓取业务数据

卡顿的瞬间记录 Cell 层次结构

[view recursiveDescription]

label text 等信息

日志

记录规则
日志按 displayLink 一次为一个单位。记录了每个 View 的布局、绘制,cellForRow 等行为

持久化
持久化在本地。提供直接在 app 内部查看 log 的能力

日志传输 在 pc 搭建了一个服务器,监控系统内部提供连接该服务器传输文件、流的能力。
因为日志量太大,没办法直接走后端接口上传,转而用自己 pc 搭建服务器的形式。

统计上报
采集标志性的数据上报服务器,后端分析通知相关负责人页面流畅度。