Linux电源管理STR以及STD详解

1. 电源状态

ACPI(Advanced Configuration and Power Interface)在运行中有以下几种模式:

  • S0 正常。
  • S1 CPU停止工作。唤醒时间:0秒。
  • S2 CPU关闭。唤醒时间:0.1秒。
  • S3 除了内存外的部件都停止工作。唤醒时间:0.5秒。
  • S4 内存信息写入硬盘,所有部件停止工作。唤醒时间:30秒。(休眠状态)
  • S5 关闭。

S1 =>Standby:

即指说系统处于低电源供应状态,在 windows or BIOS 中可设定萤幕讯号输出关闭、 硬碟停止运转进入待命状态、电源灯号处于闪烁状态。此时动一动滑鼠、按键盘任一键均可叫醒电脑。

S2 =>Power Standby:

和 S1 几乎是一样。

S3 =>Suspend to RAM:

即是把 windows 现在存在记忆体中的所有资料保存不动,然后进入「假关机」。此时除了记忆体需要电源来保持资料以外,其它的设备、装置全部停止供电。也就是说,理论上可以把 CPU, PCI, AGP device 拿掉又插回去,电脑也可能正常完成开机及运作,只要不动到记忆体和电源的部份。这时只剩下电源灯号一闪一闪的,其它和关机没什么两样。(电源供应器的风扇也停止运转喔)重新开新后,电脑只是把记忆体的资料完整性确认后,即立刻会回到你进 S3 前的画面。记得有人试过,在烧录中启动 S3 ,CDRW 还会自动启动 Just-Link ,等你回復后它又自动继续烧。(听说而以,自己没试过)。

S4 =>Suspend to Disk:

即是把 windows 记忆体中的资料完整的存在硬碟中。等开机时就直接从存这些资料的地方直接完整的读到记忆体,不需要跑一堆应用程式。使用这种模式的话,硬碟一定要腾出一个完整的连续空间。Windows 98/SE 必需要用软体去製作一个大档案或是一个磁区来提供 win98/SE 执行 S4 这功能,WinME/2000/XP 本身就有製作一个大档案来给 S4 功能用(在电源管理中有一个启动休眠,就是这个啦) 。在启动后,在 C: 下会看到一个和你电脑现有记忆体大小一样的大档案。

S5 =>Shutdown:
彻底关机掉电

2. Suspend

Linux内核支持多种类型睡眠状态,目前存在四种模式:suspend to idle(freeze)、power-on standby(standb)、suspend to ram(memory;STR)和suspend to disk(hibernate)。分别对应ACPI状态的S0、S1、S3和S4状态。

  • Suspend-To-Idle
    此状态包括frozen processes+suspended devices+idle processors,具有轻量化的特点;并且相对于相对于Idle状态能节省更多的功耗,因为此时的用户空间被冻结且I/O设备进入了低功耗状态。

    相对于Suspend-To-RAM它具有低延时的优势。

  • Power-On Suspend
    此状态简称standby状态,包括frozen processes+suspended devices+offline nonboot CPUs+suspend low-level system,对CPU的处理更近一步。所以相对于Suspend-To-Idle节省了更多的功耗,但是由于需要恢复CPU和一些底层功能也花费了更多的时间。

  • Suspend-to-RAM
    挂起到内存,简称待机。计算机将目前的运行状态等数据存放在内存,关闭硬盘、外设等设备,进入等待状态。此时内存仍然需要电力维持其数据,但整机耗电很少。恢复时计算机从内存读出数据,回到挂起前的状态,恢复速度较快。对 DDR的耗电情况进行优化是S3性能的关键,大多数手持设备都是用S3待机。此状态下计算机会冻结所有的活动并将当前工作状态保存到RAM中,然后关闭屏幕进入低功耗模式,通常睡眠和唤醒需要几秒。此状态使所有的设备进入低功耗状态,仅保留RAM自刷新。所有的设备和系统状态都保存在RAM中,所有外设被挂起。

  • Suspend-to-disk
    此状态是最省功耗的模式,简称休眠。相对Suspend-to-RAM能节省更多功耗的原因是数据会被写入磁盘中,RAM也可以被关闭。但是这也导致了,更多的恢复延时,在resume的时候读回到RAM,然后在进行系统和设备状态恢复工作。把运行状态等数据存放在硬盘上某个文件或者某个特定的区域,关闭硬盘、外设等设备,进入关机状态。此时计算机完全关闭,不耗电。恢复时计算机从休眠文件/分区中读出数据,回到休眠前的状态,恢复速度较慢。

在车载领域中,STR和STD是用到的最多的,尤其是性能和芯片能力足够时,STR是相对较优的低功耗方案,与STD相比STR复归速度更快,省去了像STD一样制作镜像和读取镜像的耗时。

1.3 PM Subsystem

1.3.1 PM接口

1.3.1.1 sys/power/state

代码流程可以先从接口开始看起,在内核代码/kernel/linux/v4.14/kernel/power/main.c这一文件中,提供了用户对电源控制的操作接口。

首先看接口定义:

power_attr(state);

#define power_attr(_name) \
static struct kobj_attribute _name##_attr = {
     
     	\
	.attr	= {
     
     				\
		.name = __stringify(_name),	\
		.mode = 0644,			\
	},					\
	.show	= _name##_show,			\
	.store	= _name##_store,		\
}

根据以上内容,系统通过sysfs创建出.show和.store这两个接口函数。

1. state_show:

state_show函数可以通过命令台命令cat /sys/power/state来查看设备支持的电源状态。

static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
			  char *buf)
{
   
   
	char *s = buf;
#ifdef CONFIG_SUSPEND
	suspend_state_t i;

	for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++)
		if (pm_states[i])
			s += sprintf(s,"%s ", pm_states[i]);

#endif
	if (hibernation_available())
		s += sprintf(s, "disk ");
	if (s != buf)
		/* convert the last space to a newline */
		*(s-1) = '\n';
	return (s - buf);
}

2. state_store:

state_store这一函数就是电源状态控制的入口函数,在控制台使用echo [*] > /sys/power/state命令来实现不同的suspend状态。

  • echo freeze > /sys/power/state (PM_SUSPEND_TO_IDLE)
  • echo standby> /sys/power/state (PM_SUSPEND_STANDBY)
  • echo mem> /sys/power/state (PM_SUSPEND_MEM)
  • echo disk> /sys/power/state (HIBERNATE)
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
			   const char *buf, size_t n)
{
   
   
	suspend_state_t state;
	int error;

	error = pm_autosleep_lock();
	if (error)
		return error;

	if (pm_autosleep_state() > PM_SUSPEND_ON) {
   
   
		error = -EBUSY;
		goto out;
	}

	state = decode_state(buf, n);
	if (state < PM_SUSPEND_MAX) {
   
   
		if (state == PM_SUSPEND_MEM)
			state = mem_sleep_current;

		error = pm_suspend(state);
	} else if (state == PM_SUSPEND_MAX) {
   
   
		error = hibernate();
	} else {
   
   
		error = -EINVAL;
	}

 out:
	pm_autosleep_unlock();
	return error ? error : n;
}

从函数中可以看出,在使用freezestandbymem命令时,其调用的处理函数都为pm_suspend()

而在使用disk命令时,调用的处理函数为hibernate()

1.3.1.2 sys/power/wakeup_count

这里介绍一下wakeup_count这个节点的机能实现,wakeup_count主要用于记录系统触发的wakeup event个数。

主要接口函数如下:

static ssize_t wakeup_count_show(struct kobject *kobj,
				struct kobj_attribute *attr,
				char *buf)
{
   
   
	unsigned int val;

	return pm_get_wakeup_count(&val, true) ?
		sprintf(buf, "%u\n", val) : -EINTR;
}

static ssize_t wakeup_count_store(struct kobject *kobj,
				struct kobj_attribute *attr,
				const char *buf, size_t n)
{
   
   
	unsigned int val;
	int error;

	error = pm_autosleep_lock();
	if (error)
		return error;

	if (pm_autosleep_state() > PM_SUSPEND_ON) {
   
   
		error = -EBUSY;
		goto out;
	}

	error = -EINVAL;
	if (sscanf(buf, "%u", &val) == 1) {
   
   
		if (pm_save_wakeup_count(val))
			error = n;
		else
			pm_print_active_wakeup_sources();
	}

 out:
	pm_autosleep_unlock();
	return error;
}

power_attr(wakeup_count);

wakeup_count接口向上层提供了两个功能,分别是读和保存wakeup_count值。

wakeup_count将用一个32位值保存(combined_event_count),此32位值的高16位用于存放已经发生的wakeup event次数,低16位用于存放正在运行中的wakeup event个数。

当某个模块在处理事件时,此时又不想被suspend打断,那么这个模块在处理前就会使用pm_stay_awake函数来告诉内核。当使用pm_stay_awake函数以后,wakeup_count的低16位将加1,此时意味着有wakeup event在运行中。

当模块将事件处理好后,会使用pm_relax进行释放,pm_stay_awakepm_relax都是成对使用的,pm_relax的调用意味着wakeup event处理完成,此时wakeup_count的低16位将减1,而wakeup_count的高16位将加1。即此时没有运行中的wakeup event,已经触发的wakeup event次数为1次。

当上层在使用sys/power/state接口来触发suspend之前,如果对wakeup_count进行了读取并保存,那么suspend过程中将通过pm_wakeup_pending函数来确认suspend流程中是否发生了wakeup event。

bool pm_wakeup_pending(void)
{
   
   
	unsigned long flags;
	bool ret 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IAYL.BL

创作不易,投个硬币😆

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值