【Linux kernel/CPU idle】CPU Idle ----framework

为啥需要CPUidle:

当cpu没有执行任务的时候,系统是如何管理cpu的?如果没有运行任务直接对cpu下电,确实做到低功耗了,但会导致下次跑任务,CPU启动太慢会导致性能太拉跨。
cpuidle就是为了兼顾功耗和性能引入的。当cpu没有执行任务,也没有收到中断/异常信号的时候,此时CPU就处于idle态,,Linux中cpuidle的管理是由cpuidle framework来负责的。

啥时候进入Idle

代码中判断进入Idle的逻辑

在Linux系统启动的时候,会在每个cpu上创建对应的idle进程,start_kernel()函数初始化内核需要的所有数据结构,并创建一个名为init的进程(pid=1),当init进程创建完后,cpu的idle进程处于cpu_idle_loop()无限循环中,当没有其他进程处于TASK_RUNNING状态时候,调度器才会执行cpu idle线程,让cpu进入idle模式.其函数调用关系简要概括如下:
在这里插入图片描述
在cpu_startup_entry这个函数中,最终程序会进入无限循环do_idle loop中
在这里插入图片描述
在do_idle()中,代码会不断地轮询,判断当前系统是否需要调度,如果系统当前不需要调度,则进入到idle状态.
在这里插入图片描述
在cpuidle_select函数里就是真正在进行cpu idle的选择操作。

为啥要搞多级idle

在SMP系统中,在负载不大的情况下,让部分core offline确实可以节省功耗,但下电后势必对性能造成一定的影响,如果在关闭之后很短的时间内就被唤醒,那么就会造成功耗/性能双方都不讨好,在进入退出idle的过程中也是会有功耗的损失的,如果在idle状态下面节省的功耗还无法弥补进入退出该idle的功耗,那么反而会得不偿失。根据性能/功耗的的这种矛盾,很多厂家会制定多个层级的idle状态,在每个层级下面的功耗、进入退出idle的功耗损失、以及进入退出的延迟都会是不同的数值,而cpuidle framework会根据不同的场景来进行仲裁选择使用何种的idle状态。

cpuidle framework

Linux kernel中,cpuidle framework位于“drivers/cpuidle”文件夹中,包含cpuidle core、cpuidle governors和cpuidle drivers三个模块,再结合位于kernel sched中的cpuidle entry,共同完成cpu的idle管理。软件架构如下图:
在这里插入图片描述
1)kernel schedule模块

位于kernel\sched\idle.c中,负责实现idle线程的通用入口(cpuidle entry)逻辑,包括idle模式的选择、idle的进入等等。

2)cpuidle core

cpuidle core负责实现cpuidle framework的整体框架,主要功能包括:
根据cpuidle的应用场景,抽象出cpuidle device、cpuidle driver、cpuidle governor三个实体;

以函数调用的形式,向上层sched模块提供接口;
以sysfs的形式,向用户空间提供接口;
向下层的cpuidle drivers模块,提供统一的driver注册和管理接口;
向下层的governors模块,提供统一的governor注册和管理接口。

3)cpuidle drivers

负责idle机制的实现,即:如何进入idle状态,什么条件下会退出,等等。
不同的architecture、不同的CPU core,会有不同的cpuidle driver,平台驱动的开发者,可以在cpuidle core提供的框架之下,开发自己的cpuidle driver。代码主要包括:cpuidle-xxx.c。

4)cpuidle governors

Linux kernel的framework有两种比较固定的抽象模式:

模式1,provider/consumer模式,interrupt、clock、timer、regulator等大多数的framework是这种模式。它的特点是,这个硬件模块是为其它一个或多个模块服务的,因而framework需要从对上(consumer)和对下(provider)两个角度进行软件抽象;

模式2,driver/governor模式,本文所描述的cpuidle framework即是这种模式。它的特点是:硬件(或者该硬件所对应的驱动软件)可以提供多种可选“方案”(这里即idle level),“方案”的实现(即机制),由driver负责,但是到底选择哪一种“方案”(即策略),则由另一个模块负责(即这里所说的governor)。

模式2的解释可能有点抽象,把它放到cpuidle的场景里面,就很容易理解了:

前面讲过,很多CPU提供了多种idle级别(即上面所说的“方案”),这些idle 级别的主要区别是“idle时的功耗”和“退出时延迟”。cpuidle driver(机制)负责定义这些idle状态(每一个状态的功耗和延迟分别是多少),并实现进入和退出相关的操作。最终,cpuidle driver会把这些信息告诉governor,由governor根据具体的应用场景,决定要选用哪种idle状态(策略)。

kernel中,cpuidle governor都位于governors/目录下。

软件流程

kernel会在系统启动完成后,在init进程(或线程)中,处理cpuidle相关的事情。大致的过程是这样的

首先需要说明的是,在SMP(多核)系统中,CPU启动的过程是:

1)先启动主CPU,启动过程和传统的单核系统类似:stext–>start_kernel–>rest_init–>cpu_startup_entry

2)启动其它CPU,可以有多种方式,例如CPU hotplug等,启动过程为:secondary_startup–>__secondary_switched–>secondary_start_kernel–>cpu_startup_entry

cpu_startup_entry负责处理CPU idle的事情,流程如下
cpu_startup_entry
arch_cpu_idle_prepare,进行idle前的准备工作,ARM64中没有实现
cpu_idle_loop,进入cpuidle的主循环
如果系统当前不需要调度(!need_resched()),执行后续的动作
local_irq_disable,关闭irq中断
arch_cpu_idle_enter,arch相关的cpuidle enter,ARM64中没有实现
cpuidle_idle_call,main idle function
cpuidle_select,通过cpuidle governor,选择一个cpuidle state
cpuidle_enter,通过cpuidle state,进入该idle状态

中断产生,idle返回(注意,此时irq是被禁止的,因此CPU不能响应产生中断的事件)
cpuidle_reflect,通知cpuidle governor,更新状态
local_irq_enable,使能中断,响应中断事件,跳转到对应的中断处理函数

arch_cpu_idle_exit,和enter类似,ARM64没有实现

需要着重说明一下:
使用cpuidle framework进入idle状态时,本地irq是处于关闭的状态,因此从idle返回时,只能接着往下执行,直到irq被打开,才能执行相应的中断handler,这和之前传统的cpuidle不同。同时也间接证实了“Linux cpuidle framework(4)_menu governor”中所提及的,为什么menu governor在reflect接口中只是简单的置一个标志。因为reflect是在关中断时被调用的,需要尽快返回,以便处理中断事件。

学习wiki:
Linux Cpuidle介绍
Linux cpuidle framework(1)_概述和软件架构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值