File Coverage

blib/lib/Benchmark/Harness/Handler.pm
Criterion Covered Total %
statement 21 239 8.7
branch 0 116 0.0
condition 0 12 0.0
subroutine 7 23 30.4
pod 0 14 0.0
total 28 404 6.9


line stmt bran cond sub pod time code
1 1     1   11 use strict;
  1         4  
  1         73  
2             package Benchmark::Harness::Handler;
3 1     1   12 use Benchmark::Harness::Constants;
  1         4  
  1         130  
4 1     1   1302 use XML::Quote;
  1         5344  
  1         92  
5 1     1   2098 use overload;
  1         1291  
  1         5  
6              
7 1     1   54 use vars qw($VERSION); $VERSION = sprintf("%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/);
  1         3  
  1         911  
8              
9             ### ###########################################################################
10             # USAGE: new Benchmark::Harness::Handler(
11             # $parentHarness,
12             # modifiers_from_(...),
13             # package-name,
14             # subroutine-name)
15             sub new {
16 0     0 0   my ($cls, $harness, $modifiers, $pckg, $subName) = @_;
17             # If already defined, then we keep the original one
18             # ("the pen once writ . . .")
19 0 0         return undef if $harness->FindHandler($pckg, $subName);
20              
21 0           my $self = bless [ $#{$harness->{EventList}}+1,
  0            
22             $harness,
23             $modifiers,
24             $subName,
25             $pckg,
26             undef,
27             0,
28             ], $cls;
29              
30 0           push @{$harness->{EventList}}, $self;
  0            
31 0           return $self;
32             }
33              
34             # Attached this event handler to this subroutine in the code
35             # Modifiers -
36             # '0' : do not harness this method (even if asked to later in the parameters)
37             # filter, filterStart : harness, but report only each filter-th event, starting
38             # with the filterStart-th event. filterStart=0|undef reports
39             # the first event, then each filter-th one thereafter.
40             sub Attach {
41 0     0 0   my ($traceSubr) = @_;
42 0           my ($modifiers, $pckg, $method) = ($traceSubr->[HNDLR_MODIFIERS], $traceSubr->[HNDLR_PACKAGE], $traceSubr->[HNDLR_NAME]);
43              
44 0 0 0       return if ( defined $modifiers && ($modifiers eq '0') ); # (0) means do not harness . . .
45              
46             # Splitting handler parameters by '|' makes it easier to include them in a qw()
47 0 0         my ($filter, $filterStart) = (split /\s*\|\s*/, $modifiers) if defined $modifiers;
48              
49 0           $traceSubr->[HNDLR_ORIGMETHOD] = \&{"$pckg\:\:$method"};
  0            
50              
51 0           my $newMethod;
52 0 0         if ( defined $filter ) {
53              
54 0   0       $filter = $filter || 1;
55 0   0       $filterStart = $filterStart || 1;
56 0           $traceSubr->[HNDLR_FILTER] = $filter;
57 0           $traceSubr->[HNDLR_FILTERSTART] = $filterStart;
58              
59             ### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
60             ## NEW METHOD ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
61             $newMethod = sub {
62 0 0   0     if ( $traceSubr->[HNDLR_FILTERSTART] ) {
63 0 0         goto $traceSubr->[HNDLR_ORIGMETHOD] if ( --$traceSubr->[HNDLR_FILTERSTART] );
64 0           $traceSubr->[HNDLR_FILTERSTART] = $traceSubr->[HNDLR_FILTER];
65             }
66 0           my @newArgs;
67 0 0         unless ( $Benchmark::Harness::IS_HARNESS_MODE ) {
68 0           $Benchmark::Harness::IS_HARNESS_MODE += 1;
69 0           @newArgs = $traceSubr->OnSubEntry(@_);
70 0           $traceSubr->harnessPrintReport('E',$traceSubr);
71 0           $Benchmark::Harness::IS_HARNESS_MODE -= 1;
72             }
73 0 0         if (wantarray) {
74 0           my @answer = $traceSubr->[HNDLR_ORIGMETHOD](@_);
75 0           my $newAnswer;
76 0 0         unless ( $Benchmark::Harness::IS_HARNESS_MODE ) {
77 0           $Benchmark::Harness::IS_HARNESS_MODE += 1;
78 0           $newAnswer = $traceSubr->OnSubExit(\@answer);
79 0           $traceSubr->harnessPrintReport('X',$traceSubr);
80 0           $Benchmark::Harness::IS_HARNESS_MODE -= 1;
81             }
82 0           return @answer;
83             } else {
84 0           my $answer;
85             my $newAnswer;
86 0 0         unless ( $Benchmark::Harness::IS_HARNESS_MODE ) {
87 0           $Benchmark::Harness::IS_HARNESS_MODE += 1;
88 0           $answer = $traceSubr->[HNDLR_ORIGMETHOD](@_);
89 0           $newAnswer = scalar $traceSubr->OnSubExit($answer);
90 0           $traceSubr->harnessPrintReport('X',$traceSubr);
91 0           $Benchmark::Harness::IS_HARNESS_MODE -= 1;
92             }
93 0           return $answer;
94             }
95 0           };
96             ### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
97             ### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
98             } else {
99             ### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
100             ## NEW METHOD ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
101             $newMethod = sub {
102 0     0     my @newArgs;
103 0 0         unless ( $Benchmark::Harness::IS_HARNESS_MODE ) {
104 0           $Benchmark::Harness::IS_HARNESS_MODE += 1;
105 0           @newArgs = $traceSubr->OnSubEntry(@_);
106 0           $traceSubr->harnessPrintReport('E',$traceSubr);
107 0           $Benchmark::Harness::IS_HARNESS_MODE -= 1;
108             }
109 0 0         if (wantarray) {
110 0           my @answer = $traceSubr->[HNDLR_ORIGMETHOD](@_);
111 0           my $newAnswer;
112 0 0         unless ( $Benchmark::Harness::IS_HARNESS_MODE ) {
113 0           $Benchmark::Harness::IS_HARNESS_MODE += 1;
114 0           $newAnswer = $traceSubr->OnSubExit(\@answer);
115 0           $traceSubr->harnessPrintReport('X',$traceSubr);
116 0           $Benchmark::Harness::IS_HARNESS_MODE -= 1;
117             }
118 0           return @answer;
119             } else {
120 0           my $answer = $traceSubr->[HNDLR_ORIGMETHOD](@_);
121 0           my $newAnswer;
122 0 0         unless ( $Benchmark::Harness::IS_HARNESS_MODE ) {
123 0           $Benchmark::Harness::IS_HARNESS_MODE += 1;
124 0           $newAnswer = scalar $traceSubr->OnSubExit($answer);
125 0           $traceSubr->harnessPrintReport('X',$traceSubr);
126 0           $Benchmark::Harness::IS_HARNESS_MODE -= 1;
127             }
128 0           return $answer;
129             }
130 0           };
131             ### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
132             ### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
133             }
134             ### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
135             ## NEW METHOD ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
136 1     1   13 no warnings; # We are redefining a method, so don't warn all that!
  1         2  
  1         162  
137 0           eval "\*$pckg\:\:$method = \$newMethod";
138 0           $traceSubr->[HNDLR_HANDLED] = 1;
139             }
140              
141             sub Detach {
142 0     0 0   my ($traceSubr) = @_;
143 0 0         return unless $traceSubr->[HNDLR_HANDLED];
144 0           my ($pckg, $method, $origMethod) = ($traceSubr->[HNDLR_PACKAGE],$traceSubr->[HNDLR_NAME],$traceSubr->[HNDLR_ORIGMETHOD]);
145 1     1   7 no warnings; # We are redefining a method, so don't warn all that!
  1         1  
  1         1952  
146 0           eval "\*$pckg\:\:$method = \$origMethod";
147             }
148              
149             ### ###########################################################################
150             sub reportTraceInfo {
151 0     0 0   my $self = shift;
152 0 0         $self->[HNDLR_REPORT] = [undef,{},undef,undef] unless defined $self->[HNDLR_REPORT];
153 0           my $rpt = $self->[HNDLR_REPORT];
154              
155 0           for ( @_ ) {
156 0           my $typ = ref($_);
157 0 0         if ( $typ ) {
158 0 0         if ( $typ eq 'HASH' ) {
    0          
    0          
159 0           my $hsh = $rpt->[1];
160 0           for my $nam ( keys %$_ ) {
161 0           $hsh->{$nam} = $_->{$nam};
162             }
163             }
164             elsif ( $typ eq 'ARRAY' ) {
165 0 0         $rpt->[2] = [] unless defined $rpt->[2];
166 0           push @{$rpt->[2]}, @$_;
  0            
167             }
168             elsif ( $typ eq 'SCALAR' ) {
169 0           $rpt->[3] .= $$_;
170             } else {
171 0           $rpt->[3] .= $_;
172             }
173             } else {
174 0           $rpt->[0] = $_;
175             }
176             }
177 0           return $self;
178             }
179              
180              
181             ### ###########################################################################
182             sub reportValueInfo {
183 0     0 0   my $self = shift;
184              
185 0           my $val = ['V',{},undef,undef];
186 0           for ( @_ ) {
187 0           my $typ = ref($_);
188 0 0         if ( $typ ) {
189 0 0         if ( $typ eq 'HASH' ) {
    0          
    0          
190 0           my $hsh = $val->[1];
191 0           for my $nam ( keys %$_ ) {
192             # I figure this is the quickest way to get both
193             # the stringified (if overloaded) and type of
194             # the value in this hash-entry.
195 0           my $_val = $_->{$nam};
196 0           my $_ref = ref($_val);
197 0 0         if ( $_ref ) {
198 0 0         if ( my $stringify = overload::Method($_val,'""') ) {
199 0           $hsh->{$nam} = $stringify->($_val);
200 0           $hsh->{_t} = ref($_val);
201             #unless defined $hsh->{_t};
202             } else {
203 0           $hsh->{$nam} = $_val;
204             }
205             } else {
206 0           $hsh->{$nam} = $_val;
207             }
208             }
209             }
210             elsif ( $typ eq 'ARRAY' ) {
211 0 0         $val->[2] = [] unless defined $val->[2];
212 0           push @{$val->[2]}, @$_;
  0            
213             }
214             elsif ( $typ eq 'SCALAR' ) {
215 0           $val->[3] .= $$_;
216             }
217             else {
218 0           $val->[3] .= "$_"; # will stringify if overloaded
219             }
220             } else {
221 0           $val->[0] = $_;
222             }
223             }
224              
225 0 0         $self->[HNDLR_REPORT] = [undef,{},[],undef] unless defined $self->[HNDLR_REPORT];
226 0           my $rpt = $self->[HNDLR_REPORT];
227 0           push @{$rpt->[2]}, $val;
  0            
228 0           return $val;
229             }
230              
231             ### ###########################################################################
232             ### harnessPrintReport ( mode, event-handler, [ report-element ] )
233             sub harnessPrintReport {
234 0     0 0   my $self = shift;
235 0 0         return unless ref($self);
236 0           my $harness = $self->[HNDLR_HARNESS];
237              
238 0           my $mode = shift;
239 0           my $trace = shift;
240 0   0       my $rpt = shift || $self->[HNDLR_REPORT];
241              
242 0 0         return unless $rpt;
243              
244 0           my $fh = $harness->{_outFH};
245 0 0         return unless $fh;
246              
247 0 0         print $fh '<'.(defined($rpt->[0])?$rpt->[0]:'T');
248 0 0         print $fh " _i='$trace->[HNDLR_ID]' _m='$mode'" if $mode;
249 0           my $closeTag = '/>';
250              
251 0           my $hsh = $rpt->[1];
252 0 0         map { print $fh " $_='".xml_quote($hsh->{$_})."'" if defined $hsh->{$_} } keys %$hsh;
  0            
253              
254 0 0         if ( defined $rpt->[2] ) {
255 0 0         print $fh '>'; $closeTag = '[0])?$rpt->[0]:'T').'>';
  0            
256 0           for ( @{$rpt->[2]} ) {
  0            
257 0           $self->harnessPrintReport(undef, undef, $_);
258             }
259             }
260              
261 0 0         if ( defined $rpt->[3] ) {
262 0 0         print $fh '>'; $closeTag = '[0])?$rpt->[0]:'T').'>';
  0            
263 0           print $fh $rpt->[3];
264             }
265              
266 0           print $fh $closeTag;
267 0           $self->[HNDLR_REPORT] = undef;
268             }
269              
270             ### ###########################################################################
271             # USAGE: Invoked by attach()'d subroutine: see above.
272             # This is, presumably, overridden by the sub-harness.
273             sub OnSubEntry {
274 0     0 0   my $self = shift;
275 0           return @_;
276             }
277              
278             ### ###########################################################################
279             # USAGE: Invoked by attach()'d subroutine: see above.
280             # This is, presumably, overridden by the sub-harness.
281             sub OnSubExit {
282 0     0 0   my $self = shift;
283 0           return @_;
284             }
285              
286              
287             ### ###########################################################################
288             # USAGE: Harness::Variables(list of any variable(s));
289             sub Variables {
290 0 0   0 0   my $self = ref($_[0])?shift:$Benchmark::Harness::Harness;
291 0 0         return unless ref($self);
292 0 0         return unless $self->{_outFH};
293             }
294              
295              
296             ### ###########################################################################
297             # USAGE: Harness::Arguments(@_);
298             sub ArgumentsXXX {
299 0     0 0   my $self = shift;
300 0 0         return $self unless ref($self);
301 0 0         return $self unless $self->{_outFH};
302              
303 0           $self->_PrintT('-Arguments', caller(1));
304              
305 0           my $i = 1;
306 0           for ( @_ ) {
307 0 0         my $obj = ref($_)?$_:\$_;
308 0           my ($nm, $sz) = (ref($_), Devel::Size::total_size($_));
309 0 0         $nm = $i unless $nm; $i += 1;
  0            
310 0           $self->print("");
311             }
312 0           $self->_PrintT_();
313 0           return $self;
314             }
315              
316             ### ###########################################################################
317             # USAGE: Harness::NamedObject($name, $self); - where $self is a blessed reference.
318             sub NamedObjects {
319 0     0 0   my $self = shift;
320 0 0         return $self unless ref($self);
321              
322 0           my %objects = @_;
323 0           for ( keys %objects ) {
324 0           $self->reportValueInfo(
325             { 'n' => $_,
326             'v' => $objects{$_},
327             }
328             );
329             }
330 0           return $self;
331             }
332              
333             ### ###########################################################################
334             # USAGE: Harness::Object($obj); - where $obj is an object reference.
335             sub Object {
336 0     0 0   my $self = shift;
337 0 0         return $self unless ref($self);
338 0           my $pckg = $_[0];
339              
340 0           my $pckgName = "$pckg";
341 0           $pckgName =~ s{=?(ARRAY|HASH|SCALAR).*$}{};
342 0           my $pckgType = $1;
343 0           $self->_PrintT("-$pckgType $pckgName", caller(1));
344 0           $self->OnObject(@_);
345              
346 0           $self->_PrintT_();
347 0           return $self;
348             }
349              
350             ### ###########################################################################
351             # USAGE: Benchmark::MemoryUsage::MethodReturn( $pckg )
352             # Print useful information about the given object ($pckg)
353             sub OnObject {
354 0     0 0   my $self = shift;
355 0           my $obj = shift;
356              
357 0           my $objName = "$obj";
358 0           $objName =~ s{=?([A-Z]+).*$}{};#s{=?(ARRAY|HASH|SCALAR|CODE).*$}{};
359 0   0       my $objType = $1 || '';
360              
361 0 0         if ( $objType eq 'HASH' ) {
    0          
    0          
362 0           my $i = 0;
363 0           for ( keys %$obj ) {
364 0 0         my $obj = ref($_)?$_:\$_;
365 0           my ($nm) = ($_);
366 0 0         $nm = $i unless $nm; $i += 1;
  0            
367 0           $self->print("");
368             }
369             } elsif ( $objType eq 'ARRAY' ) {
370 0           my $i = 0;
371 0           for ( @$obj ) {
372 0           my ($nm) = ($i);
373 0           $i += 1;
374 0           $self->print("");
375 0 0         last if ( ++$i == 20 );
376 0 0         if ( scalar(@$objType) > 20 ) {
377 0           $self->print("");
378             };
379             }
380             } elsif ( $objType eq 'SCALAR' ) {
381 0           $self->print("$$obj");
382             } else {
383 0           $self->print("$obj");
384             }
385 0           return $self;
386             }
387              
388             ### ###########################################################################
389             # USAGE: Harness::NamedVariables('name1' => $variable1 [, 'name1' => $variable2 ])
390             sub NamedVariables {
391 0 0   0 0   my $self = ref($_[0])?shift:$Benchmark::Harness::Harness;
392 0 0         return $self unless ref($self);
393              
394 0           $self->_PrintT(undef, caller(1));
395              
396 0           my $i = 1;
397 0           while ( @_ ) {
398 0           my ($nm, $sz) = (shift, Devel::Size::total_size(shift));
399 0 0         $nm = $i unless $nm; $i += 1;
  0            
400 0           $self->print("");
401             }
402 0           $self->_PrintT_();
403 0           return $self;
404             }
405              
406             1;