在linux下编译时我使用flag -j16,因为我有16个内核。我只是想知道使用像-j32这样的东西是否有意义。实际上这是一个关于处理器时间安排的问题,是否有可能比其他任何方式对特定进程施加更多压力(假设我想用-j16对每个编译进行简化,如果有一个-j32会怎么样?) 。 我认为它没有多大意义,但我不确定,因为不知道内核如何解决这些问题。
亲切的问候,
答案 0 :(得分:3)
我使用基于GNU make的非递归构建系统,我想知道它的扩展程度如何。
我在具有超线程的6核Intel CPU上运行基准测试。我使用-j1
到-j20
来衡量编译时间。对于每个-j
选项make
,运行三次并记录最短时间。使用-j9
可以缩短编译时间,比-j6
好11%。
换句话说,超线程确实有一点帮助,超线程的英特尔处理器的最佳公式是number_of_cores * 1.5
:
答案 1 :(得分:2)
我们的商店里有一台具有以下特点的机器:
当它最初设置时,在其他用户发现它存在之前,我运行了一些时序测试,看看我能推动它到底有多远。有问题的构建是非递归的,因此所有作业都是从单个make进程中启动的。我还将我的仓库克隆到/tmp
以利用ram驱动器。
我看到-j56的改进。除此之外,我的结果很像Maxim的图表,直到某个地方(大致)-j75,性能开始下降。运行多个并行构建我可以将它推到-j56的明显上限之外。
主要制作过程是单线程的;在运行一些测试之后,我意识到我遇到的上限与主线程可以服务多少个子进程有关 - 这进一步受到makefile中任何需要额外时间解析的限制(例如,使用{{1而不是=
以避免不必要的延迟评估,复杂的用户定义宏等)或使用:=
之类的东西。
这些是我能够做的事情,可以加快那些会产生明显影响的构建:
尽可能使用$(shell)
如果您使用:=
分配一个变量,然后稍后使用:=
分配变量,则会继续使用立即评估。但是,+=
和?=
,如果之前未分配变量,则始终会延迟评估。
在你有足够大的构建之前,延迟评估似乎不是什么大问题。如果变量(如+=
)在所有makefile被解析后都没有变化,那么你可能不想对它进行延迟评估(如果你做你可能已经足够了解我所说的无论如何都要忽视我的建议。
如果您使用CFLAGS
工具创建宏,请尝试尽可能提前进行评估
我曾经在脑海中创建了以下形式的宏:
$(call)
此版本生成10,000多个目标文件,其中大约8,000个来自C ++代码。如果我使用IFLINUX = $(strip $(if $(filter Linux,$(shell uname)),$(1),$(2)))
IFCLANG = $(strip $(if $(filter-out undefined,$(origin CLANG_BUILD)),$(1),$(2)))
...
# an example of how I might have made the worst use of it
CXXFLAGS = ${whatever flags} $(call IFCLANG,-fsanitize=undefined)
,它只需要在已经评估的文本的所有编译步骤中立即替换CXXFLAGS := (...)
。相反,它必须为每个编译步骤重新评估该变量的文本一次。
如果您别无选择,可以至少帮助减轻某些重新评估的替代实施:
${CXXFLAGS}
...虽然这只会有助于避免重复的ifneq 'undefined' '$(origin CLANG_BUILD)'
IFCLANG = $(strip $(1))
else
IFCLANG = $(strip $(2))
endif
和$(origin)
来电;您仍然必须遵循尽可能使用$(if)
的建议。
尽可能避免在食谱中使用自定义宏
在上述之后,推理应该非常明显;任何需要为每个编译/链接步骤重复评估变量或宏的内容都会降低您的构建速度。每个宏/变量评估发生在与启动新作业相同的线程中,因此解析所花费的时间是延迟启动另一个并行作业的时间。
每当它促进代码重用和/或提高可读性时,我都会在自定义宏中添加一些配方,但我尽量将其保持在最低限度。
答案 2 :(得分:1)
经验法则是使用处理器数+ 1。 Hyper-Thready计数,因此具有HT的四核CPU应具有-j9
将值设置得过高会产生反效果,如果你想加快编译时间,可以考虑使用ccache来缓存每个编译中不会改变的编译对象,并将distcc分配到多台机器上。