NAME

Time::Profiler provides scope-automatic or manual code time measurement.

SYNOPSIS

#!/usr/bin/perl
use strict;
use Time::Profiler;

my $pr = new Time::Profiler; # create new profiler instance

print "begin main\n";
# begin main:: scope measuring with automatic names
my $_ps = $pr->begin_scope(); 

t1();
t2();
sleep( 2 );

# main:: scope will not end before reporting so must be stopped manually
$_ps->stop(); 

# print profiler stats
print $pr->report(); 

sub t1
{   
  print "begin t1\n";
  # begin t1 function scope time measuring
  my $_ps = $pr->begin_scope();

  t2();
  sleep( 3 );
  t2();
  # t1 function scope ends here so timing will end automatically
}

sub t2
{
  print "begin t2\n";
  # begin t2 function scope time measuring
  my $_ps = $pr->begin_scope();

  sleep( 1 );
  # t2 function scope ends here so timing will end automatically
}

DESCRIPTION

Time::Profiler is designed to be called inside scopes (or functions) which are needed to be measured. It provides automatic, manual or cumulative scope names.

OUTPUT

The example in the SYNOPSIS will print this output:

begin main
begin t1
begin t2
begin t2
begin t2

SINGLE PROFILE SCOPES
    1 time  =      8.001 sec. main::
    1 time  =      5.000 sec. main::t1
    3 times =      3.000 sec. main::t2

TREE PROFILE SCOPES
    1 time  =      8.001 sec. main::
    1 time  =      5.000 sec. |    main::t1
    2 times =      2.000 sec. |    |    main::t2
    1 time  =      1.000 sec. |    main::t2

AUTOMATIC SCOPE NAMES

Time::Profiler will traverse the stack and will construct automatic name if scope name is left empty or '*':

t1();
t2();

print $pr->report();

sub t1
{
  my $_ps = $pr->begin_scope(); # same as below
  t2();
  sleep( 3 );
}

sub t2
{
  my $_ps = $pr->begin_scope( '*' ); # same as above
  sleep( 2 );
}

Output will be:

SINGLE PROFILE SCOPES
    1 time  =      5.000 sec. main::t1
    2 times =      4.000 sec. main::t2

TREE PROFILE SCOPES
                              main::
    1 time  =      5.000 sec. |    main::t1
    1 time  =      2.000 sec. |    |    main::t2
    1 time  =      2.000 sec. |    main::t2

MANUAL SCOPE NAMES

Manual names can force fixed scope names:

my $_ps = $pr->begin_scope( 'ROOT' );

t1();
t2();

$_ps->stop;
print $pr->report();

sub t1
{
  # T1 here
  t2();
  sleep( 3 );
}

sub t2
{
  my $_ps = $pr->begin_scope( 'ROOT/T1/T2' );
  sleep( 2 );
}

This will force main:: scope name to be 'ROOT' and only nested t2() name 'ROOT/T1/T2'. Output will be:

SINGLE PROFILE SCOPES
    1 time  =      5.000 sec. ROOT
    1 time  =      2.000 sec. T2

TREE PROFILE SCOPES
    1 time  =      5.000 sec. ROOT
                              |    T1
    1 time  =      2.000 sec. |    |    T2

So t1() has no profile stats but t2() scope name (path) is measured inside the 'ROOT' scope.

CUMULATIVE SCOPE NAMES

Cumulative names begin with '+' and allow measurement aggregation for same type functions. For example database module may have read_data() and write_data() function, which read or write data from/to different tables:

sub read_data
{
  my $table_name = shift;
  my $_ps = $pr->begin_scope( "+DB/READ_DATA/$table_name" );
  ...
}

sub write_data
{
  my $table_name = shift;
  my $_ps = $pr->begin_scope( "+DB/WRITE_DATA/$table_name" );
  ...
}

Possible output:

SINGLE PROFILE SCOPES
    1 time  =     14.000 sec. DB
    1 time  =      8.000 sec. DB/READ_DATA
    1 time  =      6.000 sec. DB/WRITE_DATA
    2 time  =      4.000 sec. DB/READ_DATA/CLIENTS
    2 time  =      4.000 sec. DB/READ_DATA/ADDRESSES
    1 time  =      3.000 sec. DB/WRITE_DATA/CLIENTS
    1 time  =      3.000 sec. DB/WRITE_DATA/ADDRESSES

This will measure several things:

all calls to read_data() and write_data() regardless $table_name (DB)
all calls to read_data() regardless $table_name (DB/READ_DATA)
all calls to write_data() regardless $table_name (DB/WRITE_DATA)
all calls to read_data() for specific $table_name (DB/READ_DATA/$table_name)
all calls to write_data() for specific $table_name (DB/WRITE_DATA/$table_name)

This is almost complete set of possible measurements. The only missing case is measuring of all DB access for specific table (DB/*/$table_name). To achieve this MIXED names must be used (see below):

sub read_data
{
  my $table_name = shift;
  my $_ps = $pr->begin_scope( "+DB/READ_DATA/$table_name", "+DB_$table_name" );
  ...
}

Possible output:

SINGLE PROFILE SCOPES
    1 time  =     14.000 sec. DB
    1 time  =      8.000 sec. DB/READ_DATA
    3 time  =      7.000 sec. DB_CLIENTS
    3 time  =      7.000 sec. DB_ADDRESSES
    1 time  =      6.000 sec. DB/WRITE_DATA
    2 time  =      4.000 sec. DB/READ_DATA/CLIENTS
    2 time  =      4.000 sec. DB/READ_DATA/ADDRESSES
    1 time  =      3.000 sec. DB/WRITE_DATA/CLIENTS
    1 time  =      3.000 sec. DB/WRITE_DATA/ADDRESSES

MIXED NAMES

Scopes may have multiple names including mixed types names:

sub read_data
{
  my $table_name = shift;
  my $_ps = $pr->begin_scope( "*", "+TT/T2", "ALL_FUNCS" );
  ...
}

This will produce automatic scope name ("*"), cumulative ("+DB/READ_DATA/$table_name") and manual static one ("ALL_FUNCS").

In this case stats will be mixed in the same profiler output:

SINGLE PROFILE SCOPES
    1 time  =      5.000 sec. ROOT
    1 time  =      2.000 sec. main::t2
    1 time  =      2.000 sec. TT/
    1 time  =      2.000 sec. ALL_FUNCS
    1 time  =      2.000 sec. TT/T2/

TREE PROFILE SCOPES
    1 time  =      5.000 sec. ROOT
    1 time  =      2.000 sec. TT
    1 time  =      2.000 sec. |    T2
    1 time  =      2.000 sec. ALL_FUNCS
                              main::
                              |    main::t1
    1 time  =      2.000 sec. |    |    main::t2

PITFALLS

Avoid cumulative names for recursive or nested functions, otherwise some stats may seem wrong:

t1();
t2();

print $pr->report();

sub t1
{
  my $_ps = $pr->begin_scope( '+ALL_FUNCS/T1' );
  
  t2();
  sleep( 3 );
}

sub t2
{
  my $_ps = $pr->begin_scope( '+ALL_FUNCS/T2' );
  sleep( 2 );
}

Output will be:

SINGLE PROFILE SCOPES
    3 times =      9.000 sec. ALL_FUNCS/
    1 time  =      5.000 sec. ALL_FUNCS/T1/
    2 times =      4.000 sec. ALL_FUNCS/T2/

TREE PROFILE SCOPES
    3 times =      9.000 sec. ALL_FUNCS
    1 time  =      5.000 sec. |    T1
    2 times =      4.000 sec. |    T2

Total program execution time is actually 7 sec. but we see that ALL_FUNCS says 9 sec. This is because t2() time is measured twice: once as separate function call and second time as nested function.

GITHUB REPOSITORY

https://github.com/cade-vs/perl-time-profiler

git clone git://github.com/cade-vs/perl-time-profiler.git

AUTHOR

Vladi Belperchinov-Shabanski "Cade"

<cade@biscom.net> <cade@datamax.bg> <cade@cpan.org>

http://cade.datamax.bg