23. 功耗自动化测试:编写功耗测试脚本、自动化压测场景、功耗回归测试
功耗优化做得好不好,不能光靠嘴说。你得有数据,有对比,有回归。
我见过太多团队,优化了一版功耗,下个版本又改回去了。为什么?因为没有自动化测试来守住底线。说白了,功耗优化和功能开发一样,需要持续集成,需要回归守护。
为什么需要自动化功耗测试?
手动测功耗,一次两次还行。但你要做回归,每天跑几十个场景,手都点废了。而且人测有个大问题——操作时机不准。你想想看,多按了0.5秒,电流波形就变了,数据根本没法对比。
自动化测试能解决三个核心问题:
- 一致性:每次操作的时间点、间隔、顺序完全一致
- 覆盖率:可以同时覆盖几十个场景,人做不到
- 可追溯:每次跑完都有日志和波形,出了问题能定位
核心观点:功耗自动化测试不是为了替代手动测试,而是为了守住回归底线。让机器做重复的事,让人做分析的事。
编写功耗测试脚本
写脚本这事,我习惯用Python。为什么?生态好,仪器驱动多,上手快。下面是我常用的脚本框架:
import subprocess
import time
import csv
from power_monitor import PowerMonitor
class CameraPowerTest:
def __init__(self, device_serial, monitor_ip):
self.device = device_serial
self.monitor = PowerMonitor(monitor_ip)
self.results = []
def setup(self):
"""预热设备,确保状态一致"""
subprocess.run(f"adb -s {self.device} shell am force-stop com.android.camera2")
time.sleep(2)
# 关闭后台无关进程
subprocess.run(f"adb -s {self.device} shell pm disable com.example.bloatware")
def test_preview(self, duration=30):
"""测试预览功耗"""
self.monitor.start_recording()
subprocess.run(f"adb -s {self.device} shell am start -a android.media.action.IMAGE_CAPTURE")
time.sleep(2) # 等待预览稳定
time.sleep(duration)
avg_current = self.monitor.stop_recording()
self.results.append({
'scene': 'preview',
'avg_current_ma': avg_current,
'duration_s': duration
})
def test_video_recording(self, duration=60):
"""测试录像功耗"""
self.monitor.start_recording()
# 模拟点击录像按钮
subprocess.run(f"adb -s {self.device} shell input tap 540 1800")
time.sleep(duration)
subprocess.run(f"adb -s {self.device} shell input tap 540 1800")
avg_current = self.monitor.stop_recording()
self.results.append({
'scene': 'video_recording',
'avg_current_ma': avg_current,
'duration_s': duration
})
def run_all(self):
self.setup()
self.test_preview()
self.test_video_recording()
self.save_report()
def save_report(self):
with open('power_report.csv', 'w') as f:
writer = csv.DictWriter(f, fieldnames=['scene', 'avg_current_ma', 'duration_s'])
writer.writeheader()
writer.writerows(self.results)
if __name__ == '__main__':
tester = CameraPowerTest('ABCD1234', '192.168.1.100')
tester.run_all()
小技巧:脚本里我习惯加一个warmup()方法。因为刚开机时,电流往往偏高,等30秒再测,数据更稳定。这个坑我踩过,第一次测出来的数据比实际高了20%。
自动化压测场景设计
压测不是乱测。你得知道相机最耗电的场景是什么。我个人经验,以下场景必须覆盖:
| 场景 | 操作序列 | 预期时长 | 关注指标 |
|---|---|---|---|
| 连续预览 | 打开相机 → 保持预览30分钟 | 30min | 平均电流、温升 |
| 反复拍照 | 拍照 → 等待2s → 拍照,循环100次 | 约5min | 峰值电流、恢复时间 |
| 录像循环 | 开始录像 → 5min → 停止 → 等待3s,循环10次 | 约50min | 平均电流、温度 |
| 模式切换 | 拍照→录像→夜景→人像,循环50次 | 约10min | 切换电流尖峰 |
| 低电量场景 | 电量5%时打开相机并录像 | 10min | 是否降频、电流波动 |
为什么要设计这些场景?我举个例子。有一次我们做功耗优化,预览功耗降了15%,结果一跑反复拍照场景,发现每次拍照后电流恢复时间变长了。原来是为了省电,把ISP的时钟降得太低,导致拍照后重新拉起很慢。这个场景如果不压测,根本发现不了。
功耗回归测试流程
回归测试,说白了就是每次代码提交后,自动跑一遍功耗基线。我建议这样搭:
# 回归测试脚本示例
#!/bin/bash
# 参数:$1 = 基线版本号,$2 = 当前版本号
BASELINE=$1
CURRENT=$2
# 1. 刷入基线版本
fastboot flash system baseline_${BASELINE}.img
adb reboot
sleep 30
# 2. 跑基线功耗
python3 camera_power_test.py --output baseline.csv
# 3. 刷入当前版本
fastboot flash system current_${CURRENT}.img
adb reboot
sleep 30
# 4. 跑当前功耗
python3 camera_power_test.py --output current.csv
# 5. 对比结果
python3 compare_power.py --baseline baseline.csv --current current.csv
# 6. 如果功耗增加超过5%,报警
if [ $? -gt 5 ]; then
echo "功耗回归失败!当前版本功耗增加超过5%"
exit 1
fi
注意:回归测试的环境必须一致。我曾经吃过亏——白天跑和晚上跑,室温差了5度,电流数据差了10%。后来我规定:回归测试必须在恒温箱里跑,温度控制在25±1°C。
数据对比与阈值设定
拿到数据后,怎么判断有没有回归?我一般设三个阈值:
- 绿色:功耗变化在±3%以内,正常波动
- 黄色:功耗增加3%~8%,需要人工确认
- 红色:功耗增加超过8%,直接阻断合入
阈值怎么定?我建议先跑10次基线,算标准差。比如预览场景平均电流是500mA,标准差是10mA,那±3%就是±15mA。超过这个范围,说明有显著变化。
SVG:功耗自动化测试流程
避坑指南
做功耗自动化测试,有几个坑我踩过,分享给你:
- 仪器漂移:电流计用久了会漂。我习惯每个月校准一次,用标准电阻验证。
- USB供电干扰:adb连着的USB线会供电,影响电流测量。解决方案是用无线adb,或者用USB隔离器。
- 后台进程干扰:测试前一定要确保没有后台更新、同步在跑。我脚本里会先跑一个
dumpsys batterystats --reset。 - 温度累积:连续跑压测,手机会越来越热。我建议每个场景之间休息2分钟,让温度降下来。
总结一下:功耗自动化测试不是一锤子买卖。它需要持续维护脚本、更新场景、校准仪器。但一旦跑起来,它能帮你守住功耗底线,避免「优化一时爽,回归火葬场」的尴尬。