调查:Windows中比线程优先级还高的是什么?

像其他许多调查一样,这项调查始于我自己做生意,而不是自己寻找问题的事实。这次,我要做的就是打开笔记本电脑的盖子,然后尝试登录系统。

在最初的几次中,当这导致二十秒的延迟时,我忽略了这个问题,希望它可以解决。接下来的几次我考虑了调查,但是甚至在您登录之前出现的性能问题就更难以解决,而且我很懒。

当我因为担心这些过于频繁的延误而发现自己避免关闭笔记本电脑时,我意识到该认真考虑了。

幸运的是,我最近修复了UIforETW环形缓冲区跟踪使它变得可靠,所以我启动了它并开始等待下一个延迟事件。我不必等待很长时间。

我花了好几次时间才能完全了解ETW的踪迹。由于我不熟悉这个地区,所以花了一些时间弄清正在发生的事情。我仍然没有完全理解该问题,但是90%的人知道发生此问题的原因。我学到了很多东西,包括有关Windows调度程序的一些新细节,而且我还找到了一个绝对有效的解决方案。

最终加载到Microsoft Windows Performance Analyzer(WPA)时最终记录的理想跟踪如下所示:


标准事件,焦点窗口和CPU使用率

该表和两个图形包含大量信息。顶部的表(通用事件)显示了UIforETW的记录的击键。我试图每秒按下一个键(虚拟键代码162)一次,直到出现密码输入字段。由于选择了这17个击键,因此在下图中,它们以垂直的蓝线显示,以简化可视化的关键事件的执行时间。 x轴以秒为单位表示时间。

上方图形中的水平条(“ 聚焦窗口”)显示了这段时间哪个过程具有焦点。总共有六个不同的过程。跟踪关闭是关闭笔记本电脑的短暂时间。

底部的图显示了CPU使用率信息是从上下文切换数据中获取的,因此它必须是完全准确和完整的。在此跟踪中,值100%表示使用四核八线程笔记本电脑的所有八个逻辑处理器的时刻。

接收到跟踪数据后,我不得不弄清楚笔记本计算机在合上机盖时秘密进行的工作,直到返回系统为止。

暴风雨来临前


如我们所见,笔记本电脑在其踪迹的开始处就应该是相对简单的。然后我关上了盖子。这似乎引起了CPU活动的高峰和Windows焦点的变化。焦点窗口从UIforETW更改为Idle,然后更改为csrss,再回到Idle,再到LogonUI,再回到Idle。谁曾想到?

在此间隔内,笔记本电脑执行了大约17秒的各种类型的CPU处理。其中一部分是需要关闭的工作。部分-这些是在“任务计划程序”中注册的程序(包括用户内部的Google工具),用于执行“用户锁定工作站时”,这很有意义。我什至还注意到,当用户继续工作时,正在创建用于登录的UI元素的工作-您需要预先准备好吗?

17秒的CPU-笔记本电脑进入睡眠状态需要很长时间。即使在我的具有四个核心和八个线程的笔记本电脑上,该过程也需要花费超过四秒钟的时间。在我的家用笔记本电脑上,要花费超过13秒的CPU时间才能入睡,几乎所有这些都转到Windows代码中。在便携式计算机可以休息之前,诊断策略服务是否真的需要运行几个SruDbTableSearches?

我想睡觉时,这种过度的工作也是一个问题,但这不是问题,我期待的。所以我只好决定拒绝她。

直到很久以后,我才意识到是在这段时间里,我的虫子被摧毁了。

睡觉


锁定笔记本电脑后,将没有CPU活动。在此特定测试中,笔记本电脑被锁定了约16秒钟。

惊厥


CPU进入睡眠状态的活动与开始唤醒时的活动无可比拟。在这段时间里,我超负荷工作的笔记本电脑花了172秒的CPU时间(!!!)22.6秒。这是很多工作。

这个过程的奥秘之一是在最初爆发活动后大约一秒钟内,CPU使用率几乎下降到零。考虑到周围的混乱情况,这短暂的停机时间似乎很不正常。但是我认为此功能与问题无关,因此我没有对其进行关注。

另一个谜是为什么这么多短暂的暂停后,程序就会生效。有趣的是,造成CPU 172秒运行时间中的31.6的最严重的入侵者是Windows Performance Analyzer(WPA),这是我用来分析跟踪的程序。尽管尚不可见,但我仍在运行的三个副本正在努力呈现UI。

此外,尝试初始化笔记本电脑设备时,会出现暗图案。 KeStallExecutionProcessor是一个等待循环,奇怪的是,它是整个系统中最可执行的功能。第二种等待周期是启动设备的唯一方法吗?真的需要花费700毫秒的CPU时间来初始化鼠标和键盘吗?微软和英特尔是否应该忽略微软的建议最多50微秒


等待周期的驱动程序。i8042prt.sys由Microsoft编写。以下两个是英特尔创建的。

最终,在此期间,许多程序都在积极运行他们中的大多数似乎都面临着与WPA相同的问题-他们迫切希望在隐藏的屏幕上绘制像素,这暗示了Windows错误。但即使没有这个错误EXPLORER.EXE和其他计划积极寻求的东西做的。但是最后,尽管这种过多的CPU使用量是问题的必要部分,但这不是问题本身所以我再次停止关注她。

焦点


分析痕迹时,重要的是找出何时发生重要的动作。主要证据是输入事件,因为在密码输入表单出现后,我停止单击控件。这是“ 焦点窗口中控制键的最后三个击键,以近似形式显示


似乎紧急事件已成为LockApp.exe的焦点,此后焦点几乎立即获得了LogonUI.exe。大概是我在LogonUI.exe中输入了密码(跟踪不拦截键盘事件是很方便的),然后将焦点短暂切换到资源管理器,然后切换到UIforETW,从此开始。

看起来LogonUI.exe在LockApp.exe之前无法获得焦点-此模式在我研究的所有跟踪中都重复出现。

因此,经过一千多个致力于解决这个难题的单词,我们终于有了一个可以调查的明确问题:为什么LockApp.exe在退出停机时间后会获得焦点,却需要20秒?

我们有问题吗?很好,我们来回答


使用从内容切换获得的CPU使用率(精确)数据,我很快发现,唤醒LockApp.exe后不到二十秒的CPU时间不到一毫秒,并且超过14秒(从35.158 s到49.827 s)不起作用通常:


LockApp长时间无法使用

有关CPU使用率(精确度)表中各列含义的文档在此处

如果某个进程或线程没有运行一段时间,并且您想找出原因,那么通常可以在长时间停顿(即切换到49.827秒的跟踪时间)后的第一个上下文切换中找到重要的线索。我对这些列进行了重新排序,以显示来自此上下文开关的更多数据:


LockApp已准备好但未执行。奇怪...

计数,等于1表示我们查看单个上下文切换的数据。

自上次以来的时间,等于3,820万微秒,表示此线程将不会在38.2秒内执行。这本身既不是好事,也不是坏事。闲置流量可以节省能源,最后笔记本电脑在梦中已经有一段时间了。

切入时间只是告诉我们线程何时恰好适合CPU —上下文何时切换到该线程。

现在,我们进入“就绪”列。他告诉我们线程准备执行但尚未执行的时间。换句话说,该线程正在等待某些东西(锁定,处理),这就是已被释放或启动,但线程仍未运行 19.493秒。

为了更好地了解“ 就绪”,您可以查看“ 就绪时间”。他告诉我们何时准备好流。我们看到,在跟踪30.333秒后,该线程已准备好执行,但直到49.827秒才执行。这似乎很重要。

否则,这种列排列方式向我们显示了相同的上下文切换:


新线程堆栈和就绪线程堆栈

因此,在我打开笔记本计算机盖进行了30.333秒的追踪之后不久,该线程(新线程堆栈预期NtWaitForWorkViaWorkerFactory将显示)被命令唤醒(系统进程调用KeSetEvent)。但是它不是从那时开始(这将是“好”),而是在19.494 s之后开始,这很糟糕。

通常,在进行期望的这种分析时,我会花费大量时间弄清楚为什么流在等待以及导致流未准备就绪的原因。但这是我第一次对期望进行分析,这并不重要,问题在于为什么不执行此现成的线程。

案件...


大多数人没有花太多时间研究ETW迹线,因此需要在此处进行解释。奇怪。如果线程准备就绪,则通常立即启动,或在几毫秒后启动。顾名思义流的就绪状态意味着该流已准备好执行,几乎没有任何干扰。但是,让我们弄清楚什么可以阻止执行完成的线程。

线程优先级


首先,我建议这是CPU“饥饿”的简单情况。数十个进程需要CPU时间,因此,直到负载减少,LockApp才获得正确的时间。但是,该理论与症状并不完全相符,因为即使没有获得CPU时间,LockApp进程也可能需要大约18秒

CPU饥饿理论是好的,因为它是可验证的。我能够使用任务管理器来提高LockApp进程的优先级(在UWP系统未将其暂停的短暂时间内之一),因此,在我用于本文的最终跟踪中,LockApp的执行具有高优先级。常规Windows线程的优先级大约为8-10。常规(非实时)Windows线程可以运行的最高优先级是15。我的ETW跟踪显示,LockApp始终以优先级13或更高的优先级运行。

这是关键的19.494秒的CPU时间线,按线程优先级进行分组和着色(New In Pri,即分配给线程的当前优先级)。我们看到优先级为4、8、9和10的线程消耗了大量的CPU时间,尤其是在最后:


按优先级使用CPU

这是另一个具有优先级0-12的隐藏线程的映像。每次图表下降到12.5%以下(这意味着我的八线程笔记本电脑的CPU时间是一个逻辑处理器),必须启动LockApp ,并且当许多优先级较低或相等的线程无法正常执行优先级时,这绝对让人难以置信得到大量的时间。


优先级CPU使用率,仅高优先级线程

消除优先级倒置


有人猜测Windows优先级反转算法非常有助于其他线程,从而导致LockApp.exe被阻止。但是,由于上面的图表表明在计划决策中使用了真正的优先级,因此必须放弃这种假设(总是令人信服)。

堆芯卸载


当我在Twitter上谈论这个难题时,一位评论员建议卸载线程核心堆栈我对这种情况并不熟悉,但是在John Werth的解释(他在本领域中了解)之后,我关闭了内核堆栈的交换并重新启动了计算机。没有改变。实际上,考虑到我有32 GB的内存,并且问题反复出现且经常发生,因此我认为这样做没有帮助。但最好是确定这一点。

暂停程序


由于LockApp是现代的UWP应用程序,因此它受到类似于智能手机应用程序的限制。除其他外,这意味着它可以在不在前台时挂起,然后在返回前台时“解冻”。James Forshaw建议记录Microsoft-Windows-Kernel-Process ETW,以获取有关此数据。

事件旨在引起最大的混乱。任务冻结的名称用于“解冻”和“冻结”,并且win:版本的Stop事件表示进程正在启动(它已停止冻结),而win的版本:Start表示该过程停止(开始冻结)。所有这些都是非常合乎逻辑的,但却非常令人困惑。如果将事件名称分为“冻结”和“解冻”,则混乱程度将减少。

没有这些事件的文档,但是由于分析,我确定这些事件始终由Background Tasks / Broker Infrastructure Service创建。相应进程的名称和进程ID在FrozenProcessID字段中指示。


ProcessFreeze事件(也用于除霜)

对这个提供者进行调查很有趣-它有许多很有希望的事件-但最终证明LockApp在跟踪过程中没有暂停或除霜。但是,此提供程序似乎非常有用,因此我修改了UIforETW,以便将来的版本始终将其记录下来。

我们已经排除了一切


在我看来,上述理论都不太可能,现在我们都将它们排除在外了。我开始寻求帮助,并要求我给我来自Microsoft朋友的想法。那时我发现Windows中众所周知的流优先级0-31实际上只是优先级系统的五个低优先级位

使用公职


原来,我的无知是我的错。如果我仔细阅读Windows Internals(第7版,第1部分)的“ 线程”部分所有108页,我将了解发生了什么。如果您想继续前进,则此主题在第287至295页中显示 我不知道的这个超级优先级字段称为Rank它在WPA中显示为默认隐藏列(要查找它,您必须打开视图编辑器),称为NewThreadRank在计划线程时,“线程等级”的优先级高于优先级。几乎所有流都具有等级0,并且具有等级0的流始终具有比具有等级2的流更高的优先级。

通过NewThreadRank并查看表格的左侧,我们可以立即看到问题:


等级比优先级更重要

LockLock.exe流具有等级2,这意味着,尽管优先级为14,但它们在系统中的优先级最低。

几乎完整的解释


因为事实证明,LockApp.exe线程有2级,它们只能在执行时没有以秩0线程的“希望”运行。由于许多应用程序(出于未知原因)主动渲染其不可见的屏幕,因此它们争夺CPU时间的每一分争斗,对于更高的等级值则一无所获。一旦LockApp.exe收到一小部分CPU时间,它就会快速移至Rank 0(并且CPU负载下降),然后以通常的方式执行登录过程。

了解了这些信息后,我开始研究LockApp的排名如何随时间变化。在最近的几秒钟内,LockApp突然从睡眠之前的等级0移到了2,该等级旨在防止CPU占用过多的时间,例如Windows Photos过于热衷于不需要的后台处理并进行过渡时从2到19:


Microsoft.Photos排名下降

从文档中您可以了解,流等级的主要目的是公平地共享计算机上会话之间的CPU时间,从而使一个用户的进程不会损害其他用户。这两个使用等级的选项都清楚地表明,只有在使用大量CPU时间的情况下,流的等级才应该增加,并且在笔记本电脑进入睡眠状态时,LockApp.exe仅使用79.3 ms的CPU时间,而系统的其余部分-CPU时间为17 。但是,由于某种原因,操作系统决定在进入睡眠过程中将LockApp降级为2。

仅当流属于“计划组”(KSCHEDULING_GROUP)时,操作系统才会更改流的等级),并且典型Windows安装中的大多数线程都不是成员。因此,大多数线程的等级不会改变,因此它们可以按照自己的方式花费CPU时间。

剩下的难题


不幸的是,目前尚不清楚为什么LockApp.exe在进入睡眠状态之前下降到第2级,我将认为LockApp在计划组中,并且其中一种算法的行为可能不正确。但是我找不到用于调查此问题的API,时间已不多了。如果您知道任何详细信息,请在原始文章的评论中写。在我看来,如果不将系统中的大多数流程纳入其中,那么将等级作为规划决策中最重要的组成部分这一基本原则就应该不可避免地崩溃-规划组中的线程总是冒着缺乏必要资源的风险。如果不涉及大多数线程,那么动态资源分配计划DFSS必将失败。

另外,我不知道为什么这么多应用程序在进入睡眠状态后仍保持活动状态。这通常由以下事实解释:“许多计时器在便携式计算机处于睡眠模式几个小时后会结束”,但如果便携式计算机仅在梦中停留几秒钟,并且WPA呈现行为表明窗口系统中发生了某些情况,则此解释不适用。有问题。再加上不良行为的应用程序和等待周期驱动程序,CPU随时间推移将所有内容堆叠在一起。

CPU风暴消失并且LockApp同时启动的事实导致了一个显而易见的解释:LockApp仅在CPU需求下降时才能工作。但是有一个同样令人信服的解释:一旦LockApp具备运行能力(或者可能是LogonUI拥有了运行能力),CPU需求就会下降。两种解释都行得通,但是我认为后者似乎更合理,因为否则我们无法解释为什么似乎无休止的WPA渲染突然停止了。

解决问题


一旦我意识到LockApp.exe是一个单独的应用程序,它在启动时遇到问题,并且提高其优先级无济于事,我就禁用了它。文件DisableLockScreen.reg帮助了我:

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Personalization]
“NoLockScreen”=dword:00000001

通过关闭锁定屏幕,笔记本电脑在打开护盖后会立即唤醒。我没有注意到CPU的刹车或暴风雨,现在进入它的时间减少了一步。我第一次遇到问题时发布

第一条Twitter帖子中包含进行调查的时间表,这可能对某人有用。此外,感谢他们,来自Twitter的许多聪明人也来了。

当我回到文章时,我发现重新打开锁定屏幕后,问题消失了。一次简单的重启并不能解决问题-在2月,我重启了很多次,但我们可能不知道为什么丢失了它。

讨论区



All Articles