File Coverage

blib/lib/Devel/NYTProf/FileInfo.pm
Criterion Covered Total %
statement 254 271 93.7
branch 62 96 64.5
condition 26 40 65.0
subroutine 46 46 100.0
pod 2 35 5.7
total 390 488 79.9


line stmt bran cond sub pod time code
1             package Devel::NYTProf::FileInfo; # fid_fileinfo
2              
3             =head1 NAME
4              
5             Devel::NYTProf::FileInfo
6              
7             =head1 METHODS
8              
9             =cut
10              
11 48     48   378 use strict;
  48         106  
  48         1476  
12              
13 48     48   269 use Carp;
  48         97  
  48         2606  
14 48     48   278 use Config;
  48         98  
  48         1876  
15 48     48   313 use List::Util qw(sum);
  48         137  
  48         3200  
16              
17 48     48   21564 use Devel::NYTProf::Util qw(strip_prefix_from_paths trace_level);
  48         589  
  48         4086  
18              
19 48         8265 use Devel::NYTProf::Constants qw(
20             NYTP_FIDf_HAS_SRC NYTP_FIDf_SAVE_SRC NYTP_FIDf_IS_FAKE NYTP_FIDf_IS_PMC
21             NYTP_FIDf_IS_EVAL
22              
23             NYTP_FIDi_FILENAME NYTP_FIDi_EVAL_FID NYTP_FIDi_EVAL_LINE NYTP_FIDi_FID
24             NYTP_FIDi_FLAGS NYTP_FIDi_FILESIZE NYTP_FIDi_FILEMTIME NYTP_FIDi_PROFILE
25             NYTP_FIDi_EVAL_FI NYTP_FIDi_HAS_EVALS NYTP_FIDi_SUBS_DEFINED NYTP_FIDi_SUBS_CALLED
26             NYTP_FIDi_elements
27              
28             NYTP_SCi_CALL_COUNT NYTP_SCi_INCL_RTIME NYTP_SCi_EXCL_RTIME NYTP_SCi_RECI_RTIME
29             NYTP_SCi_REC_DEPTH NYTP_SCi_CALLING_SUB
30             NYTP_SCi_elements
31 48     48   19692 );
  48         139  
32              
33             # extra constants for private elements
34             use constant {
35 48         190956 NYTP_FIDi_meta => NYTP_FIDi_elements + 1,
36             NYTP_FIDi_cache => NYTP_FIDi_elements + 2,
37 48     48   447 };
  48         222  
38              
39 17933     17933 0 98642 sub filename { shift->[NYTP_FIDi_FILENAME()] }
40 465     465 0 2924 sub eval_fid { shift->[NYTP_FIDi_EVAL_FID()] }
41 3825     3825 0 26482 sub eval_line { shift->[NYTP_FIDi_EVAL_LINE()] }
42 22227     22227 0 115485 sub fid { shift->[NYTP_FIDi_FID()] }
43 1     1 0 5 sub size { shift->[NYTP_FIDi_FILESIZE()] }
44 1     1 0 5 sub mtime { shift->[NYTP_FIDi_FILEMTIME()] }
45 2636     2636 0 9575 sub profile { shift->[NYTP_FIDi_PROFILE()] }
46 387     387 0 1553 sub flags { shift->[NYTP_FIDi_FLAGS()] }
47              
48             # if an eval then return fileinfo obj for the fid that executed the eval
49 18     18 0 119 sub eval_fi { shift->[NYTP_FIDi_EVAL_FI()] }
50             # is_eval is true only for simple string evals (doesn't consider NYTP_FIDf_IS_EVAL)
51 30 50   30 0 237 sub is_eval { shift->[NYTP_FIDi_EVAL_FI()] ? 1 : 0 }
52              
53 23     23 0 73 sub is_fake { shift->flags & NYTP_FIDf_IS_FAKE }
54             sub is_file {
55 4     4 0 10 my $self = shift;
56 4   33     9 return not ($self->is_fake or $self->is_eval or $self->flags & NYTP_FIDf_IS_EVAL());
57             }
58              
59             # general purpose hash - mainly a hack to help kill off Reader.pm
60 646   100 646 0 8211 sub meta { shift->[NYTP_FIDi_meta()] ||= {} }
61             # general purpose cache
62 928   100 928 0 8453 sub cache { shift->[NYTP_FIDi_cache()] ||= {} }
63              
64             # array of fileinfo's for each string eval in the file
65             sub has_evals {
66 4078     4078 0 10082 my ($self, $include_nested) = @_;
67              
68 4078 100       19267 my $eval_fis = $self->[NYTP_FIDi_HAS_EVALS()]
69             or return;
70 848 100       5085 return @$eval_fis if !$include_nested;
71              
72 96         297 my @eval_fis = @$eval_fis;
73             # walk down tree of nested evals, adding them to @fi
74 96         378 for (my $i=0; my $fi = $eval_fis[$i]; ++$i) {
75 112         362 push @eval_fis, $fi->has_evals(0);
76             }
77              
78 96         397 return @eval_fis;
79             }
80              
81              
82             sub sibling_evals {
83 1     1 0 3 my ($self) = @_;
84 1 50       3 my $parent_fi = $self->eval_fi
85             or return; # not an eval
86 0         0 my $eval_line = $self->eval_line;
87 0         0 return grep { $_->eval_line == $eval_line } $parent_fi->has_evals;
  0         0  
88             }
89              
90              
91             sub _nullify {
92 224     224   551 my $self = shift;
93 224         1575 @$self = (); # Zap!
94             }
95              
96              
97              
98             # return subs defined as list of SubInfo objects
99             sub subs_defined {
100 1561     1561 0 4397 my ($self, $incl_nested_evals) = @_;
101              
102 1561 50       4127 return map { $_->subs_defined(0) } $self, $self->has_evals(1)
  0         0  
103             if $incl_nested_evals;
104              
105 1561         2865 return values %{ $self->[NYTP_FIDi_SUBS_DEFINED()] };
  1561         14804  
106             }
107              
108             sub subs_defined_sorted {
109 1139     1139 0 3955 my ($self, $incl_nested_evals) = @_;
110 1139         4728 return sort { $a->subname cmp $b->subname } $self->subs_defined($incl_nested_evals);
  3303         10700  
111             }
112              
113             sub _remove_sub_defined {
114 256     256   700 my ($self, $si) = @_;
115 256         934 my $subname = $si->subname;
116 256 50       1082 delete $self->[NYTP_FIDi_SUBS_DEFINED()]->{$subname}
117             or carp sprintf "_remove_sub_defined: sub %s wasn't defined in %d %s",
118             $subname, $self->fid, $self->filename;
119             }
120              
121             sub _add_new_sub_defined {
122 240     240   816 my ($self, $subinfo) = @_;
123 240         986 my $subname = $subinfo->subname;
124 240   50     1052 my $subs_defined = $self->[NYTP_FIDi_SUBS_DEFINED()] ||= {};
125 240         746 my $existing_si = $subs_defined->{$subname};
126 240 50       717 croak sprintf "sub %s already defined in fid %d %s",
127             $subname, $self->fid, $self->filename
128             if $existing_si;
129              
130 240         1124 $subs_defined->{$subname} = $subinfo;
131             }
132              
133              
134             =head2 sub_call_lines
135              
136             $hash = $fi->sub_call_lines;
137              
138             Returns a reference to a hash containing information about subroutine calls
139             made at individual lines within the source file.
140             Returns undef if no subroutine calling information is available.
141              
142             The keys of the returned hash are line numbers. The values are references to
143             hashes with fully qualified subroutine names as keys. Each hash value is an
144             reference to an array containing an integer call count (how many times the sub
145             was called from that line of that file) and an inclusive time (how much time
146             was spent inside the sub when it was called from that line of that file).
147              
148             For example, if the following was line 42 of a file C:
149              
150             ++$wiggle if foo(24) == bar(42);
151              
152             that line was executed once, and foo and bar were imported from pkg1, then
153             sub_call_lines() would return something like:
154              
155             {
156             42 => {
157             'pkg1::foo' => [ 1, 0.02093 ],
158             'pkg1::bar' => [ 1, 0.00154 ],
159             },
160             }
161              
162             =cut
163              
164 2504     2504 1 11844 sub sub_call_lines { shift->[NYTP_FIDi_SUBS_CALLED()] }
165              
166              
167             =head2 evals_by_line
168              
169             # { line => { fid_of_eval_at_line => $fi, ... }, ... }
170             $hash = $fi->evals_by_line;
171              
172             Returns a reference to a hash containing information about string evals
173             executed at individual lines within a source file.
174              
175             The keys of the returned hash are line numbers. The values are references to
176             hashes with file id integers as keys and FileInfo objects as values.
177              
178             =cut
179              
180             sub evals_by_line {
181 19     19 1 162 my ($self) = @_;
182              
183             # find all fids that have this fid as an eval_fid
184             # { line => { fid_of_eval_at_line => $fi, ... } }
185              
186 19         33 my %evals_by_line;
187 19         55 for my $fi ($self->has_evals) {
188 0         0 $evals_by_line{ $fi->eval_line }->{ $fi->fid } = $fi;
189             }
190              
191 19         196 return \%evals_by_line;
192             }
193              
194              
195             sub line_time_data {
196 468     468 0 1340 my ($self, $levels) = @_;
197 468   100     3954 $levels ||= [ 'line' ];
198             # XXX this can be optimized once the fidinfo contains directs refs to the data
199 468         1391 my $profile = $self->profile;
200 468         1147 my $fid = $self->fid;
201 468         1587 for my $level (@$levels) {
202 468         3230 my $fid_ary = $profile->get_fid_line_data($level);
203 468 50 33     3972 return $fid_ary->[$fid] if $fid_ary && $fid_ary->[$fid];
204             }
205 0         0 return undef;
206             }
207              
208             sub excl_time { # total exclusive time for fid
209 1     1 0 3 my $self = shift;
210 1   50     5 my $line_data = $self->line_time_data([qw(sub block line)])
211             || return undef;
212 1         3 my $excl_time = 0;
213 1         3 for (@$line_data) {
214 19 100       42 next unless $_;
215 6         13 $excl_time += $_->[0];
216             }
217 1         3 return $excl_time;
218             }
219              
220              
221             sub sum_of_stmts_count {
222 16     16 0 9511 my ($self, $incl_nested_evals) = @_;
223              
224 16 50       49 return sum(map { $_->sum_of_stmts_count(0) } $self, $self->has_evals(1))
  0         0  
225             if $incl_nested_evals;
226              
227 16         45 my $ref = \$self->cache->{NYTP_FIDi_sum_stmts_count};
228 16 50       122 $$ref = $self->_sum_of_line_time_data(1)
229             if not defined $$ref;
230              
231 16         128 return $$ref;
232             }
233              
234             sub sum_of_stmts_time {
235 16     16 0 51 my ($self, $incl_nested_evals) = @_;
236              
237 16 50       42 return sum(map { $_->sum_of_stmts_time(0) } $self, $self->has_evals(1))
  0         0  
238             if $incl_nested_evals;
239              
240 16         37 my $ref = \$self->cache->{NYTP_FIDi_sum_stmts_times};
241 16 50       90 $$ref = $self->_sum_of_line_time_data(0)
242             if not defined $$ref;
243              
244 16         127 return $$ref;
245             }
246              
247             sub _sum_of_line_time_data {
248 32     32   71 my ($self, $idx) = @_;
249 32         73 my $line_time_data = $self->line_time_data;
250 32         61 my $sum = 0;
251 32   100     382 $sum += $_->[$idx]||0 for @$line_time_data;
252 32         90 return $sum;
253             }
254              
255              
256             sub outer {
257 1     1 0 4 my ($self, $recurse) = @_;
258 1 50       3 my $fi = $self->eval_fi
259             or return;
260 0         0 my $prev = $self;
261              
262 0   0     0 while ($recurse and my $eval_fi = $fi->eval_fi) {
263 0         0 $prev = $fi;
264 0         0 $fi = $eval_fi;
265             }
266 0 0       0 return $fi unless wantarray;
267 0         0 return ($fi, $prev->eval_line);
268             }
269              
270              
271             sub is_pmc {
272 359     359 0 1070 return (shift->flags & NYTP_FIDf_IS_PMC());
273             }
274              
275              
276             sub collapse_sibling_evals {
277 192     192 0 1047 my ($self, $survivor_fi, @donors) = @_;
278 192         658 my $profile = $self->profile;
279              
280             die "Can't collapse_sibling_evals of non-sibling evals"
281 192 50       540 if grep { $_->eval_fid != $survivor_fi->eval_fid or
  224 50       1008  
282             $_->eval_line != $survivor_fi->eval_line
283             } @donors;
284              
285 192         1663 my $s_ltd = $survivor_fi->line_time_data; # XXX line only
286 192         870 my $s_scl = $survivor_fi->sub_call_lines;
287 192         430 my %donor_fids;
288              
289 192         1095 for my $donor_fi (@donors) {
290             # copy data from donor to survivor_fi then delete donor
291 224         804 my $donor_fid = $donor_fi->fid;
292 224         1668 $donor_fids{$donor_fid} = $donor_fi;
293              
294 224 50       1275 warn sprintf "collapse_sibling_evals: processing donor fid %d: %s\n",
295             $donor_fid, $donor_fi->filename
296             if trace_level() >= 3;
297              
298             # XXX nested evals not handled yet
299 224 50       837 warn sprintf "collapse_sibling_evals: nested evals in %s not handled",
300             $donor_fi->filename
301             if $donor_fi->has_evals;
302              
303             # for each sub defined in the donor,
304             # move the sub definition to the survivor
305 224 100       1036 if (my @subs_defined = $donor_fi->subs_defined) {
306              
307 128         533 for my $si (@subs_defined) {
308 128 50       575 warn sprintf " - moving from fid %d: sub %s\n",
309             $donor_fid, $si->subname
310             if trace_level() >= 4;
311 128         1682 $si->_alter_fileinfo($donor_fi, $survivor_fi);
312 128 50       711 warn sprintf " - moving done\n"
313             if trace_level() >= 4;
314             }
315             }
316              
317             # for each sub call made by the donor,
318             # move the sub calls to the survivor
319             # 1 => { 'main::foo' => [ 1, '1.38e-05', '1.24e-05', ..., { 'main::RUNTIME' => undef } ] }
320 224 50       645 if (my $sub_call_lines = $donor_fi->sub_call_lines) {
321              
322 224         475 my %subnames_called_by_donor;
323              
324             # merge details of subs called from $donor_fi
325 224         1572 while ( my ($line, $sc_hash) = each %$sub_call_lines ) {
326 176   50     856 my $s_sc_hash = $s_scl->{$line} ||= {};
327 176         770 for my $subname (keys %$sc_hash ) {
328 176   100     978 my $s_sc_info = $s_sc_hash->{$subname} ||= [];
329 176         517 my $sc_info = delete $sc_hash->{$subname};
330 176         2394 Devel::NYTProf::SubInfo::_merge_in_caller_info($s_sc_info, $sc_info,
331             tag => "line $line calls to $subname",
332             );
333              
334 176         1598 $subnames_called_by_donor{$subname}++;
335             }
336             }
337 224         830 %$sub_call_lines = (); # zap
338              
339             # update subinfo (NYTP_SIi_CALLED_BY)
340             $profile->subinfo_of($_)->_alter_called_by_fileinfo($donor_fi, $survivor_fi)
341 224         1758 for keys %subnames_called_by_donor;
342             }
343              
344             # copy line time data
345 224   50     851 my $d_ltd = $donor_fi->line_time_data || []; # XXX line only
346 224         1378 for my $line (0..@$d_ltd-1) {
347 544 100       1652 my $d_tld_l = $d_ltd->[$line] or next;
348 320   50     949 my $s_tld_l = $s_ltd->[$line] ||= [];
349 320         1263 $s_tld_l->[$_] += $d_tld_l->[$_] for (0..@$d_tld_l-1);
350 320         725 warn sprintf "%d:%d: @$s_tld_l from @$d_tld_l fid:%d\n",
351             $survivor_fi->fid, $line, $donor_fid if 0;
352             }
353              
354 224         493 push @{ $survivor_fi->meta->{merged_fids} }, $donor_fid;
  224         1168  
355             ++$survivor_fi->meta->{merged_fids_src_varied}
356 224 50       938 if $donor_fi->src_digest ne $survivor_fi->src_digest;
357              
358 224         1227 $donor_fi->_nullify;
359             }
360              
361             # remove donors from parent NYTP_FIDi_HAS_EVALS
362 192 50       1491 if (my $eval_fis = $self->[NYTP_FIDi_HAS_EVALS()]) {
363 192         674 my %donors = map { +"$_" => 1 } @donors;
  224         2085  
364 192         776 my $count = @$eval_fis;
365 192         565 @$eval_fis = grep { !$donors{$_} } @$eval_fis;
  719         2400  
366 192 50       1601 warn "_delete_eval mismatch"
367             if @$eval_fis != $count - @donors;
368             }
369              
370             # update sawampersand_fid if it's one of the now-dead donors
371 192 50 50     1238 if ($donor_fids{ $profile->attributes->{sawampersand_fid} || 0 }) {
372 0         0 $profile->attributes->{sawampersand_fid} = $survivor_fi->fid;
373             }
374              
375             # now the fid merging is complete...
376             # look for any anon subs that are effectively duplicates
377             # (ie have the same name except for eval seqn)
378             # if more than one for any given name we merge them
379 192 100       1239 if (my @subs_defined = $survivor_fi->subs_defined_sorted) {
380              
381             # bucket anon subs by normalized name
382 112         273 my %newname;
383 112         323 for my $si (@subs_defined) {
384 240 50       1188 next unless $si->is_anon;
385 240         805 (my $newname = $si->subname) =~ s/ \( ((?:re_)?) eval \s \d+ \) /(${1}eval 0)/xg;
386 240         683 push @{ $newname{$newname} }, $si;
  240         1495  
387             }
388              
389 112         837 while ( my ($newname, $to_merge) = each %newname ) {
390 112         336 my $survivor_si = shift @$to_merge;
391 112 50       375 next unless @$to_merge; # nothing to do
392              
393 112         360 my $survivor_subname = $survivor_si->subname;
394             warn sprintf "collapse_sibling_evals: merging %d subs into %s: %s\n",
395             scalar @$to_merge, $survivor_subname,
396 112 50       596 join ", ", map { $_->subname } @$to_merge
  0         0  
397             if trace_level() >= 3;
398              
399 112         364 for my $delete_si (@$to_merge) {
400 128         354 my $delete_subname = $delete_si->subname;
401              
402             # for every file that called this sub, find the lines that made the calls
403             # and change the name to the new sub
404 128         875 for my $caller_fid ($delete_si->caller_fids) {
405 128         743 my $caller_fi = $profile->fileinfo_of($caller_fid);
406             # sub_call_lines ==> { line => { sub => ... } }
407 128         266 for my $subs_called_on_line (values %{ $caller_fi->sub_call_lines }) {
  128         389  
408 704 100       1869 my $sc_info = delete $subs_called_on_line->{$delete_subname}
409             or next;
410 128   50     517 my $s_sc_info = $subs_called_on_line->{$survivor_subname} ||= [];
411 128         627 Devel::NYTProf::SubInfo::_merge_in_caller_info($s_sc_info, $sc_info,
412             tag => "collapse eval $delete_subname",
413             );
414             }
415             }
416              
417 128         698 $survivor_si->merge_in($delete_si);
418 128         500 $survivor_fi->_remove_sub_defined($delete_si);
419 128         758 $profile->_disconnect_subinfo($delete_si);
420             }
421             }
422             }
423              
424 192 50       1153 warn sprintf "collapse_sibling_evals done for ".$survivor_fi->filename."\n"
425             if trace_level() >= 2;
426              
427 192         868 return $survivor_fi;
428             }
429              
430              
431             # Should return the filename that the application used when loading the file
432             # For evals should remove the @INC portion from within the "(eval N)[$path]"
433             # and similarly for Class::MOP #line evals "... defined at $path".
434             # This is a bit of a fudge. Filename handling should be improved in the profiler.
435             sub filename_without_inc {
436 989     989 0 2971 my $self = shift;
437 989         2810 my $f = [$self->filename];
438 989         3984 strip_prefix_from_paths([$self->profile->inc], $f,
439             qr/(?: ^ | \[ | \sdefined\sat\s )/x
440             );
441 989         6753 return $f->[0];
442             }
443              
444              
445             sub abs_filename {
446 343     343 0 751 my $self = shift;
447              
448 343         1277 my $filename = $self->filename;
449              
450             # strip of autosplit annotation, if any
451 343         1287 $filename =~ s/ \(autosplit into .*//;
452              
453             # if it's a .pmc then assume that's the file we want to look at
454             # (because the main use for .pmc's are related to perl6)
455 343 50       1202 $filename .= "c" if $self->is_pmc;
456              
457             # search profile @INC if filename is not absolute
458 343         1179 my @files = ($filename);
459 343 100       1223 if ($filename !~ m/^\//) {
460 340         818 my @inc = $self->profile->inc;
461 340         1129 @files = map { "$_/$filename" } @inc;
  4420         12052  
462             }
463              
464 343         1241 for my $file (@files) {
465 4423 50       48439 return $file if -f $file;
466             }
467              
468             # returning the still-relative filename is better than returning an undef
469 343         1955 return $filename;
470             }
471              
472             # has source code stored within the profile data file
473             sub has_savesrc {
474 630     630 0 1061 my $self = shift;
475 630         1819 return $self->profile->{fid_srclines}[ $self->fid ];
476             }
477              
478             sub srclines_array {
479 627     627 0 7934 my $self = shift;
480              
481 627 100       1673 if (my $srclines = $self->has_savesrc) {
482 300         1054 my $copy = [ @$srclines ]; # shallow clone
483 300         635 shift @$copy; # line 0 not used
484 300         1278 return $copy;
485             }
486              
487 327         1272 my $filename = $self->abs_filename;
488 327 50       7544 if (open my $fh, "<", $filename) {
489 0         0 return [ <$fh> ];
490             }
491              
492 327         3482 return undef;
493             }
494              
495             sub src_digest {
496 896     896 0 1947 my $self = shift;
497 896   100     2258 return $self->cache->{src_digest} ||= do {
498 608   100     2172 my $srclines_array = $self->srclines_array || [];
499 608         2403 my $src = join "\n", @$srclines_array;
500             # return empty string for digest if there's no src
501 608 100       5661 ($src) ? join ",", (
502             scalar @$srclines_array, # number of lines
503             length $src, # total length
504             unpack("%32C*",$src) ) # 32-bit checksum
505             : '';
506             };
507             }
508              
509              
510             sub normalize_for_test {
511 963     963 0 3216 my $self = shift;
512              
513             # normalize eval sequence numbers in 'file' names to 0
514             $self->[NYTP_FIDi_FILENAME] =~ s/ \( ((?:re_)?) eval \s \d+ \) /(${1}eval 0)/xg
515 963 100       10419 if not $ENV{NYTPROF_TEST_SKIP_EVAL_NORM};
516              
517             # normalize flags to avoid failures due to savesrc and perl version
518 963         3860 $self->[NYTP_FIDi_FLAGS] &= ~(NYTP_FIDf_HAS_SRC|NYTP_FIDf_SAVE_SRC);
519              
520             # '1' => { 'main::foo' => [ 1, '1.38e-05', '1.24e-05', ..., { 'main::RUNTIME' => undef } ] }
521 963         2177 for my $subscalled (values %{ $self->sub_call_lines }) {
  963         5555  
522              
523 2283         8104 for my $subname (keys %$subscalled) {
524 2395         5132 my $sc = $subscalled->{$subname};
525 2395         6795 $sc->[NYTP_SCi_INCL_RTIME] =
526             $sc->[NYTP_SCi_EXCL_RTIME] =
527             $sc->[NYTP_SCi_RECI_RTIME] = 0;
528              
529 2395 100       6822 if (not $ENV{NYTPROF_TEST_SKIP_EVAL_NORM}) {
530             # normalize eval sequence numbers in anon sub names to 0
531 2235         6141 (my $newname = $subname) =~ s/ \( ((?:re_)?) eval \s \d+ \) /(${1}eval 0)/xg;
532 2235 100       9406 if ($newname ne $subname) {
533             warn "Normalizing $subname to $newname overwrote other called-by data\n"
534 48 50       211 if $subscalled->{$newname};
535 48         366 $subscalled->{$newname} = delete $subscalled->{$subname};
536             }
537             }
538             }
539              
540             }
541             }
542              
543              
544             sub summary {
545 1     1 0 3 my ($fi) = @_;
546 1         4 return sprintf "fid%d: %s",
547             $fi->fid, $fi->filename_without_inc;
548             }
549              
550             sub dump {
551 962     962 0 4419 my ($self, $separator, $fh, $path, $prefix, $opts) = @_;
552              
553 962         2446 my @values = @{$self}[
  962         4861  
554             NYTP_FIDi_FILENAME, NYTP_FIDi_EVAL_FID, NYTP_FIDi_EVAL_LINE, NYTP_FIDi_FID,
555             NYTP_FIDi_FLAGS, NYTP_FIDi_FILESIZE, NYTP_FIDi_FILEMTIME
556             ];
557 962         6161 $values[0] = $self->filename_without_inc;
558             # also remove possible remaining perl version seen in some cpantesters
559             # http://www.cpantesters.org/cpan/report/bf913910-bfdd-11df-a657-c9f38a00995b
560 962         5415 $values[0] =~ s!^$Config{version}/!!o;
561              
562 962 50       3388 printf $fh "%s[ %s ]\n", $prefix, join(" ", map { defined($_) ? $_ : 'undef' } @values);
  6734         21300  
563              
564 962 100       5196 if (not $opts->{skip_internal_details}) {
565              
566 946         4542 for my $si ($self->subs_defined_sorted) {
567 2252         8238 my ($fl, $ll) = ($si->first_line, $si->last_line);
568 2252   100     9337 defined $_ or $_ = 'undef' for ($fl, $ll);
569 2252         6350 printf $fh "%s%s%s%s%s%s-%s\n",
570             $prefix, 'sub', $separator,
571             $si->subname(' and '), $separator,
572             $fl, $ll;
573             }
574              
575             # { line => { subname => [...] }, ... }
576 946         3153 my $sub_call_lines = $self->sub_call_lines;
577 946         3606 for my $line (sort { $a <=> $b } keys %$sub_call_lines) {
  3402         6721  
578 2146         4778 my $subs_called = $sub_call_lines->{$line};
579              
580 2146         5470 for my $subname (sort keys %$subs_called) {
581 2210         3527 my @sc = @{$subs_called->{$subname}};
  2210         6460  
582 2210         4741 $sc[NYTP_SCi_CALLING_SUB] = join "|", sort keys %{ $sc[NYTP_SCi_CALLING_SUB] };
  2210         7446  
583              
584             printf $fh "%s%s%s%s%s%s%s[ %s ]\n",
585             $prefix, 'call', $separator,
586             $line, $separator, $subname, $separator,
587 2210 50       5931 join(" ", map { defined($_) ? $_ : 'undef' } @sc)
  17680         47144  
588             }
589             }
590              
591             # string evals, group by the line the eval is on
592 946         2364 my %eval_lines;
593 946         2987 for my $eval_fi ($self->has_evals(0)) {
594 416         820 push @{ $eval_lines{ $eval_fi->eval_line } }, $eval_fi;
  416         1003  
595             }
596 946         7609 for my $line (sort { $a <=> $b } keys %eval_lines) {
  106         369  
597 368         901 my $eval_fis = $eval_lines{$line};
598              
599 368         821 my @has_evals = map { $_->has_evals(1) } @$eval_fis;
  416         900  
600 368 100       989 my @merged_fids = map { @{ $_->meta->{merged_fids}||[]} } @$eval_fis;
  416         660  
  416         1217  
601              
602 368         1588 printf $fh "%s%s%s%d%s[ count %d nested %d merged %d ]\n",
603             $prefix, 'eval', $separator,
604             $eval_fis->[0]->eval_line, $separator,
605             scalar @$eval_fis, # count of evals executed on this line
606             scalar @has_evals, # count of nested evals they executed
607             scalar @merged_fids, # count of evals merged (collapsed) away
608             }
609              
610             }
611              
612             }
613              
614             # vim: ts=8:sw=4:et
615             1;