【问题标题】:How to use GNU make --max-load on a multicore Linux machine?如何在多核 Linux 机器上使用 GNU make --max-load?
【发布时间】:2012-12-17 06:31:14
【问题描述】:

来自 GNU make 的文档:http://www.gnu.org/software/make/manual/make.html#Parallel

当系统负载很重时,您可能希望运行更少 作业比轻载时。您可以使用“-l”选项 告诉 make 限制一次运行的作业数量,基于 平均负载。 “-l”或“--max-load”选项后跟一个 浮点数。例如,

 -l 2.5

如果平均负载高于 2.5,将不会让 make 启动多个作业。 没有后面数字的“-l”选项会删除负载限制,如果有的话 与先前的“-l”选项一起给出。

更准确地说,当 make 开始工作时,它已经有了 至少有一个作业正在运行,它检查当前的平均负载;如果是 不低于“-l”给出的限制,make 等到加载 平均值低于该限制,或直到所有其他作业完成。

来自 Linux 手册页的正常运行时间:http://www.unix.com/man-page/Linux/1/uptime/

系统负载平均数是 处于可运行或不可中断状态。可运行的进程 状态要么正在使用 CPU,要么正在等待使用 CPU。一个过程 处于不间断状态正在等待一些 I/O 访问,例如等待 为磁盘。取三个时间间隔的平均值。 负载平均值未针对系统中的 CPU 数量进行标准化, 所以平均负载为 1 表示单个 CPU 系统已加载所有 在 4 CPU 系统上,这意味着它有 75% 的时间处于空闲状态。

我有一个并行的 makefile,我想做一件显而易见的事情:让 make 继续添加进程,直到我得到完全的 CPU 使用率,但我不会引起抖动。

今天的许多(全部?)机器都是多核的,这意味着平均负载不是制造商应该检查的数字,因为该数字需要根据内核数进行调整。

这是否意味着 GNU make 的 --max-load(又名 -l)标志现在没用了?在多核机器上运行并行 makefile 的人在做什么?

【问题讨论】:

    标签: gnu-make multicore uptime


    【解决方案1】:

    我的简短回答:--max-load 如果您愿意花时间充分利用它,那么它会很有用。在目前的实现中,没有简单的公式来选择好的值,也没有预制工具来发现它们。


    我维护的构建相当大。在我开始维护它之前,构建是 6 小时。在 ramdisk 上使用-j64,现在它在 5 分钟内完成(在使用 -j12 的 NFS 挂载上需要 30 分钟)。我的目标是为-j-l 找到合理的上限,以使我们的开发人员能够快速构建,但不会使服务器(构建服务器或NFS 服务器)对其他人无法使用。

    开始:

    • 如果您选择一个合理 -jN 值(在您的机器上)并找到一个合理的负载平均值上限(在您的机器上),它们可以很好地协同工作以保持平衡。李>
    • 如果您使用非常大的-jN 值(或未指定;例如,没有数字的-j)并限制平均负载,gmake 将:
      • 继续生成进程(gmake 3.81 添加了一个限制机制,但这只有助于稍微缓解问题)直到达到最大作业数或直到平均负载超过您的阈值
      • 当负载平均值超过您的阈值时:
        • 在所有子流程完成之前什么都不做
        • 一次生成一项工作
      • 从头再来

    至少在 Linux 上(可能还有其他 *nix 变体),load average isexponential moving average(重新加权的 UNIX 平均负载,Neil J. Gunther)表示等待 CPU 时间的平均进程数(可能由进程太多,等待 IO,页面错误等)。由于它是指数移动平均线,因此对其进行加权使得新样本比旧样本对当前值的影响更大。

    如果您可以为正确的最大负载和并行作业数量确定一个良好的“最佳位置”(通过有根据的猜测和经验测试的组合),假设您有一个长时间运行的构建:您的 1 分钟平均值将达到平衡点(波动不大)。但是,如果您的 -jN 数字对于给定的最大负载平均值来说太高,它会波动很大。

    找到最佳位置本质上等同于找到微分方程的最佳参数。由于它将受到初始条件的影响,因此重点是寻找使系统保持平衡的参数,而不是提出“目标”负载平均值。我所说的“平衡”是指:1m 平均负载波动不大。

    假设您没有受到 gmake 限制的限制:当您找到一个 -jN -lM 组合时,可以缩短构建时间:该组合会将您的机器推向极限。如果机器需要用于其他用途...

    ...您可能希望在完成优化后将其缩小一点。

    不考虑平均负载,我看到的构建时间随着-jN 的增加而得到的改进似乎是[大致] 对数。也就是说,我看到-j8-j12之间的区别比-j12-j16之间的区别更大。

    对我来说,事情在-j48-j64 之间达到顶峰(在Solaris 机器上大约是-j56),因为最初的gmake 进程是单线程的;在某些时候,线程无法比完成更快地启动新作业。

    我的测试是在:

    • 非递归构建
      • 递归构建可能会看到不同的结果;他们不会遇到我在-j64 周围遇到的瓶颈
      • 我已尽力减少配方中的 make-isms(变量扩展、宏等)的数量,因为配方解析发生在产生并行作业的同一线程中。配方越复杂,它在解析器中花费的时间就越多,而不是生成/收获作业。例如:
        • 配方中没有使用$(shell ...) 宏;这些在第一次解析过程中运行并缓存
        • 大多数变量都分配有:= 以避免递归扩展
    • Solaris 10/sparc
      • 256 核
      • 没有虚拟化/逻辑域
      • 构建在 ramdisk 上运行
    • x86_64 linux
      • 32 核(4 倍超线程)
      • 没有虚拟化
      • 构建在快速的本地驱动器上运行

    【讨论】:

      【解决方案2】:

      今天的许多(全部?)机器都是多核的,所以这意味着负载 平均值不是 make 应该检查的数字,因为该数字 需要根据核心数量进行调整。

      这是否意味着 GNU make 的 --max-load (aka -l) 标志现在是 没用?

      没有。想象一下对磁盘 I/O 要求很高的作业。如果您启动的作业数量与拥有 CPU 的数量一样多,那么您仍然不会很好地利用 CPU。

      就我个人而言,我只是使用 -j,因为到目前为止它对我来说已经足够好了。

      【讨论】:

        【解决方案3】:

        即使对于 CPU 是瓶颈的构建,-l 也不理想。我使用-jN,其中 N 是存在的或我想在构建上花费的内核数。在我的情况下,选择更大的数字并不能加快构建速度。它也不会减慢速度,只要您不走火入魔(例如通过-j 指定无限)。

        使用-lN大致相当于-jN,如果机器有其他独立工作可以更好地工作,但是有两个怪癖(除了你提到的那个,核心数没有考虑) :

        • 初始峰值:当构建开始时,make 会启动很多作业,远远超过 N。当进程被派生时,系统负载数不会立即增加。在我的情况下,这不是问题。
        • 饥饿:当一些构建作业比其他构建作业耗时较长时,在前 M 个快速作业结束的那一刻,系统负载仍然 >N。很快,系统负载下降到 N - M,但只要这几个缓慢的作业还在拖,就不会启动新作业,并且核心处于饥饿状态。 Make 只考虑在旧工作结束时和开始时启动新工作。它不会注意到系统负载在两者之间下降。

        【讨论】:

          【解决方案4】:

          这是否意味着 GNU make 的 --max-load (aka -l) 标志现在没用了?在多核机器上运行并行 makefile 的人在做什么?

          其中一个示例是在测试套件中运行作业,其中每个测试都必须编译和链接程序。链接有时会过多地加载系统,结果 - 致命错误:ld 以信号 9 [Killed] 终止。就我而言,这不是内存开销,而是 CPU 使用率,因此通常建议的交换文件没有帮助。

          使用选项-l 1 执行仍然是并行的,但链接几乎是顺序的:

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-10-04
            • 2011-03-25
            • 1970-01-01
            • 1970-01-01
            • 2011-01-09
            • 2020-08-19
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多