Linux CPU Idle Time Management
CPU Idle Time ManagementCopyright © 2018 Intel Corp., Rafael J. Wysocki rafael.j.wysocki@intel.com文章目录CPU Idle Time ManagementConceptsLogical CPUsIdle CPUsThe Idle LoopIdle CPUs and The Scheduler Ti..
CPU Idle Time Management
Copyright © 2018 Intel Corp., Rafael J. Wysocki rafael.j.wysocki@intel.com
文章目录
Concepts
现代处理器通常能够进入暂停执行程序的状态,并且不从存储器中取出或执行属于它的指令。 这些状态是处理器的"idle"状态。
由于处理器硬件的一部分未在空闲状态下使用,进入idle状态通常允许处理器消耗的功率减少,因此这是节省能量的机会。
CPU idle time management 关注处理器空闲状态的能量效率。
Logical CPUs
运行在CPU上的CPU idle time management ,对CPU调度程序是可见的(这是负责系统中计算工作分配的内核部分)。在它看来,CPU是逻辑单位
。也就是说,它们不必是单独的物理实体,可能只是作为单独的单核处理器出现在软件上的接口。换句话说,CPU是一个实体,它从内存中获取属于一个序列(程序)的指令并执行它们,但它不需要在物理上以这种方式工作。通常,这里可以考虑三种不同的情况。
首先,如果整个处理器一次只能遵循一个指令序列(一个程序),那么它就是一个CPU。在这种情况下,如果要求硬件进入空闲状态,则这适用于整个处理器。
其次,如果处理器是多核的,则其中的每个核能够一次执行至少一个程序。核不需要完全相互独立(例如,它们可以共享高速缓存),但是大多数时候它们在物理上彼此并行工作,每一个都只执行一个程序,这些程序彼此独立运行。在这种情况下,所有的核都是CPU,如果要求硬件进入空闲状态,那么这适用于首先要求它的核,但它也可能适用于核归属的更大的单元(例如“包”或一个“集群”)。即如果较大单元中除一个之外的的所有core级的核都已经处于idle状态,未进入idle的核心要求处理器进入idle状态时,则可以触发较大单元进入idle状态。
最后,多核处理器中的每个核心可能能够在同一时间帧内执行多个程序(也就是说,每个核心可能能够从内存中的多个位置获取指令并在同一时间执行它们,当然不一定完全彼此平行)。在这种情况下,核作为“捆绑”呈现给软件,每个捆绑包由多个单独的“处理器”组成,即硬件线程(或特别是在英特尔硬件上的超线程),每个都可以执行指令。硬件线程是来自CPU空闲时间管理角度的CPU,如果要求处理器由其中一个进入空闲状态,则要求它的硬件线程停止,但是除非同一核心内的所有其他硬件线程也要求处理器进入空闲状态,否则不会发生任何其他情况。在那种情况下,核心可以单独进入空闲状态,或者包含它的较大单元可以作为整体进入空闲状态(如果较大单元内的其他核心已经处于空闲状态)。
Idle CPUs
逻辑CPU(以下简称为“CPU”)除了特殊的“空闲”任务外,没有任何任务可以运行时,被Linux内核视为Idle
。
任务是CPU调度程序的工作表示。 每个任务都包含执行或编码指令的序列,或运行该代码时要操作的数据,以及每次CPU运行任务代码时需要加载到处理器中的一些上下文信息。 CPU调度程序的工作就是将任务分配给系统中存在的CPU。
任务可以处于各种状态。 尤其,如果没有特定的条件(例如,他们不等待任何任何事件发生或类似)阻止他们的代码由CPU运行,只要有可用的CPU,它们就是runnable
。 当任务变为可运行时,CPU调度程序将其分配给一个可用CPU。如果没有分配更多可运行任务,CPU将加载给定任务的上下文并运行其代码(从目前为止执行的最后一个指令之后的指令,可能是另一个CPU处理的)。 如果同时为一个CPU分配了多个可运行的任务,它们将受到优先级和时间共享的限制,以便它们能够随着时间的推移取得一些进展。
如果没有其他可运行的任务分配给给定的CPU,则特殊的“空闲”任务变为可运行,这时CPU被视为空闲。 换句话说,在Linux中,idle CPU运行称为the idle loop
的idle
任务的代码。 该代码可能导致处理器进入其空闲状态之一(如果它们受支持),以节省能量。如果处理器不支持任何空闲状态,或者在下一个唤醒事件之前没有足够的空闲时间 ,或者有严格的延迟约束阻止任何一个被使用的空闲状态时,CPU将简单地在循环中执行或多或少的无用指令,直到为其分配新的任务来运行。
The Idle Loop
The idle loop
代码在每次迭代中都需要两个主要步骤。 首先,它调用一个称为governor
的代码模块,它属于被称为CPUIdle
的CPU空闲时间管理子系统,用于为CPU选择要求硬件进入的空闲状态。 其次,它调用来自CPUIdle
子系统的另一个被称为driver
模块,去真正的要求处理器硬件进入governor选择的空闲状态。
governor 的作用是找到最适合当前条件的闲置状态。 为此,CPU请求硬件进入的空闲状态以独立于平台或处理器体系结构的抽象方式表示,并以一维方式组织(线性)数组。 该数组必须由CPUIdle
驱动程序准备和提供,该驱动程序与初始化时内核运行的平台相匹配。 这使得CPUIdle
governor 可以独立于底层硬件,并适用于任何运行Linux内核的平台。
这个数组中的每个空闲状态的特征在于由governor 考虑的两个参数,目标驻留
和(最坏情况)退出等待时间
。 目标驻留时间是硬件在该状态下必须花费的最短时间,包括进入它所需的时间(可能是实质性的),以便通过输入较浅的空闲状态而节省更多的能量。 [空闲状态的“深度”大致对应于处理器在该状态下绘制的功率。]退出延迟是指从CPU要求处理器硬件进入空闲状态到从该状态唤醒后开始执行第一条指令所需的最长时间。 请注意,一般情况下,退出延迟还必须涵盖进入给定状态所需的时间,如果在硬件进入时发生唤醒,则必须完全进入才能以有序方式退出。
有两种信息可以影响governor的决策。首先,governor知道最近的计时器事件的时间。因为内核管理定时器,它确切地知道它们将触发的时间。这是CPU可以在空闲状态下花费的最长时间,包括进入和退出它所需的时间。然而,CPU可以在任何时间(特别是在最接近的定时器触发之前)被非定时器事件唤醒,并且通常不知道何时可能发生这种情况。governor只能看到CPU被唤醒后实际空闲的时间(该时间将被称为空闲持续时间从现在开始)并且它可以以某种方式使用该信息以及直到最近的计时器来估计将来的空闲持续时间的时间。governor如何使用该信息取决于它实现了什么算法,这是在CPUIdle
子系统中拥有多个调控器的主要原因。
有两个CPUIdle
governor,menu
和ladder
。使用它们中的哪一个取决于内核的配置,特别是调度器tick是否可以被空闲循环<idle-cpus-and-tick_>_停止。如果将cpuidle_sysfs_switch
命令行参数传递给内核,则可以在运行时更改governor,但这通常不安全,因此不应在生产系统上完成(可能会在生产系统中更改)。未来,内核当前使用的CPUIdle
调控器的名称可以从:/ sys / devices / system / cpu / cpuidle /
current_governor_ro中读取(或者:current_governor
,如果cpuidle_sysfs_switch
出现在内核命令行)。
另一方面,使用哪种CPUIdle
驱动程序通常取决于内核运行的平台。有两个驱动程序可以适用大多数英特尔平台,intel_idle
和acpi_idle
,一个用硬编码的空闲状态信息和另一个能够读取来自系统的ACPI表。不过,即使在那些情况下,也是如此在系统初始化时选择的驱动程序以后不能替换,所以决定使用哪一个必须尽早(在英特尔平台上)如果对某些人禁用intel_idle
,则会使用acpi_idle
驱动程序原因或者如果它不能识别处理器)。内核当前使用的驱动程序的名称可以从:/ sys / devices / system / cpu / cpuidle /
current_driver`中读取。
Idle CPUs and The Scheduler Tick
scheduler tick是定期触发的计时器,为了实现CPU调度程序的时间共享。 当然,如果同时为一个CPU分配了多个可运行任务,那么允许它们在给定时间范围内取得合理处理的唯一方法就是使它们共享可用的CPU时间。 也就是说,在粗略的近似中,每个任务都有一段CPU时间片来运行其代码,受制于调度类,优先级等等,当该时间片用完时,CPU应该切换到另一个任务的运行(代码)。 无论如何,scheduler tick是为了使切换发生。 这不是tick的唯一作用,但这是使用它的主要原因。
从CPU空闲时间管理的角度看,scheduler tick是有问题的,因为它会定期且相对频繁地触发(取决于内核配置,tick周期的长度在1 ms到10 ms之间)。因此,如果允许tick 在空闲CPU上触发,要求硬件进入空闲状态并且目标驻留在tick周期长度以上是没有意义的。 此外,在这种情况下,任何CPU的空闲持续时间将永远不会超过tick周期长度,并且由于空闲CPU上的tick唤醒而浪费用于进入和退出空闲状态的能量。
幸运的是,没有必要允许tick在空闲CPU上触发,因为(根据定义)除了特殊的“空闲”之外,它们没有任何运行任务。 换句话说,从CPU调度程序的角度来看,CPU时间的唯一用户是The idle loop
。 由于空闲CPU的时间不需要在多个可运行的任务之间共享,因此如果给定的CPU空闲,则使用滴答的主要原因就会消失。 因此,对于空闲CPU上,原则上可以完全停止scheduler tick,即使这可能并不总是值得。
是否在空闲循环中停止scheduler tick是有意义的,取决于governor的期望。首先,如果还有另一个(non-tick) 计时器由于在tick范围内触发,清楚地停止tick即使计时器硬件可能不需要,也会浪费时间在那种情况下重新编程。其次,如果governor期待非计时器在tick范围内唤醒,停止tick是没有必要的,甚至可能有害。即,在这种情况下,governor将选择空闲状态在预期唤醒之前的目标驻留时间,所以状态会比较浅。因此,governor实际上无法选择深度闲置状态,因为这会违背其自身对短期唤醒的期望。现在,如果唤醒确实很快发生,停止tick将是时间浪费,在这种情况下,计时器硬件需要重新编程,代价很昂贵。另一方面,如果tick停止并且唤醒不会很快发生,硬件可能会花费无限的时间在governor选择的浅空闲状态下,这将是浪费能源。因此,如果governor期待在tick范围内发生任何形式的唤醒,最好允许tick触发。否则,调控器将选择一个相对较深的空闲状态,并且应该停止滴答这样它就不会太早唤醒CPU。
在任何情况下,governor 都知道它期望什么,关于是否停止scheduler tick的决定属于它。但是,如果已经停止了tick(在循环的前一次迭代中),最好保持原样,并且governor 需要考虑到这一点。
可以将内核配置为禁用完全停止空闲循环中的scheduler tick。这可以通过它的构建时配置来完成(通过取消设置CONFIG_NO_HZ_IDLE
配置选项)或通过在命令行中nohz = off
。在这两种情况下,由于禁用了scheduler tick的停止,因此调度器关于它的决定被空闲循环代码简单地忽略,并且tick从不停止。
运行配置为允许scheduler tick在空闲CPU上停止的系统,称为tickless
系统,并且它们通常被认为比运行不能停止tick的内核的系统更节能。如果给定的系统是无tick的,它默认情况下将使用menu
调控器,如果它不是tickless,它上面的默认CPUIdle
调控器将是ladder
。
The menu
Governor
menu
governor 是tickless 系统的默认CPUIdle
governor 。它非常复杂,但其设计的基本原理很简单。即,当被调用以选择CPU的空闲状态时(即 CPU将要求处理器硬件进入的空闲状态),它尝试预测空闲持续时间并使用预测值进行空闲状态选择。
它首先获得直到最接近的计时器事件的时间,并假设scheduler tick将被停止。 该时间,在下文中称为睡眠长度,是下一次CPU唤醒之前的时间的上限。 它用于确定睡眠长度范围,而睡眠长度范围又需要获得睡眠长度校正因子。
menu
governor 维护两个睡眠长度校正因子数组。当先前在给定CPU上运行的任务等待某些I / O操作完成时使用其中一个,而当不是那种情况时,使用另一个 数组。 每个数组包含若干校正因子值,这些校正因子值对应于组织的不同睡眠长度范围,使得数组中表示的每个范围比前一个宽约10倍。
在唤醒CPU之后更新给定睡眠长度范围的校正因子(在为CPU选择空闲状态之前确定),并且睡眠长度越接近观察到的空闲持续时间,校正因子变得越接近1 (它必须介于0和1之间)。 睡眠长度乘以其落入的范围的校正因子,以获得预测的空闲持续时间的第一近似值。
接下来,governor 使用简单的模式识别算法来改进其空闲持续时间预测。即,它保存最后8个观察到的空闲持续时间值,并且当下次预测空闲持续时间时,它计算它们的平均值和方差。如果方差小(小于400平方毫秒)或相对于平均值小(平均值大于标准偏差的6倍),则平均值被视为“典型间隔”值。否则,丢弃保存的观察到的空闲持续时间值中最长的一个,并对剩余的值重复计算。同样,如果它们的方差很小(在上述意义上),则平均值为作为“典型间隔”值等,直到确定“典型间隔”或忽略太多数据点为止,在这种情况下,假设“典型间隔”等于“无穷大”(最大无符号整数值) )。将以这种方式计算的“典型间隔”与睡眠长度乘以校正因子进行比较,并将两者中的最小值作为预测的空闲持续时间。
然后,governor 计算额外的延迟限制以帮助“交互式”工作负载。它使用的观察结果是,如果所选空闲状态的退出等待时间与预测的空闲持续时间相当,则在该状态下花费的总时间可能非常短,并且通过输入它所节省的能量将相对较小,因此可能最好避免与进入该状态并退出该状态相关的开销。因此,选择较浅的状态可能是更好的选择。额外延迟限制的第一个近似值是预测的空闲持续时间本身,其另外除以一个值,该值取决于先前在给定CPU上运行的任务的数量,现在它们正在等待I / O操作完成。将该除法的结果与来自电源管理服务质量的延迟限制或“PM QoS <cpu-pm-qos_>`_,框架进行比较,并将两者中的最小值作为空闲状态的限制’退出延迟。
现在,governor 准备遍历闲置状态列表并选择其中一个。 为此,它将每个状态的目标驻留时间与预测的空闲持续时间及其退出延迟与计算的延迟限制进行比较。 它选择目标驻留时间最接近预测的空闲持续时间但仍低于该状态的状态,并且退出延迟不超过限制。
在最后一步中,如果governor 还没有决定 停止 scheduler tick <idle-cpus-and-tick_>
`,那么governor 可能仍然需要优化空闲状态选择。 如果由它预测的空闲持续时间小于tick 周期并且tick 尚未停止(在空闲循环的先前迭代中),则会发生这种情况。 然后,在先前计算中使用的睡眠长度可能不会反映直到最接近的计时器事件的实际时间,并且如果它确实大于该时间,则调控器可能需要选择具有合适的目标驻留的较浅状态。
Representation of Idle States
出于CPU空闲时间管理目的,处理器支持的所有物理空闲状态必须表示为cpuidle_state结构体的一维数组。,每个状态允许单个(逻辑)CPU请求处理器硬件进入某些属性的空闲状态。如果处理器中存在单元层次结构,则为一个cpuidle_state对象可以覆盖由层次结构的不同级别的单元支持的空闲状态的组合。 在这种情况下,它的目标驻留和退出等待时间参数<idle-loop_>必须反映最深层的空闲状态的属性(即包含所有其他单元的空闲状态)。
例如,将一个具有两个核心的处理器放在一个更大的单元中,称为“模块”。当硬件在一个核(“core” level)进入特定的空闲状态(比如“X”)且另一个核已经处于空闲状态“X”时,则触发模块进入其自身的特定空闲状态(例如“MX”)。换句话说,在"core" level请求空闲状态“X”使硬件获得在"module" level上与空闲状态“MX”一样深的许可,但不能保证这一定发生(要求空闲状态“X”的核可能会自己中止该状态)。然后,表示空闲状态“X”的cpuidle_state 中的目标驻留时间必须反映在模块的空闲状态“MX”中花费的最短时间(包括进入它所需的时间),因为这是CPU需要空闲以节省任何能量时进入该状态的最短时间。类似地,该对象的退出延迟参数必须覆盖模块的空闲状态“MX”的退出时间(并且通常也包括其进入时间),因为这是唤醒信号到CPU将开始执行第一条新指令(假设一旦模块整体运行,模块中的两个核心将始终准备好执行指令)的最大延迟。
但是,有些处理器在它们内部的单元层次结构的不同级别之间没有直接协调。 在那些情况下,在“核心”级别请求空闲状态不会自动影响“模块”级别,例如,以任何方式,“CPUIdle”驱动程序负责整个层次结构的处理。 然后,空闲状态对象的定义完全取决于驱动程序,但处理器硬件最终进入的空闲状态的物理属性仍必须始终遵循调控器用于空闲状态选择的参数(例如, 实际退出该空闲状态的等待时间不得超过由调控器选择的空闲状态对象的退出等待时间参数。
除了上面讨论的目标驻留和退出等待时间空闲状态参数之外,表示空闲状态的对象每个包含描述空闲状态的一些其他参数和指向要运行的函数的指针以便要求硬件进入该状态。 另外,对于每个cpuidle_state对象,有一个对应的cpuidle_state_usage结构体:包含给定空闲状态的使用统计信息, 内核通过sysfs
公开了这些信息。
对于系统中的每个CPU,在sysfs
中都有一个/ sys / devices / system / cpu <N> / cpuidle /
目录,其中数字<N>
在初始化时分配给特定的CPU。 该目录包含一组名为state0
、state1
等的子目录,最多为给定CPU定义的空闲状态对象数减1。 这些目录中的每一个对应于一个空闲状态对象,并且其名称中的数字越大,由其表示的(有效)空闲状态越深。 它们中的每一个都包含许多文件(属性),表示与其对应的空闲状态对象的属性,如下所示:
above
Total number of times this idle state had been asked for, but the
observed idle duration was certainly too short to match its target
residency.
below
Total number of times this idle state had been asked for, but cerainly
a deeper idle state would have been a better match for the observed idle
duration.
desc
该空闲状态的描述
disable
该空闲状态是否被禁止
latency
该空闲状态的退出延迟(单位:微妙)
name
该空闲状态的名字
power
硬件在这种空闲状态下以毫瓦为单位的功率 (如果有的话,否则为0).
residency
该空闲状态的目标停留时间 (单位:微妙)
time
目标CPU花费在该空闲状态总共的时间 (as measured by the kernel,单位微妙).
usage
进入该空闲状态的总次数
desc
和name
文件都包含字符串。 它们之间的区别在于名称应该更简洁,而描述可能更长,它可能包含空格或特殊字符。上面列出的其他文件包含整数。
disable
是唯一可写的属性。 如果它为1,则对于此特定CPU禁用给定的空闲状态,这意味着governor 永远不会为此特定CPU选择它,并且CPUIdle
驱动程序永远不会要求硬件为该CPU进入该状态。 但是,禁用一个CPU的空闲状态不会阻止其他CPU请求它,因此必须为所有CPU禁用该状态,以便它们中的任何一个都不会被要求。 [注意,由于ladder
governor 的实现方式,禁用一个空闲状态会阻止governor 选择比禁用状态更深的任何空闲状态。
如果disable
属性为0,则为此特定CPU启用给定的空闲状态,但同时仍可能被系统中的部分或全部其他CPU禁用。 向其写入1将导致对此特定CPU禁用空闲状态,并向其写入0允许governor 将其考虑在内,以便给定CPU和驱动程序请求该状态,除非在驱动程序中全局禁用该状态( 在这种情况下,它根本不能使用)。
power
属性定义不是很好,特别是对于处理器中单元层次结构不同级别的空闲状态组合,并且通常很难获得复杂硬件的空闲状态功率 。power
经常为0(不可用),如果它为非零数字,那么这个数字可能不是很准确,不应该依赖于任何有意义的数字。
time
节点中的数字通常可能大于给定CPU在给定空闲状态下实际花费的总时间,因为它是由内核测量的,可能不包括硬件拒绝进入这个空闲状态并进入一个较浅的状态而不是它(甚至它根本没有进入任何空闲状态)的情况。内核只能测量要求硬件进入空闲状态和随后的CPU唤醒之间的时间跨度,并且它无法说明同时在硬件级别发生了什么。此外,如果所讨论的空闲状态对象表示处理器中单元层次结构的不同级别的空闲状态的组合,内核在任何特定情况下都不能说硬件在层次结构中有多深。由于这些原因,找出硬件在其支持的不同空闲状态下花费了多少时间的唯一可靠方法是在硬件中使用空闲状态停留时间计数器(如果可用)。
Power Management Quality of Service for CPUs
Linux内核中的电源管理服务质量(PM QoS)框架允许内核代码和用户空间进程对内核的各种能效特性设置约束,以防止性能降至所需级别以下。 PM QoS约束可以在称为PM QoS类的预定义类别中全局设置,或者针对各个设备设置。
CPU空闲时间管理可以通过两种方式受到PM QoS的影响,通过“PM_QOS_CPU_DMA_LATENCY”类中的全局约束以及各个CPU的恢复延迟约束。内核代码(例如设备驱动程序)可以借助PM QoS框架提供的特殊内部接口来设置它们。用户空间可以通过在/ dev /
下打开cpu_dma_latency
特殊设备文件并将二进制值(解释为带符号的32位整数)写入其中来修改前者。反过来,通过将一个字符串(表示一个带符号的32位整数)写入power / pm_qos_resume_latency_us
文件,可以通过用户空间修改CPU的恢复延迟约束/ sys / devices /系统/ cpu / cpu <N> /
。在两种情况下都将拒绝负值,并且在两种情况下,写入的整数将被解释为请求的PM QoS约束(以微秒为单位)。
但是,请求的值不会自动应用为新约束,因为它可能比其他人先前请求的另一个约束更少限制(在此特定情况下更大)。 因此,PM QoS框架维护到目前为止在每个全局类和每个设备中生成的请求列表,聚合它们并将有效(在此特定情况下的最小值)值应用为新约束。
事实上,打开cpu_dma_latency
设备文件会导致创建一个新的PM QoS请求,并加入到PM_QOS_CPU_DMA_LATENCY
类中的请求优先级列表中,并从“打开”操作拿到的文件描述符代表该请求。如果该文件描述符随后用于写入,则写入其的数字将与由其表示的PM QoS请求相关联,作为新请求的约束值。接下来,优先级列表机制将用于确定整个请求列表的新有效值,并且该有效值将被设置为新约束。因此,如果有效“列表”值受其影响,则设置新请求的约束值将仅更改实际约束。特别是,对于PM_QOS_CPU_DMA_LATENCY
类,如果它是列表中请求的约束的最小值,它仅影响实际约束。通过打开cpu_dma_latency
特殊设备文件获得的文件描述符的进程通过关联的文件描述符控制PM QoS请求,但它仅控制此特定PM QoS请求。
关闭cpu_dma_latency
特殊设备文件,或者更确切地说,关闭打开它时获得的文件描述符,导致该文件描述符关联的PM QoS请求将从PM_QOS_CPU_DMA_LATENCY
类优先级列表删除并销毁。如果发生这种情况,优先级列表机制将再次确定整个列表的新有效值而这个价值将成为新的真正约束。
反过来,对于每个CPU,只有一个与/ sys / devices / system / cpu / cpu <N> /power /pm_qos_resume_latency_us
文件相关联的恢复延迟PM QoS请求,写入它会导致更新单个PM QoS请求,无论哪个用户空间进程执行此操作。换句话说,该PM QoS请求由整个用户空间共享,因此需要仲裁对与其相关联的文件的访问避免混淆。 [可以说,在实践中唯一合法使用这种机制的方法是将一个进程固定到有问题的CPU上,并让它使用sysfs
接口来控制它的恢复延迟约束。]它仍然只是一个请求,然而。它是优先级列表的成员,用于确定每次以这种方式(或者可能有来自内核代码的其他请求)更新请求列表时要为有关CPU设置的恢复延迟约束的有效值。
CPU空闲时间governors 应该将全局有效“PM_QOS_CPU_DMA_LATENCY”类限制的最小值,并且给定CPU的有效恢复延迟约束视为它们可以为该CPU选择的空闲状态的退出延迟的上限。 他们永远不应该选择退出延迟超过该限制的任何空闲状态。
Idle States Control Via Kernel Command Line
除了sysfs
接口允许对各个CPU 禁用各个空闲状态外,影响CPU空闲时间管理的还有内核命令行参数。
cpuidle.off = 1
内核命令行选项可用于完全禁用CPU空闲时间管理。 它不会阻止空闲循环在空闲CPU上运行,但它会阻止调用CPU空闲时间governors 和驱动程序。 如果将其添加到内核命令行,则空闲循环将要求硬件通过CPU架构支持代码进入空闲CPU上的空闲状态,该代码期望为此提供默认机制。 这种默认机制通常是实现所讨论的架构(即CPU指令集)的所有处理器的最小公分母,因此它是相当粗糙的并且不是非常节能的。 因此,不建议使用。
cpuidle.governor =
内核命令行开关允许指定CPUIdle
调控器。 它必须附加一个匹配可用调控器名称的字符串(例如cpuidle.governor = menu
),并且将使用该调控器而不是默认调控器。 有可能强迫,默认情况下使用ladder
调控器的系统上使用menu
调控器。
下面描述的其他控制CPU空闲时间管理内核命令行参数仅与x86
架构相关,仅影响Intel处理器。
x86
体系结构支持代码识别与CPU空闲时间管理相关的三个内核命令行选项:idle = poll
,idle = halt
,和idle = nomwait
。前两个禁用acpi_idle
和intel_idle
驱动程序,导致整个CPUIdle
子系统完全有效地被禁用并使空闲循环调用架构支持代码来处理空闲CPU。它是如何做到的取决于将哪两个参数添加到内核命令行。在idle = halt
时,架构支持代码将使用HLT
CPU的指令(通常暂停程序的执行,并导致硬件尝试进入最浅的可用空闲状态),如果使用idle = poll
,空闲CPU将在紧密循环中执行或多或少的“轻量级”指令序列。 [注意:在许多情况下使用idle = poll
有点激烈,因为阻止空闲CPU去节省几乎任何能量,但这可能不是它的唯一影响。例如,在英特尔硬件上,它可以有效地阻止CPU使用需要包中的任意数量的CPU空闲的P-states(参见| cpufreq |),所以很可能会损害单线程计算性能以及能源效率。因此,出于性能原因使用它可能也不是一个好主意。]
idle = nomwait
选项禁用intel_idle
驱动程序并使用acpi_idle
(只要它所需的所有信息都是
在系统的ACPI表中),但不允许使用CPU的MWAIT
指令要求硬件进入空闲状态。
除了体系结构级内核命令行选项影响CPU空闲时间管理之外,有影响个别CPUIdle
的参数可以通过内核命令行传递给它们的驱动程序。特别,intel_idle.max_cstate = <n>
和processor.max_cstate = <n>
参数,其中<n>
是一个空闲状态索引,导致intel_idle
和acpi_idle
驱动程序分别放弃所有比空闲状态更深<n>
的空闲状态。在那种情况下,他们永远不会请求任何这些空闲状态或将其暴露给governor。[两个驱动程序行为的不同之处在于<n>
等于0
时。添加intel_idle.max_cstate = 0
到内核命令行禁用intel_idle
驱动程序,允许使用acpi_idle
,而processor.max_cstate = 0
相当于processor.max_cstate = 1
。此外,acpi_idle
驱动程序是processor
内核模块的一部分可以单独加载,max_cstate = <n>
可以作为模块传递给它加载时的参数。]
更多推荐
所有评论(0)