如何使Windows与Linux一样快速地编译C ++?

时间:2011-08-02 17:27:38

标签: windows linux performance compilation

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

我在公平large cross platform project上工作。在Windows上我使用VC ++ 2008.在Linux上我使用gcc。项目中有大约40k个文件。在编译和链接同一个项目时,Windows比Linux慢10到40倍。我该如何解决这个问题?

Linux上的单个更改增量构建20秒>在Windows上3分钟。为什么?我甚至可以在Linux中安装'gold'链接器并将时间缩短到7秒。

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

在git的情况下,git可能不是以最佳方式使用Windows而是使用VC ++?你认为微软希望让自己的开发人员尽可能高效,而更快的编译将会有很长的路要走。也许他们正试图鼓励开发人员加入C#?

作为简单测试,找到包含许多子文件夹的文件夹并执行简单的

dir /s > c:\list.txt
在Windows上

。执行两次并在第二次运行时间,以便从缓存中运行。将文件复制到Linux并执行等效的2次运行并在第二次运行时进行计时。

ls -R > /tmp/list.txt

我有2个工作站具有完全相同的规格。 HP Z600s配备12gig内存,8个内核,3.0ghz。在具有~400k文件的文件夹上,Windows需要40秒,Linux需要< 1秒。

我可以设置一个注册表设置来加速Windows吗?是什么给了什么?


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

11 个答案:

答案 0 :(得分:32)

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

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

  2. 缓存。我曾经尝试在RAM磁盘上运行Linux上的编译,并发现它比在磁盘上运行要慢,这要归功于内核处理缓存的方式。这是Linux的一个重要卖点,可能是性能如此不同的原因。

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

答案 1 :(得分:27)

一些想法:

  1. 禁用8.3名称。对于包含大量文件和文件夹数量相对较少的驱动器,这可能是一个重要因素:fsutil behavior set disable8dot3 1
  2. 使用更多文件夹。根据我的经验,NTFS开始变慢,每个文件夹超过1000个文件。
  3. 使用MSBuild启用并行构建;只需添加“/ m”开关,它将自动为每个CPU核心启动一份MSBuild。
  4. 将您的文件放在SSD上 - 对随机I / O有很大帮助。
  5. 如果平均文件大小远大于4KB,请考虑使用较大的群集大小重建文件系统,该大小大致与平均文件大小相对应。
  6. 确保文件已经过碎片整理。碎片文件会导致大量磁盘搜索,这会使您的吞吐量降低40倍。使用sysinternals中的“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. 禁用索引服务
  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. 如果您受I / O限制且备用CPU周期,请尝试打开磁盘压缩。它可以为高度可压缩的文件(如源代码)提供一些显着的加速,但在CPU中有一些成本。

答案 2 :(得分:23)

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

答案 3 :(得分:20)

就我所知,visual c ++的问题是编译器团队优先考虑这种情况不是优先事项。 他们的解决方案是您使用他们的预编译头功能。这是Windows特定项目所做的。它不便携,但它的工作原理。

此外,在Windows上,您通常拥有病毒扫描程序,以及系统还原和搜索工具,如果他们为您监控您的buid文件夹,可能会完全破坏您的构建时间。 Windows 7资源监视器可以帮助您发现它。 如果您真的感兴趣,我有a reply here一些优化vc ++构建时间的进一步提示。

答案 4 :(得分:16)

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

这样做我能够加快我正在进行的大型(250Kloc)C ++项目的编译时间,从15分钟到大约6分钟。

答案 5 :(得分:7)

增量链接

如果将VC 2008解决方案设置为具有.lib输出的多个项目,则需要设置“使用库依赖项输入”;这使链接器直接链接到.obj文件而不是.lib。 (实际上它会逐渐增加链接。)

目录遍历性能

将原始计算机上的目录爬网与使用其他计算机上的相同文件爬网新创建的目录进行比较有点不公平。如果要进行等效测试,则应该在源计算机上创建另一个目录副本。 (它可能仍然很慢,但这可能是由于任何数量的东西:磁盘碎片,短文件名,后台服务等)虽然我认为dir /s的性能问题更多地与编写输出比测量实际文件遍历性能。使用庞大的目录,我的机器上的dir /s /b > nul速度很慢。

答案 6 :(得分:6)

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

问题非常严重,以至于我们在Windows环境中工作的大多数开发人员都不再费心去做增量构建 - 他们发现doing a unity build instead更快。

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

答案 7 :(得分:5)

如何构建大型跨平台项目? 如果你在Linux和Windows上使用常见的makefile,如果makefile没有设计成在Windows上快速运行,那么你很容易将Windows性能降低10倍。

我刚刚使用针对Linux和Windows的通用(GNU)makefile修复了一些跨平台项目的makefile。 Make正在为配方的每一行开始sh.exe进程,导致Windows和Linux之间的性能差异!

根据GNU make文档

  

.ONESHELL:

应解决此问题,但Windows make不支持此功能(目前)。因此,将配方重写为单个逻辑行(例如,通过在当前编辑行的末尾添加\或\)非常有效!

答案 8 :(得分:4)

恕我直言,这完全是关于磁盘I / O性能的。数量级表明很多操作在Windows下运行到磁盘,而它们在Linux下在内存中处理,即Linux更好地缓存。 Windows下的最佳选择是将文件移动到快速磁盘,服务器或文件系统上。考虑购买固态硬盘或将文件移动到ramdisk或快速NFS服务器。

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

上面建议的测量时间遍历chrome目录树:

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

对于测试我拉了铬源(都在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比Windows使用四分之一的RAM要好50倍。

对于任何想要争辩数字错误的人 - 无论出于何种原因 - 请试一试并发布您的发现。

答案 9 :(得分:2)

尝试使用jom代替nmake

在此处获取: http://qt.gitorious.org/qt-labs/jom

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

由于-j选项,GNU make开箱即用,这可能是其速度与Microsoft nmake相比的原因。

jom的工作原理是在不同的处理器/内核上并行执行不同的make命令。 尝试自己感受一下差异!

答案 10 :(得分:1)

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

在我遇到大麻烦之前,因为当我并行打开VPN连接时,构建速度下降了10倍左右。在这种情况下,所有这些DNS查找都通过VPN。

这种观察也可能适用于其他构建工具,不仅仅是基于MinGW,而且它可能在最新的MinGW版本上也有所改变。