Android 功耗分析(底层篇)

最近在网上发现关于功耗分析系列的文章很少,介绍详细的更少,于是便想记录总结一下功耗分析的相关知识,有不对的地方希望大家多指出,互相学习。本系列分为底层篇和上层篇。

大概从基础知识,测试手法,以及案例分析三个方面着手。

一、基础知识

底层篇主要介绍底电流的调试与分析。首先我们要明确什么是底电流,什么是待机电流。

1.1、概念

底电流:指机器完全睡眠时的最低电流。

待机电流:是指机器在待机一段时间内的平均电流,通常需要插卡进行测试。

1.2、为什么要测试底电流

主要目的是评估设备在最低功耗状态下的能耗表现,对于电池供电的设备(如手机、可穿戴设备、IoT 设备),底电流直接影响设备在长时间非使用场景下的待机时长。

  • 测量底电流是评估产品功耗指标是否符合设计要求的关键步骤。
  • 通过实际测量与设计目标对比,发现并解决功耗异常问题
  • 底电流测试可以帮助开发者发现硬件设计中的电流泄漏问题,例如:
    • 元器件未完全关闭。
    • 电路设计不合理导致的静态电流消耗。
  • 通过逐步排查电路中的模块,找到并优化功耗"热点。

测量底电流的最终目的是确保设备在低功耗状态下的能耗最小化。它不仅有助于排查和优化硬件设计,还能验证系统功耗策略的有效性,并最终延长设备的续航时间。对于任何需要长待机时间的电池驱动设备,底电流测试是不可或缺的一步。

二、底电流调试方法以及工具

这里主要介绍高通平台的调试方法。

工具的话推荐使用Power Monitor测试电流,非常的简单好用。

Power monitor使用说明(非常不错).doc

2.1、首先要进行RF校准

射频QCN文件下载并进行射频校准。高通有专门的工具刷入机器里,因为QCN文件不下载射频不能正常工作,会引起漏电,继而引起底电流偏大。

2.2、排除其他因素

打开飞行模式,避免蓝牙、wifi、NFC、网络、FM等的一般影响。

关闭GPS,避免GPS对底电流的影响。

关闭自动旋转屏幕,排除sensor的影响。

关闭自动亮度,以及其他特效设置。

手动移除可以移除的所有外设以及驱动模块,例如:

lsmod

rmmod WLAN

2.3、进行待机测试

灭屏待机,连接power monitor 查看实时电流,分析机器是否进入睡眠状态,可以通过串口查看kernel日志,搜索关键字suspend entry查看是否进入睡眠。

2.4、分析kernel日志

kernel没有进入睡眠则查看是哪个模块引起的并有针对性分析相应模块。如果进入休眠电流还大,需要分析各个模块的clock有没有关闭。

2.5、抓取rpm dump日志进行分析

方法如下:

(1)ps_hold接地

在休眠状态下,接ps_hold到地少于200mS,机器会进入紧急下载状态,插入USB,QPST会自动得到memory dump,然后上传以下几个文件:

CODERAM.bin

MSGRAM.bin

DATARAM.bin

以及RPM_AAAAANAZR.elf(必须与机器的编译时间一致匹配的elf)

(2)改reset为download key

发这些命令改reset为download key:

bash 复制代码
 cd /sys/kernel/debug/spmi/spmi-0

 echo 0x844 > address

 echo 4 > count # cat data 00840 -- -- -- -- 0F 07 04 00

 echo 0x00 0x00 0x01 0x00 > data

 cat data 00840 -- -- -- -- 00 00 01 00

 echo 0x00 0x00 0x01 0x80 > data

 cat data 00840 -- -- -- -- 00 00 01 80 

然后长按下键,会进入download。之后抓取log方法同上

如果进不了download,需要确认

CONFIG_MSM_DLOAD_MODE=y

2.6、查看rmp_stats的状态

1、检查rpm_stats是否进入vdd min或者xo/no shutdown。使用下面的命令检查

rpm lower power mode count:

bash 复制代码
adb shell mount -t debugfs none /sys/kernel/debug

adb cat /sys/kernel/debug/rpm_stats

如果vmin的count是0,则表明设备从来没有进入vdd min(系统功耗最小化状态),non-zero则说明设备进入过vdd_min。

首先需要了解一下什么XO和VDD min

XO是XTAK Oscillator 石英晶体振荡器,XO提供RF平台BB(基带频率),WTR(射频收发器),NFC,GPS,FM所需的系统频率;XO shutdown即晶振关闭,这些传感器不工作。

VDD min指最小操作电压,即最低功耗模式。

如果XO shut down计数为零,VDD min计数不断增加,则已经进入了VDD min。

示例:

bash 复制代码
RPM Mode: xosd

count:0

time in last mode(msec):0

time since last mode(sec):794

actual last sleep(msec):0

RPM Mode:vmin

count:11

time in last mode(msec):0

time since last mode(sec):359

actual last sleep(msec):110000

或者检查以下RPM RAM转储的变量,以确定XO关闭和VDD最小化的计数
-- sleep_stats[0] --XO关闭计数(系统进入XO关闭的次数)
-- sleep_stats[1] --VDD最小化计数

注意:若系统进入VDD最小化状态,则只有VDD最小化计数会增加。VDD最小化是最低的功耗状态,包括了XO关闭。仅当系统未成功进入VDD最小化而进入XO关闭时,XO关闭计数才会增加

2、系统未进入VDD min怎么办?

如果系统未进入VDD min,则需要检查各个子系统休眠情况,通过查看子系统sleep count命令

cat /sys/power/system_sleep/stats

cat /sys/power/rpmh_stats/master_stats

能看到ADSP MPSS APSS等子系统休眠情况,如果sleep count未发生变化,则对应的子系统未进入休眠。

3、xo shutdown 和Vdd min计数最小化后就一定表示系统功耗正常了么?

答案是不一定,若终端成功进入VDD最小化后,基底电流仍大于预期值,则可以得出结论,终端中存在一个或多个泄漏源计入总电流消耗中。泄漏可能有多处来源,例如

4、可以dump出来完整详细的gpio/clk/pmic信息,排除休眠时候的状态异常。

2.7、查看modem是否休眠

可以通过检测TCXO引脚的状态来确定modem端是否休眠,在modem端tlmm_bsp.c文件下比对各个GPIO有无设置错误继而引起漏电。另外,sleep_target.c文件也值得分析。

三、待机电流优化

3.1、adb命令抓取日志

在优化前,我们需要通过日志来确定导致功耗偏高的原因。可以通过一些adb命令进行排查。

bash 复制代码
adb logcat -v time > YearMounthDayHourMinute_logcat.txt //main log

adb logcat -v time -b events > YearMounthDayHourMinute_logcat_event.txt //event log

adb logcat -v time -b radio > YearMounthDayHourMinute_logcat_radio.txt //radio log

adb shell dmesg > YearMounthDayHourMinute_dmesg.txt //kernel log

抓取对应的日志

bash 复制代码
adb shell mount -t debugfs none /sys/kernel/debug 

用于将 debugfs 文件系统挂载到 Android 设备的 /sys/kernel/debug 目录,允许开发者访问内核的调试信息、性能数据和其他调试工具

bash 复制代码
adb shell "echo 8 > /proc/sys/kernel/printk"

将内核的日志级别设置为 8,使得内核输出最详细的调试信息

除了上述的方法,我们也可以使用如下命令来打开指定文件的kernel log(以qpnp-adc-tm.c和qpnp-adc-common.c为例):

bash 复制代码
adb shell "echo 'file qpnp-adc-tm.c +p' > /sys/kernel/debug/dynamic_debug/control"

adb shell "echo 'file qpnp-adc-common.c +p' > /sys/kernel/debug/dynamic_debug/control"

我们也可以为指定的函数开启log

以qpnpint_handle_irq为例:

adb shell "echo 'func qpnpint_handle_irq +p' > /sys/kernel/debug/dynamic_debug/control" 

3.2、Top命令

使用

adb shell 
top

在待机的时候可以通过top命令查看是否有应用一直占用cpu,如果未主动开启该应用,但是却显示一直占用cpu,那么该应用的行为就存在异常。

3.3、查看唤醒源以及wakelock持锁

在调试wakeup的时候我们可以使用一下命令开启一些debug日志的信息。

(1)调试命令

3.3.1

mount -t debugfs none /sys/kernel/debug  

echo 1 > /sys/kernel/debug/clk/debug_suspend  

用于启用内核中时钟管理的调试功能,主要帮助开发人员排查设备挂起/恢复过程中与时钟相关的问题,如底电流偏高、时钟未正确关闭等

3.3.2

echo 1 > /sys/module/msm_show_resume_irq/parameters/debug_mask 

用于在高通平台上启用中断(IRQ)唤醒调试功能,帮助开发者分析设备从挂起状态恢复过程中与中断相关的问题。这是调试底电流偏高、功耗问题或唤醒异常的重要工具之一,但需注意对性能和存储的影响,调试完成后建议关闭该功能。

3.3.3

echo 4 > /sys/module/wakelock/parameters/debug_mask

用于在 Android 内核中启用 wakelock 模块 的高级调试功能,记录唤醒锁的获取和释放情况

3.3.4

echo 1 > /sys/module/lpm_levels/parameters/debug_mask 

用于启用低功耗模式(LPM)模块的基本调试日志输出

3.3.5

echo 0x16 > /sys/module/smd/parameters/debug_mask  

用于启用高通平台 SMD(共享内存驱动) 的调试日志,主要用于分析设备间通信问题和优化功耗管理

(2)wakelock

首先介绍一下什么是wakelock:

他是Android 系统中的一种机制,用于控制设备的电源管理。它可以阻止设备进入休眠状态,从而确保某些任务能够在特定条件下完成。(关于wakelock的分类,设置过程以及用法,debug将在上层篇详细介绍。)这里只做简单的了解。

一般可以通过待机后获取bugreport.txt来看kernel的wakelock,搜索关键字:all kernel

获取bugreport的命令如下:

adb bugreport > bugreport.txt

1、wakeup_sources

在待机日志中,kernel层的wakelock和userspace的wakelock都有可能阻止系统休眠,所有的wakeup_sources均保存在sys节点/sys/kernel/debug/wakeup_sources里面。(该文件记录了wake sources的详细调试信息),这个文件包含了以下的信息:

a、the total amount of time a wakeup source has prevented suspend

当系统尝试进入休眠(suspend)时,某些唤醒源(如网络、传感器、应用程序等)可能会阻止这一过程

b、the amount of time a wakelock has been active since the last activation etc. The unit of time is milliseconds

每个唤醒源通常通过 wakelock(唤醒锁)机制防止系统休眠,表示唤醒锁最近一次被激活后,持续保持活跃的时间

2、active_since

active_since的值可以用来确认wakelock是否正在阻止休眠。如果该值不是零,那么这个wakelock正在工作并且阻止休眠。

3、获取wakeup_source文件
bash 复制代码
adb root
adb shell
cat /sys/kernel/debug/wakeup_sources > /data/wakeup_sources.txt

adb pull /data/wakeup_sources.txt

查看pull出来的wakeup sources.txt文件,查看active_since 不为0的项,即为阻止系统休眠的。

下面是wakeup sources日志中的一些解释:

|----------------------|---------------------------------------------------------------------------|
| 字段 | 描述 |
| event_count | 被信号唤醒的次数 |
| wakeup_count | 中止suspend的次数 |
| expire_count | 对应wakeup source超时的次数 |
| active_since | 上一次还活跃的时间点.时间单位跟kernel log前缀时间是一样(kernel单调递增时间) |
| total_time | 对应wakeup source活跃的总时长 |
| max_time | 对应的wakeup source持续活跃最长的一次时间 |
| last_change | 上一次wakeup source变化的时间(从持锁到释放or释放到持锁),时间单位跟kernel log前缀时间是一样(kernel单调递增时间) |
| prevent_suspend_time | 对应wakeup source阻止进入autosleep的总累加时间 |

4、power:wakeup_source_activate 和 power:wakeup_source_deactivate events

当一个wakeup_sources被acquire和relerase的时候,通过启用 power:wakeup_source_activatepower:wakeup_source_deactivate 事件并记录到 trace buffer,可以记录wakeup source被driver使用的频率。

下面是开启该功能的方法。

bash 复制代码
echo "power:wakeup_source_activate power:wakeup_source_deactivate" > /sys/kernel/debug/tracing/set_event

The power:wakeup_source_activate and power:wakeup_source_deactivate events are written to the trace buffer any time a wakeup source is acquired or released and it can provide information on how often a wakeup source is being used by a driver. To enable these events, you can enable following: echo "power:wakeup_source_activate power:wakeup_source_deactivate" > /sys/kernel/debug/tracing/set_event Once the above done, the traces will be present in /sys/kernel/debug/tracing/trace.

解释如下:

  • 当唤醒源被某个驱动程序或模块 激活(acquired)释放(released) 时,内核会自动生成两个事件:

    • power:wakeup_source_activate:表示唤醒源被激活的事件。
    • power:wakeup_source_deactivate:表示唤醒源被释放的事件。
  • 这些事件会被记录到 trace buffer(内核调试追踪缓冲区)中,通过记录这些事件,可以统计每个唤醒源被驱动使用的频率,需要通过特定命令启用这些事件的记录功能

  • echo "power:wakeup_source_activate power:wakeup_source_deactivate" > /sys/kernel/debug/tracing/set_event

  • 启用事件后,所有记录的信息都会被保存到文件 /sys/kernel/debug/tracing/trace 中。

  • 作用

    通过查看该文件,可以实时了解唤醒源的活动记录。

3.4、powertop

PowerTOP 是一个由 Intel 开发的 Linux 工具,用于诊断电量消耗和电源管理的问题。它可以帮助用户识别和优化系统中的电量消耗,从而延长笔记本电脑的电池寿命。PowerTOP 不仅可以作为一个诊断工具,还可以通过其交互模式启用各种电源管理设置,监控进程并展示电量消耗特别高的应用程序。

使用sudo apt install powertop 就可以安装了。

获取powertop log的方法:

  1. 通过USB连接手机到电脑

  2. adb shell,然后执行如下命令:

sleep 10 && /data/powertop [-r] -d -t 30 > /data/powertop.log &

  1. 拔掉USB线,等待10秒后开始功耗测试

  2. 插上USB

  3. adb pull /data/powertop.log

3.5、检查系统的alarm

可以使用命令得到android alarms 和statistics

adb dumpsys alarm > alarms.txt

enable android debug message in logcat:

setprop persist.alarm.debug 1

3.6、检查kernel timer

可以使用 /proc/timer_stats 这个 sys 节点来获取内核中定时器的统计数据,通过特定的命令,用户能够分析定时器的行为,以优化性能或解决问题。

echo 0 > /proc/timer_stats && sleep 10 && echo 1 > /proc/timer_stats && sleep 30 && cat /proc/timer_stats > /data/timer_stats & 

3.7、cpu freq log

(1)、打开cpu change log,启动调试日志命令如下

mount -t debugfs none /sys/kernel/debug  

cd /sys/kernel/debug 

echo -n 'file acpuclock-8x60.c +p' > dynamic_debug/control 

echo -n 'file acpuclock-krait.c +p' > dynamic_debug/control

(2)、用命令查看cpu 频率状态

cat /sys/devices/system/cpu/cpu0/cpufreq/stats 

cat /sys/devices/system/cpu/cpu1/cpufreq/stats 

cat /sys/devices/system/cpu/cpu2/cpufreq/stats 

cat /sys/devices/system/cpu/cpu3/cpufreq/stats

(3)、锁定cpu的频率

echo the same freq to following sys mode will lock cpu freq to the setting freq. 

/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq 

/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq

未完待续。。

参考链接:

底电流分析-CSDN博客

android 功耗(1)---android 功耗分析方法和优化 - yooooooo - 博客园

高通平台底电流调节心得 - yooooooo - 博客园

高通平台底电流调节心得_高通底电调试-CSDN博客

相关推荐
大白要努力!1 小时前
Android opencv使用Core.hconcat 进行图像拼接
android·opencv
天空中的野鸟2 小时前
Android音频采集
android·音视频
曙曙学编程3 小时前
初级数据结构——树
android·java·数据结构
闲暇部落5 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
诸神黄昏EX7 小时前
Android 分区相关介绍
android
大白要努力!8 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee8 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
Winston Wood9 小时前
Perfetto学习大全
android·性能优化·perfetto
Dnelic-12 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记