line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Devel::NYTProf::SubInfo; # sub_subinfo |
2
|
|
|
|
|
|
|
|
3
|
48
|
|
|
48
|
|
367
|
use strict; |
|
48
|
|
|
|
|
122
|
|
|
48
|
|
|
|
|
1482
|
|
4
|
48
|
|
|
48
|
|
271
|
use warnings; |
|
48
|
|
|
|
|
97
|
|
|
48
|
|
|
|
|
1217
|
|
5
|
48
|
|
|
48
|
|
275
|
use Carp; |
|
48
|
|
|
|
|
96
|
|
|
48
|
|
|
|
|
2738
|
|
6
|
|
|
|
|
|
|
|
7
|
48
|
|
|
48
|
|
293
|
use List::Util qw(min max); |
|
48
|
|
|
|
|
107
|
|
|
48
|
|
|
|
|
2875
|
|
8
|
48
|
|
|
48
|
|
936
|
use Data::Dumper; |
|
48
|
|
|
|
|
8747
|
|
|
48
|
|
|
|
|
2749
|
|
9
|
|
|
|
|
|
|
|
10
|
48
|
|
|
|
|
3176
|
use Devel::NYTProf::Util qw( |
11
|
|
|
|
|
|
|
trace_level |
12
|
48
|
|
|
48
|
|
353
|
); |
|
48
|
|
|
|
|
153
|
|
13
|
48
|
|
|
|
|
6767
|
use Devel::NYTProf::Constants qw( |
14
|
|
|
|
|
|
|
NYTP_SIi_FID NYTP_SIi_FIRST_LINE NYTP_SIi_LAST_LINE |
15
|
|
|
|
|
|
|
NYTP_SIi_CALL_COUNT NYTP_SIi_INCL_RTIME NYTP_SIi_EXCL_RTIME |
16
|
|
|
|
|
|
|
NYTP_SIi_SUB_NAME NYTP_SIi_PROFILE |
17
|
|
|
|
|
|
|
NYTP_SIi_REC_DEPTH NYTP_SIi_RECI_RTIME NYTP_SIi_CALLED_BY |
18
|
|
|
|
|
|
|
NYTP_SIi_elements |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
NYTP_SCi_CALL_COUNT |
21
|
|
|
|
|
|
|
NYTP_SCi_INCL_RTIME NYTP_SCi_EXCL_RTIME NYTP_SCi_RECI_RTIME |
22
|
|
|
|
|
|
|
NYTP_SCi_REC_DEPTH NYTP_SCi_CALLING_SUB |
23
|
|
|
|
|
|
|
NYTP_SCi_elements |
24
|
48
|
|
|
48
|
|
340
|
); |
|
48
|
|
|
|
|
100
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# extra constants for private elements |
27
|
|
|
|
|
|
|
use constant { |
28
|
48
|
|
|
|
|
148964
|
NYTP_SIi_meta => NYTP_SIi_elements + 1, |
29
|
|
|
|
|
|
|
NYTP_SIi_cache => NYTP_SIi_elements + 2, |
30
|
48
|
|
|
48
|
|
398
|
}; |
|
48
|
|
|
|
|
166
|
|
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
|
33
|
3346
|
100
|
|
3346
|
0
|
22382
|
sub fid { shift->[NYTP_SIi_FID] || 0 } |
34
|
|
|
|
|
|
|
|
35
|
2376
|
|
|
2376
|
0
|
7271
|
sub first_line { shift->[NYTP_SIi_FIRST_LINE] } |
36
|
|
|
|
|
|
|
|
37
|
2270
|
|
|
2270
|
0
|
6327
|
sub last_line { shift->[NYTP_SIi_LAST_LINE] } |
38
|
|
|
|
|
|
|
|
39
|
6899
|
|
|
6899
|
0
|
85309
|
sub calls { shift->[NYTP_SIi_CALL_COUNT] } |
40
|
|
|
|
|
|
|
|
41
|
7
|
|
|
7
|
0
|
2216
|
sub incl_time { shift->[NYTP_SIi_INCL_RTIME] } |
42
|
|
|
|
|
|
|
|
43
|
1
|
|
|
1
|
0
|
5
|
sub excl_time { shift->[NYTP_SIi_EXCL_RTIME] } |
44
|
|
|
|
|
|
|
|
45
|
11470
|
|
|
11470
|
0
|
111929
|
sub subname { shift->[NYTP_SIi_SUB_NAME] } |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub subname_without_package { |
48
|
1
|
|
|
1
|
0
|
528
|
my $subname = shift->[NYTP_SIi_SUB_NAME]; |
49
|
1
|
|
|
|
|
8
|
$subname =~ s/.*:://; |
50
|
1
|
|
|
|
|
6
|
return $subname; |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
2452
|
|
|
2452
|
0
|
5772
|
sub profile { shift->[NYTP_SIi_PROFILE] } |
54
|
|
|
|
|
|
|
|
55
|
1
|
|
|
1
|
0
|
3
|
sub package { (my $pkg = shift->subname) =~ s/^(.*)::.*/$1/; return $pkg } |
|
1
|
|
|
|
|
5
|
|
56
|
|
|
|
|
|
|
|
57
|
1
|
|
|
1
|
0
|
5
|
sub recur_max_depth { shift->[NYTP_SIi_REC_DEPTH] } |
58
|
|
|
|
|
|
|
|
59
|
1
|
|
|
1
|
0
|
5
|
sub recur_incl_time { shift->[NYTP_SIi_RECI_RTIME] } |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# general purpose hash - mainly a hack to help kill off Reader.pm |
63
|
2390
|
|
100
|
2390
|
0
|
21203
|
sub meta { shift->[NYTP_SIi_meta()] ||= {} } |
64
|
|
|
|
|
|
|
# general purpose cache |
65
|
1
|
|
50
|
1
|
0
|
11
|
sub cache { shift->[NYTP_SIi_cache()] ||= {} } |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
# { fid => { line => [ count, incl_time ] } } |
69
|
|
|
|
|
|
|
sub caller_fid_line_places { |
70
|
2558
|
|
|
2558
|
0
|
61582
|
my ($self, $merge_evals) = @_; |
71
|
2558
|
50
|
|
|
|
6185
|
carp "caller_fid_line_places doesn't merge evals yet" if $merge_evals; |
72
|
|
|
|
|
|
|
# shallow clone to remove fid 0 is_sub hack |
73
|
2558
|
100
|
|
|
|
4140
|
my %tmp = %{ $self->[NYTP_SIi_CALLED_BY] || {} }; |
|
2558
|
|
|
|
|
15061
|
|
74
|
2558
|
|
|
|
|
6479
|
delete $tmp{0}; |
75
|
2558
|
|
|
|
|
9181
|
return \%tmp; |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub called_by_subnames { |
79
|
96
|
|
|
96
|
0
|
45424
|
my ($self) = @_; |
80
|
96
|
|
50
|
|
|
442
|
my $callers = $self->caller_fid_line_places || {}; |
81
|
|
|
|
|
|
|
|
82
|
96
|
|
|
|
|
250
|
my %subnames; |
83
|
96
|
|
|
|
|
358
|
for my $sc (map { values %$_ } values %$callers) { |
|
128
|
|
|
|
|
917
|
|
84
|
144
|
|
|
|
|
407
|
my $caller_subnames = $sc->[NYTP_SCi_CALLING_SUB]; |
85
|
144
|
|
|
|
|
661
|
@subnames{ keys %$caller_subnames } = (); # viv keys |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
96
|
|
|
|
|
454
|
return \%subnames; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub is_xsub { |
92
|
15
|
|
|
15
|
0
|
21
|
my $self = shift; |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
# XXX should test == 0 but some xsubs still have undef first_line etc |
95
|
|
|
|
|
|
|
# XXX shouldn't include opcode |
96
|
15
|
|
|
|
|
24
|
my $first = $self->first_line; |
97
|
15
|
50
|
|
|
|
28
|
return undef if not defined $first; |
98
|
15
|
100
|
66
|
|
|
30
|
return 1 if $first == 0 && $self->last_line == 0; |
99
|
12
|
|
|
|
|
22
|
return 0; |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub is_opcode { |
103
|
18
|
|
|
18
|
0
|
26
|
my $self = shift; |
104
|
18
|
100
|
66
|
|
|
28
|
return 0 if $self->first_line or $self->last_line; |
105
|
6
|
100
|
|
|
|
12
|
return 1 if $self->subname =~ m/(?:^CORE::|::CORE:)\w+$/; |
106
|
3
|
|
|
|
|
9
|
return 0; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub is_anon { |
110
|
336
|
|
|
336
|
0
|
1141
|
shift->subname =~ m/::__ANON__\b/; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub kind { |
114
|
18
|
|
|
18
|
0
|
28
|
my $self = shift; |
115
|
18
|
100
|
|
|
|
29
|
return 'opcode' if $self->is_opcode; |
116
|
15
|
100
|
|
|
|
39
|
return 'xsub' if $self->is_xsub; |
117
|
12
|
|
|
|
|
23
|
return 'perl'; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
sub fileinfo { |
121
|
1
|
|
|
1
|
0
|
2
|
my $self = shift; |
122
|
1
|
|
|
|
|
4
|
my $fid = $self->fid; |
123
|
1
|
50
|
|
|
|
4
|
if (!$fid) { |
124
|
0
|
|
|
|
|
0
|
return undef; # sub not have a known fid |
125
|
|
|
|
|
|
|
} |
126
|
1
|
|
|
|
|
3
|
$self->profile->fileinfo_of($fid); |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub clone { # shallow |
130
|
2
|
|
|
2
|
0
|
3
|
my $self = shift; |
131
|
2
|
|
|
|
|
9
|
return bless [ @$self ] => ref $self; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub _min { |
135
|
138
|
|
|
138
|
|
415
|
my ($a, $b) = @_; |
136
|
138
|
50
|
|
|
|
445
|
$a = $b if not defined $a; |
137
|
138
|
50
|
|
|
|
383
|
$b = $a if not defined $b; |
138
|
|
|
|
|
|
|
# either both are defined or both are undefined here |
139
|
138
|
50
|
|
|
|
352
|
return undef unless defined $a; |
140
|
138
|
|
|
|
|
717
|
return min($a, $b); |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub _max { |
144
|
138
|
|
|
138
|
|
433
|
my ($a, $b) = @_; |
145
|
138
|
50
|
|
|
|
431
|
$a = $b if not defined $a; |
146
|
138
|
50
|
|
|
|
389
|
$b = $a if not defined $b; |
147
|
|
|
|
|
|
|
# either both are defined or both are undefined here |
148
|
138
|
50
|
|
|
|
311
|
return undef unless defined $a; |
149
|
138
|
|
|
|
|
384
|
return max($a, $b); |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub _alter_fileinfo { |
154
|
240
|
|
|
240
|
|
1158
|
my ($self, $remove_fi, $new_fi) = @_; |
155
|
240
|
100
|
|
|
|
1065
|
my $remove_fid = ($remove_fi) ? $remove_fi->fid : 0; |
156
|
240
|
50
|
|
|
|
1131
|
my $new_fid = ( $new_fi) ? $new_fi->fid : 0; |
157
|
|
|
|
|
|
|
|
158
|
240
|
50
|
|
|
|
680
|
if ($self->fid == $remove_fid) { |
159
|
240
|
|
|
|
|
641
|
$self->[NYTP_SIi_FID] = $new_fid; |
160
|
|
|
|
|
|
|
|
161
|
240
|
100
|
|
|
|
1312
|
$remove_fi->_remove_sub_defined($self) if $remove_fi; |
162
|
240
|
50
|
|
|
|
2289
|
$new_fi->_add_new_sub_defined($self) if $new_fi; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
sub _alter_called_by_fileinfo { |
168
|
176
|
|
|
176
|
|
614
|
my ($self, $remove_fi, $new_fi) = @_; |
169
|
176
|
50
|
|
|
|
874
|
my $remove_fid = ($remove_fi) ? $remove_fi->fid : 0; |
170
|
176
|
50
|
|
|
|
714
|
my $new_fid = ( $new_fi) ? $new_fi->fid : 0; |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
# remove mentions of $remove_fid from called-by details |
173
|
|
|
|
|
|
|
# { fid => { line => [ count, incl, excl, ... ] } } |
174
|
176
|
50
|
|
|
|
642
|
if (my $called_by = $self->[NYTP_SIi_CALLED_BY]) { |
175
|
176
|
|
|
|
|
837
|
my $cb = delete $called_by->{$remove_fid}; |
176
|
|
|
|
|
|
|
|
177
|
176
|
50
|
33
|
|
|
2042
|
if ($cb && $new_fid) { |
178
|
176
|
|
100
|
|
|
1023
|
my $new_cb = $called_by->{$new_fid} ||= {}; |
179
|
|
|
|
|
|
|
|
180
|
176
|
50
|
|
|
|
820
|
warn sprintf "_alter_called_by_fileinfo: %s from fid %d to fid %d\n", |
181
|
|
|
|
|
|
|
$self->subname, $remove_fid, $new_fid |
182
|
|
|
|
|
|
|
if trace_level() >= 4; |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
# merge $cb into $new_cb |
185
|
176
|
|
|
|
|
1051
|
while ( my ($line, $cb_li) = each %$cb ) { |
186
|
176
|
|
100
|
|
|
886
|
my $dst_line_info = $new_cb->{$line} ||= []; |
187
|
176
|
|
|
|
|
1213
|
_merge_in_caller_info($dst_line_info, delete $cb->{$line}, |
188
|
|
|
|
|
|
|
tag => "$line:".$self->subname, |
189
|
|
|
|
|
|
|
); |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# merge details of another sub into this one |
201
|
|
|
|
|
|
|
# there are very few cases where this is sane thing to do |
202
|
|
|
|
|
|
|
# it's meant for merging things like anon-subs in evals |
203
|
|
|
|
|
|
|
# e.g., "PPI::Node::__ANON__[(eval 286)[PPI/Node.pm:642]:4]" |
204
|
|
|
|
|
|
|
sub merge_in { |
205
|
138
|
|
|
138
|
0
|
433
|
my ($self, $donor, %opts) = @_; |
206
|
138
|
|
|
|
|
380
|
my $self_subname = $self->subname; |
207
|
138
|
|
|
|
|
366
|
my $donor_subname = $donor->subname; |
208
|
|
|
|
|
|
|
|
209
|
138
|
50
|
|
|
|
527
|
warn sprintf "Merging sub %s into %s (%s)\n", |
210
|
|
|
|
|
|
|
$donor_subname, $self_subname, join(" ", %opts) |
211
|
|
|
|
|
|
|
if trace_level() >= 4; |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
# see also "case NYTP_TAG_SUB_CALLERS:" in load_profile_data_from_stream() |
214
|
138
|
|
|
|
|
252
|
push @{ $self->meta->{merged_sub_names} }, $donor->subname; |
|
138
|
|
|
|
|
616
|
|
215
|
|
|
|
|
|
|
|
216
|
138
|
|
|
|
|
767
|
$self->[NYTP_SIi_FIRST_LINE] = _min($self->[NYTP_SIi_FIRST_LINE], $donor->[NYTP_SIi_FIRST_LINE]); |
217
|
138
|
|
|
|
|
673
|
$self->[NYTP_SIi_LAST_LINE] = _max($self->[NYTP_SIi_LAST_LINE], $donor->[NYTP_SIi_LAST_LINE]); |
218
|
138
|
|
|
|
|
398
|
$self->[NYTP_SIi_CALL_COUNT] += $donor->[NYTP_SIi_CALL_COUNT]; |
219
|
138
|
|
|
|
|
298
|
$self->[NYTP_SIi_INCL_RTIME] += $donor->[NYTP_SIi_INCL_RTIME]; |
220
|
138
|
|
|
|
|
267
|
$self->[NYTP_SIi_EXCL_RTIME] += $donor->[NYTP_SIi_EXCL_RTIME]; |
221
|
138
|
|
|
|
|
340
|
$self->[NYTP_SIi_REC_DEPTH] = max($self->[NYTP_SIi_REC_DEPTH], $donor->[NYTP_SIi_REC_DEPTH]); |
222
|
|
|
|
|
|
|
# adding reci_rtime is correct only if one sub doesn't call the other |
223
|
138
|
|
|
|
|
302
|
$self->[NYTP_SIi_RECI_RTIME] += $donor->[NYTP_SIi_RECI_RTIME]; # XXX |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
# { fid => { line => [ count, incl_time, ... ] } } |
226
|
138
|
|
50
|
|
|
370
|
my $dst_called_by = $self ->[NYTP_SIi_CALLED_BY] ||= {}; |
227
|
138
|
|
100
|
|
|
370
|
my $src_called_by = $donor->[NYTP_SIi_CALLED_BY] || {}; |
228
|
|
|
|
|
|
|
|
229
|
138
|
|
33
|
|
|
1690
|
$opts{opts} ||= "merge in $donor_subname"; |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# iterate over src and merge into dst |
232
|
138
|
|
|
|
|
710
|
while (my ($fid, $src_line_hash) = each %$src_called_by) { |
233
|
|
|
|
|
|
|
|
234
|
135
|
|
|
|
|
322
|
my $dst_line_hash = $dst_called_by->{$fid}; |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# merge lines in %$src_line_hash into %$dst_line_hash |
237
|
135
|
|
|
|
|
821
|
for my $line (keys %$src_line_hash) { |
238
|
148
|
|
100
|
|
|
593
|
my $dst_line_info = $dst_line_hash->{$line} ||= []; |
239
|
148
|
|
|
|
|
267
|
my $src_line_info = $src_line_hash->{$line}; |
240
|
148
|
100
|
|
|
|
503
|
delete $src_line_hash->{$line} unless $opts{src_keep}; |
241
|
148
|
|
|
|
|
522
|
_merge_in_caller_info($dst_line_info, $src_line_info, %opts); |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
138
|
|
|
|
|
510
|
return; |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub _merge_in_caller_info { |
250
|
628
|
|
|
628
|
|
2824
|
my ($dst_line_info, $src_line_info, %opts) = @_; |
251
|
628
|
100
|
|
|
|
3313
|
my $tag = ($opts{tag}) ? " $opts{tag}" : ""; |
252
|
|
|
|
|
|
|
|
253
|
628
|
50
|
|
|
|
1980
|
if (!@$src_line_info) { |
254
|
0
|
0
|
|
|
|
0
|
carp sprintf "_merge_in_caller_info%s skipped (empty donor)", $tag |
255
|
|
|
|
|
|
|
if trace_level(); |
256
|
0
|
|
|
|
|
0
|
return; |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
628
|
50
|
|
|
|
2435
|
if (trace_level() >= 5) { |
260
|
0
|
|
|
|
|
0
|
carp sprintf "_merge_in_caller_info%s merging from $src_line_info -> $dst_line_info:", $tag; |
261
|
0
|
|
|
|
|
0
|
warn sprintf " . %s\n", _fmt_sc($src_line_info); |
262
|
0
|
|
|
|
|
0
|
warn sprintf " + %s\n", _fmt_sc($dst_line_info); |
263
|
|
|
|
|
|
|
} |
264
|
628
|
100
|
|
|
|
1782
|
if (!@$dst_line_info) { |
265
|
78
|
|
|
|
|
315
|
@$dst_line_info = (0) x NYTP_SCi_elements; |
266
|
78
|
|
|
|
|
168
|
$dst_line_info->[NYTP_SCi_CALLING_SUB] = undef; |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# merge @$src_line_info into @$dst_line_info |
270
|
628
|
|
|
|
|
2990
|
$dst_line_info->[$_] += $src_line_info->[$_] for ( |
271
|
|
|
|
|
|
|
NYTP_SCi_CALL_COUNT, NYTP_SCi_INCL_RTIME, NYTP_SCi_EXCL_RTIME, |
272
|
|
|
|
|
|
|
); |
273
|
628
|
|
|
|
|
2192
|
$dst_line_info->[NYTP_SCi_REC_DEPTH] = max($dst_line_info->[NYTP_SCi_REC_DEPTH], |
274
|
|
|
|
|
|
|
$src_line_info->[NYTP_SCi_REC_DEPTH]); |
275
|
|
|
|
|
|
|
# ug, we can't really combine recursive incl_time, but this is better than undef |
276
|
628
|
|
|
|
|
1616
|
$dst_line_info->[NYTP_SCi_RECI_RTIME] = max($dst_line_info->[NYTP_SCi_RECI_RTIME], |
277
|
|
|
|
|
|
|
$src_line_info->[NYTP_SCi_RECI_RTIME]); |
278
|
|
|
|
|
|
|
|
279
|
628
|
|
50
|
|
|
2123
|
my $src_cs = $src_line_info->[NYTP_SCi_CALLING_SUB]|| {}; |
280
|
628
|
|
100
|
|
|
2046
|
my $dst_cs = $dst_line_info->[NYTP_SCi_CALLING_SUB]||={}; |
281
|
628
|
|
|
|
|
2395
|
$dst_cs->{$_} = $src_cs->{$_} for keys %$src_cs; |
282
|
|
|
|
|
|
|
|
283
|
628
|
50
|
|
|
|
2300
|
warn sprintf " = %s\n", _fmt_sc($dst_line_info) |
284
|
|
|
|
|
|
|
if trace_level() >= 5; |
285
|
|
|
|
|
|
|
|
286
|
628
|
|
|
|
|
3305
|
return; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
sub _fmt_sc { |
290
|
0
|
|
|
0
|
|
0
|
my ($sc) = @_; |
291
|
0
|
0
|
|
|
|
0
|
return "(empty)" if !@$sc; |
292
|
0
|
|
0
|
|
|
0
|
my $dst_cs = $sc->[NYTP_SCi_CALLING_SUB]||{}; |
293
|
0
|
|
|
|
|
0
|
my $by = join " & ", sort keys %$dst_cs; |
294
|
0
|
0
|
|
|
|
0
|
sprintf "calls %d%s", |
295
|
|
|
|
|
|
|
$sc->[NYTP_SCi_CALL_COUNT], ($by) ? ", by $by" : ""; |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
sub caller_fids { |
300
|
128
|
|
|
128
|
0
|
414
|
my ($self, $merge_evals) = @_; |
301
|
128
|
|
50
|
|
|
877
|
my $callers = $self->caller_fid_line_places($merge_evals) || {}; |
302
|
128
|
|
|
|
|
596
|
my @fids = keys %$callers; |
303
|
128
|
|
|
|
|
746
|
return @fids; # count in scalar context |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
|
306
|
1
|
|
|
1
|
0
|
10
|
sub caller_count { return scalar shift->caller_places; } # XXX deprecate later |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
# array of [ $fid, $line, $sub_call_info ], ... |
309
|
|
|
|
|
|
|
sub caller_places { |
310
|
2254
|
|
|
2254
|
0
|
5295
|
my ($self, $merge_evals) = @_; |
311
|
2254
|
|
50
|
|
|
8401
|
my $callers = $self->caller_fid_line_places || {}; |
312
|
|
|
|
|
|
|
|
313
|
2254
|
|
|
|
|
3975
|
my @callers; |
314
|
2254
|
|
|
|
|
10509
|
for my $fid (sort { $a <=> $b } keys %$callers) { |
|
201
|
|
|
|
|
794
|
|
315
|
1416
|
|
|
|
|
3287
|
my $lines_hash = $callers->{$fid}; |
316
|
1416
|
|
|
|
|
6507
|
for my $line (sort { $a <=> $b } keys %$lines_hash) { |
|
1188
|
|
|
|
|
4949
|
|
317
|
2210
|
|
|
|
|
7501
|
push @callers, [ $fid, $line, $lines_hash->{$line} ]; |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
2254
|
|
|
|
|
8021
|
return @callers; # scalar: number of distinct calling locations |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
sub normalize_for_test { |
325
|
2450
|
|
|
2450
|
0
|
5694
|
my $self = shift; |
326
|
2450
|
|
|
|
|
8300
|
my $profile = $self->profile; |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
# normalize eval sequence numbers in anon sub names to 0 |
329
|
|
|
|
|
|
|
$self->[NYTP_SIi_SUB_NAME] =~ s/ \( ((?:re_)?) eval \s \d+ \) /(${1}eval 0)/xg |
330
|
|
|
|
|
|
|
if $self->[NYTP_SIi_SUB_NAME] =~ m/__ANON__/ |
331
|
2450
|
100
|
100
|
|
|
13260
|
&& not $ENV{NYTPROF_TEST_SKIP_EVAL_NORM}; |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
# zero subroutine inclusive time |
334
|
2450
|
|
|
|
|
6228
|
$self->[NYTP_SIi_INCL_RTIME] = 0; |
335
|
2450
|
|
|
|
|
5542
|
$self->[NYTP_SIi_EXCL_RTIME] = 0; |
336
|
2450
|
|
|
|
|
5245
|
$self->[NYTP_SIi_RECI_RTIME] = 0; |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
# { fid => { line => [ count, incl, excl, ... ] } } |
339
|
2450
|
|
100
|
|
|
13615
|
my $callers = $self->[NYTP_SIi_CALLED_BY] || {}; |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
# calls from modules shipped with perl cause problems for tests |
342
|
|
|
|
|
|
|
# because the line numbers vary between perl versions, so here we |
343
|
|
|
|
|
|
|
# edit the line number of calls from these modules |
344
|
2450
|
|
|
|
|
11570
|
for my $fid (keys %$callers) { |
345
|
2015
|
100
|
|
|
|
6586
|
next if not $fid; |
346
|
1548
|
50
|
|
|
|
6395
|
my $fileinfo = $profile->fileinfo_of($fid) or next; |
347
|
1548
|
100
|
|
|
|
4793
|
next if $fileinfo->filename !~ /(AutoLoader|Exporter)\.pm$/; |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
# normalize the lines X,Y,Z to 1,2,3 |
350
|
144
|
|
|
|
|
321
|
my %lines = %{ delete $callers->{$fid} }; |
|
144
|
|
|
|
|
687
|
|
351
|
144
|
|
|
|
|
856
|
my @lines = @lines{sort { $a <=> $b } keys %lines}; |
|
32
|
|
|
|
|
343
|
|
352
|
144
|
|
|
|
|
411
|
$callers->{$fid} = { map { $_ => shift @lines } 1..@lines }; |
|
176
|
|
|
|
|
1022
|
|
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
|
355
|
2450
|
|
|
|
|
8152
|
for my $sc (map { values %$_ } values %$callers) { |
|
2015
|
|
|
|
|
8580
|
|
356
|
|
|
|
|
|
|
# zero per-call-location subroutine inclusive time |
357
|
2395
|
|
|
|
|
7938
|
$sc->[NYTP_SCi_INCL_RTIME] = |
358
|
|
|
|
|
|
|
$sc->[NYTP_SCi_EXCL_RTIME] = |
359
|
|
|
|
|
|
|
$sc->[NYTP_SCi_RECI_RTIME] = 0; |
360
|
|
|
|
|
|
|
|
361
|
2395
|
100
|
|
|
|
7050
|
if (not $ENV{NYTPROF_TEST_SKIP_EVAL_NORM}) { |
362
|
|
|
|
|
|
|
# normalize eval sequence numbers in anon sub names to 0 |
363
|
2235
|
|
50
|
|
|
6252
|
my $names = $sc->[NYTP_SCi_CALLING_SUB]||{}; |
364
|
2235
|
|
|
|
|
7278
|
for my $subname (keys %$names) { |
365
|
2235
|
|
|
|
|
6429
|
(my $newname = $subname) =~ s/ \( ((?:re_)?) eval \s \d+ \) /(${1}eval 0)/xg; |
366
|
2235
|
100
|
|
|
|
7991
|
next if $newname eq $subname; |
367
|
|
|
|
|
|
|
warn "Normalizing $subname to $newname overwrote other calling-sub data\n" |
368
|
16
|
50
|
|
|
|
103
|
if $names->{$newname}; |
369
|
16
|
|
|
|
|
107
|
$names->{$newname} = delete $names->{$subname}; |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
} |
374
|
2450
|
|
|
|
|
9453
|
return $self->[NYTP_SIi_SUB_NAME]; |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
sub dump { |
378
|
2252
|
|
|
2252
|
0
|
6783
|
my ($self, $separator, $fh, $path, $prefix) = @_; |
379
|
|
|
|
|
|
|
|
380
|
2252
|
|
|
|
|
4044
|
my ($fid, $l1, $l2, $calls) = @{$self}[ |
|
2252
|
|
|
|
|
7174
|
|
381
|
|
|
|
|
|
|
NYTP_SIi_FID, NYTP_SIi_FIRST_LINE, NYTP_SIi_LAST_LINE, NYTP_SIi_CALL_COUNT |
382
|
|
|
|
|
|
|
]; |
383
|
2252
|
|
|
|
|
4656
|
my @values = @{$self}[ |
|
2252
|
|
|
|
|
5837
|
|
384
|
|
|
|
|
|
|
NYTP_SIi_INCL_RTIME, NYTP_SIi_EXCL_RTIME, |
385
|
|
|
|
|
|
|
NYTP_SIi_REC_DEPTH, NYTP_SIi_RECI_RTIME |
386
|
|
|
|
|
|
|
]; |
387
|
|
|
|
|
|
|
printf $fh "%s[ %s:%s-%s calls %s times %s ]\n", |
388
|
|
|
|
|
|
|
$prefix, |
389
|
9008
|
100
|
|
|
|
18947
|
map({ defined($_) ? $_ : 'undef' } $fid, $l1, $l2, $calls), |
390
|
2252
|
50
|
|
|
|
5459
|
join(" ", map { defined($_) ? $_ : 'undef' } @values); |
|
9008
|
|
|
|
|
28284
|
|
391
|
|
|
|
|
|
|
|
392
|
2252
|
|
|
|
|
9662
|
my @caller_places = $self->caller_places; |
393
|
2252
|
|
|
|
|
6566
|
for my $cp (@caller_places) { |
394
|
2210
|
|
|
|
|
5672
|
my ($fid, $line, $sc) = @$cp; |
395
|
2210
|
|
|
|
|
5184
|
my @sc = @$sc; |
396
|
2210
|
|
|
|
|
3362
|
$sc[NYTP_SCi_CALLING_SUB] = join "|", sort keys %{ $sc[NYTP_SCi_CALLING_SUB] }; |
|
2210
|
|
|
|
|
6681
|
|
397
|
|
|
|
|
|
|
printf $fh "%s%s%s%d:%d%s[ %s ]\n", |
398
|
|
|
|
|
|
|
$prefix, |
399
|
|
|
|
|
|
|
'called_by', $separator, |
400
|
|
|
|
|
|
|
$fid, $line, $separator, |
401
|
2210
|
50
|
|
|
|
5488
|
join(" ", map { defined($_) ? $_ : 'undef' } @sc); |
|
17680
|
|
|
|
|
45575
|
|
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
# where a sub has had others merged into it, list them |
405
|
2252
|
|
100
|
|
|
7305
|
my $merge_subs = $self->meta->{merged_sub_names} || []; |
406
|
2252
|
|
|
|
|
13223
|
for my $ms (sort @$merge_subs) { |
407
|
80
|
|
|
|
|
556
|
printf $fh "%s%s%s%s\n", |
408
|
|
|
|
|
|
|
$prefix, 'merge_donor', $separator, $ms; |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
} |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
# vim:ts=8:sw=4:et |
413
|
|
|
|
|
|
|
1; |