多核并行而不是“线程”执行?

时间:2009-10-27 15:21:47

标签: makefile parallel-processing

我有一个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(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 个答案:

答案 0 :(得分:1)

我在-j标志上做了一些阅读,我认为问题是这会为独立规则开始新的工作。每个图像的作业都是独立的,因此每个目标的第一个依赖关系将像您所看到的那样运行。

我认为这里的主要问题是这个任务本质上是串行的,也就是说每个目标的依赖关系必须按顺序运行,一个接一个。因此,在每个目标中,您无法利用多级编程,在此粒度级别

由于make似乎没有按照您想要的顺序处理依赖项,因此支持并行测试的单元测试框架可能更适合。我通过一些谷歌搜索了解了其中几个出口,但我不能推荐我什么时候没有使用过,而且我不确定你使用的是哪种语言。

答案 1 :(得分:1)

除非明确指定了目标的执行顺序,否则make将以任意顺序执行它们 - 无论是并行还是非并行模式。此订单经历make的内部算法,在您的情况下会产生令人不快的结果。

解决方案是推动对测试的明确排序。

从你的makefile部分,我假设存在一个未公开的“源”变量,其中包含要测试的目标列表(在这些目标上隐式的依赖)。此变量的立即扩展也会产生正确的结果。

假设变量是这样的:

list=file1 file2 file3 ... fileN

然后,要解决问题,只需生成以下依赖项即可:

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

我们应该如何生成它?让我们在list变量得到其值后编写一个foreach-eval循环

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

这将生成一部分makefile,就像C预处理器一样(或者更确切地说,就是LISP宏)。它将如下工作:对于由t形成的列表中的每个项join(将第一个列表的每个元素与第二个列表的对应元素连接起来)列表file2 file3 ... fileN run_tests到每个元素其中添加了后缀:(因此形成file2: file3: ... fileN: run_tests:),其中包含源列表file1 file2 ... fileN; - 对于列表中包含连接元素的每个此类项t,将其作为makefile源的一部分进行评估,因此按照上面所示的规则进行处理。

现在你只需要调用run_tests目标,它将逐一进行。

答案 2 :(得分:1)

突然间,我想到了另一个想法!

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

这解决了所有问题,除了测试可能没有按正确的顺序调用(但实际上它们很可能会很顺利)。