3

我希望有人指出我们正在经历的问题或解决方法。

使用 /MP 编译项目时,似乎只能同时编译同一文件夹中的文件。我使用进程资源管理器滑动命令行并确认行为。

项目过滤器似乎对同时编译的内容没有任何影响。

磁盘上的项目结构:

Folder\
  project.vcxproj  
  source\  
    foo.cpp  
    foo1.cpp  
  other_folder\  
    bar.cpp
    bar1.cpp
    bar3.cpp

初始进程树:

MSBuild.exe
  cl.exe  ( passed: source\foo.cpp source\foo1.cpp )
    cl.exe  ( passed: source\foo.cpp )
    cl.exe  ( passed: source\foo1.cpp )

在 cl.exe 的 2 个子实例完成后,父级关闭并出现以下进程树:

MSBuild.exe
  cl.exe  ( passed: other_folder\bar.cpp other_folder\bar1.cpp other_folder\bar2.cpp )
    cl.exe  ( passed: other_folder\bar.cpp )
    cl.exe  ( passed: other_folder\bar1.cpp )
    cl.exe  ( passed: other_folder\bar2.cpp )

我们的源代码很好地组织在许多级别的嵌套文件夹中,这些文件夹与磁盘上标题的布局相匹配——我不想放弃它来利用 /MP。

4

4 回答 4

3

在“对象文件名”(在 vcxproj XML 中,CL.exe 命令行上的 /Fo)项目中使用 %(RelativeDir) 会导致 msbuild 按目录将 cpp 文件批处理到 cl.exe。这会对使用 /MP 获得的好处产生重大影响。

请注意,如果您的项目将 %(RelativeDir) 用于目标文件,则配置可能会试图避免冲突来自不同文件夹中同名 cpp 文件的 .obj 文件。

/Fo 命令行参数通常是编译器将 obj 文件转储到的文件夹 - 只有一个传递,因此给定目录的所有 cpp 文件一次只能传递给 CL.exe。

那是一种痛苦——但我很高兴有一个理由和一个解决方案。希望能帮助到你。


更新

一位队友发现,只要将 MSBuild 参数发送到 CL.exe,它似乎就会破坏或严重限制 /MP。这很可能是因为 /MP 要正常工作,顶级 CL.exe 需要有一组 cpp 文件。

我们的解决方案是不使用任何 msbuild 参数(我认为它是 %params% )作为“对象文件名”。这要求我们重命名一些 cpp 文件,以免它们发生冲突。

希望这在 VS2012 或 VS2013 中有所改变。

于 2011-08-15T23:03:08.560 回答
1

根据 MSDN,只要有线程处理文件就应该编译文件,同时它不能保证文件的编译顺序:

源文件的编译顺序可能与它们在命令行中出现的顺序不同。尽管编译器会创建一组包含编译器副本的进程,但操作系统会安排每个进程的执行时间。因此,您不能保证源文件将按特定顺序编译。

当一个进程可用于编译源文件时,它就会被编译。如果文件多于进程,则第一组文件由可用进程编译。当进程完成对前一个文件的处理并且可用于处理剩余文件之一时,将处理剩余文件。

它还指出,创建的进程数将受命令行中的线程数和文件数的限制:

该值是您在命令行中指定的源文件数中的较小值

将这些结合起来,我们可以看到编译器以增量方式(文件方式)处理编译,以便它可以正确地将工作分派给子级,它逐个文件夹地处理这个文件夹。

如果您生成了一个自定义 make 文件,您可能能够解决这个问题,您应该能够同时处理多个文件夹(或尝试使用该MSBUILD.exe工具)。

于 2011-08-12T16:18:40.130 回答
1

我在这里用一种新方法解决了这个问题,以避免 .obj 破坏冲突

https://stackoverflow.com/a/26935613/4253427

考虑到上述情况,我可以详细说明“任何时候将 MSBuild 参数发送到 CL.exe,它似乎会破坏或严重限制 /MP”。/MP 一次调用一个 CL.exe。当您“发送一个 msbuild 参数”时,您实际上所做的是使用为每个源文件量身定制的命令行创建多个 CL.exe 调用。这些不能成批。上面链接的解决方案试图通过将命令行定制到最小的输出目录集来解决这个问题。

这应该通过在保持高度批处理的同时防止破坏来解决您的问题,只要您的项目不包含 100 个在不同目录中全部命名为 x.cpp 的文件……通常根据我的经验,只有几个冲突的 .obj在一个更大的项目中。

于 2015-06-18T01:30:49.057 回答
0

可以确认问题,而且原因不容易找到,所以让我们多输入一些关键字,以供其他用户绊倒。

我一直注意到我最新的 MSVC 项目的重建花费了太长时间。特别是 CPU 内核几乎没有被利用,任务管理器中 cl.exe 进程的数量变化很大,输出窗口显示正在编译的源文件,看起来像是批量编译的。一次编译 1 到 16 个文件,稍作停顿,然后是另一组文件,依此类推。相比之下,在我的旧项目中,CPU 几乎被充分利用,输出窗口显示正在编译的源文件的连续流。

现在,我的新项目中最大的不同是更好地使用具有匹配目录结构的命名空间,这意味着最终会得到一些具有相同名称的类,并由于指向同一目录的不同 .obj 文件而导致冲突,这会导致在 C/C++ -> 输出文件中更改对象文件名。

对输出窗口的更新也与目录结构相匹配。如果有一个名称空间/目录,其中包含一个源文件,那么 VS 一次只显示一个正在编译的文件。下一个目录有 10 个源文件,VS 显示所有 10 个正在同时编译。

解决方案并不多。避免使用相同名称的类并且不更改对象文件名,或者使用zeromus 发布的解决方法,它的功能很好。我的重建时间从 03:15 到 01:20,这是一个相当大的差异,并且在大多数编译过程中,CPU 利用率从 ~35% 变为 100%。

VS 2015、2017 和 2019 都是这样运行的,所以改变的希望不大。

于 2019-04-30T22:32:48.627 回答