File Coverage

blib/lib/Devel/NYTProf/Callgrind/Ticks.pm
Criterion Covered Total %
statement 101 104 97.1
branch 26 30 86.6
condition 2 2 100.0
subroutine 12 12 100.0
pod 7 7 100.0
total 148 155 95.4


line stmt bran cond sub pod time code
1             package Devel::NYTProf::Callgrind::Ticks; # Represents a mesh of Ticks read from a callgrind file
2              
3 6     6   2367 use strict;
  6         8  
  6         138  
4 6     6   20 use warnings;
  6         7  
  6         206  
5             our $VERSION = '0.02';
6              
7              
8 6     6   2896 use Moose;
  6         1727383  
  6         30  
9              
10             # This class is mainly for TicksDiff but you can also use it alone
11             # to load and save callgrind files.
12             #
13             # With this class you may find via getBlockEquivalent() the same callgrind
14             # block in a file by using a different callgrind file as reference to
15             # compare the values.
16             #
17             # Or you want to manipulate callgrind files by changing values or adding blocks.
18             # If you plan to write any kind of ticks analysis this class might be helpull.
19             # Then maybe getBlocksAsArray() is usefull.
20             #
21             # AUTHOR
22             # ======
23             # Andreas Hernitscheck - ahernit AT cpan.org
24             #
25             # LICENCE
26             # =======
27             # You can redistribute it and/or modify it under the conditions of
28             # LGPL and Artistic Licence.
29              
30              
31             # file to be loaded
32             has 'file' => (
33             is => 'rw',
34             isa => 'Str',
35             );
36              
37             # returns the list of blocks,
38             # or writes them
39             has 'list' => (
40             is => 'rw',
41             isa => 'ArrayRef',
42             default => sub{[]},
43             );
44              
45              
46             has 'blocks_by_id' => (
47             is => 'rw',
48             isa => 'HashRef',
49             default => sub{{}},
50             );
51              
52              
53              
54              
55             sub BUILD{
56 13     13 1 5918 my $self = shift;
57              
58             # file to be loaded?
59 13 100       426 if ( $self->file() ){
60 8         221 $self->loadFile( $self->file() );
61             }
62              
63             }
64              
65             # Loads the callgrind file into memory and starts internal indexing of the blocks.
66             sub loadFile{ # void ( $filename )
67 8     8 1 10 my $self = shift;
68 8         8 my $file = shift;
69            
70 8 50       244 if ( not -f $file ){ die "file $file does not exist" };
  0         0  
71              
72 8         323 open( my $fh, $file );
73              
74 8         11 my $area;
75             my $block;
76 0         0 my @list;
77 8         114 while ( my $line = <$fh> ){
78 270         333 $line =~ s/\n//; # remove return
79              
80             # starting an area
81 270 100       385 if ( $line =~ m/events:\s(\w+)/i ){
82 8         19 $area = lc($1);
83 8         21 next;
84             }
85              
86             # skip line if not type ticks
87 262 50       296 if ( $area ne 'ticks' ){ next };
  0         0  
88              
89             # empty line is cleaning the block buffer
90 262 100       435 if ( $line =~ m/^\s*$/ ){
91              
92             # save the found block infos
93 52 100       94 if ( scalar( keys %$block ) != 0 ){ push @list,$block };
  42         44  
94              
95 52         33 $block={};
96 52         118 next;
97             }
98              
99             # is there a equals char? (=)
100 210 100       361 if ( $line =~ m/(\w+)=(.+)/ ){
101 166         143 my $key = $1;
102 166         143 my $value = $2;
103 166         180 $block->{ $key } = $value;
104              
105 166 100       202 if ( $key eq 'calls' ){
106 26         42 my ($count, $dstpos) = split(/ /, $value, 2);
107 26         32 $block->{ 'count' } = $count;
108 26         29 $block->{ 'dstpos' } = $dstpos;
109             }
110             }
111              
112             ## read the ticks
113 210 100       469 if ( $line =~ m/^(\d+) (\d+)$/ ){
114 44         67 $block->{ 'srcpos' } = $1;
115 44         97 $block->{ 'ticks' } = $2;
116             }
117              
118             } # while
119              
120             # no blank line on the end? save the block if needed
121 8 100       20 if ( keys %$block ){ push @list,$block };
  2         5  
122              
123             #print Dumper( \@list );
124              
125             # save the callgrind list holding blocks
126 8         275 $self->list( \@list );
127 8         13 $self->_buildIdHash();
128              
129 8         186 close( $fh );
130             }
131              
132              
133             # build hash to for list_by_id to find
134             # nodes by a fingerprint/id
135             sub _buildIdHash{
136 8     8   9 my $self = shift;
137 8         215 my $list = $self->list();
138 8         12 my $idhash = {};
139              
140 8         10 foreach my $block (@$list){
141 44         47 my $id = $self->_createFingerprintOfBlock( $block );
142              
143 44         71 $idhash->{ $id } = $block;
144             }
145            
146             #print Dumper( $idhash );
147 8         233 $self->blocks_by_id( $idhash );
148             }
149              
150             # Adds a block. For example you start with an
151             # empty object and wants to add blocks from
152             # a different object. It will replace an existing
153             # block if the definition existists already. So
154             # addBlock can also be used to update a block.
155             # If you update an existing block, it does break
156             # the reference to the given hashref, it makes a copy
157             # of the values. So do not use the original hash then
158             # but use the method of this class to get the callgrind text.
159             sub addBlock{ # void ( HashRef $block )
160 31     31 1 546 my $self = shift;
161 31         20 my $block = shift;
162              
163 31         33 my $id = $self->_createFingerprintOfBlock( $block );
164 31         854 my $found = $self->blocks_by_id()->{ $id };
165              
166             # if already in, replace it, otherwise add it
167 31 100       37 if ( $found ){
168 2         2 %{ $found } = %{ $block };
  2         12  
  2         5  
169             }else{
170 29 50       353 if ( scalar( keys %$block ) != 0 ){
171 29         22 push @{ $self->list() }, $block;
  29         735  
172 29         732 $self->blocks_by_id()->{ $id } = $block;
173             }
174             }
175              
176             }
177              
178              
179             # Takes a callgrind block and creates a unique string
180             # to compare different files and find the same block.
181             sub _createFingerprintOfBlock{
182 127     127   4250 my $self = shift;
183 127         85 my $block = shift;
184 127         72 my $id;
185              
186 127         172 my @keys = qw( fl fn srcpos cfl cfn dstpos );
187              
188 127         76 my @id;
189 127         106 foreach my $w (@keys){
190 762   100     1203 push @id, $block->{ $w } || '';
191             }
192 127         193 $id = join("#", @id);
193              
194 127         193 return $id;
195             }
196              
197              
198             # returns the equivalent block in that object to a given
199             # strange block (from a different object).
200             # Returns undef if not found.
201             sub getBlockEquivalent{ # \%block ( \%block )
202 24     24 1 16 my $self = shift;
203 24         14 my $block = shift;
204 24         22 my $found = undef;
205              
206 24         27 my $id = $self->_createFingerprintOfBlock( $block );
207              
208 24 100       648 if ( exists $self->blocks_by_id()->{ $id } ){
209 22         578 $found = $self->blocks_by_id()->{ $id };
210             }
211              
212 24         44 return $found;
213             }
214              
215              
216             # Is the same as list(). It returns an ArrayRef
217             # of the blocks (HashRefs).
218             sub getBlocksAsArray{ # \@list
219 21     21 1 915 my $self = shift;
220              
221 21         691 return $self->list();
222             }
223              
224              
225             # Save the data to a callgrind file. The event type will
226             # be 'Ticks', nothing else.
227             sub saveFile{ # void ( $filename )
228 2     2 1 5 my $self = shift;
229 2         3 my $file = shift;
230            
231 2         5 my $text = $self->getAsText();
232              
233 2 50       220 open( my $fh, ">$file" ) or die "Can not write file $file";
234              
235 2         18 print $fh $text;
236              
237 2         108 close( $fh );
238              
239             }
240              
241              
242             # Returns the callgrind text
243             sub getAsText{ # $text
244 2     2 1 3 my $self = shift;
245 2         3 my @lines;
246              
247 2         2 push @lines, "events: Ticks";
248 2         3 push @lines, "";
249              
250 2         4 my @pairs = qw( fl fn cfl cfn calls );
251              
252 2         3 foreach my $node ( @{ $self->list() } ){
  2         53  
253              
254 14         9 my @block = ();
255              
256 14         12 foreach my $p ( @pairs ){
257 70 100       113 push @block,"$p=".$node->{$p} if exists $node->{$p};
258             }
259              
260 14         27 push @lines, join( "\n", @block );
261 14         20 push @lines, $node->{'srcpos'}.' '.$node->{'ticks'};
262 14         17 push @lines, "";
263              
264              
265             }
266            
267 2         10 return join( "\n", @lines );
268             }
269              
270              
271              
272             1;
273              
274             #################### pod generated by Pod::Autopod - keep this line to make pod updates possible ####################
275              
276             =head1 NAME
277              
278             Devel::NYTProf::Callgrind::Ticks - Represents a mesh of Ticks read from a callgrind file
279              
280              
281             =head1 DESCRIPTION
282              
283             This class is mainly for TicksDiff but you can also use it alone
284             to load and save callgrind files.
285              
286             With this class you may find via getBlockEquivalent() the same callgrind
287             block in a file by using a different callgrind file as reference to
288             compare the values.
289              
290             Or you want to manipulate callgrind files by changing values or adding blocks.
291             If you plan to write any kind of ticks analysis this class might be helpull.
292             Then maybe getBlocksAsArray() is usefull.
293              
294              
295              
296             =head1 REQUIRES
297              
298             L<Moose>
299              
300              
301             =head1 METHODS
302              
303             =head2 new
304              
305             $this->new();
306              
307             =head2 BUILD
308              
309             $this->BUILD();
310              
311             =head2 addBlock
312              
313             $this->addBlock(\%$block);
314              
315             Adds a block. For example you start with an
316             empty object and wants to add blocks from
317             a different object. It will replace an existing
318             block if the definition existists already. So
319             addBlock can also be used to update a block.
320             If you update an existing block, it does break
321             the reference to the given hashref, it makes a copy
322             of the values. So do not use the original hash then
323             but use the method of this class to get the callgrind text.
324              
325              
326             =head2 getAsText
327              
328             my $text = $this->getAsText();
329              
330             Returns the callgrind text
331              
332              
333             =head2 getBlockEquivalent
334              
335             my \%block = $this->getBlockEquivalent(\%block);
336              
337             returns the equivalent block in that object to a given
338             strange block (from a different object).
339             Returns undef if not found.
340              
341              
342             =head2 getBlocksAsArray
343              
344             my \@list = $this->getBlocksAsArray();
345              
346             Is the same as list(). It returns an ArrayRef
347             of the blocks (HashRefs).
348              
349              
350             =head2 loadFile
351              
352             $this->loadFile($filename);
353              
354             Loads the callgrind file into memory and starts internal indexing of the blocks.
355              
356              
357             =head2 saveFile
358              
359             $this->saveFile($filename);
360              
361             Save the data to a callgrind file. The event type will
362             be 'Ticks', nothing else.
363              
364              
365              
366             =head1 LICENCE
367              
368             You can redistribute it and/or modify it under the conditions of
369             LGPL and Artistic Licence.
370              
371              
372             =head1 AUTHOR
373              
374             Andreas Hernitscheck - ahernit AT cpan.org
375              
376              
377              
378             =cut
379