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 )

После того, как 2 дочерних экземпляра 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.

Ответ 1

Использование% (RelativeDir) в "Имя файла объекта" (в командной строке vcxproj XML,/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%) для 'Object File Name'. Это потребовало переименования некоторых файлов cpp, чтобы они не сталкивались.

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

Ответ 2

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

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

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

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

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

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

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

Ответ 3

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

fooobar.com/questions/4490/...

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

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

Ответ 4

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

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

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

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

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

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