多核以并行方式而不是“线程化”方式进行。执行?
我有一个 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
的任务?
I have a Makefile to execute a test suite that looks roughly like this:
%.diff.png: %.test.png echo '$*: Comparing with good PNG.' %.test.png: %.pdf echo '$*: Converting PDF to PNG.' %.pdf: %.tex echo '$*: Generating PDF output.'
with all the echo
statements supplemented with the actual tests in the real Makefile.
When I execute all of these tests with make test
(the test
target is not shown above), I obviously get linear output:
... umtest200b: Generating PDF output. umtest200b: Converting PDF to PNG. umtest200b: Comparing with good PNG. ...
When I run these tests with multi-job make (make -j2 test
, say), the tests are executed in a "threaded" order:
... 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. ...
Perhaps you can see the problem; before discovering if the test fails it's already run through all of the PDF generations and PNG conversions for every single other test.
Is there a way to organise the tests so that even when run with multiple jobs the tests are run to completion before moving on to the next test? Or is this a task for a better make
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
除非明确指定目标的执行顺序,否则
make
将以任意顺序执行它们——并行和非并行模式。该命令经过make
的内部算法,在您的情况下会产生令人不快的结果。解决方案是对您的测试强制执行明确的顺序。
从您的 makefile 部分来看,我假设存在一个未公开的“源”变量,其中包含要测试的目标列表(隐式目标取决于这些目标)。该变量的立即扩展也会产生正确的结果。
假设变量是这样的:
那么,为了解决这个问题,生成以下依赖就足够了:
我们应该如何生成它?让我们在
list
变量获取其值之后编写一个 foreach-eval 循环:这将生成 makefile 的一部分,就像 C 预处理器一样(或者更准确地说,LISP 宏) 。它将像这样工作:对于通过
join
ing(将第一个列表的每个元素与第二个列表的相应元素连接)形成的列表中的每个项目t
,列表file2 file3 ... fileN run_tests
,每个元素添加后缀:
(从而形成file2: file3: ... fileN: run_tests:
),带有源列表file1 file2 ... fileN
; - 对于带有连接元素的列表中的每个这样的项目t
,将其作为 makefile 源代码的一部分进行评估,从而按照上面所示的规则进行操作。现在您只需调用 run_tests 目标,它将一一进行。
Unless the order of execution of targets is explicitly specified,
make
executes them in an arbitrary order--both in parallel and in non-parallel mode. This order undergoes internal algorithms ofmake
and in your case yields unpleasant results.The solution is to impel an explicit ordering to your tests.
From your part of makefile, I assume that there exists an unrevealed "source" variable that contains a list of targets to test (on these targets implicit ones depend). Also immediate expansion of that variable yields correct results.
Assume the variable's like that:
then, to solve the problem, it would suffice to generate the following dependencies:
How should we generate it? Let's write an foreach-eval loop after the
list
variable gets its value:This will generate a part of makefile just like C preprocessor does (or, more correctly, LISP macros). It will work like this: for each item
t
in the list formed byjoin
ing (concatenating each element of first list with corresponding element of the second) the listfile2 file3 ... fileN run_tests
, to each element of which a suffix:
is added (thus formingfile2: file3: ... fileN: run_tests:
), with source listfile1 file2 ... fileN
; - for each such itemt
in list with joined elements evaluate it as part of makefile's source, thus acting as the rules shown above were prescribed.Now you're only to invoke run_tests target and it will go one-by-one.
突然,我的脑海里又冒出了另一个想法!
这解决了所有问题,除了测试可能无法按正确的顺序调用(但实际上它们很可能会顺利进行)。
Suddenly, another idea came into my mind!
This solves everything except that tests may not be invoked in proper order (but in practice they most likely will go well).
我对
-j
标志进行了一些阅读,我认为问题在于这为独立规则启动了新的工作。每个图像的作业都是独立的,因此每个目标的第一个依赖项将像您所看到的那样运行。我认为这里的主要问题是这个任务本质上是串行的,也就是说每个目标的依赖项必须按顺序运行,一个接一个。因此,在每个目标中,您无法在这种粒度级别上利用多道程序设计的优势。
由于
make
似乎没有按照您想要的顺序处理依赖项,因此支持并行测试的单元测试框架可能更合适。我通过谷歌搜索知道其中有几个退出,但我不能推荐什么时候退出,因为我没有使用过任何退出,并且不确定您正在使用哪种语言。I did some reading on the
-j
flag and I think the issue is that this starts new jobs for independent rules. The jobs for every image are independent, so the first dependency for each target will be run like you're seeing.I think the main problem here is that this task is inherently serial, that's to say that the dependencies for each target must be run in order, one after another. So within each target, you don't have a way to take advantage of multiprogramming, at this level of granularity.
As
make
doesn't seem to be processing dependencies in the order that you want, perhaps a unit testing framework that supports parallel tests would be a better fit. I know through some Googling that several of these exits, but I can't recommend when as I haven't used any and am not sure which language you're using.