make:禁用某些目标的并行执行

发布于 2024-11-30 23:38:19 字数 131 浏览 0 评论 0原文

我有一个编译工作,其中链接需要大量 IO 工作。我们有大约十几个核心,因此我们运行 make -j13,但是当涉及到链接 6 个目标时,我希望这些以循环方式完成。我想过让一个依赖于下一个,但我认为这会打破单独的目标。有什么想法如何解决这个小问题吗?

I have a compile job where linking is taking a lot of IO work. We have around a dozen of cores so we run make -j13, but when it comes to linking the 6 targets, I'd like those to be done in a round robin way. I thought about making one depend on the next but I think this would break the individual targets. Any ideas how to solve this small issue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

且行且努力 2024-12-07 23:38:19

make 本身不提供请求“N 个,但一次不超过 M 个”的机制。

您可以尝试使用 GNU parallel 包中的 sem 命令你的链接器规则的配方。其文档有一个确保一次仅运行一个工具实例的示例。在您的示例中,您将允许 make 一次启动最多 13 个 sem,但一次只有其中一个会运行链接器,而其他的则阻止。

缺点是,您可能会遇到这样的情况:make 的 13 个作业槽位中有 5 个与 sem 实例绑定,而这些实例都在等待链接器进程来执行操作。结束。根据构建的结构,这可能意味着浪费一些 CPU 时间。不过,仍然击败了 6 个链接器同时对磁盘造成的影响:-)

make itself doesn't provide a mechanism to request "N of these, but no more than M of those at a time".

You might try using the sem command from the GNU parallel package in the recipe of your linker rules. Its documentation has an example of ensuring only one instance of a tool runs at once. In your example, you would allow make to start up to 13 sems at a time, but only one of those at a time will run the linker, while the others block.

The downside is that you could get into a situation where 5 of your make's 13 job slots are tied up with instances of sem that are all waiting for a linker process to finish. Depending on the structure of your build, that might mean some wasted CPU time. Still beats 6 linkers thrashing the disk at once, though :-)

调妓 2024-12-07 23:38:19

您应该指定您的六个目标不能并行构建。将这样的行添加到您的 makefile 中:

.NOTPARALLEL: target1 target2 target3 target4 target5 target6

有关详细信息,请查看此处 https://www.gnu.org/software/make/manual/html_node/Parallel-Disable.html

You should specify that your six targets cannot be built in parallel. Add a line like this to your makefile:

.NOTPARALLEL: target1 target2 target3 target4 target5 target6

For more information look here https://www.gnu.org/software/make/manual/html_node/Parallel-Disable.html.

你怎么敢 2024-12-07 23:38:19

我偶然发现了一个 hacky 解决方案:

对于它运行的每个配方,Make 都会做两件事:它扩展配方中的变量/函数,然后运行 ​​shell 命令。

由于第一步可以读取/写入全局变量,因此它似乎是同步完成的。

因此,如果您在第一步中运行所有 shell 命令(使用 $(shell )),则其他配方在运行时将无法启动。

例如,考虑这个 makefile:

all: a b

a:
        sleep 1

b:
        sleep 1

time make -j2 报告 1 秒。

但如果您将其重写为:

# A string of all single-letter Make flags, without spaces.
override single_letter_makeflags = $(filter-out -%,$(firstword $(MAKEFLAGS)))

ifneq ($(findstring n,$(single_letter_makeflags)),)
# See below.
override safe_shell = $(info Would run shell command: $1)
else ifeq ($(filter --trace,$(MAKEFLAGS)),)
# Same as `$(shell ...)`, but triggers a error on failure.
override safe_shell = $(shell $1)$(if $(filter-out 0,$(.SHELLSTATUS)),$(error Unable to execute `$1`, exit code $(.SHELLSTATUS)))
else
# Same functions but with logging.
override safe_shell = $(info Shell command: $1)$(shell $1)$(if $(filter-out 0,$(.SHELLSTATUS)),$(error Unable to execute `$1`, exit code $(>
endif

# Same as `safe_shell`, but discards the output and expands to nothing.
override safe_shell_exec = $(call,$(call safe_shell,$1))


all: a b

a:
        $(call safe_shell_exec,sleep 1)
        @true

b:
        $(call safe_shell_exec,sleep 1)
        @true

time make -j2 现在报告 2 秒。

在这里,@true 不执行任何操作,并抑制 Nothing to be did for ?? 输出。

但这种方法存在一些问题。一是所有输出都将被丢弃,除非重定向到文件或 stderr...

I've stumbled upon a hacky solution:

For each recipe it runs, Make does two things: it expands variables/functions in the recipe, and then runs the shell commands.

Since the first step can read/write the global variables, it seems to be done synchronously.

So if you run all your shell commands during the first step (using $(shell )), no other recipe will be able to start while they're running.

E.g. consider this makefile:

all: a b

a:
        sleep 1

b:
        sleep 1

time make -j2 reports 1 second.

But if you rewrite it to this:

# A string of all single-letter Make flags, without spaces.
override single_letter_makeflags = $(filter-out -%,$(firstword $(MAKEFLAGS)))

ifneq ($(findstring n,$(single_letter_makeflags)),)
# See below.
override safe_shell = $(info Would run shell command: $1)
else ifeq ($(filter --trace,$(MAKEFLAGS)),)
# Same as `$(shell ...)`, but triggers a error on failure.
override safe_shell = $(shell $1)$(if $(filter-out 0,$(.SHELLSTATUS)),$(error Unable to execute `$1`, exit code $(.SHELLSTATUS)))
else
# Same functions but with logging.
override safe_shell = $(info Shell command: $1)$(shell $1)$(if $(filter-out 0,$(.SHELLSTATUS)),$(error Unable to execute `$1`, exit code $(>
endif

# Same as `safe_shell`, but discards the output and expands to nothing.
override safe_shell_exec = $(call,$(call safe_shell,$1))


all: a b

a:
        $(call safe_shell_exec,sleep 1)
        @true

b:
        $(call safe_shell_exec,sleep 1)
        @true

time make -j2 now reports 2 seconds.

Here, @true does nothing, and suppresses Nothing to be done for ?? output.

There are some problems with this approach though. One is that all output is discarded unless redirected to file or stderr...

却一份温柔 2024-12-07 23:38:19

它不会打破个人目标。
您可以为目标创建任意数量的 (:) 规则,只要其中只有一个规则具有构建它的实际配方即可。这似乎是一个很好的用例。

It won't break individual targets.
You can create any number of (:) rules for a target, as long as only one of them has an actual recipe for building it. This appears to be a good use case for that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文