makefileprofilingtiming

How to time the execution of a gnu make rule?


I want to time the execution of a make rule, but am having trouble getting valid start and stop times as well as getting the simple arithmetic (subtraction) to work.

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

In 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

Solution

  • Eric's answer is a good one, if you're looking to just track the time for one target. Although, there's no reason to set a separate variable; it's simpler to just echo the output of the command. Also if you use old-school backquotes instead of the newer $(...) format for shell commands it may be easier to read in a makefile recipe:

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

    The reason your attempt doesn't work is that make will evaluate all lines of the recipe before it starts the first line. So, all the make variables and functions like eval, shell, etc. in the entire recipe are all expanded up-front, before any part of the recipe starts. So the results of running the date command multiple times will always be identical.

    If you're trying to time all of your commands and you don't want to change all the recipes to keep a log, another option is to write a special script or program that will take a command line as arguments, then run that command in a shell with timing. Then set the make SHELL variable to use that script/program instead of the real shell. Getting this to work right will be a little tricky, if you have complex recipes (you have to preserve all the quoting etc.) It's easiest to actually write a little C program and use fork/exec: no quoting issues there. But, this is the most reliable and least invasive way do to it.