【问题标题】:How to improve Visual C++ compilation times?如何提高 Visual C++ 编译时间?
【发布时间】:2023-03-24 00:36:01
【问题描述】:

每次提交时,我都会在 buildbot 中编译 2 个 C++ 项目。两者都是大约 1000 个文件,一个是 100 kloc,另一个是 170 kloc。从 gcc (4.4) 到 Visual C++ (2008) 的编译时间非常不同。

一个项目的 Visual C++ 编译需要 20 分钟。他们无法利用多个核心,因为一个项目依赖于另一个。最后,在 Debug 和 Release 中完整编译这两个项目(32 位和 64 位)需要超过 2 1/2 小时。

一个项目的 gcc 编译需要 4 分钟。它可以在 4 个内核上并行化,大约需要 1 分 10 秒。 2 个项目的 4 个版本(调试/发布,32/64 位)的所有 8 个构建都在不到 10 分钟内编译完成。

Visual C++ 编译时间发生了什么变化?它们基本上慢了 5 倍。

编译 C++ kloc 的平均预期时间是多少?我的是 7 s/kloc with vc++ 和 1.4 s/kloc with gcc。

可以做些什么来加快 Visual C++ 上的编译时间吗?

【问题讨论】:

  • 磁盘只有 1/3 满。我怀疑碎片和 DLL 副本能否将编译时间缩短 5 倍!可能只有 10%,但不会更多。
  • 感谢您的意见...但只是好奇...问题是头文件中的实例化,还是我提到的其他问题之一?
  • 对我们有很大帮助的东西是将所有临时文件、中间文件和 pch 文件移动到 ram 磁盘上,但尽管 Windows 机器有 ssds 和 linux 机器有 hds,但仍然没有 GCC 快。我们在 Dual Xeon E5440 上进行编译,我发现“make -j33”的编译时间比人们推荐的“-j9”要好得多(我运行了一个简单的脚本来对从 0 到 99 的每个 -j 设置进行基准测试)跨度>

标签: c++ visual-c++ gcc comparison compilation-time


【解决方案1】:

减慢 VC++ 编译器的一件事是,如果您有一个头文件来初始化非平凡const 值类型的具体实例。您可能会在 std::string 类型的常量或 GUID 上看到这种情况。它会影响编译和链接时间。

对于单个 dll,这会导致 10 倍的减速。如果您将它们放在预编译的头文件中,或者只是在头文件中声明它们并在 cpp 文件中初始化它们,这会有所帮助。

请查看病毒扫描程序,并确保尝试使用预编译的标头,没有它您将无法看到 VC++ 的最佳状态。

哦,是的,请确保 %TMP% 文件夹与您的构建写入所在的分区位于同一分区,因为 VC++ 会生成临时文件并稍后移动它们。

【讨论】:

  • 我对第一点很好奇;你怎么能在头文件中定义一个变量而不得到多个定义呢?当然,除非它不是同一个变量,因为它被定义或未命名的命名空间更改。但在这些情况下,我想这与在 cpp 文件中定义它们是一样的,不是吗?
  • 就我而言,它们被声明为consts。我将对其进行编辑。我没有编写代码。我通过转发声明名称来修复它,并在 cpp 文件中对其进行初始化。
  • stackoverflow.com/questions/31028941/… 在接受的答案中删除 static 关键字导致巨大的构建时间,可能是相关的
【解决方案2】:

您如何构建 Visual Studio 项目?您是否只是在项目和/build 中运行 ide (devenv),或者您是否有一个类似于我假设您用于 gcc 的 makefile。我假设两个版本都使用类似的 makefile,但我认为值得检查。

您是否为任一编译器使用预编译头文件?如果您不使用 VS 的预编译头文件,那么您可能希望切换到使用它们。我个人建议使用#pragma hdrstop 方法,而不是单个的全包头文件,但如果您当前没有使用预编译的头文件并想尝试一个强制包含的单个全包头文件(使用@987654324 @编译器命令行开关)可以快速测试,无需任何代码更改。

我在这里写过/FI#pragma hdrstophttp://www.lenholgate.com/blog/2004/07/fi-stlport-precompiled-headers-warning-level-4-and-pragma-hdrstop.html

【讨论】:

  • 我正在使用 vcbuild.exe 在命令行上编译 Visual Studio 项目。 (MSBuild.exe 或 devenv.exe /build 持续时间相同)
  • +1 表示/FI 标志。虽然不是#pragma hdrstop 的忠实粉丝
  • @Manuel,你为什么不喜欢#pragma hdrstop?这是一种非常方便的方法,允许在没有预编译的情况下进行干净的最小依赖构建以及使用预编译头文件的快速构建,恕我直言,这是确保代码只包含它需要的内容的好方法,这使得它更容易重用......
  • @Len - 也许我错过了 hdrstop 的意义,但我认为我用 /FI 也能达到同样的效果,而且我不必以任何方式修改我的源文件
  • @Manuel, #pragma hdrstop 允许对您需要放入预编译头文件以及可以包含在 C++ 文件中的内容进行更精细的调整,并且比 /FI 更“隐藏”路线。
【解决方案3】:

不知道这是否仍然是一个问题以及您在此期间获得了多少改进,但如果仍然存在 msbuild 不知道如何在一个项目中同时进行编排(每个 cpp 应该可以单独构建,除非您有一些 codegens - codegens 最好移动到一个单独的项目中)你必须下载驱动程序开发工具包或 .NET SSCLI 因为它们都有 nmake,构建已知可以很好地并行化事情。 SSCLI 已经有了构建构建设置,不要记得如果 DDK 有一些构建示例,您是否必须从头开始。

还有一点陈旧的article on MSBuild 并行化没有详细说明,但提到了实际 msbuild 和 msbuild + sln 之间的一些差异。如果 /MP 与 /Gm 是唯一的问题,那么您可能需要制作一个小脚本或 C# exe 来编辑 .proj 文件以进行实验室构建。或者在项目中使用显式 cmd 行覆盖并从环境变量中获取该选项。

【讨论】:

    【解决方案4】:

    John Lakos 所著的“大型 C++ 软件设计”一书提供了许多关于构建大型项目的代码和设计的技巧。包括许多加快编译速度的技巧。与 Visual C++ 没有直接关系,但还是值得一读。

    【讨论】:

      【解决方案5】:

      一次编译和链接一个 cpp 文件,即使头文件更改会影响多个 cpp 文件。这可以通过 Visual Studio 宏来实现:

      Dim WithEvents myTimer As Timers.Timer
      
      Sub CompileAndLinkCurrentCppFile()
          DTE.ExecuteCommand("Build.Compile")
          myTimer = New Timers.Timer
          myTimer.Interval = 0.05
          myTimer.Start()
      End Sub
      
      Sub myTimer_Elapsed(ByVal ee As Object, ByVal dd As Timers.ElapsedEventArgs) Handles myTimer.Elapsed
          If DTE.Solution.SolutionBuild.BuildState <> vsBuildState.vsBuildStateInProgress And DTE.Solution.SolutionBuild.LastBuildInfo <> 1 Then
              myTimer.Stop()
              DTE.ExecuteCommand("Build.Link")
          End If
      End Sub
      

      【讨论】:

      • 这与 Ctrl+F7 有何不同?
      【解决方案6】:

      我写了两篇关于减少编译时间的技术的文章。在这些技术中,precompiled headerunity builds 上的帖子可能会帮助您缩短编译时间。他们附带了透明地处理技术的 CMake 脚本。

      【讨论】:

        【解决方案7】:

        这不是问题的直接答案,但在我的公司,我们正在使用 IncrediBuild 进行分布式编译。它确实加快了编译过程。 http://incredibuild.com/visual_studio.htm

        【讨论】:

        • Incredibuild 可以在多台机器上使用 CPU 内核,但当前项目设置无法利用本地机器上的所有内核。 IE。您首先需要处理该级别的并行化。
        【解决方案8】:

        也许依赖检查存在问题,除非您强制完全重建。

        你可以制作一些静态库。将很少更改的代码放入库中。

        构建程序最慢的部分:

        1. 打开和关闭文件。
        2. 解析和翻译源 文件。

        一般来说,链接和可执行文件创建阶段是最快的。

        你确定了吗:

        1. 哪个阶段最慢?
        2. 哪些文件编译速度最慢?

        请记住,在确定效率时,请始终分析(以一种或另一种方式)。

        【讨论】:

          【解决方案9】:

          会有这样的差异似乎很奇怪......但你也没有理由不能利用 Visual 上的多核!

          基本上你有 4 种编译模式:(Debug/Release)x(32bits/64bits),每一种都是完全独立的,你可以完美地并行运行这 4 个,充分利用可用的 4 个内核。或者干脆在 Visual Studio 上尝试 MultiProcessor 方法。

          但是,这不会削减它。 150 分钟与 10 分钟是一个巨大的差距。根据我的个人经验,减少编译时间有两个主要因素:

          • 在本地磁盘上使用所有文件(必要时使用从远程磁盘复制)以及在本地创建的所有文件 (.o .so)
          • 使用所有可用的内核,如果可以的话,甚至可以使用 Multi Machines(distcc 等...)

          【讨论】:

          • 也许我可以试试这个,然后运行 ​​vcbuild.exe 来构建相同的项目,但同时构建不同的配置。
          • 我无法在 Visual 上利用多核是有原因的:Visual C++ 不支持同时从同一个项目编译多个文件。
          • 部分正确,因为 /MP 选项与为我们所有 Debug 构建设置的 /Gm 选项(增量构建)不兼容。奇怪的是,我们将相同的项目用于开发人员工作站构建和自动化构建机器人构建。
          【解决方案10】:

          项目相互依赖并不意味着不可能进行并行化。构建系统足够聪明,可以找出并避免严重的依赖,否则 gcc 将无法使用 4 个内核。

          那么(除了其他步骤),为什么不尝试在 Visual Studio 中使用 /MP 启用多处理(请参阅 http://msdn.microsoft.com/en-us/library/bb385193.aspx)。

          【讨论】:

          • 因为 Visual Studio 中的多处理不能按编译单元(.cpp 文件)拆分工作,只能按项目!
          • Stage:至少在我的机器上(并且根据上面引用的文档)VS2008、VS2010 Beta2 都使用多个内核,即使只构建一个项目也是如此。
          • @dtrosset: VS2008 可以按编译单元分割。这就是 /MP 标志的作用。在 VS2005 中,唯一可用的并行化形式是每个项目。
          • 由于 /MP 与 /Gm(增量构建)不兼容,选择哪一个?在开发人员工作站上运行缓慢,或者在自动构建上运行缓慢。
          • 为什么它们都必须使用完全相同的标志?使用 /MP 进行自动构建,如果 /Gm 在开发人员机器上更快,请改用它。
          【解决方案11】:

          您是在同一台机器上构建吗?你用的是同一个操作系统吗?在比较 Cygwin 中的 GCC 和在托管 Cygwin 的 Windows 中运行的 VirtualBox 机器中的 GCC 时,我发现速度差异在 3-10 倍左右。

          【讨论】:

          • 不是同一台机器,但它们是等价的。 Visual Studio 在 Windows XP 32 位系统上运行。 gcc 在虚拟化 (!) Debian Linux 32 位系统上运行。
          • 嗯,根据我的经验,这可以解释整个时间差异。不知道该怎么做——也许在 debian 环境中通过 wine 运行 MS 编译器?您需要 MS 编译器,还是可以切换到 mingw?在这种情况下,您可以从您的 debian 设置进行交叉编译。
          【解决方案12】:

          首先,在大多数情况下,您可以并行构建同一个项目的调试和发布配置。

          此外,您所描述的内容听起来非常慢 - 看起来您没有在 VC++ 中使用预编译头文件或使用不正确 - 它们专门用于缩短编译时间。

          【讨论】:

          • 我根本没有使用预编译的头文件。既不是 vc++ 也不是 g++;
          猜你喜欢
          • 2011-08-12
          • 1970-01-01
          • 1970-01-01
          • 2010-09-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多