Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / tools / perl-5.8.0 / bin / dprofpp
CommitLineData
86530b38
AT
1#!/import/bw/tools/local/perl-5.8.0/bin/perl
2 eval 'exec perl -S $0 "$@"'
3 if 0;
4
5require 5.003;
6
7my $VERSION = '20000000.00_01';
8
9=head1 NAME
10
11dprofpp - display perl profile data
12
13=head1 SYNOPSIS
14
15dprofpp [B<-a>|B<-z>|B<-l>|B<-v>|B<-U>] [B<-d>] [B<-s>|B<-r>|B<-u>] [B<-q>] [B<-F>] [B<-I|-E>] [B<-O cnt>] [B<-A>] [B<-R>] [B<-S>] [B<-g subroutine>] [B<-G> <regexp> [B<-P>]] [B<-f> <regexp>] [profile]
16
17dprofpp B<-T> [B<-F>] [B<-g subroutine>] [profile]
18
19dprofpp B<-t> [B<-F>] [B<-g subroutine>] [profile]
20
21dprofpp B<-G> <regexp> [B<-P>] [profile]
22
23dprofpp B<-p script> [B<-Q>] [other opts]
24
25dprofpp B<-V> [profile]
26
27=head1 DESCRIPTION
28
29The I<dprofpp> command interprets profile data produced by a profiler, such
30as the Devel::DProf profiler. Dprofpp will read the file F<tmon.out> and
31will display the 15 subroutines which are using the most time. By default
32the times for each subroutine are given exclusive of the times of their
33child subroutines.
34
35To profile a Perl script run the perl interpreter with the B<-d> switch. So
36to profile script F<test.pl> with Devel::DProf the following command should
37be used.
38
39 $ perl5 -d:DProf test.pl
40
41Then run dprofpp to analyze the profile. The output of dprofpp depends
42on the flags to the program and the version of Perl you're using.
43
44 $ dprofpp -u
45 Total Elapsed Time = 1.67 Seconds
46 User Time = 0.61 Seconds
47 Exclusive Times
48 %Time Seconds #Calls sec/call Name
49 52.4 0.320 2 0.1600 main::foo
50 45.9 0.280 200 0.0014 main::bar
51 0.00 0.000 1 0.0000 DynaLoader::import
52 0.00 0.000 1 0.0000 main::baz
53
54The dprofpp tool can also run the profiler before analyzing the profile
55data. The above two commands can be executed with one dprofpp command.
56
57 $ dprofpp -u -p test.pl
58
59Consult L<Devel::DProf/"PROFILE FORMAT"> for a description of the raw profile.
60
61=head1 OUTPUT
62
63Columns are:
64
65=over 4
66
67=item %Time
68
69Percentage of time spent in this routine.
70
71=item #Calls
72
73Number of calls to this routine.
74
75=item sec/call
76
77Average number of seconds per call to this routine.
78
79=item Name
80
81Name of routine.
82
83=item CumulS
84
85Time (in seconds) spent in this routine and routines called from it.
86
87=item ExclSec
88
89Time (in seconds) spent in this routine (not including those called
90from it).
91
92=item Csec/c
93
94Average time (in seconds) spent in each call of this routine
95(including those called from it).
96
97=back
98
99=head1 OPTIONS
100
101=over 5
102
103=item B<-a>
104
105Sort alphabetically by subroutine names.
106
107=item B<-d>
108
109Reverse whatever sort is used
110
111=item B<-A>
112
113Count timing for autoloaded subroutine as timing for C<*::AUTOLOAD>.
114Otherwise the time to autoload it is counted as time of the subroutine
115itself (there is no way to separate autoload time from run time).
116
117This is going to be irrelevant with newer Perls. They will inform
118C<Devel::DProf> I<when> the C<AUTOLOAD> switches to actual subroutine,
119so a separate statistics for C<AUTOLOAD> will be collected no matter
120whether this option is set.
121
122=item B<-R>
123
124Count anonymous subroutines defined in the same package separately.
125
126=item B<-E>
127
128(default) Display all subroutine times exclusive of child subroutine times.
129
130=item B<-F>
131
132Force the generation of fake exit timestamps if dprofpp reports that the
133profile is garbled. This is only useful if dprofpp determines that the
134profile is garbled due to missing exit timestamps. You're on your own if
135you do this. Consult the BUGS section.
136
137=item B<-I>
138
139Display all subroutine times inclusive of child subroutine times.
140
141=item B<-l>
142
143Sort by number of calls to the subroutines. This may help identify
144candidates for inlining.
145
146=item B<-O cnt>
147
148Show only I<cnt> subroutines. The default is 15.
149
150=item B<-p script>
151
152Tells dprofpp that it should profile the given script and then interpret its
153profile data. See B<-Q>.
154
155=item B<-Q>
156
157Used with B<-p> to tell dprofpp to quit after profiling the script, without
158interpreting the data.
159
160=item B<-q>
161
162Do not display column headers.
163
164=item B<-r>
165
166Display elapsed real times rather than user+system times.
167
168=item B<-s>
169
170Display system times rather than user+system times.
171
172=item B<-T>
173
174Display subroutine call tree to stdout. Subroutine statistics are
175not displayed.
176
177=item B<-t>
178
179Display subroutine call tree to stdout. Subroutine statistics are not
180displayed. When a function is called multiple consecutive times at the same
181calling level then it is displayed once with a repeat count.
182
183=item B<-S>
184
185Display I<merged> subroutine call tree to stdout. Statistics is
186displayed for each branch of the tree.
187
188When a function is called multiple (I<not necessarily consecutive>)
189times in the same branch then all these calls go into one branch of
190the next level. A repeat count is output together with combined
191inclusive, exclusive and kids time.
192
193Branches are sorted w.r.t. inclusive time.
194
195=item B<-U>
196
197Do not sort. Display in the order found in the raw profile.
198
199=item B<-u>
200
201Display user times rather than user+system times.
202
203=item B<-V>
204
205Print dprofpp's version number and exit. If a raw profile is found then its
206XS_VERSION variable will be displayed, too.
207
208=item B<-v>
209
210Sort by average time spent in subroutines during each call. This may help
211identify candidates for inlining.
212
213=item B<-z>
214
215(default) Sort by amount of user+system time used. The first few lines
216should show you which subroutines are using the most time.
217
218=item B<-g> C<subroutine>
219
220Ignore subroutines except C<subroutine> and whatever is called from it.
221
222=item B<-G> <regexp>
223
224Aggregate "Group" all calls matching the pattern together.
225For example this can be used to group all calls of a set of packages
226
227 -G "(package1::)|(package2::)|(package3::)"
228
229or to group subroutines by name:
230
231 -G "getNum"
232
233=item B<-P>
234
235Used with -G to aggregate "Pull" together all calls that did not match -G.
236
237=item B<-f> <regexp>
238
239Filter all calls matching the pattern.
240
241=back
242
243=head1 ENVIRONMENT
244
245The environment variable B<DPROFPP_OPTS> can be set to a string containing
246options for dprofpp. You might use this if you prefer B<-I> over B<-E> or
247if you want B<-F> on all the time.
248
249This was added fairly lazily, so there are some undesirable side effects.
250Options on the commandline should override options in DPROFPP_OPTS--but
251don't count on that in this version.
252
253=head1 BUGS
254
255Applications which call _exit() or exec() from within a subroutine
256will leave an incomplete profile. See the B<-F> option.
257
258Any bugs in Devel::DProf, or any profiler generating the profile data, could
259be visible here. See L<Devel::DProf/BUGS>.
260
261Mail bug reports and feature requests to the perl5-porters mailing list at
262F<E<lt>perl5-porters@perl.orgE<gt>>. Bug reports should include the
263output of the B<-V> option.
264
265=head1 FILES
266
267 dprofpp - profile processor
268 tmon.out - raw profile
269
270=head1 SEE ALSO
271
272L<perl>, L<Devel::DProf>, times(2)
273
274=cut
275
276use Getopt::Std 'getopts';
277use Config '%Config';
278
279Setup: {
280 my $options = 'O:g:G:Pf:dlzaAvuTtqrRsUFEIp:QVS';
281
282 $Monfile = 'tmon.out';
283 if( exists $ENV{DPROFPP_OPTS} ){
284 my @tmpargv = @ARGV;
285 @ARGV = split( ' ', $ENV{DPROFPP_OPTS} );
286 getopts( $options );
287 if( @ARGV ){
288 # there was a filename.
289 $Monfile = shift;
290 }
291 @ARGV = @tmpargv;
292 }
293
294 getopts( $options );
295 if( @ARGV ){
296 # there was a filename, it overrides any earlier name.
297 $Monfile = shift;
298 }
299
300# -O cnt Specifies maximum number of subroutines to display.
301# -a Sort by alphabetic name of subroutines.
302# -z Sort by user+system time spent in subroutines. (default)
303# -l Sort by number of calls to subroutines.
304# -v Sort by average amount of time spent in subroutines.
305# -T Show call tree.
306# -t Show call tree, compressed.
307# -q Do not print column headers.
308# -u Use user time rather than user+system time.
309# -s Use system time rather than user+system time.
310# -r Use real elapsed time rather than user+system time.
311# -U Do not sort subroutines.
312# -E Sub times are reported exclusive of child times. (default)
313# -I Sub times are reported inclusive of child times.
314# -V Print dprofpp's version.
315# -p script Specifies name of script to be profiled.
316# -Q Used with -p to indicate the dprofpp should quit after
317# profiling the script, without interpreting the data.
318# -A count autoloaded to *AUTOLOAD
319# -R count anonyms separately even if from the same package
320# -g subr count only those who are SUBR or called from SUBR
321# -S Create statistics for all the depths
322
323# -G Group all calls matching the pattern together.
324# -P Used with -G to pull all other calls together.
325# -f Filter all calls mathcing the pattern.
326# -d Reverse sort
327
328 if( defined $opt_V ){
329 my $fh = 'main::fh';
330 print "$0 version: $VERSION\n";
331 open( $fh, "<$Monfile" ) && do {
332 local $XS_VERSION = 'early';
333 header($fh);
334 close( $fh );
335 print "XS_VERSION: $XS_VERSION\n";
336 };
337 exit(0);
338 }
339 $cnt = $opt_O || 15;
340 $sort = 'by_time';
341 $sort = 'by_ctime' if defined $opt_I;
342 $sort = 'by_calls' if defined $opt_l;
343 $sort = 'by_alpha' if defined $opt_a;
344 $sort = 'by_avgcpu' if defined $opt_v;
345
346 if(defined $opt_d){
347 $sort = "r".$sort;
348 }
349 $incl_excl = 'Exclusive';
350 $incl_excl = 'Inclusive' if defined $opt_I;
351 $whichtime = 'User+System';
352 $whichtime = 'System' if defined $opt_s;
353 $whichtime = 'Real' if defined $opt_r;
354 $whichtime = 'User' if defined $opt_u;
355
356 if( defined $opt_p ){
357 my $prof = 'DProf';
358 my $startperl = $Config{'startperl'};
359
360 $startperl =~ s/^#!//; # remove shebang
361 run_profiler( $opt_p, $prof, $startperl );
362 $Monfile = 'tmon.out'; # because that's where it is
363 exit(0) if defined $opt_Q;
364 }
365 elsif( defined $opt_Q ){
366 die "-Q is meaningful only when used with -p\n";
367 }
368}
369
370Main: {
371 my $monout = $Monfile;
372 my $fh = 'main::fh';
373 local $names = {};
374 local $times = {}; # times in hz
375 local $ctimes = {}; # Cumulative times in hz
376 local $calls = {};
377 local $persecs = {}; # times in seconds
378 local $idkeys = [];
379 local $runtime; # runtime in seconds
380 my @a = ();
381 my $a;
382 local $rrun_utime = 0; # user time in hz
383 local $rrun_stime = 0; # system time in hz
384 local $rrun_rtime = 0; # elapsed run time in hz
385 local $rrun_ustime = 0; # user+system time in hz
386 local $hz = 0;
387 local $deep_times = {count => 0 , kids => {}, incl_time => 0};
388 local $time_precision = 2;
389 local $overhead = 0;
390
391 open( $fh, "<$monout" ) || die "Unable to open $monout\n";
392
393 header($fh);
394
395 $rrun_ustime = $rrun_utime + $rrun_stime;
396
397 $~ = 'STAT';
398 if( ! $opt_q ){
399 $^ = 'CSTAT_top';
400 }
401
402 parsestack( $fh, $names, $calls, $times, $ctimes, $idkeys );
403
404 #filter calls
405 if( $opt_f ){
406 for(my $i = 0;$i < @$idkeys - 2;){
407 $key = $$idkeys[$i];
408 if($key =~ /$opt_f/){
409 splice(@$idkeys, $i, 1);
410 $runtime -= $$times{$key};
411 next;
412 }
413 $i++;
414 }
415 }
416
417 if( $opt_G ){
418 group($names, $calls, $times, $ctimes, $idkeys );
419 }
420
421 settime( \$runtime, $hz ) unless $opt_g;
422
423 exit(0) if $opt_T || $opt_t;
424
425 if( $opt_v ){
426 percalc( $calls, ($opt_I ? $ctimes : $times), $persecs, $idkeys );
427 }
428 if( ! $opt_U ){
429 @a = sort $sort @$idkeys;
430 $a = \@a;
431 }
432 else {
433 $a = $idkeys;
434 }
435 display( $runtime, $hz, $names, $calls, $times, $ctimes, $cnt, $a,
436 $deep_times);
437}
438
439sub group{
440 my ($names, $calls, $times, $ctimes, $idkeys ) = @_;
441 print "Option G Grouping: [$opt_G]\n";
442 # create entries to store grouping
443 $$names{$opt_G} = $opt_G;
444 $$calls{$opt_G} = 0;
445 $$times{$opt_G} = 0;
446 $$ctimes{$opt_G} = 0;
447 $$idkeys[@$idkeys] = $opt_G;
448 # Sum calls for the grouping
449
450 my $other = "other";
451 if($opt_P){
452 $$names{$other} = $other;
453 $$calls{$other} = 0;
454 $$times{$other} = 0;
455 $$ctimes{$other} = 0;
456 $$idkeys[@$idkeys] = $other;
457 }
458
459 for(my $i = 0;$i < @$idkeys - 2;){
460 $key = $$idkeys[$i];
461 if($key =~ /$opt_G/){
462 $$calls{$opt_G} += $$calls{$key};
463 $$times{$opt_G} += $$times{$key};
464 $$ctimes{$opt_G} += $$ctimes{$key};
465 splice(@$idkeys, $i, 1);
466 next;
467 }else{
468 if($opt_P){
469 $$calls{$other} += $$calls{$key};
470 $$times{$other} += $$times{$key};
471 $$ctimes{$other} += $$ctimes{$key};
472 splice(@$idkeys, $i, 1);
473 next;
474 }
475 }
476 $i++;
477 }
478 print "Grouping [$opt_G] Calls: [$$calls{$opt_G}]\n".
479 "Grouping [$opt_G] Times: [$$times{$opt_G}]\n".
480 "Grouping [$opt_G] IncTimes: [$$ctimes{$opt_G}]\n";
481}
482
483# Sets $runtime to user, system, real, or user+system time. The
484# result is given in seconds.
485#
486sub settime {
487 my( $runtime, $hz ) = @_;
488
489 $hz ||= 1;
490
491 if( $opt_r ){
492 $$runtime = ($rrun_rtime - $overhead - $over_rtime * $total_marks/$over_tests/2)/$hz;
493 }
494 elsif( $opt_s ){
495 $$runtime = ($rrun_stime - $overhead - $over_stime * $total_marks/$over_tests/2)/$hz;
496 }
497 elsif( $opt_u ){
498 $$runtime = ($rrun_utime - $overhead - $over_utime * $total_marks/$over_tests/2)/$hz;
499 }
500 else{
501 $$runtime = ($rrun_ustime - $overhead - ($over_utime + $over_stime) * $total_marks/$over_tests/2)/$hz;
502 }
503 $$runtime = 0 unless $$runtime > 0;
504}
505
506sub exclusives_in_tree {
507 my( $deep_times ) = @_;
508 my $kids_time = 0;
509 my $kid;
510 # When summing, take into account non-rounded-up kids time.
511 for $kid (keys %{$deep_times->{kids}}) {
512 $kids_time += $deep_times->{kids}{$kid}{incl_time};
513 }
514 $kids_time = 0 unless $kids_time >= 0;
515 $deep_times->{excl_time} = $deep_times->{incl_time} - $kids_time;
516 $deep_times->{excl_time} = 0 unless $deep_times->{excl_time} >= 0;
517 for $kid (keys %{$deep_times->{kids}}) {
518 exclusives_in_tree($deep_times->{kids}{$kid});
519 }
520 $deep_times->{incl_time} = 0 unless $deep_times->{incl_time} >= 0;
521 $deep_times->{kids_time} = $kids_time;
522}
523
524sub kids_by_incl { $kids{$b}{incl_time} <=> $kids{$a}{excl_time}
525 or $a cmp $b }
526
527sub display_tree {
528 my( $deep_times, $name, $level ) = @_;
529 exclusives_in_tree($deep_times);
530
531 my $kid;
532 local *kids = $deep_times->{kids}; # %kids
533
534 my $time;
535 if (%kids) {
536 $time = sprintf '%.*fs = (%.*f + %.*f)',
537 $time_precision, $deep_times->{incl_time}/$hz,
538 $time_precision, $deep_times->{excl_time}/$hz,
539 $time_precision, $deep_times->{kids_time}/$hz;
540 } else {
541 $time = sprintf '%.*f', $time_precision, $deep_times->{incl_time}/$hz;
542 }
543 print ' ' x (2*$level), "$name x $deep_times->{count} \t${time}s\n"
544 if $deep_times->{count};
545
546 for $kid (sort kids_by_incl keys %kids) {
547 display_tree( $deep_times->{kids}{$kid}, $kid, $level + 1 );
548 }
549}
550
551# Report the times in seconds.
552sub display {
553 my( $runtime, $hz, $names, $calls, $times, $ctimes, $cnt,
554 $idkeys, $deep_times ) = @_;
555 my( $x, $key, $s, $cs );
556 #format: $ncalls, $name, $secs, $percall, $pcnt
557
558 if ($opt_S) {
559 display_tree( $deep_times, 'toplevel', -1 )
560 } else {
561 for( $x = 0; $x < @$idkeys; ++$x ){
562 $key = $idkeys->[$x];
563 $ncalls = $calls->{$key};
564 $name = $names->{$key};
565 $s = $times->{$key}/$hz;
566 $secs = sprintf("%.3f", $s );
567 $cs = $ctimes->{$key}/$hz;
568 $csecs = sprintf("%.3f", $cs );
569 $percall = sprintf("%.4f", $s/$ncalls );
570 $cpercall = sprintf("%.4f", $cs/$ncalls );
571 $pcnt = sprintf("%.2f",
572 $runtime? ((($opt_I ? $csecs : $secs) / $runtime) * 100.0): 0 );
573 write;
574 $pcnt = $secs = $ncalls = $percall = "";
575 write while( length $name );
576 last unless --$cnt;
577 }
578 }
579}
580
581sub move_keys {
582 my ($source, $dest) = @_;
583 my $kid;
584
585 for $kid (keys %$source) {
586 if (exists $dest->{$kid}) {
587 $dest->{count} += $source->{count};
588 $dest->{incl_time} += $source->{incl_time};
589 move_keys($source->{kids},$dest->{kids});
590 } else {
591 $dest->{$kid} = delete $source->{$kid};
592 }
593 }
594}
595
596sub add_to_tree {
597 my ($curdeep_times, $name, $t) = @_;
598 if ($name ne $curdeep_times->[-1]{name} and $opt_A) {
599 $name = $curdeep_times->[-1]{name};
600 }
601 die "Shorted?!" unless @$curdeep_times >= 2;
602 $curdeep_times->[-2]{kids}{$name} = { count => 0 , kids => {},
603 incl_time => 0,
604 }
605 unless exists $curdeep_times->[-2]{kids}{$name};
606 my $entry = $curdeep_times->[-2]{kids}{$name};
607 # Now transfer to the new node (could not do earlier, since name can change)
608 $entry->{count}++;
609 $entry->{incl_time} += $t - $curdeep_times->[-1]{enter_stamp};
610 # Merge the kids?
611 move_keys($curdeep_times->[-1]->{kids},$entry->{kids});
612 pop @$curdeep_times;
613}
614
615
616sub parsestack {
617 my( $fh, $names, $calls, $times, $ctimes, $idkeys ) = @_;
618 my( $dir, $name );
619 my( $t, $syst, $realt, $usert );
620 my( $x, $z, $c, $id, $pack );
621 my @stack = ();
622 my @tstack = ();
623 my $tab = 3;
624 my $in = 0;
625
626 # remember last call depth and function name
627 my $l_in = $in;
628 my $l_name = '';
629 my $repcnt = 0;
630 my $repstr = '';
631 my $dprof_t = 0;
632 my $dprof_stamp;
633 my %cv_hash;
634 my $in_level = not defined $opt_g; # Level deep in report grouping
635 my $curdeep_times = [$deep_times];
636
637 my $over_per_call;
638 if ( $opt_u ) { $over_per_call = $over_utime }
639 elsif( $opt_s ) { $over_per_call = $over_stime }
640 elsif( $opt_r ) { $over_per_call = $over_rtime }
641 else { $over_per_call = $over_utime + $over_stime }
642 $over_per_call /= 2*$over_tests; # distribute over entry and exit
643
644 while(<$fh>){
645 next if /^#/;
646 last if /^PART/;
647
648 chop;
649 if (/^&/) {
650 ($dir, $id, $pack, $name) = split;
651 if ($opt_R and ($name =~ /(?:::)?(__ANON__|END)$/)) {
652 $name .= "($id)";
653 }
654 $cv_hash{$id} = "$pack\::$name";
655 next;
656 }
657 ($dir, $usert, $syst, $realt, $name) = split;
658
659 my $ot = $t;
660 if ( $dir eq '/' ) {
661 $syst = $stack[-1][0];
662 $usert = '&';
663 $dir = '-';
664 #warn("Inserted exit for $stack[-1][0].\n")
665 }
666 if (defined $realt) { # '+ times nam' '- times nam' or '@ incr'
667 if ( $opt_u ) { $t = $usert }
668 elsif( $opt_s ) { $t = $syst }
669 elsif( $opt_r ) { $t = $realt }
670 else { $t = $usert + $syst }
671 $t += $ot, next if $dir eq '@'; # Increments there
672 } else {
673 # "- id" or "- & name"
674 $name = defined $syst ? $syst : $cv_hash{$usert};
675 }
676
677 next unless $in_level or $name eq $opt_g or $dir eq '*';
678 if ( $dir eq '-' or $dir eq '*' ) {
679 my $ename = $dir eq '*' ? $stack[-1][0] : $name;
680 $overhead += $over_per_call;
681 if ($name eq "Devel::DProf::write") {
682 $dprof_t += $t - $dprof_stamp;
683 next;
684 } elsif (defined $opt_g and $ename eq $opt_g) {
685 $in_level--;
686 }
687 add_to_tree($curdeep_times, $ename,
688 $t - $dprof_t - $overhead) if $opt_S;
689 exitstamp( \@stack, \@tstack,
690 $t - $dprof_t - $overhead,
691 $times, $ctimes, $ename, \$in, $tab,
692 $curdeep_times );
693 }
694 next unless $in_level or $name eq $opt_g;
695 if( $dir eq '+' or $dir eq '*' ){
696 if ($name eq "Devel::DProf::write") {
697 $dprof_stamp = $t;
698 next;
699 } elsif (defined $opt_g and $name eq $opt_g) {
700 $in_level++;
701 }
702 $overhead += $over_per_call;
703 if( $opt_T ){
704 print ' ' x $in, "$name\n";
705 $in += $tab;
706 }
707 elsif( $opt_t ){
708 # suppress output on same function if the
709 # same calling level is called.
710 if ($l_in == $in and $l_name eq $name) {
711 $repcnt++;
712 } else {
713 $repstr = ' ('.++$repcnt.'x)'
714 if $repcnt;
715 print ' ' x $l_in, "$l_name$repstr\n"
716 if $l_name ne '';
717 $repstr = '';
718 $repcnt = 0;
719 $l_in = $in;
720 $l_name = $name;
721 }
722 $in += $tab;
723 }
724 if( ! defined $names->{$name} ){
725 $names->{$name} = $name;
726 $times->{$name} = 0;
727 $ctimes->{$name} = 0;
728 push( @$idkeys, $name );
729 }
730 $calls->{$name}++;
731 push @$curdeep_times, { kids => {},
732 name => $name,
733 enter_stamp => $t - $dprof_t - $overhead,
734 } if $opt_S;
735 $x = [ $name, $t - $dprof_t - $overhead ];
736 push( @stack, $x );
737
738 # my children will put their time here
739 push( @tstack, 0 );
740 } elsif ($dir ne '-'){
741 die "Bad profile: $_";
742 }
743 }
744 if( $opt_t ){
745 $repstr = ' ('.++$repcnt.'x)' if $repcnt;
746 print ' ' x $l_in, "$l_name$repstr\n";
747 }
748
749 if( @stack ){
750 if( ! $opt_F ){
751 warn "Garbled profile is missing some exit time stamps:\n";
752 foreach $x (@stack) {
753 print $x->[0],"\n";
754 }
755 die "Try rerunning dprofpp with -F.\n";
756 # I don't want -F to be default behavior--yet
757 # 9/18/95 dmr
758 }
759 else{
760 warn( "Faking " . scalar( @stack ) . " exit timestamp(s).\n");
761 foreach $x ( reverse @stack ){
762 $name = $x->[0];
763 exitstamp( \@stack, \@tstack,
764 $t - $dprof_t - $overhead, $times,
765 $ctimes, $name, \$in, $tab,
766 $curdeep_times );
767 add_to_tree($curdeep_times, $name,
768 $t - $dprof_t - $overhead)
769 if $opt_S;
770 }
771 }
772 }
773 if (defined $opt_g) {
774 $runtime = $ctimes->{$opt_g}/$hz;
775 $runtime = 0 unless $runtime > 0;
776 }
777}
778
779sub exitstamp {
780 my($stack, $tstack, $t, $times, $ctimes, $name, $in, $tab, $deep) = @_;
781 my( $x, $c, $z );
782
783 $x = pop( @$stack );
784 if( ! defined $x ){
785 die "Garbled profile, missing an enter time stamp";
786 }
787 if( $x->[0] ne $name and $opt_G and ($name =~ /$opt_G/)){
788 if ($x->[0] =~ /(?:::)?AUTOLOAD$/) {
789 if ($opt_A) {
790 $name = $x->[0];
791 }
792 } elsif ( $opt_F ) {
793 warn( "Garbled profile, faking exit timestamp:\n\t$name => $x->[0].\n");
794 $name = $x->[0];
795 } else {
796 foreach $z (@stack, $x) {
797 print $z->[0],"\n";
798 }
799 die "Garbled profile, unexpected exit time stamp";
800 }
801 }
802 if( $opt_T || $opt_t ){
803 $$in -= $tab;
804 }
805 # collect childtime
806 $c = pop( @$tstack );
807 # total time this func has been active
808 $z = $t - $x->[1];
809 $ctimes->{$name} += $z;
810 $times->{$name} += ($z > $c)? $z - $c: 0;
811 # pass my time to my parent
812 if( @$tstack ){
813 $c = pop( @$tstack );
814 push( @$tstack, $c + $z );
815 }
816}
817
818
819sub header {
820 my $fh = shift;
821 chop($_ = <$fh>);
822 if( ! /^#fOrTyTwO$/ ){
823 die "Not a perl profile";
824 }
825 while(<$fh>){
826 next if /^#/;
827 last if /^PART/;
828 eval;
829 }
830 $over_tests = 1 unless $over_tests;
831 $time_precision = length int ($hz - 1); # log ;-)
832}
833
834
835# Report avg time-per-function in seconds
836sub percalc {
837 my( $calls, $times, $persecs, $idkeys ) = @_;
838 my( $x, $t, $n, $key );
839
840 for( $x = 0; $x < @$idkeys; ++$x ){
841 $key = $idkeys->[$x];
842 $n = $calls->{$key};
843 $t = $times->{$key} / $hz;
844 $persecs->{$key} = $t ? $t / $n : 0;
845 }
846}
847
848
849# Runs the given script with the given profiler and the given perl.
850sub run_profiler {
851 my $script = shift;
852 my $profiler = shift;
853 my $startperl = shift;
854 my @script_parts = split /\s+/, $script;
855
856 system $startperl, "-d:$profiler", @script_parts;
857 if( $? / 256 > 0 ){
858 my $cmd = join ' ', @script_parts;
859 die "Failed: $startperl -d:$profiler $cmd: $!";
860 }
861}
862
863
864sub by_time { $times->{$b} <=> $times->{$a} }
865sub by_ctime { $ctimes->{$b} <=> $ctimes->{$a} }
866sub by_calls { $calls->{$b} <=> $calls->{$a} }
867sub by_alpha { $names->{$a} cmp $names->{$b} }
868sub by_avgcpu { $persecs->{$b} <=> $persecs->{$a} }
869# Reversed
870sub rby_time { $times->{$a} <=> $times->{$b} }
871sub rby_ctime { $ctimes->{$a} <=> $ctimes->{$b} }
872sub rby_calls { $calls->{$a} <=> $calls->{$b} }
873sub rby_alpha { $names->{$b} cmp $names->{$a} }
874sub rby_avgcpu { $persecs->{$a} <=> $persecs->{$b} }
875
876
877format CSTAT_top =
878Total Elapsed Time = @>>>>>>> Seconds
879(($rrun_rtime - $overhead - $over_rtime * $total_marks/$over_tests/2) / $hz)
880 @>>>>>>>>>> Time = @>>>>>>> Seconds
881$whichtime, $runtime
882@<<<<<<<< Times
883$incl_excl
884%Time ExclSec CumulS #Calls sec/call Csec/c Name
885.
886
887format STAT =
888 ^>>> ^>>>> ^>>>>> ^>>>>> ^>>>>> ^>>>>> ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
889$pcnt, $secs, $csecs, $ncalls, $percall, $cpercall, $name
890.
891