如何让Windows像Linux一样快速编译C ++?

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

我在一个相当大的跨平台项目上工作 。 在Windows上,我使用VC ++ 2008.在Linux上,我使用gcc。 项目中有大约4万个文件。 在编译和链接相同的项目时,Windows的速度比Linux慢10倍到40倍。 我该如何解决这个问题?

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

同样的,git在Linux上的速度是Windows的10倍到40倍。

在git的情况下,可能git不是以最佳方式使用Windows,而是使用VC ++? 你可能会认为微软希望自己的开发人员尽可能富有成效,而编译速度会更快。 也许他们试图鼓励开发人员进入C#?

作为简单的testing,find一个有很多子文件夹的文件夹,并做一个简单的

dir /s > c:\list.txt 

在Windows上。 做两次,第二次运行时,它从caching运行。 将文件复制到Linux,并执行等同的2次运行和第二次运行。

 ls -R > /tmp/list.txt 

我有两个工作站完全相同的规格。 惠普Z600s 12gig ram,8核3.0ghz。 在具有〜400k文件的文件夹中,Windows需要40秒,Linux需要<1秒。

有没有我可以设置加快Windows的registry设置? 是什么赋予了?


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

  • 显然,在Windows 10(不是在Windows 7)中存在一个问题,即closures一个进程会导致全局locking 。 当编译多个核心,因此多个进程,这个问题发生。

  • /analyse选项可能会对perf性能产生负面影响,因为它会加载Web浏览器 。 (不相关,但很好知道)

除非硬核Windows系统黑客出现,否则你不会得到超过党派评论(我不会这样做)和猜测(这是我将要尝试的)。

  1. 文件系统 – 您应该在相同的文件系统上尝试相同的操作(包括dir )。 我碰到这个基准testing几个文件系统的各种参数。

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

  3. Windows上的依赖关系规范不好。 也许Windows的铬依赖性规范并不像Linux那样正确。 这可能会导致不必要的编译,当你做一个小小的改变。 您可以在Windows上使用相同的编译器工具链validation此function。

一些想法:

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

NTFS每次都会保存文件访问时间。 您可以尝试禁用它:“fsutil行为设置disablelastaccess 1”(重新启动)

就我所知,visual c ++的问题是编译器团队优化这个场景不是优先级。 他们的解决scheme就是使用他们的预编译头文件function。 这是特定于Windows的项目所做的。 这不是便携式,但它的工作原理。

此外,在Windows上,通常有病毒扫描程序,以及系统还原和search工具,如果他们监视您的buid文件夹,可能会完全毁坏您的构build时间。 Windows 7资源监视器可以帮助你发现它。 如果您真的感兴趣,我在这里有一个回复,提供一些优化vc ++编译时间的技巧。

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

这样做,我可以加快我正在从15分钟到6分钟左右的大型(250Kloc)C ++项目的编译时间。

这样做的困难是因为C ++倾向于将自身和编译过程分散到许多小的,单独的文件中。 这是Linux擅长的,Windows不是。 如果您想为Windows制作一个非常快速的C ++编译器,请尽量将所有内容保存在RAM中,并尽可能less地触摸文件系统。

这也是您如何制作更快速的Linux C ++编译链,但在Linux中这一点并不重要,因为文件系统已经为您做了很多调整。

这是由于Unix文化的原因:从历史上看,Unix系统中的文件系统性能一直比Windows中高得多。 不是说在Windows中它不是一个优先事项,只是在Unix中它已经是一个更高的优先级。

  1. 访问源代码。

    你不能改变你无法控制的东西。 缺乏对Windows NTFS源代码的访问意味着尽pipe硬件有所改进,但大部分改善性能的努力都已经完成。 也就是说,如果性能较差,则可以通过改善硬件来解决问题:总线,存储介质等等。 如果你必须解决这个问题,那么你只能这么做,而不是解决问题。

    访问Unix源代码(甚至在开源之前)更广泛。 因此,如果你想提高性能,你可以先用软件(更便宜,更简单)和硬件来解决它。

    因此,世界上有很多人通过研究Unix文件系统获得博士学位,并find改进性能的新方法。

  2. Unix倾向于许多小文件; Windows倾向于几个(或一个)大文件。

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

    因此,Unix已经高度优化了打开和closures文件,扫描目录等的系统调用。 Unix研究论文的历史跨越了数十年的文件系统优化,为改进目录访问(查找和全目录扫描),初始文件打开等提供了很多思路。

    Windows应用程序倾向于打开一个大文件,长时间打开它,完成后closures它。 想想MS-Word。 msword.exe(或其他)打开文件一次,追加几个小时,更新内部块,等等。 优化文件打开的价值将浪费时间。

    Windows基准testing和优化的历史一直是以多快的速度读取或写入长文件。 这就是优化。

    令人遗憾的是,软件开发趋于第一种情况。 哎呀,Unix(TeX / LaTeX)最好的文字处理系统鼓励你把每一章放在一个不同的文件中,并把它们包括在一起。

  3. Unix专注于高性能; Windows着重于用户体验

    Unix在服务器机房启动:没有用户界面。 用户唯一看到的就是速度。 所以速度是重中之重。

    Windows在桌面上启动:用户只关心他们看到的内容,然后看到用户界面。 因此,改善UI的性能要比耗费更多的精力。

  4. Windows生态系统依赖计划报废。 为什么在新硬件仅用了一两年的时间就优化软件?

    我不相信阴谋论,但是如果我这样做的话,我会指出,在Windows文化中,提高绩效的动机很less。 Windows商业模式取决于人们购买发条机等新机器。 (这就是为什么如果MS迟交操作系统或者Intel错过芯片发布date,成千上万家公司的股票价格会受到影响。 这意味着通过告诉人们购买新的硬件来解决性能问题是一种激励。 不是通过改善真正的问题:慢操作系统。 Unix来自于预算紧张的学术界,你可以通过发明一种新方法来加快文件系统的速度,从而获得博士学位。 学术界的人很less能通过发出采购订单来解决问题。 在Windows中,没有阴谋保持软件缓慢,但整个生态系统取决于计划淘汰。

    另外,由于Unix是开放源代码(即使不是,每个人都可以访问源代码),任何无聊的博士生都可以阅读代码,并通过改进而成名。 这不会发生在Windows(MS确实有一个程序,让学者访问Windows源代码,这是很less利用)。 请看这个与Unix有关的性能文件的select: http : //www.eecs.harvard.edu/margo/papers/或查看Osterhaus,Henry Spencer或其他人的论文的历史。 哎呀,在Unix历史上最大的(也是最值得观赏的)辩论之一就是Osterhaus和Selzer之间的来回http://www.eecs.harvard.edu/margo/papers/usenix95-lfs/supplement/rebuttal。; html在Windows世界中你不会看到这种事情发生。 你可能会看到供应商互相之间的一对一,但最近似乎更为罕见,因为创新似乎都在标准体系层面。

这就是我所看到的。

更新:如果你看看来自微软的新的编译链,你将会非常乐观,因为他们所做的大部分工作使得把整个工具链保存在RAM中并且重复工作更less。 非常令人印象深刻

增量链接

如果VC 2008解决scheme设置为带有.lib输出的多个项目,则需要设置“使用库依赖项input”。 这使链接器链接直接对.obj文件而不是.lib。 (而且实际上使它增量链接。)

目录遍历性能

将原始机器上的目录搜寻与在另一台机器上search相同文件的新创build的目录进行比较是有点不公平的。 如果你想要一个等效的testing,你应该在源机器上创build另一个目录的副本。 (它可能还是很慢,但这可能是由于许多事情:磁盘碎片,短文件名,后台服务等等)。尽pipe我认为dir /s的perf问题与写入输出有关测量实际的文件遍历性能。 即使dir /s /b > nul很慢,我的机器上有一个巨大的目录。

我很确定它与文件系统有关。 我为Linux和Windows开发了一个跨平台的项目,除了平台相关的代码是绝对必要的之外,所有代码都是常见的。 我们使用Mercurial而不是git,因此git的“Linuxness”不适用。 与Linux相比,从中央存储库中获取更改永远在Windows上,但是我不得不说,我们的Windows 7计算机比Windows XP计算机做得好多了。 之后编译代码在VS 2008上更糟糕。它不仅仅是hg; CMake在Windows上的运行速度要慢很多,而且这两种工具都比其他的文件系统更重要。

这个问题非常糟糕,我们大多数在Windows环境下工作的开发人员甚至不愿意进行增量构build – 他们发现做一个统一构build会更快。

顺便说一句,如果你想大大提高Windows的编译速度,我会build议上述的统一build设。 在构build系统中正确实施是一件痛苦的事情(我在CMake为我们的团队做了这个工作),但是一旦自动完成,我们就可以为持续集成服务器加快速度。 根据您的构build系统吐出的二进制文件数量,您可以获得1到2个数量级的改进。 你的旅费可能会改变。 在我们的例子中,我认为它加快了Linux的三倍,Windows的速度提高了10倍,但是我们有很多共享库和可执行文件(这减less了统一构build的优点)。

你如何build立你的大型跨平台项目? 如果您在Linux和Windows上使用常见的makefiles,如果makefile在Windows上devise不快,则可以轻松地将Windows性能降低10倍。

我只是使用Linux和Windows的常见(GNU)makefiles修复了一些跨平台项目的makefile。 Make正在为配方的每一行启动一个sh.exe进程,导致Windows和Linux之间的性能差异!

根据GNU make文档

.ONESHELL:

应该解决这个问题,但是这个function是(目前)不支持Windows make的。 因此,将配方重写为单个逻辑行(例如,通过在当前编辑器行末尾添加\或\)工作得非常好!

恕我直言,这是所有关于磁盘I / O性能。 这个数量级意味着很多操作在Windows下进入磁盘,而在Linux下则是在内存中进行处理,即Linuxcaching更好。 在Windows下最好的select是把你的文件移动到快速的磁盘,服务器或文件系统上。 考虑购买固态硬盘或将您的文件移动到虚拟硬盘或快速NFS服务器。

我运行了目录遍历testing,结果非常接近报告的编译时间,这表明这与CPU处理时间或编译器/链接器algorithm完全无关。

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

  • Windows NT Home Premium 7(8GB RAM):32秒
  • NTFS上的Ubuntu 11.04 Linux(2GB Ram):10秒
  • 在ext4上的Ubuntu 11.04 Linux(2GB Ram):0.6秒

为了testing,我把铬源(都在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 

我确实closures了访问时间戳,我的病毒扫描程序,并增加了Windows(> 2Gb RAM)下的cachingpipe理器设置 – 所有这些都没有任何明显的改进。 事实上,开箱即用的Linux比内存的四分之一执行速度快了50倍。

对于任何人想要争辩的数字错误 – 无论出于何种原因 – 请尝试并张贴您的发现。

尝试使用jom而不是nmake

在这里获取: http : //qt.gitorious.org/qt-labs/jom

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

GNU make-do-the-box得益于-j选项,这可能是它的速度与Microsoft nmake的一个原因。

jom通过在不同的处理器/内核上并行执行不同的make命令来工作。 试试自己一个感觉的区别!

我想在Windows上使用MinGW工具中的Gnu make和其他工具添加一个观察:即使工具甚至无法通过IP进行通信,他们似乎也能parsing主机名。 我猜这是由MinGW运行时的一些初始化例程引起的。 运行本地DNS代理帮助我提高了这些工具的编译速度。

之前,我感到非常头疼,因为当我打开一个VPN连接时,构build速度下降了10倍左右。 在这种情况下,所有这些DNS查找都通过VPN。

这种观察也可能适用于其他构build工具,不仅基于MinGW,而且在最新的MinGW版本上也可能发生变化。

我最近可以用另外一种方式来加速编译Windows的速度,使用Gnu make,通过用win-bash中的版本replacemingw bash.exe