CPU C-state & cpuidle driver[通俗易懂]

CPU C-state & cpuidle driver[通俗易懂]1.什么是C-states、C-mode?为了在CPU空闲时节约能源,可以命令CPU进入低功耗模式。C-state是intelCPU处于空闲时的一种状态,CPU有几种电源模式,它们统称为“c状态”或“c模式”低功耗模式最初是在486DX4处理器中引入的。到目前为止,已经引入了更多的功耗模式,并且对每种模式进行了增强,以使CPU在这些低功耗模式下消耗更少的功率。CPU的每个状态都使用不同的电量,并且对应用程序性能的影响也不同。每当CPU内核处于空闲状态时,内置的节能逻辑就会启动,并尝试将内核从当前

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

1. 什么是C-states、C-mode?

为了在CPU空闲时节约能源,可以命令CPU进入低功耗模式。C-state是intel CPU处于空闲时的一种状态,CPU有几种电源模式,它们统称为“c状态”或“c模式”

低功耗模式最初是在486DX4处理器中引入的。到目前为止,已经引入了更多的功耗模式,并且对每种模式进行了增强,以使CPU在这些低功耗模式下消耗更少的功率。

CPU的每个状态都使用不同的电量,并且对应用程序性能的影响也不同。
每当CPU内核处于空闲状态时,内置的节能逻辑就会启动,并尝试将内核从当前的C状态转换为更高的C状态,从而关闭各种处理器组件以节省功耗

但是你还需要了解,每次应用程序尝试在一个CPU来执行某些任务时,相应的CPU必须从其“更深的睡眠状态”返回到“运行状态”,这需要更多时间来唤醒计算机。 CPU并再次100%启动并运行。这个过程还必须在原子环境中完成,以便在启动CP U核心时没有任何人尝试使用cpu核心。

因此,CPU过渡到的各种C模式称为C-state。
它们通常从C0开始,但C0比较特殊,它正常的CPU工作模式,即CPU已100%的开启。
随着C-state级别的增加,CPU睡眠模式会更深,即,更多的电路和信号将被关闭,并且CPU需要更多的时间才能返回到C0模式(即唤醒)。
每种模式也有一个名称,其中每个c-state具有不同的省电策略,有些c级别还有不同的子模式。

下面链接有各级别cstate说明,intel手册上也有详细描述。

https://access.redhat.com/solutions/202743

mode	Name	What id does	CPUs
C0	Operating State	CPU fully turned on	All CPUs
C1	Halt	Stops CPU main internal clocks via software; bus interface unit and APIC are kept running at full speed	486DX4 and above
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	All socket 775 CPUs
C1E	--	Stops all CPU internal clocks	Turion 64, 65-nm Athlon X2 and Phenom CPUs
C2	Stop Grant	Stops CPU main internal clocks via hardware; bus interface unit and APIC are kept running at full speed	486DX4 and above
C2	Stop Clock	Stops CPU internal and external clocks via hardware	Only 486DX4, Pentium, Pentium MMX, K5, K6, K6-2, K6-III
C2E	Extended Stop Grant	Stops CPU main internal clocks via hardware and reduces CPU voltage; bus interface unit and APIC are kept running at full speed	Core 2 Duo and above (Intel only)
C3	Sleep	Stops all CPU internal clocks	Pentium II, Athlon and above, but not on Core 2 Duo E4000 and E6000
C3	Deep Sleep	Stops all CPU internal and external clocks	Pentium II and above, but not on Core 2 Duo E4000 and E6000; Turion 64
C3	AltVID	Stops all CPU internal clocks and reduces CPU voltage	AMD Turion 64
C4	Deeper Sleep	Reduces CPU voltage	Pentium M and above, but not on Core 2 Duo E4000 and E6000 series; AMD Turion 64
C4E/C5	Enhanced Deeper Sleep	Reduces CPU voltage even more and turns off the memory cache	Core Solo, Core Duo and 45-nm mobile Core 2 Duo only
C6	Deep Power Down	Reduces the CPU internal voltage to any value, including 0 V	45-nm mobile Core 2 Duo only
C7	Deep Energy Saving	The CPU tries to flush its L3 cache. If the L3 cache is able to be entirely cleared, the CPU cuts its power to save energy. The power from the system agent is removed too.	—
C7s	—	When an MWAIT(C7) command is issued with a C7s sub-state hint, the entire L3 cache is flushed in one step as opposed to flushing the L3 cache in multiple steps. This also allows the system to send I/O devices to low power mode to reduce unnecessary power consumption when the system idles down.	—
C8	—	The L3 cache is flushed in a single step. The power to the PLL is cut.	—
C9	—	The VCCIN (VCC Input Voltage) gets lowered to a minimum.	—
C10	—	The single phase core management system, VR12.6, goes into a low-power state. The CPU is almost shut down.	—

Jetbrains全家桶1年46,售后保障稳定

2. 如何禁用处理器睡眠状态?

对延迟敏感的应用程序不希望处理器进入到更深的C状态,因为从C状态返回到C0会引起延迟。这些延迟的范围可以从数百微秒到毫秒。

有几种方法可以实现此目的。

方法1

通过使用内核命令行参数processor.max_cstate = 0、intel_idle.max_cstate=0进行引导,让系统不进入深度的C状态。可以在grub2文件中添加这些变量。

**为什么要设置2个参数,分别代表什么? **

具体作用:
1)intel_idle.max_cstate=0
在intel平台上,模式会使用intel cpuidle drviver,intel_idle.max_cstate=0 意味着禁用intel cpuidle driver,让其退化使用acpi driver。

2)processor.max_cstate=0
processor.max_cstate=0用描述acpi driver中cpu cstate的最大级别,但是实际max_cstate=0并不能真的让CPU保持在C0态,只能让CPU保持在C1状态。如下代码:

Note that intel_idle.max_state = 0 disables intel_idle and lets acpi_idle (processor.max_state) take over.

vim /usr/src/debug/kernel-3.10.0-693.19.1.el7/linux-3.10.0-693.19.1.el7.x86_64/drivers/idle/intel_idle.c
(... set number ...)
 889 /*
 890  * intel_idle_probe()
 891  */
 892 static int __init intel_idle_probe(void)
 893 {
 894         unsigned int eax, ebx, ecx;
 895         const struct x86_cpu_id *id;
 896 
 897         if (max_cstate == 0) {
 898                 pr_debug(PREFIX "disabled\n");
 899                 return -EPERM;
 900         }
(...)

looking at the acpi processor_idle code:

Raw
vim /usr/src/debug/kernel-3.10.0-693.19.1.el7/linux-3.10.0-693.19.1.el7.x86_64/drivers/acpi/processor_idle.c
(... set number ...)
 915         if (max_cstate == 0)
 916                 max_cstate = 1;
(...)

the acpi_idle driver doesn’t allow locking to C0, i.e. the effect of the following two boot command lines is the same:

processor.max_cstate=0 intel_idle.max_cstate=0
processor.max_cstate=1 intel_idle.max_cstate=0 (与上面等效)

方法2

第二种方法是使用电源管理服务质量接口(PM QOS)。

文件**/dev/cpu_dma_latency**是一个字符设备,当打开该接口时,它会注册一个服务质量请求以请求操作系统的延迟。

程序应打开**/dev/cpu_dma_latency**,向其写入一个32位数字,该数字表示最大响应时间(以微秒为单位),写入零表示您想要最快的响应时间。
通常cpu_dma_latency被系统tuned服务使用,通过配置文件来修改cpu _dma_latency的值,下面是是tuned配置文件中的一部分:

[cpu]  
force_latency = 1

通常只要调整latency后,cpu_dma_latency文件处于激活状态,该文件描述符将始终处于打开状态

[root@localhost ~]# lsof | grep cpu_dma
tuned    1709   root   11w     CHR   10,61   0t0   2219  /dev/cpu_dma_latency

tuned的配置文件将force_latency写为1,作用:以确保CPU C-state不会进入除C1之外的更深的C状态。

3. 如何读取及解释/dev/cpu_dma_latency?

我们可以使用hexdump工具来读此文件,如下示例:

[root@localhost ~]# cat /dev/cpu_dma_latency 
�5w[root@localhost ~]#
[root@localhost ~]# hexdump /dev/cpu_dma_latency 
0000000 9400 7735                              
0000004
[root@localhost ~]# echo $((0x77359400))
2000000000
[root@localhost ~]#

cpu_dma_latency反馈的数值,表示当前等待时间值为2000秒,这是CPU从较深的C状态变为C0所需或需要的时间。

在RedHat 7上,默认设置为2000秒。我们使用force_latency = 1设置调整cpu_dma_latency时,可以用tuned-adm命令来调整。

例如,我们设置tuned模式为latency-performance:

[root@localhost ~]# tuned-adm active
Current active profile: balanced
[root@localhost ~]# tuned-adm list
Available profiles:
- balanced
- desktop
- latency-performance
- network-latency
- network-throughput
- powersave
- test
- throughput-performance
- virtual-guest
- virtual-host
Current active profile: balanced
[root@localhost ~]# 
[root@localhost ~]# head /lib/tuned/latency-performance/tuned.conf | grep latency -a1
[cpu]
force_latency=1
governor=performance
[root@localhost ~]# 
[root@localhost ~]# tuned-adm profile latency-performance
[root@localhost ~]#
[root@localhost ~]# hexdump /dev/cpu_dma_latency
0000000 0001 0000                              
0000004
[root@localhost ~]#

可以看到,等待时间值已更改为1微秒。

由于cpu_dma_latency(PM qos)会影响到cpuidle driver的governor的处理逻辑,所以会影响不同C-state的进入。

cpuidle有2种governor:laddermenu,分别代表按顺序计入C-state,和选择进入

cpu在进入idle时,会通过cpuidle governor的策略选择合适的C-state进入。

static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
{
        struct menu_device *data = &__get_cpu_var(menu_devices);
        int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); //读取cpu_dma_latency
        int i;
        int multiplier;
        struct timespec t;

        if (data->needs_update) {
                menu_update(drv, dev);
                data->needs_update = 0;
        }

        data->exit_us = 0;

        /* Special case when user has set very strict latency requirement */
        if (unlikely(latency_req == 0)) 
                return 0;

        /* determine the expected residency time, round up */
        t = ktime_to_timespec(tick_nohz_get_sleep_length());
        data->expected_us =
                t.tv_sec * USEC_PER_SEC + t.tv_nsec / NSEC_PER_USEC;


        data->bucket = which_bucket(data->expected_us);

        multiplier = performance_multiplier();

        /*
         * if the correction factor is 0 (eg first time init or cpu hotplug
         * etc), we actually want to start out with a unity factor.
         */
        if (data->correction_factor[data->bucket] == 0)
                data->correction_factor[data->bucket] = RESOLUTION * DECAY;

        /* Make sure to round up for half microseconds */
        data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket],
                                         RESOLUTION * DECAY);

        get_typical_interval(data);

        if (CPUIDLE_DRIVER_STATE_START > 0) {
                data->last_state_idx = CPUIDLE_DRIVER_STATE_START - 1;
                /*
                 * We want to default to C1 (hlt), not to busy polling
                 * unless the timer is happening really really soon.
                 */
                if (data->expected_us > 5 &&
                    !drv->states[CPUIDLE_DRIVER_STATE_START].disabled &&
                        dev->states_usage[CPUIDLE_DRIVER_STATE_START].disable == 0)
                        data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
        } else {
                data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
        }

        /*
         * Find the idle state with the lowest power while satisfying
         * our constraints.
         */
        for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
                struct cpuidle_state *s = &drv->states[i];
                struct cpuidle_state_usage *su = &dev->states_usage[i];

                if (s->disabled || su->disable)
                        continue;
                if (s->target_residency > data->predicted_us)
                        continue;
                if (s->exit_latency > latency_req) //与cpu_dma_latency对比,小于才会选下一个C-state
                        continue;
                if (s->exit_latency * multiplier > data->predicted_us)
                        continue;

                data->last_state_idx = i;
                data->exit_us = s->exit_latency;
        }

        return data->last_state_idx;
}

4. CPU允许的最大C-state是多少?

intel CPU一般会有多个CPU c-state,但实际也要根据cmdline的中提供的max_cstate设定值,具体来说不同型号的处理器所允许的最大c状态会有所不同

比如:在我的笔记本上查看,共有9个C-state级别,移动设备会更注重功耗

root@ThinkPad-T450:/work/kernel # cat /sys/module/intel_idle/parameters/max_cstate
9

5. 如何检查不同C-state的唤醒延迟值?

延迟时间值可能会根据各种C-state以及从更深的C-state到C0的过渡时间而变化。

sysfs中查看CPU每个C-state的exit_latency延迟值: (exit_latency由驱动指定

root@ThinkPad-T450:/sys/devices/system/cpu/cpu2/cpuidle # for state in state{0..8};do echo c-$state `cat $state/name` `cat $state/latency`;done
c-state0 POLL 0
c-state1 C1 2
c-state2 C1E 10
c-state3 C3 40
c-state4 C6 133
c-state5 C7s 166
c-state6 C8 300
c-state7 C9 600
c-state8 C10 2600
root@ThinkPad-T450:/sys/devices/system/cpu/cpu2/cpuidle #

6. 如何检查和监视Linux中每个CPU和内核的CPU c状态使用情况?

intel平台可以使用turbostat工具,该工具
可以查所有可用CPU核心的c-state使用量及占用百分比。

root@ThinkPad-T450:/work/kernel # turbostat -q
^CCore	CPU	Avg_MHz	Busy%	Bzy_MHz	TSC_MHz	IRQ	SMI	POLL	C1	C1E	C3	C6	C7s	C8	C9	C10	POLL%	C1%	C1E%	C3%	C6%	C7s%	C8%	C9%	C10%	CPU%c1	CPU%c3	CPU%c6	CPU%c7	CoreTmp	PkgTmp	Pkg%pc2	Pkg%pc8	Pkg%pc9	Pk%pc10	PkgWatt	CorWatt	GFXWatt
-	-	267	18.28	1463	2194	10021	0	23	220	1256	3391	1215	3465	1724	875	25	0.00	0.17	1.24	10.16	6.61	25.43	20.23	17.59	0.32	15.69	13.53	8.55	43.94	46	47	0.00	0.00	0.00	0.00	4.20	1.58	0.33
0	0	249	18.09	1377	2195	2460	0	7	45	305	849	295	817	451	222	0	0.00	0.14	1.20	9.88	6.54	24.14	21.03	19.08	0.00	13.70	14.46	8.62	45.13	46	47	0.00	0.00	0.00	0.00	4.20	1.58	0.33
0	1	215	15.70	1374	2194	2573	0	2	57	372	933	317	895	437	230	5	0.00	0.21	1.31	11.59	6.57	25.82	19.51	18.87	0.53	16.08
1	2	291	18.92	1543	2194	2678	0	8	67	337	866	318	940	408	185	11	0.00	0.27	1.58	10.29	6.77	27.23	20.14	14.34	0.45	17.24	12.60	8.47	42.76	46
1	3	312	20.43	1533	2195	2310	0	6	51	242	743	285	813	428	238	9	0.00	0.06	0.88	8.90	6.57	24.54	20.22	18.06	0.31	15.75
root@ThinkPad-T450:/work/kernel #

在设置max_cstate=0的情况下,CPU最深的C-state为C1

[root@localhost ~]# cat /proc/cmdline 
BOOT_IMAGE=/vmlinuz-3.10.0-693.11.1.el7.es.10.x86_64 root=/dev/mapper/os-root ro console=ttyS0,9600 console=tty0 rootdelay=90 nomodeset 
crashkernel=auto rd.lvm.lv=os/root rd.lvm.lv=os/swap biosdevname=1 net.ifnames=1 rhgb quiet LANG=en_US.UTF-8
processor.max_cstate=0 intel_idle.max_cstate=0
[root@localhost ~]#
[root@localhost ~]# turbostat 
	Core	CPU	Avg_MHz	Busy%	Bzy_MHz	TSC_MHz	IRQ	SMI	CPU%c1	CPU%c3	CPU%c6	CoreTmp	Pkg%pc3	Pkg%pc6
	-	-	8	0.52	1600	2394	2219	176	99.48	0.00	0.00	34	0.00	0.00
	0	1	1	0.08	1600	2394	300	11	99.92	0.00	0.00	32	0.00	0.00
	0	9	0	0.03	1600	2394	24	11	99.97
	1	3	1	0.06	1600	2394	73	11	99.94	0.00	0.00	29
	1	11	117	7.33	1600	2394	411	11	92.67
	9	5	1	0.07	1600	2394	89	11	99.93	0.00	0.00	26
	9	13	1	0.04	1600	2394	47	11	99.96
	10	7	1	0.05	1600	2394	61	11	99.95	0.00	0.00	28
	10	15	1	0.05	1600	2394	39	11	99.95
	0	0	1	0.09	1600	2394	264	11	99.91	0.00	0.00	29	0.00	0.00
	0	8	0	0.03	1600	2394	46	11	99.97
	1	2	1	0.08	1600	2394	177	11	99.92	0.00	0.00	32
	1	10	1	0.08	1600	2394	59	11	99.92
	9	4	2	0.12	1600	2394	237	11	99.88	0.00	0.00	33
	9	12	1	0.04	1600	2394	27	11	99.96
	10	6	2	0.10	1600	2394	287	11	99.90	0.00	0.00	34
	10	14	2	0.13	1600	2394	78	11	99.87
^C
[root@localhost ~]#

7. 什么叫POLL idle状态?

前面看到的结果,都不能让CPU完全不进入C-state,因为cpu idle enter代码进入了C1状态,cmdlind添加idle=poll参数可以让CPU完全处于C0状态,当CPU空闲时其实是执行busy-loop,但是TOP并看不出来。

POLL idle状态不是真正的空闲状态,它不节省任何功率。取而代之的是,执行busy-waiting。如果足够了解你的应用程序,对延迟很敏感,让内核知道必须尽快处理工作,因为进入任何实际的硬件空闲状态可能会导致轻微的性能损失,则可以使用此状态。

X86体系结构平台上存在两种不同的cpuidle驱动程序:

“ acpi_idle” cpuidle驱动程序
acpi_idle cpuidle驱动程序从ACPI BIOS表(从最新平台上的_CST ACPI函数或从较旧平台上的FADT BIOS表)检索可用的睡眠状态(C状态)。不会从ACPI表中检索C1状态。如果进入C1状态,内核将调用hlt指令(或Intel上的mwait)。

“ intel_idle” cpuidle驱动程序
在内核2.6.36中引入了intel_idle驱动程序。它仅服务于最近的Intel CPU(Nehalem,Westmere,Sandybridge,Atoms或更高版本)。在较旧的Intel CPU上,仍使用acpi_idle驱动程序(如果BIOS提供C状态ACPI表)。intel_idle驱动程序知道处理器的睡眠状态功能,并忽略ACPI BIOS导出的处理器睡眠状态表。

8. 为什么操作系统可能会忽略BIOS设置?

https://access.redhat.com/solutions/202743
红帽链接中表示,操作系统可能会基于正在使用的cpidle驱动程序忽略BIOS设置,这刷新了我之前对BIOS C-state设定的认知。

针对不同的硬件厂商,BIOS中的实现也不一样,有些服务器BIOS中没有关闭C-state选项,我曾经在一台dell服务器上进入BIOS设置,并没有发现有选项可以关闭C-state,或C-state的相关配置。

如果使用intel_idle(intel计算机上的默认设置),则OS可以忽略ACPI和BIOS设置,即驱动程序可以重新启用C状态
如果禁用intel_idle并使用较旧的acpi_idle驱动程序,则操作系统应遵循BIOS设置。
可以通过以下方式禁用intel_idle驱动程序:

将intel_idle.max_cstate = 0传递到内核命令行或传递idle = xxx (其中*可以例如是poll,即idle = poll)

目前来看,关于C-state,使用OS来控制C-state的进出是最稳妥的做法。
比如:添加“idle=poll”内核参数,可以让CPU完全不进入C-state。

9. 如何查看当前加载的驱动程序?

intel_idle驱动程序是支持现代Intel处理器的CPU idle驱动程序。
intel_idle驱动程序为内核提供目标驻留时间和每个受支持的英特尔处理器的退出延迟时间。
cpu_idle memu governor用此数据来预测CPU空闲多长时间

root@ThinkPad-T450:/work/kernel # cat /sys/devices/system/cpu/cpuidle/current_driver 
intel_idle
root@ThinkPad-T450:/work/kernel # cat /sys/devices/system/cpu/cpuidle/current_governor_ro 
menu
root@ThinkPad-T450:/work/kernel #
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/215564.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • [奶奶看了都会]京东自动签到薅羊毛-完整教程

    [奶奶看了都会]京东自动签到薅羊毛-完整教程又到了节假日的时间了,每逢节假日必须得搞事情。最近北京疫情管的比较严,楼主去小区旁边的小公园散步,都要出示核酸证明了。。。上一次说到用脚本完成京东自动签到领京豆:[奶奶看了都会]教你用脚本薅京东签到羊毛这个只能领到自动签到任务的豆子而已,还有好多京豆任务都没做了,导致咱白白损失了一波豆豆?所以今天嘛,我们就把京豆的任务都做一遍,把京豆全给领了?手机抓包为了获取到京豆签到的接口,需要在手机京东APP上抓包,这就需要用到手机抓包的技术了楼主对着网上的教程实践了一波,搞了一整天之后,得到的结论是An

  • 怎样规划你毕业以后的人生

    怎样规划你毕业以后的人生怎样规划你的毕业后的人生我今年39岁了,25岁研究生毕业,工作14年,回头看看,应该说走了不少的弯路,有一些经验和教训。现在开一个小公司,赚的钱刚够养家糊口的。看看这些刚毕业的学生,对前景也很迷茫,想抛砖引玉,谈谈自己的看法,局限于理工科的学生,我对文科的不懂,身边的朋友也没有这一类型的。91年研究生毕业,那时出路就是1种:留在北京的国营单位,搞一个北京户口,这是最好的选择。到后来的2~3

  • 后端:Layui实现文件上传功能

    后端:Layui实现文件上传功能

    2020年11月14日
  • laravel 预加载特定的列

    laravel 预加载特定的列

  • java框架中的controller层、dao层、domain层、service层、view层[通俗易懂]

    1.Controller层:接口层,用户访问请求时对接。Controller层负责具体的业务模块流程的控制,在此层里面要调用Serice层的接口来控制业务流程,控制的配置也同样是在Spring的配置文件里面进行,针对具体的业务流程,会有不同的控制器,我们具体的设计过程中可以将流程进行抽象归纳,设计出可以…

  • redis memcache 区别_缓存redis的五种方式

    redis memcache 区别_缓存redis的五种方式Redis的作者SalvatoreSanfilippo曾经对这两种基于内存的数据存储系统进行过比较:1.Redis支持服务器端的数据操作:Redis相比Memcached来说,拥有更多的数据结构和并支持更丰富的数据操作,通常在Memcached里,你需要将数据拿到客户端来进行类似的修改再set回去。这大大增加了网络IO的次数和数据体积。在Redis中,这些复杂的操作通常和一般的GET/SET一…

发表回复

您的电子邮箱地址不会被公开。

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