如何计时执行GNU Make规则?

3

我希望能够计时一个make规则的执行时间,但是在获取有效的开始和结束时间以及进行简单的算术(减法)方面遇到了困难。

$ make money
sleep 2
echo "money: 1453412887" > logfile
echo "money: 1453412887" >> logfile
echo "money: 1453412887" >> logfile

Makefile 中:
money:
        $(eval start := $(shell date +%s))
        sleep 2
        $(eval end := $(shell date +%s))
        echo "$@: ${start}" > logfile
        echo "$@: ${end}" >> logfile
        echo "$@: $(shell date +%s)" >> logfile
6个回答

3
请尝试以下示例:
test:
        @start=$$(date +%s); \
        echo $@: $$start > test.log
        @sleep 2
        @end=$$(date +%s); \
        echo $@: $$end >> test.log

其中一个关键点是,shell变量赋值应该与echo命令在同一行。


3

如果您只想跟踪一个目标的时间,那么Eric的答案很好。尽管如此,没有理由设置单独的变量;只需输出命令的输出即可更简单。此外,如果您在shell命令中使用旧式反引号而不是较新的$(...)格式,则在makefile配方中阅读可能更容易:

test:
        echo $@: `date +%s` > test.log
        @sleep 2
        echo $@: `date +%s` >> test.log

你的尝试失败的原因是make会在开始执行第一行之前评估整个配方中的所有行。因此,整个配方中的make变量和函数(例如eval,shell等)都是提前扩展的,在任何部分的配方开始之前。因此,多次运行date命令的结果始终相同。
如果你想计时所有命令,又不想改变所有配方以保留日志,另一个选择是编写一个特殊的脚本或程序,它将接收命令行作为参数,然后在带时间的shell中运行该命令。然后将make SHELL变量设置为使用该脚本/程序而不是真实的shell。如果你有复杂的配方,要使其正常运行需要做一些棘手的工作(必须保留所有引号等)。最简单的方法是编写一个小的C程序并使用fork/exec:没有引号问题。但这是最可靠且最不侵入性的方法。

2

这是我用来计时 makefile 构建项 (recipes,它们各自的项甚至包括项的输出) 所使用的解决方案。

make 命令的输出被导入到这个命令中。

while read line; do date +'%s%N'; echo "$line"; done`

这段内容与编程有关。它在所有输出行之前添加一个时间戳行,以便查看各个配方及其元素/项目所使用的时间。

以下是一个例子。假设这是我们的简单 Makefile:

如果这是我们的 Makefile:

all: part1 part2
    cat part1 part2 > all

part1: 
    sleep 1
    echo "part1 content" > part1

part2: 
    sleep 2
    echo "part2 content" > part2

然后运行它会产生以下输出:

$> make | while read line; do date +'%s%N'; echo "$line"; done
1561566560276946890
sleep 1
1561566561280995480
echo "part1 content" > part1
1561566561290389273
sleep 2
1561566563292382045
echo "part2 content" > part2
1561566563298681800
cat part1 part2 > all

这不足为奇地显示了part1食谱步骤sleep 1的规则花费了1561566561280995480 - 1561566560276946890 = 1 004 048 640纳秒,这相当于预期的1秒持续时间。

所产生的Unix纪元纳秒时间戳,正如本答案建议的那样,提供了一种快速检查输出时间和命令运行时间的简单方法。

注意。当使用-j命令行参数进行多个make作业时,时间戳只能反映在没有输出同步的情况下使用-Onone的时间。


1

以下是不必修改Makefile而实现的方法。 基本上,您可以使用自己设计的shell脚本替换make通常用于执行命令的shell (/bin/sh)。 一个一行命令就可以了。类似这样:

$ cat ~/TIMING
#!/bin/bash
command time -ao ~/LOG -f "%E [$*]" bash "$@"
  • command 是因为我们想使用 /bin/time (YMMV)而不是bash 内置的 time
  • -ao 将消息附加到日志文件中。我们使用绝对路径,以便更改文件夹的子 make 仍然记录到该文件。
  • -f 指定时间格式:我选择了经过的时间后跟随 make 给 shell 的参数。
  • "$@" 展开为 make 传递给 shell 的参数。 make 使用的第一个参数应该是 -c,这会导致 bash 执行以下参数作为命令。
  • 退出代码是 make 请求执行的命令的退出代码。

测试

$ cat Makefile
.PHONY: atest
atest:
    sleep 1.5
    echo testing non-zero exit code
    exit 22
    echo done

然后是正常运行:

$ make
sleep 1.5
echo testing non-zero exit code
testing non-zero exit code
exit 22
make: *** [atest] Error 22

然后是定时运行。它看起来完全一样:
$ rm -f ~/LOG
$ chmod a+x ~/TIMING
$ make SHELL=~/TIMING
sleep 1.5
echo testing non-zero exit code
testing non-zero exit code
exit 22
make: *** [atest] Error 22

但是这次我们有一个很好的日志文件:

$ cat ~/LOG
0:01.50 [-c sleep 1.5]
0:00.00 [-c echo testing non-zero exit code]
0:00.00 [-c exit 22]

很好。并行安全也可以。您的 makefile 也是并行安全的,对吗?

1

我认为你可以使用time命令。 在我的例子中,我想获得第一个目标的时间

time make

1

如果您不想烦恼于makefile,可以使用moreutils中的ts

{ make money; echo done; } |
 ts -s '%.s'

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