iOS 最全面的功耗分析之——Power Log

前言

功耗分析是移动应用开发中一个非常重要的课题,也是衡量应用性能表现的一个重要指标。但是在 iOS 设备上,由于苹果严格的限制,我们一直较难开展功耗分析的工作。

在 iOS 10 以前,我们还可以通过 IOKit 中的 IOPMPowerSource 私有接口,获取较为详细的电量信息,如电量、电压、电池温度等一系列的信息,腾讯的 GT 就是通过该接口获取电池的信息。然而,在 iOS 10 以及更高的系统中,该接口也被封印了,现在读取该接口,只能获取到很鸡肋的信息,如下图所示。

iOS 10 及之后的系统版本只能获取到零星的数据

因此,iOS 平台上急切地需要一个功耗分析的工具。

Power Log(Sysdiagnose)

我们都知道,iOS 系统本身是有对电量的使用情况进行记录和分析的,所以我们才能在系统设置里看到过去一段时间里,各个 App 的前台工作时间和耗电情况。在进行了一整天的调研后,我震惊地发现,iOS 的耗电记录是可以导出的,并且它记录的详细程度简直令人发指!简单地说,它包括了过去几天里,系统整体的详细功耗情况、各个 App 在各个硬件上的耗电情况(包括第三方 App),等等一系列详细的数据。

有的同学可能遇到过,在向苹果反馈 Bug 时,有时苹果的工程师会要求你附上设备的诊断日志,其中,在遇到电池续航相关的问题时,苹果的工程师会让你提供一下电池的诊断日志。在电池的诊断日志中,就包含了电池电量的使用记录。

这些诊断工具在之前被苹果称为 Sysdiagnose,现在,它们被苹果统一归类到 Bug Reporting 的主题中,电池续航相关的诊断日志被称为“Power Log”。

我在苹果的 Bug Reporting 中发现了一份电池诊断日志的导出指南,其中仅仅简短地介绍了导出日志的几个步骤。我按照其中的步骤成功导出了电池续航日志,发现该日志其实是一个数据库,其中储存了几十张表。至于这几十张表中存储的内容是什么,各个字段的含义是什么,以及如何分析其中的数据,苹果的指南中则只字未提。好在经过一番查找后,我发现了腾讯的一篇博客 中有提到其中几张表的内容,有了这个开头后,我便顺腾摸瓜,大致了解了其中的结构。

下面,我简单地介绍一下,如何通过这个方法获取最全面的功耗信息,以及如何分析其中的数据。

获取数据

苹果在电池诊断日志的导出指南中详细说明了导出日志的步骤。我这里简要说明一下大概的步骤。

  • 首先在你的测试机上,安装电量分析的 profile,安装完成后,iOS 才会记录最详细的功耗数据,并开放读取;(推荐下载后用 Airdrop 发送到手机上安装)
  • 第二步,连接上 iTunes 并同步,这时 iTunes 就会自动把手机上的功耗的历史记录拷贝到电脑上;
  • 第三步,断开设备,运行你的 App,这时设备已经在记录功耗信息,记得留意你运行 App 时的时间,因为稍后要和数据库中的时间戳进行匹配;
  • 第四部,再次连接上 iTunes 并同步,这时 iTunes 就会自动把手机上的详细功耗记录拷贝到电脑上;

诊断日志的目录

到 iTunes 的同步文件夹(
~/Library/Logs/CrashReporter/MobileDevice/你的手机名/)下,找到以Powerlog_开头,后缀是.PLSQL或者.PLSQL.gz的几个文件,这些就是记录了所有功耗信息的数据库文件了,可以使用简单的数据库查看工具打开看看。

诊断日志的目录

分析数据

打开数据库后,我们可以看到里面有数百张表。苹果没有解释这些表的具体作用,只介绍了如何导出,因为苹果实际上只打算用这份记录来诊断问题,目前并没有直接向开发者开放。但我们可以通过各个表中的字段名,来了解各个表的大概用途。此外,腾讯的文档中介绍了其中比较重要的七张表,这节省了我们不少时间。下面列举一下关键的几张表的作用。

表名 内容
PLBatteryAgent_EventBackward_Battery 整机的电量信息,包含电流、电压、温度等信息。(每20秒记录一条数据)
PLBatteryAgent_EventBackward_Battery_UI 剩余电量百分比。(每20秒记录一条数据)
PLIOReportAgent_EventBackward_EnergyModel 整机不同硬件上的详细功耗数据。分别记录了 CPU、GPU、DRAM 等硬件的耗电量。
PLAccountingOperator_Aggregate_RootNodeEnergy 各个 App 的详细耗电数据。记录各个 App 在各个硬件上的耗电量。(每小时更新一次数据)
PLAccountingOperator_EventNone_Nodes 各个硬件对应的 Node ID,以及各个 App 的对应的 Node ID。
PLAccountingOperator_EventNone_AllApps 手机中安装的所有 App 的信息
PLApplicationAgent_EventForward_Application App 运行状态记录。记录各个 App 在某个时间段以什么状态运行。
PLAppTimeService_Aggregate_AppRunTime App 的运行时长统计。(每小时更新一次数据。
PLBatteryAgent_EventForward_LightningConnectorStatus Lighting 接口连接状态
PLBatteryAgent_EventNone_BatteryConfig 电池的配置信息。包括电池容量、循环计数、电池寿命、电池温度等信息。
PLBatteryAgent_EventNone_BatteryShutdown 电池导致的意外关机记录。
PLButtonAgent_EventPoint_Button 疑似物理按键的点击记录。
PLCameraAgent_EventForward_Camera 相机使用记录。记录了相机类型和使用相机的 App
PLConfigAgent_EventNone_Config 本机的一些配置信息和一些系统设置。
PLDisplayAgent_Aggregate_UserTouch 屏幕点击计数。每 15 分钟记录一条数据。
PLDisplayAgent_EventForward_Display 屏幕亮度信息。包括流明、尼特、亮度滑竿值等信息。
PLProcessNetworkAgent_EventPoint_Connection 网络连接记录。记录了发起网络连接的 App、地址、端口等信息。
PLXPCAgent_EventPoint_CacheDelete 清除缓存的记录。包括申请的空间大小、清除缓存的耗时、清除的缓存大小、服务名称、紧急程度等信息。

我们结合几张表就可以简单地分析出一些衡量耗电量的维度,例如:

1、绘制电量百分比变化曲线

直接读取 PLBatteryAgent_EventBackward_Battery_UI 表中的数据即可。

2、iPhone 整体耗电量和温度变化

直接读取 PLBatteryAgent_EventBackward_Battery 表中的电量、温度数据,数据的记录间隔是 20 秒,基本上满足了各种各样的需求。

3、分析特定 App 的详细功耗数据

结合 PLAccountingOperator_Aggregate_RootNodeEnergyPLAccountingOperator_EventNone_Nodes 两张表,可以得到某个 Bundle ID 对应的 App 在各个硬件上的耗电情况。

存储了硬件节点 ID 的表

由于 PLAccountingOperator_Aggregate_RootNodeEnergy 中的每条数据,是记录该时间点之前一个小时内的耗电情况,所以我们可以知道在每个小时内,这个 App 在各个硬件上的耗电情况。例如,我们可以查到美拍在过去一个小时内的耗电情况,如下图所示,从中我们可以找出耗电较多的硬件,其中,耗电最多的是 RootNodeID 为 10 的硬件,也就是屏幕。

美拍在一个小时内各个硬件的耗电情况

总结

Power Log 能够为我们提供十分详细和准确的功耗数据,从细节到整体都能够兼顾到。并且根据苹果官方的说法,记录详细的功耗数据并不会导致 iPhone 性能的下降,只是会占据一定的磁盘空间。不过,也因为它的数据量太大,导致它对我们不太友好。我们需要用 SQL 去读取、处理庞杂的原始数据,才能得到理想的信息。最好的方案是为此开发一个读取和分析的前端,这样才能够提高效率。此外,由于它的数据是离线获取的,这在某些情况下可能不是很方便。

但总的来说,Power Log 是十分强大的,它记录的信息之丰富让人印象深刻,也为我们的功耗分析提供了更好更强大的手段。