如何提高Makefile的速度?

时间:2011-06-30 19:30:47

标签: makefile performance

我正在使用C ++和C ++构建多个二进制文件。 CUDA在Fortran中有几个文件。我找到了this question,我遇到了类似的问题。一位用户最近要求我重新构建一个三年前版本的存储库(在我们执行大规模迁移和重命名之前),我感到非常震惊,看看它的构建速度有多快。确切地确定该版本之间的哪些更改以及现在导致构建过长的时间是不可能/非常耗时的。

然而,我在回答对上述问题的评论中注意到:

  

特别要记住使用:=而不是=,as:=进行扩展   马上,这节省了时间。 - 杰克凯利3月23日22:38

我还应该注意其他建议吗?

注意:

  • 我使用'include'范例,我想要构建的每个目录都有一个module.mk文件,该文件直接包含在一个Makefile中。
  • 我确实使用了以下几个函数:

(降价..)

#
# CUDA Compilation Rules
#

define cuda-compile-rule
  $1: $(call generated-source,$2) \
    $(call source-dir-to-build-dir, $(subst .cu,.cubin, $2)) \
    $(call source-dir-to-build-dir, $(subst .cu,.ptx, $2))
    $(NVCC) $(CUBIN_ARCH_FLAG) $(NVCCFLAGS) $(INCFLAGS) $(DEFINES) -o $$@ -c $$<

  $(call source-dir-to-build-dir, $(subst .cu,.cubin, $2)): $(call generated-source,$2)
    $(NVCC) -cubin -Xptxas -v $(CUBIN_ARCH_FLAG) $(NVCCFLAGS) $(INCFLAGS) $(DEFINES) $(SMVERSIONFLAGS) -o $$@ $$<

  $(call source-dir-to-build-dir, $(subst .cu,.ptx, $2)): $(call generated-source,$2)
    $(NVCC) -ptx $(CUBIN_ARCH_FLAG) $(NVCCFLAGS) $(INCFLAGS) $(DEFINES) $(SMVERSIONFLAGS) -o $$@ $$<

  $(subst .o,.d,$1): $(call generated-source,$2)
    $(NVCC) $(CUBIN_ARCH_FLAG) $(NVCCFLAGS) $3 $(TARGET_ARCH) $(INCFLAGS) $(DEFINES) -M $$< | \
    $(SED) 's,\($$(notdir $$*)\.o\) *:,$$(dir $$@)\1 $$@: ,' > $$@.tmp
    $(MV) $$@.tmp $$@
endef
  • 但我在旧版本中使用的大部分功能......

最后:如何确定编译时间或make时间是否真的放慢了速度?

我不想附加整个Makefile。这是914行,但我很乐意用片段更新问题,如果有帮助的话。

更新:这是我的依赖关系生成规则&amp;编译规则:

#
# Dependency Generation Rules
#

define dependency-rules

  $(subst .o,.d,$1): $2
    $(CC) $(CFLAGS) $(DEFINES) $(INCFLAGS) $3 $(TARGET_ARCH) -M $$< | \
    $(SED) 's,\($$(notdir $$*)\.o\) *:,$$(dir $$@)\1 $$@: ,' > $$@.tmp
    $(MV) $$@.tmp $$@

endef

%.d: %.cpp
    $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M $< | \
    $(SED) 's,\($(notdir $*)\.o\) *:,$(dir $@)\1 $@: ,' > $@.tmp
    $(MV) $@.tmp $@

更新2:使用@ Beta的建议,我能够分辨出依赖关系生成,Makefile时间大约是整个编译时间的14.2%。所以我将首先关注最小化我的C ++代码中的头部包含。感谢你们两位的建议!!

3 个答案:

答案 0 :(得分:3)

  1. 确定哪些更改减慢了所有内容应该不是那么困难。你拥有过去三年的所有版本(我希望),你说差异是戏剧性的。所以试试两年前的版本。如果花费太长时间,请执行二进制搜索。您甚至可以自动执行此过程,让它在一夜之间运行并在早上为您提供图表,在过去的36个月中每个月建立一个时间段。
  2. 如果您正在使用GNUMake(我希望如此),`make -n`将打印出 执行的命令,而不实际执行它们。这将为您提供所有的Make时间,无需编译时间。
  3. 不必要的构建时间的最大来源之一(甚至比递归更大,你没有使用)是不必要的重建,重新编译/重新链接/当你不需要的时候。这可能是因为你的makefile没有正确处理依赖关系,或者因为你的C ++文件`#include`标题是鲁莽的,或者是一些我不知道的CUDA或FORTRAN。连续运行两次,并查看它是否在第二次传递中执行任何操作。查看makefile以查找可疑的巨大先决条件列表。让熟练的程序员看一些源文件,尤其是新文件,并检查不必要的依赖项。

答案 1 :(得分:3)

ElectricMake(emake)是gmake的直接替代品,可以很容易地回答这样的问题。 emake可以生成带注释的构建日志,其中包含有关构建中每个作业的详细时序信息,然后您可以将其加载到ElectricInsight中以生成例如按类型划分的作业时间报告:

Job Time by Type example

如果您想尝试一下,可以get an eval copy

(免责声明:我是ElectricMake和ElectricInsight的架构师和首席开发人员!)

答案 2 :(得分:1)

我真的怀疑make的变量赋值(立即使用:=或recursive =)会对速度产生重大影响。一个特别明显的情况是它产生严重影响的是shell命令:

VAR := $(shell ...)

可能还有其他隐藏的消费过程并不明显。例如,在我们的环境中,标准临时Windows目录位于网络驱动器上。因此,当在该驱动器上存储/更新文件时(即使使用1G LAN) - 它非常慢。你需要的是调试makefile。 This maybe helpful

根据上面提到的文档,您可以以 $(警告去做bla-bla-bla)的形式放置调试打印,然后观察进程最终冻结的位置。