前言

这段时间折腾了一下 windows 的电源计划,对这坨屎山的结构略微有了一些认知,于是先记录一下。
着重记录的是结构和方法,各个选项的实际效果似乎会跟随 windows 的版本产生变化,有些东西甚至可能会和 bios 耦合,在不同机型上产生不同的效果。
所以,仅供参考。

下文中所有 HKEY_LOCAL_MACHINE 开头的路径指的都是注册表,应使用注册表编辑器打开(搜索 regedit)。

授人以渔

这一块讲一讲比较通用的结构和方法。

术语:电源模式 vs 电源计划 vs 电源选项?

控制面板里的“电源计划”应该是 win7 时代的东西了,到了 win10 ,微软又整出了一个“电源模式”,到了 win11 ,这个“电源模式”又被放到了系统的设置中。

“电源计划”是这个东西:

这是 win10 的“电源模式”:

这是 win11 的“电源模式”:

只有在“电源计划”为“平衡”时(或者是从“平衡”延伸出的自定义计划),“电源模式”才可以被切换,否则“电源模式”会被隐藏。
对于任何采用了“现代待机”的设备,只有“平衡”(及其延申计划)可以被使用,其它计划都将会被隐藏

↑ “电源选项”指的是这些东西。无论是“电源模式”还是“电源计划”,本质上都是在修改“电源选项”。只不过用户在“电源计划”中可以看到并调整一部分“电源选项”,而“电源模式”则没有给用户任何调整“电源选项”的空间。关于“电源选项”的细节以及“电源模式”和“电源计划”之间的关系,将在下面再进行介绍。

电源模式是如何工作的?

“电源模式”是在“平衡”(及其延伸计划)的基础上,叠上了一层 overlay ,也就是说,“电源模式”可以覆盖“电源计划”的内容,最终应用的“电源选项”是两者叠加后的效果(比如,某个“电源选项”如果在“电源模式”里配置了,那就优先用“电源模式”的,否则 fallback 到“电源计划”的)(“电源计划”和“电源模式”本质上修改的是同一批的“电源选项”,并没有谁比谁多出来什么)。

“电源模式”的设计初衷,应该是为了方便 OEM 通过预配包的方式来调校系统配置,可以在此处找到相关开发文档。

微软并没有公开有关“电源模式”相关细节的文档,但在网上还是能够找到非常不错的资料。

关于“电源模式”的细节:

  • Windows 电源设置注释 —— 如何用命令切换 / 禁用 overlay (这个命令甚至在 help 里都找不到)、对常见电源选项的解释。

此外,自从 win11 22H2 版本后,windows 还支持了为不同类型的进程配置不同的“电源选项”(相当于“电源模式”中加入了许多“场景配置”,不同类型的进程使用不同的“场景配置”):

(其实我挺好奇上面这些帖子里的资料是哪里来的,究竟是驱动工程师还是逆向天才? x)

电源计划的注册表结构

当前电源计划

你可以在 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes 下面找到当前保存的所有“电源计划”的信息,你也可以在此看到 overlay 。

↑ 电源计划都是以 UUID 的方式进行保存的,点开一个电源计划,你可以在右侧看到其对应的名称。对于系统自带的几个电源计划,其 UUID 的固定的,对于用户创建的电源计划,其 UUID 是随机生成的。
(由于自定义计划的 UUID 是随机生成的,而控制面板中的计划又是根据 UUID 排序的,因此,想要将自定义计划们排成一个理想的顺序就是一件很耗费运气的事情(或者可以用 powercfg -changename))

↑ 每一个电源计划都可以被展开,其中分门别类的保存了“电源选项”相较于默认值的修改。
(关于各个电源选项的默认值在哪里,会在下面讲电源选项的时候具体讲)
(需要注意的是,这里指的是相较于“电源选项的默认值”的修改,而非相较于“默认电源计划”的修改,这两者是不同的;因为“默认电源计划”可以带有“非默认的电源选项值”)

↑ 你可以理解为:在这里的界面修改了一个值,上面注册表中的内容也会对应同步修改。

↑ 你也可以在这里看到 overlay 。

↑ 在顶层,你可以看到当前选中的电源计划以及 overlay 的 UUID 。

↑ 通过观察可知,当电源模式设置为“平衡”时,对应的 overlay UUID 为 0 ,可知此时没有生效的 overlay 。因此,在“平衡”电源模式下调整电源计划中的选项时,可以保障效果的可验证性,避免 overlay 带来的干扰;反之,在“最佳性能”或“最佳能效”的电源模式下调整电源计划中的选项时,你所修改的选项可能会被 overlay 覆盖掉,导致最终没有效果。

默认电源计划

除了当前计划,系统还带有默认计划,位于 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\User\Default\PowerSchemes

如果你执行“恢复默认计划”之类的操作,比如 powercfg -restoredefaultschemes ,那么 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes 下面的内容将被 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\User\Default\PowerSchemes 完全替换,于是你的自定义计划和修改过的选项就通通消失了。

网上的一些“调度”修改的就是这个默认计划,因此在安装它们后会被要求进行一次“恢复默认”,之后才能生效。

隐藏的电源计划

↑ 你可能会注意到,无论是当前计划还是默认计划中,都有一些“历史上出现过但是现在找不到了的”电源计划,比如“高性能”和“卓越性能”。

在上面说到过,对于启用了“现代待机”的设备,非“平衡”(及其延申)的电源计划会被隐藏,那么有没有什么方法能够启用这些隐藏计划呢?

界面是肯定行不通了,只能使用 powercfg 命令了。
很遗憾的是,虽然这些隐藏计划是存在的,我们也能够从注册表里看到它们的 UUID ,但是直接切换是行不通的:

powercfg /setactive e9a42b02-d5df-448d-aa00-03f14749eb61
尝试写入不受支持的设置

唯一可行的切换方式,是先使用 powercfg -duplicatescheme <UUID> 将目标计划复制一份,然后它会显示出新计划的 UUID ,紧接着切换到这个新计划即可。

以切换到卓越性能为例:

  • 复制“卓越性能”到一个新计划:powercfg -duplicatescheme e9a42b02-d5df-448d-aa00-03f14749eb61
  • 复制新计划的 UUID 。
  • 切换到新计划:powercfg /setactive <刚刚复制的 UUID>

需要注意的是,在比较新的 win11 版本中,这个“新计划”也没法在电源计划中显示出来,也就是说,这个新计划和原始计划一样都是隐藏的,只不过这个新计划可以通过命令切换过去而原始计划不行。

& 新计划只要创建一次就行了,记下它的 UUID ,想不起来了可以去注册表里看看,要是每次切换之前都 -duplicatescheme 一下,那注册表里的电源计划会越来越多。

电源选项

无论是“电源模式”还是“电源计划”,本质上都是在修改“电源选项”。

在默认情况下,我们可以在电源计划的“更改计划设置”->“更改高级电源设置”中修改电源选项。但是,在这里能被修改的选项只占很小的一部分,大多数关键的电源选项都是隐藏的。

微软的意思是:对于这些隐藏选项,你们这些用户反正也搞不懂,那就不要改了,把修改的工作交给芯片厂商和 OEM ;选项的配置会以预配包的形式安装到系统中,你们这些用户就按需设置一下“电源模式”,然后工程师精心调校好的选项就会被应用。

事实上,即使这些隐藏的电源选项被解锁了出来,在“电源计划”中修改的“电源选项”仍然可能遭到“电源模式”的覆盖,造成最终没有效果,我想,这便是微软选择隐藏这些选项的直接原因吧(毕竟,总不能给你调但是不生效吧),微软想把这些选项的配置权完全交给 OEM ,而非用户。

在我看来,使用“电源计划”来修改电源选项远比修改“电源模式”来的方便,因为前者至少是有界面的,而后者只能依靠一堆文档都没写的 powercfg 命令以及自制预配包。

所以也上面说了,要把“电源模式”设置为“平衡”,确保注册表里的 overlay UUID 全为 0 ,此时“电源计划”不会被“电源模式”覆盖,能够在一定程度上方便调试,避免额外的干扰。

↑ 首先来展示一下一些隐藏的选项,接下来会进一步展开讲讲如何寻找这些隐藏选项,以及如何解锁它们,使他们显示在“更改高级电源设置”中。
这些隐藏选项真的非常非常的关键,它们可以控制处理器的频率激进程度、处理器的负载策略、处理器的大小核调度策略、核心 parking 策略,甚至还有离电时的性能(调一调就能实现插电和离电性能相同,向 mac 看齐 x)。

类比到 linux ,单“处理器电源管理”下的选项就覆盖了 cpufreq governor 、scheduler、cpuidle、thermal ,更别提别的分类下也有许多的隐藏选项,调起来还是非常爽的。

寻找隐藏电源选项

这篇文章中,微软透露了一种显示所有电源选项的方法,虽然这种方法在 powercfg /? 里根本就没有提及。

只要在 powershell 中运行 powercfg /qh ,所有的电源选项就会被乖乖打印出来了。

↑ 对于打印出的结果,主要关注三个点:

  • 1、你想调什么,你看上了哪个选项。
  • 2、这个选项的 GUID (电源设置 GUID )是多少,记下来,等下解锁的时候要用。
  • 3、这个选项位于哪个组,也就是说,它是属于哪个分类的(比如处理器电源管理),记下这个组的 GUID ,等下解锁的时候也要用。

注册表结构 & 解锁隐藏的电源选项

所有可用的电源选项位于 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\PowerSettings

↑ 其下的每一个子项都对应了一个“组”的 UUID ,选中一项后可以看到这个组对应的名称。就以上面的“处理器电源管理”组为例,其 UUID 为 54533251-82be-4824-96c1-47b60b740d00 ,那么我们可以通过 UUID 在此处找到这个组,并在右侧看到其 Processor power management 的英文名称。
(不属于任何组的子项也会在这个层级呈现)

↑ 展开一个组,便可以看到组中的电源选项了。电源选项也是由 UUID 的形式呈现的,选中后在右侧同样可以看到其英文名称。就以上面“处理器电源管理”中的“处理器性能提高阈值”为例,我们只需要展开刚刚找到的组,在其下寻找 UUID 为 06cadf0e-64ed-448a-8927-ce7bf90eb35d 的子项即可。找到后,点击一下,可以在右侧面板确认一下英文名称,确定没有找错。
右侧面板中的 Attributes 控制了电源选项的隐藏与否,如果你想解锁一个选项,双击 Attributes 将其值修改为 2 即可(如上图所示),无需重启,只需要重新打开“更改高级电源设置”,所解锁的电源选项就会在对应的组下出现了。

↑ 进一步展开一个电源选项,可以在其下看到一个 DefaultPowerSchemeValues 的“文件夹”,里面的每一个子项都对应了该电源选项在不同电源计划 / overlay 下的默认值。就比如图上选中的项目 UUID 为 ded574b5-45a0-4f42-8737-46345c09c238 ,与 Max Performance Overlay 的 UUID 是吻合的,表示这个电源选项在“最佳性能”电源模式下的默认值是 30 (Both AC & DC)。

还记得上面讲电源计划时说的: 每一个电源计划都可以被展开,其中分门别类的保存了“电源选项”相较于默认值的修改 吗?
这里的 DefaultPowerSchemeValues 就是这个默认值:如果对应的电源计划 / overlay 下面没有配置该条目,所采用的默认值就是这里的。

↑ What about 和 DefaultPowerSchemeValues 同级的另一个“目录”?它又是个啥?嘿嘿,其实它是“场景配置”,里面的结构和 DefaultPowerSchemeValues 是类似的,相当于:这个电源选项在这个场景中在各个电源计划 / overlay 里的默认值。

↑ 至于 UUID 到场景名称的对应关系,可以在 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\Profile\Events 下面找到。

很绕对吧,下面会有命令来一键打印各个场景模式 / overlay 的配置内容的。

寻找电源选项的含义

微软只为少数一部分电源选项提供了文档。
你可以复制 GUID 别名,然后在谷歌上限制 site:learn.microsoft.com 进行搜索,如图所示:

↑ 运气好的话,是可以找到比较官方的文档的。

此外,上面提到的文章也是非常有参考价值的。

浏览 overlay 及场景配置的内容

这一块的东西全是参照上面提及过的这几篇文章的:

不过,我的需求倒是简单,我只想看看那“最佳性能”、“最佳能效”的 overlay 都干了什么,以及各个“场景配置”会做什么,确认它们会不会覆盖我对电源计划的修改。
(其实也可以通过上面在注册表中看默认值的方式进行,不过还是太麻烦了)

& 如果你想用预配包的方式调校电源选项,上面的文章非常值得仔细阅读。

Basically ,如果你想浏览 overlay 的内容,只需要在 powercfg /qh 的后面加上对应 overlay 的 UUID 即可。

↑ 以“最佳性能” overlay 为例,先在注册表里看看它的 UUID ,然后 powercfg /qh ded574b5-45a0-4f42-8737-46345c09c238

当然,你也可以使用“别名”的方式,比如 powercfg /qh OVERLAY_SCHEME_MAX ,上面的参考文章中用的也是这种方式。不过,由于我不知道别名到 UUID 的转换表写在哪里,所以别名用起来还是不太舒服。

对于场景配置,可以使用 powercfg /queryprofile 来列出内容。

场景配置似乎是可以通过将 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power 下面的 EventProcessorEnabled 改为 0 来进行关闭的,不过这是参考文章中的说法,我并没有能够在比较官方的文档中找到证据来支持这一点。

授人以鱼

接下来是一些我在调校过程中的信息搜集,可能因为机型和版本不同,在行为上出现差异。

Golden Cove vs Gracemont

有一说一,当时在选 Intel 和 AMD 的时候还真的纠结了一下,一个能效好,一个更好玩。思考的结论是:如果能效不好,我可能会后悔;但是如果玩不到大小核,我一定会后悔。

这有一篇关于大小核能效测试的文章,是一切调校的基础。

总的来说,在日用比较常见的整数负载下,Gracemont 在 3GHz 下都相较于 Golden Cove 有着明显的能效优势。Golden Cove 在 3GHz 左右的能效也挺好的,此时约等于 4.5GHz 的 Skylake 。
Gracemont 跑 3GHz 以上的频率,意义不大,因为此时能效会剧烈的衰减,还不如相同性能时的 Golden Cove (从能效核变成面积效率核了 x)。
Golden Cove 功耗的剧烈上升则发生在 4GHz 以上。

离电性能的关键?

在先前的测试中,我注意到了一个非常特别的情况。

手里的机器在离电状态时,会倾向于不给小核任何负载,小核基本上一直处于全部 parking 的状态,这可以理解,调度策略嘛(即使可能并不高效)。

但是,如果在离电状态下,我使用“相关性”将任务强制锁定在小核上,该任务会遭遇非常非常严重的性能下降,远大于插电时的性能下降水平。

插电时将 chrome 锁在小核上,正常流畅运行没啥问题;离电时锁在小核上,卡的飞起,只是简单滚动都会严重掉帧;此时查看小核频率,插电和离电时并无区别;此时查看功耗,会发现离电绑小核的 IA 功耗比插电绑小核反而高了两瓦左右,又热又卡不可理喻。

更神奇的是,离电时,如果小核上被绑了任务,会反过来导致大核上的前台任务也遭遇严重的性能下降。也就是说:离电时,就让小核摸鱼 -> 性能还行;把 chrome 绑到小核上 -> 不仅 chrome 卡飞,任务管理器都会卡飞。

& 如果离电时将“异类线程调度策略”设为“高效处理器”,即小核负载,那么你将可以看到任务在大核和小核之间反复横跳,来回迁移;插电状态下则是稳定的小核负载。

这一切都是由“处理器电源管理”中的“处理器性能增强策略” ( PERFBOOSTPOL / 45bcc044-d885-43e2-8605-ee0ec6e96b59 )决定的,离电下其默认值为 40 ,就会出现上述情况,将值改为与插电时相同的 60 后,情况消失。

有意思的是,这个选项开 0 和开 40 的效果是差不多的;开 60 和开 100 的效果也是差不多的;但是从 60 调到 40 却会发生明显的负载策略变化(小核变得非常不积极)。

所以,我怀疑,这个选项本身不能背锅。可能是驱动层或者 bios 借助这个选项默认值的差异做了个开关,切换了不同的负载甚至是电压策略。

至于上面剧烈卡顿的原因,我猜是驱动层在努力的让小核 parking 起来,于是发生了负载迁移上的打架。

分别设置大小核的最大频率

有一说一,现在网上的什么关睿频教程还在教你设置“最大处理器状态”,殊不知,这一招在大小核时代已经失效了。

单纯将“最大处理器状态”设为 99% 只能关掉小核的睿频,大核仍然是跑满的,没有卵用。

在新时代,如果你想设置大核的“最大处理器状态”,首先你需要在注册表中解锁隐藏的电源选项“第 1 类处理器电源效率的最大处理器状态”( PROCTHROTTLEMAX1 / bc5038f7-23e0-4960-96da-33abaf5935ed ),然后对其进行设置才有用。

如果你只是想关睿频的话,不妨试试解锁“处理器性能提升模式”( PERFBOOSTMODE / be337238-0d82-4146-a960-4f3749d470c7 ),然后将其设为“已禁用”,这样可以同时关掉大小核的睿频,不用设置两次。

另外,只是关睿频也太捞了吧,其实完全可以控制它的最大频率的。
可以解锁两个选项:“处理器最大频率”( PROCFREQMAX / 75b0ae3f-bce0-45a7-8c89-c9611c25e100 )和“第 1 类处理器电源效率的处理器最大频率”( PROCFREQMAX1 / 75b0ae3f-bce0-45a7-8c89-c9611c25e101 ),用以分别设置小核和大核的最高频率。

需要注意的是,这里设置的小核最高频率是 normalize 到大核的,相当于 小核实际最大频率 = 你设置的频率 / 大核最大频率 * 小核最大频率

以 13700H 为例:比如你设置小核最大频率为 5GHz ,实际最高频率会是 3.7GHz;设置小核最大频率为 3.5GHz ,实际最高频率会是 2.6GHz 。

EPP 控制调度激进程度 / 最大睿频

在较新的英特尔处理器上,采用的是 Hardware Controlled P-states 。说白了,处理器的调频不需要 OS 参与,OS 只需要告诉处理器对性能/能效的偏好( EPP ),剩下的就全部交给处理器本身了。

在电源选项中,EPP 体现为下列两个选项:

  • “处理器能源性能首选项策略”( PERFEPP / 36687f9e-e3a5-4dbf-b1dc-15eb381c6863
  • “针对第 1 类处理器电源效率的处理器能源性能首选项策略”( PERFEPP1 / 36687f9e-e3a5-4dbf-b1dc-15eb381c6864

其分别对应小核和大核,在注册表中解锁隐藏后即可调整。其中 0% 对应非常激进的升频策略,100% 对应非常懒的升频策略。

需要注意的是,在我的平台上,EPP 也会影响最大睿频频率。当 EPP 被设为 45% 时,大核的最大睿频只有 4.5GHz ,开到 25% 时能够解锁满血的 5GHz 。
(这便是为什么原来只有“最佳性能”电源模式下才有满血睿频,因为“最佳性能” overlay 会覆盖 EPP 的电源选项)

另外,因为有了 Hardware Controlled P-states ,所以那一堆什么性能提升降低阈值都是没有用的,那些东西只适用于由 OS 控制频率的时候。

其实在 Linux 下,Hardware Controlled P-states 也是有体现的,比如你会发现 CPU 调速器是 intel_pstate xD。当然,你也是可以切回 ondemand 或者 schedutil 的,对应到 windows 就是关闭“处理器性能自主模式”( PERFAUTONOMOUS / 8baa4a8a-14c6-4451-8e8b-14bdbd197537 )。

异构策略 / 大小核负载模式

异构策略对应的是以下几个电源选项:

  • “生效的异类策略”( HETEROPOLICY / 7f2f5cfa-f10c-4823-b5e1-e93ae85f46b5
  • “异类线程调度策略”( SCHEDPOLICY / 93b8b6dc-0698-4d1c-9ee4-0644e900c85d
  • “异类短运行线程调度策略”( SHORTSCHEDPOLICY / bae08b81-2d5e-4688-ad6a-13243356654b
  • “短与长时间运行线程阈值”( SHORTTHREADRUNTIMETHRESHOLD / d92998c2-6a48-49ca-85d4-8cceec294570

在注册表中解锁后即可调整。需要特别注意一下 overlay 的影响,因为“最佳性能”和“最佳能效” overlay 都会将 “生效的异类策略” 设为 0 ,导致效果被覆盖。

至于这几个选项是何含义,我也说不清楚,也没有官方的文档,可以参考一下下面几篇文章的讨论:

对我来说,发现:

  • “异类策略0” + “高效处理器” = 负载会在大核上先过一遍,然后再迁移到小核,会在大核上造成百分之十几的负载。
  • “异类策略1” + “高效处理器” = 几乎完美仅小核负载,除了某些绑核的软件 / 驱动 / 中断仍然会给大核偶尔造成 0.x% 的负载。

至于其它策略,我不需要(只是想手搓一颗 N300 ),没有测试。

另外,上面说的“场景配置”也是可以影响负载策略的,如果有调校的需要,可以关注一下。

Core Parking

这块我没有什么兴趣,原先的 Parking 策略就挺正常的,可以参考:

后记

算是简单摸索了一下 windows 的电源管理策略。总的来说,不开源的东西就是麻烦。

& Gracemont 算是意外的香啊,特别是这种弹幕视频场景,IA 功耗只有 2w+ ,风扇都不用转,Golden Cove 即使锁 2.4GHz 也能跑到 4W+ 了。

& 整了一堆电源计划,配合 PowerSwitcher 真香!