GNU make: чи повинна кількість робочих місць дорівнювати кількості ядер процесора в системі?


87

Здається, є певні суперечки щодо того, чи повинна кількість робочих місць у GNU дорівнювати кількості ядер, чи ви можете оптимізувати час збірки, додавши одне зайве завдання, яке можна поставити в чергу, поки інші "працюють" .

Чи краще використовувати -j4або -j5на чотирьохядерній системі?

Ви бачили (чи робили) якісь тести, які підтримують те чи інше?


8
Тільки для підказки, ви можете використовувати, make `nproc`щоб зробити незалежний від процесора сценарій :)
VivienG

Якщо у вас є суміш рецептів, які пов’язані з йодом та процесором, тоді ви потенційно хочете набагато більше, ніж NCPU. Також розгляньте можливість додавання опцій -lX. Це насправді не відповідь на запитання, крім "це залежить від вашого обладнання та завдань".
James Moore

Технічно можна побачити покращення. Вам потрібен повільний диск, недостатньо оперативної пам'яті та безліч невеликих файлів вихідного коду. Простіше дістатись десять років тому.
Ганс Пассант,

Відповіді:


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.

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

У будь-якому випадку, ви повинні бути обережними, тому що деякі ланцюжки виробів просто не сумісні з цією --jobsопцією, і можуть призвести до несподіваних результатів. Якщо у вас трапляються дивні помилки залежностей, просто спробуйте makeбез --jobs.


19
Пояснення (хоча не можна поручитися за його науковість) полягає в тому, що "+ 1" дає додаткову роботу, яка працює, коли хтось із інших російських завдань виконує введення-виведення.
Laurynas Biveinis

@LaurynasBiveinis: Але тоді робочі місця постійно працюють на різних ядрах, принаймні частіше, ніж у більш консервативних умовах, коли робота має шанс залишатися на одному ядрі протягом більш тривалого періоду часу. Тут є плюси і мінуси ...
krlmlr

1
Кількість ядер + 1 - це також моє налаштування за замовчуванням. Одне питання полягає в тому, що в будь-якій досить великій системі, здається, затримує зв'язок і робить усі кроки з'єднання разом. У цей момент у вас закінчується оперативна пам’ять. Бах!
bobbogo

4
деякі ланцюжки макетів просто несумісні з параметром --jobs -> Це означає, що у вас відсутні залежності. Виправте свої файли make, якщо ви коли-небудь отримаєте це.
dascandy

7

Врешті-решт, вам доведеться виконати деякі еталони, щоб визначити найкращу кількість для вашої збірки, але пам’ятайте, що центральний процесор - це не єдиний важливий ресурс!

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

І тоді ви отримаєте "справжні" ядра проти гіперпотоків. Ви можете або не отримувати користь від нересту для кожного гіперпотоку. Знову ж таки, вам доведеться порівняти, щоб це з’ясувати.

Я не можу сказати, що я спеціально пробував #cores + 1 , але на наших системах (Intel i7 940, 4 гіперпоточних ядра, багато оперативної пам'яті та диски VelociRaptor) та нашій збірці (масштабна збірка C ++, яка поперемінно є CPU і / O обмежене) існує дуже мала різниця між -j4 та -j8. (Це, можливо, на 15% краще ... але ніде не вдвічі краще.)

Якщо я їду на обід, я буду використовувати -j8, але якщо я хочу використовувати свою систему для чогось іншого, поки вона будується, я буду використовувати менший номер. :)


1
Здається чудово, але мене бентежить, чому б ви не просто взяли це + 15% щоразу, використовуючи-j 8
sg

1
@sg: j8 справді оподатковував систему, яку я описав у своєму первісному дописі ... машина все ще була придатною для використання , але вона, безумовно, була менш чутливою. Тому, якби я все-таки хотів використовувати його інтерактивно для інших завдань (як правило, робота над іншим кодом і, можливо, випадкова збірка одного DLL), я б зарезервував пару ядер для інтерактивних бітів.
ijprest

@sg: Це менше проблем у наших новіших системах ... Я підозрюю, що це головним чином тому, що ми зараз використовуємо твердотільні накопичувачі. (Я думаю, що ми повністю пов’язані з центральним процесором, коли ми збираємося використовувати твердотільні накопичувачі ... ми спробували повністю побудувати на 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' .

простий "make":

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

1
Що просто make -jробить ця система? Марка повинна перевіряти навантаження та масштабувати кількість процесів на основі навантаження.
docwhat

1
make -jне обмежує кількість робочих місць взагалі. Як правило, це катастрофічно для середнього чи великого проекту, оскільки швидко розгалужується більше робочих місць, ніж може підтримувати оперативна пам’ять. Варіант, який вам потрібно обмежити навантаженням -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 Kernel Development від Роберта Лава?
Бехруз,

Так, саме з тієї книги.
Nan Xiao

1

З мого досвіду, додавання додаткових робочих місць повинно мати певні переваги в продуктивності. Це просто тому, що дисковий ввід / вивід є однією з основних горловин, крім процесора. Однак визначитися з кількістю додаткових завдань непросто, оскільки це дуже взаємопов’язано з кількістю ядер та типами використовуваного диска.


1

Багато років потому більшість цих відповідей все ще є правильними. Однак відбулися деякі зміни: використання більшої кількості робочих місць, ніж у вас фізичних ядер, дає справді значний пришвидшення. Як додаток до таблиці Дасканді, ось мій час для складання проекту на AMD Ryzen 5 3600X на Linux. (Іграшка порошок, коміт c6f653ac3cef03acfbc44e8f29f11e1b301f1ca2)

Я рекомендую перевірити себе, але я впізнав, що інші користувачі вказують, що використання вашого логічного підрахунку ядер для підрахунку завдань добре працює на Zen. Поряд з цим система, здається, не втрачає чуйності. Думаю, це стосується і останніх процесорів Intel. Зауважте, у мене також є твердотільний накопичувач, тому, можливо, варто його протестувати самостійно.

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 можуть отримати кращі часи, ніж я. Під час цього тесту у мене був увімкнений режим Еко, дещо зменшивши швидкість процесора.


0

ТАК! На моєму 3950x я запускаю -j32, і це економить години компіляції! Я все ще можу дивитися YouTube, переглядати Інтернет тощо під час компіляції без різниці. Процесор не завжди прив'язаний навіть до 1TB 970 PRO nvme або 1TB Auros Gen4 nvme та 64GB 3200C14. Навіть коли це так, я не помічаю розумного інтерфейсу. Найближчим часом я планую протестувати з -j48 на деяких великих майбутніх проектах. Я сподіваюся, як і ви, мабуть, побачите вражаюче покращення. Ті, хто все ще має чотирьохядерний процесор, можуть не отримати однакові прибутки ....

Сам Лінус щойно підвищив рівень до 3970x, і ви можете поставити свій нижчий долар, він, принаймні, працює -j64.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.