MSVC10/MP строит не многоядерные папки в проекте

Я надеюсь, что кто-то укажет на что-то неправильное или обходной путь для того, что мы испытываем.

При компиляции проекта с параметром /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 родительский закрывается, и появляется следующее дерево процессов:

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.


person Zac    schedule 11.08.2011    source источник
comment
Это не то, что вы могли видеть. Параллельное построение на основе проекта, а не исходного файла. Вы должны увидеть один экземпляр cl.exe, создающий оба файла .cpp. И если между проектами вообще нет никакой зависимости (что маловероятно), то одновременно будут создаваться только эти два проекта.   -  person Hans Passant    schedule 12.08.2011
comment
Вы пробовали это? Вы знакомы с /MP? Я знаю о строительстве проектов одновременно, это не то, о чем я спрашиваю.   -  person Zac    schedule 12.08.2011
comment
Что отображается в вашем журнале MSBuild? Я только что создал новый проект VS 2010 C++ на своем компьютере со структурой каталогов, которую вы описали выше, добавил в проект все файлы C++ и построил из командной строки с помощью MSBuild. MSBuild зарегистрировал одно выполнение CL.exe и передал все файлы (из обоих каталогов) в одной командной строке с параметром /MP.   -  person Bilal    schedule 13.08.2011
comment
@Bilal, я попробую в понедельник и посмотрю, что у меня получится.   -  person Zac    schedule 13.08.2011


Ответы (4)


Использование %(RelativeDir) в проекте «Имя файла объекта» (в XML-файле vcxproj, /Fo в командной строке CL.exe) заставляет msbuild группировать файлы cpp в cl.exe для каждого каталога. Это может существенно повлиять на преимущества, получаемые от использования /MP.

Обратите внимание, что если ваш проект использует %(RelativeDir) для объектных файлов, вероятно, конфигурация пытается избежать столкновения файлов .obj с файлами cpp с одинаковыми именами в разных папках.

Параметр командной строки /Fo обычно представляет собой папку, в которую компилятор выгружает файлы obj — передается только ОДИН, поэтому все файлы cpp для данного каталога могут быть переданы только CL.exe за раз.

Это было больно, но я рад, что есть причина и решение. Надеюсь, поможет.


Обновить

Товарищ по команде обнаружил, что каждый раз, когда параметр MSBuild отправляется в CL.exe, он, кажется, ломает или сильно ограничивает /MP. Скорее всего, это связано с тем, что для правильной работы /MP CL.exe верхнего уровня должен иметь набор файлов cpp.

Наше решение состояло в том, чтобы не использовать какие-либо параметры msbuild (я думаю, что это %params%) для «Имени объектного файла». Это потребовало, чтобы мы переименовали некоторые файлы cpp, чтобы они не конфликтовали.

Надеюсь, это изменилось в VS2012 или VS2013.

person Zac    schedule 15.08.2011
comment
Интересно, у меня та же проблема с автоматически сгенерированным файлом проекта, и он также последовательно компилируется для всех файлов, для которых ObjectFileName имеет значение относительно $(IntDir). Все они также находятся в отдельных папках, и всегда есть несколько с одинаковым именем (отсюда и спецификация ObjectFileName в XML). Кажется, что тогда нет простого решения, даже если имена объектных файлов не перекрываются... - person OregonGhost; 15.08.2012
comment
У меня точно такая же проблема. Мы реструктурировали наши исходные файлы в подпапки, чтобы получить четкую иерархию папок. Теперь время сборки в 3 раза медленнее. Есть ли вариант исправить это? - person Mark; 12.10.2013

Согласно MSDN, файлы должны быть скомпилированы всякий раз, когда есть поток для их обработки, он в то же время не дает никаких гарантий относительно порядка, в котором файлы должны быть скомпилированы:

Исходные файлы могут быть скомпилированы не в том порядке, в котором они отображаются в командной строке. Хотя компилятор создает набор процессов, содержащих копии компилятора, операционная система планирует выполнение каждого процесса. Следовательно, вы не можете гарантировать, что исходные файлы будут скомпилированы в определенном порядке.

Исходный файл компилируется, когда доступен процесс для его компиляции. Если файлов больше, чем процессов, первый набор файлов компилируется доступными процессами. Остальные файлы обрабатываются, когда процесс завершает обработку предыдущего файла и становится доступным для работы с одним из оставшихся файлов.

Также указано, что количество созданных процессов будет привязано к количеству потоков и файлов в командной строке:

Это значение является меньшим из числа исходных файлов, указанных в командной строке.

Комбинируя их с вещами, мы видим, что компилятор обрабатывает компиляцию постепенно (по файлам), чтобы он мог правильно отправлять работу дочерним элементам, он дозирует эту папку за папкой.

Возможно, вы сможете обойти это, если создадите собственный make-файл, в котором вы сможете получить более одной папки, обрабатываемой одновременно (или попробуйте использовать инструмент MSBUILD.exe).

person Necrolis    schedule 12.08.2011
comment
Я прихожу к выводу, что именно так msbuild группирует файлы cpp и медленно передает их компилятору. - person Zac; 12.08.2011

Я рассмотрел эту проблему здесь с новым подходом, позволяющим избежать конфликтов затирания .obj.

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

Имея в виду вышеизложенное, я могу уточнить: «Каждый раз, когда параметр MSBuild отправляется в CL.exe, он, кажется, нарушает или серьезно ограничивает /MP». /MP работает с одним вызовом CL.exe за раз. Когда вы «отправляете параметр msbuild», на самом деле вы создаете несколько вызовов CL.exe с командными строками, адаптированными для каждого исходного файла. Их нельзя группировать. Связанное выше решение пытается обойти это, адаптируя командную строку к минимальному набору выходных каталогов.

Это должно решить вашу проблему, предотвращая стирание при сохранении высокой степени пакетной обработки, если ваш проект не содержит 100 файлов с именами x.cpp в разных каталогах... обычно, по моему опыту, только несколько конфликтующих .obj в гораздо более крупном проекте.

person zeromus    schedule 18.06.2015

Может подтвердить проблему, и причину было нелегко найти, поэтому давайте добавим еще несколько ключевых слов для других пользователей, которые наткнулись на нее.

Я заметил, что перестроение моего последнего проекта MSVC занимает слишком много времени. В частности, ядра процессора почти не используются, количество процессов cl.exe в диспетчере задач сильно различается, а в окне вывода показаны исходные файлы, которые компилируются в виде пакетов. Компилируется где-то от одного до 16 за раз, небольшая пауза, потом еще набор файлов и так далее. Для сравнения, в моих старых проектах процессор почти полностью используется, и окно вывода показывает непрерывный поток компилируемых исходных файлов.

Теперь большая разница в моем новом проекте заключалась в более эффективном использовании пространств имен с соответствующей структурой каталогов, что означало, что некоторые классы имели одинаковые имена и вызывали конфликты из-за разных файлов .obj, заголовков для одного и того же каталога, что приводило к для изменения имени объектного файла в C/C++ -> Выходные файлы.

Обновления в окне вывода также соответствуют структуре каталогов. Если есть пространство имен/каталог с одним исходным файлом внутри него, то VS показывает только один компилируемый файл за раз. В следующем каталоге есть 10 исходных файлов, и VS показывает, что все 10 компилируются одновременно.

Решений не много. Либо избегайте классов с одинаковыми именами и не меняйте имя объектного файла, либо используйте обходной путь, опубликованный zeromus, он отлично работает. Мое время перестроения увеличилось с 03:15 до 01:20, что является большой разницей и соответствует загрузке ЦП от ~ 35% до 100% в течение большей части компиляции.

VS 2015, 2017 и 2019 все ведут себя таким образом, так что особых надежд на изменение нет.

person oliver253    schedule 30.04.2019