B-Stats
view release on metacpan or search on metacpan
lib/B/Stats.pm view on Meta::CPAN
=head1 NAME
B::Stats - print optree statistics
=head1 SYNOPSIS
perl -MB::Stats myprog.pl # all
perl -MO=Stats myprog.pl # compile-time only
perl -MB::Stats[,OPTIONS] myprog.pl
=head1 DESCRIPTION
Print statistics for all generated ops.
static analysis at compile-time,
static analysis at end-time to include all runtime added modules,
and dynamic analysis at run-time, as with a profiler.
The purpose is to help you in your goal:
no bloat;
=head1 OPTIONS
Options can be bundled: C<-c,-e,-r> eq C<-cer>
=over
=item -c I<static>
Do static analysis at compile-time. This does not include all run-time require packages.
Invocation via -MO=Stats does this automatically.
=item -e I<end>
Do static analysis at end-time. This is includes all run-time require packages.
This calculates the heap space for the optree.
=item -r I<run>
Do dynamic run-time analysis of all actually visited ops, similar to a profiler.
Single ops can be called multiple times.
=item -a I<all (default)>
Same as -cer: static compile-time, end-time and dynamic run-time.
=item -t I<table>
Tabular list of -c, -e and -r results.
=item -u I<summary>
Short summary only, no op class.
With -t only the final table(s).
=item -F I<Files>
Prints included file names
=item -x I<fragmentation> B<NOT YET>
Calculates the optree I<fragmentation>. 0.0 is perfect, 1.0 is very bad.
A perfect optree has no null ops and every op->next is immediately next
to the op.
=item -f<op,...> I<filter> B<NOT YET>
Filter for op names and classes. Only calculate the given ops, resp. op class.
perl -MB::Stats,-fLOGOP,-fCOP,-fconcat myprog.pl
=item -lF<logfile>
Print output only to this file. Default: STDERR
perl -MB::Stats,-llog myprog.pl
=back
=head1 METHODS
=over
=cut
our (%B_inc, %B_env);
BEGIN { %B_inc = %INC; }
use strict;
# B includes 14 files and 3821 lines. overhead subtracted with B::Stats::Minus
use B;
use B::Stats::Minus;
# XSLoader adds 0 files and 0 lines, already with B.
# Changed to DynaLoader
# Opcodes-0.10 adds 6 files and 5303-3821 lines: Carp, AutoLoader, subs
# Opcodes-0.11 adds 2 files and 4141-3821 lines: subs
# use Opcodes; # deferred to run-time below
our ($static, @runtime, $compiled, $imported, $LOG);
my (%opt, $nops, $rops, @all_subs, $frag, %roots);
my ($c_count, $e_count, $r_count);
# check options
sub import {
$DB::single = 1 if defined &DB::DB;
#print STDERR "opt: ",join(',',@_),"; "; # for Debugging
for (@_) { # switch bundling without Getopt bloat
if (/^-?([acerxtFu])(.*)$/) {
$opt{$1} = 1;
my $rest = $2;
do {
if ($rest =~ /^-?([acerxtFu])(.*)$/) {
$opt{$1} = 1;
$rest = $2;
}
} while $rest;
}
# taking multiple arguments: -ffilter
if (/^-?f(.*)$/) {
my $arg = $1;
if ($arg =~ /^[A-Z_]*OP$/) {
my @optype = qw(BASEOP UNOP BINOP LOGOP LISTOP PMOP SVOP PADOP PVOP_OR_SVOP
LOOP COP BASEOP_OR_UNOP FILESTATOP LOOPEXOP);
$opt{f}->{class}->{$arg} = 1;
die "invalid B::Stats,-fOPCLASS argument: $arg\n"
unless grep {$arg eq $_} @optype;
# pre-expand names for the class
require Opcodes;
my $maxo = Opcodes::opcodes();
for my $i (0..$maxo-1) {
my $name = Opcodes::opname($i);
my $class = $optype[ Opcodes::opclass($i) ];
if ($class eq $arg) {
$opt{f}->{name}->{$name} = 1;
}
}
} elsif ($arg =~ /^[a-z_]+$/) {
$opt{f}->{name}->{$arg} = 1;
} else {
die "invalid B::Stats,-ffilter argument: $arg\n";
}
}
if (/^-?(l)(.*)$/) { # taking arguments: -llogfile
$opt{$1} = $2;
open $LOG, ">", $opt{l} or die "Cannot write to B::Stats,-llogfile: $opt{l}\n";
}
}
$opt{a} = 1 if !$opt{c} and !$opt{e} and !$opt{r}; # default
$opt{c} = $opt{e} = $opt{r} = 1 if $opt{a};
#warn "%opt: ",keys %opt,"\n"; # for Debugging
$LOG = \*STDERR unless $opt{l};
$imported = 1;
}
sub _class {
my $name = ref shift;
$name =~ s/^.*:://;
return $name;
}
( run in 1.416 second using v1.01-cache-2.11-cpan-b16cb0d3907 )