24. 功耗基线管理:建立功耗基线、基线对比方法、功耗回归预防

功耗优化做到一定程度,你会发现一个尴尬的问题:改了一版代码,功耗到底是变好了还是变差了?

我见过太多团队,优化做了几个月,结果一问基线是多少,没人说得清。大家凭感觉说“好像省电了”,但拿不出数据。这其实很危险——你很可能在“优化”的过程中,反而引入了功耗回归。

所以这一章,我们来聊聊功耗基线管理。说白了,就是给功耗上个“锚点”,让每一次改动都有据可查。

24.1 什么是功耗基线?为什么它如此重要?

功耗基线,就是你在某个特定版本、特定场景下测得的功耗数据。它像一个“标尺”,用来衡量后续所有改动的影响。

我个人习惯把基线分为三层:

  • 版本基线:每个正式发布版本(如V1.0、V2.0)的功耗数据
  • 场景基线:特定场景下的功耗数据(如相机预览、录像、HDR拍照)
  • 模块基线:某个子模块的功耗数据(如ISP、GPU、DSP)

没有基线,你根本不知道优化有没有效果。更可怕的是——你可能在“优化”的路上越走越远,功耗反而越来越差。

核心观点:基线不是一次性的,它是持续迭代的。每次发布新版本,基线都要更新。

24.2 如何建立功耗基线?

建立基线,听起来高大上,其实步骤很清晰。我总结了一个“四步法”:

第一步:确定测试场景

相机场景太多了。你不能把所有场景都测一遍,那会累死人。我建议选几个“黄金场景”:

  • 相机冷启动:从点击图标到第一帧预览显示
  • 预览场景:30fps预览,持续5分钟
  • 录像场景:1080P@30fps录像,持续10分钟
  • 拍照场景:连拍20张,间隔1秒
  • 待机场景:相机后台挂起,持续30分钟

每个场景测3次,取平均值。为什么是3次?因为功耗数据波动很大,一次不准。

第二步:统一测试环境

这一点我吃过亏。有一次基线数据波动很大,查了半天,发现是测试时屏幕亮度不一样。嗯,从那以后,我定了个规矩:

  • 屏幕亮度固定为200nit
  • WiFi/BT关闭,SIM卡插入但无业务
  • 手机温度控制在25±2°C
  • 使用同一台测试设备(不要换机器)
  • 测试前充满电,静置10分钟

注意:环境温度对功耗影响巨大。夏天和冬天的基线数据不能直接对比。我建议在恒温箱里测,或者至少记录环境温度。

第三步:采集数据

数据采集工具,我推荐用这三件套:

工具 用途 精度
Monsoon Power Monitor 整机电流采集 ±1mA
Perfetto 模块级功耗分析 ±5%
BatteryStats 软件级功耗统计 ±10%

我个人习惯用Monsoon做基线,因为它最准。Perfetto用来做模块级分析,BatteryStats用来做快速验证。

第四步:记录基线

基线数据要记录到文档里,格式要统一。我常用的模板是这样的:

# 功耗基线报告 - Camera V2.1

## 测试信息
- 设备:Pixel 6 Pro
- 版本:V2.1 (Build 20240301)
- 测试日期:2024-03-05
- 环境温度:25°C

## 基线数据
| 场景 | 平均电流(mA) | 峰值电流(mA) | 功耗(mW) |
|------|-------------|-------------|---------|
| 冷启动 | 580 | 1200 | 2146 |
| 预览 | 420 | 650 | 1554 |
| 录像 | 680 | 850 | 2516 |
| 拍照 | 750 | 1100 | 2775 |
| 待机 | 15 | 30 | 55.5 |

## 备注
- 预览场景使用默认相机APP,后置摄像头
- 录像场景使用1080P@30fps,H.264编码

24.3 基线对比方法

基线建好了,怎么对比?直接看数字大小?没那么简单。

方法一:绝对值对比

最简单的方法。新版本测一遍,和基线比绝对值。比如基线预览是420mA,新版本是400mA,那就是优化了20mA。

但这里有个坑:功耗数据有波动。你测3次,可能得到410、420、430。所以对比时,要看置信区间。我一般用这个规则:

  • 差异 < 5%:视为无变化
  • 差异 5%-10%:需要复测确认
  • 差异 > 10%:确认有变化

方法二:归一化对比

有时候场景不完全一致,比如录像时长不同。这时候需要归一化。我常用的归一化方式:

  • 按时间归一化:总功耗 / 测试时长,得到平均功耗
  • 按帧数归一化:总功耗 / 总帧数,得到每帧功耗
  • 按分辨率归一化:总功耗 / 像素数,得到每像素功耗

举个例子:

基线:录像10分钟,总功耗1500mAh,平均功耗150mAh/min
新版本:录像8分钟,总功耗1280mAh,平均功耗160mAh/min

结论:新版本功耗反而高了6.7%!

你看,如果不归一化,只看总功耗(1280 vs 1500),你会以为优化了。但归一化后,真相大白。

方法三:趋势对比

单个版本对比不够,要看趋势。我习惯画一个“功耗趋势图”,横轴是版本号,纵轴是功耗值。这样一眼就能看出功耗是在变好还是变差。

相机功耗趋势图(预览场景) 平均电流 (mA) 版本号 300 350 400 450 500 V1.0 V1.1 V2.0 V2.1 V3.0 450 430 420 440 400 ⚠ 功耗回归 基线区域 (420±20mA) 正常版本 回归版本 优化版本

你看这张图,V2.1版本出现了明显的功耗回归。如果没有趋势图,你可能根本不会注意到。

24.4 功耗回归预防

功耗回归,说白了就是“改坏了”。我见过太多案例:

  • 加了一个新功能,功耗涨了10%
  • 修了一个bug,结果引入了新的功耗问题
  • 升级了SDK版本,相机功耗直接翻倍

怎么预防?我总结了三个“防线”:

第一道防线:代码审查

代码审查时,加一个“功耗检查项”。我常用的检查清单:

  • 是否新增了不必要的唤醒锁?
  • 是否在预览路径中增加了耗时操作?
  • 是否关闭了不再使用的硬件模块?
  • 是否使用了高效的编码格式?
  • 是否有内存泄漏导致GC频繁?

我曾经在代码审查中发现一个同事在预览回调里做了图像处理,每次回调都申请新内存。嗯,这直接导致GC频率从1次/分钟变成了10次/分钟,功耗涨了8%。

第二道防线:自动化测试

手动测试太慢了。我建议把功耗测试集成到CI/CD流水线中。每次提交代码,自动跑一遍基线场景,如果功耗超过阈值,自动告警。

阈值怎么设?我一般用这个规则:

  • 警告阈值:基线 + 5%
  • 失败阈值:基线 + 10%

超过警告阈值,发邮件通知。超过失败阈值,直接阻断合并。

小技巧:自动化测试不要跑所有场景,太耗时。选3个核心场景就够了:预览、录像、待机。每个场景跑2分钟,整条流水线控制在10分钟以内。

第三道防线:回归分析

如果发现功耗回归,怎么定位?我习惯用“二分法”:

  1. 找到回归版本和上一个正常版本
  2. 列出两个版本之间的所有代码变更
  3. 逐个回退变更,测试功耗
  4. 找到罪魁祸首

举个例子:

正常版本:V2.0,预览功耗420mA
回归版本:V2.1,预览功耗440mA

变更列表:
1. 升级了ISP驱动
2. 增加了美颜滤镜
3. 修改了预览帧率控制

回退测试:
- 回退ISP驱动 → 功耗仍为440mA(排除)
- 回退美颜滤镜 → 功耗降为420mA(找到!)

你看,二分法很有效。但要注意,有时候多个变更叠加才会导致回归,单个回退可能看不出来。这时候需要组合测试。

24.5 基线管理的“最佳实践”

最后,分享几个我踩过的坑和总结的经验:

经验一:基线数据要“可复现”

记录基线时,一定要把测试条件写清楚。我曾经看到一份基线报告,只写了“预览功耗420mA”,其他什么都没写。后来想复现,发现根本不知道当时用的什么相机APP、什么分辨率、什么帧率。这基线等于白建。

经验二:基线不是“死”的

基线要定期更新。我建议每个大版本更新一次基线。如果中间有重大改动(比如换了ISP芯片),也要立即更新基线。

经验三:关注“异常值”

有时候基线数据里会出现一个异常高的值。不要直接忽略,要查清楚原因。可能是测试环境有问题,也可能是代码有bug。我曾经遇到过一次,基线里有个异常值,后来发现是测试时手机在充电。嗯,这种低级错误,谁都会犯。

好了,这一章的内容就到这里。功耗基线管理,说白了就是“用数据说话”。没有基线,你所有的优化都是盲人摸象。有了基线,你才能知道每一步是前进还是后退。

记住:基线不是终点,而是起点。每一次优化,都要以基线为参照,以数据为证据。这样,你的功耗优化之路才会越走越稳。

最后一个小建议:把基线管理做成一个“仪式”。每次发布版本前,团队一起看基线数据,讨论功耗变化。这不仅能发现问题,还能培养团队的功耗意识。