Что может вызывать зависание make при компиляции на нескольких ядрах?

17

Вчера я пытался скомпилировать пакет ROOT из исходного кода. Поскольку я собирал его на 6-ядерном компьютере-монстре, я решил пойти дальше и собрать с использованием нескольких ядер make -j 6. Поначалу компиляция прошла гладко и очень быстро, но в какой-то момент makeзависала, используя 100% CPU только на одном ядре.

Я немного погуглил и нашел этот пост на досках объявлений ROOT. Поскольку я сам собрал этот компьютер, я беспокоился, что неправильно применил радиатор, а процессор перегрелся или что-то в этом роде. К сожалению, у меня нет холодильника на работе, чтобы я мог его вставить. ;-)

Я установил lm-sensorsпакет и make -j 6снова запустил , на этот раз следя за температурой процессора. Несмотря на то, что он достиг высокой температуры (около 60 ° С), он никогда не превышал высокую или критическую температуру.

Я попытался запустить, make -j 4но снова makeзавис во время компиляции, на этот раз в другом месте.

В итоге я скомпилировал только что запущенный makeи все заработало нормально. Мой вопрос: почему он завис? Из-за того, что он остановился в двух разных точках, я бы предположил, что это было из-за какого-то состояния гонки, но я думаю, что он makeдолжен быть достаточно умным, чтобы все расставить в правильном порядке, поскольку он предлагает такую -jвозможность.

user545424
источник
4
Это похоже на состояние гонки. Одна вещь, которую вы могли бы сделать, это присоединиться к запущенному процессу make (тот, который вращается), используя, например, strace -p <pid>и посмотреть, сможете ли вы узнать, на что он смотрит. strace покажет вам только системные вызовы (не вызовы функций), но он все равно может дать вам ценную информацию, если он вращается при просмотре или для определенного файла.
JLP
Тема, которую вы нашли через Google, приводит к выводу, что никто не смог скомпилировать ее -j >1.
Нильс
Не имеет отношения к параллельной компиляции, но у меня был зависший make-файл, который потребовался навсегда для отладки. Оказывается, это было просто при инициализации переменной, в $(shell ...)конечном счете, выполнялась команда, которая ожидала ввода отstdin . Это было вызвано тем, что переменная была пустой, и никакие аргументы файла не были переданы команде.
jozxyqk

Ответы:

13

У меня нет ответа на этот конкретный вопрос, но я могу попытаться дать вам подсказку о том, что может происходить: отсутствие зависимостей в Make-файлах.

Пример:

target: a.bytecode b.bytecode
    link a.bytecode b.bytecode -o target

a.bytecode: a.source
    compile a.source -o a.bytecode

b.bytecode: b.source
    compile b.source a.bytecode -o a.bytecode

Если вы позвоните, make targetвсе будет правильно скомпилировано. Компиляция a.sourceвыполняется (произвольно, но детерминировано) в первую очередь. Затем b.sourceвыполняется компиляция .

Но если у вас make -j2 targetобе compileкоманды будут выполняться параллельно. И вы действительно заметите, что зависимости вашего Makefile нарушены. Вторая компиляция предполагает, что a.bytecodeона уже скомпилирована, но она не отображается в зависимостях. Так что ошибка может произойти. Правильная строка зависимости для b.bytecodeдолжна быть:

b.bytecode: b.source a.bytecode

Возвращаясь к вашей проблеме, если вам не повезло, возможно, команда зависла в 100% цикле ЦП из-за отсутствия зависимости. Это, вероятно, то, что происходит здесь, отсутствующая зависимость не может быть обнаружена последовательной сборкой, но она была обнаружена вашей параллельной сборкой.

Стефан Хименес
источник
Интересный. Знаете ли вы, есть ли какие-либо инструменты, которые могут работать через make-файл и проверять эти зависимости?
user545424
Я не знаю ни одного. В любом случае такой инструмент может найти только очевидные ошибки. Если он не понимает синтаксис каждой команды, которая появляется в Makefile, и не знает, каковы (потенциально неявные) зависимости.
Стефан Гименес
2

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

killermist
источник
1

Я понимаю, что это действительно старый вопрос, но он все еще появляется в верхней части результатов поиска, поэтому вот мое решение:

В GNU make есть механизм сервера заданий, который гарантирует, что make и его рекурсивные дочерние элементы не потребляют больше указанного числа ядер: http://make.mad-scientist.net/papers/jobserver-implementation/

Он опирается на канал, общий для всех процессов. Каждый процесс, который хочет обработать дополнительные дочерние элементы, должен сначала потреблять токены из канала, а затем отказаться от них после завершения. Если дочерний процесс не возвращает использованные им токены, верхний уровень make while навсегда зависает, ожидая их возврата.

https://bugzilla.redhat.com/show_bug.cgi?id=654822

Я столкнулся с этой ошибкой при сборке binutils с GNU make на моем компьютере Solaris, где «sed» не является GNU sed. Решив проблему с PATH, чтобы сделать sed == gsed приоритетным по отношению к системе sed, эта проблема была устранена. Я не знаю, почему Сед потребляет токены из трубы.

Фазал Маджид
источник
0

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

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

fduff
источник
0

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

MahmutBulut
источник