HACK#42 使用CPU省电(C、P状态)
本节介绍使用C状态和P状态的CPU省电方法。
C状态的使用方法
C状态是CPU空闲时的电力状态。通过设置为更深的C状态就可以减少电能消耗。C状态的层次越深入,C状态将停止更多CPU功能,因此C状态的层次越深,从空闲状态恢复的时间越长。ACPI中从C状态的恢复基本上是以中断为契机进行的。因此,降低中断频率可以让C状态持续更长时间,从而抑制电能消耗。
ACPI具有两个用来控制C状态的接口。
1.Processor寄存器块(P_BLK)的P_LVL2和P_LVL3寄存器。
2.定义块中定义的处理器的对象列表的_CST对象。
使用_CST的C状态控制对使用P_BLK的控制进行了扩展。它可以使用称为Functional固定硬件(FFH)接口的厂商固有接口。可以根据CPU架构使用C状态,如Intel公司的CPU使用的就是MWAIT命令等。从而可以使用ACPI中未定义的C状态。_CST对象针对各个状态分别定义了下列内容。
Linux中有用来控制包括x86在内的各种CPU空闲状态的cpuidle子系统。通过cpuidle子系统可以设置CPU空闲时的轮询(polling)方法和策略(governor)。从而可以将每个CPU的空闲状态的特性抽象化,使用CPU固有功能或ACPI的功能。
控制Linux的cpuidle的用户接口位于/sys/devices/system/cpu/cpuidle/下。各接口的说明如下所示。
Linux中现有策略列表如下。
menu策略从中断等情况预测可以休眠的时间,选择与该休眠时间相符的最深C状态。使用CPU负载、中断、I/O负载等进行预测。
基本上可以使用默认的cpuidle的策略来控制电能消耗。策略虽然有在运行中可以变更的接口,但切换的接口是面向开发者的,启动中不应进行切换。
每个CPU的C状态信息可以从/sys/devices/system/cpu/cpuN/cpuidle/stateM/下获取(N、M为整数。N为CPU编号,M为C状态的状态编号)。
除sysfs以外,还有可以通过proc文件系统参照的信息。其示例如下所示。/proc/acpi/processor/cpuN/power(N为CPU编号)。
cat/proc/acpi/processor/CPU0/power
active state:C0
max_cstate:C8
maximum allowed latency:2000000000 usec
states:
C1:type[C1]promotion[—]demotion[—]latency[001]
usage[00008972]duration[00000000000000000000]
C2:type[C2]promotion[—]demotion[—]latency[001]
usage[00339308]duration[00000000000238036741]
C3:type[C3]promotion[—]demotion[—]latency[017]
usage[05986201]duration[00000000089960255002]
cat/proc/acpi/processor/CPU0/info
processor id:0
acpi id:0
bus mastering control:yes
power management:yes
throttling control:no
limit interface:no
关于sched_mc_power_savings、sched_smt_power_savings
/sys/devices/system/cpu下存在sched_mc_power_savings、sched_smt_power_savings这些对进程调度程序进行调整的参数。它们可以在多核、同时多线程(Intel Hyper-threading等)的CPU中发挥作用。
sched_mc_power_savings
设置为0或1。设置为1时,进程调度程序尽量仅针对某个特定CPU套接字调度进程数。只有在运行中的所有内核都繁忙时,才能对位于其他CPU套接字的核进行进程调度。这在每个核具有各自的C状态,所有的核超过某个特定C状态才能进入更深C状态的CPU中有效。
sched_smt_power_savings
设置为0或1。设置为1时,进程调度程序尽量仅对位于某个特定内核的线程进行调度。只有在运行中的所有线程繁忙时,才对其他内核的线程进行调度。这与上述sched_mc_power_savings同样,对于每个线程具有各自的C状态的CPU有效。
Linux下x86 CPU中的C状态运行情况如下所示。
1.Linux下一旦变成空闲状态,就会调度idle进程,调用pm_idle函数。
2.在使用cpuidle子系统的系统下,pm_idle调用cpuidle_idle_call()。
3.cpuidle_idle_call()中通过cpuidle governor的select方法选择下一个状态。
4.每个状态各自调用登录的enter方法,迁移到所选择的状态。
想要确保CPU的bug和应答性时,有时需要限制C状态。这时通过使用max_cstate这一内核启动参数,就可以限制C状态的最大值。向max_cstate输入希望使用的最深层的C状态的值。将CI设置为最大值时,在/etc/grub.conf中设置max_cstate=1。
title Fedora(2.6.35.12-88.fc14.i686)
root(hd0,0)
kernel/boot/vmlinuz-2.6.35.12-88.fc14.i686 ro root=UUID=82f8f09d-b0d7-49ee-a57b-13e6484bd840 rd_NO_LUKS rd_NO_LVM rd_NO_MD rd_NO_DM LANG=ja_JP.UTF-8 KEYTABLE=jp106 rhgb quiet processor.max_cstate=1
initrd/boot/initramfs-2.6.35.12-88.fc14.i686.img
title Fedora(2.6.35.11-83.fc14.i686)
使用max_cstate后,可以在/proc/acpi/processor/CPUN/power(N为CPU编号)确认max_cstate已变更。
cat/proc/acpi/processor/CPU0/power
active state:C0
max_cstate:C1
maximum allowed latency:2000000000 usec
states:
C1:type[C1]promotion[—]demotion[—]latency[001]
usage[00000000]duration[00000000000000000000]