如何计时 gnu make 规则的执行时间?

How to time the execution of a gnu make rule?

我想为 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

请尝试以下示例,

test:
        @start=$$(date +%s); \
        echo $@: $$start > test.log
        @sleep 2
        @end=$$(date +%s); \
        echo $@: $$end >> test.log

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

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

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

您的尝试无效的原因是 make 会在开始第一行 之前评估食谱的 所有行 。因此,整个配方中的所有 make 变量和函数,如 evalshell 等,都在配方的任何部分开始之前展开 up-front。因此,运行多次执行 date 命令的结果将始终相同。

如果您尝试为所有命令计时并且不想更改所有食谱以保留日志,另一种选择是编写一个特殊的脚本或程序,将命令行作为参数,然后 运行 该命令在 shell 中计时。然后设置 make SHELL 变量以使用那个 script/program 而不是真正的 shell。如果你有复杂的食谱(你必须保留所有引用等),让它正常工作会有点棘手。实际编写一个小 C 程序并使用 fork/exec 是最简单的:那里没有引用问题。但是,这是最可靠和侵入性最小的方法。

这是我用来计时 makefile 构建项(配方及其各自的项,甚至项的输出)的执行时间的解决方案。

make 命令的输出通过管道传输到此

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

它在 make 调用发出的所有输出行前添加了一个时间戳行,允许查看用于各个配方的时间及其 elements/items。

一个例子说明了这一点。假设这个简单的 Makefile

如果这是我们的 Makefile

all: part1 part2
    cat part1 part2 > all

part1: 
    sleep 1
    echo "part1 content" > part1

part2: 
    sleep 2
    echo "part2 content" > part2

然后 运行ning 它导致这个输出:

$> 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 epoc 纳秒时间戳,如本答案中所建议 提供一种简单的方法来快速检查输出的持续时间和 因此表扬 运行.

警告。当通过 -j 命令行参数使用多个 make 作业时,如果 -Onone,时间戳只能反映时间,即不使用输出同步。

这里是如何做到这一点而无需在 makefile 中乱涂乱画。 基本上, 您将 make 通常用于执行命令 (/bin/sh) 的 shell 替换为您自己设计的 shell 脚本。 一条线就可以了。类似于:

$ cat ~/TIMING
#!/bin/bash
command time -ao ~/LOG -f "%E [$*]" bash "$@"
  • command 因为我们想使用 /bin/time (YMMV) 而不是 bash 内置 time.
  • -ao 将消息附加到日志文件。我们使用绝对路径,以便子使更改文件夹继续记录到文件。
  • -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 是并行安全的,对吧?