Visual Studio 2010中C++并行构建调优

有哪些参数可以调整?

项目级并行构建是由MSBuild控制的,它是在Visual Studio的解决方案级进行设置的(实际上Visual Studio是为每个用户都保存了设置,与你想象的可能有点不一样,你可能认为不同解决方案有不同的设置,但UI却不允许你这么做),默认情况下,Visual Studio选取你机器上的处理器数量作为最大并行构建项目的数量,如图1所示,你可以将这个数字调大调小找出一个并行构建速度最快的合适值,有些人可能喜欢将其调小,以便在构建期间还可以做点其它工作。

Visual Studio 2010中C++并行构建调优

图 1 并行构建项目的最大数量

虽然MSBuild从Visual Studio接管了部分功能,但这里的设置仍然保持和Visual Studio 2008一样。

如果你正在构建C++或C++/CLI项目,还有一个地方你可以设置并行构建参数,CL编译器支持/MP参数,它告诉编译器使用自身的一个单独实例同时构建它的子集,默认的并行数仍然使用了CPU的数量,但你可以指定一个值,如/MP5,注意现在情况发生了一点变化,因此我要告诉你如何找到这个值,以及在MSBuild格式项目文件中看起来是什么样子。

打开项目的“属性”窗口,转到“C/C++”*“常规”窗口,我建议你选择“所有配置”和“所有平台”,在后面你才有更多的可选项。

Visual Studio 2010中C++并行构建调优

图 2 项目属性设置

象往常一样,通过转储,你可以看到项目文件中有什么内容,在“解决方案资源管理器”中的节点上点击右键,选择“编辑”。

图 3

Visual Studio 2010中C++并行构建调优

下图显示了项目文件的一部分代码。

Visual Studio 2010中C++并行构建调优

图 4 项目文件代码示例

在这里,所有类型为“ClCompile”的项目都自动拥有元数据MultiProcessorCompilation,默认值为true,除非明确指定了一个不同的值。

顺便说一下,MSBuild项目通常都是一个文件,它们的子元素是元数据,下面是一个例子,注意它们被放在一个“ItemGroup”中。

Visual Studio 2010中C++并行构建调优

图 5 MSBuild项目文件示例

因为这是一个元数据,如果是高手,完全可以直接修改每个文件,你需要为使用了#import的文件禁用/MP,因为它不支持/MP,其它不支持/MP的特性是/Gm,/Gm表示渐进式编译,更多参数请参考http://msdn.microsoft.com/en-us/library/bb385193.aspx。

回到多处理器CL,如果你想明确告诉CL有多少并行编译执行,Visual Studio可通过/MP实现,它出现在全局设置中。

Visual Studio 2010中C++并行构建调优

图 6 C++编译最大并行任务数设置

Visual Studio通过一个全局属性CL_MPCount进行设置,这意味着在Visual Studio外构建时将不受任何影响。

如果你选择一个更细粒度的值,你就不能使用图形界面进行设置了,因为你根本看不到它的设置项,这时就必须打开项目文件直接进行修改。在CLICompile项目上这是一个完全不同的元数据块,叫做“ProcessorNumber”,你可以设定一个从1到你认为合理的一个值,然后在/MP后也追加一个同样的值,如果没有<MultiProcessorCompilation>,它就会被忽略。

Visual Studio 2010中C++并行构建调优

图 7 ProcessorNumber和MultiProcessorCompilation设置

图中出现的波浪线是一个小小的bug,直接忽略它。

如何在命令行上构建?

/MP设置来自项目文件,因此在命令行上进行设置作用是一样的,它是整个MSBuild的一部分,在命令行上构建和在Visual Studio中构建是一样的效果吗?在Visual Studio中设置的全局并行设置不会影响到命令行,你必须亲自给msbuild.exe传递/m参数,这个参数是可选的,如果你不设置,它就使用CPU的数量,但和Visual Studio开箱即用的特性不一样,在命令行中如果不指定/m参数,它只会使用1颗CPU,这个问题可能在将来的版本中会得到修正。

Visual Studio 2010中C++并行构建调优

图 8 命令行构建参数

如果想给/MP选任意的值,你可以设置一个环境变量,或象Visual Studio那样传递一个属性CL_MPCount。

在每个项目上都设置/MP是很烦人的,怎么才能提高设置效率?

你可能想在多个项目上使用/MP,但你又不想在每个项目上都设置一遍,Visual Studio解决这类问题的办法是使用属性表。首先从“视图”菜单打开“属性管理器”,根据你使用的设置它的确切位置可能不一样,下面是一个C++项目设置的位置。

Visual Studio 2010中C++并行构建调优

图 9 视图菜单中的属性管理器

在一个项目上点击右键,选择“添加新的属性表”:

Visual Studio 2010中C++并行构建调优

图 10 给项目添加新的属性表

我给它取了一个名字叫做“MultiprocCpp.props”,你将会看到该项目的所有配置都将添加这个属性表,在它上面点击右键,你将看到与项目相同的属性窗口,但这个时候你编辑的是属性表,再次将“Multi-processor Compilation”设为“YES”。关闭属性窗口,在属性管理器中选择属性表,然后点击“保存”。

现在可以在编辑器中打开新建的MultiprocCpp.props文件,我的看起来如下:

Visual Studio 2010中C++并行构建调优

图 11 在编辑器中打开MultiprocCpp.props

仔细查看这个项目文件,你可以看到属性表通过一个Import标签应用到每个配置中了,这一点和C++中的#include非常类似。

Visual Studio 2010中C++并行构建调优

图 12 通过Import引用属性表

现在我们就可以重用之前在项目文件中的定义了,于是我可以在属性管理器中选中多个项目,然后点击右键,选择“添加现有属性表”。

Visual Studio 2010中C++并行构建调优

图 13 为多个项目同时指定属性表

OK!现在所有项目编译时都带有/MP参数了。

在某些情况下,你可能想要更简单一点,例如,你可能想要删除大量的属性表,幸运的是,MSBuild 4.0有一个强大的,完整的对象模型,你可以使用它,再编写几行代码就可以搞定这种工作了。

如果你不想通过图形界面进行设置,完全可以自己手动进行编辑,例如,在VS自己的构建中,我们在每个项目的顶级都设置了一套属性。

Visual Studio 2010中C++并行构建调优

图 14 手动设置项目顶级属性

在这里我们定义了所有类型的全局设置,并导入了其它设置,我将在以后的文章中介绍组织大型构建树的方法。

并行数量太多了也不好

一般来说,利用完所有处理器或处理器核心就已经足够了,否则可能会导致机器变慢甚至崩溃,下图就显示了这样一个例子。

Visual Studio 2010中C++并行构建调优

图 15 太多的并行构建进程很容易让机器崩溃

我是在一台8 CPU的机器上做的这个实验,我把解决方案中的所有项目全部开启/MP了,然后使用msbuild.exe /m进行构建(我使用命令行进行构建不会出现这个问题,但在Visual Studio中进行构建就会出现),如果相关依赖不能阻止它,MSBuild将立即启动8个项目,每个CL将会一次运行自己的8个实例,因此总共会有64个CL运行考验我们的处理器核心和磁盘,这样做不但不能提升速度,反倒会使性能急剧下降。

你可能希望有一天系统能够实现自我调整,但如果现在遇到这样的问题,你不得不手工调整。下面是一些建议

◆将全局值设小一点

例如将/m:4减少到/m:3,或使用属性表将/MP修改为/MP2,如果你的构建中还有其它问题,如有许多的并行项目,但并行的CL不够,反之亦然,这个时候你都应该将全局并行构建参数调小。

◆为每个项目和配置调整/MP

有些时候使用/MP可能不是最佳的办法,你也可以通过配置进行调整,Retail配置可能会使速度变得更慢,因为编译器要做的优化更多了,为Retail开启/MP而不是为Debug开启/MP可能更有意义。

◆获得超级定制

在你的团队中,你可能有一系列硬件,也许你的开发人员使用的是双CPU机器,但夜间构建是在一台8 CPU的机器上进行的,两者构建时需要的来源是一样的,你希望两者的速度都不能太慢,在这种情况下,你可以使用环境变量,或是在MSBuild标签上设置条件,几乎所有MSBuild标签都可以设置条件。

下面是一个例子,当“MultiprocCLCount”有一个大于零的值时,就可以使用这个值启用/MP。

Visual Studio 2010中C++并行构建调优

图 16 通过环境变量调整处理器数量

MSBuild启动时将所有环境变量的值作为初始属性值,因此在我更快速的机器上,我将MultiprocCLCount的值设为8,而在我的开发用机上,我将其设为2。

类似的方法还可以应用到MSBuild.exe的/m参数中,如/m:%MultiprocMSBuildCount%,

在外来条件中还有其它属性可能很有用,如$(Number_Of_Processors)表示逻辑处理核心数量,它来自环境变量。$(MSBuildNodeCount)是传递给msbuild.exe /m参数的值,在Visual Studio中,这个值是通过“工具”*“选项”进行设置的。

相关推荐