Visual Studio - 并行构建不会提高性能

Visual Studio - Parallelizing builds doesn't improve performance

我一直在研究一些大型 visual studio C++ 项目,似乎花在构建预编译头文件上的时间比单独的源文件要多。

我已经对项目本身做了一些更改(启用 /MP 标志并在 "Tools ==> Options" 中设置最大作业数),构建速度似乎提高了大约 10% ,但没有同项目的 Linux 版本那么大的改进,在 make 中指定 -j 选项时 运行 快了将近 4-5 倍。

首先,是否需要设置任何其他选项以利用多核系统来提高构建速度,尤其是生成预编译头文件时?

其次,似乎通过启用多处理器支持,我不能再这样做了"incremental builds"。如果我理解正确,每个 "Build" 将与完整的 "Rebuild" 或 "Clean, Build" 操作相同。是这样吗?最后我检查了一下,如果 makefile 编写得当,GNU makefile 项目就不会受到这个限制,所以像 Visual Studio 这样现代且昂贵的工具会遇到这样的问题似乎很奇怪。

谢谢。

上周我一直在调查这个问题。事实证明,启用并行构建的底层 "msbuild" 工具(“/m:njobs”)可以并行构建项目,但项目中的各个任务始终是串行的。考虑到项目之间的依赖性,这通常意味着并行化机会的数量非常有限。

我使用 CMake 生成解决方案和项目文件,这意味着可以比较使用不同构建系统的生成器的相同构建。我一直在使用 Ninja 构建工具,它可以更好地利用并行化。使用资源监视器监视所有 CPU 内核的使用情况表明 MSBuild 使用 1 个内核,有时使用 2 个内核。Ninja 将所有 8 个内核都限制在我工作站上绝大多数构建的极限。对于我的代码,这相当于在 24 核构建节点上使用 msbuild 花费 125 分钟,而使用 Ninja 花费 45 分钟——它不是 24 倍加速的事实是单元测试占用了大部分时间并且没有并行化,但是与 msbuild 不同,我确实看到它在构建过程中固定了所有 24 个内核。

所以总的来说,Visual Studio/msbuild 对有效并行化的支持非常有限,如果你想尽可能快地构建,你将不得不在别处寻找更好的工具。我发现 CMake/Ninja 是一个有效的选择。

Visual Studio 有两种类型的并行构建:项目内和项目间。

在一个项目中,当启用 "Multi-Processor Compilation" 选项 (/MP) 时,它将 运行 C++ 编译器的多个副本(一旦构建了预编译 header)。链接器 运行 是单线程的,但我还没有尝试 Link 时间代码生成来了解它的作用。如果您的项目中的文件很少,您不会从中看到太多好处。

它做的另一个并行构建是同时进行多个项目,并使用工具 => 选项进行设置。这将同时构建多个 C++、C# 和其他类型的项目,只要项目依赖项允许(即,如果两个项目不相互依赖,则可以同时构建)。

我已经成功地使用了一个或另一个,这取决于我的解决方案的内容和大小。启用两者可能是有益的,但您也可能会为您的系统超额预订可用的 CPU 线程。如果您的解决方案包含所有或大部分 C++ 项目,请选择一个或另一个。在一个 8 核系统上构建 8 个项目,每个项目都尝试使用 8 个进程,这可能有点费力。

为了减少预编译 header 的构建时间,您可以在包含 windows header 之前定义 WIN32_LEAN_AND_MEAN 宏以排除很少使用的内容。 windows.h中也定义了一些NOxxx宏来排除API中的其他部分。 (参见 What does #defining WIN32_LEAN_AND_MEAN exclude exactly?。)

为了回答您的第二个问题,/Gm 增量重建选项将检查 class 定义是否在修改后的 header 中更改,以查看源文件是否需要重建。这是对 VS(和 make)执行的正常时间戳检查的补充和不同。重建或 Clean/Build 将删除所有编译器生成的文件并重建所有内容,无论文件是否已更改。虽然 /MP 标志不适用于 /Gm(编译器会忽略 /MP,如果它们都给定),它不会阻止 make 使用的基于时间戳的依赖性检查。