关于GNU make中作业数量是否应该等于处理器核心数还是可通过添加一个额外的作业来优化构建时间,这似乎存在一些争议。
在四核系统上,使用-j4
还是-j5
更好?
您是否看到(或进行)了任何支持其中一种的基准测试?
我已经在我的带超线程的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
基本结果:
我的猜测:如果您的计算机正在进行其他操作,请使用核心数。否则,请使用线程数。超过线程数不会带来任何好处。在某些时候,由于内存限制导致崩溃,编译速度变得更慢。"inf"行是在很晚之后添加的,这让我怀疑在执行8个或更多任务时存在一些热量限制。这表明对于这个项目大小,没有内存或吞吐量限制。但考虑到只有8GB内存可以用于编译,这是一个相对较小的项目。
-j4
到 -j8
的 10% 加速((59.8-53.5) / 59.8
)与 Maxim 从 -j6
到 -j9
的 12% 加速差不多,这被证明是他的 6c12t 机器的最佳选择。 - Peter Cordes我认为最好的做法是在你特定的环境和工作负载上自行进行基准测试。看起来有太多的变量(源文件的大小/数量,可用内存,磁盘缓存,源目录和系统头是否位于不同的磁盘上等),无法给出适合所有情况的答案。
根据我的个人经验(在一台2核MacBook Pro上),使用-j2比-j1快得多,但超过这个数量(-j3,-j4等)没有明显的加速效果。因此,在我的环境中,“jobs == number of cores”似乎是一个不错的答案。(但结果可能会有所差异)
个人而言,我使用make -j n
,其中n为“核心数”+1。
然而,我无法给出科学解释:我看到很多人都使用相同的设置,并且到目前为止它们给了我不错的结果。
无论如何,你必须小心,因为有些make链根本不兼容--jobs
选项,可能会导致意外结果。如果你遇到奇怪的依赖错误,请尝试不使用--jobs
进行make
。
两种方法都没有错。为了让自己感到平静,并且与您正在编译的软件的作者和解(不同的多线程/单线程限制适用于软件本身),我建议您使用:
make -j`nproc`
注意:nproc
是Linux命令,用于返回系统上可用的核心/线程数(现代CPU)。将它放在如上所示的引号“`”下面,将数字传递给make命令。
附加信息:正如某些人提到的,使用所有的核心/线程来编译软件可能会让您的系统变得非常缓慢甚至无响应,并且甚至可能比使用较少的核心需要更长时间。我曾经看到一位Slackware用户发布了他拥有双核CPU,但仍然进行了高达j 8的测试,这在j 2处停止不再有区别(该CPU只能利用2个硬件核心)。因此,为了避免出现无响应的问题,建议您按照以下方式运行它:
make -j`nproc --ignore=2`
这将把nproc
的输出传递给make
,并从其结果中减去2个核心。
make -j$(nproc --ignore=2)
,因为它比反引号更易于阅读。 - Mikko Rantalainen我刚刚购买了一台带有Foxconn主板和4GB G-Skill内存的Athlon II X2 Regor处理器。
我在最后附上了我的规格信息,包括 'cat /proc/cpuinfo' 和 'free' 命令的输出,方便其他人查看。这是一款双核心的Athlon II x2处理器,配备4GB内存。
uname -a on default slackware 14.0 kernel is 3.2.45.
我将下一个步骤的内核源代码 (linux-3.2.46) 下载到 /archive4 目录;
解压它 (tar -xjvf linux-3.2.46.tar.bz2
);
进入该目录 (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' 的测试。
普通的 "make":
real 51m47.510s
user 47m52.228s
sys 3m44.985s
bob@Moses:/archive4/linux-3.2.46$
real 27m3.194s
user 48m5.135s
sys 3m39.431s
bob@Moses:/archive4/linux-3.2.46$
与上面相同,只是使用make -j3
real 27m30.203s
user 48m43.821s
sys 3m42.309s
bob@Moses:/archive4/linux-3.2.46$
与前面相同,但使用make -j4
real 27m32.023s
user 49m18.328s
sys 3m43.765s
bob@Moses:/archive4/linux-3.2.46$
与上述相同,但使用 make -j8
real 28m28.112s
user 50m34.445s
sys 3m49.877s
bob@Moses:/archive4/linux-3.2.46$
'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
'free' 的结果为:
bob@Moses:/archive4$ free
total used free shared buffers cached
Mem: 3991304 3834564 156740 0 519220 2515308
make -j
是什么意思?Make 应该会检查负载并根据负载调整进程数量。 - docwhatmake -j
doesn't limit the number of jobs at all. This is usually disastrous on a medium- or large-sized project as quickly more jobs are forked than can be supported by RAM.The option you need to restrict by load is -l [load]
, in conjunction with -j
- Matt Godboltscons -j1 --release --native 120.68s user 9.78s system 99% cpu 2:10.60 total
scons -j2 --release --native 122.96s user 9.59s system 197% cpu 1:07.15 total
scons -j3 --release --native 125.62s user 9.75s system 292% cpu 46.291 total
scons -j4 --release --native 128.26s user 10.41s system 385% cpu 35.971 total
scons -j5 --release --native 133.73s user 10.33s system 476% cpu 30.241 total
scons -j6 --release --native 144.10s user 11.24s system 564% cpu 27.510 total
scons -j7 --release --native 153.64s user 11.61s system 653% cpu 25.297 total
scons -j8 --release --native 161.91s user 12.04s system 742% cpu 23.440 total
scons -j9 --release --native 169.09s user 12.38s system 827% cpu 21.923 total
scons -j10 --release --native 176.63s user 12.70s system 910% cpu 20.788 total
scons -j11 --release --native 184.57s user 13.18s system 989% cpu 19.976 total
scons -j12 --release --native 192.13s user 14.33s system 1055% cpu 19.553 total
scons -j13 --release --native 193.27s user 14.01s system 1052% cpu 19.698 total
scons -j14 --release --native 193.62s user 13.85s system 1076% cpu 19.270 total
scons -j15 --release --native 195.20s user 13.53s system 1056% cpu 19.755 total
scons -j16 --release --native 195.11s user 13.81s system 1060% cpu 19.692 total
( -jinf test not included, as it is not supported by scons.)
相关:
https://www.phoronix.com/review/amd-epyc-9754-smt/6 在拥有 128 个 Zen4c 核心的 AMD Bergamo 上测试了开启和关闭 SMT。使用 clang 和 GCC 进行编译时,开启 SMT 的情况下编译时间比关闭 SMT 的情况更长。(拥有充足的内存,并且源代码已经热存在磁盘缓存中,在无 SMT 构建中已经有足够的并行性,因为这是一个巨大的物理核心数量。甚至可能与某些目录中的源文件数量相比。)
Zen 4C 核心每个核心的 L3 缓存较少(每个 CCX 16 个核心而不是 8 个),这可能对 SMT 的影响更大。
此外,那台 EPYC 的 CPU 频率可能受到功耗限制,所以没有开启 SMT 的情况下 CPU 频率可能更高。在 "Eco" 模式下运行可能会改变这一点。
根据我的经验,增加额外的作业可以带来一些性能优势。这是因为磁盘 I/O 是除 CPU 外的瓶颈之一。然而,要决定增加多少个额外的作业并不容易,因为这与使用的 CPU 核心数量和磁盘类型高度相关。
是的!在我的3950x上,我运行-j32,它可以节省几个小时的编译时间!即使在编译期间,我仍然可以观看YouTube、浏览网页等,没有任何区别。即使使用1TB 970 PRO nvme或1TB Auros Gen4 nvme和64GB的3200C14,处理器也不总是被占用。即使它被占用了,我在用户界面上也没有注意到差异。我计划在不久的将来在一些大型项目中测试-j48。像你一样,我期望看到一些令人印象深刻的改进。那些仍然使用四核心的人可能不会获得同样的收益....
连Linus本人都升级到了3970x,你可以打赌他至少在运行-j64。
make \
nproc``命令来创建独立于CPU的脚本 :) - VivienG