放慢Windows第2部分:创建进程



长期以来,Windows一直被认为是文件操作和进程创建缓慢的罪魁祸首。 您是否曾经尝试过使其变慢? 本文将向您展示如何逐步降低大多数用户在Windows(无穷)中创建进程的技巧!

当然,本文还将告诉您如何检测和避免此问题。

这是我年初开始遇到的一个实际问题,文章介绍了我是如何发现它并找到解决方法的。 以前有关降低Windows速度的文章:


出了点问题


我不是在找麻烦,但我想我找到了他们。 也许是因为我在周末从来源收集了数百次Chrome,或者我一生不走运。 我想我们永远不会知道。 本文以一种或另一种方式描述了构建Chrome时在Windows中遇到的第五个严重问题。

  1. 计划外的序列化导致一个完整的挂起UI: “ 24核处理器,但我不能移动光标
  2. Microsoft的Windows附加组件之一中的进程描述符泄漏: “僵尸进程耗尽了您的内存
  3. Windows文件高速缓存中长期存在的正确性错误: “编译器错误? 链接器错误? Windows内核错误。”
  4. 错误使用文件通知时的性能失败: “放慢Windows,第1部分:文件访问
  5. 这就是:一种奇怪的体系结构解决方案,随着时间的流逝会减慢进程的创建。

罕见的崩溃跟踪


计算机应该是可靠的和可预测的,还有其他让我烦恼的事情。 如果我连续构建Chrome数百次,那么我希望看到每个组装都成功。 因此,当我们的分布式编译过程(gomacc.exe)有时崩溃时,我想对此进行调查。 我已经配置了故障转储的自动记录 ,因此我发现在检测到堆损坏时发生崩溃。 一种简单的检查方法是启用页面堆,以便Windows堆将每个内存分配放在单独的页面上。 这意味着释放后使用和缓冲区溢出会导致即时故障,而不是难以诊断的损坏。 我之前曾写过有关使用App Verifier启用pageheap的文章

App Verifier减慢程序的速度有两个原因:内存分配变慢,而页面对齐的分配实际上停用了处理器缓存。 因此,可以预见装配会略有放缓,并且确实发生了。

但是当我晚些时候进来时,大会似乎完全停止了。 在大约7000个组装步骤之后 ,没有明显的进展。

O(n ^ 2)通常不好


原来Application Verifier喜欢创建日志文件。 而且,不管没人在看这些文件,他都会创建它们以防万一。 这些文件必须具有唯一的名称。 我敢肯定,仅以升序方式为日志提供数字名称似乎是个好主意,例如gomacc.exe.0.dat,gomacc.exe.1.dat等。

要获得升序的数字名称,您需要确定接下来要使用的数字。 最简单的方法是尝试可能的名称/编号,直到找到尚未使用的名称/编号。 也就是说,尝试创建一个名为gomacc.exe.0.dat的新文件,如果该文件已经存在,请尝试gomacc.exe.1.dat,以此类推。

可能出什么问题了?

实际上,在最坏的情况下,一切都非常糟糕


事实证明,如果在创建进程时对未使用的文件名进行线性搜索,则启动N个进程需要进行O(N ^ 2)个操作。 常识表明,如果不能保证N始终保持相对较小,则O(N ^ 2)个算法太慢。

这种情况的严重程度取决于验证文件是否存在所需的时间。 我进行了测量,发现在Windows上大约需要80微秒(80μs或0.08 ms)。 启动第一个进程很快,但是启动第1000个进程需要扫描1000个已经创建的日志文件。 它需要80毫秒,然后还要更多。

典型的Chrome版本需要编译器运行约30,000次。 编译器的每次运行都需要扫描N个先前创建的日志文件,其中0.08 ms用于检查每个文件。 线性搜索下一个可用的日志文件名意味着运行N个进程需要(N ^ 2)/ 2个检查文件是否存在,即30,000 * 30,000 / 2,即4.5亿个。 由于每次验证文件是否存在都需要0.08毫秒,因此这是3600万毫秒,即36,000秒。 也就是说,Chrome的构建时间(通常为五到十分钟)将再增加十个小时。

妈的

在撰写本文时,我通过运行一个空的可执行文件约7000次来重现该错误-并看到一条清晰的O(n ^ 2)曲线,如下所示:



奇怪的是,如果我们使用ETW跟踪并查看对CreateFile的平均调用时间,那么对于几乎所有文件而言,结果都小于5微秒(在下面的示例中平均为4.386μs):



看来这只显示了对文件I / O跟踪的ETW限制。 文件I / O事件仅跟踪文件系统的最低级别,在Ntfs.sys之上,还有更多级别,包括FLTMGR.SYS和ntoskrnl.exe。 但是,速度下降不能完全被隐藏-CPU使用率在“ CPU使用率”图上可见。 下面的屏幕截图显示了548 ms的时间间隔,它表示单个进程的创建。 基本上,所有时间扫描大约6850个可能的日志文件名:



生产效率更高的磁盘会有所帮助吗?


不行

处理的数据量很小,写入磁盘的数量甚至更少。 在我测试重现错误的过程中,磁盘几乎完全空闲。 因为所有相关的磁盘数据都被缓存,所以此问题与CPU有关。 即使间接费用成本降低了一个数量级,它们仍然会太大。 您无法改进O(N ^ 2)算法。

发现


可以通过在%userprofile%\ appverifierlogs中搜索.dat文件来检测到此特定问题。 通常,您可以通过检查ETW跟踪来检测流程创建速度的降低,现在您知道要查找的内容了。

解决方案


最简单的解决方案是关闭日志记录。 这也将停止用GB的日志填充磁盘。 可以通过以下命令禁用它:

appverif.exe -logtofile disable

禁用日志记录后,我发现我的进程的启动速度比测试开始时快三倍(!),并且速度完全消失了。 在1.5分钟(而不是40分钟)内创建了7000个受监视的Application Verifier进程。 通过用于测试和简单过程的简单批处理文件,可以看到以下过程创建速度:

  • 通常为每秒200次(每个过程5毫秒)
  • 启用应用程序验证程序但禁用日志记录时每秒75个(每个进程13毫秒)
  • 最初以40每秒的速度打开Application Verifier并打开日志记录...(每个进程25毫秒,时间逐渐增加到无穷大)
  • 一次安装Chrome后每秒显示0.4

Microsoft可以通过放弃日志文件数量的单调增加来解决此问题。 如果他们使用当前日期和时间作为文件名(最长为毫秒或更高的分辨率),则他们将获得日志的语义上更有意义的名称,这些名称可以非常快速地创建,而对于唯一文件几乎没有搜索逻辑。

但是不再支持Application Verifier,并且无论如何日志文件都无用,因此只需禁用它们。

配套信息


可以在此处找到批处理文件和为empty.exe启用Application Verifier后重新创建错误的脚本。

实验结束后的ETW轨迹在此处

其他连结:

用于创建图表的原始计时数据。

关于Reddit的讨论

黑客新闻上的讨论

有关兜售的其他O(n ^ 2)个算法的示例,请参见偶然地平方

要获得更平凡的享受,请观看有关我9月份上班的19种不同方式的视频汇编-我太忙了,无法在本月继续进行实验。

Source: https://habr.com/ru/post/zh-CN427303/


All Articles