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 3     3   59784 use strict;
  3         7  
  3         111  
2             package Devel::Timer;
3             $Devel::Timer::VERSION = '0.13';
4 3     3   12 use warnings;
  3         7  
  3         77  
5 3     3   46 use 5.006;
  3         8  
6              
7 3     3   871 use Time::HiRes();
  3         2337  
  3         2315  
8              
9             ## no critic (ProhibitAccessOfPrivateData )
10              
11             ##
12             ## instantiate (and initialize) timer object
13             ##
14              
15             sub new {
16 5     5 1 67879 my ($class) = @_;
17 5         21 my $self = {
18             times => [],
19             count => 0,
20             label => {}, ## index:label
21             };
22              
23 5         11 bless $self, $class;
24              
25 5         25 $self->initialize();
26              
27 5         18 $self->mark('INIT');
28              
29 5         10 return $self;
30             }
31              
32             ##
33             ## mark time (w/ optional label)
34             ##
35              
36             sub mark {
37 36     36 1 4217178 my($self, $label) = @_;
38              
39 36 50       129 $label = '' if (!defined($label));
40              
41 36         167 my $t = [ Time::HiRes::gettimeofday() ];
42              
43 36         53 my $last_time;
44 36 100       107 if ($self->{count} == 0) { ## first time has no last time
45 5         8 $last_time = $t;
46             }
47             else {
48 31         607 $last_time = $self->{times}->[($self->{count}-1)];
49             }
50              
51             ## save time for final report
52              
53 36         48 push(@{$self->{times}}, $t);
  36         71  
54              
55             ## save time interval
56              
57             my $interval = {
58             value => Time::HiRes::tv_interval($last_time, $t),
59             index => $self->{count},
60 36         124 };
61 36         559 push(@{$self->{intervals}}, $interval);
  36         77  
62              
63             ## save label in separate hash for fast lookup
64              
65 36         134 $self->{label}->{$self->{count}} = $label;
66              
67 36         96 $self->{count}++;
68             }
69              
70              
71             ##
72             ## output report to error log
73             ##
74              
75             sub report {
76 4     4 1 39 my ($self, %args) = @_;
77              
78             ## calculate total time (start time vs last time)
79              
80 4         26 my $total_time = Time::HiRes::tv_interval($self->{times}->[0], $self->{times}->[$self->{count}-1]);
81              
82 4         64 $self->print("\n");
83 4         71 $self->print(ref($self) . ' Report -- Total time: ' . sprintf('%.4f', $total_time) . ' secs');
84 4 100       20 if ($args{collapse}) {
85 2         11 $self->_calculate_collapsed;
86              
87 2         7 $self->print('Count Time Percent');
88 2         9 $self->print('----------------------------------------------');
89              
90 2         6 my $c = $self->{collapsed};
91 2   100     12 my $sort_by = $args{sort_by} || 'time';
92 2         17 my @labels = sort { $c->{$b}->{$sort_by} <=> $c->{$a}->{$sort_by} } keys %$c;
  9         22  
93 2         7 foreach my $label (@labels) {
94 8         17 my $count = $c->{$label}->{count};
95 8         11 my $time = $c->{$label}->{time};
96 8         52 my $msg = sprintf('%8s %.4f %5.2f%% %s',
97             ($count, $time, (($time/$total_time)*100), $label));
98 8         19 $self->print($msg);
99             }
100 2         14 return 1;
101             }
102              
103              
104 2         6 $self->print('Interval Time Percent');
105 2         7 $self->print('----------------------------------------------');
106              
107             ## sort interval structure based on value
108              
109 2         3 @{$self->{intervals}} = sort { $b->{value} <=> $a->{value} } @{$self->{intervals}};
  2         13  
  21         30  
  2         11  
110              
111             ##
112             ## report of each time space between marks
113             ##
114              
115 2         4 for my $i (@{$self->{intervals}})
  2         5  
116             {
117             ## skip first time (to make an interval,
118             ## compare the current time with the previous one)
119              
120 12 100       33 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         85 $self->{label}->{($i->{index}-1)}, $self->{label}->{$i->{index}});
125              
126 10         23 $self->print($msg);
127             }
128             }
129              
130             sub _calculate_collapsed {
131 6     6   18 my ($self) = @_;
132              
133 6         10 my %collapsed;
134 6         22 foreach my $i (0 .. $self->{count} - 2) {
135 42         100 my $label = $self->{label}->{$i} . ' -> ' . $self->{label}->{$i + 1};
136 42         87 my $time = Time::HiRes::tv_interval($self->{times}->[$i], $self->{times}->[$i + 1]);
137 42         382 $collapsed{$label}{time} += $time;
138 42         79 $collapsed{$label}{count}++;
139             }
140 6         20 $self->{collapsed} = \%collapsed;
141             }
142              
143             sub get_stats {
144 4     4 1 12521 my ($self, $a, $b) = @_;
145 4         13 $self->_calculate_collapsed;
146 4         7 my $collapsed = $self->{collapsed};
147 4         11 my $total_time = Time::HiRes::tv_interval($self->{times}->[0], $self->{times}->[$self->{count}-1]);
148 4         37 my $label = "$a -> $b";
149 4         7 my $time = $collapsed->{$label}->{time};
150 4         8 my $count = $collapsed->{$label}->{count};
151 4         20 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 43 my($self, $msg) = @_;
168 27         382 print STDERR $msg . "\n";
169             }
170              
171       4 1   sub shutdown {
172             }
173              
174             sub DESTROY {
175 5     5   15605 my $self = shift;
176 5         23 $self->shutdown();
177             }
178              
179             1;
180              
181             __END__