File Coverage

blib/lib/Telemetry/Any.pm
Criterion Covered Total %
statement 124 132 93.9
branch 27 32 84.3
condition 6 10 60.0
subroutine 21 21 100.0
pod 1 7 14.2
total 179 202 88.6


line stmt bran cond sub pod time code
1             package Telemetry::Any;
2 2     2   2170 use 5.008001;
  2         7  
3 2     2   10 use strict;
  2         3  
  2         38  
4 2     2   10 use warnings;
  2         3  
  2         45  
5              
6 2     2   8 use Carp;
  2         4  
  2         125  
7              
8 2     2   12 use base 'Devel::Timer';
  2         4  
  2         956  
9              
10             our $VERSION = "0.07";
11              
12             my $telemetry = __PACKAGE__->new();
13              
14             sub import {
15 2     2   15 my ( $class, $var ) = @_;
16              
17 2 50       25 return if !defined $var;
18              
19 0         0 my $saw_var;
20 0 0       0 if ( $var =~ /^\$(\w+)/x ) {
21 0         0 $saw_var = $1;
22             }
23             else {
24 0         0 croak('Аrgument must be a variable');
25             }
26              
27 0         0 my $caller = caller();
28              
29 2     2   6060 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  2         5  
  2         3261  
30 0         0 my $varname = "${caller}::${saw_var}";
31 0         0 *$varname = \$telemetry;
32              
33 0         0 return;
34             }
35              
36             ## calculate total time (start time vs last time)
37             sub total_time {
38 50     50 0 95 my ($self) = @_;
39              
40 50         131 return Time::HiRes::tv_interval( $self->{times}->[0], $self->{times}->[ $self->{count} - 1 ] );
41             }
42              
43             sub report {
44 8     8 1 9528645 my ( $self, %args ) = @_;
45              
46 8         58 my $report = $self->_report_headers(%args);
47 8         48 $report .= $self->_report_data(%args);
48              
49 8         32 return $report;
50             }
51              
52             sub detailed {
53 3     3 0 9 my ( $self, %args ) = @_;
54              
55             ## sort interval structure based on value
56              
57 3         6 @{ $self->{intervals} } = sort { $b->{value} <=> $a->{value} } @{ $self->{intervals} };
  3         41  
  45         85  
  3         26  
58              
59             ##
60             ## report of each time space between marks
61             ##
62              
63 3         10 my @records;
64              
65 3         5 for my $i ( @{ $self->{intervals} } ) {
  3         12  
66             ## skip first time (to make an interval,
67             ## compare the current time with the previous one)
68              
69 23 100       56 next if ( $i->{index} == 0 );
70              
71             my $record = { ## no critic (NamingConventions::ProhibitAmbiguousNames
72             interval => $i->{index},
73             time => sprintf( '%.6f', $i->{value} ),
74             percent => sprintf( '%.2f', $i->{value} / $self->total_time() * 100 ),
75 20         114 label => sprintf( '%s -> %s', $self->{label}->{ $i->{index} - 1 }, $self->{label}->{ $i->{index} } ),
76             };
77              
78 20         354 push @records, $record;
79             }
80              
81 3         11 return @records;
82             }
83              
84             sub collapsed {
85 3     3 0 15 my ( $self, %args ) = @_;
86              
87 3         25 $self->_calculate_collapsed;
88              
89 3         399 my $c = $self->{collapsed};
90 3   100     23 my $sort_by = $args{sort_by} || 'time';
91              
92 3         32 my @labels = sort { $c->{$b}->{$sort_by} <=> $c->{$a}->{$sort_by} } keys %$c;
  13         42  
93              
94 3         8 my @records;
95              
96 3         9 foreach my $label (@labels) {
97              
98             my $record = { ## no critic (NamingConventions::ProhibitAmbiguousNames
99             count => $c->{$label}->{count},
100             time => sprintf( '%.6f', $c->{$label}->{time} ),
101 12         106 percent => sprintf( '%.2f', $c->{$label}->{time} / $self->total_time() * 100 ),
102             label => $label,
103             };
104              
105 12         200 push @records, $record;
106             }
107              
108 3         16 return @records;
109             }
110              
111             sub reset { ## no critic (Subroutines::ProhibitBuiltinHomonyms)
112 1     1 0 1057501 my ($self) = @_;
113              
114 1         5 %{$self} = (
  1         20  
115             times => [],
116             count => 0,
117             label => {},
118             );
119              
120 1         4 return $self;
121             }
122              
123             sub _report_headers {
124 8     8   31 my ( $self, %args ) = @_;
125              
126 8         18 my $report;
127              
128 8 100 66     87 if ( defined $args{format} && $args{format} eq 'table' ) {
129 2 100       10 my $column = $args{collapse} ? "Count " : "Interval ";
130              
131 2         13 $report = ref($self) . ' Report -- Total time: ' . sprintf( '%.4f', $self->total_time() ) . " secs\n";
132 2         53 $report .= "$column Time Percent\n";
133 2         6 $report .= "----------------------------------------------\n";
134             }
135              
136 8         31 return $report;
137             }
138              
139             sub _report_data {
140 8     8   34 my ( $self, %args ) = @_;
141              
142 8         17 my $report;
143              
144             my @records
145             = $args{labels}
146             ? ( $args{collapse} ? $self->any_labels_collapsed(%args) : $self->any_labels_detailed(%args) )
147 8 100       62 : ( $args{collapse} ? $self->collapsed(%args) : $self->detailed(%args) );
    100          
    100          
148              
149 8 100       27 if ( $args{collapse} ) {
150             $report .= join "\n",
151 4         14 map { sprintf( '%8s %.4f %5.2f%% %s', $_->{count}, $_->{time}, $_->{percent}, $_->{label}, ) } @records;
  16         199  
152             }
153             else {
154             $report .= join "\n", map {
155 4         12 sprintf(
156             '%04d -> %04d %.4f %5.2f%% %s',
157             $args{labels} ? $_->{from} : $_->{interval} - 1,
158             $args{labels} ? $_->{to} : $_->{interval},
159             $_->{time}, $_->{percent}, $_->{label},
160             )
161 26 100       232 } @records;
    100          
162             }
163              
164 8         75 return $report;
165             }
166              
167             sub any_labels_detailed {
168 2     2 0 7 my ( $self, %args ) = @_;
169              
170 2         5 my @labels = _filter_input_labels( @{ $args{labels} } );
  2         9  
171 2         9 my @count_pairs = $self->_define_count_pairs(@labels);
172              
173 2 50       7 return () if ( !scalar @count_pairs );
174              
175 2         10 my @sorted = sort { $b->{time} <=> $a->{time} } $self->_any_labels_detailed_records(@count_pairs);
  20         45  
176              
177 2         10 return @sorted;
178             }
179              
180             sub any_labels_collapsed {
181 1     1 0 5 my ( $self, %args ) = @_;
182              
183 1         6 my @detailed = $self->any_labels_detailed(%args);
184 1         6 my $collapsed = _calculate_any_labels_collapsed(@detailed);
185 1   50     8 my $sort_by = $args{sort_by} || 'time';
186              
187 1         4 return $self->_any_labels_collapsed_records( $collapsed, $sort_by );
188             }
189              
190             sub _filter_input_labels {
191 2     2   6 my (@labels) = @_;
192              
193 2 50 33     8 return grep { $_->[0] && $_->[1] && $_->[0] ne $_->[1] } @labels;
  8         55  
194             }
195              
196             sub _define_count_pairs {
197 2     2   5 my ( $self, @labels ) = @_;
198              
199 2         6 my @counts_pairs = ();
200 2         4 my @labels_counts = sort { $a <=> $b } keys %{ $self->{label} };
  30         49  
  2         21  
201              
202 2         8 foreach my $labels (@labels) {
203              
204 8         12 my @starts_counts = ();
205 8         16 foreach my $count (@labels_counts) {
206              
207 64 100       132 if ( $self->{label}->{$count} eq $labels->[0] ) {
    100          
208 16         31 push @starts_counts, $count;
209             }
210             elsif ( $self->{label}->{$count} eq $labels->[1] ) {
211 16         20 my $start_count = pop @starts_counts;
212 16 100       33 if ( defined $start_count ) {
213 12         32 push @counts_pairs, [ $start_count, $count ];
214             }
215             }
216             }
217             }
218              
219 2         8 return @counts_pairs;
220             }
221              
222             sub _calculate_any_labels_collapsed {
223 1     1   4 my (@records) = @_;
224              
225 1         3 my %collapsed;
226 1         5 foreach my $i (@records) {
227 6         8 my $label = $i->{label};
228 6         11 my $time = $i->{time};
229 6         13 $collapsed{$label}{time} += $time;
230 6         13 $collapsed{$label}{count}++;
231             }
232              
233 1         4 return \%collapsed;
234             }
235              
236             sub _any_labels_detailed_records {
237 2     2   8 my ( $self, @count_pairs ) = @_;
238              
239 2         4 my @records = ();
240              
241 2         7 foreach my $counts (@count_pairs) {
242 12         20 my $start_count = $counts->[0];
243 12         19 my $finish_count = $counts->[1];
244 12         27 my $time = Time::HiRes::tv_interval( $self->{times}->[$start_count], $self->{times}->[$finish_count] );
245             my $record = { ## no critic (NamingConventions::ProhibitAmbiguousNames
246             from => $start_count,
247             to => $finish_count,
248             time => sprintf( '%.6f', $time ),
249             percent => sprintf( '%.2f', $time / $self->total_time() * 100 ),
250 12         183 label => sprintf( '%s -> %s', $self->{label}->{$start_count}, $self->{label}->{$finish_count} ),
251             };
252 12         220 push @records, $record;
253             }
254              
255 2         8 return @records;
256             }
257              
258             sub _any_labels_collapsed_records {
259 1     1   3 my ( $self, $collapsed, $sort_by ) = @_;
260              
261 1         5 my @labels = sort { $collapsed->{$b}->{$sort_by} <=> $collapsed->{$a}->{$sort_by} } keys %$collapsed;
  5         13  
262              
263 1         3 my @records = ();
264 1         4 foreach my $label (@labels) {
265              
266             my $record = { ## no critic (NamingConventions::ProhibitAmbiguousNames
267             count => $collapsed->{$label}->{count},
268             time => sprintf( '%.6f', $collapsed->{$label}->{time} ),
269 4         22 percent => sprintf( '%.2f', $collapsed->{$label}->{time} / $self->total_time() * 100 ),
270             label => $label,
271             };
272 4         62 push @records, $record;
273             }
274              
275 1         10 return @records;
276             }
277              
278             1;
279             __END__
280              
281             =encoding utf-8
282              
283             =head1 NAME
284              
285             Telemetry::Any - It's new $module
286              
287             =head1 SYNOPSIS
288              
289             use Telemetry::Any;
290              
291             =head1 DESCRIPTION
292              
293             Telemetry::Any is ...
294              
295             =head1 LICENSE
296              
297             Copyright (C) Mikhail Ivanov.
298              
299             This library is free software; you can redistribute it and/or modify
300             it under the same terms as Perl itself.
301              
302             =head1 AUTHOR
303              
304             Mikhail Ivanov E<lt>m.ivanych@gmail.comE<gt>
305              
306             =cut
307