Linux Cpuidle介绍

Linux Cpuidle介绍一 引入背景先来看一个抖音场景下面的功耗表现 这个是功耗分解板拆解出来的某一款手机 cpu 的核压和功率 会发现它们它们的数值不是一直保持在高位 有些时间会下降到很低 这个时候有人会说下降是因为 cpu 上面没有任务在执行了 所以 cpu 就不需要工作造成功耗损失 那么就引出来一件事情 当 cpu 上面没有任务执行的时候 系统是如何进行 cpu 管理的 如果在没有任务的时候只是单纯的关闭 cp

一、引入背景

先来看一个抖音场景下面的功耗表现,这个是功耗分解板拆解出来的某一款手机cpu的核压和功率,会发现它们它们的数值不是一直保持在高位,有些时间会下降到很低。

7f3d645ebcec88de77c86116e4abf111.png

这个时候有人会说下降是因为cpu上面没有任务在执行了,所以cpu就不需要工作造成功耗损失,那么就引出来一件事情,当cpu上面没有任务执行的时候,系统是如何进行cpu管理的,如果在没有任务的时候只是单纯的关闭cpu,那么下一次来一个事件的时候系统又如何兼顾此时的性能呢。在Linux kernel中,当cpu中没有任务在执行,也没有任何中断、异常信号过来的时候,我们称为处于idle状态,针对这种状态Linux设计了一套cpuidle framework框架,专门用于cpuidle的管理。

二、Idle状态

1. Idle状态,在代码里面是如何判断的呢

在Linux系统启动的时候,会在每个cpu上创建对应的idle进程,start_kernel()函数初始化内核需要的所有数据结构,并创建一个名为init的进程(pid=1),当init进程创建完后,cpu的idle进程处于cpu_idle_loop()无限循环中,当没有其他进程处于TASK_RUNNING状态时候,调度器才会执行cpu idle线程,让cpu进入idle模式.其函数调用关系简要概括如下:

start_kernel –> rest_init –> cpu_startup_entry,在cpu_startup_entry这个函数中,最终程序会进入无限循环do_idle loop中

7e382b81588e66746455f86a007ec6c8.png

在do_idle()中,代码会不断地轮询,判断当前系统是否需要调度,如果系统当前不需要调度,则进入到idle状态. 

do_idle()->cpuidle_idle_call()->cpuidle_select()

在cpuidle_select函数里就是真正在进行cpu idle的选择操作。

2. 多级idle状态的产生

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

三、cpuidle framework软件架构

在kernel中cpuidle framework主体包含三个模块,分别为cpuidle core、cpuidle governors和cpuidle drivers,架构图如下:

eab897a1db495992d61d0d98ab932b1c.png

cpu idle core:负责整体框架,同时负责和sched模块对接,当调度器发现没有任务在执行时候,就切换到idle进程,通知到cpuidle framework的cpuidle core模块要做接下来的idle操作。向cpuidle driver/governors模块提供统一的driver和governors注册和管理接口,向用户空间程序提供governor选择的接口。

cpuidle driver:负责具体idle机制的实现(不同等级下面idle的指标也是在这个模块进行填充),不同的平台会有不同的drivers实现。

cpudile governors:在这个模块进行cpuidle的选择,选择的算法主要是基于切换的功耗代价和系统的延迟容忍度,电源管理的目标就是在保证延迟在系统可以接受的范围内尽可能的节省功耗。

下面分别介绍下这几个模块的主体功能。

cpuidle core

cpuidle core是cpuidle framework的核心模块,负责抽象出cpuidle device、cpuidle driver和cpuidle governor三个实体。主体数据结构如下:

cpuidle_state:

ac6ac658a4d9bbea8dbd98bdbea2fefb.png

458c7a8f2b579789bd4cae2c2c17e1f6.png

上面也提到了现在很多厂家都会制定多个层级的idle状态,Linux kernel使用struct cpuidle_state结构抽象idle级别,主要成员的含义如下:

lname、desc:名称和简介;

lexit_latency:CPU从该idle state下返回运行状态的延迟

ltarget_residency: 期望的停留时间,进入退出idle状态是需要额外的功耗的,如果cpu很快进入退出idle状态,那么它的额外的功耗损失可能还弥补不了处于idle状态的功耗收益,从上面的图形中比较容易理解。所以就有了这样的一个指标,当cpu在idle状态下面停留超过一个的时间,才不会有功耗的损失,而这个临界点就是这里面提到的期望的停留时间,不同的平台和不同的idle等级下面这个值大小是不同的,Cpuidle Governor也会根据该数值来进行idle level的选择。

lpower_usage:cpu在该idle state下的功耗,单位nw

lenter:该state的回调函数

cpuidle_deivce

d8832cb4731658ce5989dbe3e1b0048a.png

在现在的SMP系统中,每个cpu core都会有一个对应的cpuidle device,内核是通过使用struct cpuidle_device抽象cpuidle device,该结构体主要成员含义如下:

lenabled:设备是否已经使能

lcpu:该device对应的cpu number

llast_residency:该设备上一次停留在idle状态的时间

lstates_usage:记录了该设备的每个idle state的统计信息

cpuidle_driver:

0ab222aca25d694820c891d1a265ff58.png

主要成员含义如下:

lstates、state_count:该driver支持的cpuidle state及其个数

cpuidle driver的主要工作是定义所支持的cpuidle state,以及state的enter接口,如下面所示,cpudile driver就要负责将平台定义的idle-state信息填充到这个结构体中

14c7c3cab18187e148cb6ddbf5872da6.png

cpuidle_governor:

内核通过使用struct cpuidle_governor结构体来抽象cpuidle governor,主要成员含义如下:

lgovernor_list:将该gover添加到一个全局的链表中

lrating:governor的级别

lenable/disable:governor的回调函数,主要进行一些初始化的操作

lselect:决策一个最佳的idle state

lreflect:告知governor上一次所处的idle state是哪一个

1b880131a4b060d8c618bff8a1e85321.png

cpuidle governor是cpuidle框架进行idle state决策的核心,下面我们重点对该模块展开讲解。

四、cpuidle governor

在当前的内核中,有两种主流的governor策略:ladder和menu,选择哪一种取决于内核的配置,ladder在periodic timer tick system中使用,menu在tickless system中使用

Ladder,从字面上理解是阶梯式的策略,即要到更高的层级必须从低层级step by step上去,在ladder策略中,ladder governor会首先进入最浅的idle state,然后如果待的时间足够长,则会进入到更深一级的idle state,以此类推,直到到达最深的idle state,被唤醒时,会尽可能快地重新启动CPU;等到下次空闲,则又会从idle state1开始进入。在这种策略中,系统可能长时间都不进入最深的idle state中,造成功耗低一些损失。

Menu,从字面上理解是菜单式的策略,即只要具备进入更深层次idle state的条件,系统就可以选择进入到该idle state中,不需要从浅到深逐层递进。

由于主流系统中常采用tickless system,所以接下来重点介绍menu governor

在上面的章节中有提到,governor的主要职责是决策一个最佳的idle state(在kernel的术语中也成为c-state),主要的考量是基于切换的功耗代价和系统的延迟容忍度。

切换代价:

在讲cpuidle core的时候有提到cpuidle_state中有个成员变量,名为target_residency(期望的停留时间),这个可以认为是在一次切换过程中满足功耗不损失的min时间值,所以这里切换的代价落到实处就是需要在选择idle state的时候需要cpu在c state的停留时间要超过target_residency,这里的停留时间系统有一个术语来进行表征:预测时间(predicted_us)

系统的延迟容忍度:

系统延迟容忍度主要是考虑对性能的影响,系统延迟容忍度在前面的文章《Linux pm_qos介绍》中有提到,kernel会通过pm qos来获取当前系统对延迟的容忍度(latency_req),接下来governors所要做的事情就是在备选的几个c-state中,在所有exit_latency小于latency_req的state中,选取功耗(power_usage)最小的那个即可。

落到实处,这两个关键的考量点是如何来满足的呢:1、即预测时间如何来判断更准确,2、系统延迟容忍度如何更准确知道系统对延迟的要求。下面我们结合menu governor的主要结构和函数来展开。

主要数据结构:

Struct menu_governor:

9d987643cf7d7112e9671ffeb4777bbe.png

在初始化的时候会调用cpuidle_register_governor来注册menu_governor,主要是提供了enable、select、reflect三个接口

struct menu_device:

34132625a87ad38e36f48c92e4c5735a.png

lCorrection_factor:保存校正因子,一共有BUCKETS个(一般为12个),后面会提到

lBucket:当前使用的矫正因子

lNext_timer_ns:距离下一个tick来临的时间,在后面的代码中会提到。

主体函数接口:

menu_enable_device接口

08b27ac1badfed5c9ac682f5e6632d50.png

该函数比较简单,主要任务就是初始化在结构体stuct menu_device中保存的校准因子correction_factor

menu_select接口

24a5cb7df681a57eab837a1227734dc2.png

3d2b6c0ab486291b4981937dea55af3b.png

总结下来就是几个过程:

1、计算使用哪一类校正因子以及predicted_us,因为预测时间不是很准确的,期间随时都可能产生除next timer event之外的其它wakeup event。为了使预测更准确,有必要加入一个校正因子(correction factor),该校正因子基于过去的实际predicted_us和next_timer_us之间的比率,为了更精确,menu使用动态平均的factor。另外对于不同的next_timers_us,校正因子的影响程度是不一样的;对于不同的io wait场景,系统对校正因子也有着不同的敏感程度 。随后尝试通过最近的8个过去的停留时间来查找重复间隔,如果他们的标准差小于一定阈值,则将这8个时间的平均值作为predicted_us。最后取以上两个流程中的最小值

2、计算延迟容忍度:根据predicted_us和系统负荷(iowaiters)计算此时的延迟容忍度,计算公式为predicted_us / (1 +10 * iowaiters),这个公式反映的是退出延迟和预期停留时间之间的比例,iowaiters越大,对退出延迟的要求就越高,最后latency_req的值取上面这个估值和pm_qos 中lantency中的最小值作为最后的延迟容忍度

3、最后根据前面计算出来的两个因素来选取具体的idle state,将计算出的predicted_us与所有idle状态的停留时间进行比较,选择特定idle状态的条件是相应的停留时间应小于predicted_us。另外,将状态的exit_latency与系统的交互性要求进行比较。基于两个等待时间因素,选择适当的空闲状态。

在cpu退出idle状态后,menu governor会将将上一轮的进入idle状态的数据更新到menu driver中,作为下一次select的参数,具体见menu_reflect函数接口:

0786dac88ff5e1a48b8edc7e5a98d291.png

接下来下一次进入选择流程时,会先触发更新需求,在 menu_update函数接口中进行操作

以上是menu governor的核心流程,最终结果是在延迟容忍度满足的前提下选择一个最佳的idle state.

、cpuidle案例呈现

在系统健康的情况下,cpuidle framwork会选择一个最适合性能功耗的c-state,但是在实际工作中,会遇到一些代码编写不规范的情况,导致最后的c-state处于一个我们不希望停留的状态。如下的一个案例:

在桌面idle场景,实际的trace表现:

39ac3f6b0ddaac998653e6d36cbe7652.png

而我们预期的表现应该是这样的

c8c927a48572e4cfcb007dc29174d5ef.png

分析trace发现在idle的时候系统最深是进入到state=2状态,而目前主流的几个平台一般会存在c0~c4几个状态,idx为2是没有进入到此时预期的最深idle状态(此时为桌面待机场景,无其他操作,理应进入最深的idle状态)

5554a89c32616f95a392339e2ed87ec6.png

添加debug信息发现request latency的时候有模块在request  cpu_dma_latency=400us,而查看平台数据时发现该cpu有四个idle-state等级,exit-latency时间分别为:100us/250us/1200us/1400us,从而导致系统无法进入到更深层次的idle状态

559152d3cbc899f0b299f2ffa9984333.png

六、总结

以上内容从背景、idle状态、cpuidle framework软件架构、cpuidle goveror四个维度进行cpuidle的介绍,并且以一个实际的案例来说明在工作中可能遇到的问题点,希望可以帮助到大家来学习linux cpuidle模块

参考文献:

1、http://www.wowotech.net/tag/cpuidle

2、https://www.kernel.org/doc/html/v5.0/admin-guide/pm/cpuidle.html

3、https://zhuanlan.zhihu.com/p/

4、https://blog.csdn.net/feelabclihu/article/details/

05bb961ded614c9a5b1c94360d8c9368.gif

长按关注内核工匠微信 Linux 内核黑科技 | 技术文章 | 精选教程
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/203484.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午9:44
下一篇 2026年3月19日 下午9:44


相关推荐

  • xcode自动签名_配置实用工具也不能移除

    xcode自动签名_配置实用工具也不能移除之前看到过一篇无证做真机测试的文章,很受用~不过因为当时手贱,把默认的“iPhoneDeveloper”签名改成了自己的名字直接导致后来的每一个XCode项目,我想在真机上面看效果都要重新设置签名配置。当然,是可以按照那篇文章把这个名字再修改回来,不过我当时懒,就一直这么弄着了如今经过了那么长的时间,我电脑里面存储的很多工程都沿用了这蛋疼的配置所以一时半会儿

    2026年4月15日
    8
  • 配置IIS的步骤

    配置IIS的步骤欢迎使用 Markdown 编辑器配置 IIS 步骤打开控制面板 选择 程序 再点击 打开或关闭程序 选择 Internet 信息服务 勾选如下 IIS 管理控制台 静态内容 默认文档 asp 右击计算机 选择 管理 查看 服务和应用程序 下的 服务 Worldwideweb 已启动 点击 IIS 服务 选择 默认网站 基本设置 选择科讯文件夹 选择

    2026年3月16日
    2
  • 通义千问Embedding模型延迟高?vLLM批处理优化教程

    通义千问Embedding模型延迟高?vLLM批处理优化教程

    2026年3月13日
    2
  • iscsiadm命令详解_iscsi 局域网

    iscsiadm命令详解_iscsi 局域网启动iscsi守护进程serviceiscsistart发现目标iscsiadm-mdiscovery-tsendtargets-p192.168.1.1:3260-mdiscovery指定模式为discovery-p192.168.1.1:3260指定目标ip和端口登入节点iscsiadm-mnode–Tiqn.19…

    2022年8月23日
    10
  • Java的System.getProperty详解

    Java的System.getProperty详解packagejavax org lang Date 2013 6 18 Author jilongliang Description System getProperty 详解 SuppressWarn all publicclassS publicstatic

    2026年3月17日
    1
  • linux RWX权限的解读

    linux RWX权限的解读Linux的权限不是很细致,只有RWX三种r(Read,读取):对文件而言,具有读取文件内容的权限;对目录来说,具有浏览目录的权限。w(Write,写入):对文件而言,具有新增,修改,删除文件内容的权限;对目录来说,具有新建,删除,修改,移动目录内文件的权限。x(eXecute,执行):对文件而言,具有执行文件的权限;对目录了来说该用户具有进入目录的权限。1、目录的只读访问不允许使

    2022年6月12日
    43

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号