Многоядерное выполнение параллельно, а не «резьбовое» исполнение? - PullRequest
1 голос
/ 27 октября 2009

У меня есть Makefile для выполнения набора тестов, который выглядит примерно так:

%.diff.png: %.test.png
    echo '$*: Comparing with good PNG.'

%.test.png: %.pdf
    echo '$*: Converting PDF to PNG.'

%.pdf: %.tex
    echo '$*: Generating PDF output.'

со всеми echo утверждениями, дополненными фактическими тестами в реальном Makefile.

Когда я выполняю все эти тесты с make test (цель test не показана выше), я, очевидно, получаю линейный вывод:

...
umtest200b: Generating PDF output.
umtest200b: Converting PDF to PNG.
umtest200b: Comparing with good PNG.
...

Когда я запускаю эти тесты с многозадачной сборкой (скажем, make -j2 test), тесты выполняются в «поточном» порядке:

...
umtest202a: Generating PDF output.
umtest202b: Generating PDF output.
...
umtest202a: Converting PDF to PNG.
umtest202b: Converting PDF to PNG.
...
umtest202a: Comparing with good PNG.
umtest202b: Comparing with good PNG.
...

Возможно, вы видите проблему; прежде чем обнаруживать, что тест не пройден, он уже проходит через все поколений PDF и преобразования PNG для каждого другого теста.

Есть ли способ организовать тесты так, чтобы даже при запуске с несколькими заданиями тесты выполнялись до завершения, прежде чем переходить к следующему тесту? Или это задача для лучшего make?

Ответы [ 3 ]

1 голос
/ 27 октября 2009

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

Решение состоит в том, чтобы придать четкий порядок вашим тестам.

Из вашей части make-файла я предполагаю, что существует нераскрытая переменная «source», которая содержит список целей для тестирования (от этих целей зависят неявные). Также немедленное расширение этой переменной дает правильные результаты.

Предположим, что переменная такова:

list=file1 file2 file3 ... fileN

тогда для решения проблемы достаточно сгенерировать следующие зависимости:

file2: file1
file3: file2 
...
fileN: fileN-1
run_tests: fileN

Как мы должны генерировать это? Давайте напишем цикл foreach-eval после того, как переменная list получит свое значение:

len=$(words $(list))
$(foreach t,                                                  \
   $(join                                                     \ 
      $(addsuffix : ,$(wordlist 2,$(len),$(list)) run_tests), \
      $(list)                                                 \
   )                                                          \
   , $(eval $(t))                                             \
)

Это создаст часть make-файла точно так же, как это делает препроцессор C (или, вернее, макросы LISP). Это будет работать так: для каждого элемента t в списке, сформированном путем join ing (конкатенация каждого элемента первого списка с соответствующим элементом второго) списка file2 file3 ... fileN run_tests, к каждому элементу которого суффикс : добавлен (таким образом формируя file2: file3: ... fileN: run_tests:), с исходным списком file1 file2 ... fileN; - для каждого такого элемента t в списке с присоединенными элементами оцените его как часть источника make-файла, действуя так, как предписано вышеизложенными правилами.

Теперь вам нужно только вызвать цель run_tests, и она будет идти один за другим.

1 голос
/ 28 октября 2009

Внезапно в мою голову пришла другая идея!

%.diff.png:
    $(MAKE) $*.test.png
    echo '$*: Comparing with good PNG.'

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

1 голос
/ 27 октября 2009

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

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

Поскольку make, похоже, не обрабатывает зависимости в нужном вам порядке, возможно, лучше подойдет среда модульного тестирования, поддерживающая параллельные тесты. Через некоторые поиски в Google я знаю, что некоторые из этих выходов, но я не могу рекомендовать, когда, поскольку я не использовал их, и не уверен, какой язык вы используете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...