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


174

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


Это действительно поможет? Все мои задания компиляции связаны с вводом / выводом, а не с процессором.
— Брайан Кноблаух

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 , который также будет обрабатывать компиляции.


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 заданий будет ожидать ввода-вывода, поэтому остальные задания будут использовать доступные ядра. Число, большее, чем ядра, лучше, и вы можете даже подняться до 2х . Смотрите также: Гну приводят -jаргументы
— бесхитростный шум

4
@JimMichaels Это может быть из-за того, что зависимости плохо установлены в вашем проекте (цель начинает строить, даже если ее зависимости еще не готовы), так что только последовательная сборка в конечном итоге будет успешной.
— Антонио

42

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

сделать -j4

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



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

12

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

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


9

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


+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х.


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.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.