电源管理入门-9 CPU Idle

张开发
2026/6/13 8:42:46 15 分钟阅读
电源管理入门-9 CPU Idle
关于Linux的很多知识其实网上的资料非常的多但是也有些问题有时候是缺乏系统的讲解不像书里一章一章的有时候知识性太强往往基础概念或者用法介绍缺失就像“我们从哪里来我们是谁我们要到哪里去”只讲中间的我们是谁并且讲的很详细我们从哪里来到哪里去压根没提到这也是入门的一个障碍往往大多数人不需要知道我们是谁你先告诉我这东西有什么用为啥搞出来个这个东西对我有用了我再学习啊。1. CPU Idle有什么用答案就是“省电”当多核CPU没有任务执行的时候这时候需要将除主Core之外的其他Core进行低功耗处理这件事就是CPU Idle机制做的。idle状态: 在Linux kernel中当cpu中没有任务在执行也没有任何中断、异常信号过来的时候我们称为处于idle状态针对这种状态Linux设计了一套cpuidle framework框架专门用于cpuidle的管理。Linux系统初始化时会为每个cpu创建一个idle线程当没有其他进程需要运行的时候便运行idle线程。对于不同的功耗及恢复时间的要求可以根据芯片硬件支持的情况定义多种idle状态这些状态按功耗从低到高对应着恢复时间从少到多排列利用linux提供的cpuidle框架用户选用不同的idle策略。这么做的目的就是尽可能在不影响性能的前提下减少功耗。在ARM64架构中至少会提供一个wfi的idle状态有些芯片可能还会提供core下电的idle状态。当CPU idle时根据预测的idle时间、功耗受益大小、恢复的时间长短选用一个idle状态比如进入wfi关掉CPU的arch timer以便降低功耗当有中断触发时CPU又会恢复回来。2. CPU Idle整体框架首先是CPUIdle子系统通过sysfs向userspace提供的节点一类是针对整个系统的/sys/devices/system/cpu/cpuidle通过其中的current_driver、current_governor、available_governors等节点可以获取或设置CPUIdle的驱动信息以及governor。一类是针对每个CPU的/sys/devices/system/cpu/cpux/cpuidle通过子节点暴露各个在线的CPU中每个不同Idle级别的name、desc、power、latency等信息。什么时候进入idle关闭一些核可以节省功耗但关闭之后对时延(性能)必会造成一定的影响如果在关闭之后很短的时间内就被唤醒那么就会造成功耗/性能双方都不讨好在进入退出idle的过程中也是会有功耗的损失的如果在idle状态下面节省的功耗还无法弥补进入退出该idle的功耗那么反而会得不偿失。–解决方法就是策略。是由cpuidle framework会根据不同的场景来进行仲裁选择使用何种的idle状态。在kernel中cpuidle framework主体包含三个模块分别为cpuidle core、cpuidle governors和cpuidle driverscpu idle core负责整体框架同时负责和sched模块对接当调度器发现没有任务在执行时候就切换到idle进程通知到cpuidle framework的cpuidle core模块要做接下来的idle操作。向cpuidle driver/governors模块提供统一的driver和governors注册和管理接口向用户空间程序提供governor选择的接口。cpuidle driver负责具体idle机制的实现不同等级下面idle的指标也是在这个模块进行填充不同的平台会有不同的drivers实现。cpudile governors在这个模块进行cpuidle的选择选择的算法主要是基于切换的功耗代价和系统的延迟容忍度电源管理的目标就是在保证延迟在系统可以接受的范围内尽可能的节省功耗。3. Idle状态判断在Linux系统启动的时候会在每个cpu上创建对应的idle进程start_kernel()函数初始化内核需要的所有数据结构并创建一个名为init的进程pid1当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中。这里我们又进入看代码环节可以参考公众号之前的文章# Linux驱动-IMX6ULL开发板qemu环境搭建我们修改好qemu启动脚本加-s -S后在VS中打断点进行代码查看。cpu_idle_loop函数中会不断的进行轮询判断while(1){...if(cpu_is_offline(cpu)){cpuhp_report_idle_dead();arch_cpu_idle_dead();}local_irq_disable();arch_cpu_idle_enter();...}3. cpuidle corecpuidle core抽象出了三个数据结构cpuidle device用于描述CPU核的cpuidle设备。cpuidle driver用于描述CPU核的cpuidle驱动。cpuidle governor主要根据cpuidle的device和driver状态来选择策略。以cpuidle-pcsi.c为例整个cpuidle注册流程如下图4. 注册初始化cpuidle初始化包括governor注册、驱动注册和设备注册三部分4.1 cpuidle governor注册cpuidle governor在cpuidle驱动和设备之前注册内核使用一个链表维护系统中所有已注册的governor。当前新版内核一共支持ladder、menu、teo和haltpoll四种governor它们都通过调用cpuidle_register_governor函数将自身注册到系统中。Haltpoll governor它是用于优化虚拟机性能的一种cpuidle governor。其原理为当vcpu进入idle时通过guest端执行poll操作以避免使其陷入host中。它的优点是减少了vm切换和通过ipi唤醒vcpu的成本但它也造成在guest睡眠时host无法复用该vcpu对应的物理cpu从而降低系统吞吐量的问题。Ladder governor该governor通过cpu前一次idle状态的驻留时间是否超过该state延迟时间一个特定的值promotion_time_ns以及下一个state的延迟时间是否超过系统延迟容忍度来确定是否需要提升idle state。由于该governor每次只能提升一个state因此其state提升方式就像梯子一样逐级往上这也是它的名字由来。它往往用于periodic timer tick system。Menu governor直接选择可能满足需求的最深休眠态就好像你拿着菜单menu选菜一样。如果深度的idle state更好那么就会直接进入到深度的idle state。Teo governor采用的策略跟menu governor一样都是预测接下来会有多长时间能待在idle状态然后据此选择合适的idle mode。不过它跟menu governor考虑多方因素的策略是不同的。teo的理念是多数系统上CPU唤醒最频繁的唤醒源都是timer events而不是设备中断(device interrupts)。timer中断的数量要比其他中断高几个数量级。所以只要依据timer event就可以做好预测工作了。4.2 cpuidle driver注册cpuidle驱动注册流程比较简单它主要包含以下三部分内容idle state相关参数设置、以及可能的broadcast timer若设置了local-timer-stop属性则为每个cpu设置相应的broadcast timer若为该driver指定了governor则切换current governorcpuidle driver的主要工作是定义所支持的cpuidle state以及state的enter接口如下面所示cpudile driver就要负责将平台定义的idle-state信息填充到这个结构体中4.3 cpuidle device注册cpuidle设备注册主要包括初始化一些参数值将该设备添加到全局设备链表中然后为其初始化sysfs属性和使能该设备。注册之后cpuidle设备、cpuidle驱动及governor之间建立起了连接最终系统经由cpuidle framework通过接口来调用下层的接口进而完成具体的硬件操作。在现在的SMP系统中每个cpu core都会有一个对应的cpuidle device内核是通过使用struct cpuidle_device抽象cpuidle device,该结构体主要成员含义如下lenabled设备是否已经使能 lcpu:该device对应的cpu number llast_residency:该设备上一次停留在idle状态的时间 lstates_usage:记录了该设备的每个idle state的统计信息5.cpuidle触发流程Idle task通过cpu_startup_entry为入口调用到cpuidle_framework流程如下图cpu启动完成时会通过cpu_startup_entry函数将其自身切换到idle线程。除此之外当某个cpu上没有可运行线程时也会切换idle线程上流程没画出后面梳理进程调度的时候再细讲。切换idle线程后最终都会执行idle线程的主函数do_idle并最终通过该函数将cpu设置为特定的idle state。其中governor中的select、reflect函数是cpuidle的核心功能决定了cpuidle状态的选择策略。参考资料https://zhuanlan.zhihu.com/p/548268554https://blog.csdn.net/feelabclihu/article/details/125688355后记关于cpu idle的学习大家可以自己百度找点资料文章中的资料也是参考别人写的进行学习感觉要想彻底掌握还是需要调试大多数我们能做的还是配置DTS简单了解下基本构架也是可以的。“啥都懂一点啥都不精通干啥都能干干啥啥不是专业入门劝退堪称程序员杂家”。欢迎各位自己有博客公众号的留言申请转载多谢后续会继续更新纯干货分析欢迎分享给朋友欢迎点赞、收藏、在看、划线和评论交流以公众号“那路谈OS与SoC嵌入式软件”欢迎关注个人文章汇总https://thatway1989.github.io

更多文章