Linux内核电源管理全解析
1. 引言
随着移动设备功能日益复杂,消费者既期望设备具备高性能,又希望其电池续航能力强。然而,高性能和节能是相互矛盾的概念,因此需要电源管理来平衡两者。Linux内核提供了多种电源管理功能,从短暂空闲时的节能到系统闲置时进入睡眠状态,都能有效降低功耗。
2. 技术要求
为了更好地理解Linux内核电源管理,需要具备以下技术要求:
- 基本的电气知识
- 基本的C编程技能
- 良好的计算机架构知识
- 可从https://github.com/torvalds/linux获取的Linux内核4.19源代码
3. Linux系统电源管理概念
电源管理(PM)旨在尽可能降低功耗,操作系统需处理两种类型的电源管理:设备电源管理和系统电源管理。
3.1 设备电源管理
设备电源管理是针对特定设备的,允许设备在系统运行时进入低功耗状态。例如,不打字时关闭键盘背光灯。它也被称为运行时电源管理(Runtime Power Management),可手动触发,也可在设备闲置一段时间后自动进行。
3.2 系统电源管理(睡眠状态)
系统电源管理使平台进入全系统的低功耗状态,即睡眠状态。系统可根据平台能力和唤醒延迟进入不同的低功耗状态,如笔记本合盖、手机息屏或电池电量低时。这些状态通常会在系统断电前保存运行状态,恢复供电后再恢复,避免了完全关机和启动的过程。
系统PM和运行时PM虽然处理不同的闲置管理场景,但两者都很重要,应视为互补的。
3.3 运行时电源管理
运行时电源管理是Linux PM的一部分,可在不使整个系统进入低功耗状态的情况下管理单个设备的电源。在系统运行时,通过动态改变设备属性来调整功耗,因此也称为动态电源管理。
3.4 动态电源管理接口
除了驱动开发者可在设备驱动中实现的每设备电源管理功能外,Linux内核还提供了用户空间接口来添加、删除或修改电源策略,常见的有:
- CPU Idle:在CPU无任务执行时管理其功耗。
- CPUFreq:根据系统负载动态调整CPU的电压和频率。
- Thermal:根据系统预定义区域(通常靠近CPU)的温度调整电源属性。
3.4.1 CPU Idle
当逻辑CPU无任务执行时,可进入特定状态以节省电源。CPU Idle是管理空闲线程的框架,有多个空闲级别(C状态),从C0(正常运行模式)开始,C值越大,睡眠模式越深,唤醒所需时间越长。每个空闲状态由退出延迟、功耗和目标驻留时间三个特征描述。
CPU Idle驱动是平台特定的,Linux内核期望CPU驱动最多支持10个状态,但实际数量取决于CPU硬件。状态选择由 governors 管理的策略决定,常见的 governors 有 ladder(适用于基于周期性定时器的系统)和 menu(适用于无定时器系统)。
可以通过以下命令查看当前的 governor:
$ cat /sys/devices/system/cpu/cpuidle/current_governor_ro
在ARM平台上,空闲状态可在设备树中描述。与其他电源管理框架不同,CPU Idle无需用户干预即可工作。此外,还有类似的CPU Hotplug框架,可在运行时动态启用或禁用CPU,例如:
# 禁用CPU #2
# echo 0 > /sys/devices/system/cpu/cpu2/online
# 确认CPU #2已禁用
# grep processor /proc/cpuinfo
# 启用CPU #2
# echo 1 > /sys/devices/system/cpu/cpu2/online
3.4.2 CPUfreq(动态电压和频率缩放,DVFS)
CPUfreq框架可根据约束、需求、用户偏好等因素动态选择CPU的电压和频率。它使用操作性能点(OPPs)的概念,用{频率, 电压}元组表示系统的性能状态。OPPs可在设备树中描述。
CPUfreq也使用 governors 实现缩放算法,常见的 governors 有:
| Governor名称 | 特点 |
| ---- | ---- |
| ondemand | 积极调整CPU频率以提供适当的处理能力,并在必要时将频率重置为最大值 |
| conservative | 与ondemand类似,但增加OPPs的方式较温和,不会直接从最低OPPs跳到最高 |
| performance | 始终选择最高频率的OPPs,优先考虑性能 |
| powersave | 始终选择最低频率的OPPs,优先考虑节能 |
| userspace | 允许用户通过/sys/devices/system/cpu/cpuX/cpufreq/scaling_available_frequencies中的值设置所需的OPPs |
| schedutil | 作为调度器的一部分,可访问调度器数据结构,获取更准确的系统负载统计信息,以选择合适的OPPs |
可以通过以下命令查看和设置相关信息:
# 查看可用的governors
$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors
# 查看当前的governor
$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# 设置governor
$ echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# 查看当前的OPPs(频率,单位kHz)
$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
# 查看支持的OPPs(频率,单位kHz)
$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies
# 更改OPPs
$ echo 275000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
3.4.3 Thermal
Thermal框架用于监控系统温度,根据温度阈值有专门的配置文件。它与冷却设备协同工作,控制和限制过热。该框架使用以下概念:
- 热区(Thermal zones):需要监控温度的硬件区域。
- 热传感器(Thermal sensors):用于测量温度的组件。
- 冷却设备(Cooling devices):提供功耗控制,有被动冷却(如使用DVFS调节设备性能)和主动冷却(如启动风扇)两种方式。
- 触发点(Trip points):建议进行冷却操作的关键温度阈值。
- Governors:根据某些标准选择最佳冷却方式的算法。
- 冷却映射(Cooling maps):描述触发点和冷却设备之间的关联。
Thermal框架可分为热区、热governor、热冷却和热核心四个部分,可在用户空间的/sys/class/thermal/目录下进行管理:
$ ls /sys/class/thermal/
以下是Thermal框架工作流程的mermaid流程图:
graph LR
A[热传感器测量温度] --> B[热区驱动报告温度和触发点]
B --> C[热governor根据算法选择冷却方式]
C --> D[冷却设备执行冷却操作]
4. 系统电源管理睡眠状态
系统电源管理旨在使整个系统进入低功耗状态,以节省能源并保持较低的响应延迟。系统可进入的睡眠状态取决于平台,常见的有四种:
4.1 挂起到空闲(冻结,Suspend to idle / freeze)
这是最基本和轻量级的状态,纯软件驱动。通过冻结用户空间任务和将I/O设备置于低功耗状态,使CPU尽可能处于最深的空闲状态。可使用以下命令使系统进入该状态:
$ echo freeze > /sys/power/state
该状态总是受支持(前提是设置了CONFIG_SUSPEND内核配置选项),可用于不支持其他睡眠状态的平台,也可与挂起到RAM结合使用以减少恢复延迟。
4.2 开机待机(Standby / Power-on suspend)
除了冻结用户空间和将I/O设备置于低功耗状态外,还会关闭所有非引导CPU。使用以下命令使系统进入该状态(前提是平台支持):
$ echo standby > /sys/power/state
该状态比冻结状态更节能,但恢复延迟通常更长。
4.3 挂起到RAM(Suspend to ram / mem)
将系统所有组件置于低功耗状态,关闭所有CPU并使内存进入自刷新状态以保存内容。使用以下命令使系统进入该状态:
# echo mem > /sys/power/state
实际操作由/sys/power/mem_sleep文件控制,该文件列出了系统可进入的模式,常见的有:
- s2idle:等同于挂起到空闲,始终可用。
- shallow:等同于开机待机,取决于平台支持。
- deep:真正的挂起到RAM状态,取决于平台支持。
可通过以下命令查询和设置模式:
$ cat /sys/power/mem_sleep
# 选择其他模式
$ echo deep > /sys/power/mem_sleep
可以使用系统上支持唤醒闹钟功能的RTC进行测试:
# 查看是否设置闹钟
$ cat /sys/class/rtc/rtc0/wakealarm
# 设置20秒后唤醒
# echo +20 > /sys/class/rtc/rtc0/wakealarm
# 挂起到RAM
# echo mem > /sys/power/state
4.4 挂起到磁盘(休眠,Suspend to disk / hibernation)
该状态可实现最大程度的节能,通过关闭系统大部分组件,包括内存,并将内存内容写入持久存储介质(通常是磁盘)。恢复时,从磁盘读取内容并启动系统。使用以下命令使系统进入该状态:
$ echo disk > /sys/power/state
内存状态写入磁盘后,具体操作由/sys/power/disk文件控制,可能的操作有:
- platform:自定义和特定于平台的操作,可能需要固件(BIOS)干预。
- shutdown:关闭系统。
- reboot:重启系统(常用于诊断)。
- suspend:使系统进入之前通过mem_sleep文件选择的睡眠状态。
- test_resume:用于系统恢复诊断。
可通过以下命令查询和设置操作:
$ cat /sys/power/disk
# 选择操作
$ echo reboot > /sys/power/disk
为了检查休眠是否正常工作,可在重启模式下进行测试:
$ echo reboot > /sys/power/disk
# echo disk > /sys/power/state
以下是系统电源管理睡眠状态的总结表格:
| 睡眠状态 | 描述 | 命令 | 特点 |
| ---- | ---- | ---- | ---- |
| 挂起到空闲(冻结) | 纯软件驱动,冻结用户空间和I/O设备 |
echo freeze > /sys/power/state
| 基本、轻量级,始终支持 |
| 开机待机 | 冻结用户空间、I/O设备,关闭非引导CPU |
echo standby > /sys/power/state
| 比冻结更节能,恢复延迟稍长 |
| 挂起到RAM | 关闭CPU,内存自刷新保存内容 |
echo mem > /sys/power/state
| 恢复较快,取决于平台支持不同模式 |
| 挂起到磁盘(休眠) | 关闭系统大部分组件,保存内存到磁盘 |
echo disk > /sys/power/state
| 节能最多,恢复时间长 |
综上所述,Linux内核提供了丰富的电源管理功能,通过合理配置和使用这些功能,可以在保证系统性能的同时,最大程度地降低功耗,延长设备的电池续航时间。
5. 设备驱动中添加电源管理功能
在设备驱动中添加电源管理功能,能够让设备更好地参与到系统的电源管理中,实现节能的目的。下面将详细介绍如何在设备驱动中添加电源管理功能。
5.1 理解设备电源管理需求
在添加电源管理功能之前,需要明确设备的电源管理需求。不同的设备在不同的工作场景下,对电源的需求是不同的。例如,键盘在不使用时可以进入低功耗状态,而硬盘在读写数据时需要保持较高的性能。因此,需要根据设备的特点和使用场景,确定合适的低功耗状态和唤醒条件。
5.2 实现设备的低功耗状态
在设备驱动中,需要实现设备的低功耗状态。这通常涉及到将设备的某些功能模块关闭或降低其工作频率,以减少功耗。例如,对于一个USB设备,可以在设备空闲时将其控制器置于低功耗模式。
以下是一个简单的示例代码,展示了如何在设备驱动中实现低功耗状态:
#include <linux/device.h>
// 设备进入低功耗状态的函数
static int my_device_suspend(struct device *dev)
{
// 关闭设备的某些功能模块
// ...
return 0;
}
// 设备从低功耗状态恢复的函数
static int my_device_resume(struct device *dev)
{
// 开启设备的某些功能模块
// ...
return 0;
}
// 定义设备的电源管理操作结构体
static SIMPLE_DEV_PM_OPS(my_device_pm_ops, my_device_suspend, my_device_resume);
// 在设备驱动初始化时注册电源管理操作
static int __init my_device_init(void)
{
// 注册设备驱动
// ...
// 设置设备的电源管理操作
dev_pm_ops(dev, &my_device_pm_ops);
return 0;
}
module_init(my_device_init);
5.3 处理设备的唤醒事件
在设备处于低功耗状态时,需要能够处理唤醒事件,使设备恢复到正常工作状态。唤醒事件可以是外部中断、定时器超时等。在设备驱动中,需要实现相应的中断处理函数或定时器回调函数,以处理唤醒事件。
以下是一个处理外部中断唤醒事件的示例代码:
#include <linux/interrupt.h>
// 中断处理函数
static irqreturn_t my_device_irq_handler(int irq, void *dev_id)
{
// 处理唤醒事件
// ...
// 唤醒设备
device_wakeup(dev);
return IRQ_HANDLED;
}
// 在设备驱动初始化时注册中断处理函数
static int __init my_device_init(void)
{
// 注册中断处理函数
request_irq(irq, my_device_irq_handler, IRQF_SHARED, "my_device", dev);
return 0;
}
module_init(my_device_init);
5.4 与系统电源管理的集成
设备驱动的电源管理功能需要与系统的电源管理机制进行集成。这意味着设备驱动需要响应系统的电源管理请求,如系统进入睡眠状态或从睡眠状态恢复。在设备驱动中,需要实现相应的回调函数,以处理系统的电源管理请求。
以下是一个与系统电源管理集成的示例代码:
#include <linux/pm_runtime.h>
// 设备驱动的电源管理回调函数
static int my_device_pm_runtime_suspend(struct device *dev)
{
// 设备进入低功耗状态
// ...
return 0;
}
static int my_device_pm_runtime_resume(struct device *dev)
{
// 设备从低功耗状态恢复
// ...
return 0;
}
// 定义设备驱动的电源管理回调结构体
static const struct dev_pm_ops my_device_pm_runtime_ops = {
.runtime_suspend = my_device_pm_runtime_suspend,
.runtime_resume = my_device_pm_runtime_resume,
};
// 在设备驱动初始化时注册电源管理回调
static int __init my_device_init(void)
{
// 注册设备驱动
// ...
// 设置设备驱动的电源管理回调
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
dev_pm_set_driver_ops(dev, &my_device_pm_runtime_ops);
return 0;
}
module_init(my_device_init);
5.5 测试和验证
在完成设备驱动的电源管理功能开发后,需要进行测试和验证。可以使用一些工具和方法来测试设备的功耗和唤醒功能,确保设备在不同的电源管理状态下都能正常工作。例如,可以使用功耗测试仪来测量设备在不同状态下的功耗,使用调试工具来验证设备的唤醒功能是否正常。
6. 系统唤醒源
系统唤醒源是指能够将系统从低功耗状态唤醒的事件或设备。了解系统唤醒源对于优化系统的电源管理非常重要,因为合理配置唤醒源可以减少不必要的唤醒,从而降低系统的功耗。
6.1 常见的系统唤醒源
常见的系统唤醒源包括:
-
定时器
:定时器可以设置在特定的时间唤醒系统,例如定时执行任务或更新数据。
-
外部中断
:外部设备的中断信号可以唤醒系统,例如键盘按键、鼠标移动等。
-
网络事件
:网络连接的变化或收到网络数据包可以唤醒系统,例如收到电子邮件或即时消息。
-
传感器事件
:传感器检测到特定的事件可以唤醒系统,例如温度变化、光线变化等。
6.2 配置系统唤醒源
在Linux系统中,可以通过sysfs接口来配置系统唤醒源。以下是一些常见的配置步骤:
6.2.1 查看可用的唤醒源
可以使用以下命令查看系统中可用的唤醒源:
$ cat /sys/power/wakeup
该命令会列出所有可用的唤醒源,每个唤醒源后面会显示其当前的状态(enabled或disabled)。
6.2.2 启用或禁用唤醒源
可以使用以下命令来启用或禁用某个唤醒源:
# 启用唤醒源
$ echo enabled > /sys/class/rtc/rtc0/wakealarm/wakeup
# 禁用唤醒源
$ echo disabled > /sys/class/rtc/rtc0/wakealarm/wakeup
6.2.3 设置唤醒时间
对于定时器唤醒源,可以设置唤醒时间。例如,使用RTC(实时时钟)设置唤醒时间:
# 设置唤醒时间为20秒后
$ echo +20 > /sys/class/rtc/rtc0/wakealarm
6.3 优化系统唤醒源
为了降低系统的功耗,需要优化系统唤醒源的配置。以下是一些优化建议:
-
减少不必要的唤醒源
:禁用那些不需要的唤醒源,避免系统被不必要的事件唤醒。
-
合理设置唤醒时间
:对于定时器唤醒源,合理设置唤醒时间,避免过于频繁的唤醒。
-
使用低功耗唤醒机制
:对于一些需要频繁唤醒的设备,可以使用低功耗唤醒机制,例如使用中断唤醒而不是轮询。
以下是一个优化系统唤醒源的mermaid流程图:
graph LR
A[查看可用唤醒源] --> B[禁用不必要的唤醒源]
B --> C[合理设置唤醒时间]
C --> D[使用低功耗唤醒机制]
D --> E[测试和验证]
7. 总结
Linux内核的电源管理功能为我们提供了丰富的手段来降低系统的功耗,延长设备的电池续航时间。通过合理配置系统电源管理睡眠状态、在设备驱动中添加电源管理功能以及优化系统唤醒源,可以在保证系统性能的同时,实现节能的目标。
在实际应用中,需要根据设备的特点和使用场景,选择合适的电源管理策略。同时,需要不断地测试和优化,以确保系统的电源管理功能能够达到最佳效果。希望本文能够帮助你更好地理解和使用Linux内核的电源管理功能。
通过以下表格,我们可以再次回顾不同电源管理功能的特点和操作方法:
| 功能 | 特点 | 操作方法 |
| ---- | ---- | ---- |
| CPU Idle | 管理CPU空闲状态,有多个C状态 | 通过/sys/devices/system/cpu/cpuidle/目录下的文件查看和配置 |
| CPUfreq | 动态调整CPU电压和频率 | 通过/sys/devices/system/cpu/cpuX/cpufreq/目录下的文件查看和配置 |
| Thermal | 监控系统温度,控制过热 | 通过/sys/class/thermal/目录下的文件管理 |
| 系统电源管理睡眠状态 | 使系统进入低功耗状态 | 通过/sys/power/state文件设置 |
| 设备驱动电源管理 | 让设备参与系统电源管理 | 在设备驱动中实现低功耗状态、处理唤醒事件并与系统集成 |
| 系统唤醒源 | 唤醒系统的事件或设备 | 通过/sys/power/wakeup文件查看和配置 |


超级会员免费看
630

被折叠的 条评论
为什么被折叠?



