Visual Studio - 并行化构建不会提高性能
Posted
技术标签:
【中文标题】Visual Studio - 并行化构建不会提高性能【英文标题】:Visual Studio - Parallelizing builds doesn't improve performance 【发布时间】:2015-08-15 21:43:26 【问题描述】:我一直在玩一些大型的 Visual Studio C++ 项目,似乎花费在构建预编译头文件上的时间比构建单个源文件的时间更多。
我已经对项目本身进行了一些更改(启用了/MP
标志并在“工具 ==> 选项”中设置了最大作业数),构建似乎快了 10% 左右,但是几乎没有相同项目的 Linux 版本的改进那么大,当在 make
中指定 -j
选项时,Linux 版本的运行速度快了近 4-5 倍。
首先,是否需要设置任何其他选项以利用多核系统来提高构建速度,尤其是在生成预编译头文件时?
其次,似乎通过启用多处理器支持,我不能再进行“增量构建”了。如果我理解正确,每个“构建”都将与完整的“重建”或“清理、构建”操作相同。是这样吗?最后我检查了一下,如果 makefile 编写正确,GNU makefile 项目就不会受到这个限制,所以像 Visual Studio 这样一个现代且昂贵的工具会遇到这样的问题似乎很奇怪。
谢谢。
【问题讨论】:
从我个人的经验来看,通常是链接器需要很长时间。所以我通常禁用 IPO、整个程序优化和链接时间代码生成。这会将所有“昂贵”的步骤移到高度可并行化的主编译中。只有在生产版本中,我才会重新打开所有这些东西。 【参考方案1】:上周我一直在调查这个问题。事实证明,启用并行构建的底层“msbuild”工具(“/m:njobs”)可以并行构建项目,但项目中的各个任务始终是串行的。鉴于项目之间的依赖关系,这通常意味着并行化机会的数量非常有限。
我使用 CMake 生成解决方案和项目文件,这意味着可以使用不同构建系统的生成器来比较相同的构建。我一直在使用 Ninja 构建工具,它可以更好地利用并行化。使用资源监视器监视所有 CPU 内核的使用情况表明,MSBuild 使用 1 个内核,有时使用 2 个内核。Ninja 将所有 8 个内核与我工作站上绝大多数构建的限制挂钩。对于我的代码,这意味着使用 msbuild 需要 125 分钟,而在 24 核构建节点上使用 Ninja 需要 45 分钟——事实上它不是 24 倍加速,因为单元测试占用了大部分时间并且没有并行化,但是我确实看到它在构建过程中与 msbuild 不同,它与所有 24 个内核挂钩。
因此,一般的带回家的信息是,Visual Studio/msbuild 对有效并行化的支持非常有限,如果您想尽可能快地构建,您将不得不在其他地方寻找更好的工具。我发现 CMake/Ninja 是一种有效的替代方案。
【讨论】:
cmake/ninja 工具可以在 Windows 上运行吗?我可以给他们链接吗? 不管怎样,最近我听说 Visual Studio 2015 能够在项目中并行构建文件。 对于 CMake,请参阅 cmake.org 对于 Ninja,请参阅 martine.github.io/ninja 和下载 github.com/martine/ninja/releases VS 有能力与项目并行构建东西已经有一段时间了。但是,有许多选项会导致它默认被禁用。因此,您需要使用设置才能使其实际工作。根据我的经验,这涉及打开/MP
、禁用整个程序优化和禁用链接时代码生成。
@Mysticial 这似乎只影响罗杰在他的回答中所说的话——并行项目的数量,而不是单个项目中的文件。【参考方案2】:
Visual Studio 有两种类型的并行构建:项目内和项目之间。
在一个项目中,当启用“多处理器编译”选项 (/MP) 时,它将运行 C++ 编译器的多个副本(一旦构建了预编译头文件)。链接器运行单线程,但我还没有尝试过链接时间代码生成来了解它的作用。如果您的项目中的文件很少,您将不会从中看到太多好处。
它所做的另一个并行构建是同时执行多个项目,并使用工具 => 选项进行设置。这将同时构建多个 C++、C# 和其他类型的项目,只要项目依赖项允许(即,如果两个项目不相互依赖,则可以同时构建)。
我已经成功使用了其中一个,具体取决于我的解决方案的内容和大小。启用两者可能是有益的,但您也可能会为您的系统超额预订可用的 CPU 线程。如果您的解决方案包含所有或几乎所有 C++ 项目,请选择其中一个。在一个 8 核系统上构建 8 个项目,每个项目都尝试使用 8 个进程,这可能有点费力。
为了减少构建预编译头文件的时间,您可以在包含 windows 头文件之前定义 WIN32_LEAN_AND_MEAN 宏以排除很少使用的东西。 windows.h 中也定义了一些 NOxxx 宏来排除 API 的其他部分。 (见What does #defining WIN32_LEAN_AND_MEAN exclude exactly?。)
为了回答您的第二个问题,/Gm 增量重建选项将检查类定义是否在修改后的标头中发生更改,以查看是否需要重建源文件。这是对 VS(和 make)执行的正常时间戳检查的补充和不同。 Rebuild 或 Clean/Build 将删除所有编译器生成的文件并重建所有内容,无论文件是否已更改。虽然 /MP 标志不能与 /Gm 一起使用(如果 /MP 都给出,编译器会忽略),但它不会阻止 make 使用的基于时间戳的依赖项检查。
【讨论】:
以上是关于Visual Studio - 并行化构建不会提高性能的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Visual Studio 2010 中并行化数据驱动的单元测试?
如何在 Microsoft Visual Studio 2017 或 2019 中启用或使用自动矢量化以及自动并行化?
如何使用 BatchBuild 并行构建多个 C++ Visual Studio v2015+ 配置