Initial Commit

This commit is contained in:
Riley Schneider
2025-12-03 16:38:10 +01:00
parent c5e26bf594
commit b732d8d4b5
17680 changed files with 5977495 additions and 2 deletions

View File

@@ -0,0 +1,86 @@
package IPC::Run3::ProfArrayBuffer;
$VERSION = 0.048;
=head1 NAME
IPC::Run3::ProfArrayBuffer - Store profile events in RAM in an array
=head1 SYNOPSIS
=head1 DESCRIPTION
=cut
use strict;
=head1 METHODS
=over
=item C<< IPC::Run3::ProfArrayBuffer->new() >>
=cut
sub new {
my $class = ref $_[0] ? ref shift : shift;
my $self = bless { @_ }, $class;
$self->{Events} = [];
return $self;
}
=item C<< $buffer->app_call(@events) >>
=item C<< $buffer->app_exit(@events) >>
=item C<< $buffer->run_exit(@events) >>
The three above methods push the given events onto the stack of recorded
events.
=cut
for my $subname ( qw(app_call app_exit run_exit) ) {
no strict 'refs';
*{$subname} = sub {
push @{shift->{Events}}, [ $subname => @_ ];
};
}
=item get_events
Returns a list of all the events. Each event is an ARRAY reference
like:
[ "app_call", 1.1, ... ];
=cut
sub get_events {
my $self = shift;
@{$self->{Events}};
}
=back
=head1 LIMITATIONS
=head1 COPYRIGHT
Copyright 2003, R. Barrie Slaymaker, Jr., All Rights Reserved
=head1 LICENSE
You may use this module under the terms of the BSD, Artistic, or GPL licenses,
any version.
=head1 AUTHOR
Barrie Slaymaker E<lt>barries@slaysys.comE<gt>
=cut
1;

View File

@@ -0,0 +1,157 @@
package IPC::Run3::ProfLogReader;
$VERSION = 0.048;
=head1 NAME
IPC::Run3::ProfLogReader - read and process a ProfLogger file
=head1 SYNOPSIS
use IPC::Run3::ProfLogReader;
my $reader = IPC::Run3::ProfLogReader->new; ## use "run3.out"
my $reader = IPC::Run3::ProfLogReader->new( Source => $fn );
my $profiler = IPC::Run3::ProfPP; ## For example
my $reader = IPC::Run3::ProfLogReader->new( ..., Handler => $p );
$reader->read;
$eaderr->read_all;
=head1 DESCRIPTION
Reads a log file. Use the filename "-" to read from STDIN.
=cut
use strict;
=head1 METHODS
=head2 C<< IPC::Run3::ProfLogReader->new( ... ) >>
=cut
sub new {
my $class = ref $_[0] ? ref shift : shift;
my $self = bless { @_ }, $class;
$self->{Source} = "run3.out"
unless defined $self->{Source} && length $self->{Source};
my $source = $self->{Source};
if ( ref $source eq "GLOB" || UNIVERSAL::isa( $source, "IO::Handle" ) ) {
$self->{FH} = $source;
}
elsif ( $source eq "-" ) {
$self->{FH} = \*STDIN;
}
else {
open PROFILE, "<$self->{Source}" or die "$!: $self->{Source}\n";
$self->{FH} = *PROFILE{IO};
}
return $self;
}
=head2 C<< $reader->set_handler( $handler ) >>
=cut
sub set_handler { $_[0]->{Handler} = $_[1] }
=head2 C<< $reader->get_handler() >>
=cut
sub get_handler { $_[0]->{Handler} }
=head2 C<< $reader->read() >>
=cut
sub read {
my $self = shift;
my $fh = $self->{FH};
my @ln = split / /, <$fh>;
return 0 unless @ln;
return 1 unless $self->{Handler};
chomp $ln[-1];
## Ignore blank and comment lines.
return 1 if @ln == 1 && ! length $ln[0] || 0 == index $ln[0], "#";
if ( $ln[0] eq "\\app_call" ) {
shift @ln;
my @times = split /,/, pop @ln;
$self->{Handler}->app_call(
[
map {
s/\\\\/\\/g;
s/\\_/ /g;
$_;
} @ln
],
@times
);
}
elsif ( $ln[0] eq "\\app_exit" ) {
shift @ln;
$self->{Handler}->app_exit( pop @ln, @ln );
}
else {
my @times = split /,/, pop @ln;
$self->{Handler}->run_exit(
[
map {
s/\\\\/\\/g;
s/\\_/ /g;
$_;
} @ln
],
@times
);
}
return 1;
}
=head2 C<< $reader->read_all() >>
This method reads until there is nothing left to read, and then returns true.
=cut
sub read_all {
my $self = shift;
1 while $self->read;
return 1;
}
=head1 LIMITATIONS
=head1 COPYRIGHT
Copyright 2003, R. Barrie Slaymaker, Jr., All Rights Reserved
=head1 LICENSE
You may use this module under the terms of the BSD, Artistic, or GPL licenses,
any version.
=head1 AUTHOR
Barrie Slaymaker E<lt>barries@slaysys.comE<gt>
=cut
1;

View File

@@ -0,0 +1,139 @@
package IPC::Run3::ProfLogger;
$VERSION = 0.048;
=head1 NAME
IPC::Run3::ProfLogger - write profiling data to a log file
=head1 SYNOPSIS
use IPC::Run3::ProfLogger;
my $logger = IPC::Run3::ProfLogger->new; ## write to "run3.out"
my $logger = IPC::Run3::ProfLogger->new( Destination => $fn );
$logger->app_call( \@cmd, $time );
$logger->run_exit( \@cmd1, @times1 );
$logger->run_exit( \@cmd1, @times1 );
$logger->app_exit( $time );
=head1 DESCRIPTION
Used by IPC::Run3 to write a profiling log file. Does not
generate reports or maintain statistics; its meant to have minimal
overhead.
Its API is compatible with a tiny subset of the other IPC::Run profiling
classes.
=cut
use strict;
=head1 METHODS
=head2 C<< IPC::Run3::ProfLogger->new( ... ) >>
=cut
sub new {
my $class = ref $_[0] ? ref shift : shift;
my $self = bless { @_ }, $class;
$self->{Destination} = "run3.out"
unless defined $self->{Destination} && length $self->{Destination};
open PROFILE, ">$self->{Destination}"
or die "$!: $self->{Destination}\n";
binmode PROFILE;
$self->{FH} = *PROFILE{IO};
$self->{times} = [];
return $self;
}
=head2 C<< $logger->run_exit( ... ) >>
=cut
sub run_exit {
my $self = shift;
my $fh = $self->{FH};
print( $fh
join(
" ",
(
map {
my $s = $_;
$s =~ s/\\/\\\\/g;
$s =~ s/ /_/g;
$s;
} @{shift()}
),
join(
",",
@{$self->{times}},
@_,
),
),
"\n"
);
}
=head2 C<< $logger->app_exit( $arg ) >>
=cut
sub app_exit {
my $self = shift;
my $fh = $self->{FH};
print $fh "\\app_exit ", shift, "\n";
}
=head2 C<< $logger->app_call( $t, @args) >>
=cut
sub app_call {
my $self = shift;
my $fh = $self->{FH};
my $t = shift;
print( $fh
join(
" ",
"\\app_call",
(
map {
my $s = $_;
$s =~ s/\\\\/\\/g;
$s =~ s/ /\\_/g;
$s;
} @_
),
$t,
),
"\n"
);
}
=head1 LIMITATIONS
=head1 COPYRIGHT
Copyright 2003, R. Barrie Slaymaker, Jr., All Rights Reserved
=head1 LICENSE
You may use this module under the terms of the BSD, Artistic, or GPL licenses,
any version.
=head1 AUTHOR
Barrie Slaymaker E<lt>barries@slaysys.comE<gt>
=cut
1;

View File

@@ -0,0 +1,156 @@
package IPC::Run3::ProfPP;
$VERSION = 0.048;
=head1 NAME
IPC::Run3::ProfPP - Generate reports from IPC::Run3 profiling data
=head1 SYNOPSIS
=head1 DESCRIPTION
Used by IPC::Run3 and/or run3profpp to print out profiling reports for
human readers. Use other classes for extracting data in other ways.
The output methods are plain text, override these (see the source for
now) to provide other formats.
This class generates reports on each run3_exit() and app_exit() call.
=cut
require IPC::Run3::ProfReporter;
@ISA = qw( IPC::Run3::ProfReporter );
use strict;
use POSIX qw( floor );
=head1 METHODS
=head2 C<< IPC::Run3::ProfPP->new() >>
Returns a new profile reporting object.
=cut
sub _emit { shift; warn @_ }
sub _t {
sprintf "%10.6f secs", @_;
}
sub _r {
my ( $num, $denom ) = @_;
return () unless $denom;
sprintf "%10.6f", $num / $denom;
}
sub _pct {
my ( $num, $denom ) = @_;
return () unless $denom;
sprintf " (%3d%%)", floor( 100 * $num / $denom + 0.5 );
}
=head2 C<< $profpp->handle_app_call() >>
=cut
sub handle_app_call {
my $self = shift;
$self->_emit("IPC::Run3 parent: ",
join( " ", @{$self->get_app_cmd} ),
"\n",
);
$self->{NeedNL} = 1;
}
=head2 C<< $profpp->handle_app_exit() >>
=cut
sub handle_app_exit {
my $self = shift;
$self->_emit("\n") if $self->{NeedNL} && $self->{NeedNL} != 1;
$self->_emit( "IPC::Run3 total elapsed: ",
_t( $self->get_app_cumulative_time ),
"\n");
$self->_emit( "IPC::Run3 calls to run3(): ",
sprintf( "%10d", $self->get_run_count ),
"\n");
$self->_emit( "IPC::Run3 total spent in run3(): ",
_t( $self->get_run_cumulative_time ),
_pct( $self->get_run_cumulative_time, $self->get_app_cumulative_time ),
", ",
_r( $self->get_run_cumulative_time, $self->get_run_count ),
" per call",
"\n");
my $exclusive =
$self->get_app_cumulative_time - $self->get_run_cumulative_time;
$self->_emit( "IPC::Run3 total spent not in run3(): ",
_t( $exclusive ),
_pct( $exclusive, $self->get_app_cumulative_time ),
"\n");
$self->_emit( "IPC::Run3 total spent in children: ",
_t( $self->get_sys_cumulative_time ),
_pct( $self->get_sys_cumulative_time, $self->get_app_cumulative_time ),
", ",
_r( $self->get_sys_cumulative_time, $self->get_run_count ),
" per call",
"\n");
my $overhead =
$self->get_run_cumulative_time - $self->get_sys_cumulative_time;
$self->_emit( "IPC::Run3 total overhead: ",
_t( $overhead ),
_pct(
$overhead,
$self->get_sys_cumulative_time
),
", ",
_r( $overhead, $self->get_run_count ),
" per call",
"\n");
}
=head2 C<< $profpp->handle_run_exit() >>
=cut
sub handle_run_exit {
my $self = shift;
my $overhead = $self->get_run_time - $self->get_sys_time;
$self->_emit("\n") if $self->{NeedNL} && $self->{NeedNL} != 2;
$self->{NeedNL} = 3;
$self->_emit( "IPC::Run3 child: ",
join( " ", @{$self->get_run_cmd} ),
"\n");
$self->_emit( "IPC::Run3 run3() : ", _t( $self->get_run_time ), "\n",
"IPC::Run3 child : ", _t( $self->get_sys_time ), "\n",
"IPC::Run3 overhead: ", _t( $overhead ),
_pct( $overhead, $self->get_sys_time ),
"\n");
}
=head1 LIMITATIONS
=head1 COPYRIGHT
Copyright 2003, R. Barrie Slaymaker, Jr., All Rights Reserved
=head1 LICENSE
You may use this module under the terms of the BSD, Artistic, or GPL licenses,
any version.
=head1 AUTHOR
Barrie Slaymaker E<lt>barries@slaysys.comE<gt>
=cut
1;

View File

@@ -0,0 +1,256 @@
package IPC::Run3::ProfReporter;
$VERSION = 0.048;
=head1 NAME
IPC::Run3::ProfReporter - base class for handling profiling data
=head1 SYNOPSIS
=head1 DESCRIPTION
See L<IPC::Run3::ProfPP|IPC::Run3::ProfPP> and for an example subclass.
This class just notes and accumulates times; subclasses use methods like
"handle_app_call", "handle_run_exit" and "handle_app_exit" to emit reports on
it. The default methods for these handlers are noops.
If run from the command line, a reporter will be created and run on
each logfile given as a command line parameter or on run3.out if none
are given.
This allows reports to be run like:
perl -MIPC::Run3::ProfPP -e1
perl -MIPC::Run3::ProfPP -e1 foo.out bar.out
Use "-" to read from STDIN (the log file format is meant to be moderately
greppable):
grep "^cvs " run3.out perl -MIPC::Run3::ProfPP -e1 -
Use --app to show only application level statistics (ie don't emit
a report section for each command run).
=cut
use strict;
my $loaded_by;
sub import {
$loaded_by = shift;
}
END {
my @caller;
for ( my $i = 0;; ++$i ) {
my @c = caller $i;
last unless @c;
@caller = @c;
}
if ( $caller[0] eq "main"
&& $caller[1] eq "-e"
) {
require IPC::Run3::ProfLogReader;
require Getopt::Long;
my ( $app, $run );
Getopt::Long::GetOptions(
"app" => \$app,
"run" => \$run,
);
$app = 1, $run = 1 unless $app || $run;
for ( @ARGV ? @ARGV : "" ) {
my $r = IPC::Run3::ProfLogReader->new(
Source => $_,
Handler => $loaded_by->new(
Source => $_,
app_report => $app,
run_report => $run,
),
);
$r->read_all;
}
}
}
=head1 METHODS
=over
=item C<< IPC::Run3::ProfReporter->new >>
Returns a new profile reporting object.
=cut
sub new {
my $class = ref $_[0] ? ref shift : shift;
my $self = bless { @_ }, $class;
$self->{app_report} = 1, $self->{run_report} = 1
unless $self->{app_report} || $self->{run_report};
return $self;
}
=item C<< $reporter->handle_app_call( ... ) >>
=item C<< $reporter->handle_app_exit( ... ) >>
=item C<< $reporter->handle_run_exit( ... ) >>
These methods are called by the handled events (see below).
=cut
sub handle_app_call {}
sub handle_app_exit {}
sub handle_run_exit {}
=item C<< $reporter->app_call(\@cmd, $time) >>
=item C<< $reporter->app_exit($time) >>
=item C<< $reporter->run_exit(@times) >>
$self->app_call( $time );
my $time = $self->get_app_call_time;
Sets the time (in floating point seconds) when the application, run3(),
or system() was called or exited. If no time parameter is passed, uses
IPC::Run3's time routine.
Use get_...() to retrieve these values (and _accum values, too). This
is a separate method to speed the execution time of the setters just a
bit.
=cut
sub app_call {
my $self = shift;
( $self->{app_cmd}, $self->{app_call_time} ) = @_;
$self->handle_app_call if $self->{app_report};
}
sub app_exit {
my $self = shift;
$self->{app_exit_time} = shift;
$self->handle_app_exit if $self->{app_report};
}
sub run_exit {
my $self = shift;
@{$self}{qw(
run_cmd run_call_time sys_call_time sys_exit_time run_exit_time
)} = @_;
++$self->{run_count};
$self->{run_cumulative_time} += $self->get_run_time;
$self->{sys_cumulative_time} += $self->get_sys_time;
$self->handle_run_exit if $self->{run_report};
}
=item C<< $reporter->get_run_count() >>
=item C<< $reporter->get_app_call_time() >>
=item C<< $reporter->get_app_exit_time() >>
=item C<< $reporter->get_app_cmd() >>
=item C<< $reporter->get_app_time() >>
=cut
sub get_run_count { shift->{run_count} }
sub get_app_call_time { shift->{app_call_time} }
sub get_app_exit_time { shift->{app_exit_time} }
sub get_app_cmd { shift->{app_cmd} }
sub get_app_time {
my $self = shift;
$self->get_app_exit_time - $self->get_app_call_time;
}
=item C<< $reporter->get_app_cumulative_time() >>
=cut
sub get_app_cumulative_time {
my $self = shift;
$self->get_app_exit_time - $self->get_app_call_time;
}
=item C<< $reporter->get_run_call_time() >>
=item C<< $reporter->get_run_exit_time() >>
=item C<< $reporter->get_run_time() >>
=cut
sub get_run_call_time { shift->{run_call_time} }
sub get_run_exit_time { shift->{run_exit_time} }
sub get_run_time {
my $self = shift;
$self->get_run_exit_time - $self->get_run_call_time;
}
=item C<< $reporter->get_run_cumulative_time() >>
=cut
sub get_run_cumulative_time { shift->{run_cumulative_time} }
=item C<< $reporter->get_sys_call_time() >>
=item C<< $reporter->get_sys_exit_time() >>
=item C<< $reporter->get_sys_time() >>
=cut
sub get_sys_call_time { shift->{sys_call_time} }
sub get_sys_exit_time { shift->{sys_exit_time} }
sub get_sys_time {
my $self = shift;
$self->get_sys_exit_time - $self->get_sys_call_time;
}
=item C<< $reporter->get_sys_cumulative_time() >>
=cut
sub get_sys_cumulative_time { shift->{sys_cumulative_time} }
=item C<< $reporter->get_run_cmd() >>
=cut
sub get_run_cmd { shift->{run_cmd} }
=back
=head1 LIMITATIONS
=head1 COPYRIGHT
Copyright 2003, R. Barrie Slaymaker, Jr., All Rights Reserved
=head1 LICENSE
You may use this module under the terms of the BSD, Artistic, or GPL licenses,
any version.
=head1 AUTHOR
Barrie Slaymaker <barries@slaysys.com>
=cut
1;