如何让 Windows 在编译 C + + 时能像 Linux 一样快?

我知道这不是一个编程问题,但它是相关的。

我用的是 大型跨平台工程。在 Windows 上使用 VC + + 2008。在 Linux 上我使用 gcc。这个项目中有大约40000个文件。在编译和链接同一个项目时,Windows 比 Linux 慢10到40倍。我该怎么补救?

在 Linux 上单次更改增量构建需要20秒,在 Windows 上需要 > 3分钟。为什么?我甚至可以在 Linux 中安装这个“黄金”链接器,把时间缩短到7秒。

同样,Linux 上的 git 比 Windows 快10到40倍。

在 git 的情况下,有可能 git 不是以最佳方式使用 Windows,而是使用 VC + + ?你可能会认为微软想让他们自己的开发人员尽可能地高效,而更快的编译将大大有助于实现这一点。也许他们正试图鼓励开发人员使用 C # ?

作为简单的测试,找到一个包含很多子文件夹的文件夹,然后执行一个简单的

dir /s > c:\list.txt

在视窗上。执行两次并计算第二次运行的时间,以便它从缓存中运行。将文件复制到 Linux 并执行相应的2次运行和第二次运行的时间。

ls -R > /tmp/list.txt

我有两台规格一模一样的工作站。HP Z600拥有12G 内存,8核3.0 GHz。对于一个包含约400k 个文件的文件夹,Windows 需要40秒,而 Linux 需要 < 1秒。

是否有一个注册表设置,我可以设置加速 Windows? 什么给?


一些稍微相关的链接,与编译时间相关,不一定是 i/o。

27679 次浏览

增量链接

如果 VC 2008解决方案设置为多个项目,则为。Lib 输出,您需要设置“使用库依赖项输入”; 这使链接器链接直接对。Obj 文件,而不是。Lib.(并且实际上使它逐渐连接起来。)

目录遍历性能

比较原始计算机上的目录爬行和在另一台计算机上用相同文件爬行新创建的目录是有点不公平的。如果希望进行等效的测试,则可能应该在源计算机上创建该目录的另一个副本。虽然我认为 dir /s的性能问题更多的是与写输出有关,而不是测量实际的文件遍历性能。在我的机器上,即使是 dir /s /b > nul也很慢,因为它有一个巨大的目录。

除非出现一个 Windows 系统的铁杆黑客,否则你不会得到比党派评论(我不会这样做)和猜测(这是我将要尝试)更多的东西。

  1. 文件系统-您应该在同一个文件系统上尝试相同的操作(包括 dir)。我遇到了 这个,它对一些文件系统的各种参数进行了基准测试。

  2. 缓存。我曾经尝试在一个 RAM 磁盘上运行 Linux 编译,发现由于内核处理缓存的方式,它比在磁盘上运行要慢。这对 Linux 来说是一个很好的卖点,也许这就是为什么性能如此不同的原因。

  3. Windows 上错误的依赖项规范。也许 Windows 的 chrome 依赖性规范不像 Linux 那样正确。这可能导致在进行小更改时进行不必要的编译。您可以在 Windows 上使用相同的编译器工具链来验证这一点。

我很确定这和文件系统有关。我在一个 Linux 和 Windows 的跨平台项目中工作,在这个项目中,除了绝对需要平台相关代码之外,所有代码都是通用的。我们使用 Mercurial,而不是 git,所以 git 的“ Linuxness”不适用。与 Linux 相比,从中央存储库获取更改在 Windows 上需要花费很长时间,但我不得不说,我们的 Windows 7机器要比 Windows XP 机器好得多。在 VS2008上编译此后的代码更糟糕。不仅仅是 hg; CMake 在 Windows 上运行速度也要慢得多,而且这两个工具使用文件系统的次数比其他任何工具都多。

这个问题非常严重,以至于我们大多数在 Windows 环境下工作的开发人员甚至不再费心做增量构建了——他们发现 而是进行团结建设更快。

顺便说一句,如果你想在 Windows 中大幅度降低编译速度,我建议使用前面提到的统一构建。在构建系统中正确实现是一件痛苦的事情(我在 CMake 中为我们的团队这样做过) ,但是一旦这样做了,我们的持续集成服务器就会自动加快速度。根据构建系统输出的二进制文件的数量,你可以得到1到2个数量级的改进。你的情况可能会有所不同。在我们的例子中,我认为它使 Linux 的构建速度提高了三倍,使 Windows 的构建速度提高了10倍,但是我们有很多共享库和可执行文件(这降低了统一构建的优势)。

我个人发现在 linux 上运行 Windows 虚拟机可以消除 Windows 中的大量 IO 缓慢,这可能是因为 linux vm 做了大量的缓存,而 Windows 本身没有。

通过这样做,我可以将正在处理的大型(250Kloc) C + + 项目的编译时间从15分钟提高到6分钟左右。

这样做的困难在于 C + + 倾向于将自身和编译过程分散到许多小的、单独的文件中。这是 Linux 擅长而 Windows 不擅长的。如果你想为 Windows 制作一个真正快速的 C + + 编译器,试着把所有东西都放在 RAM 中,尽可能少地触及文件系统。

这也是创建更快的 Linux C + + 编译链的方法,但是在 Linux 中这一点不那么重要,因为文件系统已经为您做了大量的调优工作。

原因在于 Unix 文化: 历史上,在 Unix 世界中,文件系统性能的优先级要比在 Windows 中高得多。并不是说它在 Windows 系统中没有优先权,只是在 Unix 系统中有更高的优先权。

  1. 访问源代码。

    你无法改变你无法控制的事。缺乏对 Windows NTFS 源代码的访问意味着大多数提高性能的努力都是通过硬件改进来完成的。也就是说,如果性能较低,可以通过改进硬件(总线、存储介质等)来解决这个问题。如果你必须解决问题,而不是解决它,你只能做这么多。

    对 Unix 源代码的访问(甚至在开源之前)更为普遍。因此,如果您想要提高性能,您应该首先从软件(更便宜和更容易)着手,其次才是硬件。

    因此,世界上有许多人是通过研究 Unix文件系统和寻找提高绩效的新方法而获得博士学位的。

  2. Unix 倾向于使用许多小文件; Windows 倾向于使用少数(或单个)大文件。

    Unix 应用程序倾向于处理许多小文件。考虑一个软件开发环境: 许多小的源文件,每个都有自己的用途。最后一个阶段(链接)确实创建了一个大文件,但这个比例很小。

    因此,Unix 对打开和关闭文件、扫描目录等进行了高度优化的系统调用。Unix 研究论文的历史跨越了几十年的文件系统优化,这些优化花费了大量精力来改进目录访问(查找和全目录扫描)、初始文件打开等等。

    Windows 应用程序倾向于打开一个大文件,长时间保持打开状态,完成后关闭。想想 MS-Word。Exe (或其他)打开文件一次,附加数小时,更新内部块,等等。优化文件打开的价值将被浪费时间。

    Windows 基准测试和优化的历史一直在于读写长文件的速度。这才是最优化的。

    不幸的是,软件开发趋向于第一种情况。最好的 Unix 文字处理系统(TeX/LaTeX)鼓励您将每个章节放在不同的文件中,并且 # 将它们放在一起。

  3. Unix 侧重于高性能,Windows 侧重于用户体验

    Unix 在服务器机房启动: 没有用户界面。用户只能看到速度。因此,速度是第一位的。

    Windows 是从桌面开始的: 用户只关心他们看到的,他们看到的是 UI。因此,花在改进 UI 上的精力比花在性能上的精力更多。

  4. Windows 的生态系统依赖于计划报废。当新的硬件只剩下一两年的时间了,为什么还要优化软件呢?

    我不相信阴谋论,但如果我相信,我会指出,在 Windows 文化中,提高性能的动机较少。Windows 的商业模式依赖于人们像钟表一样购买新机器。(这就是为什么如果微软推迟发布操作系统,或者英特尔错过了芯片发布日期,数千家公司的股价会受到影响。).这意味着通过告诉人们购买新硬件来解决性能问题是一种激励,而不是通过改进真正的问题: 慢速操作系统。Unix 来自预算紧张的学术界,你可以通过发明一种新的方法使文件系统更快地获得博士学位; 学术界很少有人通过发出采购订单来解决问题而获得积分。在 Windows 系统中,没有让软件运行速度变慢的阴谋,但整个生态系统都依赖于计划报废。

    此外,由于 Unix 是开源的(即使它不是,每个人都可以访问源代码) ,任何无聊的博士生都可以阅读代码,并通过改进它而出名。这种情况在 Windows 中不会发生(MS 确实有一个程序可以让学术界人士访问 Windows 源代码,但很少有人利用它)。看看这些与 Unix 相关的性能论文选集: http://www.eecs.harvard.edu/margo/papers/或者查阅 Osterhaus、 Henry Spencer 或其他人的论文历史。见鬼,Unix 历史上最大的(也是最有趣的)争论之一就是奥斯特豪斯和塞尔泽之间的 http://www.eecs.harvard.edu/margo/papers/usenix95-lfs/supplement/rebuttal.html 在 Windows 的世界里,你不会看到这样的事情发生。您可能会看到厂商之间相互竞争,但是最近这种情况似乎更加罕见,因为创新似乎都是在标准主体级别上进行的。

我就是这么想的。

更新: 如果你看看微软正在推出的新的编译器链,你会非常乐观,因为他们所做的大部分工作使得将整个工具链保存在 RAM 中并重复更少的工作变得更容易。令人印象深刻。

据我所知,可视化 c + + 的问题在于,优化这个场景不是编译器团队的优先事项。 他们的解决方案是你使用他们的预编译头功能。这就是特定于 Windows 的项目所做的工作。虽然不便携,但是很有用。

此外,在窗口,你通常有病毒扫描器,以及系统恢复和搜索工具,可以完全破坏你的构建时间,如果他们监视你的构建文件夹。Windows7资源监视器可以帮助您发现它。 如果你真的感兴趣的话,我有一些关于优化 vc + + 构建时间的进一步技巧的 这里有回复

试着用 jom 代替 nmake

拿过来: Https://github.com/qt-labs/jom

事实上,nmake 只使用了您的一个内核,jom 是 nmake 的克隆,它使用了多核处理器。

GNU 通过-j 选项实现了这一点,这可能是其速度优于 Microsoft nmake 的原因之一。

Jom 通过在不同的处理器/内核上并行执行不同的 make 命令来工作。 试着感受一下其中的不同!

NTFS 每次都能节省文件访问时间。您可以尝试禁用它: “ fsutil 行为集 disabelastaccess 1” (重启)

恕我直言,这完全是关于磁盘 I/O 性能的。这个数量级建议大部分操作在 Windows 下进入磁盘,而在 Linux 下在内存中进行处理,也就是说 Linux 缓存更好。Windows 下的最佳选择是将文件移动到一个快速磁盘、服务器或文件系统上。考虑购买一个固态驱动器或将您的文件移动到内存磁盘或快速 NFS 服务器。

我运行了目录遍历测试,结果与报告的编译时间非常接近,表明这与 CPU 处理时间或编译器/链接器算法毫无关系。

如上所示,遍历 chrome 目录树的测量时间:

  • WindowsHomePremium7(8GB 内存)在 NTFS 上: 32秒
  • Ubuntu 11.04 Linux (2GB 内存)在 NTFS 上: 10秒
  • 在 ext4上使用 Ubuntu 11.04 Linux (2GB 内存) : 0.6秒

对于测试,我提取了 chrome 源代码(都在 win/linux 下)

git clone http://github.com/chromium/chromium.git
cd chromium
git checkout remotes/origin/trunk

来测量我跑步的时间

ls -lR > ../list.txt ; time ls -lR > ../list.txt # bash
dir -Recurse > ../list.txt ; (measure-command { dir -Recurse > ../list.txt }).TotalSeconds  #Powershell

我确实关闭了访问时间戳,我的病毒扫描器,增加了 Windows 下的缓存管理器设置(> 2Gb RAM)——所有这些都没有任何明显的改进。事实是,开箱即用的 Linux 比只有四分之一 RAM 的 Windows 性能好50倍。

如果有人认为这些数字是错误的——不管是什么原因——请试一试,并公布你的发现。

一些想法:

  1. 禁用8.3个名字。对于拥有大量文件和相对较少数量的文件夹的驱动器来说,这可能是一个很大的因素: fsutil behavior set disable8dot3 1
  2. 使用更多的文件夹。根据我的经验,NTFS 开始慢下来,每个文件夹大约有1000个文件。
  3. 使用 MSBuild 启用并行构建; 只需添加“/m”开关,它就会自动为每个 CPU 核启动一个 MSBuild 副本。
  4. 把你的文件放在固态硬盘上——对随机输入输出非常有帮助。
  5. 如果您的平均文件大小远远大于4KB,请考虑使用与您的平均文件大小大致相当的较大集群大小重新构建文件系统。
  6. 确保文件已被整理。碎片化的文件会导致大量磁盘搜索,这可能会使吞吐量降低40多倍。使用 sysInternal 中的“ contig”实用程序或内置的 Windows 碎片整理程序。
  7. 如果您的平均文件大小很小,并且所在的分区相对较满,那么可能运行的是一个支离破碎的 MFT,这对性能不利。此外,小于1K 的文件直接存储在 MFT 中。上面提到的“ contig”实用程序可以提供帮助,或者您可能需要增加 MFT 的大小。下面的命令将使其翻倍,达到卷的25% : fsutil behavior set mftzone 2将最后一个数字更改为3或4,以增加额外的12.5% 的增量。运行命令之后,重新启动,然后创建文件系统。
  8. 禁用最后访问时间: fsutil behavior set disablelastaccess 1
  9. 关闭 Windows索引服务
  10. 禁用您的反病毒和反间谍软件,或至少设置相关的文件夹被忽略。
  11. 将文件放在与操作系统和分页文件不同的物理驱动器上。使用单独的物理驱动器允许 Windows 对两个驱动器使用并行 I/O。
  12. 看看你的编译器标志。Windows C + + 编译器有很多选项; 请确保只使用真正需要的选项。
  13. 尝试增加操作系统用于分页池缓冲区的内存量(首先确保有足够的 RAM) : fsutil behavior set memoryusage 2
  14. 检查 Windows 错误日志,以确保不会偶尔出现磁盘错误。
  15. 查看与物理磁盘相关的性能计数器,了解磁盘有多忙。队列长度过长或每次传输时间过长是不好的迹象。
  16. 就原始传输时间而言,前30% 的磁盘分区比其他磁盘分区快得多。更窄的分区还有助于最小化查找时间。
  17. 你在使用 RAID 吗?如果是这样,您可能需要优化 RAID 类型的选择(RAID-5不利于编译等写操作)
  18. 禁用任何不需要的服务
  19. 整理文件夹: 将所有文件复制到另一个驱动器(只有文件) ,删除原始文件,将所有文件夹复制到另一个驱动器(只有空文件夹) ,然后删除原始文件夹,对原始驱动器进行整理,首先复制文件夹结构,然后复制文件。当 Windows 一次构建一个大文件夹时,文件夹会变得支离破碎,速度变慢。(“ contig”在这里也应该有帮助)
  20. 如果你的输入/输出受限,并且有多余的 CPU 周期,试着打开磁盘压缩。它可以为高度可压缩的文件(比如源代码)提供一些重要的加速,但是需要一定的 CPU 成本。

如何构建大型跨平台项目? 如果你在 Linux 和 Windows 上使用通用的 makefile,如果 makefile 在 Windows 上的速度不够快,那么你很容易降低 Windows 的性能10倍。

我刚刚修复了一个跨平台项目的一些 makefile,这些 makefile 使用 Linux 和 Windows 的 common (GNU) makefile。Make 正在为菜谱的每一行启动 sh.exe进程,导致 Windows 和 Linux 之间的性能差异!

根据 GNU make 文档

。 ONESHELL:

应该可以解决这个问题,但是这个特性(目前)不支持 Windows make。因此,将菜谱重写为单一逻辑行(例如通过添加; 或在当前编辑器行的末尾)效果非常好!

我想补充一点,在 Windows 上使用 Gnu make 和 MinGW 工具中的其他工具: 它们似乎可以解析主机名,即使这些工具甚至不能通过 IP 进行通信。我猜这是由于 MinGW 运行时的一些初始化例程造成的。运行本地 DNS 代理帮助我提高了这些工具的编译速度。

之前我有一个很大的头痛,因为构建速度下降了10倍左右,当我打开一个 VPN 连接并行。在本例中,所有这些 DNS 查找都通过 VPN 进行。

这一观察结果也可能适用于其他构建工具,不仅基于 MinGW,而且可能在最新的 MinGW 版本上进行了更改。

最近,我可以使用 Gnu make 在 Windows 上存档另一种方法,用 双赢的版本替换 mingw bash.exe,从而使编译速度提高约10%

(关于交互式编辑,win-bash 并不是很舒服。)