为什么 intel_idle 不支持某些 Intel 家族 6 CPU 型号(Core 2、Pentium M)?

val*_*tis 26 linux cpu drivers power-management intel

我一直在为Intel Core 2 Quad (Yorkfield) 处理器调整我的 Linux 内核,我注意到以下消息dmesg

[    0.019526] cpuidle: using governor menu
[    0.531691] clocksource: acpi_pm: mask: 0xffffff max_cycles: 0xffffff, max_idle_ns: 2085701024 ns
[    0.550918] intel_idle: does not run on family 6 model 23
[    0.554415] tsc: Marking TSC unstable due to TSC halts in idle
Run Code Online (Sandbox Code Playgroud)

PowerTop 仅显示用于封装和单个内核的状态 C1、C2 和 C3:

          Package   |            CPU 0
POLL        0.0%    | POLL        0.0%    0.1 ms
C1          0.0%    | C1          0.0%    0.0 ms
C2          8.2%    | C2          9.9%    0.4 ms
C3         84.9%    | C3         82.5%    0.9 ms

                    |            CPU 1
                    | POLL        0.1%    1.6 ms
                    | C1          0.0%    1.5 ms
                    | C2          9.6%    0.4 ms
                    | C3         82.7%    1.0 ms

                    |            CPU 2
                    | POLL        0.0%    0.1 ms
                    | C1          0.0%    0.0 ms
                    | C2          7.2%    0.3 ms
                    | C3         86.5%    1.0 ms

                    |            CPU 3
                    | POLL        0.0%    0.1 ms
                    | C1          0.0%    0.0 ms
                    | C2          5.9%    0.3 ms
                    | C3         87.7%    1.0 ms
Run Code Online (Sandbox Code Playgroud)

好奇,查询sysfs了一下,发现用的是legacyacpi_idle驱动(本来想看到intel_idle驱动的):

cat /sys/devices/system/cpu/cpuidle/current_driver
Run Code Online (Sandbox Code Playgroud)

acpi_idle

查看内核源代码,当前的intel_idle驱动程序包含一条调试消息,特别指出驱动程序不支持某些 Intel 家族 6 型号:

if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && boot_cpu_data.x86 == 6)
    pr_debug("does not run on family %d model %d\n", boot_cpu_data.x86, boot_cpu_data.x86_model);
Run Code Online (Sandbox Code Playgroud)

intel_idle.c的早期分支(2010 年 11 月 22 日)显示了对 Core 2 处理器的预期支持(模型 23 实际上涵盖了 Core 2 Duo 和 Quad):

#ifdef FUTURE_USE
    case 0x17:  /* 23 - Core 2 Duo */
        lapic_timer_reliable_states = (1 << 2) | (1 << 1); /* C2, C1 */
#endif
Run Code Online (Sandbox Code Playgroud)

上述代码在 2010 年 12 月的commit 中被删除。

不幸的是,源代码中几乎没有文档,因此没有解释这些 CPU 中缺乏对空闲功能的支持。

我当前的内核配置如下:

CONFIG_SMP=y
CONFIG_MCORE2=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_ACPI_PROCESSOR_IDLE=y
CONFIG_CPU_IDLE=y
# CONFIG_CPU_IDLE_GOV_LADDER is not set
CONFIG_CPU_IDLE_GOV_MENU=y
# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
CONFIG_INTEL_IDLE=y
Run Code Online (Sandbox Code Playgroud)

我的问题如下:

  • 是否有不支持 Core 2 处理器的特定硬件原因intel_idle
  • 是否有更合适的方法来配置内核以获得对该系列处理器的最佳 CPU 空闲支持(除了禁用对 的支持intel_idle)?

val*_*tis 30

在研究 Core 2 CPU 电源状态(“ C 状态”)时,我实际上设法实现了对大多数传统 Intel Core/Core 2 处理器的支持。此处记录了包含所有背景信息的完整实现(Linux 补丁)。

随着我积累了更多关于这些处理器的信息,很明显,Core 2 模型支持的 C 状态远比早期和后期处理器中的复杂。这些被称为增强型 C 状态(或“ CxE ”),涉及芯片组上的封装、单个内核和其他组件(例如,内存)。在intel_idle发布驱动程序时,代码还不是特别成熟,并且已经发布了几个具有冲突 C 状态支持的 Core 2 处理器。

这篇 2006 年的文章中找到了一些关于 Core 2 Solo/Duo C-state 支持的令人信服的信息。这与 Windows 上的支持有关,但它确实表明这些处理器上的强大硬件 C 状态支持。关于 Kentsfield 的信息与实际型号冲突,所以我相信他们实际上指的是下面的 Yorkfield:

...四核英特尔酷睿 2 Extreme (Kentsfield) 处理器支持所有五种性能和节能技术 — 增强型英特尔 SpeedStep (EIST)、热监控器 1 (TM1) 和热监控器 2 (TM2)、旧的按需时钟调制 (ODCM) 以及增强型 C 状态 (CxE)。与 Intel Pentium 4 和 Pentium D 600、800 和 900 处理器仅具有 Enhanced Halt (C1) State 特征相比,此功能已在 Intel Core 2 处理器(以及 Intel Core Solo/Duo 处理器)中扩展为处理器的所有可能空闲状态,包括停止授予 (C2)、深度睡眠 (C3) 和深度睡眠 (C4)。

这篇 2008 年的文章概述了对多核 Intel 处理器上每核 C 状态的支持,包括 Core 2 Duo 和 Core 2 Quad(在戴尔的这份白皮书中找到了其他有用的背景阅读资料):

核心 C 状态是硬件 C 状态。有几个核心空闲状态,例如 CC1 和 CC3。众所周知,现代最先进的处理器具有多个内核,例如最近发布的 Core Duo T5000/T7000 移动处理器,在某些圈子中称为 Penryn。我们过去认为的 CPU/处理器,实际上有多个通用 CPU。Intel Core Duo 在处理器芯片中有 2 个内核。Intel Core-2 Quad 每个处理器芯片有 4 个这样的内核。这些内核中的每一个都有自己的空闲状态。这是有道理的,因为一个核心可能处于空闲状态,而另一个核心正在努力处理线程。因此,核心 C 状态是这些核心之一的空闲状态。

我发现英特尔 2010 年的演示文稿提供了一些有关intel_idle驱动程序的额外背景,但不幸的是并没有解释缺乏对 Core 2 的支持:

此实验驱动程序取代了英特尔凌动处理器、英特尔酷睿 i3/i5/i7 处理器和相关英特尔至强处理器上的 acpi_idle。它不支持 Intel Core2 处理器或更早版本。

上面的介绍确实表明intel_idle驱动程序是“菜单”CPU 调控器的实现,它对 Linux 内核配置(即CONFIG_CPU_IDLE_GOV_LADDERvs. 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
Run Code Online (Sandbox Code Playgroud)

从这张表(我后来发现在某些情况下是不正确的)中,Core 2 处理器在 C 状态支持方面似乎存在各种差异(注意几乎所有 Core 2 处理器都是 Socket LGA775,除了 Core 2 Solo SU3500,即Socket BGA956和Merom/Penryn处理器。“Intel Core”Solo/Duo处理器是Socket PBGA479或PPGA478之一)。

这篇文章中发现了表的另一个例外:

Intel 的 Core 2 Duo E8500 支持 C-states C2 和 C4,而 Core 2 Extreme QX9650 不支持。

有趣的是,QX9650是Yorkfield处理器(Intel家族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 }
Run Code Online (Sandbox Code Playgroud)

model在枚举ASM / Intel的family.h。检查这个头文件,我看到英特尔 CPU 被分配了 8 位标识符,这些标识符似乎与英特尔家族 6 型号匹配:

#define INTEL_FAM6_CORE2_PENRYN 0x17
Run Code Online (Sandbox Code Playgroud)

从上面,我们将 Intel Family 6, Model 23 (0x17) 定义为INTEL_FAM6_CORE2_PENRYN. 这应该足以为大多数 Model 23 处理器定义空闲状态,但可能会导致 QX9650 出现上述问题。

因此,至少需要在此列表中定义具有不同 C 状态集的每组处理器。

Zagacki 和 Ponnala, Intel Technology Journal 12 (3):219-227, 2008表明 Yorkfield 处理器确实支持 C2 和 C4。它们似乎还表明 ACPI 3.0a 规范仅支持 C 状态 C0、C1、C2 和 C3 之间的转换,我认为这也可能限制 Linuxacpi_idle驱动程序在有限的 C 状态集之间转换。但是,本文表明情况可能并非总是如此:

请记住,这是 ACPI C 状态,而不是处理器状态,因此 ACPI C3 可能是 HW C6 等。

另外值得注意的是:

除了处理器本身,由于 C4 是平台中主要硅组件之间的同步工作,英特尔 Q45 高速芯片组实现了 28% 的功率提升。

我使用的芯片组确实是 Intel Q45 Express 芯片组。

上MWAIT状态Intel文档是简洁,但确认了特定的BIOS的ACPI行为:

MWAIT 扩展中定义的特定于处理器的 C 状态可以映射到 ACPI 定义的 C 状态类型(C0、C1、C2、C3)。映射关系取决于处理器实现对 C 状态的定义,并由 BIOS 使用 ACPI 定义的 _CST 表向 OSPM 公开。

我对上表的解释(结合来自维基百科asm/intel-family.h和上述文章的表)是:

型号 9 0x09(奔腾 M赛扬 M):

  • 巴尼亚斯:C0、C1、C2、C3、C4

型号 13 0x0D(奔腾 M赛扬 M):

  • 多森、斯蒂利:C0、C1、C2、C3、C4

型号 14 0x0E INTEL_FAM6_CORE_YONAH(增强型奔腾 M增强型赛扬 M英特尔酷睿):

  • Yonah ( Core Solo , Core Duo ): C0, C1, C2, C3, C4, C4E/C5

型号 15 0x0F INTEL_FAM6_CORE2_MEROM(一些Core 2Pentium Dual-Core):

  • Kentsfield、Merom、Conroe、Allendale(E2xxx/E4xxxCore 2 Duo E6xxx、T7xxxx/T8xxxxCore 2 Extreme QX6xxxCore 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
  • Yorkfield ( Core 2 Extreme QX9650 ): C0, C1, C1E, C2E?, C3
  • Wolfdale/Yorkfield(Core 2 QuadC2Q XeonCore 2 Duo E5xxx/E7xxx/E8xxxPentium Dual-Core E6xxxCeleron 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 }
};
Run Code Online (Sandbox Code Playgroud)

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,
};
Run Code Online (Sandbox Code Playgroud)

intel_idle.c第 1073 行:

ICPU(INTEL_FAM6_CORE2_MEROM,  idle_cpu_conroe),
ICPU(INTEL_FAM6_CORE2_PENRYN, idle_cpu_core2),
Run Code Online (Sandbox Code Playgroud)

快速编译并重新启动我的 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
Run Code Online (Sandbox Code Playgroud)

现在 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
Run Code Online (Sandbox Code Playgroud)

我终于访问了 Enhanced Core 2 C-states,看起来功耗有可测量的下降 - 我的 8 个节点上的仪表似乎平均降低了至少 5%(一个节点仍在运行旧内核) ,但我会尝试再次交换内核作为测试。

关于 C4E 支持的一个有趣说明 - 我的 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或者它们是否是多余的。我在Intel Labs Pittsburgh 的 2010 年演示文稿中发现了一条说明,指出转换为 C0 - C1 - C0 - C1E - C0,并进一步说明:

C1E 仅在所有内核都在 C1E 中时使用

我相信这会被解释为只有当所有内核都处于 C1E 状态时才会在其他组件(例如内存)上进入 C1E 状态。我也认为这等效地适用于 C2/C2E 和 C4/C4E 状态(尽管 C4E 被称为“C4E/C5”,所以我不确定 C4E 是 C4 的子状态还是 C5 是子状态) C4E 的状态。测试似乎表明 C4/C4E 是正确的)。我可以通过注释掉 C2 状态来强制使用 C2E - 但是,这会导致使用 C4 状态而不是 C4E(此处可能需要做更多工作)。希望没有任何缺少状态 C2E 的模型 15 或模型 23 处理器,因为这些处理器将被限制为具有上述代码的 C1/C1E。

此外,标志、延迟和驻留值可能会进行微调,但仅根据 Nehalem 空闲值进行有根据的猜测似乎工作正常。需要更多阅读才能做出任何改进。

我测试此上的酷睿2 E2220Allendale的),一个双核奔腾E5300Wolfdale的),酷睿2 E7400酷睿2 E8400Wolfdale的),核心2四方Q9550S的Yorkfield)和核心2极端QX9650,我除了上述对状态 C2/C2E 和 C4/C4E 的偏好之外,没有发现任何问题。

此驱动程序修改未涵盖:

  • 最初的Core Solo / Core DuoYonah,非 Core 2)是系列 6,型号 14。这很好,因为它们支持 C4E/C5(增强型深度睡眠)C 状态但不支持 C1E/C2E 状态并且需要它们自己的空闲定义。

我能想到的唯一问题是:

  • Core 2 Solo SU3300/ SU3500 (Penryn-L) 是系列 6,型号 23,将被此驱动程序检测到。但是,它们不是 Socket LGA775,因此它们可能不支持 C1E Enhanced Halt C 状态。Core 2 Solo ULV U2100/U2200 ( Merom-L ) 也是如此。但是,intel_idle驱动程序似乎会根据子状态的硬件支持来选择适当的 C1/C1E。
  • 据报道,Core 2 Extreme QX9650 (Yorkfield) 不支持 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的函数。一旦我知道去哪里寻找,实施支持就很容易了。非常感谢有用的评论和其他答案,如果亚马逊正在倾听,您就会知道将支票寄往何处。

此更新已提交给 github。我将很快通过电子邮件向 LKML 发送补丁。

更新:我还设法找到了一个 Socket 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
Run Code Online (Sandbox Code Playgroud)

更新:最近一名英特尔员工发表的一篇文章intel_idle详细说明MWAIT状态。

  • 那是不错的侦探工作!我忘记了 C2D/C2Q C 状态有多复杂。重新开发节电功能,如果您的固件足够好,那么您仍然应该至少从一些 C 状态 *via* `acpi_idle` 和各种性能调节器中受益。“powertop”在您的系统上显示什么状态? (5认同)

sou*_*edi 6

是否有更合适的方法来配置内核以获得对该系列处理器的最佳 CPU 空闲支持(除了禁用对 intel_idle 的支持)

您已启用 ACPI,并且您已检查 acpi_idle 是否正在使用中。我真诚地怀疑您是否错过了任何有用的内核配置选项。您可以随时检查powertop可能的建议,但您可能已经知道了。


这不是答案,但我想对其进行格式化:-(。

查看内核源代码,当前的 intel_idle 驱动程序包含一个专门从驱动程序中排除 Intel 家族 6 的测试。

不,它没有:-)。

id = x86_match_cpu(intel_idle_ids);
if (!id) {
    if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
        boot_cpu_data.x86 == 6)
        pr_debug(PREFIX "does not run on family %d model %d\n",
            boot_cpu_data.x86, boot_cpu_data.x86_model);
    return -ENODEV;
}
Run Code Online (Sandbox Code Playgroud)

if声明不排除系列 6。相反,该if声明在启用调试时提供一条消息,即intel_idle. 事实上,我目前的 i5-5300U CPU 是 Family 6,它使用intel_idle.

排除您的 CPU 的是intel_idle_ids表中没有匹配项。

我注意到实现该表的提交。它删除的代码有一个switch语句。这很容易看出最早的模型 intel_idle 已经实现/成功测试/无论是 0x1A = 26。 https://github.com/torvalds/linux/commit/b66b8b9a4a79087dde1b358a016e5c8739ccf186


Ste*_*itt 6

我怀疑这可能只是机会和成本的问题。当intel_idle加入,似乎Core 2 Duo处理器的支持进行了规划,但它从来没有被完全执行-也许是由当时的英特尔工程师腾出空来,这是不值得了。这个等式相对复杂:intel_idle需要提供足够的好处acpi_idle以使其值得在这里支持,在 CPU 上将看到足够数量的“改进”内核......

正如sourcejedi回答所说,驱动程序不排除所有家族 6。CPU 模型列表中的 CPUintel_idle初始化检查,基本上涵盖了从 Nehalem 到 Kaby Lake 的所有微架构。Yorkfield 比这更古老(并且明显不同——Nehalem 与之前的架构非常不同)。family 6 测试只影响是否打印错误信息;它的效果只是错误消息只会显示在 Intel CPU 上,而不是 AMD CPU(Intel 系列 6 包括自 Pentium Pro 以来的所有非 NetBurst Intel CPU)。

要回答您的配置问题,您可以完全禁用intel_idle,但将其保留也可以(只要您不介意警告)。

  • @sourcejedi 我提到这一点是因为 OP 正在看到它。 (2认同)