Компиляция с g ++ с использованием нескольких ядер

174

Быстрый вопрос: что такое флаг компилятора, позволяющий g ++ порождать несколько экземпляров самого себя, чтобы быстрее компилировать большие проекты (например, 4 исходных файла за один раз для многоядерного процессора)?

bsofman
источник
Это действительно поможет? Все мои задания компиляции связаны с вводом / выводом, а не с процессором.
Брайан Кноблаух
5
Даже если они связаны с вводом / выводом, вы, вероятно, сможете сохранить нагрузку на ввод / вывод более высокой, когда происходят тяжелые биты ЦП (только с одним экземпляром g ++, будут затишья), и, возможно, получите эффективность ввода / вывода, если у планировщика есть больше выбора что читать с диска дальше. Мой опыт показывает, что разумное использование make -jпочти всегда приводит к некоторому улучшению.
Флекс
1
@BrianKnoblauch Но на моей машине (реальной или в VirtualBox), она привязана к процессору, я обнаружил, что при компиляции процессор занят командой top.
大 宝剑
1
Даже если они связаны с вводом / выводом, мы можем использовать флаг gcc '-pipe', чтобы уменьшить боль.
大 宝剑
только что видел это в google: gcc.gnu.org/onlinedocs/libstdc++/manual/…
Джим Майклз

Ответы:

240

Вы можете сделать это с помощью make - с помощью gnu make это флаг -j (это также поможет на однопроцессорной машине).

Например, если вы хотите 4 параллельных задания из make:

make -j 4

Вы также можете запустить GCC в трубе с

gcc -pipe

Это будет направлять этапы компиляции, что также поможет поддерживать занятость ядер.

Если у вас также есть дополнительные машины, вы можете проверить distcc , который также будет обрабатывать компиляции.

frankodwyer
источник
36
Вы -j число должно быть в 1,5 раза больше ядер, которые у вас есть.
Марк Беквит с
2
Спасибо. Я продолжал пытаться передать "-j #" в gcc через CFLAGS / CPPFLAGS / CXXFLAGS. Я полностью забыл, что "-j #" был параметром для GNU make (а не для GCC).
chriv
33
Почему параметр -j для GNU Make должен быть в 1,5 раза больше числа ядер процессора?
укус
28
Число 1,5 из-за отмеченной проблемы ввода-вывода . Это эмпирическое правило. Около 1/3 заданий будет ожидать ввода-вывода, поэтому остальные задания будут использовать доступные ядра. Число, большее, чем ядра, лучше, и вы можете даже подняться до . Смотрите также: Гну приводят -jаргументы
бесхитростный шум
4
@JimMichaels Это может быть из-за того, что зависимости плохо установлены в вашем проекте (цель начинает строить, даже если ее зависимости еще не готовы), так что только последовательная сборка в конечном итоге будет успешной.
Антонио
42

Такого флага не существует, и его использование противоречит философии Unix, согласно которой каждый инструмент выполняет только одну функцию и выполняет ее хорошо. Порождение процессов компилятора концептуально является задачей системы сборки. Вероятно, вам нужен флаг -j (jobs) для GNU make

сделать -j4

Или вы можете использовать pmake или аналогичные системы параллельного создания.

Михай Лимбакан
источник
3
«Педантичность в Unix бесполезна» Хорошо, тогда это не педантизм, анонимный редактор. Откат. Рецензенты, пожалуйста, уделите больше внимания тому, что вы делаете.
Гонки легкости на орбите
12

Люди упоминали, makeно bjamтакже поддерживают аналогичную концепцию. Использование bjam -jxинструктирует bjam для создания xпараллельных команд.

Мы используем одни и те же сценарии сборки в Windows и Linux, и использование этой опции сокращает время сборки на обеих платформах вдвое. Ницца.

MattyT
источник
9

makeсделаю это для вас. Исследуйте -jи -lпереключатели в справочной странице. Я не думаю, что g++можно распараллелить.

rmeador
источник
+1 за упоминание -lопции (не запускает новую работу, если все предыдущие работы не прекратились). В противном случае создается впечатление, что задание компоновщика начинается с создания не всех объектных файлов (так как некоторые компиляции все еще продолжаются), поэтому задание компоновщика завершается неудачно.
NGI
8

Если вы используете make, используйте -j. От man make:

  -j [jobs], --jobs[=jobs]
       Specifies the number of jobs (commands) to run simultaneously.  
       If there is more than one -j option, the last one is effective.
       If the -j option is given without an argument, make will not limit the
       number of jobs that can run simultaneously.

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

https://docs.python.org/3/library/multiprocessing.html#multiprocessing.cpu_count

Как это:

make -j $(python3 -c 'import multiprocessing as mp; print(int(mp.cpu_count() * 1.5))')

Если вы спрашиваете, почему 1.5я приведу пользователя artless-noise в комментарии выше:

Число 1,5 из-за отмеченной проблемы ввода-вывода. Это эмпирическое правило. Около 1/3 заданий будет ожидать ввода-вывода, поэтому остальные задания будут использовать доступные ядра. Число, большее, чем ядра, лучше, и вы можете даже подняться до 2х.

Havok
источник
5
Большинство пользователей Linux, вероятно , предпочитают короче: make -j`nproc` с nprocв GNU Coreutils.
Сиро Сантилли 郝海东 郝海东 病 六四 事件 事件
Если вы используете SSD, I / O не будет такой большой проблемой. Просто, основываясь на комментариях Ciro выше, вы можете сделать это: make -j $(( $(nproc) + 1 ))(убедитесь, что вы поставили пробелы там, где они у меня есть).
Эд К
Хорошее предложение использовать python, в системах, где nprocнет, например, в manylinux1контейнерах, это экономит дополнительное время, избегая запуска yum update/ yum install.
крик
7

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

Джейсон
источник
+1, distcc - полезный инструмент, который можно использовать в своем арсенале для больших сборок.
Флексо
Похоже, есть несколько таких, которые работают как "distcc": stackoverflow.com/questions/5374106/distributed-make/…
rogerdpack
3

Я не уверен насчет g ++, но если вы используете GNU Make, то make -j N (где N - количество потоков, которое может создать make) позволит make запускать несколько заданий g ++ одновременно (так долго так как файлы не зависят друг от друга).

Энди
источник
2
нет, не число потоков! Многие люди не понимают этого, но -j Nсообщают, сколько процессов должно быть запущено одновременно, а не потоков. Вот почему он не так производительный, как MS cl -MT(действительно многопоточный).
Sebi2020
2

Параллельный GNU

Я делал синтетический тест для компиляции и не мог потрудиться написать Makefile, поэтому я использовал:

sudo apt-get install parallel
ls | grep -E '\.c$' | parallel -t --will-cite "gcc -c -o '{.}.o' '{}'"

Объяснение:

  • {.} принимает входной аргумент и удаляет его расширение
  • -t распечатывает команды, которые выполняются, чтобы дать нам представление о прогрессе
  • --will-cite удаляет запрос на цитирование программного обеспечения, если вы публикуете результаты, используя его ...

parallel это так удобно, что я даже сам могу проверить временную метку:

ls | grep -E '\.c$' | parallel -t --will-cite "\
  if ! [ -f '{.}.o' ] || [ '{}' -nt '{.}.o' ]; then
    gcc -c -o '{.}.o' '{}'
  fi
"

xargs -Pтакже может запускать задания параллельно, но это немного менее удобно, если вы выполняете манипулирование расширением или запускаете несколько команд с ним: вызов нескольких команд через xargs

Параллельное связывание было задано по адресу: Может ли gcc использовать несколько ядер при связывании?

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

Проверено в Ubuntu 18.10.

Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
источник