首页 > 解决方案 > 即使我添加了 --jobs 并且 --max-load 甚至没有关闭,为什么 GNU Make 会按顺序运行?

问题描述

这是在 GNU Make 3.82、RHEL 7 上的。即使我传入 .Make 似乎是按顺序运行的--jobs

我正在做大约 700K 的琐碎工作——将大型 gzip 文件连接到其他 gzip 文件上。如果只有一个文件要连接,那么我创建一个符号链接。这是命令:

# Pattern to rebuild gzip file - concatenate if needed, otherwise just link
$(THISDIR)/%.tgz:
    mkdir -p $$(dirname $@) && \
    if [ $$(echo '$^' | wc -w) -gt 1 ]; then cat $^ > $@; else ln -s $^ $@; fi

我已经分开&&以避免另一个shell调用,没有区别。

70 万个作业中约有 60 万个只是创建符号链接。对于其余部分,要连接的平均文件数为四个。

为什么这么慢?我得到 5-8 TPS。更重要的是,即使我指定(在具有 64 个 CPU 的机器上):

make --jobs --max-load=48

我在top. 因此,Make 似乎根本没有运行并行作业。并行性在 GNU Make 上有效工作是否有最小的工作长度?

top从现在开始的平均负载是

top - 22:50:32 up 3 days, 13:13, 32 users,  load average: 7.96, 7.44, 5.73

一些可能有帮助的进一步细节:

  1. Make 本身以接近 100% 的 CPU 运行。
  2. 当然,除了目标和对同一规则的依赖关系之外,任何文件之间都没有依赖关系。换句话说,没有文件同时出现在$@和中$^
  3. 正在从 NFS 挂载创建和读取文件
  4. 我已经生成了 700K 依赖项作为规则,这些规则使用include. 该过程本身需要 25 分钟左右。

标签: bashmakefileparallel-processing

解决方案


可以提高性能,尤其是在使用 (gnu) make 函数替换 shell 命令来重建大量文件时。这将减少完成任务所需的“fork”和“exec”的数量:

%.tgz:
        mkdir -p $(<D) && \
        $(if $(findstring $(words $^),1),ln -s $^ $@, cat $^ > $@)

对于 mkdir 命令,使用$(<D)将消除对dirname

对于cat/ln命令,使用$(findstring ...)andwords将替换echo ... | wc管道,并且$if(...)将替换 shell if 语句。

总体而言,每个目标只有 2 个命令(mkdir、cat/ln),而不是 5 个命令(mkdir、dirname、echo、wc、cat/ln)。性能约为 2X


推荐阅读