NAME
Devel::Agent
SYNOPSIS
perl -d:Agent
DESCRIPTION
For years people in the perl commnity have been asking for a way to do performance monitoring and tracing of runtime production code. This module attempts to fill this role by implementing a stripped down debugger that is intended to provides an agent or agent like interface for perl 5.34.0+ that is simlilar in nature to the agent interface in other langagues Such as python or java.
This is accomplished by running the script or code in debug mode, "perl -d:Agent" and then turning the debugger on only as needed to record traching and performance metrics. That said this module just provides an agent interface, it does not act on code directly until something turns it on.
Agent interface
The Agent interface is implemented via an on demand debugger that can be turned on/off on the fly. Also it is possible to run multiple different debugger instances with diffrent configurations on different blocks of code. This was done intentionally as perl is fairly complex in its nature and an agent interface isn't very useful unless it is flexible.
The agent interface itself is activated by setting $DB::Agent to an instance of itself.
To turn tracing on:
Make sure you either start your perl script -d:Agent or set PERL5OPT="-d:Agent" before launching your script
Inside you script you can issue the following
use Data::Dumper;
my $db=DB->new(
save_to_stack=>1
);
$db->start_trace;
# run some code
...
# and we are done wathcing
$db->stop_trace;
# to dump a very human readable full trace
print Dumper($db->trace);
But altering you code is far from ideal.
Another option is to load the agent and a module that pre-configures it for use such as the Devel::Trace::EveryThing module, wich provides a stack trace to STDERR in real time as frames begin and exit.
Example using: Devel::Trace::EveryThing
perl -Ilib -d:Agent -MDevel::Agent::EveryThing examples/everything.pl
DB Constructor options
This section documents the %args the be passed to the new DB(%args) or DB->new(%args) call. For each option documented in this section, there is an accesor by that given name that can be called by $self->$name($new_value) or my $current_value=$self->$name.
level=>ArrayRef
This is an auto generated array ref that is use by the internals to track current stack level state information.
resolve_constructor=>Bool
This option is used to turn on or off the resolution of a class name when being constructed and other situations. By default this option is set to true.
trace=>[]
When the object instance is constructed with save_to_stack=>1 ( default is: 0 ) then the stack trace will be saved into a single multi tier data structrure represented by $self->trace.
ignore_calling_class_re=>ArrayRef[RegexpRef]
This option allows a list of calling calsses to be ignored when they match the regular expression.
Example ignore_calling_class_re being set to [qr{^Do::Not::Track::Me::}] will prevent the debugger for trying to trace or record calls made by any methods within "Do::Not::Track::Me::". This does not prevent this class from showing up fully ina stack trace. If this class calls a class that calls another class that calls a class unlisted in ignore_calling_class_re, then Do::Not::Track::Me::xxx will show up as the owner frame of the calls as a biproduct of correctness in stack tracing.
excludes=>HashRef[Int]
This is a collection of classes that should be ignored when they make calls. The defaults are defined in @DB::EXCLUDE_DEFAULTS and include classes like Data::Dumper and Time::HiRes to name a few. For a full list of the current defaults just perl -MDevel::Agent -MData::Dumper -e 'print Dumper(\@DB::EXCLUDE_DEFAULTS)'
last_depth=>Int
This value is used at runtime to determine the previous point in the stack trace.
depths=>ArrayRef
This is used at runtime to determin the current frame stack depth. Each currently executing frame is kept in order from top to the bottom of the stack.
order_id=>Int
This option acts as the sequence or order of execution counter for frames. When a frame starts $self->order_id is incremented by 1 and set to the frame's oder_id when the frame has completed execution the current $self->order_id is incremented again and set to the frame's end_id.
save_to_stack=>Bool
This option is used to turn on or of the saving of frames details in to a layered structure inside of $self->trace. The default is 0 or false.
on_frame_end=>CodeRef
This code ref is called when a frame is closed. This should act as the default data streaming hook callback. All tracing operations are halted durriong this callback.
Example:
sub { my ($self,$last)=@_; # $self: An instance of DB # $last: The most currently closed frame }
trace_id=>Int
This method provides the current agent tracing pass. This number is incremented at the start of each call to $self->start_trace.
ignore_blocks=>HasRef[Int]
This hashref reprents what perl phazed blocks to ignore, the defaults are.
{ BEGIN=>1, END=>1, INIT=>1, CHECK=>1, UNITCHECK=>1, }
The default values used to generate the hashref contained in in @DB::@PHAZES
constructor_methods=>HashRef[Int]
This is a hash of method names we consider object constructors
Default:
{ # we assume new is an object constructor new=>1 }
max_depth=>Int
When the value is set to something other than -1, the number represents the maxium stack depth to trace too. Once the frame of max_depth exits, then max_depth will again be set to -1.
tid=>Int
This is mostly here for completeness, retuns the tid id this debugger was created in.
Note Note Note:
The code was not orginally develpoed without threading in mind, if you wish to trace elemetns within a thread make sure you start an instance of the debugger within that thread.
existing_trace=>Maybe[InstanceOf['DB']]
This acts as a save point for another existing trace to be exected.
process_result=>CodeRef
This callback can be used to evaluate/modify the results of a callback.
Example callback
sub { my ($self,$type,$frame)=@_; # $self: Instance of Devel::Agent # $type: -1,0,1 # $frame: The current frame }
Notes on $type and where the current return values are stored
When $type is: -1 This is in a call to DESTROY( the envy of the programming world! ) Return value is in $DB::ret
0 This method was called in a scalar context Return value is in $DB::ret 1 This method was called in a list context Return value is in @DB::ret
filter_on_args=>CodeRef
This allows a code ref to be passed in to filter arguments passed into a method. If the method returns false, the frame is ignored.
Default always returns true
sub { my ($self,$frame,$args,$caller)=@_; # $self: Instance of Devel::Agent # $frame: Current frame hashref # $args: The @_ contents # $caller: The contents of caller($depth) return 1; }
pid=>Int
By default this is set to $$
API Methods
This section documents general api methods.
Bool=$self->_filter($caller,$args)
This method is the core interface used to decide if a method should show up in the debug/stack trace.
This is where the following constructor options are applied:
ignore_calling_class_re
The $self->ignore_calling_class_re is applied to each calling or caller->[0], if it matches the frame is ignored.
excludes
If $caller->[0] matches an element of excludes, then this frame is ignored.
resolve_constructor
This converts the "class" portion of the frame value class_method to the first argument of a method that matches anything found in resolve_constructor.
excludes
The updated class value is applied to excludes again, if it matches, then the frame is not traced.
$self->resolve_class($class,$method,$caller,$args)
Changes $class to the constructor class if $self->resolve_constructor && exists $self->constructor_methods->{$method}
$self->close_depth($depth)
After a frame ahs finished execution, this method is called. This removes the frame from $self->depths
Sets the following frame option:
error the $@ state
end_id the order_id this frame ended on
duration Execution time in micro seconds
my $id=$self->next_order_id
Returns the next order_id.
$self->close_to($depth,$frame|undef)
Closes down the stack trace to $depth, performs addtional actions if $frame is defiend.
$self->filter($caller,$args)
This method is called by the DB method after the sub method and is used to place a frame on the stack for tracing.
Self->save_to($frame)
Saves the frame to the stack trace at the proper depth.
$self->push_to_stack($frame)
This method handles the saving, closing and backfilling logic for a given frame.
my $depth=$self->get_depth
Returns undef or a number representing the stack depth. When the value is undef, the trace would exceed $self->max_depth;
my $frame=$self->caller_to_ref($caller,$depth|undef,$raw_method,$no_frame)
Returns a frame hashref. If $depth is not defined a call to $depth is made, if it exceeds a set value of $self->max_depth undef is returned.
$self->reset
Rsets the internals of the object for starting a new stack trace.
$self->start_trace
Begins the stack trace process.
$self->stop_trace
Ends the current stack trace process.
$self->pause_trace
Turns tracing off until a call to $self->restore_trace is made
$self->restore_trace
Turns tracking back on.
$self->close_sub($res)
This method is called by the sub method. It is used to send notice that a frame has finished execution.
my $frames=$self->grab_missing($depth,$frame);
Returns any skiped frames between $depth and $frame.
$depth is expected to be a number and $frame expected to be a frame hash.
DB(@_)
This method is manditory for the implemntation of a debugger. With the current perl internals it is called every time a breakable point of code is reached. Unfortunatly this overhead is unavoidable.
Example:
foreach(1,3,4) { # Debugger would normally stop here
someMethod($_) # agent tracing only happens when your function is called
}
# total calls would be 4 + 3 * 2
# 1 call when foreach is reached
# 1 call for each element in the loop
# 2 times for every method
The as an optimization the agent ensures that tracing only happens on user defined functions. All other operations should be ignored.
The optimization reduces the number of calls to 3 or just once per method.
sub(@_)
THis is a manditory for implementation, this method is called twice per user defined method. Once before the execution once to actually run the function.
Example:
foreach(1,3,4) {
someMethod($_) # sub is called 2 times per function
}
# calls to sub 6
If $AGENT is undef, this method does nothing.
Compile time notes
For perl 5.34.0
When loading this moduel All features of the debugger are disabled aside from: ( 0x01, 0x02, and 0x20 ) which are requried to force the execution of DB::DB. Please see the perldoc perlvar and the $PERLDB section.
Which means: $^P==35
Also as a note: $^D==0
RUNTIME
At runtime, this modue tries to exectue $Devel::Agent::AGENT->filter($caller,$args). If $Devel::Agent::AGENT is not defined, then nothing happens.
$caller: is the caller information
$args: contains an array reference that represents the arguments passed to a given method
Silly stuff
Please forgive the typos, this was written on holiday in my spare time.
AUTHOR
Michael Shipper AKALINUX@CPAN.ORG