13

来自 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(aka -l) 标志现在没用了?在多核机器上运行并行 makefile 的人在做什么?

4

4 回答 4

8

我的简短回答是:--max-load如果您愿意投入时间来充分利用它,这很有用。在当前的实现中,没有简单的公式可以选择好的值,也没有用于发现它们的预制工具。


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

首先:

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

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

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

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

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

编译

...当您完成优化时,您可能希望将其缩小一点。

不考虑平均负载,我在构建时间上看到的改进-jN似乎是 [大致] 对数。也就是说,我看到 and 之间的差异-j8-j12and 之间-j12的差异更大-j16

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

我的测试是在:

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

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

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

不。想象一下要求磁盘 i/o 的作业。如果您开始的工作与拥有 CPU 的数量一样多,那么您仍然不会很好地利用 CPU。

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

于 2013-05-02T10:59:54.170 回答
0

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

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

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

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

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

使用选项-l 1执行仍然是并行的,但链接几乎是顺序的: 系统监视器可视化资源消耗

于 2018-09-14T16:47:08.960 回答