GNU make:作业数量是否应该等于系统中的CPU核心数量?

Joh*_*han 80 makefile gnu-make

关于GNU make中的作业数量是否应该等于核心数量似乎存在争议,或者如果您可以通过添加一个可以排队等待而其他人"工作"的额外作业来优化构建时间.

使用-j4-j5四核系统更好吗?

您是否看过(或已完成)支持其中一种或哪种的基准测试?

Dav*_*har 52

我想说最好的办法是自己根据你的特定环境和工作量进行基准测试.似乎有太多的变量(源文件的大小/数量,可用内存,磁盘缓存,您的源目录和系统头是否位于不同的磁盘上等),以获得一个通用的答案.

我的个人经验(在双核MacBook Pro上)是-j2明显比-j1快,但除此之外(-j3,-j4等),没有可衡量的加速.因此,对于我的环境,"jobs ==核心数"似乎是一个很好的答案.(YMMV)


das*_*ndy 51

我在我的4核上使用超线程笔记本电脑运行我的家庭项目并记录结果.这是一个相当重编译器的项目,但它包括最后17.7秒的单元测试.编译不是非常密集的IO; 有很多可用的内存,如果没有,其余的是在快速SSD上.

1 job        real   2m27.929s    user   2m11.352s    sys    0m11.964s    
2 jobs       real   1m22.901s    user   2m13.800s    sys    0m9.532s
3 jobs       real   1m6.434s     user   2m29.024s    sys    0m10.532s
4 jobs       real   0m59.847s    user   2m50.336s    sys    0m12.656s
5 jobs       real   0m58.657s    user   3m24.384s    sys    0m14.112s
6 jobs       real   0m57.100s    user   3m51.776s    sys    0m16.128s
7 jobs       real   0m56.304s    user   4m15.500s    sys    0m16.992s
8 jobs       real   0m53.513s    user   4m38.456s    sys    0m17.724s
9 jobs       real   0m53.371s    user   4m37.344s    sys    0m17.676s
10 jobs      real   0m53.350s    user   4m37.384s    sys    0m17.752s
11 jobs      real   0m53.834s    user   4m43.644s    sys    0m18.568s
12 jobs      real   0m52.187s    user   4m32.400s    sys    0m17.476s
13 jobs      real   0m53.834s    user   4m40.900s    sys    0m17.660s
14 jobs      real   0m53.901s    user   4m37.076s    sys    0m17.408s
15 jobs      real   0m55.975s    user   4m43.588s    sys    0m18.504s
16 jobs      real   0m53.764s    user   4m40.856s    sys    0m18.244s
inf jobs     real   0m51.812s    user   4m21.200s    sys    0m16.812s
Run Code Online (Sandbox Code Playgroud)

基本结果:

  • 扩展到核心数量几乎可以线性地提高性能.实际时间从2.5分钟下降到1.0分钟(快2.5倍),但编译时间从2.11上升到2.50分钟.系统注意到这个位中几乎没有额外的负载.
  • 从核心数量到线程数量的扩展极大地增加了用户负载,从2.50分钟增加到4.38分钟.这种接近翻倍很可能是因为其他编译器实例想要同时使用相同的CPU资源.系统对请求和任务切换的负载有所增加,导致它使用了17.7秒的时间.编译时间为53.5秒,优势约为6.5秒,速度提高了12%.
  • 从线程计数到双线程计数的缩放没有显着的加速.12和15的时间很可能是您可以忽略的统计异常.所用的总时间略有增加,系统时间也是如此.两者都很可能是由于任务切换增加.这没有任何好处.

我现在的猜测:如果您在计算机上执行其他操作,请使用核心计数.如果不这样做,请使用线程计数.超过它显示没有好处.在某些时候,由于这种情况,它们将变得内存受限并崩溃,使编译速度变慢."inf"系列是在更晚的日期添加的,让我怀疑8个工作岗位有一些热量限制.这确实表明,对于此项目大小,实际上没有内存或吞吐量限制.这是一个小项目,虽然可以编译8GB的内存.


ere*_*eOn 30

我个人使用的make -j n地方是n是"核心数"+ 1.

但是,我不能给出科学的解释:我看到很多人使用相同的设置,到目前为止他们给了我相当不错的结果.

无论如何,你必须要小心,因为一些make-chains只是与--jobs选项不兼容,并且可能导致意想不到的结果.如果您遇到奇怪的依赖错误,请尝试make不使用--jobs.

  • 解释(虽然不能保证其科学性)是"+ 1"提供额外的工作,当其他n个工作中的任何一个正在进行I/O时运行. (17认同)
  • 一些make-chains只是与--jobs选项不兼容 - >这意味着你缺少了依赖项.如果你得到这个,修复你的makefile. (4认同)

ijp*_*est 7

最终,您必须做一些基准来确定用于构建的最佳数字,但请记住,CPU并不是唯一重要的资源!

例如,如果你有一个严重依赖磁盘的构建,那么在多核系统上产生大量作业实际上可能会更慢,因为磁盘必须做额外的工作来回移动磁盘头以服务所有不同的工作(取决于很多因素,例如操作系统处理磁盘缓存的程度,磁盘的本机命令排队支持等).

然后你就拥有了"真正的"内核和超线程.您可能会或可能不会从每个超线程的产生作业中受益.再次,你将需要基准来找出答案.

我不能说我已经专门尝试了#cores + 1,但在我们的系统上(Intel i7 940,4个超线程内核,大量RAM和VelociRaptor驱动器)和我们的构建(大规模C++构建,交替使用CPU和I)/O bound)-j4和-j8之间的差别很小.(它可能好15%......但远不及两倍好.)

如果我要去吃午饭,我会使用-j8,但是如果我想在我的系统建设时使用我的系统,我将使用较低的数字.:)

  • @sg:j8 对我在原帖中描述的系统来说真的很费劲……这台机器仍然*可用*,但它的响应速度肯定较慢。因此,如果我仍然想以交互方式将它用于其他任务(通常处理其他代码,也许偶尔会构建单个 DLL),我会为交互位保留几个核心。 (2认同)

小智 6

两者都没有错。为了与您自己以及您正在编译的软件的作者保持和平(不同的多线程/单线程限制适用于软件级别本身),我建议您使用:

make -j`nproc`
Run Code Online (Sandbox Code Playgroud)

注意:nproc是 linux 命令,它将返回系统上可用的内核/线程数(现代 CPU)。像上面一样将它放在勾号下,会将数字传递给 make 命令。

附加信息:正如有人提到的那样,使用所有内核/线程来编译软件实际上会使您的机器窒息(无响应),甚至可能比使用更少的内核花费更长的时间。正如我在这里看到的一位 Slackware 用户发布的那样,他有双核 CPU,但仍然提供高达 j 8 的测试,这在 j 2 时不再不同(CPU 只能使用 2 个硬件内核)。所以,为了避免无响应的框,我建议你像这样运行它:

make -j`nproc --ignore=2`
Run Code Online (Sandbox Code Playgroud)

这将传递nprocto的输出make并从其结果中减去 2 个内核。


小智 5

我刚买了一台带有 Foxconn M/B 和 4GB G-Skill 内存的 Athlon II X2 Regor proc。

我把我的 'cat /proc/cpuinfo' 和 'free' 放在最后,这样其他人就可以看到我的规格。它是一款双核 Athlon II x2,具有 4GB 内存。

uname -a on default slackware 14.0 kernel is 3.2.45.
Run Code Online (Sandbox Code Playgroud)

我将下一步内核源代码(linux-3.2.46)下载到/archive4;

提取出来 ( tar -xjvf linux-3.2.46.tar.bz2);

cd 进入目录 ( cd linux-3.2.46);

并将默认内核的配置复制到 ( cp /usr/src/linux/.config .) 上;

用于make oldconfig准备3.2.46内核配置;

然后用 -jX 的各种咒语运行 make。

我通过在 time 命令之后发出 make 来测试每次运行的时间,例如,'time make -j2'。在每次运行之间,我 'rm -rf' linux-3.2.46 树并重新提取它,将默认的 /usr/src/linux/.config 复制到目录中,运行 make oldconfig 然后再次进行我的 'make -jX' 测试.

简单的“制作”:

real    51m47.510s
user    47m52.228s
sys     3m44.985s
bob@Moses:/archive4/linux-3.2.46$
Run Code Online (Sandbox Code Playgroud)

如上所述,但使用 make -j2

real    27m3.194s
user    48m5.135s
sys     3m39.431s
bob@Moses:/archive4/linux-3.2.46$
Run Code Online (Sandbox Code Playgroud)

如上所述,但使用 make -j3

real    27m30.203s
user    48m43.821s
sys     3m42.309s
bob@Moses:/archive4/linux-3.2.46$
Run Code Online (Sandbox Code Playgroud)

如上所述,但使用 make -j4

real    27m32.023s
user    49m18.328s
sys     3m43.765s
bob@Moses:/archive4/linux-3.2.46$
Run Code Online (Sandbox Code Playgroud)

如上所述,但使用 make -j8

real    28m28.112s
user    50m34.445s
sys     3m49.877s
bob@Moses:/archive4/linux-3.2.46$
Run Code Online (Sandbox Code Playgroud)

'cat /proc/cpuinfo' 产生:

bob@Moses:/archive4$ cat /proc/cpuinfo
processor       : 0
vendor_id       : AuthenticAMD
cpu family      : 16
model           : 6
model name      : AMD Athlon(tm) II X2 270 Processor
stepping        : 3
microcode       : 0x10000c8
cpu MHz         : 3399.957
cache size      : 1024 KB
physical id     : 0
siblings        : 2
core id         : 0
cpu cores       : 2
apicid          : 0
initial apicid  : 0
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 5
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmo
v pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rd
tscp lm 3dnowext 3dnow constant_tsc nonstop_tsc extd_apicid pni monitor cx16 p
opcnt lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowpre
fetch osvw ibs skinit wdt npt lbrv svm_lock nrip_save
bogomips        : 6799.91
clflush size    : 64
cache_alignment : 64
address sizes   : 48 bits physical, 48 bits virtual
power management: ts ttp tm stc 100mhzsteps hwpstate

processor       : 1
vendor_id       : AuthenticAMD
cpu family      : 16
model           : 6
model name      : AMD Athlon(tm) II X2 270 Processor
stepping        : 3
microcode       : 0x10000c8
cpu MHz         : 3399.957
cache size      : 1024 KB
physical id     : 0
siblings        : 2
core id         : 1
cpu cores       : 2
apicid          : 1
initial apicid  : 1
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 5
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmo
v pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rd
tscp lm 3dnowext 3dnow constant_tsc nonstop_tsc extd_apicid pni monitor cx16 p
opcnt lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowpre
fetch osvw ibs skinit wdt npt lbrv svm_lock nrip_save
bogomips        : 6799.94
clflush size    : 64
cache_alignment : 64
address sizes   : 48 bits physical, 48 bits virtual
power management: ts ttp tm stc 100mhzsteps hwpstate
Run Code Online (Sandbox Code Playgroud)

“免费”收益:

bob@Moses:/archive4$ free
             total       used       free     shared    buffers     cached
Mem:       3991304    3834564     156740          0     519220    2515308
Run Code Online (Sandbox Code Playgroud)

  • `make -j` 根本不限制作业数量。这对于中型或大型项目来说通常是灾难性的,因为分叉的作业数量很快就超出了 RAM 的支持能力。您需要通过负载限制的选项是“-l [load]”,与“-j”结合使用 (2认同)