My question is similar to this one and this one.
In essence, something like the following is what I'm looking for -- or a fairly clean hack for pulling it off:
GET_TIMESTAMP = $(shell perl -e 'print time()')
START_TIME := ${GET_TIMESTAMP}
all: T1 T2 ... TN
T1:
T2:
...:
TN:
#...
timer:
@perl -e 'printf( "Loaded makefiles in %ds, build completed in %ds\n", $ARGV[1] - $ARGV[0], $ARGV[2] - $ARGV[1] );' ${START_TIME} ${LOAD_COMPLETE} ${GET_TIMESTAMP}
.ATEND: timer
LOAD_COMPLETE := ${GET_TIMESTAMP}
... which could be kicked off in a number of ways:
~ gmake all
(...)
Loaded makefiles in 8s, build completed in 93s
~ gmake T2 T3 T4
(...)
Loaded makefiles in 8s, build completed in 13s
At the heart of it is this idea of an .ATEND
special target that causes something to happen when all CMDGOALS
or DEFAULTGOALS
are finished.
If you just want to time your build, and you're running on a UNIXy platform, why not just use time
itself?
As in:
pax$ time sleep 1
real 0m1.004s
user 0m0.000s
sys 0m0.000s
(although, in your case, it would of course be time gmake all
).
This seems a much more elegant solution than trying to code something up in make
and uses the right tools for the job.
Alternatively, you could modify the rule itself to be something like:
all: T1 T2 ... TN
@perl -e blah blah blah
This will ensure the Perl is executed once all targets are complete - you'll have to fiddle with the makefile
so it's not an automatic solution (you'll be best off limiting yourself to certain high-level targets), but I don't think that's a huge burden since makefiles tend to be relatively changeless once set up correctly.
Well I have been wondering the same for a while, and tried a few things. I guess a recursive make might do it, but I avoid those so far. Pity there isn't a .ATEND indeed!
Note: Obviously you will only show how long re-made recipes take, unless from a clean.
So as paxdiablo suggested unix time commmand is the easiest (and what I have done in the past).
% time make
Adding a timer to each recipe will give you a cumulative run time, but not an idea of how long each recipe took (not that it was in the question). However for specific recipes you could make use of time again within the recipe and even tee the output to a logfile (using pipefail in bash). eg
# SHELL = /bin/bash -o pipefail
# @bash -o pipefail -c ' ( time /home/matt/bin/example_stdouterr.bash ) |& tee z.log'
# @bash -o pipefail -c ' ( time /home/matt/bin/example_stdouterr.bash ) 2>&1 | tee z.log '
So I think just adding it to most of the recipes would be the best. You don't need a special call then. See below for an example, which should show differences with:
time -p make
time -p make -j 2
Gives cumulative time, as well as timestamp.
TIME_START := $(shell date +%s)
define TIME-END
@time_end=`date +%s` ; time_exec=`awk -v "TS=${TIME_START}" -v "TE=$$time_end" 'BEGIN{TD=TE-TS;printf "%02dd:%02dh:%02dm:%02ds\n",TD/(60*60*24),TD/(60*60)%24,TD/(60)%60,TD%60}'` ; echo "##DATE end `date '+%Y-%m-%d %H:%M:%S %Z'` cumulative $${time_exec} $@"
endef
PHONY_GOALS := all
all: toprule1
$(TIME-END)
PHONY_GOALS += toprule1
toprule1: subrule1 subrule2
@echo toprule 1 start
@sleep 1
@echo toprule 1 done
$(TIME-END)
PHONY_GOALS += subrule1
subrule1: botrule1
@echo subrule 1 start
@sleep 1
@echo subrule 1 done
$(TIME-END)
PHONY_GOALS += subrule2
subrule2: botrule1
@echo subrule 2 start
@time -p sleep 2
@echo subrule 2 done
$(TIME-END)
PHONY_GOALS += botrule1
botrule1:
@echo botrule 1 start
@sleep 1
@echo "botrule 1 done"
$(TIME-END)
PHONY_GOALS += help
help:
@echo "$(info All the goals are: ${PHONY_GOALS})"
########### end bit
.PHONY :${PHONY_GOALS}
OTHER_GOALS := ${filter-out ${PHONY_GOALS}, ${MAKECMDGOALS}}
${OTHER_GOALS}:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With