GNU make: должно ли количество заданий равняться количеству ядер ЦП в системе?

87

Похоже, есть некоторые разногласия по поводу того, должно ли количество заданий в GNU make быть равным количеству ядер, или вы можете оптимизировать время сборки, добавив одно дополнительное задание, которое может быть поставлено в очередь, пока другие «работают» .

Лучше использовать -j4или -j5на четырехъядерной системе?

Вы видели (или проводили) какой-либо сравнительный анализ, который поддерживает одно или другое?

Johan
источник
8
Just for the tip, you can use make `nproc` to make CPU independant script :)
VivienG
Если у вас есть сочетание рецептов, связанных с io и cpu, то вам потенциально может понадобиться гораздо больше, чем NCPU. Также рассмотрите возможность добавления параметров -lX. На этот вопрос нет ответа, кроме «это зависит от вашего оборудования и выполняемых задач».
Джеймс Мур
Технически возможно улучшение. Вам нужен медленный диск, недостаточно оперативной памяти и множество небольших файлов исходного кода. Проще было прийти десять лет назад.
Hans Passant

Ответы:

56

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

По моему личному опыту (на 2-ядерном MacBook Pro) -j2 значительно быстрее, чем -j1, но помимо этого (-j3, -j4 и т. Д.) Нет измеримого ускорения. Так что для моей среды «вакансии == количество ядер» кажется хорошим ответом. (YMMV)

Дэвид Гелхар
источник
57

Я запустил свой домашний проект на своем 4-ядерном ноутбуке с гиперпоточностью и записал результаты. Это довольно сложный для компилятора проект, но он включает в себя модульный тест продолжительностью 17,7 секунды в конце. Компиляции не очень интенсивны по вводу-выводу; доступной памяти очень много, а остальная часть находится на быстром SSD.

1 job        real   2m27.929s    user   2m11.352s    sys    0m11.964s    
2 jobs       real   1m22.901s    user   2m13.800s    sys    0m9.532s
3 jobs       real   1m6.434s     user   2m29.024s    sys    0m10.532s
4 jobs       real   0m59.847s    user   2m50.336s    sys    0m12.656s
5 jobs       real   0m58.657s    user   3m24.384s    sys    0m14.112s
6 jobs       real   0m57.100s    user   3m51.776s    sys    0m16.128s
7 jobs       real   0m56.304s    user   4m15.500s    sys    0m16.992s
8 jobs       real   0m53.513s    user   4m38.456s    sys    0m17.724s
9 jobs       real   0m53.371s    user   4m37.344s    sys    0m17.676s
10 jobs      real   0m53.350s    user   4m37.384s    sys    0m17.752s
11 jobs      real   0m53.834s    user   4m43.644s    sys    0m18.568s
12 jobs      real   0m52.187s    user   4m32.400s    sys    0m17.476s
13 jobs      real   0m53.834s    user   4m40.900s    sys    0m17.660s
14 jobs      real   0m53.901s    user   4m37.076s    sys    0m17.408s
15 jobs      real   0m55.975s    user   4m43.588s    sys    0m18.504s
16 jobs      real   0m53.764s    user   4m40.856s    sys    0m18.244s
inf jobs     real   0m51.812s    user   4m21.200s    sys    0m16.812s

Основные результаты:

  • Масштабирование до количества ядер увеличивает производительность почти линейно. Реальное время снизилось с 2,5 до 1,0 минуты (в 2,5 раза быстрее), но время, затрачиваемое на компиляцию, увеличилось с 2,11 до 2,50 минут. Система практически не заметила дополнительной нагрузки в этом бите.
  • Масштабирование от количества ядер к количеству потоков значительно увеличило пользовательскую нагрузку с 2,50 до 4,38 минуты. Это почти удвоение, скорее всего, связано с тем, что другие экземпляры компилятора хотели одновременно использовать те же ресурсы ЦП. Система становится немного более загруженной запросами и переключением задач, в результате чего используется 17,7 секунды. Преимущество составляет около 6,5 секунд при времени компиляции 53,5 секунды, что составляет 12% ускорения.
  • Масштабирование от количества потоков к двойному количеству потоков не дало значительного ускорения. Значения времени 12 и 15, скорее всего, представляют собой статистические аномалии, которые можно не учитывать. Общее затраченное время немного увеличивается, как и системное время. Оба, скорее всего, связаны с увеличением числа переключений задач. В этом нет никакой пользы.

Я предполагаю прямо сейчас: если вы делаете что-то еще на своем компьютере, используйте количество ядер. Если вы этого не сделаете, используйте счетчик потоков. Превышение не дает никакой пользы. В какой-то момент они станут ограниченными в памяти и из-за этого разрушатся, что сделает компиляцию намного медленнее. Строка «inf» была добавлена ​​намного позже, что вызвало у меня подозрение, что для 8+ заданий было некоторое тепловое дросселирование. Это действительно показывает, что для этого размера проекта нет действующих ограничений по памяти или пропускной способности. Однако это небольшой проект с 8 ГБ памяти для компиляции.

нарядный
источник
Согласно stackoverflow.com/questions/56272639/… , вы можете получить преимущество, выполняя больше задач, чем у вас есть ЦП, но только если ваши задачи тратят значительную долю времени в ожидании сетевого ввода-вывода. Однако для задач компиляции это не так.
ivan_pozdeev
30

Я лично использую make -j nгде n - «количество ядер» + 1.

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

В любом случае, вы должны быть осторожны, потому что некоторые make-цепочки просто несовместимы с этой --jobsопцией и могут привести к неожиданным результатам. Если вы испытываете странные ошибки зависимости, просто попробуйте makeобойтись без них --jobs.

ereOn
источник
19
Объяснение (хотя и не может ручаться за его научность) состоит в том, что "+ 1" дает дополнительную работу, которая выполняется, в то время как любое из других n заданий выполняет ввод-вывод.
Laurynas Biveinis,
@LaurynasBiveinis: Но тогда задания выполняются на разных ядрах все время, по крайней мере, чаще, чем при более консервативных настройках, когда заданию предоставляется возможность оставаться на одном ядре в течение более длительного периода времени. Здесь есть плюсы и минусы ...
krlmlr 08
1
Количество ядер + 1 также является моей настройкой по умолчанию. Одна из проблем заключается в том, что в любой достаточно большой системе make, кажется, задерживает связывание и выполняет все шаги связывания вместе. На этом этапе у вас заканчивается оперативная память. Ба!
bobbogo
4
некоторые make-chain просто несовместимы с параметром --jobs -> Это означает, что у вас отсутствуют зависимости. Исправьте ваши make-файлы, если вы когда-нибудь получите это.
dascandy
7

В конечном итоге вам придется провести несколько тестов, чтобы определить лучшее число для вашей сборки, но помните, что ЦП - не единственный ресурс, который имеет значение!

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

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

Не могу сказать, что специально пробовал # баллы + 1 , но в наших системах (Intel i7 940, 4 ядра с гиперпоточностью, много ОЗУ и диски VelociRaptor) и в нашей сборке (крупномасштабная сборка C ++, в которой попеременно используются ЦП и я / O bound) между -j4 и -j8 очень мало различий. (Возможно, на 15% лучше ... но далеко не вдвое лучше.)

Если я ухожу на обед, я использую -j8, но если я хочу использовать свою систему для чего-нибудь еще во время ее сборки, я буду использовать меньшее число. :)

ijprest
источник
1
Выглядит здорово, но я не понимаю, почему вы не будете просто брать эти + 15% каждый раз, используя-j 8
SG
1
@sg: j8 действительно обременил систему, которую я описал в моем первоначальном посте ... машина все еще была пригодна для использования , но определенно была менее отзывчивой. Так что, если бы я все еще хотел использовать его в интерактивном режиме для других задач (обычно работая над другим кодом и, возможно, время от времени создавая единственную DLL), я бы зарезервировал пару ядер для интерактивных битов.
ijprest
@sg: Это меньшая проблема для наших новых систем ... Я подозреваю, что это в основном потому, что сейчас мы используем SSD. (Я думаю, что теперь, когда мы перейдем к твердотельным накопителям, мы полностью привязаны к процессору ... мы попытались полностью использовать RAM-диск, но почти без улучшений.) делать что-то большее, чем простое редактирование текста на переднем плане.
ijprest
5

Я только что получил процессор Athlon II X2 Regor с Foxconn M / B и 4 ГБ памяти G-Skill.

Я поставил в конце «cat / proc / cpuinfo» и «free», чтобы другие могли видеть мои спецификации. Это двухъядерный Athlon II x2 с 4 ГБ оперативной памяти.

uname -a on default slackware 14.0 kernel is 3.2.45.

Я загрузил исходный код ядра следующего шага (linux-3.2.46) в / archive4;

извлек его (tar -xjvf linux-3.2.46.tar.bz2 );

cd'd в каталог (cd linux-3.2.46 );

и скопировал конфигурацию ядра по умолчанию через ( cp /usr/src/linux/.config .);

используется make oldconfigдля подготовки конфигурации ядра 3.2.46;

затем запустил make с различными заклинаниями -jX.

Я проверил время каждого запуска, выполнив make после команды time, например, «time make -j2». Между каждым запуском я 'rm -rf' дерево linux-3.2.46 и извлекал его повторно, копировал /usr/src/linux/.config по умолчанию в каталог, запускал make oldconfig и затем снова выполнял мой тест 'make -jX' .

простой "сделать":

real    51m47.510s
user    47m52.228s
sys     3m44.985s
bob@Moses:/archive4/linux-3.2.46$

как указано выше, но с make -j2

real    27m3.194s
user    48m5.135s
sys     3m39.431s
bob@Moses:/archive4/linux-3.2.46$

как указано выше, но с make -j3

real    27m30.203s
user    48m43.821s
sys     3m42.309s
bob@Moses:/archive4/linux-3.2.46$

как указано выше, но с make -j4

real    27m32.023s
user    49m18.328s
sys     3m43.765s
bob@Moses:/archive4/linux-3.2.46$

как указано выше, но с make -j8

real    28m28.112s
user    50m34.445s
sys     3m49.877s
bob@Moses:/archive4/linux-3.2.46$

'cat / proc / cpuinfo' дает:

bob@Moses:/archive4$ cat /proc/cpuinfo
processor       : 0
vendor_id       : AuthenticAMD
cpu family      : 16
model           : 6
model name      : AMD Athlon(tm) II X2 270 Processor
stepping        : 3
microcode       : 0x10000c8
cpu MHz         : 3399.957
cache size      : 1024 KB
physical id     : 0
siblings        : 2
core id         : 0
cpu cores       : 2
apicid          : 0
initial apicid  : 0
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 5
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmo
v pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rd
tscp lm 3dnowext 3dnow constant_tsc nonstop_tsc extd_apicid pni monitor cx16 p
opcnt lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowpre
fetch osvw ibs skinit wdt npt lbrv svm_lock nrip_save
bogomips        : 6799.91
clflush size    : 64
cache_alignment : 64
address sizes   : 48 bits physical, 48 bits virtual
power management: ts ttp tm stc 100mhzsteps hwpstate

processor       : 1
vendor_id       : AuthenticAMD
cpu family      : 16
model           : 6
model name      : AMD Athlon(tm) II X2 270 Processor
stepping        : 3
microcode       : 0x10000c8
cpu MHz         : 3399.957
cache size      : 1024 KB
physical id     : 0
siblings        : 2
core id         : 1
cpu cores       : 2
apicid          : 1
initial apicid  : 1
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 5
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmo
v pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rd
tscp lm 3dnowext 3dnow constant_tsc nonstop_tsc extd_apicid pni monitor cx16 p
opcnt lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowpre
fetch osvw ibs skinit wdt npt lbrv svm_lock nrip_save
bogomips        : 6799.94
clflush size    : 64
cache_alignment : 64
address sizes   : 48 bits physical, 48 bits virtual
power management: ts ttp tm stc 100mhzsteps hwpstate

'бесплатные' доходности:

bob@Moses:/archive4$ free
             total       used       free     shared    buffers     cached
Mem:       3991304    3834564     156740          0     519220    2515308
sloMoses
источник
1
Что просто make -jделать в этой системе? Make должен проверять загрузку и масштабировать количество процессов в зависимости от нагрузки.
docwhat
1
make -jсовсем не ограничивает количество рабочих мест. Обычно это катастрофа для среднего или крупного проекта, поскольку быстро создается больше заданий, чем может поддерживаться RAM. Вариант, который вам нужно ограничить по нагрузке -l [load], в сочетании с-j
Matt G
5

Оба не ошибаются. Чтобы быть в гармонии с собой и с автором компилируемого программного обеспечения (на самом программном уровне действуют различные ограничения на многопоточность / однопоточность), я предлагаю вам использовать:

make -j`nproc`

Примечания: nprocэто команда linux, которая возвращает количество ядер / потоков (современный процессор), доступных в системе. Поместив его под галочкой, как указано выше, вы передадите номер команде make.

Дополнительная информация: как кто-то упомянул, использование всех ядер / потоков для компиляции программного обеспечения может буквально задушить вашу коробку до смерти (отсутствие ответа) и может даже занять больше времени, чем использование меньшего количества ядер. Как я видел, один пользователь Slackware разместил здесь сообщение, что у него был двухъядерный ЦП, но он все еще проводил тесты до j 8, которые перестали отличаться при j 2 (только 2 аппаратных ядра, которые может использовать ЦП). Итак, чтобы избежать зависания окна, я предлагаю вам запустить его следующим образом:

make -j`nproc --ignore=2`

Это будет передавать выходной сигнал , nprocчтобы makeи вычесть 2 ядра из своего результата.

Цифровой Люцифер
источник
3

Так же как исх .:

Из Spawning Multiple Build Jobsраздела в LKD :

где n - количество создаваемых заданий. Обычная практика - создать одно или два задания на процессор. Например, на двухпроцессорной машине можно сделать

$ make j4

Нан Сяо
источник
неработающая ссылка, это цитата из статьи Роберта Лава «Разработка ядра Linux»?
Behrooz
Да, это из той книги.
Нан Сяо
1

По моему опыту, при добавлении дополнительных рабочих мест должны быть некоторые преимущества в производительности. Это просто потому, что дисковый ввод-вывод является одним из узких мест, помимо ЦП. Однако определить количество дополнительных заданий непросто, поскольку оно сильно зависит от количества ядер и типов используемого диска.

Мэтт
источник
1

Спустя много лет большинство этих ответов все еще верны. Однако произошли небольшие изменения: использование большего количества заданий, чем у вас есть физических ядер, теперь дает действительно значительное ускорение. В качестве дополнения к таблице Dascandy, вот мои времена для компиляции проекта на AMD Ryzen 5 3600X в Linux. (The Powder Toy, commit c6f653ac3cef03acfbc44e8f29f11e1b301f1ca2)

Я рекомендую проверить себя, но на основе отзывов других я обнаружил, что использование логического числа ядер для подсчета должностей хорошо работает в Zen. При этом система не теряет отзывчивости. Я полагаю, это относится и к недавним процессорам Intel. Обратите внимание, что у меня тоже есть SSD, так что, возможно, стоит проверить ваш процессор самостоятельно.

scons -j1 --release --native  120.68s user 9.78s system 99% cpu 2:10.60 total
scons -j2 --release --native  122.96s user 9.59s system 197% cpu 1:07.15 total
scons -j3 --release --native  125.62s user 9.75s system 292% cpu 46.291 total
scons -j4 --release --native  128.26s user 10.41s system 385% cpu 35.971 total
scons -j5 --release --native  133.73s user 10.33s system 476% cpu 30.241 total
scons -j6 --release --native  144.10s user 11.24s system 564% cpu 27.510 total
scons -j7 --release --native  153.64s user 11.61s system 653% cpu 25.297 total
scons -j8 --release --native  161.91s user 12.04s system 742% cpu 23.440 total
scons -j9 --release --native  169.09s user 12.38s system 827% cpu 21.923 total
scons -j10 --release --native  176.63s user 12.70s system 910% cpu 20.788 total
scons -j11 --release --native  184.57s user 13.18s system 989% cpu 19.976 total
scons -j12 --release --native  192.13s user 14.33s system 1055% cpu 19.553 total
scons -j13 --release --native  193.27s user 14.01s system 1052% cpu 19.698 total
scons -j14 --release --native  193.62s user 13.85s system 1076% cpu 19.270 total
scons -j15 --release --native  195.20s user 13.53s system 1056% cpu 19.755 total
scons -j16 --release --native  195.11s user 13.81s system 1060% cpu 19.692 total
( -jinf test not included, as it is not supported by scons.)

Тестирование проводилось на Ubuntu 19.10 с Ryzen 5 3600X, Samsung 860 Evo SSD (SATA) и 32 ГБ ОЗУ

Последнее замечание: у других людей с 3600X могут быть лучшие времена, чем у меня. Во время этого теста у меня был включен режим Eco, что немного снизило скорость процессора.

moonheart08
источник
0

ДА! На моем 3950x я запускаю -j32, и это экономит часы компиляции! Я все еще могу смотреть YouTube, просматривать веб-страницы и т. Д. Во время компиляции без каких-либо различий. Процессор не всегда привязан даже к 1 ТБ 970 PRO nvme или 1 ТБ Auros Gen4 nvme и 64 ГБ 3200C14. Даже когда это так, я не замечаю мудрого пользовательского интерфейса. Я планирую в ближайшем будущем протестировать с -j48 на некоторых крупных будущих проектах. Я ожидаю, как и вы, вероятно, увидеть некоторые впечатляющие улучшения. Те, у кого все еще есть четырехъядерный процессор, могут не получить такой же прирост ...

Сам Линус только что обновился до 3970x, и вы можете поставить свой самый низкий доллар, он, по крайней мере, использует -j64.

lazyacevw
источник