如何在多核Linux机器上使用GNU make --max-load?

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”选项时没有指定数字,则“-l”选项将删除负载限制。

更确切地说,在make尝试启动作业并且已经有至少一个作业正在运行时,它会检查当前的负载平均值;如果负载平均值不低于使用“-l”指定的限制,则make会等待,直到负载平均值降至此限制以下,或者直到所有其他作业完成为止。

来自Linux man页面uptime: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的人们在做什么?
5个回答

11
我的简短回答是:--max-load 对于愿意投入时间来充分利用它的人是有用的。目前的实现方式没有简单的公式来选择好的值,也没有预制的工具来发现它们。
我维护的构建项目相当大。在我开始维护之前,构建需要6个小时。现在使用-j64和ramdisk,它只需要5分钟(如果使用-j12和NFS挂载,则需要30分钟)。我的目标是找到合理的-j-l上限,以使我们的开发人员能够快速构建,但不会使服务器(构建服务器或NFS服务器)对其他人无法使用。
首先:
如果您在您的机器上选择了一个合理的-jN值,并找到了一个合理的负载平均值的上限,它们可以很好地协同工作,以保持系统平衡。如果您使用非常大的-jN值(或未指定;例如,没有数字的-j),并限制负载平均值,gmake会:
- 继续生成进程(gmake 3.81添加了一个限流机制,但这只有点帮助来缓解问题),直到达到最大作业数或负载平均值超过您的阈值 - 当负载平均值超过您的阈值时:
- 等待所有子进程完成 - 每次只生成一个作业
- 再重复以上步骤
在Linux上(以及可能其他*nix变体),负载平均值是一个指数移动平均值(UNIX负载平均值重新加权,Neil J. Gunther),表示等待CPU时间的进程的平均数量(可能由于太多进程、等待IO、页面故障等原因)。由于它是指数移动平均值,因此它的加权方式使得新样本对当前值的影响比旧样本更强。
如果您可以通过教育性猜测和实证测试的组合来确定正确的最大负载和并行作业数量的好“甜点”,假设您有一个长时间运行的构建:您的1分钟平均值将达到一个平衡点(波动不大)。然而,如果您的-jN数字对于给定的最大负载平均值过高,则会波动相当大。
找到那个最佳点实质上相当于找到微分方程的最优参数。由于它将受到初始条件的影响,因此重点是找到使系统保持在平衡状态的参数,而不是提出“目标”负载平均值。所谓“平衡状态”,我指的是:1分钟的平均负载几乎没有波动。
假设您没有受到gmake的限制:当您找到一个-jN -lM组合,可以获得最短的构建时间时:该组合将推动您的机器达到极限。如果该机器需要用于其他用途...

compiling

“优化完成后,您可能希望将其缩小一点。”
“不考虑负载平均值,我发现增加-jN的构建时间改善大致呈对数曲线。也就是说,我在-j8和-j12之间看到了更大的差异,而在-j12和-j16之间看到的差异较小。”
“对我来说,在-j48和-j64之间达到了峰值(在Solaris机器上约为-j56),因为初始gmake进程是单线程的;在某些时候,该线程无法比它们完成得更快地启动新的作业。”
“我的测试是在以下环境中进行的:”
一个非递归构建
- 递归构建可能会看到不同的结果;它们不会遇到我在-j64周围遇到的瓶颈 - 我已经尽力减少了配方中的make-isms(变量扩展、宏等)的数量,因为配方解析发生在生成并行作业的同一线程中。 配方越复杂,它花费在解析器上的时间就越多,而不是生成/收割作业。 例如:
- 在配方中没有使用$(shell ...)宏;这些在第一次解析时运行并缓存 - 大多数变量都用:=赋值以避免递归扩展
Solaris 10/sparc
- 256个内核 - 没有虚拟化/逻辑域 - 构建在ramdisk上运行
x86_64 linux
- 32个内核(4x超线程) - 没有虚拟化 - 构建在快速本地驱动器上运行

1
今天的许多(或全部?)机器都是多核的,这意味着负载平均值不是make应该检查的数字,因为该数字需要根据核心数进行调整。
这是否意味着GNU make的--max-load(又名-l)标志现在无用了?
不是。想象一下需要大量磁盘I/O的作业。如果您启动与CPU数量相同的作业,仍然无法很好地利用CPU。
就我个人而言,我只是使用-j,因为到目前为止它已经足够好用了。

1
即使在CPU成为瓶颈的情况下,-l也不是最理想的选择。我使用-jN,其中N是存在或我想要用于编译的核心数量。在我的情况下,选择更大的数字并不能加速编译。只要不过度使用(例如通过-j无限启动),它也不会减慢编译速度。
使用-lN-jN大体相当,并且如果机器有其他独立工作要做,则可以更好地工作,但有两个怪癖(除了你提到的未计算核心数之外):
  • 初始峰值:当构建开始时,make会启动许多作业,比N多得多。当进程被forked时,系统负载数字不会立即增加。在我的情况下,这不是问题。
  • 饥饿:当一些构建作业花费大量时间而其他作业同样快速时,在前M个快速作业结束时,系统负载仍然≥N。很快,系统负载降至N-M,但只要那些慢作业还在拖延,就不会启动新的作业,并且核心将保持空闲。Make只有当旧作业结束和开始时才考虑启动新作业。它没有注意到中间系统负载的下降。

0
这是否意味着 GNU make 的 --max-load(又名 -l)标志现在已经无用了?那些在多核机器上运行并行 makefile 的人在做什么?
其中一个例子是在测试套件中运行作业,每个测试都必须编译和链接程序。链接有时会使系统负载过重,结果是致命错误:ld 以信号 9 [Killed] 终止。在我的情况下,不是内存开销,而是 CPU 使用率,因此通常建议的交换文件没有帮助。
使用选项 -l 1,执行仍然是并行的,但链接几乎是顺序的: system monitor visualizes resources consumption

0

这实际上是关于找到RAM使用和CPU使用之间的正确平衡。 RAM必须向CPU提供数据,而CPU需要完成工作,它们需要同步工作,这取决于您对其规格的确切设置。

对于我的系统(CPU:i5-1035G4,4核心,8线程,RAM:8GB和10GB交换,交换率为99%),最佳设置为:-l 1.9 -j7。

通过这种设置,我的系统编译速度快,性能约为50%,因此我仍然可以在前台使用我的系统进行其他所有操作。


通常情况下,对于交互式使用,较低的“swappiness”值更好,例如1或6。随着zswap的出现,将页面压缩为3:1或2:1,稍后再将它们写入磁盘,这种情况是否发生了变化?或者您运行一些应用程序,这些应用程序倾向于保留大型脏分配,以便可以将它们换出而不会影响交互延迟,以便快速切换回它们? - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接