在研究Core 2 CPU的电源状态(“ C状态 ”)时,我实际上设法实现了对大多数传统Intel Core / Core 2处理器的支持。此处记录了具有所有背景信息的完整实现(Linux补丁)。
当我积累了有关这些处理器的更多信息时,很明显,Core 2模型所支持的C状态要比早期和以后的处理器中的C状态复杂得多。这些被称为增强型C状态(或“ CxE ”),涉及封装,芯片组(例如内存)上的各个内核和其他组件。在intel_idle
发布驱动程序时,代码并不是特别成熟,并且已经发布了几个具有冲突的C状态支持的Core 2处理器。
从2006年开始的这篇文章中找到了一些有关Core 2 Solo / Duo C状态支持的令人信服的信息。这与Windows上的支持有关,但是它确实表明了这些处理器上强大的硬件C状态支持。有关Kentsfield的信息与实际型号冲突,因此我认为它们实际上是指以下的Yorkfield:
...四核Intel Core 2 Extreme(Kentsfield)处理器支持所有五项性能和节能技术-增强的Intel SpeedStep(EIST),Thermal Monitor 1(TM1)和Thermal Monitor 2(TM2),旧的按需时钟调制(ODCM)以及增强的C状态(CxE)。与仅以增强暂停(C1)状态为特征的Intel Pentium 4和Pentium D 600、800和900处理器相比,此功能在Intel Core 2处理器(以及Intel Core Solo / Duo处理器)中得到了扩展。处理器的所有可能的空闲状态,包括停止授权(C2),深度睡眠(C3)和深度睡眠(C4)。
2008年的这篇文章概述了对多核Intel处理器(包括Core 2 Duo和Core 2 Quad)的每核C状态的支持(在本白皮书中来自Dell,还有其他有用的背景知识):
核心C状态是硬件C状态。有几个核心空闲状态,例如CC1和CC3。众所周知,现代的处理器具有多个内核,例如最近发布的Core Duo T5000 / T7000移动处理器,在某些领域被称为Penryn。我们以前认为是CPU /处理器的东西实际上实际上有多个通用CPU。英特尔酷睿双核处理器芯片中有2个内核。英特尔酷睿2四核每个处理器芯片具有4个这样的内核。这些内核中的每个内核都有其自己的空闲状态。这很有意义,因为一个核心可能处于空闲状态,而另一个核心可能很难在线程上工作。因此,核心C状态是这些核心之一的空闲状态。
我在Intel的2010年演讲中找到了有关该intel_idle
驱动程序的其他背景知识,但不幸的是,这并不能解释缺少对Core 2的支持的原因。
此实验驱动程序取代了acpi_idle,它们位于Intel Atom处理器,Intel Core i3 / i5 / i7处理器以及相关的Intel Xeon处理器上。它不支持Intel Core2处理器或更早的版本。
上面的演示确实表明该intel_idle
驱动程序是“菜单” CPU调控器的实现,这对Linux内核配置(即CONFIG_CPU_IDLE_GOV_LADDER
vs. CONFIG_CPU_IDLE_GOV_MENU
)有影响。在此答案中简要描述了梯形调速器和菜单调速器之间的差异。
戴尔有一篇有用的文章,列出了C状态C0到C6的兼容性:
模式C1至C3通过基本切断CPU内部使用的时钟信号来工作,而模式C4至C6通过降低CPU电压来工作。“增强”模式可以同时进行。
Mode Name CPUs
C0 Operating State All CPUs
C1 Halt 486DX4 and above
C1E Enhanced Halt All socket LGA775 CPUs
C1E — Turion 64, 65-nm Athlon X2 and Phenom CPUs
C2 Stop Grant 486DX4 and above
C2 Stop Clock Only 486DX4, Pentium, Pentium MMX, K5, K6, K6-2, K6-III
C2E Extended Stop Grant Core 2 Duo and above (Intel only)
C3 Sleep Pentium II, Athlon and above, but not on Core 2 Duo E4000 and E6000
C3 Deep Sleep Pentium II and above, but not on Core 2 Duo E4000 and E6000; Turion 64
C3 AltVID AMD Turion 64
C4 Deeper Sleep Pentium M and above, but not on Core 2 Duo E4000 and E6000 series; AMD Turion 64
C4E/C5 Enhanced Deeper Sleep Core Solo, Core Duo and 45-nm mobile Core 2 Duo only
C6 Deep Power Down 45-nm mobile Core 2 Duo only
从此表中(我后来发现在某些情况下是不正确的),似乎对Core 2处理器的C状态支持存在多种差异(请注意,除Core之外,几乎所有Core 2处理器都是Socket LGA775。 2 Solo SU3500,它是Socket BGA956和Merom / Penryn处理器。“ Intel Core” Solo / Duo处理器是Socket PBGA479或PPGA478之一。
在本文中找到了该表的另一个例外:
英特尔的Core 2 Duo E8500支持C状态C2和C4,而Core 2 Extreme QX9650不支持。
有趣的是,QX9650是Yorkfield处理器(英特尔家族6,型号23,步进6)。作为参考,我的Q9550S是Intel系列6,型号23(0x17),步进10,据称支持C状态C4(通过实验确认)。此外,Core 2 Solo U3500具有与Q9550S相同的CPUID(系列,型号,步进),但在非LGA775插槽中可用,这混淆了上表的解释。
显然,必须使用CPUID至少直到步进为止,以识别对此处理器模型的C状态支持,并且在某些情况下可能不够用(此时尚不确定)。
分配CPU空闲信息的方法签名为:
#define ICPU(model, cpu) \
{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&cpu }
凡model
在枚举ASM / Intel的family.h。检查此头文件,我发现为Intel CPU分配了8位标识符,这些标识符似乎与Intel家族6型号匹配:
#define INTEL_FAM6_CORE2_PENRYN 0x17
综上所述,我们将英特尔家族6,模型23(0x17)定义为INTEL_FAM6_CORE2_PENRYN
。这足以为大多数Model 23处理器定义空闲状态,但如上所述可能会导致QX9650出现问题。
因此,至少需要在此列表中定义具有不同C状态集的每组处理器。
Zagacki和Ponnala在2008年英特尔技术期刊 12(3):219-227中指出,Yorkfield处理器确实支持C2和C4。它们似乎也表明ACPI 3.0a规范仅支持C状态C0,C1,C2和C3之间的转换,我想这也可能会限制Linux acpi_idle
驱动程序在有限的C状态集之间进行转换。但是,本文指出可能并非总是这样:
请记住,这是ACPI C状态,而不是处理器状态,因此ACPI C3可能是硬件C6,依此类推。
还要注意:
除了处理器本身之外,由于C4是平台中主要芯片组件之间的同步工作,因此Intel Q45 Express芯片组可将功耗提高28%。
我使用的芯片组确实是Intel Q45 Express芯片组。
在上MWAIT状态Intel文档是简洁,但确认了特定的BIOS的ACPI行为:
在MWAIT扩展中定义的特定于处理器的C状态可以映射到ACPI定义的C状态类型(C0,C1,C2,C3)。映射关系取决于处理器实现对C状态的定义,并由BIOS使用ACPI定义的_CST表向OSPM公开。
我对上面的表(结合Wikipedia的表,asm / intel-family.h和上面的文章的解释)是:
型号9 0x09(奔腾M和赛扬M):
型号13 0x0D(Pentium M和Celeron M):
- Dothan,Steeley:C0,C1,C2,C3,C4
型号14 0x0E INTEL_FAM6_CORE_YONAH(增强的Pentium M,增强的Celeron M或Intel Core):
- Yonah(Core Solo,Core Duo):C0,C1,C2,C3,C4,C4E / C5
型号15 0x0F INTEL_FAM6_CORE2_MEROM(某些Core 2和Pentium Dual-Core):
- Kentsfield,Merom,Conroe,Allendale(E2xxx / E4xxx和Core 2 Duo E6xxx,T7xxxx / T8xxxx,Core 2 Extreme QX6xxx,Core 2 Quad Q6xxx):C0,C1,C1E,C2,C2E
型号23 0x17 INTEL_FAM6_CORE2_PENRYN(核心2):
- Merom-L / Penryn-L :?
- Penryn(Core 2 Duo 45-nm mobile):C0,C1,C1E,C2,C2E,C3,C4,C4E / C5,C6
- 约克菲尔德(Core 2 Extreme QX9650):C0,C1,C1E,C2E ?, C3
- Wolfdale / Yorkfield(Core 2 Quad,C2Q Xeon,Core 2 Duo E5xxx / E7xxx / E8xxx,Pentium Dual-Core E6xxx,Celeron Dual-Core):C0,C1,C1E,C2,C2E,C3,C4
从仅Core 2系列处理器对C状态支持的多样性来看,似乎缺乏对C状态的一致支持可能是未尝试通过intel_idle
驱动程序完全支持它们的原因。我想完整地完成整个Core 2产品线的上述清单。
这并不是一个令人满意的答案,因为这使我想知道,由于没有充分利用这些处理器上强大的省电MWAIT C状态,因此使用了多少不必要的功率,并且已经(并且仍然)产生了多余的热量。
Chattopadhyay 等。2018年,《高效能高性能处理器:设计绿色高性能计算的最新方法》因我在Q45 Express芯片组中寻找的特定行为而值得注意:
程序包C状态(PC0-PC10)-当计算域,核心和图形(GPU)处于空闲状态时,处理器将有机会在非核心和平台级别上进一步节省功耗,例如,冲洗LLC并对其进行电源门控存储器控制器和DRAM IO,并且在某些状态下,可以关闭整个处理器,同时将其状态保留在始终在线的电源域中。
作为测试,我在linux / drivers / idle / intel_idle.c第127行中插入了以下内容:
static struct cpuidle_state conroe_cstates[] = {
{
.name = "C1",
.desc = "MWAIT 0x00",
.flags = MWAIT2flg(0x00),
.exit_latency = 3,
.target_residency = 6,
.enter = &intel_idle,
.enter_s2idle = intel_idle_s2idle, },
{
.name = "C1E",
.desc = "MWAIT 0x01",
.flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 20,
.enter = &intel_idle,
.enter_s2idle = intel_idle_s2idle, },
// {
// .name = "C2",
// .desc = "MWAIT 0x10",
// .flags = MWAIT2flg(0x10),
// .exit_latency = 20,
// .target_residency = 40,
// .enter = &intel_idle,
// .enter_s2idle = intel_idle_s2idle, },
{
.name = "C2E",
.desc = "MWAIT 0x11",
.flags = MWAIT2flg(0x11),
.exit_latency = 40,
.target_residency = 100,
.enter = &intel_idle,
.enter_s2idle = intel_idle_s2idle, },
{
.enter = NULL }
};
static struct cpuidle_state core2_cstates[] = {
{
.name = "C1",
.desc = "MWAIT 0x00",
.flags = MWAIT2flg(0x00),
.exit_latency = 3,
.target_residency = 6,
.enter = &intel_idle,
.enter_s2idle = intel_idle_s2idle, },
{
.name = "C1E",
.desc = "MWAIT 0x01",
.flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 20,
.enter = &intel_idle,
.enter_s2idle = intel_idle_s2idle, },
{
.name = "C2",
.desc = "MWAIT 0x10",
.flags = MWAIT2flg(0x10),
.exit_latency = 20,
.target_residency = 40,
.enter = &intel_idle,
.enter_s2idle = intel_idle_s2idle, },
{
.name = "C2E",
.desc = "MWAIT 0x11",
.flags = MWAIT2flg(0x11),
.exit_latency = 40,
.target_residency = 100,
.enter = &intel_idle,
.enter_s2idle = intel_idle_s2idle, },
{
.name = "C3",
.desc = "MWAIT 0x20",
.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 85,
.target_residency = 200,
.enter = &intel_idle,
.enter_s2idle = intel_idle_s2idle, },
{
.name = "C4",
.desc = "MWAIT 0x30",
.flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 100,
.target_residency = 400,
.enter = &intel_idle,
.enter_s2idle = intel_idle_s2idle, },
{
.name = "C4E",
.desc = "MWAIT 0x31",
.flags = MWAIT2flg(0x31) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 100,
.target_residency = 400,
.enter = &intel_idle,
.enter_s2idle = intel_idle_s2idle, },
{
.name = "C6",
.desc = "MWAIT 0x40",
.flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 200,
.target_residency = 800,
.enter = &intel_idle,
.enter_s2idle = intel_idle_s2idle, },
{
.enter = NULL }
};
在intel_idle.c
983行:
static const struct idle_cpu idle_cpu_conroe = {
.state_table = conroe_cstates,
.disable_promotion_to_c1e = false,
};
static const struct idle_cpu idle_cpu_core2 = {
.state_table = core2_cstates,
.disable_promotion_to_c1e = false,
};
在intel_idle.c
1073行:
ICPU(INTEL_FAM6_CORE2_MEROM, idle_cpu_conroe),
ICPU(INTEL_FAM6_CORE2_PENRYN, idle_cpu_core2),
快速编译并重新启动我的PXE节点后,dmesg
现在显示:
[ 0.019845] cpuidle: using governor menu
[ 0.515785] clocksource: acpi_pm: mask: 0xffffff max_cycles: 0xffffff, max_idle_ns: 2085701024 ns
[ 0.543404] intel_idle: MWAIT substates: 0x22220
[ 0.543405] intel_idle: v0.4.1 model 0x17
[ 0.543413] tsc: Marking TSC unstable due to TSC halts in idle states deeper than C2
[ 0.543680] intel_idle: lapic_timer_reliable_states 0x2
现在,PowerTOP显示:
Package | CPU 0
POLL 2.5% | POLL 0.0% 0.0 ms
C1E 2.9% | C1E 5.0% 22.4 ms
C2 0.4% | C2 0.2% 0.2 ms
C3 2.1% | C3 1.9% 0.5 ms
C4E 89.9% | C4E 92.6% 66.5 ms
| CPU 1
| POLL 10.0% 400.8 ms
| C1E 5.1% 6.4 ms
| C2 0.3% 0.1 ms
| C3 1.4% 0.6 ms
| C4E 76.8% 73.6 ms
| CPU 2
| POLL 0.0% 0.2 ms
| C1E 1.1% 3.7 ms
| C2 0.2% 0.2 ms
| C3 3.9% 1.3 ms
| C4E 93.1% 26.4 ms
| CPU 3
| POLL 0.0% 0.7 ms
| C1E 0.3% 0.3 ms
| C2 1.1% 0.4 ms
| C3 1.1% 0.5 ms
| C4E 97.0% 45.2 ms
我终于访问了增强型Core 2 C状态,看起来功耗有明显下降-我的8个节点上的电表平均平均降低了至少5%(其中一个节点仍在运行旧内核) ,但我将尝试再次换出内核作为测试。
有关C4E支持的有趣说明-My Yorktown Q9550S处理器似乎支持它(或C4的某些其他子状态),如上所示!这让我感到困惑,因为Core 2 Q9000处理器上的Intel数据表(第6.2节)仅提到了C状态:正常(C0),HALT(C1 = 0x00),扩展HALT(C1E = 0x01),停止授权(C2 = 0x10) ,扩展停止授权(C2E = 0x11),睡眠/深度睡眠(C3 = 0x20)和深度睡眠(C4 = 0x30)。这个额外的0x31状态是什么?如果启用状态C2,则使用C4E而不是C4。如果我禁用状态C2(强制状态C2E),则使用C4代替C4E。我怀疑这可能与MWAIT标志有关,但是我尚未找到有关此行为的文档。
我不确定该怎么做:C1E状态似乎代替了C1,C2代替了C2E,C4E代替了C4。我不确定C1 / C1E,C2 / C2E和C4 / C4E是否可以一起使用,intel_idle
或者它们是否多余。我在2010年匹兹堡英特尔实验室的演讲中发现了一个笔记,该笔记指出过渡是C0-C1-C0-C1E-C0,并进一步说明:
仅当所有核心都在C1E中时才使用C1E
我认为,只有当所有内核都处于C1E状态时,才能在其他组件(例如内存)上进入C1E状态。我还将其等同地应用于C2 / C2E和C4 / C4E状态(尽管C4E被称为“ C4E / C5”,所以我不确定C4E是C4的子状态还是C5是子状态,测试似乎表明C4 / C4E是正确的)。我可以通过注释掉C2状态来强制使用C2E-但是,这将导致使用C4状态代替C4E(这里可能需要做更多的工作)。希望不会有任何缺少状态C2E的模型15或模型23处理器,因为使用上述代码,这些处理器将限于C1 / C1E。
同样,标记,等待时间和驻留值可能可以进行微调,但是仅基于Nehalem空闲值进行有根据的猜测似乎可以正常工作。需要进行更多阅读才能进行任何改进。
我在Core 2 Duo E2220(Allendale),双核Pentium E5300(Wolfdale),Core 2 Duo E7400,Core 2 Duo E8400(Wolfdale),Core 2 Quad Q9550S(Yorkfield)和Core 2 Extreme QX9650上进行了测试,除了上述对状态C2 / C2E和C4 / C4E的偏好之外,没有发现任何问题。
此驱动程序修改不包括:
我能想到的唯一问题是:
- Core 2 Solo SU3300 / SU3500(Penryn-L)是系列6,型号23,将被此驱动程序检测到。但是,它们不是Socket LGA775,因此它们可能不支持C1E增强的暂停C状态。对于Core 2 Solo ULV U2100 / U2200(Merom-L)同样如此。但是,
intel_idle
驱动程序似乎基于子状态的硬件支持选择适当的C1 / C1E。
- 据报道,Core 2 Extreme QX9650(约克菲尔德)不支持C状态C2或C4。我已经在eBay上购买了二手的Optiplex 780和QX9650 Extreme处理器来确认这一点。处理器支持C状态C1和C1E。通过修改该驱动程序,CPU处于状态C1E而不是C1的空闲状态,因此可以节省一些电能。我期望看到C状态C3,但是使用此驱动程序时它不存在,因此我可能需要进一步研究。
我设法从2009年英特尔的演示文稿中找到了有关C状态之间转换(即深度掉电)的幻灯片:
总而言之,事实证明,没有真正原因导致intel_idle
驱动程序中缺少Core 2支持。现在很明显,“ Core 2 Duo”的原始存根代码仅处理C状态C1和C2,这比acpi_idle
处理C状态C3 的功能要低得多。一旦知道了要看的地方,就可以轻松实现支持。非常感谢您提供有用的评论和其他答案,如果Amazon在听,您知道将支票发送到哪里。
此更新已提交给github。我很快会通过电子邮件将补丁发送给LKML。
更新:我还设法挖掘了套接字T / LGA775 Allendale(Conroe)Core 2 Duo E2220,它是6系列,15型,因此我也对此添加了支持。该模型不支持C状态C4,但支持C1 / C1E和C2 / C2E。这也应该适用于其他基于Conroe的芯片(E4xxx / E6xxx),可能还适用于所有Kentsfield和Merom(非Merom-L)处理器。
更新:我终于找到了一些MWAIT调优资源。此Power vs. Performance文章以及Deeper C状态和增加的延迟博客文章均包含一些有关识别CPU空闲延迟的有用信息。不幸的是,这仅报告那些已编码到内核中的退出延迟(但是,有趣的是,只有处理器支持的那些硬件状态):
# cd /sys/devices/system/cpu/cpu0/cpuidle
# for state in `ls -d state*` ; do echo c-$state `cat $state/name` `cat $state/latency` ; done
c-state0/ POLL 0
c-state1/ C1 3
c-state2/ C1E 10
c-state3/ C2 20
c-state4/ C2E 40
c-state5/ C3 20
c-state6/ C4 60
c-state7/ C4E 100
acpi_idle
和各种性能州长。powertop
系统上显示什么状态?