File Coverage

blib/lib/Devel/Timer.pm
Criterion Covered Total %
statement 80 80 100.0
branch 7 8 87.5
condition 2 2 100.0
subroutine 13 13 100.0
pod 7 7 100.0
total 109 110 99.0


line stmt bran cond sub pod time code
1             package Devel::Timer;
2             $Devel::Timer::VERSION = '0.12';
3 3     3   14416 use strict;
  3         3  
  3         67  
4 3     3   8 use warnings;
  3         3  
  3         54  
5 3     3   43 use 5.006;
  3         7  
6              
7 3     3   923 use Time::HiRes();
  3         1959  
  3         1943  
8              
9             ## no critic (ProhibitAccessOfPrivateData )
10              
11             ##
12             ## instantiate (and initialize) timer object
13             ##
14              
15             sub new {
16 5     5 1 20369 my ($class) = @_;
17 5         18 my $self = {
18             times => [],
19             count => 0,
20             label => {}, ## index:label
21             };
22              
23 5         9 bless $self, $class;
24              
25 5         14 $self->initialize();
26              
27 5         11 $self->mark('INIT');
28              
29 5         9 return $self;
30             }
31              
32             ##
33             ## mark time (w/ optional label)
34             ##
35              
36             sub mark {
37 36     36 1 4206216 my($self, $label) = @_;
38              
39 36 50       118 $label = '' if (!defined($label));
40              
41 36         185 my $t = [ Time::HiRes::gettimeofday() ];
42              
43 36         47 my $last_time;
44 36 100       104 if ($self->{count} == 0) { ## first time has no last time
45 5         6 $last_time = $t;
46             }
47             else {
48 31         86 $last_time = $self->{times}->[($self->{count}-1)];
49             }
50              
51             ## save time for final report
52              
53 36         31 push(@{$self->{times}}, $t);
  36         141  
54              
55             ## save time interval
56              
57             my $interval = {
58             value => Time::HiRes::tv_interval($last_time, $t),
59             index => $self->{count},
60 36         115 };
61 36         428 push(@{$self->{intervals}}, $interval);
  36         59  
62              
63             ## save label in separate hash for fast lookup
64              
65 36         100 $self->{label}->{$self->{count}} = $label;
66              
67 36         94 $self->{count}++;
68             }
69              
70              
71             ##
72             ## output report to error log
73             ##
74              
75             sub report {
76 4     4 1 48 my ($self, %args) = @_;
77              
78             ## calculate total time (start time vs last time)
79              
80 4         17 my $total_time = Time::HiRes::tv_interval($self->{times}->[0], $self->{times}->[$self->{count}-1]);
81              
82 4         38 $self->print("\n");
83 4         113 $self->print(ref($self) . ' Report -- Total time: ' . sprintf('%.4f', $total_time) . ' secs');
84 4 100       23 if ($args{collapse}) {
85 2         9 $self->_calculate_collapsed;
86              
87 2         6 $self->print('Count Time Percent');
88 2         4 $self->print('----------------------------------------------');
89              
90 2         4 my $c = $self->{collapsed};
91 2   100     15 my $sort_by = $args{sort_by} || 'time';
92 2         23 my @labels = sort { $c->{$b}->{$sort_by} <=> $c->{$a}->{$sort_by} } keys %$c;
  10         22  
93 2         5 foreach my $label (@labels) {
94 8         9 my $count = $c->{$label}->{count};
95 8         7 my $time = $c->{$label}->{time};
96 8         53 my $msg = sprintf('%8s %.4f %5.2f%% %s',
97             ($count, $time, (($time/$total_time)*100), $label));
98 8         9 $self->print($msg);
99             }
100 2         17 return 1;
101             }
102              
103              
104 2         6 $self->print('Interval Time Percent');
105 2         4 $self->print('----------------------------------------------');
106              
107             ## sort interval structure based on value
108              
109 2         3 @{$self->{intervals}} = sort { $b->{value} <=> $a->{value} } @{$self->{intervals}};
  2         6  
  21         25  
  2         11  
110              
111             ##
112             ## report of each time space between marks
113             ##
114              
115 2         2 for my $i (@{$self->{intervals}})
  2         6  
116             {
117             ## skip first time (to make an interval,
118             ## compare the current time with the previous one)
119              
120 12 100       34 next if ($i->{index} == 0);
121              
122             my $msg = sprintf('%02d -> %02d %.4f %5.2f%% %s -> %s',
123             ($i->{index}-1), $i->{index}, $i->{value}, (($i->{value}/$total_time)*100),
124 10         79 $self->{label}->{($i->{index}-1)}, $self->{label}->{$i->{index}});
125              
126 10         14 $self->print($msg);
127             }
128             }
129              
130             sub _calculate_collapsed {
131 6     6   10 my ($self) = @_;
132              
133 6         32 my %collapsed;
134 6         25 foreach my $i (0 .. $self->{count} - 2) {
135 42         80 my $label = $self->{label}->{$i} . ' -> ' . $self->{label}->{$i + 1};
136 42         77 my $time = Time::HiRes::tv_interval($self->{times}->[$i], $self->{times}->[$i + 1]);
137 42         236 $collapsed{$label}{time} += $time;
138 42         56 $collapsed{$label}{count}++;
139             }
140 6         43 $self->{collapsed} = \%collapsed;
141             }
142              
143             sub get_stats {
144 4     4 1 742 my ($self, $a, $b) = @_;
145 4         11 $self->_calculate_collapsed;
146 4         9 my $collapsed = $self->{collapsed};
147 4         9 my $total_time = Time::HiRes::tv_interval($self->{times}->[0], $self->{times}->[$self->{count}-1]);
148 4         20 my $label = "$a -> $b";
149 4         4 my $time = $collapsed->{$label}->{time};
150 4         4 my $count = $collapsed->{$label}->{count};
151 4         21 return ($time, $time / $total_time * 100, $count);
152             }
153              
154              
155              
156             ## output methods
157             ## note: if you want to send output to somewhere other than stderr,
158             ## you can override the print() method below. The initialize()
159             ## and shutdown() methods are provided in case you need to open a file
160             ## or connect to a database before printing the report.
161             ## See pod for an example.
162              
163       4 1   sub initialize {
164             }
165              
166             sub print {
167 27     27 1 25 my($self, $msg) = @_;
168 27         82802 print STDERR $msg . "\n";
169             }
170              
171       4 1   sub shutdown {
172             }
173              
174             sub DESTROY {
175 5     5   2257 my $self = shift;
176 5         15 $self->shutdown();
177             }
178              
179             1;
180              
181             __END__