如何定时执行gnu make规则?

时间:2016-01-21 22:26:44

标签: makefile profiling timing

我想计算一个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

4 个答案:

答案 0 :(得分:2)

请尝试以下示例,

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

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

答案 1 :(得分:2)

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

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

您的尝试不起作用的原因是make会在开始第一行之前评估配方所有行。因此,在配方的任何部分开始之前,整个配方中的所有make变量和函数(如evalshell等)都是预先扩展的。因此,多次运行date命令的结果将始终相同。

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

答案 2 :(得分:1)

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

原理上,make命令的输出通过管道

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

所有在make调用中发出的所有输出行都加上了一个时间戳记行,从而可以查看用于各个配方及其元素/项目的时间。

一个例子说明了这一点。假设这个简单的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 epoc纳秒产生的时间戳,如本答案所示 提供一种简单的方法来快速检查输出的时间长度,并 从而获得表彰。

注意。通过-j命令行参数使用多个make作业时,时间戳仅反映-Onone的时间,即不使用输出同步。

答案 3 :(得分:0)

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

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