Makefile 多核并行制造,而不是;螺纹;执行?
我有一个Makefile来执行一个大致如下的测试套件: %.diff.png: %.test.png echo '$*: Comparing with good PNG.' %.test.png: %.pdf echo '$*: Converting PDF to PNG.' %.pdf: %.tex echo '$*: Generating PDF output.' 当我使用多作业make运行这些测试时(Makefile 多核并行制造,而不是;螺纹;执行?,makefile,parallel-processing,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.' 当我使用多作业make运行这些测试时(make-j2 test),测试以“线程化”顺序执行: ...
make-j2 test
),测试以“线程化”顺序执行:
...
umtest202a:生成PDF输出。
umtest202b:生成PDF输出。
...
umtest202a:将PDF转换为PNG。
umtest202b:将PDF转换为PNG。
...
umtest202a:与良好的PNG进行比较。
umtest202b:与良好的PNG进行比较。
...
也许你能看到问题所在;在发现测试是否失败之前,它已经为每个其他测试运行了所有PDF生成和PNG转换
是否有一种方法来组织测试,以便即使在使用多个作业运行时,测试也会在继续下一个测试之前一直运行到完成?或者这是一个更好的
制作的任务吗?我读了一些关于-j
标志的文章,我认为问题是这为独立规则启动了新的工作。每个图像的作业都是独立的,因此每个目标的第一个依赖项将像您看到的那样运行
我认为这里的主要问题是,这个任务本质上是串行的,也就是说,每个目标的依赖项必须依次运行。因此,在每个目标中,您没有办法在这种粒度级别上利用多道程序设计
由于make
似乎没有按照您想要的顺序处理依赖项,因此支持并行测试的单元测试框架可能更合适。我通过谷歌搜索知道其中有几个退出,但我不能推荐什么时候退出,因为我没有使用过任何语言,也不确定您使用的是哪种语言。除非明确指定了目标的执行顺序,make
以任意顺序执行它们——并行和非并行模式。此订单会经历make
的内部算法,在您的情况下会产生令人不快的结果
解决方案是促使对测试进行显式排序
在makefile中,我假设存在一个未公开的“source”变量,该变量包含要测试的目标列表(隐式目标依赖于这些目标)。同时,该变量的立即展开也会产生正确的结果
假设变量如下所示:
list=file1 file2 file3 ... fileN
然后,为了解决问题,生成以下依赖项就足够了:
file2: file1
file3: file2
...
fileN: fileN-1
run_tests: fileN
我们应该如何生成它?让我们在列表
变量获取其值后编写一个foreach eval循环:
len=$(words $(list))
$(foreach t, \
$(join \
$(addsuffix : ,$(wordlist 2,$(len),$(list)) run_tests), \
$(list) \
) \
, $(eval $(t)) \
)
这将生成makefile的一部分,就像C预处理器(或者更准确地说,LISP宏)一样。它的工作原理如下:对于由join
ing(将第一个列表的每个元素与第二个列表的相应元素连接起来)形成的列表中的每个项目t
,列表file2 file3。。。fileN run_tests
,在每个元素中添加后缀:
(从而形成file2:file3:…fileN:run_tests:
),源列表file1 file2。。。文件
;-对于具有连接元素的列表中的每个此类项t
,将其作为makefile源的一部分进行评估,从而按照上述规则进行操作
现在您只需调用run_tests目标,它就会一个接一个地运行。突然,我想到了另一个主意
%.diff.png:
$(MAKE) $*.test.png
echo '$*: Comparing with good PNG.'
这解决了所有问题,只是测试可能没有按正确的顺序调用(但在实践中,它们很可能会进行得很顺利)。您的“每个目标的依赖项必须按顺序运行”一针见血。不过,我想我的问题不清楚;无论我指定了多少个作业,都会生成整个PDF集,然后全部转换为PNG,然后全部进行正确性测试。奇怪的是,DEP会以这种方式处理。我已经用一些不同的建议更新了我的答案。我明白你在这里说的,但我认为它需要更多的工作:这种方法将完全串行化处理,否定任何可以并行实现的收益。所以我想我想要test3:test1
,test4:test2
,test5:test3
,等等。(对并行执行的数量进行硬编码,但没关系。)就在两天前,在我的工作中,我遇到了同样的问题。我推断,如果你想混合顺序和并行,最好不要使用make
。假设您采用了test3:test1
方案,并且test1
需要1小时才能完成,而所有其他测试总共需要1小时。然后,使用这种方案,总执行时间将延长50%(使用2个并行作业)。
len=$(words $(list))
$(foreach t, \
$(join \
$(addsuffix : ,$(wordlist 2,$(len),$(list)) run_tests), \
$(list) \
) \
, $(eval $(t)) \
)
%.diff.png:
$(MAKE) $*.test.png
echo '$*: Comparing with good PNG.'