cpuidle framework in Linux Kernel(2)what's idle state

processor中可以有多个不同的idle级别,对应着不同的power consumption和exit latency。当CPU上没有任务执行时,可以系统当前的状态,把processor切换到不同的low power state,降低power consumption。
本文从ACPI spec中定义的processor low power state和Linux kernel中idle state的实现两个方面来阐述cpuidle state。

一、processor power state in ACPI spec

1.1 processor power state definition

ACPI spec中定义了processor power state,用C0, C1, C2, C3,…Cn来表示,并规定了processor power state C0~C3 的行为如下:

C0

fully power on,normally execution;

C1

CPU halt state,通过HLT指令进入,不需要硬件支持;
所有的processor都必须支持C1 state;
在C1 state下,CPU能够保持cache coherent;
C1 state的exit latency很小;有中断时,processor退回到C0 state;

C2

core clock gating to save power,optionally supported;
if supported, C2 has lower power and higher wakeup latency than C1 state;
通过P_LVL2 register进入,需要clock logic hardware support;
在C2 state下,processor依然能够保持cache coherent,bus master and multiprocessor activity can take place without corrupting cache context。
wakeup event触发时,processor退回到C0;

C3

core clock gating and lower voltage to save more power,optionally supported;
通过P_LVL3 register进入,lower power and higher wakeup latency than C2 state;
在C3 state下,processor无法保持cache coherency,OSPM需要保证cache coherency。
interrupt或bus master request都可以让processor退回到C0 state;
为了支持C3 state,ACPI支持使用两种方式来保证cache coherency:
1)uniprocessor 系统中,在进入C3 state之前,disable bus master arbitration
这样当processor处于C3 state时,bus master就无法执行memory access操作;
bus master request需要先把core叫回到C0,再re-enable bus master arbitration之后才能处理。
2)在multiprocessor系统中,进入C3 state之前,由OSPM去flush & invalidate cache;

C4~Cn

optionally supported, lower power and longer exit latency;

1.2 processor power state transition

processor power state transition转换如下图所示:
在这里插入图片描述
processor power state的转换流程如下:
在这里插入图片描述
PREP:在hardware开始操作clock/voltage之前的准备阶段,不是所有的idle state都需要PREP,比如进入C1 state时,只需要SW执行一条HLT指令,不需要硬件配合,就没有PREP;而进入C3 state时,flush cache等操作就需要在PREP阶段完成。如果有wakeup event触发,CPU会停止进入idle的操作,退回到C0。
ENTRY: hardware控制clock/voltage到idle state指定的状态。这个阶段无法被打断,一旦开始,就必须完成;
IDLE: CPU真正处于low-power,CPU可以一直待在idle state,直到有wakeup source触发;
EXIT: wakeup event触发时,执行一些必要的操作,使CPU恢复到idle之前的状态。和PREP一样,EXIT也不是必须的,通常在processor进入到power down时,processor context需要save and restore。
worst case wakeup latency:从wakeup event触发,到CPU恢复到C0 state的最长时间,一般地,the deeper idle state,the more energy saved,but the longer wakeup latency。
min_residency:CPU在idle state中保持的最短时间,从以上的流程中不难看出,CPU进入idle state不是effortless,多数是需要一些额外的操作的。如果CPU在idle state中停留的时间太短,节省的功耗小于idle过程额外需要的功耗,那就得不偿失了。因此,每个idle state都有一个min_residency要求,需要超过这个时间,一次idle操作才是合算的。

二、power state supported for processor

ACPI table中,可以在processor object中使用_CST或_LPI(ACPI 6.0 introduced) method声明processor支持的idle state。

_CST method

_CST method描述processor 支持的low power states信息。_CST 返回一个变长的package,格式如下:

	Package {
		count,				//支持的idle states个数;
		Cstate[0]			//每个entry都对应着一个idle state,格式如下:
		……
		Cstates[count-1]			
	}
	Cstate sub-package如下:
	Package {
		Register			// c-state entry method
		Type				//C-state type
		 Latency			//the worst case latency to enter/exit the C-state
		 Power				//average power consumption in the state
	}

我们以Intel I5为例,查看processor支持的power state如下:
在这里插入图片描述
DSDT table中对应的_CST method 如下:

	#C1 state sub-package
	Name(C1LM, Package(0x04)			
	{
		ResourceTemplate ()
		{
			Register (FFixedHW, 0x01, 0x02, 0x0000000000000000,0x01)
		},
		one, one, 0x3E8
	})
	#C3 state sub-package
	Name(C3LM, Package(0x04)
	{
		ResourceTemplate ()
		{
			Register (FFixedHW, 0x01, 0x02, 0x0000000000000010,0x01)
		},
		0x02, 0x94, 0x1F4
	})	
	#C6 state sub-package
	Name(C6LM, Package(0x04)
	{
		ResourceTemplate ()
		{
			Register (FFixedHW, 0x01, 0x02, 0x0000000000000020,0x01)
		},
		0x03, 0xA9, 0x15E
	})
	
	#3 idle states supported;
	Name(C3ST, Package(0x04)
	{
		0x03,
		C1LM,
		C3LM,
		C6LM
	})
	Scope (_PR)
	{
		Processor (CPU0, 0x01, 0x00000410, 0x06)
		{
			Method (_CST, 0, Serialized)
			{
				return (C3ST)
			}
		}
	}

三、cpuidle state in Linux kernel

Linux kernel 使用struct cpuidle_state来描述一个idle state,包括:
1)该idle state的特性,主要包括exit_latency、power_usage和target_residency,governor在选择idle level时,需要考虑这些因素;
2)进入这个idle state的方法,即enter method;
具体的数据结构如下:

struct cpuidle_state {
	char		name[CPUIDLE_NAME_LEN];
	char		desc[CPUIDLE_DESC_LEN];
	unsigned int	flags;
	bool			disabled; 				/* disabled on all CPUs */	
	unsigned int	exit_latency; 			/* in US */
	unsigned int	target_residency; 	/* in US */
	int				power_usage; 		/* in mW */	
	int (*enter)	(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index);
	int (*enter_dead) (struct cpuidle_device *dev, int index);
};

关键的成员描述:
1) name, desc都是用来描述该idle state的;
2) exit_latency:CPU从该idle state返回到C0的延迟,单位是us;
3) power_usage:CPU在该idle state下的功耗,单位是mW;
4) target_residency:该idle state期望的停留时间,单位是us。
进出idle state是需要消耗额外的能量的,如果在idle state的停留时间太短,节省的功耗等于甚至小于额外消耗,那就有点得不偿失了。因此,governor在选择要进入哪个idle state时,需要结合系统当前的情况,选择一个适当的idle state。
5)disabled:若为1,表示该idle state不可用;
5) enter:进入该idle state的回调函数;
6) enter_dead:CPU长时间不需要工作时(offline),调用该函数。
7) flags:包括
CPUIDLE_FLAG_TIME_VALID:residency时间是否可测量;
CPUIDLE_FLAG_COUPLED:该idle state是否应用在多CPU;
CPUIDLE_FLAG_TIMER_STOP:进入该idle state时,是否会停掉CPU local timer。若设置该标记,表示CPU在进入该idle state时,会停掉该CPU的local timer,此时需要提供一个broadcast timer(Broadcast timer独立于所有的CPU运行,可以把timer tick广播到每个CPU上,不会受到idle state的影响。)
cpuidle driver初始化时,会执行_CST method,从ACPI table中获取所有的idle state信息,并为每个idle state创建并初始化一个struct cpuidle_state对象。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值