NAME
Timer::Milestones - measure code execution time succinctly by setting milestones
VERSION
This is version 0.001.
SYNOPSIS
use Timer::Milestones qw(start_timing mark_milestone stop_timing
time_method);
start_timing();
time_method('Some::ThirdParty::Module::do_slow_thing');
my @objects = _set_up_objects();
mark_milestone('Everything set up');
for my $object (@objects) {
_do_something_potentially_slow($object);
}
mark_milestone('Telling the user')
for my $object (@objects) {
_inform_user($object);
}
...
stop_timing();
Spits out to STDERR e.g.
START: Tue Feb 4 16:03:08 2020
3 s ( 0.28%)
Everything set up
5 min 30 s ( 31.22%)
3 min 7 s Some::ThirdParty::Module::do_slow_thing
Telling the user
12 min 7 s ( 68.78%)
8 min 30 s Some::ThirdParty::Module::do_slow_thing (x3)
END: Tue Feb 4 16:20:48 2020
DESCRIPTION
At its simplest, Timer::Milestones is yet another timer module. It is designed to have the smallest possible interface, so adding timing calls to your code doesn't make it look unreadable. It can also time execution time of functions in other modules, as a more informative (and quicker!) alternative to running everything under Devel::NYTProf.
Functional vs OO interface
You can use Timer::Milestones via a functional interface:
use Timer::Milestones qw(start_timing mark_milestone stop_timing);
start_timing();
...;
mark_milestone('Half-way through');
...;
stop_timing();
Or via an OO interface:
use Timer::Milestones;
{
my $timer = Timer::Milestones->new;
# $timer->start_timing automatically called
...;
$timer->mark_milestone('Half-way through');
...;
}
# $timer->stop_timing automatically called when $timer is destroyed
The OO interface is simpler if you're timing a monolithic block of code. If you need to add timing calls throughout code scattered across multiple files, you're better off with the functional interface as you don't need to pass a Timer::Milestone object around.
Milestones and reports
At its simplest, the report you get will include when timing started and when timing ended. These are displayed in your locale's local time, on the assumption that that's what makes sense to you.
As soon as you add milestones, you will also be told how much time passed between the start, each milestone, and the end. Times are specified in both human-friendly periods (a number of milliseconds; seconds; minutes and seconds; or hours and minutes), and percentages of the total elapsed time.
If you decide that you want to time individual functions as well, they'll be mentioned with the milestones they follow. If you provide a coderef to summarise the arguments passed to them that will be included; if you decide that you don't need to see individual timings for each function call, just an overall time, you'll get a shorter list of function calls and an overall time.
Basic functionality
new
Out: $timer
Creates a new Timer::Milestones object, and calls "start_timing" on it.
start_timing
If timing hadn't already been started, starts timing. Otherwise does nothing. Automatically called by "new", but you'll need to call it explicitly when using the functional interface.
add_milestone
In: $name (optional)
Adds another milestone. If supplied with a name, uses that name for the milestone; otherwise, generates a name from the place it was called from (package, function, line number).
Throws an exception if a timing report has already been generated by "generate_report".
generate_intermediate_report
Out: $report
Returns a report on the milestones that have elapsed so far, or undef if a report has previously been generated and no new milestones have been reached since then.
generate_final_report
Out: $report
Stops timing, and returns a report for all of the milestones.
stop_timing
Stops timing, and spits out the result of "generate_intermediate_report" to STDERR. This is called automatically in OO mode when the object goes out of scope. This does nothing if you've already called "generate_final_report".
Timing other people's code
Adding calls to "mark_milestone" throughout your code is all very well, but sometimes you want to time a small handful of methods deep in someone else's code (or deep in your code - same difference). By carefully targeting only a few methods to time, you can avoid the pitfalls of profiling with Devel::NYTProf, where code that does zillions of fast method calls will appear to be much slower than it is when not profiling.
time_function
In: $function_name
In: %args (optional)
Supplied with a function name, e.g. DBIx::Class::Storage::DBI::_dbh_execute, and an optional hash of arguments, wraps it with a temporary shim that records the time spent inside this function. That shim is removed, and the original code restored, when timing stops. Details of the functions called are included between milestones in the resulting report.
Optional arguments are as follows:
- summarise_arguments
-
A coderef, which will be passed the arguments passed to the function, and which should return a scalar that will be included in the report.
- summarise_calls
-
If set to a true value, repeated calls to this function will be summarised rather than listed individually: the first time a function call is found, it will also mention all subsequent calls.
This can combine with
summarise_arguments: calls which result in an identical return value from that coderef will be combined.
SEE ALSO
Timer::Simple, which is simpler but more verbose.
Devel::Timer, which does some similar things.
Devel::NYTProf, which is probably worth using as a first pass, even if you don't necessarily trust its idea of what's actually slow.
AUTHOR
Sam Kington <skington@cpan.org>
The source code for this module is hosted on GitHub https://github.com/skington/timer-milestones - this is probably the best place to look for suggestions and feedback.
COPYRIGHT
Copyright (c) 2020 Sam Kington.
LICENSE
This library is free software and may be distributed under the same terms as perl itself.