idle process进程_CPU进入idle进程状态的流程

指南框架

每个CPU内核都会有一个空闲进程。当系统不调度CPU资源时,空闲进程就会进入空闲进程,空闲进程的作用就是通过不使用CPU来省电。

在ARM64架构中,当CPU空闲时,会调用WFI指令(等待中断),关闭CPU时钟以降低功耗,当外设中断触发时,CPU会恢复。

Cpuidle core是Cpuidle框架的核心模块,负责抽象出三个实体:cpuidle设备、cpuidle驱动和cpuidle调控器,如下图所示:

Cpuidle核心抽象了三种数据结构:cpuidle设备、cpuidle驱动程序和cpuidle调控器。

数据结构

cpuidle_device

每个CPU核对应一个struct cpuidle_device结构,主要字段介绍如下。

Structcpuidle_device{//内核中cpu unsignedintregistered:1是否无符号:1;cpu内核是否启用了unsigned:1;unsignedintuse _ deepth _ state:1;//对应的cpunumberunsignedintcpucpu内核最后一次停留在cpuidle状态(US US)int last _ residency;//记录每个cpuidle状态的统计信息,包括是否启用,进入cpuidle状态的次数,停留在cpuidle状态的总时间(US)Struct CPUIDLE _ State _ Usages _ Usage[CPUIDLE _ State _ Max];};

对应的注册接口是cpuidle_register_device。

cpuidle_driver

Cpuidle驱动用于驱动一个或多个CPU内核,关键字段描述如下:

struct guidle _ driver { const char * name;structmodule *所有者;intrefcnt//用于判断驱动注册时是否需要设置BroadcastTimeRunsignedintbtimer:1;//用来描述cpuidle的状态,需要按照功耗降序排序。有多少种状态?struct CPUIDLE _ STATES[CPUIDLE _ State _ MAX];};//CPU空闲有许多不同的级别。这些空闲级别具有不同的功耗和延迟,因此可以用于不同的场景。//主要包括exit_latency,power_usage,target_residency。这些特征是调控器制定空闲策略的基础:struct puidle _ state { charname[cpuidle _ name _ len];char desc[CPUIDLE _ desc _ LEN];unsignedintflags//CPU从空闲状态返回运行状态的延迟时间,单位为us。它决定了CPU在空闲状态和运行状态之间切换的效率,如果延迟过大,会影响系统性能;unsignedintexit _ latency/CPU在此idlestate下的功耗,以mWintpower_usage为单位;/预期停留时间,美国。进入和退出空闲状态需要额外的能量。如果在空闲状态下停留时间太短,节省的电量小于额外的消耗,那就得不偿失了。根据这个字段和当前系统情况(比如可以空闲多长时间),调控器会选择空闲级别;unsignedinttarget _ residencybool disabled;/进入状态的回调函数int(* Enter)(structcpuidle _ device * dev,structcpuidle _ driver * DRV,int index);//这个回调函数可以在//CPU不需要长时间工作时调用(称为离线)。int(* enter _ dead)(structcpuidle _ device * dev,int index);};

对应的注册接口是cpuidle_register_driver。

cpuidle_governor

调控器结构主要提供不同的回调函数,最终由menu_governor填充。主要字段如下:

struct puidle _ governor { charname[c puidle _ NAME _ LEN];structlist _ headgovernor _ list//省长的级别。一般情况下,内核会选择系统中rating值最大的调控器作为当前的governorunsignedintrating//设备驱动注册注销时调用int(* enable)(structcpuidle _ driver * DRV,structcpuidle _ device * dev);void(* disable)(structcpuidle _ driver * drv,structcpuidle _ device * dev);//根据当前系统运行状态和各个idlestate的特点选择一个状态(即决策)int(* Select)(struct cpuidle _ driver * DRV,struct cpuidle _ device * dev,bool * stop _ tick);//通过这个回调函数,可以告诉调控器系统上次在哪个void(* reflect)(struct cpuidle _ device * dev,intindex);};

对应的注册接口是cpuidle_register_governor。

程序

让我们来看看设备和驱动程序的注册过程:

注册后,设备和驱动程序之间的连接就建立了。最后,cpuidle框架的用户可以通过接口调用下层接口,完成具体的硬件操作。

我们来看看CPU进入空闲状态的流程图:

可以看出,CPU挂起最终是通过PSCI实现的。

PSCI

ARM定义的电源管理接口规范psci(power state coordination interface)通常由固件实现,而Linux系统可以通过smc/hvc指令进入不同的异常级别,然后调用相应的实现。

PSCI支持以下功能:

CPU热插拔(开/关)

CPU空闲(挂起/恢复)

系统挂起/恢复

系统关闭和复位

每个函数与ATF之间的调用接口如下:

审计刘清