0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

讨论一下Linux的各种躺平姿势

Linux阅码场 来源:Linux阅码场 作者:Liam 2021-06-13 17:59 次阅读

CPU 就和皮鞋厂的工人一样, 无可奈何之时也得躺平。历代CPU的架构师都有一颗仁慈的心——给自己的产品留下了躺平的功能,而且是一代更比一代强。相关的指令有HLT/PAUSE/MWAIT/UMWAT/TPAUSE,其中我最喜爱的是UMWAIT,它的妙处我们后面再说。

当然经理并不会轻易让CPU工人去摸鱼, 必须满足一定的条件。Linux 内核中那么严格说来是由Scheduler 来判断目前的工作量是否饱满。如果工作量实在不够,也只好让CPU划划水, 睁只眼闭只眼, 好歹省点电费不是。虽然在CPU层面摸鱼的手段花样百出, 但是在OS层面只有一个抽象的概念就是IDLE。在这个时候经理表面上放任CPU工人划水, 其实打的是省电的小九九,这也算是Win-Win的帕累托改进。那么问题就来了, Scheduler 到底是如何判断当前工作量不饱满呢?

调度器中idle 触发条件

Linux Scheduler 为每一个CPU工人都维护了一个RunQueue 可以认为是一个任务列表, 当且仅当这个列表里所有的任务都不是runnable的状态时, Scheduler 才会切换到idle process。也就是说这个时候CPU工人完全无所事事, 必须休息节省体力以及节省电费! 同时还要注意可以通过nohz/nohz_full启动参数减少tick 中断对正在休息的CPU工人的干扰!

身世显赫

那么首先我们要考虑得是idle进程从何而来,在描述细节之前我先剧透一下, idle进程虽然名字听起来不怎么样, 但是出身显赫。首个idle进程实际上转化自0号进程!内核成为了生活的真相帝, 躺平并不是人人都能拥有的选项!

具体的过程则是说来话长. 在开辟鸿蒙之初, kernel 所有的进程之始祖是一个静态的结构体:

struct task_struct init_task

init_task 并非由任何kernel API所创建, 是所有进程的祖先, 名副其实的the one。

它肩负了非常重要的职责, 例如创建首个内核线程kernel_init。从而达到 一生二,二生三,三生万物 的效果。不过今天这些不是本文的重点, 重点在于大功告成之际, init_task 并未事了拂衣去而是默默的转化成了idle 进程。它继续无言的守护着整个系统, 俯首甘当孺子牛啊。

这里参见代码 init/main.c line 451,这里是函数rest_init 的最后阶段大家可以发现调用了 cpu_startup_entry 这个函数。

我们可以跳转到 kernel/sched/idle.c 来一窥细节. 这里第一个arch_cpu_idle_entry 是可选接口,x86并没有实现,核心中的核心还是函数 do_idle()-- just 躺平.

如果没有在启动时强制idle 模式为poll, 则我们将在这里进入真正的躺平函数 cpuidle_idle_call.

在smp系统中 core0 以外的其它core 也会通过 start_secondary 函数最终产生0号进程且调用cpu_startup_entry 来进入idle loop之中。

CPU各种“躺平”的姿势

各个厂子出产的CPU工人的idle 姿势也是慢慢演化的, 从简入繁, 花样百出。下面我们一起来浮光掠影的看一下这些"超能力"。

X86

HLT

这是初代的idle 指令, 于486DX时代引入. 首先只有在ring0的特权级别才能执行HLT指令, 同时执 行的效果是 CPU 进入了C1/C1E state(参考ACPI标准)。严格说起来只能算是摸鱼0.1v。APIC/BUS /CACHE 都是照常运转, 只要中断发生, CPU工人立即就要回到产线继续搬砖。C1E 稍微又优待了CPU点, 停止内部时钟又降了压, 比较体贴。

PAUSE

这个也是非常早期的指令(Pentium 4)许可CPU 工人打个盹,大概从几个到几十个cycles吧(各代CPU有差异)。为什么要打盹呢?其实主要是要降低CPU工人在特定情况下(spin-lock)给内存控制器带来的压力,与其让CPU工人阻塞了内存控器, 不如让他打个盹吧。在最近的几代Xeon之上还附带了降低功耗的buff。

MWAIT/MONITOR

新一代CPU架构师回顾了前辈的设计, 觉得CPU工人的权力完全没有得到充分的照顾, 应该给予更进一步的休息机会乃至真正的躺平!而且唤醒的条件又多了一个, 除了中断这种强唤醒模式以外, 又加了内存的CacheLine Invalidate唤醒。你的邻居CPU 除了敲门以外还多了拿橡皮筋弹窗户玻璃的渠道。首先这两条指令也只能在ring0 级别执行, 首先是调用MONITOR 地址范围, 其次是MWAIT 进入休眠,一旦该地址的内存被任何其它的主体修改, 则唤醒CPU工人起来继续搬砖。同时这次最大的改进是可以通过MWAIT 进入各种不同的Cstate。其中C6 是我心目中真正的躺平 CPU 电压可以归0同时cache 也停, 实至名归啊。

最常见的C State 状态详细描述,引自[2]

Cstate Name Description
C0 Operating State CPU fully turned on
C1E Enhanced Halt Stops CPU main internal clocks via software and reduces CPU voltage; bus interface unit and APIC are kept running at full speed
C3 Deep Sleep Stops all CPU internal and external clocks
C6 Deep Power Down Reduces the CPU internal voltage to any value, including 0 Volts

UMWAIT/UMONITOR

MWAIT虽好, 但是奈何必须在ring0特权级下执行, 如果是一些特定的用户级应用例如DPDK, Linux的 idle driver 是很难得到执行的机会,所以CPU架构师又生怜悯之心, 允许CPU在用户级也能进入躺平的模式, 不过作为妥协连C1 state都不行,只能进入 C0.1/C0.2 等神秘模式。效果还有待观察,不过话说回来SPR这代Xeon才开始支持....距离上市少说还得1年之久。

TPAUSE

UMWAIT 指令的升级加强版, 附带了一个timer。TPAUSE 可以让CPU工人根据规定好的时间进行休息, 时间一到, 立刻继续搬砖。当然这也是一个簇新簇新的指令,大家还要等待SPR。

ARM

ARM的Idle-state 级别情况比较复杂一些, 更多的是和具体的芯片实现相关. 但是总体上也是把握几个大的类别:

只是停止CPU内部时钟

CPU降频

停止给Cache供电

停止给CPU供电

和X86 相比 Arm的唤醒机制没有和MESI协议连接有些遗憾(也就是没有实现通过MEM 地址监控的方式达成唤醒).

YEILD

这条颇为类似 PAUSE基本功能接近,使用场景也接近(spin lock).

WFE/WFI

这两条指令顾名思义 wait for event/ wait for interrupt,中断这条大家都可以理解类似HLT,那么event这条就值得看看了。ARM架构可以从一个CPU向所有其它CPU 发送event(sev 指令),我的理解类似IPI广播,收到了此event的CPU如果处于idle状态, 则需要立即唤醒。(注:和宋老师讨论以后发现 event 和IPI的一个区别是不需要ISR来响应,同时event并不能唤醒由于WFI指令进入的idle,这个有点囧,反过来中断可以唤醒由于WFE进入的idle。这两个躺平姿势水很深啊)

软件实现

除了硬件的各种花式躺平技术之外还有两类“伪躺平”技术。

idle polling

通过启动参数, 我们可以指定cpu的idle 进程并不调用硬件提供的idle功能而仅仅是polling, 这种情况主要用于需要极低的CPU从idle状态返回时延的场景。那么如果压根没有进入实际的idle状态,当然时延是极低的,同时也能融入到idle整体的框架,不至于破坏规矩开特例。

halt-polling

在打开虚拟化的场景下, 事情就变得更加有趣了。大多数情况下, qemu 会缺省的只对guest 提供HLT指令作为idle的唯一机制,但是 HLT 指令毫无悬念的会触发VMEXIT。虽然说大多数情况下kvm看到exit reason 是HLT 也只是执行poll而已, 但是VMEXIT/VM_RESUME 还是如此的痛,毕竟几千个cycles已经无谓流逝, 追求极致的我们怎么能放任资源浪费。于是Redhat在Guest端引入了halt poll 机制, 也就是说如果matrix中的CPU工人首先开始假摸鱼(poll), 如果假摸鱼时间超过了阈值才真的去触发HLT指令。如果很快就被从假模鱼状态拉回去搬砖, 则省去了出入matrix的费用(经理得意的笑了)。

最后软件硬件各路躺平姿势花样繁多, 内核无奈又祭出了抽象大法把idle的时长与返回时延的选择与具体执行idle的机制分离开来。

idle governor 就负责做时长与时延的选择,也可以称为 idle -select。

idle driver 则是负责通过我们上面描述的各种软硬件机制来实现governor指定的目标。同时向governor menu 经理提供各种不同机制的性能参数,以供menu经理选择,就是所谓的idle-enter。

idle governor 缺省的算法只有一个就是menu, 还有3个候选的ladder/TEO/haltpoll 算法但是一般需要重新编译内核来激活。

ladder 算法故名意思, 是首先从能耗较高/返回时延较小的状态开始,当系统idle超过了阈值再进入更深的节能状态,从而逐步升级节能状态。俗称添油战术也可以美其名曰“快速迭代”。

menu 算法单从名字看则有点让人摸不到头脑,其内部机制也确实颇为复杂,menu算法主要是要在节能状态的停留时间与系统能容忍的返回时延之间做权衡以达到最佳效果。

请原谅我非常不精确地描述一下menu。menu仿佛一个非常敬业的经理凡事都要精算做出最优选择,CPU工人一旦休息再想打起精神干活这个转换是有一个代价的, 往往需要口头鼓励(画饼)+物质鼓励(肉夹馍)。那么经理就要考虑如果工人休息时间太短,休息的好处远低于让CPU工人重新振作的代价,那么这个休息就是不合理的(无情啊)。而且休息也有好些种类, 从假休息到完全躺平, 到底哪一种休息状态才是收益比最佳的? menu会无情的选择那个休息带来好处大于重新振作代价的方案。同时menu经理还会受到来自客户的压力, 时延也是要满足的。客户的耐心大抵上都是不好的, menu经理会疯狂试探客户的底线。它选择的方案是满足客户耐心上限的情况下CPU工人消耗能耗最少的方案。同时做到以上两点 menu经理大约才能有希望完成OKR/KPI。

结语

今天我们一起浮光掠影的讨论了一下Linux的各种躺平姿势,从中能领略到一代代CPU架构师对CPU打工人的关爱。最后我衷心的祝愿CPU打工人在层出不穷的各类躺平技术加持下,最终能同各位经理一起实现碳中和的OKR/KPI。

原文标题:漫话Linux之“躺平”: IDLE 子系统

文章出处:【微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • cpu
    cpu
    +关注

    关注

    68

    文章

    10442

    浏览量

    206545
  • Linux
    +关注

    关注

    87

    文章

    10990

    浏览量

    206733

原文标题:漫话Linux之“躺平”: IDLE 子系统

文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    stm32外部中断不能唤醒stop休眠模式怎么解决?

    按键引脚设置成外部中断方式,可以正常唤醒stop模式;但是充电口设置成外部中断,却无法唤醒stop休眠!!!配置都是样的,按键下降沿触发,充电检测是上升沿触发。 有可能是什么原因,遇到类似情况的讨论一下吧!
    发表于 04-26 06:11

    功率器件 Spice 模型建立

    社区有关于器件 SPICE model建模的吗,如LDMOS、VDMOS、IGBT、SiC功率器件spice model?可以相互讨论一下,或者有建模需求的也可以沟通。
    发表于 04-12 22:37

    STM32可以使用手机APP,蓝牙或者WIFI软件升级MCU软件的方法吗?

    STM32有方法可以使用手机APP,使用蓝牙或者WIFI 软件升级MCU软件的方法吗? 大家讨论一下,个人决定这个方向很好用,可能是以后的趋势。
    发表于 04-09 07:52

    请问有人用过瑞芯微自定义3A算法模块吗

    目前也研究了好阵了,想请教一下如何开发自己的3A算法库或者别的图像处理算法库。想和各位讨论一下
    发表于 01-25 10:15

    ubuntu和linux的区别

    Ubuntu和Linux是两个相关但不完全相同的概念,它们之间有着一些区别。在开始深入讨论Ubuntu和Linux之间的区别之前,让我们首先了解一下这两个概念的含义。
    的头像 发表于 11-27 17:06 885次阅读

    为什么要讨论用来升压的电荷泵电路呢?

    今天我们一起来讨论一下用来升压的 **电荷泵电路** (Charge Pump),也称为 **开关电容转换器** (Switched Capacitor Converter)。
    的头像 发表于 11-10 14:11 759次阅读
    为什么要<b class='flag-5'>讨论</b>用来升压的电荷泵电路呢?

    伺服控制系统,进线电压降低后,输出扭矩变没变?

    讨论一下,伺服控制系统,进线电压降低后,输出扭矩变没变? 例如840D系统,进线是380V,直流母线约为600V,到电机。 若进线电压变为220V,直流母线约为340V,那么电机输出扭矩会不会变呢?
    发表于 11-10 07:47

    什么是LDO?LDO中的噪声和PSRR介绍

    在本文中,我们将介绍噪声和电源抑制比 (PSRR) 在低压差 (LDO) 稳压器中的影响。让我们简要讨论一下什么是 LDO。
    的头像 发表于 09-26 14:29 2617次阅读
    什么是LDO?LDO中的噪声和PSRR介绍

    电路保护如何先躺赢,后躺平?

    电路保护如何先躺赢,后躺平?最近流行躺平,特别在大城市生活的苦难工程师兄弟姐妹,但又有几个人能真正做到躺平,年轻人的世界只有奋斗,先躺赢后躺平。由于
    的头像 发表于 08-24 08:03 471次阅读
    电路保护如何先躺赢,后<b class='flag-5'>躺平</b>?

    为什么Python没有main函数?

    今天的文章中,我们来讨论一下为什么有的编程语言有main函数,而Python为什么没有main函数。
    发表于 08-17 11:47 171次阅读

    离散小波变换的FPGA实现(一)

    在正式进入小波变换之前,我们不妨来讨论一下傅里叶变换的局限性和为什么我们需要引入小波变换。
    发表于 06-27 11:30 767次阅读
    离散小波变换的FPGA实现(一)

    如何实现新塘的vcom在Linux的Driver?

    开发用到NUC123 的vcom,现在移植到linux用,求高手指导一下如何实现新塘的vcom在Linux的 Driver
    发表于 06-19 10:24

    基于VN5650讨论一下以太网的配置与使用

    嵌入式开发,仿真环节至关重要。仿真,自然脱离不了仿真设备的使用,本文基于VN5650,讨论一下以太网的配置与使用。
    的头像 发表于 05-26 09:22 1687次阅读
    基于VN5650<b class='flag-5'>讨论一下</b>以太网的配置与使用

    介绍一下Linux内核中的各种

    Linux内核中有许多不同类型的锁,它们都可以用来保护关键资源,以避免多个线程或进程之间发生竞争条件,从而保护系统的稳定性和可靠性。
    的头像 发表于 05-16 14:13 3771次阅读

    讨论一下Yokogawa横河的AQ2180光波长计

    | AQ6150B:横河凭借着在光测试测量领域拥有的广泛客户经验,设计出了世界上可靠性最高且广泛通用的光波长计。 AQ6150系列具有特定的技术特点,完全有能力测量光子技术应用中使用的各种设备和系统
    发表于 05-16 11:54