Как определить максимальное число для передачи в опцию make -j?

31

Я хочу собрать как можно быстрее. Пойди разберись. И хотел бы автоматизировать выбор номера, следуя -jопции. Как я могу программно выбрать это значение, например, в сценарии оболочки?

Вывод nprocэквивалентен числу потоков, которые у меня есть для компиляции?

make -j1 make -j16

tarabyte
источник

Ответы:

34

nprocдает число доступных ядер / потоков ЦП, например, 8 на четырехъядерном ЦП, поддерживающем двустороннюю SMT.

Количество заданий, которые вы можете выполнять параллельно с makeиспользованием этой -jопции, зависит от ряда факторов:

  • объем доступной памяти
  • объем памяти, используемой каждой makeработой
  • степень, до которой makeзадания связаны с вводом / выводом или с процессором

make -j$(nproc) это хорошее место для начала, но вы можете использовать более высокие значения, если вы не исчерпаете доступную память и не начнете перебивать.

Для действительно быстрых сборок, если у вас достаточно памяти, я рекомендую использовать так tmpfs, чтобы большинство заданий было связано с процессором и make -j$(nproc)работало как можно быстрее.

Стивен Китт
источник
3
и ccacheдля дальнейшего восстановления, но это ОТ
solsTiCe
1
Стоит ли здесь использовать что-то вроде параллельной GNU?
Тердон
Если я буду использовать a tmpfs, буду ли я ограничен размером каталога, который всегда меньше моего физического объема ОЗУ?
Тарабайт
2
Это не очень хороший ответ, но в строгом духе вопроса о программном определении самого быстрого значения «j» вы можете зациклить j от 1 до некоторого разумного верхнего предела (2x nproc ??) и заключить make в timeвызов. Очистите результаты, снова промойте и промойте значения time / j.
Джефф Шаллер
3
@terdon Нет. Make - это все о разрешении зависимостей, что означает, что задания все равно должны выполняться в определенном порядке. GNU параллель не заботится об этом. С другой стороны, решить, какие задания безопасно выполнять параллельно, а какие нет, - сложная задача. Всем программам make, которые предлагали параллельные сборки, потребовались годы, пока они не стали пригодными для использования.
lcd047
6

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

Компиляция 100 крошечных C-файлов может быть быстрее, чем компиляция одного огромного или наоборот. Построение небольшого очень сложного кода может быть медленнее, чем создание огромного количества прямого / линейного кода.

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

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

Я могу продолжать и продолжать. Дело в том, что вы должны реально оценить свою сборку в том же контексте, для которого вы хотите оптимизировать j-фактор. Комментарий @Джеффа Шаллера применим: итерируйте, пока не найдете свое лучшее соответствие. Лично я бы начал со значения nproc, попробуйте сначала вверх и вниз, только если попытки вверх показывают немедленную деградацию.

Может быть хорошей идеей будет сначала измерить несколько идентичных сборок в предположительно идентичных контекстах, просто чтобы получить представление об изменчивости ваших измерений - если слишком высокое, это может поставить под угрозу все ваши усилия по оптимизации (20% -ая изменчивость полностью затмевает улучшение на 10% / ухудшение чтения в поиске j-фактора).

И наконец, IMHO, лучше использовать (адаптивный) сервер заданий, если он поддерживается и доступен, вместо фиксированного j-фактора - он последовательно обеспечивает лучшую производительность сборки в более широком диапазоне контекстов.

Дан Корнилеску
источник
хорошо поставлено относительно зависимостей базовой сборки. Вы можете прокомментировать передачу без фиксированного числа с -jпараметром? напр.make -j
тарабайт
4
make -jбудет порождать столько заданий, сколько позволяют зависимости, как бомба-вилка ( superuser.com/questions/927836/… ); сборка будет в лучшем случае сканировать, тратя больше ресурсов ЦП на управление процессами, чем на их запуск ( superuser.com/questions/934685/… ), а в высокопараллельных сборках системе не хватит памяти / swap или pid #, и сборка завершится неудачно ,
Дэн Корнилеску
3

Самый простой способ - использовать nprocтак:

make -j`nproc`

Команда nprocвернет количество ядер на вашем компьютере. Обернув его в галочки, nprocкоманда выполнится первой, вернет число, и это число будет передано make.

У вас может быть некоторый анекдотичный опыт, когда выполнение core-count + 1 приводит к более быстрому времени компиляции. Это в большей степени связано с такими факторами, как задержки ввода-вывода, другие задержки ресурсов и другая доступность ограничений ресурсов.

Чтобы сделать это nproc+1, попробуйте это:

make -j$((`nproc`+1))
010110110101
источник
0

Если вы хотите написать makeкоманду, чтобы использовать столько параллельных рабочих, сколько у вас виртуальных процессоров, я предлагаю использовать:

nproc | xargs -I % make -j%

Который может быть записан как отдельная команда или как RUNдиректива внутри Dockerfile(так как Docker не поддерживает вложенные команды)

Максим Ганенко
источник