第三章 功耗测量方法论:板级功耗测量、芯片内部传感器与软件统计

功耗测量这件事,说白了就是回答三个问题:芯片到底吃了多少电?这些电都花在哪了?有没有办法省下来?

我做了这么多年功耗优化,发现很多工程师一上来就调参数、改代码,结果越调越乱。为什么?因为连功耗数据都不准,你调个啥?

这一章,咱们就把功耗测量的三种手段讲透。板级测量、芯片内部传感器、软件统计——这三板斧你都得会。

3.1 板级功耗测量:最直接的方法

板级测量,就是把芯片当成一个黑盒子,直接测它从电源上抽了多少电流。我个人习惯先用这个方法做基准,因为它最可靠。

3.1.1 Shunt电阻法

原理很简单:在电源路径上串一个小电阻,测它两端的压降,再用欧姆定律算出电流。

公式长这样:

I = V_shunt / R_shunt
P = I × V_core

嗯,这里要注意几个坑:

  • 电阻值不能太大——我见过有人用1Ω的电阻,结果压降太大,芯片直接欠压复位了。一般选10mΩ到100mΩ比较合适。
  • 电阻精度要够——至少1%,最好0.5%。我曾经因为用了5%的电阻,测出来的数据偏差20%,排查了三天才发现是电阻的问题。
  • 走线要小心——Shunt电阻的焊盘要开Kelvin连接,不然焊锡电阻会引入误差。
避坑指南: 我曾经在Exynos 9820的板子上用Shunt电阻测GPU功耗,结果发现数据跳得厉害。后来发现是地线回路太长,引入了噪声。解决办法是把示波器的地线夹直接焊在Shunt电阻的接地端。

3.1.2 功率监控芯片

如果你觉得Shunt电阻法太麻烦,可以用专用的功率监控芯片。比如TI的INA219、INA3221,或者Maxim的MAX34407。

这些芯片的好处是:

  • 内置ADC,直接输出电流和功率值
  • 支持I2C/SMBus接口,方便软件读取
  • 精度高,一般能做到±1%以内

我在三星的时候,Exynos 2100的参考板上就用了INA3221,三通道同时监控CPU、GPU和内存的功耗。调试的时候特别方便,一个命令就能看到各路功耗。

代码示例(读取INA3221数据):

// 伪代码:读取INA3221通道1的电流和电压
uint16_t read_ina3221_channel(uint8_t ch) {
    uint16_t shunt_voltage = i2c_read(INA3221_ADDR, SHUNT_VOLTAGE_REG + ch*2);
    uint16_t bus_voltage   = i2c_read(INA3221_ADDR, BUS_VOLTAGE_REG + ch*2);
    
    // 计算电流和功率
    float current_mA = shunt_voltage * 0.005;  // 取决于Shunt电阻值
    float power_mW   = current_mA * bus_voltage * 0.001;
    
    return power_mW;
}
个人经验: 功率监控芯片的采样率一般不高(几十Hz到几百Hz),适合看平均功耗。如果你想看瞬态电流尖峰,还是得上示波器+Shunt电阻。

3.2 芯片内部功耗传感器

板级测量只能看到芯片整体的功耗,但内部各个模块(CPU核、GPU、NPU、DSP)到底吃了多少电?这时候就得靠芯片内部的传感器了。

3.2.1 Thermal Diode(热敏二极管)

Thermal Diode其实不是直接测功耗的,它是测温度的。但温度变化和功耗有强相关性,所以可以用来估算功耗。

原理:二极管的正向压降随温度变化,大约是-2mV/°C。通过测量压降,反推温度。

在Exynos芯片里,每个主要模块都配了Thermal Diode。我记得Exynos 990有十几个温度传感器,分布在CPU、GPU、NPU、Modem等区域。

用法:

  • 先校准:在已知温度下记录电压值
  • 运行时读取电压,换算成温度
  • 根据温度变化率,估算功耗
注意: Thermal Diode的响应速度比较慢(毫秒级),而且受散热条件影响很大。你想想看,同样的功耗,冬天和夏天测出来的温度肯定不一样。所以它只能做定性分析,不能做精确的定量测量。

3.2.2 Power Monitor(片上功耗监控器)

这个才是真正的功耗传感器。三星从Exynos 9820开始,在芯片内部集成了Power Monitor模块。

工作原理:在每个电源域(Power Domain)的供电路径上,集成一个小的电流检测电路。它不像Shunt电阻那样需要外部元件,而是用片上MOSFET做电流镜,把电流复制一份出来,然后通过ADC量化。

优点:

  • 精度高:一般能做到±5%以内
  • 响应快:微秒级,能捕捉到瞬态功耗变化
  • 粒度细:每个电源域独立监控

我在Exynos 2100的项目中,就用Power Monitor抓到了GPU的一个功耗异常。当时跑一个游戏场景,GPU功耗突然飙到8W,但帧率没提升。后来发现是某个shader单元没正确进入低功耗模式。如果没有Power Monitor,这种问题根本发现不了。

读取Power Monitor的寄存器示例:

// 读取Exynos GPU Power Monitor寄存器
uint32_t gpu_power = readl(EXYNOS_PMU_BASE + GPU_POWER_MONITOR_REG);
// 寄存器格式:高16位是电流值,低16位是电压值
uint16_t current_raw = (gpu_power >> 16) & 0xFFFF;
uint16_t voltage_raw = gpu_power & 0xFFFF;

// 换算成实际值
float current_A = current_raw * 0.001;  // 单位:A
float voltage_V = voltage_raw * 0.001;  // 单位:V
float power_W   = current_A * voltage_V;

3.3 软件功耗统计

板级测量和芯片传感器都是硬件手段,但很多时候我们没法接示波器,也没法读寄存器。比如用户手里的手机,你怎么测?这时候就得靠软件了。

3.3.1 BatteryStats

Android系统里的BatteryStats,说白了就是记录每个应用、每个硬件模块用了多少电。它基于一个简单的模型:

  • CPU:根据运行时间和频率,查表得到功耗
  • 屏幕:根据亮度和时间,查表得到功耗
  • WiFi/蜂窝:根据收发数据量和时间,查表得到功耗

嗯,这里要泼一盆冷水:BatteryStats的精度其实不高。我做过对比测试,同一个场景,BatteryStats报的功耗和板级实测值能差30%以上。

为什么?因为它的功耗模型是固定的,但实际芯片的功耗受温度、制程偏差、具体 workload 的影响很大。你想想看,同一个CPU频率,跑整数运算和浮点运算的功耗能差一倍,但BatteryStats只按频率查表,怎么可能准?

不过,BatteryStats有一个好处:它能告诉你「相对」的功耗分布。比如某个App占了50%的功耗,那它大概率就是耗电大户。用来做问题定位,还是很有价值的。

3.3.2 PowerProfile

PowerProfile是Android系统里的功耗配置文件,存在/system/framework/framework-res.apk里。它定义了各个硬件模块在不同状态下的功耗值。

举个例子:

<?xml version="1.0" encoding="utf-8"?>
<device name="Android">
    <item name="screen.on">200</item>
    <item name="screen.full">800</item>
    <item name="wifi.active">100</item>
    <item name="wifi.scan">200</item>
    <item name="cpu.speeds">[200000, 500000, 1000000, 1500000]</item>
    <item name="cpu.active">[50, 100, 200, 400]</item>
</device>

这个文件里的数值,单位是mA(毫安)。系统根据这些值,结合硬件使用时间,算出总功耗。

我在三星的时候,负责过Exynos 990的PowerProfile校准。说实话,这是个苦差事。你得在几十种场景下实测功耗,然后反推每个模块的系数。而且不同批次芯片的功耗有差异,还得取平均值。

技巧: 如果你发现BatteryStats报的功耗和实际偏差很大,可以检查一下PowerProfile里的数值是否准确。我见过有些手机厂商直接复制公版数据,结果偏差30%以上。

3.4 三种方法的对比

好了,三种方法都讲完了。我做个总结对比:

方法 精度 响应速度 粒度 适用场景
Shunt电阻法 ±1%~5% 纳秒级(示波器) 板级 实验室基准测量、瞬态分析
功率监控芯片 ±1%~3% 毫秒级 板级/模块级 长时间监控、自动化测试
Thermal Diode ±10%~20% 毫秒级 模块级 温度保护、功耗趋势分析
Power Monitor ±5% 微秒级 电源域级 芯片内部功耗分析、调优
BatteryStats ±20%~30% 秒级 应用级 用户场景功耗分析

我个人建议的实践流程是:

  1. 先用Shunt电阻法或功率监控芯片,拿到板级基准功耗
  2. 再用Power Monitor,定位到具体哪个模块耗电
  3. 最后用BatteryStats,验证优化效果在用户场景下的表现

这三步走下来,功耗问题基本无处遁形。下一章,咱们就讲讲怎么用这些工具,去抓Exynos芯片里的「电老虎」。