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

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

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

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

Ответ 1

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

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

Ответ 2

Я запустил свой домашний проект на своем 4-ядерном ноутбуке с гиперпотоком и записал результаты. Это довольно сложный проект, но он включает в себя unit test из 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 ГБ памяти для компиляции.

Ответ 3

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

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

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

Ответ 4

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

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

И тогда у вас есть "реальные" ядра и гиперпотоки. Вы можете или не можете использовать нерестовые задания для каждой гиперпотоки. Опять же, вам придется ориентироваться, чтобы узнать.

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

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

Ответ 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) в /archive 4;

извлек его (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 make -j2'. Между каждым запуском я 'rm -rf' дерево linux-3.2.46 и повторно его перекодировал, скопировал по умолчанию /usr/src/linux/.config в каталог, запустил make oldconfig, а затем снова выполнил мой тест "make -jX".

plain "make":

real    51m47.510s
user    47m52.228s
sys     3m44.985s
[email protected]:/archive4/linux-3.2.46$

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

real    27m3.194s
user    48m5.135s
sys     3m39.431s
[email protected]:/archive4/linux-3.2.46$

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

real    27m30.203s
user    48m43.821s
sys     3m42.309s
[email protected]:/archive4/linux-3.2.46$

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

real    27m32.023s
user    49m18.328s
sys     3m43.765s
[email protected]:/archive4/linux-3.2.46$

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

real    28m28.112s
user    50m34.445s
sys     3m49.877s
[email protected]:/archive4/linux-3.2.46$

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

[email protected]:/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

'free' дает:

[email protected]:/archive4$ free
             total       used       free     shared    buffers     cached
Mem:       3991304    3834564     156740          0     519220    2515308

Ответ 6

Просто как ссылка:

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

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

$make j4

Ответ 7

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

Ответ 8

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

make -j'nproc'

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

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

make -j'nproc --ignore=2'

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