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   334 use strict;
  48         99  
  48         1420  
12              
13 48     48   260 use Carp;
  48         117  
  48         2737  
14 48     48   294 use Config;
  48         118  
  48         1811  
15 48     48   342 use List::Util qw(sum);
  48         129  
  48         3295  
16              
17 48     48   21577 use Devel::NYTProf::Util qw(strip_prefix_from_paths trace_level);
  48         592  
  48         4101  
18              
19 48         8407 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   20009 );
  48         141  
32              
33             # extra constants for private elements
34             use constant {
35 48         193690 NYTP_FIDi_meta => NYTP_FIDi_elements + 1,
36             NYTP_FIDi_cache => NYTP_FIDi_elements + 2,
37 48     48   424 };
  48         231  
38              
39 17928     17928 0 96654 sub filename { shift->[NYTP_FIDi_FILENAME()] }
40 465     465 0 2867 sub eval_fid { shift->[NYTP_FIDi_EVAL_FID()] }
41 3825     3825 0 26769 sub eval_line { shift->[NYTP_FIDi_EVAL_LINE()] }
42 22222     22222 0 118720 sub fid { shift->[NYTP_FIDi_FID()] }
43 1     1 0 5 sub size { shift->[NYTP_FIDi_FILESIZE()] }
44 1     1 0 10 sub mtime { shift->[NYTP_FIDi_FILEMTIME()] }
45 2636     2636 0 9174 sub profile { shift->[NYTP_FIDi_PROFILE()] }
46 387     387 0 1512 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 108 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 181 sub is_eval { shift->[NYTP_FIDi_EVAL_FI()] ? 1 : 0 }
52              
53 23     23 0 71 sub is_fake { shift->flags & NYTP_FIDf_IS_FAKE }
54             sub is_file {
55 4     4 0 9 my $self = shift;
56 4   33     11 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 8533 sub meta { shift->[NYTP_FIDi_meta()] ||= {} }
61             # general purpose cache
62 928   100 928 0 8894 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 10653 my ($self, $include_nested) = @_;
67              
68 4078 100       19403 my $eval_fis = $self->[NYTP_FIDi_HAS_EVALS()]
69             or return;
70 848 100       5106 return @$eval_fis if !$include_nested;
71              
72 96         325 my @eval_fis = @$eval_fis;
73             # walk down tree of nested evals, adding them to @fi
74 96         361 for (my $i=0; my $fi = $eval_fis[$i]; ++$i) {
75 112         448 push @eval_fis, $fi->has_evals(0);
76             }
77              
78 96         354 return @eval_fis;
79             }
80              
81              
82             sub sibling_evals {
83 1     1 0 5 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   575 my $self = shift;
93 224         1557 @$self = (); # Zap!
94             }
95              
96              
97              
98             # return subs defined as list of SubInfo objects
99             sub subs_defined {
100 1561     1561 0 4418 my ($self, $incl_nested_evals) = @_;
101              
102 1561 50       4396 return map { $_->subs_defined(0) } $self, $self->has_evals(1)
  0         0  
103             if $incl_nested_evals;
104              
105 1561         2975 return values %{ $self->[NYTP_FIDi_SUBS_DEFINED()] };
  1561         14909  
106             }
107              
108             sub subs_defined_sorted {
109 1139     1139 0 3980 my ($self, $incl_nested_evals) = @_;
110 1139         4722 return sort { $a->subname cmp $b->subname } $self->subs_defined($incl_nested_evals);
  3357         11054  
111             }
112              
113             sub _remove_sub_defined {
114 256     256   751 my ($self, $si) = @_;
115 256         1026 my $subname = $si->subname;
116 256 50       1286 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   952 my ($self, $subinfo) = @_;
123 240         1063 my $subname = $subinfo->subname;
124 240   50     1048 my $subs_defined = $self->[NYTP_FIDi_SUBS_DEFINED()] ||= {};
125 240         665 my $existing_si = $subs_defined->{$subname};
126 240 50       731 croak sprintf "sub %s already defined in fid %d %s",
127             $subname, $self->fid, $self->filename
128             if $existing_si;
129              
130 240         1148 $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 11573 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 118 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         44 my %evals_by_line;
187 19         58 for my $fi ($self->has_evals) {
188 0         0 $evals_by_line{ $fi->eval_line }->{ $fi->fid } = $fi;
189             }
190              
191 19         186 return \%evals_by_line;
192             }
193              
194              
195             sub line_time_data {
196 468     468 0 1400 my ($self, $levels) = @_;
197 468   100     4093 $levels ||= [ 'line' ];
198             # XXX this can be optimized once the fidinfo contains directs refs to the data
199 468         1412 my $profile = $self->profile;
200 468         1214 my $fid = $self->fid;
201 468         1536 for my $level (@$levels) {
202 468         3413 my $fid_ary = $profile->get_fid_line_data($level);
203 468 50 33     3816 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 2 my $self = shift;
210 1   50     5 my $line_data = $self->line_time_data([qw(sub block line)])
211             || return undef;
212 1         2 my $excl_time = 0;
213 1         5 for (@$line_data) {
214 19 100       41 next unless $_;
215 6         10 $excl_time += $_->[0];
216             }
217 1         3 return $excl_time;
218             }
219              
220              
221             sub sum_of_stmts_count {
222 16     16 0 9138 my ($self, $incl_nested_evals) = @_;
223              
224 16 50       56 return sum(map { $_->sum_of_stmts_count(0) } $self, $self->has_evals(1))
  0         0  
225             if $incl_nested_evals;
226              
227 16         93 my $ref = \$self->cache->{NYTP_FIDi_sum_stmts_count};
228 16 50       91 $$ref = $self->_sum_of_line_time_data(1)
229             if not defined $$ref;
230              
231 16         142 return $$ref;
232             }
233              
234             sub sum_of_stmts_time {
235 16     16 0 49 my ($self, $incl_nested_evals) = @_;
236              
237 16 50       57 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       118 $$ref = $self->_sum_of_line_time_data(0)
242             if not defined $$ref;
243              
244 16         114 return $$ref;
245             }
246              
247             sub _sum_of_line_time_data {
248 32     32   103 my ($self, $idx) = @_;
249 32         65 my $line_time_data = $self->line_time_data;
250 32         65 my $sum = 0;
251 32   100     361 $sum += $_->[$idx]||0 for @$line_time_data;
252 32         95 return $sum;
253             }
254              
255              
256             sub outer {
257 1     1 0 5 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 1342 return (shift->flags & NYTP_FIDf_IS_PMC());
273             }
274              
275              
276             sub collapse_sibling_evals {
277 192     192 0 1112 my ($self, $survivor_fi, @donors) = @_;
278 192         797 my $profile = $self->profile;
279              
280             die "Can't collapse_sibling_evals of non-sibling evals"
281 192 50       629 if grep { $_->eval_fid != $survivor_fi->eval_fid or
  224 50       885  
282             $_->eval_line != $survivor_fi->eval_line
283             } @donors;
284              
285 192         1569 my $s_ltd = $survivor_fi->line_time_data; # XXX line only
286 192         854 my $s_scl = $survivor_fi->sub_call_lines;
287 192         436 my %donor_fids;
288              
289 192         1247 for my $donor_fi (@donors) {
290             # copy data from donor to survivor_fi then delete donor
291 224         894 my $donor_fid = $donor_fi->fid;
292 224         1825 $donor_fids{$donor_fid} = $donor_fi;
293              
294 224 50       1308 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       716 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       1041 if (my @subs_defined = $donor_fi->subs_defined) {
306              
307 128         452 for my $si (@subs_defined) {
308 128 50       560 warn sprintf " - moving from fid %d: sub %s\n",
309             $donor_fid, $si->subname
310             if trace_level() >= 4;
311 128         1640 $si->_alter_fileinfo($donor_fi, $survivor_fi);
312 128 50       765 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       741 if (my $sub_call_lines = $donor_fi->sub_call_lines) {
321              
322 224         457 my %subnames_called_by_donor;
323              
324             # merge details of subs called from $donor_fi
325 224         1315 while ( my ($line, $sc_hash) = each %$sub_call_lines ) {
326 176   50     775 my $s_sc_hash = $s_scl->{$line} ||= {};
327 176         766 for my $subname (keys %$sc_hash ) {
328 176   100     1214 my $s_sc_info = $s_sc_hash->{$subname} ||= [];
329 176         601 my $sc_info = delete $sc_hash->{$subname};
330 176         2666 Devel::NYTProf::SubInfo::_merge_in_caller_info($s_sc_info, $sc_info,
331             tag => "line $line calls to $subname",
332             );
333              
334 176         1972 $subnames_called_by_donor{$subname}++;
335             }
336             }
337 224         781 %$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         1699 for keys %subnames_called_by_donor;
342             }
343              
344             # copy line time data
345 224   50     982 my $d_ltd = $donor_fi->line_time_data || []; # XXX line only
346 224         1449 for my $line (0..@$d_ltd-1) {
347 544 100       1743 my $d_tld_l = $d_ltd->[$line] or next;
348 320   50     1200 my $s_tld_l = $s_ltd->[$line] ||= [];
349 320         1240 $s_tld_l->[$_] += $d_tld_l->[$_] for (0..@$d_tld_l-1);
350 320         693 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         476 push @{ $survivor_fi->meta->{merged_fids} }, $donor_fid;
  224         1016  
355             ++$survivor_fi->meta->{merged_fids_src_varied}
356 224 50       877 if $donor_fi->src_digest ne $survivor_fi->src_digest;
357              
358 224         1085 $donor_fi->_nullify;
359             }
360              
361             # remove donors from parent NYTP_FIDi_HAS_EVALS
362 192 50       1445 if (my $eval_fis = $self->[NYTP_FIDi_HAS_EVALS()]) {
363 192         723 my %donors = map { +"$_" => 1 } @donors;
  224         2813  
364 192         738 my $count = @$eval_fis;
365 192         596 @$eval_fis = grep { !$donors{$_} } @$eval_fis;
  722         2524  
366 192 50       1678 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     1148 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       1285 if (my @subs_defined = $survivor_fi->subs_defined_sorted) {
380              
381             # bucket anon subs by normalized name
382 112         345 my %newname;
383 112         434 for my $si (@subs_defined) {
384 240 50       1375 next unless $si->is_anon;
385 240         913 (my $newname = $si->subname) =~ s/ \( ((?:re_)?) eval \s \d+ \) /(${1}eval 0)/xg;
386 240         706 push @{ $newname{$newname} }, $si;
  240         1540  
387             }
388              
389 112         806 while ( my ($newname, $to_merge) = each %newname ) {
390 112         385 my $survivor_si = shift @$to_merge;
391 112 50       488 next unless @$to_merge; # nothing to do
392              
393 112         427 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       653 join ", ", map { $_->subname } @$to_merge
  0         0  
397             if trace_level() >= 3;
398              
399 112         379 for my $delete_si (@$to_merge) {
400 128         368 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         3258 for my $caller_fid ($delete_si->caller_fids) {
405 128         968 my $caller_fi = $profile->fileinfo_of($caller_fid);
406             # sub_call_lines ==> { line => { sub => ... } }
407 128         291 for my $subs_called_on_line (values %{ $caller_fi->sub_call_lines }) {
  128         389  
408 704 100       2039 my $sc_info = delete $subs_called_on_line->{$delete_subname}
409             or next;
410 128   50     492 my $s_sc_info = $subs_called_on_line->{$survivor_subname} ||= [];
411 128         752 Devel::NYTProf::SubInfo::_merge_in_caller_info($s_sc_info, $sc_info,
412             tag => "collapse eval $delete_subname",
413             );
414             }
415             }
416              
417 128         771 $survivor_si->merge_in($delete_si);
418 128         511 $survivor_fi->_remove_sub_defined($delete_si);
419 128         682 $profile->_disconnect_subinfo($delete_si);
420             }
421             }
422             }
423              
424 192 50       1424 warn sprintf "collapse_sibling_evals done for ".$survivor_fi->filename."\n"
425             if trace_level() >= 2;
426              
427 192         777 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 2726 my $self = shift;
437 989         3015 my $f = [$self->filename];
438 989         3417 strip_prefix_from_paths([$self->profile->inc], $f,
439             qr/(?: ^ | \[ | \sdefined\sat\s )/x
440             );
441 989         6590 return $f->[0];
442             }
443              
444              
445             sub abs_filename {
446 343     343 0 807 my $self = shift;
447              
448 343         1306 my $filename = $self->filename;
449              
450             # strip of autosplit annotation, if any
451 343         1251 $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       1235 $filename .= "c" if $self->is_pmc;
456              
457             # search profile @INC if filename is not absolute
458 343         1118 my @files = ($filename);
459 343 100       1192 if ($filename !~ m/^\//) {
460 340         843 my @inc = $self->profile->inc;
461 340         1212 @files = map { "$_/$filename" } @inc;
  4420         12379  
462             }
463              
464 343         1207 for my $file (@files) {
465 4423 50       49220 return $file if -f $file;
466             }
467              
468             # returning the still-relative filename is better than returning an undef
469 343         2073 return $filename;
470             }
471              
472             # has source code stored within the profile data file
473             sub has_savesrc {
474 630     630 0 1354 my $self = shift;
475 630         1877 return $self->profile->{fid_srclines}[ $self->fid ];
476             }
477              
478             sub srclines_array {
479 627     627 0 9495 my $self = shift;
480              
481 627 100       1956 if (my $srclines = $self->has_savesrc) {
482 300         1219 my $copy = [ @$srclines ]; # shallow clone
483 300         771 shift @$copy; # line 0 not used
484 300         1221 return $copy;
485             }
486              
487 327         1292 my $filename = $self->abs_filename;
488 327 50       7720 if (open my $fh, "<", $filename) {
489 0         0 return [ <$fh> ];
490             }
491              
492 327         3570 return undef;
493             }
494              
495             sub src_digest {
496 896     896 0 2097 my $self = shift;
497 896   100     2410 return $self->cache->{src_digest} ||= do {
498 608   100     2148 my $srclines_array = $self->srclines_array || [];
499 608         2451 my $src = join "\n", @$srclines_array;
500             # return empty string for digest if there's no src
501 608 100       5644 ($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 3115 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       10030 if not $ENV{NYTPROF_TEST_SKIP_EVAL_NORM};
516              
517             # normalize flags to avoid failures due to savesrc and perl version
518 963         3440 $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         2053 for my $subscalled (values %{ $self->sub_call_lines }) {
  963         5396  
522              
523 2283         7379 for my $subname (keys %$subscalled) {
524 2395         4941 my $sc = $subscalled->{$subname};
525 2395         6344 $sc->[NYTP_SCi_INCL_RTIME] =
526             $sc->[NYTP_SCi_EXCL_RTIME] =
527             $sc->[NYTP_SCi_RECI_RTIME] = 0;
528              
529 2395 100       6366 if (not $ENV{NYTPROF_TEST_SKIP_EVAL_NORM}) {
530             # normalize eval sequence numbers in anon sub names to 0
531 2235         5917 (my $newname = $subname) =~ s/ \( ((?:re_)?) eval \s \d+ \) /(${1}eval 0)/xg;
532 2235 100       8432 if ($newname ne $subname) {
533             warn "Normalizing $subname to $newname overwrote other called-by data\n"
534 48 50       166 if $subscalled->{$newname};
535 48         328 $subscalled->{$newname} = delete $subscalled->{$subname};
536             }
537             }
538             }
539              
540             }
541             }
542              
543              
544             sub summary {
545 1     1 0 5 my ($fi) = @_;
546 1         5 return sprintf "fid%d: %s",
547             $fi->fid, $fi->filename_without_inc;
548             }
549              
550             sub dump {
551 962     962 0 4594 my ($self, $separator, $fh, $path, $prefix, $opts) = @_;
552              
553 962         2496 my @values = @{$self}[
  962         4832  
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         5824 $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         5282 $values[0] =~ s!^$Config{version}/!!o;
561              
562 962 50       3554 printf $fh "%s[ %s ]\n", $prefix, join(" ", map { defined($_) ? $_ : 'undef' } @values);
  6734         20937  
563              
564 962 100       5294 if (not $opts->{skip_internal_details}) {
565              
566 946         4700 for my $si ($self->subs_defined_sorted) {
567 2252         8031 my ($fl, $ll) = ($si->first_line, $si->last_line);
568 2252   100     9177 defined $_ or $_ = 'undef' for ($fl, $ll);
569 2252         6394 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         3462 my $sub_call_lines = $self->sub_call_lines;
577 946         3727 for my $line (sort { $a <=> $b } keys %$sub_call_lines) {
  3352         6713  
578 2146         4779 my $subs_called = $sub_call_lines->{$line};
579              
580 2146         5627 for my $subname (sort keys %$subs_called) {
581 2210         3611 my @sc = @{$subs_called->{$subname}};
  2210         6287  
582 2210         4153 $sc[NYTP_SCi_CALLING_SUB] = join "|", sort keys %{ $sc[NYTP_SCi_CALLING_SUB] };
  2210         7330  
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       6041 join(" ", map { defined($_) ? $_ : 'undef' } @sc)
  17680         47308  
588             }
589             }
590              
591             # string evals, group by the line the eval is on
592 946         2367 my %eval_lines;
593 946         2890 for my $eval_fi ($self->has_evals(0)) {
594 416         832 push @{ $eval_lines{ $eval_fi->eval_line } }, $eval_fi;
  416         1033  
595             }
596 946         7510 for my $line (sort { $a <=> $b } keys %eval_lines) {
  100         347  
597 368         933 my $eval_fis = $eval_lines{$line};
598              
599 368         847 my @has_evals = map { $_->has_evals(1) } @$eval_fis;
  416         968  
600 368 100       913 my @merged_fids = map { @{ $_->meta->{merged_fids}||[]} } @$eval_fis;
  416         663  
  416         1263  
601              
602 368         1474 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;